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