001package com.fs.starfarer.api.impl.campaign.procgen;
002
003import org.lwjgl.util.vector.Vector2f;
004
005import com.fs.starfarer.api.impl.campaign.terrain.BaseTiledTerrain;
006import com.fs.starfarer.api.util.Misc;
007
008public class NebulaEditor {
009        
010        protected BaseTiledTerrain plugin;
011        protected int [][] tiles;
012        protected int [][] orig;
013        protected float ts;
014        protected float width, height;
015        protected float cx, cy;
016        protected int w, h;
017        private float [][] noise;
018
019        
020        public NebulaEditor(BaseTiledTerrain plugin) {
021                this.plugin = plugin;
022                tiles = plugin.getTiles();
023                ts = plugin.getTileSize();
024                
025                width = tiles.length * ts;
026                height = tiles[0].length * ts;
027                
028                cx = plugin.getEntity().getLocation().x;
029                cy = plugin.getEntity().getLocation().y;
030                
031                w = tiles.length;
032                h = tiles[0].length;
033                
034                orig = getTilesCopy();
035                
036                regenNoise();
037        }
038        
039        public int[][] getTilesCopy() {
040                int [][] copy = new int[w][h];
041                for (int i = 0; i < w; i++) {
042                        for (int j = 0; j < h; j++) {
043                                copy[i][j] = tiles[i][j];
044                        }
045                }
046                return copy;
047        }
048        
049        public int[][] getTiles() {
050                return tiles;
051        }
052
053        public int[][] getOrigTiles() {
054                return orig;
055        }
056        
057        public float getTileSize() {
058                return ts;
059        }
060
061        public void regenNoise() {
062                float spikes = 1f;
063                noise = Misc.initNoise(StarSystemGenerator.random, w, h, spikes);
064                Misc.genFractalNoise(StarSystemGenerator.random, noise, 0, 0, w - 1, h - 1, 1, spikes);
065                Misc.normalizeNoise(noise);
066                
067//              // bug in noise generation? last line doesn't seem to have high enough values
068                // never mind, noise has to be power of two-sized
069//              for (int i = 0; i < w; i++) {
070//                      noise[i][h - 1] = noise[i][h - 2];
071//              }
072        }
073        
074//      public void noisePrune(float fractionKeep) {
075//              if (noise == null) regenNoise();
076//              int count = 0;
077//              for (int i = 0; i < w; i++) {
078//                      for (int j = 0; j < h; j++) {
079//                              if (noise[i][j] < 1f - fractionKeep) {
080//                                      tiles[i][j] = -1;
081//                                      count++;
082//                              }
083//                      }
084//              }
085//              //System.out.println("Pruned " + (int)((count * 100f) / (float) (w * h)) + "% with keep=" + fractionKeep);
086//      }
087        
088        public void noisePrune(float fractionKeep) {
089                if (noise == null) regenNoise();
090                float [] counts = new float[100];
091                for (int i = 0; i < w; i++) {
092                        for (int j = 0; j < h; j++) {
093                                float f = noise[i][j];
094                                int index = (int) (f * 100f);
095                                if (index < 0) index = 0;
096                                if (index > 99) index = 99;
097                                counts[index]++;
098                        }
099                }
100                
101                float total = w * h;
102                float keep = fractionKeep * total;
103                float threshold = 0f;
104                float totalKept = 0f;
105                for (int i = 0; i < 100; i++) {
106                        totalKept += counts[i];
107                        if (totalKept >= keep) {
108                                threshold = (float) i / 100f;
109                                break;
110                        }
111                }
112                
113                int count = 0;
114                for (int i = 0; i < w; i++) {
115                        for (int j = 0; j < h; j++) {
116                                if (noise[i][j] > threshold) {
117                                        tiles[i][j] = -1;
118                                        count++;
119                                }
120                        }
121                }
122                //System.out.println("Pruned " + (int)((count * 100f) / (float) (w * h)) + "% with keep=" + fractionKeep);
123        }
124        
125        
126        public void clearArc(float x, float y, float innerRadius, float outerRadius, float startAngle, float endAngle) {
127                clearArc(x, y, innerRadius, outerRadius, startAngle, endAngle, 0f);
128        }
129        
130        public void clearArc(float x, float y, float innerRadius, float outerRadius, float startAngle, float endAngle, float noiseThresholdToClear) {
131                clearArc(x, y, innerRadius, outerRadius, startAngle, endAngle, 1f, noiseThresholdToClear);
132        }
133        
134        public void clearArc(float x, float y, float innerRadius, float outerRadius, float startAngle, float endAngle, float endRadiusMult, float noiseThresholdToClear) {
135                float circumference = (float) Math.PI * 2f * outerRadius;
136                float degreesPerIteration = 360f / (circumference / (ts * 0.5f));
137                
138                for (float angle = startAngle; angle < endAngle; angle += degreesPerIteration) {
139                        Vector2f dir = Misc.getUnitVectorAtDegreeAngle(angle);
140                        float distMult = 1f;
141                        if (endAngle > startAngle) {
142                                float p = (angle - startAngle) / (endAngle - startAngle);
143                                distMult = 1f + (endRadiusMult - 1f) * p;
144                        }
145                        
146                        //for (float dist = innerRadius; dist <= outerRadius; dist += ts * 0.5f) {
147                        for (float dist = innerRadius * distMult; dist <= innerRadius * distMult + (outerRadius - innerRadius); dist += ts * 0.5f) {
148                                Vector2f curr = new Vector2f(dir);
149                                //curr.scale(dist * distMult);
150                                curr.scale(dist);
151                                curr.x += x;
152                                curr.y += y;
153                                setTileAt(curr.x, curr.y, -1, noiseThresholdToClear, setToOrigInsteadOfClear);
154                        }
155                }
156        }
157        
158        protected boolean setToOrigInsteadOfClear = false;
159        public boolean isSetToOrigInsteadOfClear() {
160                return setToOrigInsteadOfClear;
161        }
162        public void setSetToOrigInsteadOfClear(boolean setToOrigInsteadOfClear) {
163                this.setToOrigInsteadOfClear = setToOrigInsteadOfClear;
164        }
165
166        public void setTileAt(float x, float y, int value) {
167                setTileAt(x, y, value, 0f);
168        }
169        
170        public void setTileAt(float x, float y, int value, float noiseThresholdToClear) {
171                setTileAt(x, y, value, noiseThresholdToClear, false);
172        }
173        public void setTileAt(float x, float y, int value, float noiseThresholdToClear, boolean setToOrigTile) {
174                int cellX = (int) ((width / 2f + x - cx) / ts);
175                int cellY = (int) ((height / 2f + y - cy) / ts);
176                
177//              if (cellX < 0) cellX = 0;
178//              if (cellY < 0) cellY = 0;
179//              if (cellX > tiles.length - 1) cellX = tiles.length - 1; 
180//              if (cellY > tiles[0].length - 1) cellY = tiles[0].length - 1;
181                
182                if (cellX < 0) return;
183                if (cellY < 0) return;
184                if (cellX > tiles.length - 1) return; 
185                if (cellY > tiles[0].length - 1) return;
186//              if (cellX < 0) cellX = 0;
187//              if (cellY < 0) cellY = 0;
188//              if (cellX > tiles.length - 1) cellX = tiles.length - 1; 
189//              if (cellY > tiles[0].length - 1) cellY = tiles[0].length - 1;
190                
191                if (setToOrigTile) {
192                        value = orig[cellX][cellY];
193                }
194                if (noiseThresholdToClear <= 0 || noise[cellX][cellY] > noiseThresholdToClear) {
195                        tiles[cellX][cellY] = value;
196                }
197                //tiles[cellX][tiles[0].length - 1] = -1;
198        }
199        
200        
201        
202}
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219