Starsector API
Loading...
Searching...
No Matches
PulsarRenderer.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.terrain;
2
3import java.awt.Color;
4import java.nio.ByteBuffer;
5import java.nio.ByteOrder;
6import java.nio.FloatBuffer;
7
8import org.lwjgl.opengl.GL11;
9import org.lwjgl.util.vector.Vector2f;
10
11import com.fs.starfarer.api.graphics.SpriteAPI;
12import com.fs.starfarer.api.util.Misc;
13
14public class PulsarRenderer {
15 public static interface PulsarRendererDelegate {
16 float getPulsarInnerRadius();
17 float getPulsarOuterRadius();
18 Vector2f getPulsarCenterLoc();
19
20 float getPulsarInnerWidth();
21 float getPulsarOuterWidth();
22
23 Color getPulsarColorForAngle(float angle);
24
25 SpriteAPI getPulsarTexture();
26 RangeBlockerUtil getPulsarBlocker();
27
28 float getPulsarScrollSpeed();
29 }
30
31 private PulsarRendererDelegate delegate;
32 private float texOffset = 0f;
33 public PulsarRenderer(PulsarRendererDelegate delegate) {
34 this.delegate = delegate;
35 }
36
37 private float currAngle;
38 public float getCurrAngle() {
39 return currAngle;
40 }
41
42
43 public void setCurrAngle(float currAngle) {
44 this.currAngle = currAngle;
45 }
46
47
48 public void advance(float amount) {
49 //float days = Global.getSector().getClock().convertToDays(amount);
50 //texOffset += days * delegate.getFlareScrollSpeed();
51 float imageWidth = delegate.getPulsarTexture().getWidth();
52 texOffset += amount * delegate.getPulsarScrollSpeed() / imageWidth;
53 while (texOffset > 1) texOffset--;
54
55 if (!rendered && vertexBuffer != null) {
56 Misc.cleanBuffer(vertexBuffer);
57 Misc.cleanBuffer(textureBuffer);
58 Misc.cleanBuffer(colorBuffer);
59 vertexBuffer = textureBuffer = null;
60 colorBuffer = null;
61 }
62 rendered = false;
63 }
64
65 transient private FloatBuffer vertexBuffer, textureBuffer;
66 transient private ByteBuffer colorBuffer;
67 transient private boolean rendered = false;
68 public void render(float alphaMult) {
69 if (alphaMult <= 0) return;
70
71 float distClose = delegate.getPulsarInnerRadius();
72 float distFar = delegate.getPulsarOuterRadius();
73
74 if (distFar < distClose + 10f) distFar = distClose + 10f;
75
76 float length = distFar - distClose;
77
78 float wClose = delegate.getPulsarInnerWidth();
79 float wFar = delegate.getPulsarOuterWidth();
80
81 float pixelsPerSegment = 25f;
82 float segments = Math.round(wFar / pixelsPerSegment);
83 pixelsPerSegment = wFar / segments;
84
85
86 Vector2f loc = delegate.getPulsarCenterLoc();
87 float x = loc.x;
88 float y = loc.y;
89
90
91 GL11.glPushMatrix();
92 GL11.glTranslatef(x, y, 0);
93
94 GL11.glEnable(GL11.GL_TEXTURE_2D);
95 //GL11.glDisable(GL11.GL_TEXTURE_2D);
96
97 //GL11.glShadeModel(GL11.GL_SMOOTH);
98
99 //delegate.getPulsarTexture().bindTexture();
100
101
102 GL11.glEnable(GL11.GL_BLEND);
103 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
104
105 //GL11.glEnable(GL11.GL_DITHER);
106
107 float texHeight = delegate.getPulsarTexture().getTextureHeight();
108 float imageHeight = delegate.getPulsarTexture().getHeight();
109 float texPerSegment = texHeight / segments;
110
111 //texPerSegment *= 20f;
112
113 float texWidth = delegate.getPulsarTexture().getTextureWidth();
114 float imageWidth = delegate.getPulsarTexture().getWidth();
115
116 RangeBlockerUtil blocker = delegate.getPulsarBlocker();
117
118 float numIter = (float)Math.ceil(distFar - distClose) / (imageWidth * texWidth);
119 float widthFactor = ((wClose + wFar) / 2f) / (imageHeight * texHeight);
120 numIter /= widthFactor;
121
122 float texPerUnitLength = 1f / (imageWidth * widthFactor);
123
124 float angle = currAngle;
125
126 //Vector2f dir = Misc.getUnitVectorAtDegreeAngle(angle);
127
128 float fadeInDist = Math.min(1000f, length * 0.25f);
129 float fadeOutDist = Math.min(1500f, length * 0.25f);
130
131 boolean wireframe = false;
132 //wireframe = true;
133 if (wireframe) {
134 GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
135 GL11.glDisable(GL11.GL_TEXTURE_2D);
136 //GL11.glDisable(GL11.GL_BLEND);
137 }
138
139 float [] rPrev = new float [(int) segments + 1];
140 float [] blockedPrev = new float [(int) segments + 1];
141
142 float [] xPrev = new float [(int) segments + 1];
143 float [] yPrev = new float [(int) segments + 1];
144
145 float [] texPrev = new float [(int) segments + 1];
146
147 int numInnerSegments = (int) ((length - fadeInDist - fadeOutDist) / (pixelsPerSegment * 5f));
148 if (numInnerSegments < 1) numInnerSegments = 1;
149 numInnerSegments = 1;
150
151 int numSegments = 2 + numInnerSegments;
152 float distPerInnerSegment = (length - fadeInDist - fadeOutDist) / (float) numInnerSegments;
153
154 boolean arrays = false;
155 //arrays = true;
156
157 int numVertices = (numSegments) * ((int) segments + 1) * 2;
158 //System.out.println("Num: " + numVertices);
159 if (arrays) {
160 if (vertexBuffer == null) {
161 vertexBuffer = ByteBuffer.allocateDirect(numVertices * 4 * 2).order(ByteOrder.nativeOrder()).asFloatBuffer();
162 }
163 if (textureBuffer == null) {
164 textureBuffer = ByteBuffer.allocateDirect(numVertices * 4 * 2).order(ByteOrder.nativeOrder()).asFloatBuffer();
165 }
166 if (colorBuffer == null) {
167 colorBuffer = ByteBuffer.allocateDirect(numVertices * 4).order(ByteOrder.nativeOrder());
168 }
169
170 vertexBuffer.clear();
171 textureBuffer.clear();
172 colorBuffer.clear();
173 }
174
175 rendered = true;
176
177// for (int t = 0; t < 2; t++) {
178//
179// SpriteAPI tex = Global.getSettings().getSprite("terrain", "pulsar");
180// if (t == 1) {
181// tex = Global.getSettings().getSprite("terrain", "pulsar2");
182// }
183 delegate.getPulsarTexture().bindTexture();
184 //int count = 0;
185 //for (int j = 0; j < 3; j++) {
186 for (int j = 0; j < numSegments; j++) {
187 //for (int j = 1; j < 2; j++) {
188
189 boolean isFirst = j == 0;
190 boolean isLast = j == numSegments - 1;
191 boolean isMid = !isFirst && !isLast;
192
193 float alphaCloser = 1f;
194 float alphaFarther = 1f;
195 float r1 = distClose;
196 float r2 = distFar;
197
198 if (isFirst) {
199 alphaCloser = 0f;
200 alphaFarther = 1f;
201 r1 = distClose;
202 r2 = distClose + fadeInDist;
203 } else if (isMid) {
204 alphaCloser = 1f;
205 alphaFarther = 1f;
206
207 //r1 = distClose + fadeInDist;
208 //r2 = distFar - fadeOutDist;
209 r1 = distClose + (j - 1) * distPerInnerSegment + fadeInDist;
210 r2 = r1 + distPerInnerSegment;
211 } else if (isLast) {
212 alphaCloser = 1f;
213 alphaFarther = 0f;
214// r1 = distFar;
215// r2 = distFar + fadeOutDist;
216 r1 = distFar - fadeOutDist;
217 //r1 = distClose + (j - 1) * distPerInnerSegment + fadeInDist;
218 r2 = distFar;
219 }
220
221
222 float w1 = wClose + (wFar - wClose) * (r1 - distClose) / length;
223 float w2 = wClose + (wFar - wClose) * (r2 - distClose) / length;
224
225 float arcClose = (float) Math.toRadians(Misc.computeAngleSpan(w1 / 2f, r1));
226 float arcFar = (float) Math.toRadians(Misc.computeAngleSpan(w2 / 2f, r2));
227
228 float closeAnglePerSegment = arcClose / segments;
229 float farAnglePerSegment = arcFar / segments;
230
231 float currCloseAngle = (float) Math.toRadians(angle) - arcClose / 2f;
232 float currFarAngle = (float) Math.toRadians(angle) - arcFar / 2f;
233
234 //float closeTX = 0f - texOffset;
235 //float farTX = texWidth * numIter - texOffset;
236 //texOffset = 0f;
237// float closeTX = texWidth * texPerUnitLength * (r1 - distClose) - texOffset;
238// float farTX = texWidth * texPerUnitLength * (r2 - distClose) - texOffset;
239
240 // horizontal, i.e. along width of beam
241 float texProgress = 0f;
242
243 //texPerUnitLength * (r2 - r1)
244 GL11.glBegin(GL11.GL_QUAD_STRIP);
245 for (float i = 0; i < segments + 1; i++) {
246 float blockedAt = 1f;
247 float blockerMax = 100000f;
248 if (isMid && blocker != null) {
249 blockerMax = blocker.getCurrMaxAt((float) Math.toDegrees((currCloseAngle)));
250 if (blockerMax > blocker.getMaxRange()) {
251 blockerMax = blocker.getMaxRange();
252 }
253 if (blockerMax < fadeInDist + 100) {
254 blockerMax = fadeInDist + 100;
255 }
256 blockedAt = (blockerMax - r1) / (r2 - r1);
257 if (blockedAt > 1) blockedAt = 1;
258 if (blockedAt < 0) blockedAt = 0;
259
260 rPrev[(int) i] = Math.min(r2, blockerMax);
261 blockedPrev[(int) i] = blockedAt;
262 }
263
264 float curr1 = r1;
265 float curr2 = r2;
266
267 float extraAlpha = 1f;
268// if (isMid || isLast) {
269// if (curr1 > blockerMax) {
270// curr1 = blockerMax;
271// //curr2 = curr1 + distPerInnerSegment;
272// curr2 = curr1;
273// //blockedAt = 0f;
274// //extraAlpha = 0f;
275// }
276// }
277
278 if (isLast) {
279 curr1 = rPrev[(int) i];
280 float block = blockedPrev[(int) i];
281 curr2 = curr1 + Math.max(300f, fadeOutDist * block);
282
283// if (block > 0.5f) {
284// curr2 = distFar;
285// }
286
287 //curr2 = curr1 + 200f;
288
289 w2 = wClose + (wFar - wClose) * (curr2 - distClose) / length;
290 arcFar = (float) Math.toRadians(Misc.computeAngleSpan(w2 / 2f, curr2));
291 farAnglePerSegment = arcFar / segments;
292 currFarAngle = (float) Math.toRadians(angle) - arcFar / 2f + farAnglePerSegment * i;
293 }
294
295
296 float cosClose = (float) Math.cos(currCloseAngle);
297 float sinClose = (float) Math.sin(currCloseAngle);
298
299 float cosFar = (float) Math.cos(currFarAngle);
300 float sinFar = (float) Math.sin(currFarAngle);
301
302 float x1 = cosClose * curr1;
303 float y1 = sinClose * curr1;
304 float x2 = cosFar * curr2;
305 float y2 = sinFar * curr2;
306
307 //if (j == 1 || j == 2) {
308 if (isMid || isLast) {
309 x1 = xPrev[(int) i];
310 y1 = yPrev[(int) i];
311 }
312
313 //blockedAt = 1f;
314 x2 = x1 + (x2 - x1) * blockedAt;
315 y2 = y1 + (y2 - y1) * blockedAt;
316
317 xPrev[(int) i] = x2;
318 yPrev[(int) i] = y2;
319
320 float closeTX = texWidth * texPerUnitLength * (curr1 - distClose) - texOffset;
321 float farTX = texWidth * texPerUnitLength * ((curr1 + (curr2 - curr1) * blockedAt) - distClose) - texOffset;
322
323 if (isMid || isLast) {
324 closeTX = texPrev[(int) i];
325 }
326 texPrev[(int) i] = farTX;
327
328 float edgeMult = 1f;
329 float max = 10;
330 if (i < max) {
331 edgeMult = i / max;
332 } else if (i > segments - 1 - max) {
333 edgeMult = 1f - (i - (segments - max)) / max;
334 }
335
336 Color color = delegate.getPulsarColorForAngle(angle);
337 //color = new Color(100,165,255,200);
338
339 if (arrays) {
340 vertexBuffer.put(x1).put(y1).put(x2).put(y2);
341// vertexBuffer.put((float) Math.random() * -100f).put((float) Math.random() * -100f).
342// put((float) Math.random() * -100f).put((float) Math.random() * -100f);
343 textureBuffer.put(closeTX).put(texProgress).put(farTX).put(texProgress);
344 colorBuffer.put((byte)color.getRed()).
345 put((byte)color.getGreen()).
346 put((byte)color.getBlue()).
347 put((byte)((float) color.getAlpha() * alphaMult * alphaCloser * edgeMult * extraAlpha));
348 colorBuffer.put((byte)color.getRed()).
349 put((byte)color.getGreen()).
350 put((byte)color.getBlue()).
351 put((byte)((float) color.getAlpha() * alphaMult * alphaFarther * edgeMult * extraAlpha));
352 } else {
353 GL11.glColor4ub((byte)color.getRed(),
354 (byte)color.getGreen(),
355 (byte)color.getBlue(),
356 (byte)((float) color.getAlpha() * alphaMult * alphaCloser * edgeMult * extraAlpha));
357
358 GL11.glTexCoord2f(closeTX, texProgress);
359 GL11.glVertex2f(x1, y1);
360
361 GL11.glColor4ub((byte)color.getRed(),
362 (byte)color.getGreen(),
363 (byte)color.getBlue(),
364 (byte)((float) color.getAlpha() * alphaMult * alphaFarther * edgeMult * extraAlpha));
365 GL11.glTexCoord2f(farTX, texProgress);
366 GL11.glVertex2f(x2, y2);
367
368 //count += 2;
369 }
370
371 texProgress += texPerSegment * 1f;
372 currCloseAngle += closeAnglePerSegment;
373 currFarAngle += farAnglePerSegment;
374 }
375 GL11.glEnd();
376 }
377
378 //System.out.println("Count: " + count);
379
380
381 if (arrays) {
382 //System.out.println("Pos: " + colorBuffer.position() + ", size: " + colorBuffer.capacity());
383 vertexBuffer.position(0);
384 textureBuffer.position(0);
385 colorBuffer.position(0);
386
387 GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
388 GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
389 GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);
390
391 GL11.glTexCoordPointer(2, 0, textureBuffer);
392 GL11.glColorPointer(4, true, 0, colorBuffer);
393 GL11.glVertexPointer(2, 0, vertexBuffer);
394
395
396 GL11.glDrawArrays(GL11.GL_QUAD_STRIP, 0, numVertices);
397
398 GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
399 GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
400 GL11.glDisableClientState(GL11.GL_COLOR_ARRAY);
401 }
402
403
404 if (wireframe) GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
405
406 GL11.glPopMatrix();
407
408// GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
409 }
410
411}
412
413
414
415