001package com.fs.starfarer.api.impl.campaign.velfield; 002 003import java.awt.Color; 004import java.util.ArrayList; 005import java.util.Iterator; 006import java.util.LinkedHashMap; 007import java.util.LinkedHashSet; 008import java.util.List; 009import java.util.Map; 010import java.util.Set; 011 012import org.lwjgl.input.Mouse; 013import org.lwjgl.opengl.GL11; 014import org.lwjgl.opengl.GL14; 015import org.lwjgl.util.vector.Vector2f; 016 017import com.fs.starfarer.api.Global; 018import com.fs.starfarer.api.campaign.CampaignEngineLayers; 019import com.fs.starfarer.api.campaign.CampaignFleetAPI; 020import com.fs.starfarer.api.campaign.SectorEntityToken; 021import com.fs.starfarer.api.combat.ViewportAPI; 022import com.fs.starfarer.api.fleet.FleetMemberViewAPI; 023import com.fs.starfarer.api.graphics.SpriteAPI; 024import com.fs.starfarer.api.impl.campaign.BaseCustomEntityPlugin; 025import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceTerrainPlugin; 026import com.fs.starfarer.api.util.FaderUtil; 027import com.fs.starfarer.api.util.Misc; 028import com.fs.starfarer.api.util.MutatingVertexUtil; 029import com.fs.starfarer.api.util.WeightedRandomPicker; 030 031public class SlipstreamEntityPlugin2 extends BaseCustomEntityPlugin { 032 033 public static class SlipstreamSegment { 034 public Vector2f locB = new Vector2f(); 035 public Vector2f loc = new Vector2f(); 036 public Vector2f dir = new Vector2f(); 037 public float width; 038 039 transient public float wobbledWidth; 040 transient public int index = 0; 041 transient public Vector2f normal = new Vector2f(); 042 transient public float tx = 0f; 043 transient public float txe1 = 0f; 044 transient public float txe2 = 0f; 045 transient public float totalLength; 046 transient public float lengthToPrev; 047 transient public float lengthToNext; 048 049 public MutatingVertexUtil wobble1; 050 public MutatingVertexUtil wobble2; 051 public FaderUtil fader = new FaderUtil(0f, 1f, 1f); 052 } 053 054 public static class SlipstreamParticle { 055 float speed; 056 float dist; 057 float yPos; 058 Color color; 059 float remaining; 060 float elapsed; 061 } 062 063 public static class SlipstreamParams2 { 064 public String spriteKey1 = "slipstream"; 065 public String edgeKey = "slipstream_edge3"; 066 public Color spriteColor = new Color(0.3f, 0.5f, 1f, 1f); 067 public Color windGlowColor = new Color(0.3f, 0.5f, 1f, 1f); 068 public Color edgeColor = Color.white; 069 public float edgeWidth = 256; 070 //public float width; 071 public float areaPerParticle = 2875; 072 public int maxParticles = 2000; 073 //public int numParticles; 074 public float minSpeed; 075 public float maxSpeed; 076 public int burnLevel = 30; 077 public Color minColor; 078 public Color maxColor; 079 public float particleFadeInTime = 1f; 080 public float minDur = 0f; 081 public float maxDur = 4f; 082 public float lineLengthFractionOfSpeed = 0.5f; 083 public boolean slowDownInWiderSections = false; 084 public float widthForMaxSpeed = 1f; 085 public float widthForMaxSpeedMinMult = 0.5f; 086 public float widthForMaxSpeedMaxMult = 1.5f; 087 } 088 089 public static int MAX_PARTICLES_ADD_PER_FRAME = 250; 090 091 public static float RAD_PER_DEG = 0.01745329251f; 092 public static Vector2f rotateAroundOrigin(Vector2f v, float cos, float sin) { 093 Vector2f r = new Vector2f(); 094 r.x = v.x * cos - v.y * sin; 095 r.y = v.x * sin + v.y * cos; 096 return r; 097 } 098 099 100 101 protected SlipstreamParams2 params = new SlipstreamParams2(); 102 103 protected List<SlipstreamSegment> segments = new ArrayList<SlipstreamEntityPlugin2.SlipstreamSegment>(); 104 protected float totalLength = 0f; 105 106 protected transient List<SlipstreamParticle> particles = new ArrayList<SlipstreamParticle>(); 107 protected transient int [] lengthToIndexMap; 108 protected transient int lengthDivisor; 109 110 protected boolean needsRecompute = true; 111 protected List<BoundingBox> bounds = new ArrayList<BoundingBox>(); 112 protected int segmentsPerBox; 113 114 public SlipstreamEntityPlugin2() { 115 } 116 117 public void setNeedsRecompute() { 118 this.needsRecompute = true; 119 } 120 121 public void updateLengthToIndexMap() { 122 float minSegmentLength = Float.MAX_VALUE; 123 for (SlipstreamSegment curr : segments) { 124 if (curr.lengthToNext > 0 && minSegmentLength > curr.lengthToNext) { 125 minSegmentLength = curr.lengthToNext; 126 } 127 } 128 if (minSegmentLength < 50f) minSegmentLength = 50f; 129 130 lengthDivisor = (int) (minSegmentLength - 1f); 131 int numIndices = (int) (totalLength / lengthDivisor); 132 lengthToIndexMap = new int [numIndices]; 133 134 int lengthSoFar = 0; 135 for (int i = 0; i < segments.size(); i++) { 136 SlipstreamSegment curr = segments.get(i); 137 while (lengthSoFar < curr.totalLength + curr.lengthToNext) { 138 int lengthIndex = lengthSoFar / lengthDivisor; 139 if (lengthIndex < lengthToIndexMap.length) { 140 lengthToIndexMap[lengthIndex] = i; 141 } 142 lengthSoFar += lengthDivisor; 143 } 144 } 145 } 146 147 public SlipstreamSegment getSegmentForDist(float distAlongStream) { 148 if (lengthToIndexMap == null) return null; 149 int mapIndex = (int) (distAlongStream / lengthDivisor); 150 if (mapIndex < 0 || mapIndex >= lengthToIndexMap.length) return null; 151 //System.out.println("Index: " + mapIndex + ", dist: " + distAlongStream); 152 int segIndex = lengthToIndexMap[mapIndex]; 153 SlipstreamSegment segment = segments.get(segIndex); 154 while (distAlongStream < segment.totalLength) { 155 segIndex--; 156 if (segIndex < 0) return null; 157 segment = segments.get(segIndex); 158 } 159 while (distAlongStream > segment.totalLength + segment.lengthToNext) { 160 segIndex++; 161 if (segIndex >= segments.size()) return null; 162 segment = segments.get(segIndex); 163 } 164 return segment; 165 } 166 167 public void addSegment(Vector2f loc, float width) { 168 SlipstreamSegment s = new SlipstreamSegment(); 169 s.loc.set(loc); 170 s.width = width; 171 172 float minRadius = 0f; 173 float maxRadius = s.width * 0.05f; 174 float rate = maxRadius * 0.5f; 175 float angleRate = 50f; 176 s.wobble1 = new MutatingVertexUtil(minRadius, maxRadius, rate, angleRate); 177 s.wobble2 = new MutatingVertexUtil(minRadius, maxRadius, rate, angleRate); 178 179 s.fader.fadeIn(); 180 181 segments.add(s); 182 setNeedsRecompute(); 183 } 184 185 public void init(SectorEntityToken entity, Object pluginParams) { 186 super.init(entity, pluginParams); 187 this.params = (SlipstreamParams2) pluginParams; 188 fader.fadeIn(); 189 readResolve(); 190 } 191 192 public float getRenderRange() { 193 return totalLength * 0.6f + 1000f; 194 //return totalLength + 1000f; 195 } 196 197 Object readResolve() { 198 if (particles == null) { 199 particles = new ArrayList<SlipstreamParticle>(); 200 } 201 return this; 202 } 203 204 public void advance(float amount) { 205 if (!entity.isInCurrentLocation()) return; 206 207 applyEffectToFleets(amount); 208 209 fader.advance(amount); 210 211 212// entity.getLocation().x += Misc.getSpeedForBurnLevel(params.burnLevel) * amount; 213// entity.setFacing(0f); 214// entity.getLocation().set(Global.getSector().getPlayerFleet().getLocation().x + 500, 215// Global.getSector().getPlayerFleet().getLocation().y + 1000f); 216// entity.getLocation().set(Global.getSector().getPlayerFleet().getLocation()); 217 218 params.minColor = new Color(0.5f, 0.3f, 0.75f, 0.85f); 219 params.maxColor = new Color(0.5f, 0.6f, 1f, 1f); 220 params.spriteColor = new Color(0.3f, 0.5f, 1f, 1f); 221 params.minDur = 1f; 222 params.maxDur = 4f; 223 params.minSpeed = 700f; 224 params.maxSpeed = 1500f; 225 //params.lineLengthFractionOfSpeed = 0.5f; 226 //params.lineLengthFractionOfSpeed = 1f; 227 //params.lineLengthFractionOfSpeed = 0.15f; 228 params.burnLevel = 30; 229 //params.burnLevel = 1000; 230 //params.particleFadeInTime = 0.01f; 231 params.minSpeed = Misc.getSpeedForBurnLevel(params.burnLevel - 5); 232 params.maxSpeed = Misc.getSpeedForBurnLevel(params.burnLevel + 5); 233 params.lineLengthFractionOfSpeed = 0.25f * Math.max(0.25f, Math.min(1f, 30f / (float) params.burnLevel)); 234 //params.burnLevel = 200; 235 //params.numParticles = 2000; 236 //params.numParticles = 1; 237 params.minColor = new Color(0.5f, 0.3f, 0.75f, 0.1f); 238 params.maxColor = new Color(0.5f, 0.6f, 1f, 0.5f); 239 240 241 float width = 512; 242 params.widthForMaxSpeed = width; 243 params.slowDownInWiderSections = true; 244 params.widthForMaxSpeedMinMult = 0.5f; 245 246 params.edgeWidth = 256f; 247 params.spriteColor = new Color(0.3f, 0.5f, 1f, 0.5f); 248 params.edgeColor = new Color(0.3f, 0.5f, 1f, 0.75f); 249 params.edgeColor = Color.white; 250 251 //params.edgeWidth = 128f; 252 //params.minDur = 2f; 253 //params.maxDur = 2f; 254 params.minDur = 2f; 255 params.maxDur = 6f; 256 257 params.areaPerParticle = 10000; 258 //params.areaPerParticle = 10f; 259 //params.maxParticles = 100000; 260 //MAX_PARTICLES_ADD_PER_FRAME = 2000; 261 262 263// params.minSpeed = Misc.getSpeedForBurnLevel(16f); 264// params.maxSpeed = Misc.getSpeedForBurnLevel(16f); 265// params.numParticles = 0; 266 267 //segments.clear(); 268// if (segments.isEmpty()) { 269// float currX = entity.getLocation().x + 200f; 270// addSegment(new Vector2f(currX, entity.getLocation().y), 1600f); 271// currX += 200f; 272// addSegment(new Vector2f(currX, entity.getLocation().y), 1200f); 273// currX += 300f; 274// addSegment(new Vector2f(currX, entity.getLocation().y), 800f); 275// currX += 400f; 276// addSegment(new Vector2f(currX, entity.getLocation().y), 700f); 277// currX += 500f; 278// addSegment(new Vector2f(currX, entity.getLocation().y), 600f); 279// currX += 600f; 280// addSegment(new Vector2f(currX, entity.getLocation().y), 512f); 281// } 282 if (segments.isEmpty()) { 283 float spacing = 200f; 284// for (int i = 0; i < 100; i++) { 285// addSegment(new Vector2f(entity.getLocation().x + i * spacing, entity.getLocation().y), params.width); 286// } 287// float x = segments.get(segments.size() - 1).loc.x; 288// float y = segments.get(segments.size() - 1).loc.y; 289// addSegment(new Vector2f(x + 200f, y - 100f), params.width); 290// addSegment(new Vector2f(x + 400f, y - 200f), params.width); 291// addSegment(new Vector2f(x + 600f, y - 300f), params.width); 292// addSegment(new Vector2f(x + 800f, y - 400f), params.width); 293// addSegment(new Vector2f(x + 1000f, y - 500f), params.width); 294// addSegment(new Vector2f(x + 1000f, y - 600f), params.width); 295// addSegment(new Vector2f(x + 800f, y - 700f), params.width); 296// addSegment(new Vector2f(x + 600f, y - 800f), params.width); 297// addSegment(new Vector2f(x + 400f, y - 900f), params.width); 298// addSegment(new Vector2f(x + 200f, y - 1000f), params.width); 299// for (int i = 100; i >= 0; i--) { 300// addSegment(new Vector2f(entity.getLocation().x + i * spacing, entity.getLocation().y - 1100), params.width); 301// } 302 303 int iter = 1000; 304 for (int i = 0; i < iter; i++) { 305 float yOff = (float) Math.sin(i * 0.05f); 306 addSegment(new Vector2f(entity.getLocation().x + i * spacing, 307 //addSegment(new Vector2f(entity.getLocation().x + i * (spacing + (50 - i) * 5), 308 entity.getLocation().y + yOff * 2000f), 309 //width); 310 //width * (0.7f + (float) Math.random() * 0.7f)); 311 width + i * 10f); 312 } 313// float spacing = 1000f; 314// for (int i = 0; i < 500; i++) { 315// float yOff = 0f; 316// addSegment(new Vector2f(entity.getLocation().x + i * spacing, 317// //addSegment(new Vector2f(entity.getLocation().x + i * (spacing + (50 - i) * 5), 318// entity.getLocation().y + yOff * 2000f), 319// //width); 320// //width * (0.7f + (float) Math.random() * 0.7f)); 321// width + 500f + i * 2f); 322// } 323 } 324 325 recomputeIfNeeded(); 326 advanceNearbySegments(amount); 327 328 addParticles(); 329 advanceParticles(amount); 330 } 331 332 333 public void recomputeIfNeeded() { 334 if (!needsRecompute) return; 335 recompute(); 336 } 337 338 public void recompute() { 339 needsRecompute = false; 340 341 // compute average location, set segment indices 342 Vector2f avgLoc = new Vector2f(); 343 for (int i = 0; i < segments.size(); i++) { 344 SlipstreamSegment curr = segments.get(i); 345 curr.index = i; 346 Vector2f.add(avgLoc, curr.loc, avgLoc); 347 } 348 349 if (segments.size() > 0) { 350 avgLoc.scale(1f / segments.size()); 351 entity.setLocation(avgLoc.x, avgLoc.y); 352 } 353 354 355 SpriteAPI sprite = Global.getSettings().getSprite("misc", params.spriteKey1); 356 SpriteAPI edge = Global.getSettings().getSprite("misc", params.edgeKey); 357 358 // compute texture coordinates etc 359 float tx = 0f; 360 float txe1 = 0f; 361 float txe2 = 0f; 362 float totalLength = 0f; 363 for (int i = 0; i < segments.size(); i++) { 364 SlipstreamSegment prev = null; 365 if (i > 0) prev = segments.get(i - 1); 366 SlipstreamSegment curr = segments.get(i); 367 SlipstreamSegment next = null; 368 SlipstreamSegment next2 = null; 369 SlipstreamSegment next3 = null; 370 if (i < segments.size() - 1) { 371 next = segments.get(i + 1); 372 } 373 if (i < segments.size() - 2) { 374 next2 = segments.get(i + 2); 375 } 376 if (i < segments.size() - 3) { 377 next3 = segments.get(i + 3); 378 } 379 380 if (next == null) { 381 if (prev != null) { 382 curr.dir.set(prev.dir); 383 } 384 } else { 385 Vector2f dir = Vector2f.sub(next.loc, curr.loc, new Vector2f()); 386 dir = Misc.normalise(dir); 387 curr.dir = dir; 388 } 389 390 Vector2f dir = curr.dir; 391 Vector2f normal = new Vector2f(-dir.y, dir.x); 392 curr.normal.set(normal); 393 394 float length = 0f; 395 float texLength = 0f; 396 float e1TexLength = 0f; 397 float e2TexLength = 0f; 398 if (prev != null) { 399 Vector2f dir2 = Vector2f.sub(curr.loc, prev.loc, new Vector2f()); 400 length = dir2.length(); 401 texLength = length / sprite.getWidth(); 402 texLength = Math.min(texLength, sprite.getHeight() / curr.width); 403 404 Vector2f edgeCurr = new Vector2f(curr.loc); 405 edgeCurr.x += curr.normal.x * curr.width * 0.5f; 406 edgeCurr.y += curr.normal.y * curr.width * 0.5f; 407 408 Vector2f edgePrev = new Vector2f(prev.loc); 409 edgePrev.x += prev.normal.x * prev.width * 0.5f; 410 edgePrev.y += prev.normal.y * prev.width * 0.5f; 411 412 float length2 = Vector2f.sub(edgeCurr, edgePrev, new Vector2f()).length(); 413 e1TexLength = length2 / edge.getWidth() * edge.getHeight() / params.edgeWidth; 414 415 416 edgeCurr = new Vector2f(curr.loc); 417 edgeCurr.x -= curr.normal.x * curr.width * 0.5f; 418 edgeCurr.y -= curr.normal.y * curr.width * 0.5f; 419 420 edgePrev = new Vector2f(prev.loc); 421 edgePrev.x -= prev.normal.x * prev.width * 0.5f; 422 edgePrev.y -= prev.normal.y * prev.width * 0.5f; 423 424 length2 = Vector2f.sub(edgeCurr, edgePrev, new Vector2f()).length(); 425 e2TexLength = length2 / edge.getWidth() * edge.getHeight() / params.edgeWidth; 426 } 427 428 tx += texLength; 429 txe1 += e1TexLength; 430 txe2 += e2TexLength; 431 curr.tx = tx; 432 curr.txe1 = txe1; 433 curr.txe2 = txe2; 434 curr.lengthToPrev = length; 435 436 totalLength += length; 437 curr.totalLength = totalLength; 438 //curr.lengthToNext = Misc.getDistance(curr.loc, next.loc); 439 if (prev != null) { 440 prev.lengthToNext = length; 441 } 442 443 if (next != null && next2 != null && next3 != null) { 444 Vector2f p0 = curr.loc; 445 Vector2f p1 = next.loc; 446 Vector2f p2 = next2.loc; 447 Vector2f p3 = next3.loc; 448 449 float p1ToP2 = Misc.getAngleInDegrees(p1, p2); 450 float p2ToP3 = Misc.getAngleInDegrees(p2, p3); 451 float diff = Misc.getAngleDiff(p1ToP2, p2ToP3); 452 float adjustment = Math.min(diff, Math.max(diff * 0.25f, diff - 10f)); 453 adjustment = diff * 0.5f; 454 //adjustment = diff * 0.25f; 455 float angle = p1ToP2 + Misc.getClosestTurnDirection(p1ToP2, p2ToP3) * adjustment * 1f + 180f; 456 //angle = Misc.getAngleInDegrees(p3, p2); 457 float dist = Misc.getDistance(p2, p1); 458 Vector2f p1Adjusted = Misc.getUnitVectorAtDegreeAngle(angle); 459 p1Adjusted.scale(dist); 460 Vector2f.add(p1Adjusted, p2, p1Adjusted); 461 next.locB = p1Adjusted; 462 } else if (next != null) { 463 next.locB = next.loc; 464 } 465 if (prev == null) { 466 curr.locB = new Vector2f(curr.loc); 467 } 468 } 469 this.totalLength = totalLength; 470 471 updateLengthToIndexMap(); 472 updateBoundingBoxes(); 473 } 474 475 protected void updateBoundingBoxes() { 476 segmentsPerBox = (int) Math.sqrt(segments.size()) + 1; 477 if (segmentsPerBox < 20) segmentsPerBox = 20; 478 479 bounds.clear(); 480 for (int i = 0; i < segments.size(); i+= segmentsPerBox) { 481 List<SlipstreamSegment> section = new ArrayList<SlipstreamSegment>(); 482 for (int j = i; j < i + segmentsPerBox && j < segments.size(); j++) { 483 section.add(segments.get(j)); 484 } 485 if (i + segmentsPerBox < segments.size()) { 486 section.add(segments.get(i + segmentsPerBox)); 487 } 488 //BoundingBox box = BoundingBox.create(section); 489 //bounds.add(box); 490 } 491 } 492 493 protected void advanceNearbySegments(float amount) { 494 CampaignFleetAPI pf = Global.getSector().getPlayerFleet(); 495 if (pf == null || !entity.isInCurrentLocation()) { 496 return; 497 } 498 499 if (segments.size() > 0) { 500 segments.get(0).fader.forceOut(); 501 segments.get(segments.size() - 1).fader.fadeOut(); 502 } 503 504 ViewportAPI viewport = Global.getSector().getViewport(); 505 float viewRadius = new Vector2f(viewport.getVisibleWidth() * 0.5f, viewport.getVisibleHeight() * 0.5f).length(); 506 viewRadius = Math.max(6000f, viewRadius); 507 viewRadius += 1000f; 508 List<SlipstreamSegment> near = getSegmentsNear(viewport.getCenter(), viewRadius); 509 510 // advance fader and wobble, compute wobbledWidth 511 for (int i = 0; i < near.size(); i++) { 512 SlipstreamSegment curr = near.get(i); 513 514 curr.fader.advance(amount); 515 516 float r1 = 0.5f + (float) Math.random() * 1f; 517 float r2 = 0.5f + (float) Math.random() * 1f; 518 curr.wobble1.advance(amount * r1); 519 curr.wobble2.advance(amount * r2); 520// curr.wobble1.vector.set(0, 0); 521// curr.wobble2.vector.set(0, 0); 522 523 Vector2f p1 = new Vector2f(curr.loc); 524 Vector2f p2 = new Vector2f(curr.loc); 525 p1.x += curr.normal.x * curr.width * 0.5f; 526 p1.y += curr.normal.y * curr.width * 0.5f; 527 p2.x -= curr.normal.x * curr.width * 0.5f; 528 p2.y -= curr.normal.y * curr.width * 0.5f; 529 530 p1.x += curr.wobble1.vector.x; 531 p1.y += curr.wobble1.vector.y; 532 p2.x += curr.wobble2.vector.x; 533 p2.y += curr.wobble2.vector.y; 534 535 //curr.wobbledWidth = Misc.getDistance(p1, p2); 536 float d = Misc.getDistance(p1, p2); 537 curr.wobbledWidth = d - params.edgeWidth * 2f * 0.5f; 538 if (curr.wobbledWidth < d * 0.5f) curr.wobbledWidth = d * 0.5f; 539 //curr.wobbledWidth = curr.width; 540 541 if (curr.index > 0) { 542 SlipstreamSegment prev = segments.get(curr.index - 1); 543 Vector2f prev1 = new Vector2f(prev.loc); 544 Vector2f prev2 = new Vector2f(prev.loc); 545 prev1.x += curr.normal.x * curr.width * 0.5f; 546 prev1.y += curr.normal.y * curr.width * 0.5f; 547 prev2.x -= curr.normal.x * curr.width * 0.5f; 548 prev2.y -= curr.normal.y * curr.width * 0.5f; 549 550 float maxWobbleRadius = Math.min(prev.width, curr.width) * 0.05f; 551 float maxWobble1 = Misc.getDistance(p1, prev1) * 0.33f; 552 float maxWobble2 = Misc.getDistance(p2, prev2) * 0.33f; 553 maxWobble1 = Math.min(maxWobbleRadius, maxWobble1); 554 maxWobble2 = Math.min(maxWobbleRadius, maxWobble2); 555 prev.wobble1.radius.setMax(maxWobble1); 556 prev.wobble2.radius.setMax(maxWobble2); 557 curr.wobble1.radius.setMax(maxWobble1); 558 curr.wobble2.radius.setMax(maxWobble2); 559 } 560 } 561 } 562 563 564 565 public void addParticles() { 566 if (Global.getSector().getPlayerFleet() == null) { 567 particles.clear(); 568 return; 569 } 570 571 boolean useNewSpawnMethod = true; 572 //useNewSpawnMethod = false; 573 574 if (useNewSpawnMethod) { 575 boolean inCurrentLocation = entity.isInCurrentLocation(); 576 boolean inHyperspace = entity.isInHyperspace(); 577 boolean spawnForAllSegments = false; 578 ViewportAPI viewport = Global.getSector().getViewport(); 579 Vector2f locFrom = viewport.getCenter(); 580 float viewRadius = new Vector2f(viewport.getVisibleWidth() * 0.5f, viewport.getVisibleHeight() * 0.5f).length(); 581 viewRadius += 2000f; 582 viewRadius = Math.max(viewRadius, 10000f); 583 if (!inCurrentLocation) { 584 if (inHyperspace) { 585 viewRadius = 5000f; 586 locFrom = Global.getSector().getPlayerFleet().getLocationInHyperspace(); 587 } else { 588 float dist = Misc.getDistanceToPlayerLY(entity); 589 spawnForAllSegments = dist < 2f; 590 } 591 } 592 Set<SlipstreamSegment> veryNearSet = new LinkedHashSet<SlipstreamEntityPlugin2.SlipstreamSegment>(); 593 if (inCurrentLocation) { 594 float veryNearRadius = new Vector2f(viewport.getVisibleWidth() * 0.5f, viewport.getVisibleHeight() * 0.5f).length(); 595 viewRadius += 500f; 596 veryNearSet = new LinkedHashSet<SlipstreamEntityPlugin2.SlipstreamSegment>( 597 getSegmentsNear(viewport.getCenter(), veryNearRadius)); 598 } 599 600 // viewRadius *= 0.5f; 601 // viewRadius = 500f; 602 603 List<SlipstreamSegment> near; 604 if (spawnForAllSegments) { 605 near = new ArrayList<SlipstreamSegment>(segments); 606 } else { 607 near = getSegmentsNear(locFrom, viewRadius); 608 } 609 Set<SlipstreamSegment> nearSet = new LinkedHashSet<SlipstreamSegment>(near); 610 611 Map<SlipstreamSegment, List<SlipstreamParticle>> particleMap = new LinkedHashMap<SlipstreamEntityPlugin2.SlipstreamSegment, List<SlipstreamParticle>>(); 612 //for (SlipstreamParticle p : particles) { 613 Iterator<SlipstreamParticle> iter = particles.iterator(); 614 while (iter.hasNext()) { 615 SlipstreamParticle p = iter.next(); 616 SlipstreamSegment seg = getSegmentForDist(p.dist); 617 if (seg != null) { 618 if (!nearSet.contains(seg)) { 619 iter.remove(); 620 continue; 621 } 622 623 List<SlipstreamParticle> list = particleMap.get(seg); 624 if (list == null) { 625 list = new ArrayList<SlipstreamEntityPlugin2.SlipstreamParticle>(); 626 particleMap.put(seg, list); 627 } 628 list.add(p); 629 } 630 } 631 632 633 float totalArea = 0f; 634 int nearParticles = 0; 635 WeightedRandomPicker<SlipstreamSegment> segmentPicker = new WeightedRandomPicker<SlipstreamEntityPlugin2.SlipstreamSegment>(); 636 637 // figure out how many particles to add total, and also which segments to add them 638 // to to achieve a relatively even distribution 639 for (int i = 0; i < near.size(); i++) { 640 SlipstreamSegment curr = near.get(i); 641 if (curr.lengthToNext <= 0) continue; // last segment, can't have particles in it since the stream is over 642 643 float area = curr.lengthToNext * curr.width; 644 float desiredParticles = area / params.areaPerParticle; 645 if (desiredParticles < 1) desiredParticles = 1; 646 647 float particlesInSegment = 0; 648 List<SlipstreamParticle> list = particleMap.get(curr); 649 if (list != null) { 650 particlesInSegment = list.size(); 651 } 652 653 float mult = 1f; 654 // spawn more particles in visible/nearly visible areas 655 // better to have less visible particles when the player zooms out while paused 656 // than to have less visible particles when zoomed in 657 if (veryNearSet.contains(curr)) mult = 10f; 658 659 float w = desiredParticles - particlesInSegment; 660 w *= mult; 661 if (w < 5f) w = 5f; 662 segmentPicker.add(curr, w); 663 //segmentPicker.add(curr, 1f); 664 665 totalArea += area; 666 nearParticles += particlesInSegment; 667 } 668 669 670 int numParticlesBasedOnArea = (int) (totalArea / params.areaPerParticle); 671 int actualDesired = numParticlesBasedOnArea; 672 if (numParticlesBasedOnArea < 10) numParticlesBasedOnArea = 10; 673 if (numParticlesBasedOnArea > params.maxParticles) numParticlesBasedOnArea = params.maxParticles; 674 //System.out.println("Area: " + totalArea/params.numParticles); 675 //numParticlesBasedOnArea = 20000; 676 677 678 int particlesToAdd = numParticlesBasedOnArea - nearParticles; 679 if (particlesToAdd > MAX_PARTICLES_ADD_PER_FRAME) { 680 particlesToAdd = MAX_PARTICLES_ADD_PER_FRAME; 681 } 682 particlesToAdd = Math.min(particlesToAdd, params.maxParticles - particles.size()); 683 684 int added = 0; 685 while (added < particlesToAdd) { 686 added++; 687 SlipstreamSegment seg = segmentPicker.pick(); 688 if (seg == null) continue; 689 690 SlipstreamParticle p = new SlipstreamParticle(); 691 float fLength = (float) Math.random() * 1f; 692 float fWidth = (float) Math.random() * 2f - 1f; 693 694 float speed = params.minSpeed + (params.maxSpeed - params.minSpeed) * (float) Math.random(); 695 float dur = params.minDur + (params.maxDur - params.minDur) * (float) Math.random(); 696 697 p.yPos = fWidth; 698 //p.dist = totalLength * fLength; 699 p.dist = seg.totalLength + seg.lengthToNext * fLength; 700 p.speed = speed; 701 702 float intensity = getIntensity(p.yPos); 703 float wMult = getWidthBasedSpeedMult(p.dist); 704 // if (wMult <= 0) { 705 // getWidthBasedSpeedMult(p.dist); 706 // } 707 float speedMult = (0.65f + 0.35f * intensity) * wMult; 708 p.speed *= speedMult; 709 710 p.remaining = dur; 711 p.color = getRandomColor(); 712 713 particles.add(p); 714 } 715 716 //System.out.println("Particles: " + particles.size() + " desired based on area: " + actualDesired); 717 718 } else { 719 float totalArea = 0f; 720 for (int i = 0; i < segments.size(); i++) { 721 SlipstreamSegment curr = segments.get(i); 722 totalArea += curr.lengthToPrev * curr.width; 723 } 724 725 int numParticlesBasedOnArea = (int) (totalArea / params.areaPerParticle); 726 if (numParticlesBasedOnArea < 10) numParticlesBasedOnArea = 10; 727 if (numParticlesBasedOnArea > params.maxParticles) numParticlesBasedOnArea = params.maxParticles; 728 //System.out.println("Area: " + totalArea/params.numParticles); 729 //numParticlesBasedOnArea = 20000; 730 731 732 int added = 0; 733 //while (particles.size() < params.numParticles && added < MAX_PARTICLES_ADD_PER_FRAME) { 734 while (particles.size() < numParticlesBasedOnArea && added < MAX_PARTICLES_ADD_PER_FRAME) { 735 added++; 736 737 SlipstreamParticle p = new SlipstreamParticle(); 738 float fLength = (float) Math.random() * 1f; 739 float fWidth = (float) Math.random() * 2f - 1f; 740 741 float speed = params.minSpeed + (params.maxSpeed - params.minSpeed) * (float) Math.random(); 742 float dur = params.minDur + (params.maxDur - params.minDur) * (float) Math.random(); 743 744 p.yPos = fWidth; 745 p.dist = totalLength * fLength; 746 p.speed = speed; 747 748 float intensity = getIntensity(p.yPos); 749 float wMult = getWidthBasedSpeedMult(p.dist); 750 // if (wMult <= 0) { 751 // getWidthBasedSpeedMult(p.dist); 752 // } 753 float speedMult = (0.65f + 0.35f * intensity) * wMult; 754 p.speed *= speedMult; 755 756 p.remaining = dur; 757 p.color = getRandomColor(); 758 759 particles.add(p); 760 } 761 } 762 } 763 764 public void advanceParticles(float amount) { 765 Iterator<SlipstreamParticle> iter = particles.iterator(); 766 while (iter.hasNext()) { 767 SlipstreamParticle p = iter.next(); 768 p.remaining -= amount; 769 p.elapsed += amount; 770 if (p.remaining <= 0) { 771 iter.remove(); 772 continue; 773 } 774 775 p.dist += p.speed * amount; 776 } 777 } 778 779 public float getWidthBasedSpeedMult(float distAlong) { 780 float mult = 1f; 781 if (params.slowDownInWiderSections) { 782 SlipstreamSegment curr = getSegmentForDist(distAlong); 783 if (curr != null) { 784 float width = curr.width; 785 if (segments.size() > curr.index + 1) { 786 SlipstreamSegment next = segments.get(curr.index + 1); 787 float f = (distAlong - curr.totalLength) / curr.lengthToNext; 788 if (f < 0) f = 0; 789 if (f > 1) f = 1; 790 width = Misc.interpolate(width, next.width, f); 791 mult = Math.min(params.widthForMaxSpeedMaxMult, 792 params.widthForMaxSpeedMinMult + (1f - params.widthForMaxSpeedMinMult) * params.widthForMaxSpeed / width); 793 } 794 } 795 } 796 return mult; 797 } 798 public float getIntensity(float yOff) { 799 yOff = Math.abs(yOff); 800 float intensity = 1f; 801 if (yOff > 0.5f) { 802 intensity = 1f - 1f * (yOff - 0.5f) / 0.5f; 803 } 804 return intensity; 805 } 806 807 public float getFaderBrightness(float distAlong) { 808 SlipstreamSegment curr = getSegmentForDist(distAlong); 809 if (curr != null) { 810 if (segments.size() > curr.index + 1) { 811 SlipstreamSegment next = segments.get(curr.index + 1); 812 float f = (distAlong - curr.totalLength) / curr.lengthToNext; 813 if (f < 0) f = 0; 814 if (f > 1) f = 1; 815 return Misc.interpolate(curr.fader.getBrightness(), next.fader.getBrightness(), f); 816 } else { 817 return 0f; 818 } 819 } 820 return 0f; 821 } 822 823 public void render(CampaignEngineLayers layer, ViewportAPI viewport) { 824 recomputeIfNeeded(); 825 if (lengthToIndexMap == null) return; 826 827 828 if (true && false) { 829 //BoundingBox box = BoundingBox.create(segments); 830 float mx = Mouse.getX(); 831 float my = Mouse.getY(); 832 float wmx = Global.getSector().getViewport().convertScreenXToWorldX(mx); 833 float wmy = Global.getSector().getViewport().convertScreenYToWorldY(my); 834 boolean inside = false; 835 for (BoundingBox box : bounds) { 836 box.renderDebug(1f); 837 inside |= box.pointNeedsDetailedCheck(new Vector2f(wmx, wmy)); 838 } 839 840 GL11.glDisable(GL11.GL_TEXTURE_2D); 841 GL11.glEnable(GL11.GL_BLEND); 842 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); 843 844 GL11.glPointSize(20f); 845 GL11.glEnable(GL11.GL_POINT_SMOOTH); 846 if (inside) { 847 Misc.setColor(Color.green); 848 } else { 849 Misc.setColor(Color.gray); 850 } 851 852 GL11.glBegin(GL11.GL_POINTS); 853 GL11.glVertex2f(wmx, wmy); 854 GL11.glEnd(); 855 //return; 856 } 857 858 859 860 861 float viewRadius = new Vector2f(viewport.getVisibleWidth() * 0.5f, viewport.getVisibleHeight() * 0.5f).length(); 862 viewRadius += 500f; 863 864// viewRadius *= 0.5f; 865// viewRadius = 500f; 866 867 List<SlipstreamSegment> near = getSegmentsNear(viewport.getCenter(), viewRadius); 868 Set<SlipstreamSegment> nearSet = new LinkedHashSet<SlipstreamSegment>(near); 869 870 List<List<SlipstreamSegment>> subsections = new ArrayList<List<SlipstreamSegment>>(); 871 int prevIndex = -10; 872 List<SlipstreamSegment> subsection = new ArrayList<SlipstreamSegment>(); 873 for (SlipstreamSegment seg : near) { 874 if (prevIndex != seg.index -1) { 875 if (subsection != null && !subsection.isEmpty()) { 876 subsections.add(subsection); 877 } 878 subsection = new ArrayList<SlipstreamSegment>(); 879 } 880 subsection.add(seg); 881 prevIndex = seg.index; 882 } 883 if (subsection != null && !subsection.isEmpty()) { 884 subsections.add(subsection); 885 } 886 887 SpriteAPI sprite = Global.getSettings().getSprite("misc", params.spriteKey1); 888 //sprite.setAdditiveBlend(); 889 sprite.setNormalBlend(); 890 sprite.setColor(params.spriteColor); 891 892 SpriteAPI edge = Global.getSettings().getSprite("misc", params.edgeKey); 893 edge.setNormalBlend(); 894 edge.setColor(params.edgeColor); 895 896 //sprite.setColor(Misc.setAlpha(params.spriteColor1, 255)); 897 //sprite.setColor(Color.blue); 898 for (List<SlipstreamSegment> subsection2 : subsections) { 899 renderSegments(sprite, edge, viewport.getAlphaMult(), subsection2); 900 } 901 902 //sprite.setColor(Color.red); 903 //renderLayer(sprite, texProgress2, viewport.getAlphaMult()); 904 //sprite.setColor(Color.green); 905 //renderLayer(sprite, texProgress3, viewport.getAlphaMult()); 906 907// int state = 0; 908// for (int i = 0; i < segments.size() - 4; i += 2) { 909// //GL11.glBegin(GL11.GL_POINTS); 910// SlipstreamSegment prev = null; 911// if (i > 0) { 912// prev = segments.get(i - 1); 913// } 914// SlipstreamSegment curr = segments.get(i); 915// SlipstreamSegment next = segments.get(i + 1); 916// SlipstreamSegment next2 = segments.get(i + 2); 917// SlipstreamSegment next3 = segments.get(i + 3); 918// Vector2f p0 = curr.loc; 919// Vector2f p1 = next.loc; 920// Vector2f p2 = next2.loc; 921// Vector2f p3 = next3.loc; 922// 923// if (state == 0) { 924// state = 1; 925// float p1ToP2 = Misc.getAngleInDegrees(p1, p2); 926// float p2ToP3 = Misc.getAngleInDegrees(p2, p3); 927// float diff = Misc.getAngleDiff(p1ToP2, p2ToP3); 928// float angle = p1ToP2 + Misc.getClosestTurnDirection(p1ToP2, p2ToP3) * diff * 0.5f + 180f; 929// angle = Misc.getAngleInDegrees(p3, p2); 930// float dist = Misc.getDistance(p2, p1); 931// Vector2f p1Adjusted = Misc.getUnitVectorAtDegreeAngle(angle); 932// p1Adjusted.scale(dist); 933// Vector2f.add(p1Adjusted, p2, p1Adjusted); 934// curr.locB.set(p1Adjusted); 935// } else if (state == 1) { 936// curr.locB.set(curr.loc); 937// } else if (state == 2) { 938// 939// } 940// } 941 942 943 944 945 946 GL11.glDisable(GL11.GL_TEXTURE_2D); 947 GL11.glEnable(GL11.GL_BLEND); 948 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); 949 950 float zoom = Global.getSector().getViewport().getViewMult(); 951 952 //GL11.glLineWidth(2f); 953 //GL11.glLineWidth(Math.max(1f, 2f/zoom)); 954 GL11.glLineWidth(Math.max(1f, Math.min(2f, 2f/zoom))); 955 //GL11.glLineWidth(1.5f); 956 GL11.glEnable(GL11.GL_LINE_SMOOTH); 957 958 Misc.setColor(new Color(1f, 1f, 1f, 0.5f)); 959 Misc.setColor(Color.white); 960 //GL11.glLineWidth(1f); 961 962// for (SlipstreamSegment seg : segments) { 963// if (seg.totalLength <= 0f && segments.indexOf(seg) > 1) { 964// System.out.println("efwefwefwefe"); 965// } 966// } 967 968 // draw bezier lines for debug 969 for (float offset = -1f; false && offset <= 1f; offset += 0.1f) { 970 //for (float offset = 0f; offset <= 0f; offset += 0.1f) { 971 GL11.glBegin(GL11.GL_LINE_STRIP); 972 float incr = 10f; 973 for (float len = 0; len < totalLength; len += incr) { 974// if (len > 10000f) { 975// System.out.println("ewfwefew"); 976// } 977 /* 978 SlipstreamSegment curr = getSegmentForDist(len); 979 if (curr == null) continue; 980 int index = curr.index; 981 if (index >= segments.size() - 2) continue; 982 SlipstreamSegment next = segments.get(index + 1); 983 SlipstreamSegment next2 = segments.get(index + 2); 984 985 if (index % 2 != 0) { 986 curr = segments.get(index - 1); 987 next = segments.get(index); 988 next2 = segments.get(index + 1); 989 } 990 991 float lenForT = len - curr.totalLength; 992 float t = lenForT / (curr.lengthToNext + next.lengthToNext); 993 994 //Vector2f p = Misc.bezier(curr.loc, next.loc, next2.loc, t); 995 Vector2f p0 = curr.loc; 996 Vector2f p1 = next.loc; 997 Vector2f p2 = next2.loc; 998 999 p0 = new Vector2f(p0); 1000 p0.x += curr.normal.x * params.width * 0.5f * offset; 1001 p0.y += curr.normal.y * params.width * 0.5f * offset; 1002 1003 p2 = new Vector2f(p2); 1004 p2.x += next2.normal.x * params.width * 0.5f * offset; 1005 p2.y += next2.normal.y * params.width * 0.5f * offset; 1006 1007 p1 = new Vector2f(next.locB); 1008 p1 = new Vector2f(p1); 1009 p1.x += next.normal.x * params.width * 0.5f * offset; 1010 p1.y += next.normal.y * params.width * 0.5f * offset; 1011 1012 Vector2f p = Misc.bezier(p0, p1, p2, t); 1013 1014// float tPrev = (prev.lengthToNext + len) / (prev.lengthToNext + curr.lengthToNext); 1015// Vector2f pPrev = Misc.bezier(prev.loc, curr.loc, next.loc, tPrev); 1016 //curr.lengthToNext + next.lengthToNext 1017// float f = lenForT / curr.lengthToNext; 1018// Vector2f perp; 1019// if (f < 1f) { 1020// perp = Misc.interpolateVector(curr.normal, next.normal, f); 1021// } else { 1022// f = (lenForT - curr.lengthToNext) / next.lengthToNext; 1023//// if (f > 1f) { 1024//// System.out.println("wefwefe " + index); 1025//// } 1026// perp = Misc.interpolateVector(next.normal, next2.normal, f); 1027// } 1028// perp.scale(offset * params.width * 0.5f); 1029 //perp.set(0, 0); 1030 1031 //p = Misc.interpolateVector(pPrev, p, 0.5f); 1032 //GL11.glVertex2f(p.x + perp.x, p.y + perp.y); 1033 * 1034 */ 1035 1036 Vector2f p = getPointAt(len, offset); 1037 if (p != null) { 1038 GL11.glVertex2f(p.x, p.y); 1039 } 1040 } 1041 if (false) { 1042 Misc.setColor(Color.red); 1043 for (int i = 0; i < segments.size() - 3; i+=2) { 1044 //GL11.glBegin(GL11.GL_POINTS); 1045 SlipstreamSegment prev = null; 1046 if (i > 0) { 1047 prev = segments.get(i - 1); 1048 } 1049 SlipstreamSegment curr = segments.get(i); 1050 SlipstreamSegment next = segments.get(i + 1); 1051 SlipstreamSegment next2 = segments.get(i + 2); 1052 SlipstreamSegment next3 = segments.get(i + 3); 1053 1054 // GL11.glVertex2f(curr.loc.x, curr.loc.y); 1055 // GL11.glVertex2f(next.loc.x, next.loc.y); 1056 // GL11.glVertex2f(next2.loc.x, next2.loc.y); 1057 1058 Vector2f p0 = curr.loc; 1059 Vector2f p1 = next.loc; 1060 Vector2f p2 = next2.loc; 1061 Vector2f p3 = next3.loc; 1062 1063 // float p1ToP2 = Misc.getAngleInDegrees(p1, p2); 1064 // float p2ToP3 = Misc.getAngleInDegrees(p2, p3); 1065 // float diff = Misc.getAngleDiff(p1ToP2, p2ToP3); 1066 // float adjustment = Math.min(diff, Math.max(diff * 0.25f, diff - 10f)); 1067 // adjustment = diff * 0.5f; 1068 // //adjustment = diff * 0.25f; 1069 // float angle = p1ToP2 + Misc.getClosestTurnDirection(p1ToP2, p2ToP3) * adjustment * 1f + 180f; 1070 // //angle = Misc.getAngleInDegrees(p3, p2); 1071 // float dist = Misc.getDistance(p2, p1); 1072 // Vector2f p1Adjusted = Misc.getUnitVectorAtDegreeAngle(angle); 1073 // p1Adjusted.scale(dist); 1074 // Vector2f.add(p1Adjusted, p2, p1Adjusted); 1075 1076 //GL11.glVertex2f(p1Adjusted.x, p1Adjusted.y); 1077 //GL11.glVertex2f(p1.x, p1.y); 1078 1079 p0 = new Vector2f(p0); 1080 p0.x += curr.normal.x * curr.width * 0.5f * offset; 1081 p0.y += curr.normal.y * curr.width * 0.5f * offset; 1082 1083 p2 = new Vector2f(p2); 1084 p2.x += next2.normal.x * next2.width * 0.5f * offset; 1085 p2.y += next2.normal.y * next2.width * 0.5f * offset; 1086 1087 p1 = new Vector2f(next.locB); 1088 p1 = new Vector2f(p1); 1089 p1.x += next.normal.x * next.width * 0.5f * offset; 1090 p1.y += next.normal.y * next.width * 0.5f * offset; 1091 1092 // p1ToP2 = Misc.getAngleInDegrees(p1, p2); 1093 // p2ToP3 = Misc.getAngleInDegrees(p2, p3); 1094 // diff = Misc.getAngleDiff(p1ToP2, p2ToP3); 1095 // adjustment = Math.min(diff, Math.max(diff * 0.25f, diff - 10f)); 1096 // adjustment = diff * 0.5f; 1097 // //adjustment = diff * 0.25f; 1098 // angle = p1ToP2 + Misc.getClosestTurnDirection(p1ToP2, p2ToP3) * adjustment * 1f + 180f; 1099 // //angle = Misc.getAngleInDegrees(p3, p2); 1100 // dist = Misc.getDistance(p2, p1); 1101 // p1Adjusted = Misc.getUnitVectorAtDegreeAngle(angle); 1102 // p1Adjusted.scale(dist); 1103 // Vector2f.add(p1Adjusted, p2, p1Adjusted); 1104 1105 incr = 10f; 1106 for (float len = 0; len < curr.lengthToNext + next.lengthToNext; len += incr) { 1107 float t = len / (curr.lengthToNext + next.lengthToNext); 1108 //Vector2f p = Misc.bezier(curr.loc, next.loc, next2.loc, t); 1109 Vector2f p = Misc.bezier(p0, p1, p2, t); 1110 1111 // float tPrev = (prev.lengthToNext + len) / (prev.lengthToNext + curr.lengthToNext); 1112 // Vector2f pPrev = Misc.bezier(prev.loc, curr.loc, next.loc, tPrev); 1113 1114 float f = len / curr.lengthToNext; 1115 Vector2f perp; 1116 if (f < 1f) { 1117 perp = Misc.interpolateVector(curr.normal, next.normal, f); 1118 } else { 1119 f = (len - curr.lengthToNext) / next.lengthToNext; 1120 perp = Misc.interpolateVector(next.normal, next2.normal, f); 1121 } 1122 perp.scale(offset * curr.width * 0.5f); 1123 perp.set(0, 0); 1124 1125 //p = Misc.interpolateVector(pPrev, p, 0.5f); 1126 GL11.glVertex2f(p.x, p.y); 1127 //GL11.glVertex2f(p.x + perp.x, p.y + perp.y); 1128 //GL11.glVertex2f(pPrev.x, pPrev.y); 1129 } 1130 //if (i == 4) break; 1131 } 1132 } 1133 GL11.glEnd(); 1134 } 1135 1136// GL11.glBegin(GL11.GL_LINES); 1137// for (int i = 0; i < segments.size() - 4; i+=2) { 1138// //GL11.glBegin(GL11.GL_POINTS); 1139// SlipstreamSegment prev = null; 1140// if (i > 0) { 1141// prev = segments.get(i - 1); 1142// } 1143// SlipstreamSegment curr = segments.get(i); 1144// SlipstreamSegment next = segments.get(i + 1); 1145// SlipstreamSegment next2 = segments.get(i + 2); 1146// SlipstreamSegment next3 = segments.get(i + 3); 1147// 1148//// GL11.glVertex2f(curr.loc.x, curr.loc.y); 1149//// GL11.glVertex2f(next.loc.x, next.loc.y); 1150//// GL11.glVertex2f(next2.loc.x, next2.loc.y); 1151// 1152// Vector2f p0 = curr.loc; 1153// Vector2f p1 = next.loc; 1154// Vector2f p2 = next2.loc; 1155// Vector2f p3 = next3.loc; 1156// 1157// float p1ToP2 = Misc.getAngleInDegrees(p1, p2); 1158// float p2ToP3 = Misc.getAngleInDegrees(p2, p3); 1159// float diff = Misc.getAngleDiff(p1ToP2, p2ToP3); 1160// float adjustment = Math.min(diff, Math.max(diff * 0.25f, diff - 10f)); 1161// adjustment = diff * 0.5f; 1162// //adjustment = diff * 0.25f; 1163// float angle = p1ToP2 + Misc.getClosestTurnDirection(p1ToP2, p2ToP3) * adjustment * 1f + 180f; 1164// //angle = Misc.getAngleInDegrees(p3, p2); 1165// float dist = Misc.getDistance(p2, p1); 1166// Vector2f p1Adjusted = Misc.getUnitVectorAtDegreeAngle(angle); 1167// p1Adjusted.scale(dist); 1168// Vector2f.add(p1Adjusted, p2, p1Adjusted); 1169// 1170// //skip = diff < 30f; 1171// skip = false; 1172// if (skip) p1Adjusted.set(p1); 1173// skip = !skip; 1174// 1175// prevAdjustedP1 = p1Adjusted; 1176// //GL11.glVertex2f(p1Adjusted.x, p1Adjusted.y); 1177// //GL11.glVertex2f(p1.x, p1.y); 1178// 1179// float incr = 10f; 1180// Misc.setColor(new Color(1f, 0.5f, 0f, 1f)); 1181// for (float len = 0; len < curr.lengthToNext + next.lengthToNext; len += incr) { 1182// float t = len / (curr.lengthToNext + next.lengthToNext); 1183// //Vector2f p = Misc.bezier(curr.loc, next.loc, next2.loc, t); 1184// Vector2f p = Misc.bezier(curr.loc, p1Adjusted, next2.loc, t); 1185//// float tPrev = (prev.lengthToNext + len) / (prev.lengthToNext + curr.lengthToNext); 1186//// Vector2f pPrev = Misc.bezier(prev.loc, curr.loc, next.loc, tPrev); 1187// 1188// float f = len / curr.lengthToNext; 1189// Vector2f perp; 1190// if (f < 1f) { 1191// perp = Misc.interpolateVector(curr.normal, next.normal, f); 1192// } else { 1193// f = (len - curr.lengthToNext) / next.lengthToNext; 1194// perp = Misc.interpolateVector(next.normal, next2.normal, f); 1195// } 1196// 1197// 1198// perp.scale(1f * params.width * 0.5f); 1199// 1200// //p = Misc.interpolateVector(pPrev, p, 0.5f); 1201// //GL11.glVertex2f(p.x, p.y); 1202// GL11.glVertex2f(p.x + perp.x, p.y + perp.y); 1203// GL11.glVertex2f(p.x - perp.x, p.y - perp.y); 1204// //GL11.glVertex2f(pPrev.x, pPrev.y); 1205// } 1206// //if (i == 4) break; 1207// } 1208// GL11.glEnd(); 1209 1210// GL11.glPointSize(10); 1211// GL11.glBegin(GL11.GL_POINTS); 1212// for (int i = 0; i < segments.size() - 4; i+=2) { 1213// if (i % 4 == 0) { 1214// Misc.setColor(Color.red); 1215// } else { 1216// Misc.setColor(Color.green); 1217// } 1218// //GL11.glBegin(GL11.GL_POINTS); 1219// //SlipstreamSegment prev = segments.get(i); 1220// SlipstreamSegment curr = segments.get(i); 1221// SlipstreamSegment next = segments.get(i + 1); 1222// SlipstreamSegment next2 = segments.get(i + 2); 1223// SlipstreamSegment next3 = segments.get(i + 3); 1224// 1225//// GL11.glVertex2f(curr.loc.x, curr.loc.y); 1226//// GL11.glVertex2f(next.loc.x, next.loc.y); 1227//// GL11.glVertex2f(next2.loc.x, next2.loc.y); 1228// 1229// Vector2f p0 = curr.loc; 1230// Vector2f p1 = next.loc; 1231// Vector2f p2 = next2.loc; 1232// Vector2f p3 = next3.loc; 1233// 1234// float p1ToP2 = Misc.getAngleInDegrees(p1, p2); 1235// float p2ToP3 = Misc.getAngleInDegrees(p2, p3); 1236// float diff = Misc.getAngleDiff(p1ToP2, p2ToP3); 1237// float angle = p1ToP2 + Misc.getClosestTurnDirection(p1ToP2, p2ToP3) * diff * 1f + 180f; 1238// //angle = Misc.getAngleInDegrees(p3, p2); 1239// float dist = Misc.getDistance(p2, p1); 1240// Vector2f p1Adjusted = Misc.getUnitVectorAtDegreeAngle(angle); 1241// p1Adjusted.scale(dist); 1242// Vector2f.add(p1Adjusted, p2, p1Adjusted); 1243// prevAdjustedP1 = p1Adjusted; 1244// //GL11.glVertex2f(p1Adjusted.x, p1Adjusted.y); 1245// //GL11.glVertex2f(p1.x, p1.y); 1246// 1247// GL11.glVertex2f(p0.x, p0.y); 1248// GL11.glVertex2f(p1Adjusted.x, p1Adjusted.y); 1249// GL11.glVertex2f(p2.x, p2.y); 1250// } 1251// GL11.glEnd(); 1252 1253 if (false) { 1254 float[] place = getLengthAndWidthFractionWithinStream(Global.getSector().getPlayerFleet().getLocation()); 1255 if (place != null) { 1256 Misc.setColor(Color.red); 1257 GL11.glPointSize(40f/zoom); 1258 GL11.glEnable(GL11.GL_POINT_SMOOTH); 1259 GL11.glBegin(GL11.GL_POINTS); 1260 Vector2f p = getPointAt(place[0], place[1]); 1261 1262 GL11.glVertex2f(p.x, p.y); 1263 1264 Misc.setColor(Color.blue); 1265 p = Global.getSector().getPlayerFleet().getLocation(); 1266 GL11.glVertex2f(p.x, p.y); 1267 1268 SlipstreamSegment seg = getSegmentForDist(place[0]); 1269 if (seg != null) { 1270 float withinSeg = place[0] - seg.totalLength; 1271 Vector2f p2 = new Vector2f(seg.normal.y, -seg.normal.x); 1272 p2.scale(withinSeg); 1273 Vector2f.add(p2, seg.loc, p2); 1274 float width = seg.wobbledWidth; 1275 if (segments.size() > seg.index + 1) { 1276 SlipstreamSegment next = segments.get(seg.index + 1); 1277 width = Misc.interpolate(seg.wobbledWidth, next.wobbledWidth, 1278 (place[0] - seg.totalLength) / seg.lengthToNext); 1279 } 1280 p2.x += getNormalAt(place[0]).x * place[1] * width * 0.5f; 1281 p2.y += getNormalAt(place[0]).y * place[1] * width * 0.5f; 1282 Misc.setColor(Color.green); 1283 GL11.glVertex2f(p2.x, p2.y); 1284 } 1285 GL11.glEnd(); 1286 } 1287 } 1288 1289// GL11.glBegin(GL11.GL_LINE_STRIP); 1290// for (int i = 1; i < segments.size() - 2; i++) { 1291// SlipstreamSegment prev = segments.get(i); 1292// SlipstreamSegment curr = segments.get(i); 1293// SlipstreamSegment next = segments.get(i + 1); 1294// SlipstreamSegment next2 = segments.get(i + 2); 1295// 1296// float incr = 5f; 1297// for (float len = 0; len < curr.lengthToNext; len += incr) { 1298// float t = len / (curr.lengthToNext + next.lengthToNext); 1299// Vector2f p = Misc.bezier(curr.loc, next.loc, next2.loc, t); 1300// 1301// float tPrev = (prev.lengthToNext + len) / (prev.lengthToNext + curr.lengthToNext); 1302// Vector2f pPrev = Misc.bezier(prev.loc, curr.loc, next.loc, tPrev); 1303// 1304// //p = Misc.interpolateVector(pPrev, p, 0.5f); 1305// //GL11.glVertex2f(p.x, p.y); 1306// GL11.glVertex2f(pPrev.x, pPrev.y); 1307// } 1308// if (i == 4) break; 1309// } 1310// GL11.glEnd(); 1311 1312 boolean curvedTrails = true; 1313 boolean useTex = false; 1314 //if (zoom > 1.25f) useTex = false; 1315 //useTex = false; 1316 //System.out.println("USETEX = " + useTex); 1317 if (!useTex) { 1318 GL11.glDisable(GL11.GL_TEXTURE_2D); 1319 GL11.glEnable(GL11.GL_BLEND); 1320 GL11.glLineWidth(Math.max(1f, Math.min(2f, 2f/zoom))); 1321 //GL11.glLineWidth(25f); 1322 GL11.glEnable(GL11.GL_LINE_SMOOTH); 1323 GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST); 1324 } 1325 1326 //curvedTrails = false; 1327 if (!curvedTrails) { 1328 GL11.glBegin(GL11.GL_LINES); 1329 } 1330// GL11.glEnable(GL11.GL_POINT_SMOOTH); 1331// GL11.glPointSize(10f); 1332// GL11.glBegin(GL11.GL_POINTS); 1333 //int index = 0; 1334 1335 if (useTex) { 1336 GL11.glEnable(GL11.GL_TEXTURE_2D); 1337 GL11.glEnable(GL11.GL_BLEND); 1338 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); 1339 1340 SpriteAPI line = Global.getSettings().getSprite("graphics/hud/line4x4.png"); 1341 //line = Global.getSettings().getSprite("graphics/hud/line32x32.png"); 1342 line.bindTexture(); 1343 } 1344 1345 for (SlipstreamParticle p : particles) { 1346 SlipstreamSegment seg = getSegmentForDist(p.dist); 1347 if (seg == null || !nearSet.contains(seg)) continue; 1348 1349// index++; 1350// if (index > 1) break; 1351 //if (true) break; 1352 float a = viewport.getAlphaMult(); 1353 if (p.remaining <= 0.5f) { 1354 a = p.remaining / 0.5f; 1355 } else if (p.elapsed < params.particleFadeInTime) { 1356 a = p.elapsed / params.particleFadeInTime; 1357 } 1358 1359 a *= getFaderBrightness(p.dist); 1360 1361 //a *= 0.5f; 1362 //a *= 0.1f; 1363 1364 //a = 1f; 1365 1366// SlipstreamSegment seg = getSegmentForDist(p.dist); 1367// if (seg == null) continue; 1368 float yPos = p.yPos; 1369 //yPos = 0f; 1370 1371 if (curvedTrails) { 1372 if (useTex) { 1373 GL11.glBegin(GL11.GL_QUAD_STRIP); 1374 Vector2f curr = getPointAt(p.dist, yPos); 1375 if (curr == null || !viewport.isNearViewport(curr, p.speed * params.lineLengthFractionOfSpeed + 50f)) { 1376 GL11.glEnd(); 1377 continue; 1378 } 1379 float iter = 5f; 1380 float incr = p.speed * params.lineLengthFractionOfSpeed / iter; 1381 float lw = 1f; 1382 for (float i = 0; i < iter; i++) { 1383 float min = incr * 1f; 1384 float dist = p.dist - i * incr - min; 1385 Vector2f next = getPointAt(dist, yPos); 1386 if (next == null) break; 1387 1388 Vector2f perp = getNormalAt(dist); 1389 if (perp == null) { 1390 GL11.glEnd(); 1391 break; 1392 } 1393 1394 float a1 = a * (iter - i) / (iter - 1); 1395 if (i == 0) a1 = 0f; 1396 1397 Misc.setColor(p.color, a1); 1398 GL11.glTexCoord2f(0, 0f); 1399 GL11.glVertex2f(curr.x + perp.x * lw, curr.y + perp.y * lw); 1400 GL11.glTexCoord2f(0, 1f); 1401 GL11.glVertex2f(curr.x - perp.x * lw, curr.y - perp.y * lw); 1402 curr = next; 1403 } 1404 GL11.glEnd(); 1405 } else { 1406 GL11.glBegin(GL11.GL_LINE_STRIP); 1407 //GL11.glBegin(GL11.GL_LINES); 1408 Vector2f curr = getPointAt(p.dist, yPos); 1409 if (curr == null || !viewport.isNearViewport(curr, p.speed * params.lineLengthFractionOfSpeed + 50f)) { 1410 GL11.glEnd(); 1411 continue; 1412 } 1413 float iter = 5f; 1414 float incr = p.speed * params.lineLengthFractionOfSpeed / iter; 1415 for (float i = 0; i < iter; i++) { 1416 1417 float min = incr * 0.5f; 1418 Vector2f next = getPointAt(p.dist - i * incr - min, yPos); 1419 if (next == null) { 1420 GL11.glEnd(); 1421 break; 1422 } 1423 1424 float a1 = a * (iter - i) / (iter - 1); 1425 //float a2 = a * (iter - i - 1) / (iter - 1); 1426 if (i == 0) a1 = 0f; 1427 1428 Misc.setColor(p.color, a1); 1429 GL11.glVertex2f(curr.x, curr.y); 1430 //Misc.setColor(p.color, a2); 1431 //GL11.glVertex2f(next.x, next.y); 1432 curr = next; 1433 } 1434 GL11.glEnd(); 1435 } 1436 } else { 1437 Vector2f start = getPointAt(p.dist + p.speed * params.lineLengthFractionOfSpeed * 0.1f, yPos); 1438 if (start == null || !viewport.isNearViewport(start, 500)) continue; 1439 1440 Vector2f mid = getPointAt(p.dist, yPos); 1441 if (mid == null) continue; 1442 Vector2f end = getPointAt(p.dist - p.speed * params.lineLengthFractionOfSpeed * 0.9f, yPos); 1443 if (end == null) continue; 1444 1445 Misc.setColor(p.color, 0f); 1446 GL11.glVertex2f(start.x, start.y); 1447 Misc.setColor(p.color, a); 1448 GL11.glVertex2f(mid.x, mid.y); 1449 GL11.glVertex2f(mid.x, mid.y); 1450 Misc.setColor(p.color, 0f); 1451 GL11.glVertex2f(end.x, end.y); 1452 } 1453// 1454 } 1455 if (!curvedTrails) { 1456 GL11.glEnd(); 1457 } 1458 } 1459 1460 1461 protected FaderUtil fader = new FaderUtil(0f, 0.5f, 0.5f); 1462 1463 public void renderSegments(SpriteAPI sprite, SpriteAPI edge, float alpha, List<SlipstreamSegment> segments) { 1464 //if (true) return; 1465 GL11.glEnable(GL11.GL_TEXTURE_2D); 1466 sprite.bindTexture(); 1467 GL11.glEnable(GL11.GL_BLEND); 1468 //GL11.glDisable(GL11.GL_BLEND); 1469 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); 1470 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); 1471 Color color = sprite.getColor(); 1472 //color = Misc.interpolateColor(color, Color.black, 0.5f); 1473 //color = Color.black; 1474 //color = Misc.scaleColorOnly(color, 0.3f); 1475 //color = Misc.setAlpha(color, 100); 1476 1477 boolean wireframe = false; 1478 //wireframe = true; 1479 if (wireframe) { 1480 GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE); 1481 GL11.glDisable(GL11.GL_TEXTURE_2D); 1482 GL11.glDisable(GL11.GL_BLEND); 1483 } 1484 1485 boolean subtract = false; 1486 //subtract = true; 1487 if (subtract) { 1488 GL14.glBlendEquation(GL14.GL_FUNC_REVERSE_SUBTRACT); 1489 } 1490 1491 // "channel" 1492 Color c = Color.black; 1493 //c = Misc.setAlpha(c, 255); 1494 GL11.glDisable(GL11.GL_TEXTURE_2D); 1495 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); 1496 1497 int alphaInDeep = 255; 1498 int alphaOutside = 0; 1499 HyperspaceTerrainPlugin plugin = (HyperspaceTerrainPlugin) Misc.getHyperspaceTerrain().getPlugin(); 1500 1501 GL11.glBegin(GL11.GL_QUAD_STRIP); 1502 1503 for (int i = 0; i < segments.size(); i++) { 1504 SlipstreamSegment curr = segments.get(i); 1505 float a = curr.fader.getBrightness(); 1506 1507 if (entity.isInHyperspace() && plugin.isInClouds(curr.loc, 100f)) { 1508 c = Misc.setAlpha(c, alphaInDeep); 1509 } else { 1510 c = Misc.setAlpha(c, alphaOutside); 1511 } 1512 1513 Vector2f p1 = new Vector2f(curr.loc); 1514 p1.x += curr.normal.x * curr.width * 0.5f; 1515 p1.y += curr.normal.y * curr.width * 0.5f; 1516 Vector2f p2 = new Vector2f(curr.loc); 1517 p2.x += curr.normal.x * (curr.width * 0.5f - params.edgeWidth); 1518 p2.y += curr.normal.y * (curr.width * 0.5f - params.edgeWidth); 1519 1520 p1.x += curr.wobble1.vector.x; 1521 p1.y += curr.wobble1.vector.y; 1522 1523 Misc.setColor(c, alpha * 0f * a); 1524 GL11.glVertex2f(p1.x, p1.y); 1525 Misc.setColor(c, alpha * 1f * a); 1526 GL11.glVertex2f(p2.x, p2.y); 1527 } 1528 GL11.glEnd(); 1529 1530 //edge2.bindTexture(); 1531 GL11.glBegin(GL11.GL_QUAD_STRIP); 1532 1533 for (int i = 0; i < segments.size(); i++) { 1534 SlipstreamSegment curr = segments.get(i); 1535 float a = curr.fader.getBrightness(); 1536 1537 if (entity.isInHyperspace() && plugin.isInClouds(curr.loc, 100f)) { 1538 c = Misc.setAlpha(c, alphaInDeep); 1539 } else { 1540 c = Misc.setAlpha(c, alphaOutside); 1541 } 1542 1543 Vector2f p1 = new Vector2f(curr.loc); 1544 p1.x -= curr.normal.x * curr.width * 0.5f; 1545 p1.y -= curr.normal.y * curr.width * 0.5f; 1546 Vector2f p2 = new Vector2f(curr.loc); 1547 p2.x -= curr.normal.x * (curr.width * 0.5f - params.edgeWidth); 1548 p2.y -= curr.normal.y * (curr.width * 0.5f - params.edgeWidth); 1549 1550 p1.x += curr.wobble2.vector.x; 1551 p1.y += curr.wobble2.vector.y; 1552 1553 Misc.setColor(c, alpha * 0f * a); 1554 GL11.glVertex2f(p1.x, p1.y); 1555 Misc.setColor(c, alpha * 1f * a); 1556 GL11.glVertex2f(p2.x, p2.y); 1557 } 1558 GL11.glEnd(); 1559 1560 GL11.glBegin(GL11.GL_QUAD_STRIP); 1561 1562 for (int i = 0; i < segments.size(); i++) { 1563 SlipstreamSegment curr = segments.get(i); 1564 float a = curr.fader.getBrightness(); 1565 1566 if (entity.isInHyperspace() && plugin.isInClouds(curr.loc, 100f)) { 1567 c = Misc.setAlpha(c, alphaInDeep); 1568 } else { 1569 c = Misc.setAlpha(c, alphaOutside); 1570 } 1571 1572 Vector2f p1 = new Vector2f(curr.loc); 1573 p1.x += curr.normal.x * (curr.width * 0.5f - params.edgeWidth); 1574 p1.y += curr.normal.y * (curr.width * 0.5f - params.edgeWidth); 1575 Vector2f p2 = new Vector2f(curr.loc); 1576 p2.x -= curr.normal.x * (curr.width * 0.5f - params.edgeWidth); 1577 p2.y -= curr.normal.y * (curr.width * 0.5f - params.edgeWidth); 1578 1579 Misc.setColor(c, alpha * 1f * a); 1580 GL11.glVertex2f(p1.x, p1.y); 1581 GL11.glVertex2f(p2.x, p2.y); 1582 } 1583 GL11.glEnd(); 1584 // end "channel" 1585 1586 1587 // main background 1588 if (!wireframe) { 1589 GL11.glEnable(GL11.GL_TEXTURE_2D); 1590 GL11.glEnable(GL11.GL_BLEND); 1591 } 1592 //GL11.glDisable(GL11.GL_BLEND); 1593 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); 1594 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); 1595 1596 GL11.glBegin(GL11.GL_QUAD_STRIP); 1597 for (int i = 0; i < segments.size(); i++) { 1598 SlipstreamSegment curr = segments.get(i); 1599 float a = curr.fader.getBrightness(); 1600 1601 Vector2f p1 = new Vector2f(curr.loc); 1602 p1.x += curr.normal.x * curr.width * 0.5f; 1603 p1.y += curr.normal.y * curr.width * 0.5f; 1604 Vector2f p2 = new Vector2f(curr.loc); 1605 p2.x -= curr.normal.x * curr.width * 0.5f; 1606 p2.y -= curr.normal.y * curr.width * 0.5f; 1607 1608 p1.x += curr.wobble1.vector.x; 1609 p1.y += curr.wobble1.vector.y; 1610 p2.x += curr.wobble2.vector.x; 1611 p2.y += curr.wobble2.vector.y; 1612 1613 Misc.setColor(color, alpha * 1f * a); 1614 GL11.glTexCoord2f(curr.tx, 0f); 1615 GL11.glVertex2f(p1.x, p1.y); 1616 GL11.glTexCoord2f(curr.tx, 1f); 1617 GL11.glVertex2f(p2.x, p2.y); 1618 } 1619 GL11.glEnd(); 1620 1621 1622 // edges 1623 color = edge.getColor(); 1624 float wobbleMult = 0.5f; 1625 edge.bindTexture(); 1626 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); 1627 //GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); 1628 1629 GL11.glBegin(GL11.GL_QUAD_STRIP); 1630 1631 for (int i = 0; i < segments.size(); i++) { 1632 SlipstreamSegment curr = segments.get(i); 1633 float a = curr.fader.getBrightness(); 1634 1635 Vector2f p1 = new Vector2f(curr.loc); 1636 p1.x += curr.normal.x * curr.width * 0.5f; 1637 p1.y += curr.normal.y * curr.width * 0.5f; 1638 Vector2f p2 = new Vector2f(curr.loc); 1639 p2.x += curr.normal.x * (curr.width * 0.5f - params.edgeWidth); 1640 p2.y += curr.normal.y * (curr.width * 0.5f - params.edgeWidth); 1641 1642 p1.x += curr.wobble1.vector.x * wobbleMult; 1643 p1.y += curr.wobble1.vector.y * wobbleMult; 1644 p2.x += curr.wobble1.vector.x * wobbleMult; 1645 p2.y += curr.wobble1.vector.y * wobbleMult; 1646 1647 Misc.setColor(color, alpha * 1f * a); 1648 GL11.glTexCoord2f(curr.txe1, 1f); 1649 GL11.glVertex2f(p1.x, p1.y); 1650 GL11.glTexCoord2f(curr.txe1, 0f); 1651 GL11.glVertex2f(p2.x, p2.y); 1652 } 1653 GL11.glEnd(); 1654 1655 //edge2.bindTexture(); 1656 GL11.glBegin(GL11.GL_QUAD_STRIP); 1657 1658 for (int i = 0; i < segments.size(); i++) { 1659 SlipstreamSegment curr = segments.get(i); 1660 float a = curr.fader.getBrightness(); 1661 1662 Vector2f p1 = new Vector2f(curr.loc); 1663 p1.x -= curr.normal.x * curr.width * 0.5f; 1664 p1.y -= curr.normal.y * curr.width * 0.5f; 1665 Vector2f p2 = new Vector2f(curr.loc); 1666 p2.x -= curr.normal.x * (curr.width * 0.5f - params.edgeWidth); 1667 p2.y -= curr.normal.y * (curr.width * 0.5f - params.edgeWidth); 1668 1669 p1.x += curr.wobble2.vector.x * wobbleMult; 1670 p1.y += curr.wobble2.vector.y * wobbleMult; 1671 p2.x += curr.wobble2.vector.x * wobbleMult; 1672 p2.y += curr.wobble2.vector.y * wobbleMult; 1673 1674 Misc.setColor(color, alpha * 1f * a); 1675 GL11.glTexCoord2f(curr.txe2, 1f); 1676 GL11.glVertex2f(p1.x, p1.y); 1677 GL11.glTexCoord2f(curr.txe2, 0f); 1678 GL11.glVertex2f(p2.x, p2.y); 1679 } 1680 GL11.glEnd(); 1681 1682 1683 if (subtract) { 1684 GL14.glBlendEquation(GL14.GL_FUNC_ADD); 1685 } 1686 1687 if (wireframe) GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL); 1688 } 1689 1690 1691 1692 1693 1694 public Color getRandomColor() { 1695 return Misc.interpolateColor(params.minColor, params.maxColor, (float) Math.random()); 1696 } 1697 1698 1699 /** 1700 * result[0] = actual distance along the length of the slipstream 1701 * result[1] = offset along the width of the slipstream, 1702 * 0 = on center, 1 = on edge along normal, -1 = on edge along negative of normal 1703 * null if outside stream 1704 * Assumes rectangular, non-tapered stream 1705 * @param loc 1706 * @return 1707 */ 1708 public float [] getLengthAndWidthFractionWithinStream(Vector2f loc) { 1709 float dist = Misc.getDistance(loc, entity.getLocation()); 1710 if (dist > getRenderRange()) return null; 1711 1712 List<SlipstreamSegment> near = getSegmentsNear(loc, 0f); 1713 1714 for (SlipstreamSegment curr : near) { 1715 SlipstreamSegment next = null; 1716 if (segments.size() > curr.index + 1) { 1717 next = segments.get(curr.index + 1); 1718 } else { 1719 next = new SlipstreamSegment(); 1720 //next2.width = next.width; 1721 next.wobbledWidth = curr.wobbledWidth; 1722 1723 next.normal = curr.normal; 1724 //next2.dir = next.dir; 1725 next.loc = new Vector2f(curr.dir); 1726 next.loc.scale(curr.lengthToPrev); 1727 Vector2f.add(next.loc, curr.loc, next.loc); 1728 //next2.locB = next2.loc; 1729 next.lengthToPrev = curr.lengthToPrev; 1730 //continue; 1731 } 1732 1733 Vector2f p3 = loc; 1734 Vector2f p1 = curr.loc; 1735 Vector2f p2 = next.loc; 1736 1737 Vector2f currNormalP1 = new Vector2f(curr.loc); 1738 Vector2f currNormalP2 = new Vector2f(curr.normal); 1739 currNormalP2.scale(100f); 1740 Vector2f.add(currNormalP2, currNormalP1, currNormalP2); 1741 1742 Vector2f nextNormalP1 = new Vector2f(next.loc); 1743 Vector2f nextNormalP2 = new Vector2f(next.normal); 1744 nextNormalP2.scale(100f); 1745 Vector2f.add(nextNormalP2, nextNormalP1, nextNormalP2); 1746 1747 //Vector2f dir = Misc.getUnitVectorAtDegreeAngle(Misc.getAngleInDegrees(p1, p2)); 1748 Vector2f dir = new Vector2f(curr.dir); 1749 dir.scale(100f); 1750 Vector2f p4 = Vector2f.add(p3, dir, new Vector2f()); 1751 1752 Vector2f currNormalP = Misc.intersectLines(currNormalP1, currNormalP2, p3, p4); 1753 if (currNormalP == null) continue; 1754 Vector2f nextNormalP = Misc.intersectLines(nextNormalP1, nextNormalP2, p3, p4); 1755 if (nextNormalP == null) continue; 1756 1757 float u = (p3.x - currNormalP.x) * (nextNormalP.x - currNormalP.x) + 1758 (p3.y - currNormalP.y) * (nextNormalP.y - currNormalP.y); 1759 float denom = Vector2f.sub(nextNormalP, currNormalP, new Vector2f()).length(); 1760 denom *= denom; 1761 if (denom == 0) continue; 1762 u /= denom; 1763 1764 if (u >= 0 && u <= 1) { // p3 is between the two points on the normals 1765 Vector2f normalAtP3 = Misc.interpolateVector(curr.normal, next.normal, u); 1766 normalAtP3.scale(100f); 1767 Vector2f p3PlusNormal = Vector2f.add(p3, normalAtP3, new Vector2f()); 1768 1769 Vector2f intersect = Misc.intersectLines(p1, p2, p3, p3PlusNormal); 1770 if (intersect == null) continue; 1771 1772 float distFromLine = Vector2f.sub(intersect, p3, new Vector2f()).length(); 1773 float width = Misc.interpolate(curr.wobbledWidth, next.wobbledWidth, u); 1774 if (distFromLine >= width / 2f) return null; 1775 1776 float [] result = new float[2]; 1777 //result[0] = curr.totalLength + u * curr.lengthToNext; 1778 result[0] = curr.totalLength + u * next.lengthToPrev; 1779 result[1] = distFromLine / (width / 2f); 1780 1781 float currToLoc = Misc.getAngleInDegrees(p1, p3); 1782 float segDir = Misc.getAngleInDegrees(p1, p2); 1783 if (Misc.getClosestTurnDirection(segDir, currToLoc) < 0) { 1784 result[1] = -result[1]; 1785 } 1786 1787 return result; 1788 1789// float u = (p3.x - p1.x) * (p2.x - p1.x) + (p3.y - p1.y) * (p2.y - p1.y); 1790// float denom = Vector2f.sub(p2, p1, new Vector2f()).length(); 1791// denom *= denom; 1792// if (denom == 0) continue; 1793// u /= denom; 1794// 1795//// if (u < 0 && u > -0.03f) u = 0f; 1796//// if (u > 1 && u < 1.03f) u = 1f; 1797// 1798// if (u >= 0 && u <= 1) { // intersection is between p1 and p2 1799// Vector2f intersect = new Vector2f(); 1800// intersect.x = p1.x + u * (p2.x - p1.x); 1801// intersect.y = p1.y + u * (p2.y - p1.y); 1802// float distFromLine = Vector2f.sub(intersect, p3, new Vector2f()).length(); 1803// 1804// float width = curr.wobbledWidth; 1805// if (next != null) { 1806// width = Misc.interpolate(curr.wobbledWidth, next.wobbledWidth, u); 1807// } 1808// 1809// if (distFromLine >= width / 2f) return null; 1810// 1811// float [] result = new float[2]; 1812// result[0] = curr.totalLength + u * curr.lengthToNext; 1813// result[1] = distFromLine / (width / 2f); 1814// 1815// float currToLoc = Misc.getAngleInDegrees(p1, p3); 1816// float segDir = Misc.getAngleInDegrees(p1, p2); 1817// if (Misc.getClosestTurnDirection(segDir, currToLoc) < 0) { 1818// result[1] = -result[1]; 1819// } 1820// 1821// return result; 1822 } 1823 1824 } 1825 1826// Vector2f p3 = new Vector2f(loc); 1827// Vector2f p1 = new Vector2f(entity.getLocation()); 1828// Vector2f p2 = Misc.getUnitVectorAtDegreeAngle(entity.getFacing() + 180f); 1829// //p2.scale(params.length); 1830// Vector2f.add(p2, p1, p2); 1831// 1832// float u = (p3.x - p1.x) * (p2.x - p1.x) + (p3.y - p1.y) * (p2.y - p1.y); 1833// float denom = Vector2f.sub(p2, p1, new Vector2f()).length(); 1834// denom *= denom; 1835// if (denom == 0) return null; 1836// u /= denom; 1837// 1838// if (u >= 0 && u <= 1) { // intersection is between p1 and p2 1839// Vector2f intersect = new Vector2f(); 1840// intersect.x = p1.x + u * (p2.x - p1.x); 1841// intersect.y = p1.y + u * (p2.y - p1.y); 1842// float distFromLine = Vector2f.sub(intersect, p3, new Vector2f()).length(); 1843// //float distAlongLine = u * params.length; 1844// if (distFromLine >= params.width/2f) return null; 1845// 1846// float [] result = new float[2]; 1847// result[0] = u; 1848// result[1] = distFromLine / (params.width / 2f); 1849// return result; 1850// } 1851 return null; 1852 } 1853 1854 public void applyEffectToFleets(float amount) { 1855 float days = Global.getSector().getClock().convertToDays(amount); 1856 for (CampaignFleetAPI fleet : entity.getContainingLocation().getFleets()) { 1857 applyEffect(fleet, days); 1858 } 1859 } 1860 1861 //protected boolean playerWasInSlipstream = false; 1862 protected int playerWasInSlipstreamFramesAgo = 1000; 1863 public void applyEffect(SectorEntityToken other, float days) { 1864 if (other instanceof CampaignFleetAPI) { 1865 CampaignFleetAPI fleet = (CampaignFleetAPI) other; 1866 1867// if (fleet.isPlayerFleet()) { 1868// if (getLengthAndWidthFractionWithinStream(fleet.getLocation()) == null) { 1869// System.out.println("wefwefwefe"); 1870// } 1871// System.out.println("efwefwef"); 1872// } 1873 1874 float [] offset = getLengthAndWidthFractionWithinStream(fleet.getLocation()); 1875 if (offset == null) { 1876 if (fleet.isPlayerFleet()) { 1877 playerWasInSlipstreamFramesAgo++; 1878 if (playerWasInSlipstreamFramesAgo > 1000) { 1879 playerWasInSlipstreamFramesAgo = 1000; 1880 } 1881 } 1882 return; 1883 } 1884 1885// if (fleet.isPlayerFleet()) { 1886// System.out.println("Location in stream: " + offset[0] + ", " + offset[1]); 1887// } 1888 1889 //params.burnLevel = 10; 1890 1891 float distAlong = offset[0]; 1892 float yOff = offset[1]; 1893 1894// float intensity = 1f; 1895// if (Math.abs(yOff) > 0.5f) { 1896// intensity *= (1f - Math.abs(yOff)) / 0.5f; 1897// } 1898 float intensity = getIntensity(yOff); 1899 float wMult = getWidthBasedSpeedMult(distAlong); 1900 //System.out.println("wMult: " + wMult); 1901 intensity *= wMult; 1902 intensity *= getFaderBrightness(distAlong); 1903 //intensity *= intensity; 1904 //System.out.println(intensity); 1905 1906 if (intensity <= 0) { 1907 if (fleet.isPlayerFleet()) { 1908 playerWasInSlipstreamFramesAgo++; 1909 if (playerWasInSlipstreamFramesAgo > 1000) { 1910 playerWasInSlipstreamFramesAgo = 1000; 1911 } 1912 } 1913 return; 1914 } 1915 1916 if (fleet.isPlayerFleet()) { 1917 //if (!playerWasInSlipstream) { 1918 // playerWasInSlipstream = true; 1919 if (playerWasInSlipstreamFramesAgo > 5) { 1920 fleet.addFloatingText("Entering slipstream", Misc.setAlpha(fleet.getIndicatorColor(), 255), 0.5f); 1921 } 1922 playerWasInSlipstreamFramesAgo = 0; 1923 } 1924 1925 //System.out.println("Intensity: " + intensity); 1926 1927 // "wind" effect - adjust velocity 1928 float maxFleetBurn = fleet.getFleetData().getBurnLevel(); 1929 float currFleetBurn = fleet.getCurrBurnLevel(); 1930 1931 float maxWindBurn = params.burnLevel * 2f; 1932 1933 float currWindBurn = intensity * maxWindBurn; 1934 float maxFleetBurnIntoWind = maxFleetBurn - Math.abs(currWindBurn); 1935 float seconds = days * Global.getSector().getClock().getSecondsPerDay(); 1936 1937// float angle = Misc.getAngleInDegreesStrict(this.entity.getLocation(), fleet.getLocation()) + 180f; 1938// Vector2f windDir = Misc.getUnitVectorAtDegreeAngle(angle); 1939 Vector2f p1 = getPointAt(distAlong, yOff); 1940 Vector2f p2 = getPointAt(distAlong + 1f, yOff); 1941 if (p1 == null || p2 == null) { 1942 if (fleet.isPlayerFleet()) { 1943 playerWasInSlipstreamFramesAgo++; 1944 if (playerWasInSlipstreamFramesAgo > 1000) { 1945 playerWasInSlipstreamFramesAgo = 1000; 1946 } 1947 } 1948 return; 1949 } 1950 1951 //Vector2f windDir = Misc.getUnitVectorAtDegreeAngle(entity.getFacing()); 1952 Vector2f windDir = Misc.getUnitVectorAtDegreeAngle(Misc.getAngleInDegrees(p1, p2)); 1953 if (currWindBurn < 0) { 1954 windDir.negate(); 1955 } 1956 Vector2f velDir = Misc.normalise(new Vector2f(fleet.getVelocity())); 1957 //float baseFleetAccel = Misc.getSpeedForBurnLevel(fleet.getFleetData().getMinBurnLevel()); 1958 float baseFleetAccel = fleet.getTravelSpeed(); 1959 if (baseFleetAccel < 10f) baseFleetAccel = 10f; 1960 1961 boolean fleetTryingToMove = fleet.getMoveDestination() != null && 1962 Misc.getDistance(fleet.getLocation(), fleet.getMoveDestination()) > fleet.getRadius() + 10f; 1963 if (fleet.isPlayerFleet()) { 1964 fleetTryingToMove &= ( 1965 Global.getSector().getCampaignUI().isPlayerFleetFollowingMouse() || 1966 fleet.wasSlowMoving()); 1967 } 1968 float windSpeedReduction = 0f; 1969 if (!fleetTryingToMove) { 1970 Vector2f dest = new Vector2f(windDir); 1971 dest.scale(1000f); 1972 Vector2f.add(dest, fleet.getLocation(), dest); 1973 fleet.setMoveDestination(dest.x, dest.y); 1974 } else { 1975 Vector2f moveDir = Misc.getUnitVectorAtDegreeAngle( 1976 Misc.getAngleInDegrees(fleet.getLocation(), fleet.getMoveDestination())); 1977 float dot = Vector2f.dot(windDir, moveDir); 1978 if (fleet.wasSlowMoving()) dot = -1f; 1979 if (dot < 0) { 1980 float accelBasedMult = fleet.getAcceleration() / baseFleetAccel; 1981 accelBasedMult *= accelBasedMult; 1982 if (accelBasedMult > 1f) accelBasedMult = 1f; 1983 if (accelBasedMult < 0.1f) accelBasedMult = 0.1f; 1984 windSpeedReduction = -dot * fleet.getFleetData().getBurnLevel() * accelBasedMult; 1985 } 1986 } 1987 1988 //float burnBonus = fleet.getFleetData().getBurnLevel() - fleet.getFleetData().getMinBurnLevelUnmodified(); 1989 float burnBonus = fleet.getFleetData().getBurnLevel() - fleet.getFleetData().getMinBurnLevel(); 1990 if (burnBonus < 0) burnBonus = 0; 1991 //float maxSpeedWithWind = Misc.getSpeedForBurnLevel(params.burnLevel + burnBonus); 1992 float maxSpeedWithWind = Misc.getSpeedForBurnLevel((params.burnLevel * intensity) + burnBonus); 1993 if (windSpeedReduction > 0) { 1994 maxSpeedWithWind = Misc.getSpeedForBurnLevel( 1995 Math.max(params.burnLevel * 0.5f * intensity, params.burnLevel * intensity - windSpeedReduction)); 1996 } 1997 1998 float fleetSpeedAlongWind = Vector2f.dot(windDir, fleet.getVelocity()); 1999 if (fleetSpeedAlongWind >= maxSpeedWithWind) { 2000// float dotPlayerAndWindVel = Vector2f.dot(windDir, velDir); 2001// if (dotPlayerAndWindVel > 0.98f) { 2002 return; 2003 //} 2004 } 2005 2006 velDir.scale(currFleetBurn); 2007 2008 float fleetBurnAgainstWind = -1f * Vector2f.dot(windDir, velDir); 2009 2010 2011 float windSpeed = Misc.getSpeedForBurnLevel(currWindBurn); 2012 //float fleetSpeed = fleet.getTravelSpeed(); 2013 Vector2f windVector = new Vector2f(windDir); 2014 windVector.scale(windSpeed); 2015 2016 Vector2f vel = fleet.getVelocity(); 2017 Vector2f diff = Vector2f.sub(windVector, vel, new Vector2f()); 2018 //windDir.scale(seconds * fleet.getAcceleration()); 2019 float max = diff.length(); 2020 diff = Misc.normalise(diff); 2021 //diff.scale(Math.max(windSpeed * seconds, fleet.getAcceleration() * 1f * seconds)); 2022 diff.scale(fleet.getAcceleration() * 3f * seconds); 2023 //diff.scale(fleet.getTravelSpeed() * 5f * seconds); 2024 //diff.scale(accelMult); 2025 if (diff.length() > max) { 2026 diff.scale(max / diff.length()); 2027 } 2028 //System.out.println("Applying diff: " + diff); 2029 //fleet.setVelocity(vel.x + diff.x, vel.y + diff.y); 2030 2031 2032// Vector2f velDir = Misc.normalise(new Vector2f(fleet.getVelocity())); 2033// velDir.scale(currFleetBurn); 2034// 2035// float fleetBurnAgainstWind = -1f * Vector2f.dot(windDir, velDir); 2036// 2037 float accelMult = 0.5f; 2038 if (fleetBurnAgainstWind > maxFleetBurnIntoWind) { 2039 accelMult += 0.75f + 0.25f * (fleetBurnAgainstWind - maxFleetBurnIntoWind); 2040 } 2041 2042 2043 //Vector2f vel = fleet.getVelocity(); 2044 //windDir.scale(seconds * fleet.getAcceleration() * accelMult); 2045 //float baseFleetAccel = Math.max(fleet.getTravelSpeed(), fleet.getAcceleration()); 2046 2047 windDir.scale(seconds * baseFleetAccel * accelMult); 2048 fleet.setVelocity(vel.x + windDir.x, vel.y + windDir.y); 2049 2050 2051 boolean withGlow = true; 2052 //withGlow = false; 2053 if (withGlow) { 2054 Color glowColor = params.windGlowColor; 2055 int alpha = glowColor.getAlpha(); 2056 if (alpha < 75) { 2057 glowColor = Misc.setAlpha(glowColor, 75); 2058 } 2059 // visual effects - glow, tail 2060 2061 p1 = getNoWobblePointAt(distAlong, yOff); 2062 p2 = getNoWobblePointAt(distAlong + 100f, yOff); 2063 if (p1 != null && p2 != null) { 2064 windDir = Misc.getUnitVectorAtDegreeAngle(Misc.getAngleInDegrees(p1, p2)); 2065 2066// float fleetSpeedAlongWind = Vector2f.dot(windDir, fleet.getVelocity()); 2067// //float fleetSpeed = fleet.getVelocity().length(); 2068// 2069// windSpeed = Misc.getSpeedForBurnLevel(params.burnLevel); 2070// float matchingWindFraction = fleetSpeedAlongWind/windSpeed; 2071// float effectMag = 1f - matchingWindFraction; 2072// if (effectMag < 0f) effectMag = 0f; 2073 //if (effectMag < 0.25f) effectMag = 0.25f; 2074 //effectMag = 0.5f; 2075 2076 String modId = "slipstream_" + entity.getId(); 2077 float durIn = 1f; 2078 float durOut = 3f; 2079 //durIn = 0.5f; 2080 //float sizeNormal = (15f + 30f * effectMag * effectMag) * (intensity); 2081 float sizeNormal = 5f + 10f * intensity; 2082 for (FleetMemberViewAPI view : fleet.getViews()) { 2083 view.getWindEffectDirX().shift(modId, windDir.x * sizeNormal, durIn, durOut, 1f); 2084 view.getWindEffectDirY().shift(modId, windDir.y * sizeNormal, durIn, durOut, 1f); 2085 view.getWindEffectColor().shift(modId, glowColor, durIn, durOut, 1f); 2086 } 2087 } 2088 } 2089 } 2090 } 2091 2092 2093 public Vector2f getPointAt(float lengthAlongStream, float offset) { 2094 SlipstreamSegment curr = getSegmentForDist(lengthAlongStream); 2095 if (curr == null) return null; 2096 int index = curr.index; 2097 2098 SlipstreamSegment next = null; 2099 SlipstreamSegment next2 = null; 2100 2101 if (index >= segments.size() - 1) return null; 2102 2103 if (index % 2 == 0) { 2104 next = segments.get(index + 1); 2105 if (index >= segments.size() - 2) { 2106 next2 = new SlipstreamSegment(); 2107 //next2.width = next.width; 2108 next2.wobbledWidth = next.wobbledWidth; 2109 2110 next2.normal = next.normal; 2111 //next2.dir = next.dir; 2112 next2.loc = new Vector2f(next.dir); 2113 next2.loc.scale(next.lengthToPrev); 2114 Vector2f.add(next2.loc, next.loc, next2.loc); 2115 //next2.locB = next2.loc; 2116 next2.lengthToPrev = next.lengthToPrev; 2117 } else { 2118 next2 = segments.get(index + 2); 2119 } 2120 } 2121 if (index % 2 != 0) { 2122 if (index >= segments.size() - 1) return null; 2123 curr = segments.get(index - 1); 2124 next = segments.get(index); 2125 next2 = segments.get(index + 1); 2126 } 2127 2128 float lenForT = lengthAlongStream - curr.totalLength; 2129 //float t = lenForT / (curr.lengthToNext + next.lengthToNext); 2130 float t = lenForT / (curr.lengthToNext + next2.lengthToPrev); 2131// if (t < 0) { 2132// System.out.println("wefwefe"); 2133// } 2134 2135 Vector2f p0 = new Vector2f(curr.loc); 2136 Vector2f p1 = new Vector2f(next.locB); 2137 Vector2f p2 = new Vector2f(next2.loc); 2138 2139// offset *= 0.7f; 2140// p0.x += curr.normal.x * curr.width * 0.5f * offset; 2141// p0.y += curr.normal.y * curr.width * 0.5f * offset; 2142// 2143// p2.x += next2.normal.x * next2.width * 0.5f * offset; 2144// p2.y += next2.normal.y * next2.width * 0.5f * offset; 2145// 2146// p1.x += next.normal.x * next.width * 0.5f * offset; 2147// p1.y += next.normal.y * next.width * 0.5f * offset; 2148 2149 p0.x += curr.normal.x * curr.wobbledWidth * 0.5f * offset; 2150 p0.y += curr.normal.y * curr.wobbledWidth * 0.5f * offset; 2151 2152 p2.x += next2.normal.x * next2.wobbledWidth * 0.5f * offset; 2153 p2.y += next2.normal.y * next2.wobbledWidth * 0.5f * offset; 2154 2155 p1.x += next.normal.x * next.wobbledWidth * 0.5f * offset; 2156 p1.y += next.normal.y * next.wobbledWidth * 0.5f * offset; 2157 2158 //System.out.println("T: " + t); 2159 Vector2f p = Misc.bezier(p0, p1, p2, t); 2160 2161 return p; 2162 } 2163 2164 public Vector2f getNoWobblePointAt(float lengthAlongStream, float offset) { 2165 SlipstreamSegment curr = getSegmentForDist(lengthAlongStream); 2166 if (curr == null) return null; 2167 int index = curr.index; 2168 if (index >= segments.size() - 2) return null; 2169 2170 SlipstreamSegment next = segments.get(index + 1); 2171 SlipstreamSegment next2 = segments.get(index + 2); 2172 2173 if (index % 2 != 0) { 2174 curr = segments.get(index - 1); 2175 next = segments.get(index); 2176 next2 = segments.get(index + 1); 2177 } 2178 2179 float lenForT = lengthAlongStream - curr.totalLength; 2180 float t = lenForT / (curr.lengthToNext + next.lengthToNext); 2181// if (t < 0) { 2182// System.out.println("wefwefe"); 2183// } 2184 2185 Vector2f p0 = new Vector2f(curr.loc); 2186 Vector2f p1 = new Vector2f(next.locB); 2187 Vector2f p2 = new Vector2f(next2.loc); 2188 2189 float edges = params.edgeWidth * 2f * 0.5f; 2190 p0.x += curr.normal.x * (curr.width - edges) * 0.5f * offset; 2191 p0.y += curr.normal.y * (curr.width - edges) * 0.5f * offset; 2192 2193 p2.x += next2.normal.x * (next2.width - edges) * 0.5f * offset; 2194 p2.y += next2.normal.y * (next2.width - edges) * 0.5f * offset; 2195 2196 p1.x += next.normal.x * (next.width - edges) * 0.5f * offset; 2197 p1.y += next.normal.y * (next.width - edges) * 0.5f * offset; 2198 2199 Vector2f p = Misc.bezier(p0, p1, p2, t); 2200 2201 return p; 2202 } 2203 2204 2205 public Vector2f getNormalAt(float lengthAlongStream) { 2206 SlipstreamSegment curr = getSegmentForDist(lengthAlongStream); 2207 if (curr == null) return null; 2208 int index = curr.index; 2209 if (index >= segments.size() - 2) return null; 2210 2211 SlipstreamSegment next = segments.get(index + 1); 2212 SlipstreamSegment next2 = segments.get(index + 2); 2213 2214 if (index % 2 != 0) { 2215 curr = segments.get(index - 1); 2216 next = segments.get(index); 2217 next2 = segments.get(index + 1); 2218 } 2219 2220 float lenForT = lengthAlongStream - curr.totalLength; 2221 2222 float f = lenForT / curr.lengthToNext; 2223 Vector2f perp; 2224 if (f < 1f) { 2225 perp = Misc.interpolateVector(curr.normal, next.normal, f); 2226 } else { 2227 f = (lenForT - curr.lengthToNext) / next.lengthToNext; 2228 perp = Misc.interpolateVector(next.normal, next2.normal, f); 2229 } 2230 return perp; 2231 } 2232 2233 public List<SlipstreamSegment> getSegmentsNear(Vector2f loc, float range) { 2234 //List<SlipstreamSegment> potential = new ArrayList<SlipstreamEntityPlugin2.SlipstreamSegment>(); 2235 List<SlipstreamSegment> result = new ArrayList<SlipstreamEntityPlugin2.SlipstreamSegment>(); 2236 int boxIndex = 0; 2237 for (BoundingBox box : bounds) { 2238 if (box.pointNeedsDetailedCheck(loc, range)) { 2239 int min = boxIndex * segmentsPerBox; 2240 for (int i = min; i < min + segmentsPerBox && i < segments.size(); i++) { 2241 SlipstreamSegment curr = segments.get(i); 2242 float distSq = Misc.getDistanceSq(curr.loc, loc); 2243 float r = range + curr.width + Math.max(curr.lengthToPrev, curr.lengthToNext); 2244 if (distSq < r * r) { 2245 result.add(curr); 2246 } 2247 } 2248 } 2249 boxIndex++; 2250 } 2251 2252// for (SlipstreamSegment curr : potential) { 2253// float distSq = Misc.getDistanceSq(curr.loc, loc); 2254// float r = range + curr.width + Math.max(curr.lengthToPrev, curr.lengthToNext); 2255// if (distSq < r * r) { 2256// result.add(curr); 2257// } 2258// } 2259// List<SlipstreamSegment> result = new ArrayList<SlipstreamEntityPlugin2.SlipstreamSegment>(); 2260// for (SlipstreamSegment curr : segments) { 2261// float distSq = Misc.getDistanceSq(curr.loc, loc); 2262// float r = range + curr.width + Math.max(curr.lengthToPrev, curr.lengthToNext); 2263// if (distSq < r * r) { 2264// result.add(curr); 2265// } 2266// } 2267 return result; 2268 } 2269} 2270 2271 2272 2273 2274