001package com.fs.starfarer.api.impl.campaign.velfield;
002
003import java.util.ArrayList;
004import java.util.List;
005
006import org.lwjgl.util.vector.Vector2f;
007
008import com.fs.starfarer.api.util.Misc;
009
010public class TurbulenceCalc2 {
011
012        public static class TurbulenceParams {
013                public VelocityField field;
014                public float effectWidth;
015                public float effectLength;
016                public float propagationAmount;
017                
018                public float maxDispersionAngle = 120f;
019                public float energyTransferMult = 5f; // should be 2 for proper energy conservation, but something's off
020                public float dampenFactor = 0.2f;
021                public float maxVelocity = 1000f;
022        }
023        
024        public static class DeltaData {
025                public Vector2f delta;
026                public Vector2f velocity;
027                public Vector2f dir;
028                public float weight;
029                public DeltaData(Vector2f delta, Vector2f velocity, Vector2f dir, float weight) {
030                        this.delta = delta;
031                        this.velocity = velocity;
032                        this.dir = dir;
033                        this.weight = weight;
034                }
035        }
036        
037
038        public static void advance(TurbulenceParams params) {
039                
040                if (params.propagationAmount > 1f) params.propagationAmount = 1f;
041                
042                Vector2f[][] f = params.field.getField();
043                float s = params.field.getCellSize();
044                
045                float effectWidth = params.effectWidth;
046                float effectLength = params.effectLength;
047                
048                Vector2f[][] delta = new Vector2f[f.length][f[0].length];
049                for (int i = 0; i < f.length; i++) {
050                        for (int j = 0; j < f[0].length; j++) {
051                                delta[i][j] = new Vector2f();
052                        }
053                }
054
055                
056                
057                for (int i = 0; i < f.length; i++) {
058                        for (int j = 0; j < f[0].length; j++) {
059                                
060                                float cx = i * s;
061                                float cy = j * s;
062                                Vector2f v = f[i][j];
063                                
064                                Vector2f dir = Misc.normalise(new Vector2f(v));
065                                
066                                Vector2f p1 = new Vector2f(dir);
067                                p1.scale(-effectLength * 0.5f);
068                                p1.x += cx;
069                                p1.y += cy;
070                                
071                                Vector2f p2 = new Vector2f(dir);
072                                p2.scale(effectLength * 0.5f);
073                                //p2.scale(effectLength);
074                                p2.x += cx;
075                                p2.y += cy;
076                                
077                                float minX = Math.min(p1.x - effectWidth * 0.5f, p2.x - effectWidth * 0.5f);
078                                float maxX = Math.max(p1.x + effectWidth * 0.5f, p2.x + effectWidth * 0.5f);
079                                float minY = Math.min(p1.y - effectLength * 0.5f, p2.y - effectLength * 0.5f);
080                                float maxY = Math.max(p1.y + effectLength * 0.5f, p2.y + effectLength * 0.5f);
081                                
082                                int cellX1 = (int) (minX / s);
083                                int cellY1 = (int) (minY / s);
084                                if (minX < 0) cellX1 = (int) (-1f * Math.abs(minX) / s) - 1;
085                                if (minY < 0) cellY1 = (int) (-1f * Math.abs(minY) / s) - 1;
086                                
087                                int cellX2 = (int) (maxX / s);
088                                int cellY2 = (int) (maxY / s);
089                                if (maxX < 0) cellX2 = (int) (-1f * Math.abs(maxX) / s) - 1;
090                                if (maxY < 0) cellY2 = (int) (-1f * Math.abs(maxY) / s) - 1;
091                                maxX += 1;
092                                maxY += 1;
093                                
094                                float velDir = Misc.getAngleInDegrees(dir);
095                                velDir = Misc.normalizeAngle(velDir);
096                                
097//                              if (speed > 0) {
098//                                      System.out.println("efwefwef");
099//                              }
100
101                                //if (true) continue;
102                                List<DeltaData> deltaData = new ArrayList<TurbulenceCalc2.DeltaData>();
103                                for (int a = cellX1; a <= cellX2; a++) {
104                                        for (int b = cellY1; b <= cellY2; b++) {
105                                                if (a == i && b == j) continue;
106                                                
107                                                Vector2f p3 = new Vector2f(a * s, b * s);
108                                                
109                                                float u = (p3.x - p1.x) * (p2.x - p1.x) + (p3.y - p1.y) * (p2.y - p1.y);
110                                                float denom = Vector2f.sub(p2, p1, new Vector2f()).length();
111                                                denom *= denom;
112                                                if (denom == 0) continue;
113                                                u /= denom;
114                                                
115                                                if (u >= 0 && u <= 1) { // intersection is between p1 and p2
116                                                        Vector2f intersect = new Vector2f();
117                                                        intersect.x = p1.x + u * (p2.x - p1.x);
118                                                        intersect.y = p1.y + u * (p2.y - p1.y);
119                                                        float distFromLine = Vector2f.sub(intersect, p3, new Vector2f()).length();
120                                                        float distAlongLine = Math.abs((u - 0.5f) * effectLength);
121                                                        if (distFromLine > effectWidth * 0.5f) continue;
122                                                        if (distAlongLine > effectLength * 0.5f) continue;
123                                                        
124                                                        float rateMult = (0.5f * (1f - distFromLine / (effectWidth * 0.5f))) +
125                                                                                         (0.5f * (1f - distAlongLine / (effectLength * 0.5f)));
126//                                                      if (distFromLine <= 0f) {
127//                                                              System.out.println("efwfwefwe");
128//                                                      }
129                                                        float offsetMult = (distFromLine / (effectWidth * 0.5f)) *
130                                                                                           (0.5f + 0.5f * distAlongLine / (effectLength * 0.5f));
131                                                        float deltaAngleOffset = offsetMult * params.maxDispersionAngle;
132                                                        //float offsetDir = Misc.getClosestTurnDirection(velDir, Misc.getAngleInDegrees(p1, p3));
133                                                        
134                                                        float offsetDir = 0f;
135                                                        float diff = Misc.normalizeAngle(Misc.getAngleInDegrees(p1, p3)) - velDir;
136                                                        //diff = Misc.normalizeAngle(diff);
137                                                    if (diff < 0) diff += 360;
138                                                    if (diff == 0 || diff == 360f) {
139                                                        offsetDir = 0f;
140                                                    } else if (diff > 180) {
141                                                        offsetDir = -1f;
142                                                    } else {
143                                                        offsetDir = 1f;
144                                                    }
145                                                    //offsetDir = Misc.getClosestTurnDirection(velDir, Misc.getAngleInDegrees(p1, p3));
146//                                                  float offsetDir2 = Misc.getClosestTurnDirection(velDir, Misc.getAngleInDegrees(p1, p3));
147//                                                  if (offsetDir != offsetDir2) {
148//                                                      System.out.println("NOT THE SAME");
149//                                                  }
150                                                        
151                                                        
152                                                        Vector2f dv = Misc.getUnitVectorAtDegreeAngle(velDir + deltaAngleOffset * offsetDir);
153                                                        Vector2f d = getCell(delta, a, b);
154                                                        Vector2f destVel = getCell(f, a, b);
155                                                        
156                                                        DeltaData data = new DeltaData(d, destVel, dv, rateMult);
157                                                        deltaData.add(data);
158                                                }
159                                        }
160                                }
161                                
162                                float totalWeight = 0f;
163                                for (DeltaData data : deltaData) {
164                                        totalWeight += data.weight;
165                                }
166                                
167                                float speed = v.length();
168                                float energy = 0.5f * speed * speed;
169                                float energyToTransfer = energy * params.propagationAmount;
170                                
171                                if (totalWeight > 0) {
172                                        for (DeltaData data : deltaData) {
173                                                float mult = data.weight / totalWeight;
174                                                float energyToAdd = energyToTransfer * mult;
175                                                
176                                                // 0.5 Vold^2 + energyToAdd = 0.5 Vnew^2
177                                                // Vold^2 + 2 energyToAdd = Vnew^2
178                                                float speedOther = data.velocity.length();
179                                                float speedOtherNew = (float) Math.sqrt(speedOther * speedOther + params.energyTransferMult * energyToAdd);
180                                                float speedAdd = speedOtherNew - speedOther;
181                                                data.delta.x += data.dir.x * speedAdd;
182                                                data.delta.y += data.dir.y * speedAdd;
183                                        }
184//                                      if (speedToTransfer > 0) {
185//                                              System.out.println("To transfer: " + speedToTransfer + ", transferred: " + totalTransferred);
186//                                      }
187                                        float speedNew = (float) Math.sqrt(speed * speed - 2f * energyToTransfer);
188                                        float speedAdd = speedNew - speed; // should be a negative number
189                                        Vector2f deltaForCurrCell = getCell(delta, i, j);
190                                        deltaForCurrCell.x += dir.x * speedAdd;
191                                        deltaForCurrCell.y += dir.y * speedAdd;
192                                }
193                        }
194                }
195                
196                float maxVel = params.maxVelocity;
197                for (int i = 0; i < f.length; i++) {
198                        for (int j = 0; j < f[0].length; j++) {
199                                Vector2f.add(f[i][j], delta[i][j], f[i][j]);
200                                float len = f[i][j].length();
201                                if (len > maxVel) {
202                                        f[i][j].scale(maxVel/len);
203                                }
204                        }
205                }
206
207                // dapmen by a fraction of the propagation rate
208                float dampenFraction = params.dampenFactor;
209                //dampenFraction = 0f;
210                if (dampenFraction > 0) {
211                        for (int i = 0; i < f.length; i++) {
212                                for (int j = 0; j < f[0].length; j++) {
213                                        Vector2f v = f[i][j];
214                                        //Vector2f dv = getCell(delta, i, j);
215                                        
216                                        float speed = v.length();
217                                        float dampen = speed * params.propagationAmount * dampenFraction;
218                                        if (speed > 0f) {
219                                                v.scale((speed - dampen) / speed);
220                                        }
221                                }
222                        }
223                }
224                
225        }
226        
227        public static Vector2f getCell(Vector2f [][] data, int i, int j) {
228                if (i < 0 || j < 0) return new Vector2f();
229                if (i >= data.length || j >= data[0].length) return new Vector2f();
230                return data[i][j];
231        }
232        
233        public static void addCell(Vector2f[][] field, Vector2f[][] delta, int fromX, int fromY, int x, int y, Vector2f dir, float propagationMult) {
234                Vector2f cell = getCell(field, fromX, fromY);
235                Vector2f d = getCell(delta, x, y);
236                Vector2f dFrom = getCell(delta, fromX, fromY);
237                float dot = Vector2f.dot(cell, dir);
238                
239                d.x += dir.x * dot * propagationMult;
240                d.y += dir.y * dot * propagationMult;
241                
242                dFrom.x -= dir.x * dot * propagationMult;
243                dFrom.y -= dir.y * dot * propagationMult;
244        }
245        
246        public static void addCell(Vector2f cell, Vector2f dir, Vector2f delta) {
247                float dot = Vector2f.dot(cell, dir);
248                delta.x += dir.x * dot;
249                delta.y += dir.y * dot;
250        }
251}
252
253
254
255
256
257
258