Starsector API
Loading...
Searching...
No Matches
SlipstreamBuilder.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.velfield;
2
3import java.awt.Color;
4import java.util.ArrayList;
5import java.util.List;
6import java.util.Random;
7
8import org.lwjgl.opengl.GL11;
9import org.lwjgl.util.vector.Vector2f;
10
11import com.fs.starfarer.api.Global;
12import com.fs.starfarer.api.impl.campaign.velfield.SlipstreamTerrainPlugin2.SlipstreamParams2;
13import com.fs.starfarer.api.impl.campaign.velfield.SlipstreamTerrainPlugin2.SlipstreamSegment;
14import com.fs.starfarer.api.util.Misc;
15import com.fs.starfarer.api.util.WeightedRandomPicker;
16
17public class SlipstreamBuilder {
18
19 public static enum StreamType {
20 NORMAL,
21 WIDE,
22 NARROW,
23 }
24
25 public static float MIN_SPACING = 200f;
26 public static float MAX_SPACING = 400f;
27 public static float WIDTH_TO_SPACING_MULT = 0.2f;
28
29 public static float MIN_NARROW = 0.5f;
30 public static float MAX_NARROW = 0.7f;
31 public static float MIN_NORMAL = 0.9f;
32 public static float MAX_NORMAL = 1.1f;
33 public static float MIN_WIDE = 1.3f;
34 public static float MAX_WIDE = 1.6f;
35 public static float MIN_VERY_WIDE = 1.8f;
36 public static float MAX_VERY_WIDE = 2.1f;
37
38 public static float WCHANGE_SLOW_T_MULT_MIN = 1f;
39 public static float WCHANGE_SLOW_T_MULT_MIN_MAX = 1.2f;
40 public static float WCHANGE_MEDIUM_T_MULT_MIN = 1.8f;
41 public static float WCHANGE_MEDIUM_T_MULT_MAX = 2.2f;
42 public static float WCHANGE_FAST_T_MULT_MIN = 2.8f;
43 public static float WCHANGE_FAST_T_MULT_MAX = 3.2f;
44
45 public static float WRAND_NONE_MULT = 0f;
46 public static float WRAND_LOW_MULT = 0.1f;
47 public static float WRAND_MEDIUM_MULT = 0.17f;
48 public static float WRAND_HIGH_MULT = 0.25f;
49
50 public static float FLUCT_LENGTH_MIN = 2500f;
51 public static float FLUCT_LENGTH_MAX = 4000f;
52 public static float FLUCT_MAG_MIN = 350f;
53 public static float FLUCT_MAG_MAX = 500f;
54
55 public static float FLUCT_NONE_MULT = 0f;
56 public static float FLUCT_LOW_MULT = 0.33f;
57 public static float FLUCT_MEDIUM_MULT = 0.67f;
58 public static float FLUCT_HIGH_MULT = 1f;
59
60
61 // width
62 public static final int WIDTH_NARROW = 0;
63 public static final int WIDTH_NORMAL = 1;
64 public static final int WIDTH_WIDE = 2;
65 public static final int WIDTH_VERY_WIDE = 3;
66
67 // width randomness
68 public static final int WRAND_NONE = 0;
69 public static final int WRAND_LOW = 1;
70 public static final int WRAND_MEDIUM = 2;
71 public static final int WRAND_HIGH = 3;
72
73 // how quickly width changes
74 public static final int WCHANGE_SLOW = 0;
75 public static final int WCHANGE_MEDIUM = 1;
76 public static final int WCHANGE_FAST = 2;
77
78 // path fluctuations within sections
79 public static final int FLUCT_NONE = 0;
80 public static final int FLUCT_LOW = 1;
81 public static final int FLUCT_MEDIUM = 2;
82 public static final int FLUCT_HIGH = 3;
83
84
85 public void initTransitionMatrices() {
86 widthTM = new float[4][4];
87 if (type == StreamType.NORMAL) {
88 widthTM[WIDTH_NARROW] = new float [] {0.5f, 1f, 0.4f, 0.3f};
89 widthTM[WIDTH_NORMAL] = new float [] { 1f, 1f, 0.5f, 0.3f};
90 widthTM[WIDTH_WIDE] = new float [] {0.7f, 1f, 0.2f, 0.5f};
91 widthTM[WIDTH_VERY_WIDE] = new float [] { 1f, 1f, 1f, 0.1f};
92 } else if (type == StreamType.WIDE) {
93 widthTM[WIDTH_NARROW] = new float [] {0.1f, 1f, 0.6f, 0.4f};
94 widthTM[WIDTH_NORMAL] = new float [] {0.2f, 0.5f, 1f, 0.5f};
95 widthTM[WIDTH_WIDE] = new float [] {0.1f, 0.5f, 1f, 0.5f};
96 widthTM[WIDTH_VERY_WIDE] = new float [] { 0f, 0.5f, 1f, 0.3f};
97 } else if (type == StreamType.NARROW) {
98 widthTM[WIDTH_NARROW] = new float [] {0.8f, 1f, 0.3f, 0.1f};
99 widthTM[WIDTH_NORMAL] = new float [] { 1f, 1f, 0.3f, 0.1f};
100 widthTM[WIDTH_WIDE] = new float [] {0.7f, 1f, 0.2f, 0.2f};
101 widthTM[WIDTH_VERY_WIDE] = new float [] { 1f, 1f, 1f, 0.1f};
102 }
103
104 wrandTM = new float[4][4];
105 wrandTM[WRAND_NONE] = new float [] { 1f, 1f, 0.1f, 0.1f};
106 wrandTM[WRAND_LOW] = new float [] { 1f, 1f, 1f, 0.1f};
107 wrandTM[WRAND_MEDIUM] = new float [] {0.1f, 1f, 0.5f, 0.2f};
108 wrandTM[WRAND_HIGH] = new float [] {0.1f, 0.1f, 1f, 0.1f};
109
110 wchangeTM = new float[3][3];
111 wchangeTM[WCHANGE_SLOW] = new float [] { 1f, 1f, 0.1f};
112 wchangeTM[WCHANGE_MEDIUM] = new float [] { 1f, 1f, 1f};
113 wchangeTM[WCHANGE_FAST] = new float [] {0.1f, 1f, 1f};
114
115 fluctTM = new float[4][4];
116 fluctTM[FLUCT_NONE] = new float [] { 1f, 1f, 0.1f, 0.1f};
117 fluctTM[FLUCT_LOW] = new float [] { 1f, 1f, 1f, 0.1f};
118 fluctTM[FLUCT_MEDIUM] = new float [] {0.1f, 1f, 0.5f, 0.2f};
119 fluctTM[FLUCT_HIGH] = new float [] {0.1f, 0.1f, 1f, 0.1f};
120 }
121
122
123 public static class SlipstreamSection {
124 public Vector2f from = new Vector2f();
125 public Vector2f to = new Vector2f();
126 public Vector2f control = new Vector2f();
127
128 public int width;
129 public int wrand;
130 public int wchange;
131 public int fluct;
132
133 public boolean subdivision = false;
134 public float approxCurveLength;
135 }
136
137 public static class AddedSegment {
138 public SlipstreamSegment segment;
139 public Vector2f dir;
140 public Vector2f perp;
141 }
142
143 protected float [][] widthTM;
144 protected float [][] wrandTM;
145 protected float [][] wchangeTM;
146 protected float [][] fluctTM;
147
148 protected Random random;
149 protected SlipstreamParams2 params;
151 protected List<SlipstreamSection> sections = new ArrayList<SlipstreamSection>();
152
153 protected int currWidth = 0;
154 protected int currWRand = 0;
155 protected int currWChange = 0;
156 protected int currFluct = 0;
157
158 protected Vector2f start;
159 protected StreamType type;
160
161 public SlipstreamBuilder(Vector2f start, SlipstreamTerrainPlugin2 plugin, StreamType type, Random random) {
162 this.plugin = plugin;
163 this.type = type != null ? type : StreamType.NORMAL;
164 this.params = plugin.getParams();
165
166 if (random == null) random = Misc.random;
167 this.random = random;
168 this.start = start;
170 for (int i = 0; i < 10; i++) {
171 pickAllNext();
172 }
173 }
174
175 protected float maxAngleVarianceForCurve = 30f;
176 protected float maxAngleVariance = 60f;
177 public float getMaxAngleVariance() {
178 return maxAngleVariance;
179 }
180
182 this.maxAngleVariance = maxAngleVariance;
183 }
186 }
188 this.maxAngleVarianceForCurve = maxAngleVarianceForCurve;
189 }
190
191 public void buildToDestination(Vector2f control, Vector2f control2, Vector2f to) {
192 Vector2f p0 = new Vector2f(start);
193 Vector2f p1 = new Vector2f(control);
194 Vector2f p2 = new Vector2f(control2);
195 Vector2f p3 = new Vector2f(to);
196
197 float len = getApproximateBezierLength(p0, p1, p2, p3);
198
199 float t = 0f;
200 Vector2f prev = new Vector2f(p0);
201 while (true) {
202 float length = 3000f + random.nextInt(2000);
203 float tIncr = length / len;
204 t += tIncr;
205 if (t > 1f) t = 1f;
206
207 Vector2f loc = Misc.bezierCubic(p0, p1, p2, p3, t);
208 boolean wide = currWidth == WIDTH_WIDE || currWidth == WIDTH_VERY_WIDE;
209 pickAllNext();
211 float angle = random.nextFloat() * maxAngleVarianceForCurve - maxAngleVarianceForCurve/2f;
212 if (wide) angle *= 0.5f;
213 if (t >= 1f) angle = 0f;
214
215 loc = Misc.rotateAroundOrigin(loc, angle, prev);
216 float actualDist = Misc.getDistance(prev, loc);
217 if (actualDist > length * 0.5f) {
218 prev.set(loc);
219 addSection(new Vector2f(loc), true);
220 }
221
222 if (t >= 1f) break;
223 }
224
225 generate();
226 }
227
228 public void buildToDestination(Vector2f control, Vector2f to) {
229 Vector2f p0 = new Vector2f(start);
230 Vector2f p1 = new Vector2f(control);
231 Vector2f p2 = new Vector2f(to);
232
233 float len = getApproximateBezierLength(p0, p1, p2);
234
235 float t = 0f;
236 Vector2f prev = new Vector2f(p0);
237 while (true) {
238 float length = 3000f + random.nextInt(2000);
239 float tIncr = length / len;
240 t += tIncr;
241 if (t > 1f) t = 1f;
242
243 Vector2f loc = Misc.bezier(p0, p1, p2, t);
244 boolean wide = currWidth == WIDTH_WIDE || currWidth == WIDTH_VERY_WIDE;
245 pickAllNext();
247
248 float angle = random.nextFloat() * maxAngleVarianceForCurve - maxAngleVarianceForCurve/2f;
249 if (wide) angle *= 0.5f;
250 if (t >= 1f) angle = 0f;
251
252 loc = Misc.rotateAroundOrigin(loc, angle, prev);
253 float actualDist = Misc.getDistance(prev, loc);
254 if (actualDist > length * 0.5f) {
255 prev.set(loc);
256 addSection(new Vector2f(loc), true);
257 }
258
259 if (t >= 1f) break;
260 }
261
262 generate();
263 }
264
265 public void buildToDestination(Vector2f to) {
266 Vector2f loc = new Vector2f(start);
267 Vector2f p0 = new Vector2f(loc);
268 Vector2f p1 = new Vector2f(to);
269
270 float len = Misc.getDistance(p0, p1);
271 Vector2f dir = Misc.getUnitVector(p0, p1);
272 float dirAngle = Misc.getAngleInDegrees(dir);
273
274 float distSoFar = 0f;
275 float prevAngle = 0f;
276 for (int i = 0; distSoFar < len; i++) {
277 float angle = random.nextFloat() * maxAngleVariance - maxAngleVariance/2f;
278
279 boolean wide = currWidth == WIDTH_WIDE || currWidth == WIDTH_VERY_WIDE;
280 pickAllNext();
282 //if (wide) angle *= 0.5f;
283
284 angle += dirAngle;
285 if (i % 2 == 1) angle = prevAngle;
286 prevAngle = angle;
287 //if (i == 0) angle = 90f;
288 Vector2f add = Misc.getUnitVectorAtDegreeAngle(angle);
289 float length = 3000f + random.nextInt(2000);
290 distSoFar += length;
291 //length *= 0.25f;
292 add.scale(length);
293 Vector2f.add(loc, add, loc);
294 addSection(new Vector2f(loc), true);
295 }
296 Vector2f end = sections.get(sections.size() - 1).to;
297
298
299 float actualAngle = Misc.getAngleInDegrees(p0, end);
300 float angleDiff = Misc.getAngleDiff(dirAngle, actualAngle);
301 float turnDir = Misc.getClosestTurnDirection(actualAngle, dirAngle);
302
303 for (SlipstreamSection section : sections) {
304 section.from = Misc.rotateAroundOrigin(section.from, angleDiff * turnDir, p0);
305 section.to = Misc.rotateAroundOrigin(section.to, angleDiff * turnDir, p0);
306 }
307
308 end = sections.get(sections.size() - 1).to;
309 float actualDist = Misc.getDistance(p0, end);
310 float distToAdd = len - actualDist;
311
312 //System.out.println("Distance short: " + distToAdd);
313 if (distToAdd > 1000) {
314 angleDiff = Misc.getAngleDiff(dirAngle, prevAngle);
315 turnDir = Misc.getClosestTurnDirection(actualAngle, dirAngle);
316 float turnAmount = Math.min(30f, angleDiff) * turnDir;
317 //float turnAmount = angleDiff * turnDir;
318
319 Vector2f add = Misc.getUnitVectorAtDegreeAngle(prevAngle + turnAmount);
320 float length = distToAdd;
321 add.scale(length);
322 loc = Vector2f.add(end, add, loc);
323 addSection(new Vector2f(loc));
324 }
325
326 generate();
327 }
328
329
330 protected float [] buildNoise;
331 public void buildTest() {
332
333 if (false) {
334 Vector2f loc = new Vector2f(start);
335
336 Vector2f p0 = loc;
337 Vector2f p1 = new Vector2f(loc);
338 float w = 15000;
339 float h = 15000;
340 h = 0f;
341 w = 25000f;
342 w = 20000f;
343 p1.x += w;
344 p1.y += h;
345 float len = Misc.getDistance(p0, p1);
346 Vector2f dir = Misc.getUnitVector(p0, p1);
347 Vector2f perp = new Vector2f(-dir.y, dir.x);
348
349 float averageSection = 4000;
350
351 int numNoisePoints = 32;
352 while (numNoisePoints < len / averageSection) {
353 numNoisePoints *= 2f;
354 }
355 if (numNoisePoints > 2048) numNoisePoints = 2048;
356 float spikes = 0.75f;
357 float [] noise = initNoise1D(random, numNoisePoints, spikes);
358 noise[0] = 0.5f;
359 noise[noise.length - 1] = 0.5f;
360 genNoise1D(random, noise, numNoisePoints, spikes);
361 normalizeNoise1D(noise);
362 buildNoise = noise;
363
364 float startLength = 1500 + random.nextFloat() * 1500f;
365 float endLength = 1500 + random.nextFloat() * 1500f;
366 Vector2f curr = new Vector2f(dir);
367 curr.scale(startLength);
368 Vector2f.add(curr, p0, curr);
369 addSection(curr);
370
371
372 float mid = len - startLength - endLength;
373 float remaining = mid;
374 float distSoFar = startLength;
375
376 //float maxMag = 500f + mid * 0.025f + random.nextFloat() * (2000f + mid * 0.05f);
377 //float maxMag = 500f + mid * 0.025f + 1f * (2000f + mid * 0.05f);
378 float maxMag = 500f + mid * 0.01f + 1f * (1000f + mid * 0.025f);
379
380 while (remaining > 0) {
381 float segLen = 3000f + random.nextFloat() * 2000f;
382 segLen = Math.min(segLen, remaining);
383 remaining -= segLen;
384 if (remaining < segLen * 0.5f) {
385 segLen += remaining;
386 remaining = 0f;
387 }
388 distSoFar += segLen;
389
390 float t = (distSoFar - startLength) / mid;
391 float n = getInterpNoise(noise, t) - 0.5f;
392
393 if (t < 0.25f) {
394 n *= t / 0.25f;
395 } else if (t > 0.75f) {
396 n *= (1f - t) / 0.25f;
397 }
398
399 n *= 2f;
400
401 curr = new Vector2f(dir);
402 curr.scale(distSoFar);
403 Vector2f.add(curr, p0, curr);
404 curr.x += perp.x * maxMag * n;
405 curr.y += perp.y * maxMag * n;
406 addSection(curr);
407 }
408
409 addSection(p1);
410
411 generate();
412 return;
413 }
414
415 if (true) {
416 Vector2f loc = new Vector2f(start);
417 Vector2f p0 = new Vector2f(loc);
418 Vector2f p1 = new Vector2f(loc);
419 float w = 15000;
420 float h = 15000;
421 h = 0f;
422 w = 25000f;
423 //w = 80000f;
424 w = 50000f;
425// h = 50000f;
426// w = 164000f;
427// h = 104000f;
428 p1.x += w;
429 p1.y += h;
430 float len = Misc.getDistance(p0, p1);
431 Vector2f dir = Misc.getUnitVector(p0, p1);
432 Vector2f perp = new Vector2f(-dir.y, dir.x);
433 float dirAngle = Misc.getAngleInDegrees(dir);
434
435 float distSoFar = 0f;
436 float prevAngle = 0f;
437 for (int i = 0; distSoFar < len; i++) {
438 float angle = random.nextFloat() * 60f - 30f;
439 //float angle = StarSystemGenerator.getNormalRandom(random, -30f, 30f);
440 angle += dirAngle;
441 if (i % 2 == 1) angle = prevAngle;
442 prevAngle = angle;
443 //if (i == 0) angle = 90f;
444 Vector2f add = Misc.getUnitVectorAtDegreeAngle(angle);
445 float length = 3000f + random.nextInt(2000);
446 distSoFar += length;
447 //length *= 0.25f;
448 add.scale(length);
449 Vector2f.add(loc, add, loc);
450 addSection(new Vector2f(loc));
451 }
452 Vector2f end = sections.get(sections.size() - 1).to;
453
454
455 float actualAngle = Misc.getAngleInDegrees(p0, end);
456 float angleDiff = Misc.getAngleDiff(dirAngle, actualAngle);
457 float turnDir = Misc.getClosestTurnDirection(actualAngle, dirAngle);
458
459 for (SlipstreamSection section : sections) {
460 section.from = Misc.rotateAroundOrigin(section.from, angleDiff * turnDir, p0);
461 section.to = Misc.rotateAroundOrigin(section.to, angleDiff * turnDir, p0);
462 }
463
464 end = sections.get(sections.size() - 1).to;
465 float actualDist = Misc.getDistance(p0, end);
466 float distToAdd = len - actualDist;
467 //System.out.println("Distance short: " + distToAdd);
468 if (distToAdd > 1000) {
469 angleDiff = Misc.getAngleDiff(dirAngle, prevAngle);
470 turnDir = Misc.getClosestTurnDirection(actualAngle, dirAngle);
471 float turnAmount = Math.min(30f, angleDiff) * turnDir;
472 //float turnAmount = angleDiff * turnDir;
473
474 Vector2f add = Misc.getUnitVectorAtDegreeAngle(prevAngle + turnAmount);
475 float length = distToAdd;
476 add.scale(length);
477 loc = Vector2f.add(end, add, loc);
478 addSection(new Vector2f(loc));
479 }
480
481 generate();
482
483 //System.out.println("Segments: " + plugin.getSegments().size());
484 return;
485 }
486
487 if (true) {
488 Vector2f loc = new Vector2f(start);
489 float prevAngle = 0f;
490 for (int i = 0; i < 20; i++) {
491 float angle = random.nextFloat() * 60f - 30f;
492 if (i % 2 == 1) angle = prevAngle;
493 prevAngle = angle;
494 //if (i == 0) angle = 90f;
495 Vector2f add = Misc.getUnitVectorAtDegreeAngle(angle);
496 float length = 3000f + random.nextInt(2000);
497 //length *= 0.25f;
498 add.scale(length);
499 Vector2f.add(loc, add, loc);
500 addSection(new Vector2f(loc));
501 }
502 generate();
503 return;
504 }
505
506 if (true) {
507 Vector2f loc = new Vector2f(start);
508
509 Vector2f p0 = loc;
510 Vector2f p1 = new Vector2f(loc);
511 float w = 15000;
512 float h = 15000;
513 h = 0f;
514 w = 25000f;
515 w = 80000f;
516 p1.x += w;
517 p1.y += h;
518 float len = Misc.getDistance(p0, p1);
519 Vector2f dir = Misc.getUnitVector(p0, p1);
520 Vector2f perp = new Vector2f(-dir.y, dir.x);
521
522 //System.out.println("LEN: " + len);
523
524 if (len <= 7000f) {
525 addSection(p1);
526 generate();
527 return;
528 }
529 if (len <= 15000f) {
530 float midLength = len * (0.4f + random.nextFloat() * 0.2f);
531
532 Vector2f curr = new Vector2f(dir);
533 curr.scale(1000f + random.nextFloat() * 1000f);
534 Vector2f.add(curr, p0, curr);
535 addSection(new Vector2f(curr));
536
537 curr = new Vector2f(dir);
538 curr.scale(midLength);
539
540 float mag = 0f + random.nextFloat() * 1000f + len * 0.05f;
541 if (random.nextFloat() < 0.75f) {
542 if (random.nextBoolean()) {
543 perp.negate();
544 }
545 curr.x += perp.x * mag;
546 curr.y += perp.y * mag;
547 }
548
549 Vector2f.add(curr, p0, curr);
550 addSection(curr);
551
552 float endLength = 1000f + random.nextFloat() * 1000f;
553 curr = new Vector2f(dir);
554 curr.scale(len - endLength);
555 Vector2f.add(curr, p0, curr);
556 addSection(curr);
557
558 addSection(p1);
559
560 generate();
561 return;
562 }
563
564
565
566 float startLength = 1500 + random.nextFloat() * 1500f;
567 float endLength = 1500 + random.nextFloat() * 1500f;
568 Vector2f curr = new Vector2f(dir);
569 curr.scale(startLength);
570 Vector2f.add(curr, p0, curr);
571 addSection(curr);
572
573 float remaining = len - startLength - endLength;
574 float distSoFar = startLength;
575 while (remaining > 0) {
576 float lengthForArc = 10000f + random.nextFloat() * 20000f;
577 lengthForArc = Math.min(lengthForArc, remaining);
578 remaining -= lengthForArc;
579 if (remaining < 10000f) {
580 lengthForArc += remaining;
581 remaining = 0f;
582 }
583
584 if (random.nextBoolean()) {
585 perp.negate();
586 }
587
588 float maxMag = 500f + random.nextFloat() * (2000f + lengthForArc * 0.1f);
589 maxMag = 4000;
590 float t = 0f;
591 while (t < 1f) {
592 float perIter = 3000f + random.nextFloat() * 2000f;
593 float tForIter = perIter / lengthForArc;
594 t += tForIter;
595 if (t > 1f - tForIter * 0.5f) {
596 tForIter += 1f - t;
597 t = 1f;
598 }
599 perIter = tForIter * lengthForArc;
600 distSoFar += perIter;
601
602 float mag = getFluctuationFunc(t) * maxMag;
603 curr = new Vector2f(dir);
604 curr.scale(distSoFar);
605 Vector2f.add(curr, p0, curr);
606 curr.x += perp.x * mag;
607 curr.y += perp.y * mag;
608 addSection(new Vector2f(curr));
609 }
610 }
611
612 addSection(p1);
613 generate();
614 return;
615 }
616
617
618 if (false) {
619 Vector2f loc = new Vector2f(start);
620
621 Vector2f p0 = loc;
622 Vector2f p3 = new Vector2f(loc);
623 float w = 30000;
624 float h = 30000;
625 p3.x += w;
626 p3.y += h;
627 float len = Misc.getDistance(p0, p3);
628
629// Vector2f p1 = new Vector2f(p0);
630// Vector2f p2 = new Vector2f(p3);
631
632 Vector2f p1 = Vector2f.add(p0, p3, new Vector2f());
633 p1.scale(0.5f);
634 Vector2f p2 = new Vector2f(p1);
635
636 p1.x -= len * 0.2f;
637 p1.y += len * 0.2f;
638 p2.x += len * 0.2f;
639 p2.y -= len * 0.2f;
640
641 float dist1 = len * 0.5f + random.nextFloat() * len * 0.5f;
642 float dist2 = len * 0.5f + random.nextFloat() * len * 0.5f;
643
644 p1 = Misc.getPointAtRadius(p0, dist1, random);
645 p2 = Misc.getPointAtRadius(p3, dist2, random);
646
647 p1 = new Vector2f(p0.x, p3.y);
648 p2 = new Vector2f(p3.x, p0.y);
649
650 if (random.nextBoolean()) {
651 Vector2f temp = p1;
652 p1 = p2;
653 p2 = temp;
654 }
655
656 float veryApproxPathLength = len * 1.5f;
657 float tPerIter = 8000f / (veryApproxPathLength + 1f);
658
659 float t = 0f;
660 while (t < 1f) {
661 t += tPerIter * (0.8f + 0.4f * random.nextFloat());
662 if (t > 1f - tPerIter * 0.5f) t = 1f;
663
664 Vector2f curr = Misc.bezierCubic(p0, p1, p2, p3, t);
665 addSection(new Vector2f(curr));
666 }
667 generate();
668 return;
669 }
670
671 if (false) {
672 Vector2f loc = new Vector2f(start);
673
674 Vector2f p0 = loc;
675 Vector2f p2 = new Vector2f(loc);
676 float w = 30000;
677 float h = 30000;
678 p2.x += w;
679 p2.y += h;
680 float len = Misc.getDistance(p0, p2);
681
682 Vector2f p1 = Vector2f.add(p0, p2, new Vector2f());
683 p1.scale(0.5f);
684 p1.x -= len * 0.25f;
685 p1.y += len * 0.25f;
686
687 float approxPathLength = getApproximateBezierLength(p0, p1, p2);
688 float tPerIter = 8000f / (approxPathLength + 1f);
689
690 float t = 0f;
691 while (t < 1f) {
692 t += tPerIter * (0.8f + 0.4f * random.nextFloat());
693 if (t > 1f - tPerIter * 0.5f) t = 1f;
694
695 Vector2f curr = Misc.bezier(p0, p1, p2, t);
696 addSection(new Vector2f(curr));
697 }
698 generate();
699 return;
700 }
701
702
703 if (false) {
704 Vector2f loc = new Vector2f(start);
705 loc.x += 5000;
706 addSection(loc, 1, 0, 0, 3);
707 loc.x += 5000;
708 addSection(loc, 1, 0, 0, 3);
709 loc.x += 5000;
710 addSection(loc, 1, 0, 0, 3);
711 loc.x += 5000;
712 addSection(loc, 1, 0, 0, 3);
713
714 loc.x += 5000;
715 loc.y += 5000;
716 addSection(loc, 0, 0, 0, 3);
717 loc.y += 2000;
718 addSection(loc, 0, 0, 0, 3);
719 loc.x -= 5000;
720 loc.y += 5000;
721 addSection(loc, 0, 0, 0, 3);
722 loc.x -= 5000;
723 addSection(loc, 0, 0, 0, 3);
724 generate();
725 return;
726 }
727
728 Vector2f loc = new Vector2f(start);
729 float prevAngle = 0f;
730 for (int i = 0; i < 20; i++) {
731 float angle = random.nextFloat() * 60f - 30f;
732 if (i % 2 == 1) angle = prevAngle;
733 prevAngle = angle;
734 //if (i == 0) angle = 90f;
735 Vector2f add = Misc.getUnitVectorAtDegreeAngle(angle);
736 float length = 3000f + random.nextInt(2000);
737 //length *= 0.25f;
738 add.scale(length);
739 Vector2f.add(loc, add, loc);
740 addSection(new Vector2f(loc));
741 }
742
743 generate();
744 }
745
746 public void generate() {
747
748// MIN_SPACING = 200f;
749// MAX_SPACING = 400f;
750// WIDTH_TO_SPACING_MULT = 0.2f;
751// MIN_SPACING = 300f;
752// MAX_SPACING = 600f;
753// WIDTH_TO_SPACING_MULT = 0.4f;
754// long seed = 23895464576452L + 4384357483229348234L;
755// seed = 1181783497276652981L ^ seed;
756// this.random = new Random(seed);
757
759 buildStream();
760 }
761
762
763 public void buildStream() {
764 plugin.setBuilder(this);
765 if (sections.isEmpty()) return;
766
767
768 float totalCurveLength = 0f;
769 for (SlipstreamSection curr : sections) {
770 totalCurveLength += curr.approxCurveLength;
771 }
772
773 int numNoisePoints = 32;
774 while (numNoisePoints * (MIN_SPACING + MAX_SPACING) / 2f < totalCurveLength) {
775 numNoisePoints *= 2f;
776 }
777 if (numNoisePoints > 2048) numNoisePoints = 2048;
778
779 float spikes = 0.67f;
780 float [] noiseForWidth = initNoise1D(random, numNoisePoints, spikes);
781 noiseForWidth[0] = 0.5f;
782 noiseForWidth[noiseForWidth.length - 1] = 0.5f;
783 genNoise1D(random, noiseForWidth, numNoisePoints, spikes);
784 normalizeNoise1D(noiseForWidth);
785
786 float width = getGoalWidth(sections.get(0));
787 //width *= 3f;
788 //width *= .5f;
789
790
791 float curveLengthSoFar = 0f;
792 for (SlipstreamSection curr : sections) {
793 //curr.fluct = FLUCT_NONE;
794 //curr.fluct = FLUCT_LOW;
795 //curr.fluct = FLUCT_MEDIUM;
796 //curr.fluct = FLUCT_HIGH;
797
798 float startingWidth = width;
799 float goalWidth = getGoalWidth(curr);
800 float changeRate = getWChangeMult(curr);
801 float wrandMult = getWRandMult(curr);
802 float fluctMult = getFluctMult(curr);
803
804
805 float desiredSpacing = Math.max(MIN_SPACING, width * WIDTH_TO_SPACING_MULT);
806 if (desiredSpacing > MAX_SPACING) desiredSpacing = MAX_SPACING;
807
808 int segments = (int) (curr.approxCurveLength / desiredSpacing);
809 if (segments < 2) segments = 2;
810 float spacing = curr.approxCurveLength / segments;
811
812 List<AddedSegment> added = new ArrayList<AddedSegment>();
813
814 int startIndex = 1;
815 if (getPrev(curr) == null) startIndex = 0;
816 for (int i = startIndex; i < segments; i++) {
817 float f = (float)i / ((float)segments - 1f);
818 float f2 = (float)(i + 0.1f) / ((float)segments - 1f);
819
820 width = Misc.interpolate(startingWidth, goalWidth, Math.min(1f, f * f * changeRate));
821 float t = (curveLengthSoFar + f * curr.approxCurveLength) / totalCurveLength;
822 float wNoise = (getInterpNoise(noiseForWidth, t) - 0.5f) * 2f;
823 wNoise *= wrandMult;
824 //wNoise *= 3f;
825 width *= (1f + wNoise);
826
827 Vector2f loc = Misc.bezier(curr.from, curr.control, curr.to, f);
828 Vector2f loc2 = Misc.bezier(curr.from, curr.control, curr.to, f2);
829 Vector2f dir = Vector2f.sub(loc2, loc, new Vector2f());
830 Misc.normalise(dir);
831 Vector2f perp = new Vector2f(-dir.y, dir.x);
832
833 plugin.addSegment(loc, width);
834 AddedSegment seg = new AddedSegment();
835 seg.segment = plugin.getSegments().get(plugin.getSegments().size() - 1);
836 seg.dir = new Vector2f(dir);
837 seg.perp = new Vector2f(perp);
838 added.add(seg);
839 }
840
841 float distPerFluct = FLUCT_LENGTH_MIN + random.nextFloat() * (FLUCT_LENGTH_MAX - FLUCT_LENGTH_MIN);
842 float fluctAmount = FLUCT_MAG_MIN + random.nextFloat() * (FLUCT_MAG_MAX - FLUCT_MAG_MIN);
843 float fluctDir = Math.signum(random.nextFloat() - 0.5f);
844 float distSoFar = 0f;
845 List<AddedSegment> temp = new ArrayList<AddedSegment>();
846 AddedSegment prev = null;
847 for (AddedSegment seg : added) {
848 if (prev != null) {
849 distSoFar += Misc.getDistance(seg.segment.loc, prev.segment.loc);
850 }
851 temp.add(seg);
852 prev = seg;
853
854 if (distSoFar > distPerFluct && temp.size() >= 4) {
855 for (int i = 0; i < temp.size(); i++) {
856 float t = i / (temp.size() - 1f);
857 AddedSegment seg2 = temp.get(i);
858
859 float fluctMag = getFluctuationFunc(t);
860 fluctMag *= fluctMult;
861 //fluctDir = 1f;
862
863 fluctMag *= fluctAmount * fluctDir;
864
865 seg2.segment.loc.x += seg2.perp.x * fluctMag;
866 seg2.segment.loc.y += seg2.perp.y * fluctMag;
867
868 }
869 temp.clear();
870 distSoFar = 0f;
871 distPerFluct = FLUCT_LENGTH_MIN + random.nextFloat() * (FLUCT_LENGTH_MAX - FLUCT_LENGTH_MIN);
872 fluctAmount = FLUCT_MAG_MIN + random.nextFloat() * (FLUCT_MAG_MAX - FLUCT_MAG_MIN);
873 fluctDir = Math.signum(random.nextFloat() - 0.5f);
874 }
875 }
876
877 curveLengthSoFar += curr.approxCurveLength;
878 }
879
881
882 float fadeDist = 500f;
883 float distSoFar = 0f;
884 SlipstreamSegment prev = null;
885 for (int i = 0; i < plugin.getSegments().size(); i++) {
886 SlipstreamSegment curr = plugin.getSegments().get(i);
887 if (prev != null) {
888 distSoFar += Misc.getDistance(prev.loc, curr.loc);
889 }
890 if (distSoFar >= fadeDist) {
891 break;
892 }
893
894 float b = distSoFar / fadeDist;
895 if (b < 0f) b = 0f;
896 if (b > 1f) b = 1f;
897 curr.bMult = b;
898 prev = curr;
899 }
900
901 distSoFar = 0f;
902 prev = null;
903 for (int i = plugin.getSegments().size() - 1; i >= 0; i--) {
904 SlipstreamSegment curr = plugin.getSegments().get(i);
905 if (prev != null) {
906 distSoFar += Misc.getDistance(prev.loc, curr.loc);
907 }
908 if (distSoFar >= fadeDist) {
909 break;
910 }
911
912 float b = distSoFar / fadeDist;
913 if (b < 0f) b = 0f;
914 if (b > 1f) b = 1f;
915 curr.bMult = b;
916 prev = curr;
917 }
918 }
919
920 protected float getFluctuationFunc(float t) {
921 float pi = (float) Math.PI;
922 return ((float)Math.cos(pi + 2f * pi * t) + 1f) * 0.5f;
923 }
924
926 for (int i = 1; i < plugin.getSegments().size() - 1; i++) {
927 SlipstreamSegment prev = plugin.getSegments().get(i - 1);
928 SlipstreamSegment curr = plugin.getSegments().get(i);
929 SlipstreamSegment next = plugin.getSegments().get(i + 1);
930
931 float dir1 = Misc.getAngleInDegrees(prev.loc, curr.loc);
932 float dir2 = Misc.getAngleInDegrees(curr.loc, next.loc);
933 float diff = Misc.getAngleDiff(dir1, dir2);
934 if (diff > 5f) {
935 Vector2f avg = Vector2f.add(prev.loc, next.loc, new Vector2f());
936 avg.scale(0.5f);
937 curr.loc.set(Misc.interpolateVector(curr.loc, avg, 0.67f));
938 //i++;
939 }
940 }
941 }
942
943 protected float getWRandMult(SlipstreamSection curr) {
944 float mult = 0f;
945 if (curr.wrand == WRAND_NONE) {
946 mult = WRAND_NONE_MULT;
947 } else if (curr.wrand == WRAND_LOW) {
948 mult = WRAND_LOW_MULT;
949 } else if (curr.wrand == WRAND_MEDIUM) {
950 mult = WRAND_MEDIUM_MULT;
951 } else if (curr.wrand == WRAND_HIGH) {
952 mult = WRAND_HIGH_MULT;
953 }
954 //mult *= 0.9f + 0.2f * random.nextFloat();
955 return mult;
956 }
957
958 protected float getFluctMult(SlipstreamSection curr) {
959 float mult = 0f;
960 if (curr.fluct == FLUCT_NONE) {
961 mult = FLUCT_NONE_MULT;
962 } else if (curr.fluct == WRAND_LOW) {
963 mult = FLUCT_LOW_MULT;
964 } else if (curr.fluct == FLUCT_MEDIUM) {
965 mult = FLUCT_MEDIUM_MULT;
966 } else if (curr.fluct == FLUCT_HIGH) {
967 mult = FLUCT_HIGH_MULT;
968 }
969 mult *= 0.9f + 0.2f * random.nextFloat();
970 return mult;
971 }
972
973 protected float getWChangeMult(SlipstreamSection curr) {
974 float mult = 1f;
975 if (curr.wchange == WCHANGE_SLOW) {
977 } else if (curr.wchange == WCHANGE_MEDIUM) {
979 } else if (curr.wchange == WCHANGE_FAST) {
981 }
982 return mult;
983 }
984
985 protected float getGoalWidth(SlipstreamSection curr) {
986 float goalWidth = params.baseWidth;
987 float mult = 1f;
988 if (curr.width == WIDTH_NARROW) {
989 mult = MIN_NARROW + random.nextFloat() * (MAX_NARROW - MIN_NARROW);
990 } else if (curr.width == WIDTH_NORMAL) {
991 mult = MIN_NORMAL + random.nextFloat() * (MAX_NORMAL - MIN_NORMAL);
992 } else if (curr.width == WIDTH_WIDE) {
993 mult = MIN_WIDE + random.nextFloat() * (MAX_WIDE - MIN_WIDE);
994 } else if (curr.width == WIDTH_VERY_WIDE) {
995 mult = MIN_VERY_WIDE + random.nextFloat() * (MAX_VERY_WIDE - MIN_VERY_WIDE);
996 }
997 return goalWidth * mult;
998 }
999
1000 protected void computeControlPoints() {
1001 float angleLimit = 30f;
1002 for (SlipstreamSection curr : sections) {
1003 SlipstreamSection prev = getPrev(curr);
1004 SlipstreamSection next = getNext(curr);
1005
1006
1007 if (prev == null && next == null) {
1008 curr.control = Vector2f.add(curr.from, curr.to, new Vector2f());
1009 curr.control.scale(0.5f);
1010 } else if (prev == null && next != null) {
1011 Vector2f p1 = curr.from;
1012 Vector2f p2 = curr.to;
1013 Vector2f p3 = next.to;
1014 float angleP2ToControl = Misc.getAngleInDegrees(p3, p2);
1015 Vector2f dirP2ToControl = Misc.getUnitVectorAtDegreeAngle(angleP2ToControl);
1016 Vector2f p2ToP1 = Vector2f.sub(p1, p2, new Vector2f());
1017 float angleP2toP1 = Misc.getAngleInDegrees(p2ToP1);
1018 float angleToControlAndP2toP1 = Vector2f.angle(dirP2ToControl, p2ToP1) * Misc.DEG_PER_RAD;
1019 if (angleToControlAndP2toP1 > angleLimit) {
1020 angleToControlAndP2toP1 = angleLimit;
1021 float turnDir = Misc.getClosestTurnDirection(angleP2toP1, angleP2ToControl);
1022 angleP2ToControl = angleP2toP1 + turnDir * angleToControlAndP2toP1;
1023 dirP2ToControl = Misc.getUnitVectorAtDegreeAngle(angleP2ToControl);
1024 }
1025 float dist = Misc.getDistance(p1, p2);
1026 dist /= 2f;
1027 float h = dist * (float) Math.tan(angleToControlAndP2toP1 * Misc.RAD_PER_DEG);
1028 float b = (float) Math.sqrt(dist * dist + h * h);
1029 dirP2ToControl.scale(b);
1030 Vector2f.add(dirP2ToControl, p2, curr.control);
1031 } else {
1032 Vector2f p1 = prev.control;
1033 Vector2f p2 = curr.from;
1034 Vector2f p3 = curr.to;
1035 float angleP2ToControl = Misc.getAngleInDegrees(p1, p2);
1036 Vector2f dirP2ToControl = Misc.getUnitVectorAtDegreeAngle(angleP2ToControl);
1037 Vector2f p2ToP3 = Vector2f.sub(p3, p2, new Vector2f());
1038 float angleP2ToP3 = Misc.getAngleInDegrees(p2ToP3);
1039 float angleToControlAndP2toP3 = Vector2f.angle(dirP2ToControl, p2ToP3) * Misc.DEG_PER_RAD;
1040 if (angleToControlAndP2toP3 > angleLimit) {
1041 angleToControlAndP2toP3 = angleLimit;
1042 float turnDir = Misc.getClosestTurnDirection(angleP2ToP3, angleP2ToControl);
1043 angleP2ToControl = angleP2ToP3 + turnDir * angleToControlAndP2toP3;
1044 dirP2ToControl = Misc.getUnitVectorAtDegreeAngle(angleP2ToControl);
1045 }
1046
1047 float dist = Misc.getDistance(p2, p3);
1048 dist /= 2f;
1049 float h = dist * (float) Math.tan(angleToControlAndP2toP3 * Misc.RAD_PER_DEG);
1050 float b = (float) Math.sqrt(dist * dist + h * h);
1051 dirP2ToControl.scale(b);
1052 Vector2f.add(dirP2ToControl, p2, curr.control);
1053 }
1054
1055 curr.approxCurveLength = getApproximateBezierLength(curr.from, curr.control, curr.to);
1056 }
1057 }
1058
1059 public void addSection(Vector2f to) {
1060 addSection(to, false);
1061 }
1062 public void addSection(Vector2f to, boolean alreadyPicked) {
1063 if (!alreadyPicked) {
1064 pickAllNext();
1065 }
1067 }
1068
1069 public void addSection(Vector2f to, int width, int wrand, int wchange, int fluct) {
1070 addSection(to, width, wrand, wchange, fluct, -1);
1071 }
1072
1073 public void addSection(Vector2f to, int width, int wrand, int wchange, int fluct, int insertIndex) {
1074 SlipstreamSection s = new SlipstreamSection();
1075 s.to.set(to);
1076 s.width = width;
1077 s.wrand = wrand;
1078 s.wchange = wchange;
1079 s.fluct = fluct;
1080
1081 if (insertIndex < 0) {
1082 sections.add(s);
1083 } else {
1084 sections.add(insertIndex, s);
1085 }
1086
1087 SlipstreamSection p = getPrev(s);
1088 if (p != null) {
1089 s.from.set(p.to);
1090 } else {
1091 s.from.set(start);
1092 }
1093 }
1094
1095
1096 public SlipstreamSection getPrev(SlipstreamSection s) {
1097 int index = sections.indexOf(s);
1098 if (index < 1) return null;
1099 return sections.get(index - 1);
1100 }
1101 public SlipstreamSection getNext(SlipstreamSection s) {
1102 int index = sections.indexOf(s);
1103 if (index < 0 || index >= sections.size() - 1) return null;
1104 return sections.get(index + 1);
1105 }
1106
1107 public void pickAllNext() {
1112
1113 if (currWidth == WIDTH_NARROW) {
1114 if (currFluct == FLUCT_HIGH) {
1116 } else if (currFluct == FLUCT_MEDIUM) {
1118 }
1119 }
1120 }
1121
1122 public int pickWidth(int curr) {
1123 return pickNext(curr, widthTM);
1124 }
1125
1126 public int pickWRand(int curr) {
1127 return pickNext(curr, wrandTM);
1128 }
1129
1130 public int pickWChange(int curr) {
1131 return pickNext(curr, wchangeTM);
1132 }
1133
1134 public int pickFluct(int curr) {
1135 return pickNext(curr, fluctTM);
1136 }
1137
1138 public int pickNext(int curr, float [][] matrix) {
1139 float [] weights = matrix[curr];
1140 WeightedRandomPicker<Integer> picker = new WeightedRandomPicker<Integer>(random);
1141 for (int i = 0; i < weights.length; i++) {
1142 picker.add(i, weights[i]);
1143 }
1144 return picker.pick();
1145 }
1146
1147
1148 public void renderDebug(float alpha) {
1149 //if (true) return;
1150
1151 GL11.glDisable(GL11.GL_TEXTURE_2D);
1152 GL11.glEnable(GL11.GL_BLEND);
1153 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
1154
1155// float scale = 0.25f;
1156// //scale = 1f;
1157// GL11.glPushMatrix();
1158// GL11.glTranslatef(sections.get(0).from.x, sections.get(0).from.y, 0f);
1159// GL11.glScalef(scale, scale, 1f);
1160// GL11.glTranslatef(sections.get(0).from.x * -scale, sections.get(0).from.y * -scale, 0f);
1161
1162 if (false) {
1163 Misc.setColor(Color.white);
1164 GL11.glEnable(GL11.GL_LINE_SMOOTH);
1165 GL11.glLineWidth(3f);
1166 GL11.glBegin(GL11.GL_LINE_STRIP);
1167 Vector2f p0 = new Vector2f(0, 0);
1168 Vector2f p1 = new Vector2f(10000, 0);
1169 Vector2f p2 = new Vector2f(0, 10000);
1170 Vector2f p3 = new Vector2f(10000, 10000);
1171 for (float t = 0f; t <= 1f; t += 0.02f) {
1172 Vector2f p = Misc.bezierCubic(p0, p1, p2, p3, t);
1173 GL11.glVertex2f(p.x, p.y);
1174 }
1175 GL11.glEnd();
1176 }
1177
1178 if (false) {
1179 GL11.glEnable(GL11.GL_POINT_SMOOTH);
1180 GL11.glPointSize(10f);
1181 GL11.glBegin(GL11.GL_POINTS);
1182 Misc.setColor(Color.yellow);
1183 for (SlipstreamSection curr : sections) {
1184 Misc.setColor(Color.yellow);
1185 if (curr.subdivision) {
1186 Misc.setColor(Color.green);
1187 }
1188 Vector2f p = curr.from;
1189 GL11.glVertex2f(p.x, p.y);
1190 p = curr.to;
1191 GL11.glVertex2f(p.x, p.y);
1192
1193 Misc.setColor(Color.cyan);
1194 p = curr.control;
1195 GL11.glVertex2f(p.x, p.y);
1196 }
1197 GL11.glEnd();
1198
1199 Misc.setColor(Color.white);
1200 GL11.glEnable(GL11.GL_LINE_SMOOTH);
1201 GL11.glLineWidth(3f);
1202 GL11.glBegin(GL11.GL_LINE_STRIP);
1203 for (SlipstreamSection curr : sections) {
1204 for (float t = 0f; t <= 1f; t += 0.02f) {
1205 Vector2f p = Misc.bezier(curr.from, curr.control, curr.to, t);
1206 GL11.glVertex2f(p.x, p.y);
1207 }
1208 }
1209 GL11.glEnd();
1210 }
1211
1212 for (BoundingBox box : plugin.getBounds()) {
1213 Misc.setColor(Color.cyan);
1214 GL11.glEnable(GL11.GL_LINE_SMOOTH);
1215 GL11.glLineWidth(3f);
1216 GL11.glBegin(GL11.GL_LINE_LOOP);
1217 if (box != null) {
1218 for (Vector2f p : box.box) {
1219 GL11.glVertex2f(p.x, p.y);
1220 }
1221 }
1222 GL11.glEnd();
1223 }
1224
1225 GL11.glPopMatrix();
1226
1227 if (false) {
1228 GL11.glPushMatrix();
1229 Vector2f loc = Global.getSector().getPlayerFleet().getLocation();
1230 GL11.glTranslatef(loc.x - 1000, loc.y + 100, 0f);
1231//
1232// long seed = 23895464576452L + 4384357483229348234L;
1233// //seed += System.nanoTime() / 1000000000L;
1234// seed = 1181783497276652981L ^ seed;
1235// Random random = new Random(seed);
1236// float spikes = 0.67f;
1237// float [] noise = initNoise1D(random, 128, spikes);
1238// noise[0] = 0.5f;
1239// noise[noise.length - 1] = 0.5f;
1240// genNoise1D(random, noise, 128, spikes);
1241// normalizeNoise1D(noise);
1242
1243 Misc.setColor(Color.orange);
1244 GL11.glEnable(GL11.GL_LINE_SMOOTH);
1245 GL11.glLineWidth(3f);
1246 GL11.glBegin(GL11.GL_LINE_STRIP);
1247 float horz = 50f;
1248 float vert = 500f;
1249 for (int i = 0; i < buildNoise.length; i++) {
1250 float f = buildNoise[i];
1251 GL11.glVertex2f(i * horz, f * vert);
1252 }
1253 GL11.glEnd();
1254// GL11.glBegin(GL11.GL_LINE_STRIP);
1255// float iter = 2000f;
1256// for (int i = 0; i < iter; i++) {
1257// float f = getInterpNoise(noise, i / iter);
1258// GL11.glVertex2f(i, f * vert);
1259// }
1260// GL11.glEnd();
1261 Misc.setColor(Color.white);
1262 GL11.glBegin(GL11.GL_LINES);
1263 GL11.glVertex2f(0, 0);
1264 GL11.glVertex2f(buildNoise.length * horz, 0);
1265 GL11.glVertex2f(0, 0);
1266 GL11.glVertex2f(0, vert);
1267 GL11.glEnd();
1268
1269 GL11.glPopMatrix();
1270 }
1271 }
1272
1273 public static float getInterpNoise(float [] noise, float t) {
1274 t *= noise.length;
1275 int index = (int) t;
1276 if (index >= noise.length) index = noise.length - 1;
1277 if (index < 0) index = 0;
1278
1279 int index2 = index + 1;
1280 if (index2 >= noise.length) index2 = index - 1;
1281
1282 float f = t - index;
1283
1284 return Misc.interpolate(noise[index], noise[index2], f);
1285 }
1286
1287
1292 public static void normalizeNoise1D(float [] noise) {
1293 float min = Float.MAX_VALUE;
1294 float max = -Float.MAX_VALUE;
1295 for (float f : noise) {
1296 if (f < min) min = f;
1297 if (f > max) max = f;
1298 }
1299
1300 if (max <= min) {
1301 for (int i = 0; i < noise.length; i++) {
1302 noise[i] = 0.5f;
1303 }
1304 return;
1305 }
1306
1307 float range = max - min;
1308 for (int i = 0; i < noise.length; i++) {
1309 noise[i] = (noise[i] - min) / range;
1310 }
1311 }
1312
1313 public static float [] initNoise1D(Random random, int size, float spikes) {
1314 float [] noise = new float[size];
1315 for (int i = 0; i < noise.length; i++) {
1316 noise[i] = -1f;
1317 }
1318 noise[0] = random.nextFloat() * spikes;
1319 noise[noise.length - 1] = random.nextFloat() * spikes;
1320 return noise;
1321 }
1322 public static void genNoise1D(Random random, float [] noise, int size, float spikes) {
1323 genNoise1DFill(random, noise, 0, noise.length - 1, 1, spikes);
1324 }
1325
1326 public static void genNoise1DFill(Random random, float [] noise, int x1, int x2, int iter, float spikes) {
1327 if (x1 + 1 >= x2) return;
1328
1329 int midX = (x1 + x2) / 2;
1330
1331 float avg = (noise[x1] + noise[x2]) / 2f;
1332 noise[midX] = avg + ((float) Math.pow(spikes, (iter)) * (float) (random.nextFloat() - .5f));
1333
1334 genNoise1DFill(random, noise, x1, midX, iter + 1, spikes);
1335 genNoise1DFill(random, noise, midX, x2, iter + 1, spikes);
1336 }
1337
1338 public static float getApproximateBezierLength(Vector2f p0, Vector2f p1, Vector2f p2) {
1339 float total = 0f;
1340 Vector2f prev = p0;
1341 for (float f = 0; f <= 1.01f; f += 0.1f) {
1342 Vector2f curr = Misc.bezier(p0, p1, p2, f);
1343 total += Misc.getDistance(prev, curr);
1344 prev = curr;
1345 }
1346 return total;
1347 }
1348 public static float getApproximateBezierLength(Vector2f p0, Vector2f p1, Vector2f p2, Vector2f p3) {
1349 float total = 0f;
1350 Vector2f prev = p0;
1351 for (float f = 0; f <= 1.01f; f += 0.05f) {
1352 Vector2f curr = Misc.bezierCubic(p0, p1, p2, p3, f);
1353 total += Misc.getDistance(prev, curr);
1354 prev = curr;
1355 }
1356 return total;
1357 }
1358}
1359
1360
1361
1362
1363
static SectorAPI getSector()
Definition Global.java:59
static float getApproximateBezierLength(Vector2f p0, Vector2f p1, Vector2f p2)
static void genNoise1DFill(Random random, float[] noise, int x1, int x2, int iter, float spikes)
static void genNoise1D(Random random, float[] noise, int size, float spikes)
void addSection(Vector2f to, int width, int wrand, int wchange, int fluct)
void addSection(Vector2f to, int width, int wrand, int wchange, int fluct, int insertIndex)
void buildToDestination(Vector2f control, Vector2f control2, Vector2f to)
static float[] initNoise1D(Random random, int size, float spikes)
SlipstreamBuilder(Vector2f start, SlipstreamTerrainPlugin2 plugin, StreamType type, Random random)
static float getApproximateBezierLength(Vector2f p0, Vector2f p1, Vector2f p2, Vector2f p3)