1 /* bzflag
2 * Copyright (c) 1993-2021 Tim Riker
3 *
4 * This package is free software; you can redistribute it and/or
5 * modify it under the terms of the license found in the file
6 * named COPYING that should have accompanied this file.
7 *
8 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11 */
12
13 // interface header
14 #include "BoltSceneNode.h"
15
16 // system headers
17 #include <stdlib.h>
18 #include <math.h>
19
20 // common implementation headers
21 #include "StateDatabase.h"
22 #include "BZDBCache.h"
23 #include "TextureManager.h"
24
25 // local implementation headers
26 #include "ViewFrustum.h"
27
28 // FIXME (SceneRenderer.cxx is in src/bzflag)
29 #include "SceneRenderer.h"
30
31 #include "TimeKeeper.h"
32
BoltSceneNode(const GLfloat pos[3],const GLfloat vel[3],bool super)33 BoltSceneNode::BoltSceneNode(const GLfloat pos[3],const GLfloat vel[3], bool super) :
34 isSuper(super),
35 invisible(false),
36 drawFlares(false),
37 texturing(false),
38 colorblind(false),
39 size(1.0f),
40 renderNode(this),
41 azimuth(0),
42 elevation(0),
43 length(1.0f)
44 {
45
46 OpenGLGStateBuilder builder(gstate);
47 builder.setBlending();
48 builder.setAlphaFunc();
49 //builder.setTextureEnvMode(GL_DECAL);
50 gstate = builder.getState();
51
52 // prepare light
53 light.setAttenuation(0, 0.05f);
54 light.setAttenuation(1, 0.0f);
55 light.setAttenuation(2, 0.03f);
56
57 // prepare geometry
58 move(pos, vel);
59 setSize(size);
60 setColor(1.0f, 1.0f, 1.0f);
61 teamColor = fvec4(1,1,1,1);
62 }
63
~BoltSceneNode()64 BoltSceneNode::~BoltSceneNode()
65 {
66 // do nothing
67 }
68
setFlares(bool on)69 void BoltSceneNode::setFlares(bool on)
70 {
71 drawFlares = on;
72 }
73
setSize(float radius)74 void BoltSceneNode::setSize(float radius)
75 {
76 size = radius;
77 setRadius(size * size);
78 }
setTextureColor(GLfloat r,GLfloat g,GLfloat b,GLfloat a)79 void BoltSceneNode::setTextureColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
80 {
81 color[0] = r;
82 color[1] = g;
83 color[2] = b;
84 color[3] = a;
85 light.setColor(1.5f * r, 1.5f * g, 1.5f * b);
86 renderNode.setTextureColor(color);
87 }
88
setColor(GLfloat r,GLfloat g,GLfloat b,GLfloat a)89 void BoltSceneNode::setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
90 {
91 color[0] = r;
92 color[1] = g;
93 color[2] = b;
94 color[3] = a;
95 light.setColor(1.5f * r, 1.5f * g, 1.5f * b);
96 renderNode.setColor(color);
97 }
98
setTeamColor(const GLfloat * c)99 void BoltSceneNode::setTeamColor(const GLfloat *c)
100 {
101 teamColor.r = c[0];
102 teamColor.g = c[1];
103 teamColor.b = c[2];
104 teamColor.w = 1.0f;
105 }
106
setColor(const GLfloat * rgb)107 void BoltSceneNode::setColor(const GLfloat* rgb)
108 {
109 setColor(rgb[0], rgb[1], rgb[2]);
110 }
111
getColorblind() const112 bool BoltSceneNode::getColorblind() const
113 {
114 return colorblind;
115 }
116
setColorblind(bool _colorblind)117 void BoltSceneNode::setColorblind(bool _colorblind)
118 {
119 colorblind = _colorblind;
120 }
121
setTexture(const int texture)122 void BoltSceneNode::setTexture(const int texture)
123 {
124 OpenGLGStateBuilder builder(gstate);
125 builder.setTexture(texture);
126 builder.enableTexture(texture>=0);
127 gstate = builder.getState();
128 }
129
setTextureAnimation(int cu,int cv)130 void BoltSceneNode::setTextureAnimation(int cu, int cv)
131 {
132 renderNode.setAnimation(cu, cv);
133 }
134
move(const GLfloat pos[3],const GLfloat vel[3])135 void BoltSceneNode::move(const GLfloat pos[3],
136 const GLfloat vel[3])
137 {
138 setCenter(pos);
139 light.setPosition(pos);
140 velocity[0] = vel[0];
141 velocity[1] = vel[1];
142 velocity[2] = vel[2];
143 length = sqrtf((vel[0] * vel[0]) +
144 (vel[1] * vel[1]) +
145 (vel[2] * vel[2]));
146
147 azimuth = (float)(+RAD2DEG * atan2f(vel[1], vel[0]));
148 elevation = (float)(-RAD2DEG * atan2f(vel[2], sqrtf(vel[0]* vel[0] + vel[1] *vel[1])));
149 }
150
addLight(SceneRenderer & renderer)151 void BoltSceneNode::addLight(
152 SceneRenderer& renderer)
153 {
154 renderer.addLight(light);
155 }
156
notifyStyleChange()157 void BoltSceneNode::notifyStyleChange()
158 {
159 texturing = BZDBCache::texture && BZDBCache::blend;
160 OpenGLGStateBuilder builder(gstate);
161 builder.enableTexture(texturing);
162 if (BZDBCache::blend)
163 {
164 const int shotLength = (int)(BZDBCache::shotLength * 3.0f);
165 if (shotLength > 0 && !drawFlares)
166 builder.setBlending(GL_SRC_ALPHA, GL_ONE);
167 else
168 builder.setBlending(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
169 builder.setStipple(1.0f);
170 builder.setAlphaFunc();
171 if ((RENDERER.useQuality() >= 3) && drawFlares)
172 {
173 builder.setShading(GL_SMOOTH);
174 builder.enableMaterial(false);
175 }
176 else
177 builder.setShading(texturing ? GL_FLAT : GL_SMOOTH);
178 }
179 else
180 {
181 builder.resetBlending();
182 builder.resetAlphaFunc();
183 builder.setStipple(0.5f);
184 builder.setShading(GL_FLAT);
185 }
186 gstate = builder.getState();
187 }
188
addRenderNodes(SceneRenderer & renderer)189 void BoltSceneNode::addRenderNodes(
190 SceneRenderer& renderer)
191 {
192 renderer.addRenderNode(&renderNode, &gstate);
193 }
194
195 //
196 // BoltSceneNode::BoltRenderNode
197 //
198
199 const GLfloat BoltSceneNode::BoltRenderNode::CoreFraction = 0.4f;
200 const GLfloat BoltSceneNode::BoltRenderNode::FlareSize = 1.0f;
201 const GLfloat BoltSceneNode::BoltRenderNode::FlareSpread = 0.08f;
202 GLfloat BoltSceneNode::BoltRenderNode::core[9][2];
203 GLfloat BoltSceneNode::BoltRenderNode::corona[8][2];
204 const GLfloat BoltSceneNode::BoltRenderNode::ring[8][2] =
205 {
206 { 1.0f, 0.0f },
207 { (float)M_SQRT1_2, (float)M_SQRT1_2 },
208 { 0.0f, 1.0f },
209 { (float)-M_SQRT1_2, (float)M_SQRT1_2 },
210 { -1.0f, 0.0f },
211 { (float)-M_SQRT1_2, (float)-M_SQRT1_2 },
212 { 0.0f, -1.0f },
213 { (float)M_SQRT1_2, (float)-M_SQRT1_2 }
214 };
215
BoltRenderNode(const BoltSceneNode * _sceneNode)216 BoltSceneNode::BoltRenderNode::BoltRenderNode(
217 const BoltSceneNode* _sceneNode) :
218 sceneNode(_sceneNode),
219 numFlares(0)
220 {
221 // initialize core and corona if not already done
222 static bool init = false;
223 if (!init)
224 {
225 init = true;
226 core[0][0] = 0.0f;
227 core[0][1] = 0.0f;
228 for (int i = 0; i < 8; i++)
229 {
230 core[i+1][0] = CoreFraction * ring[i][0];
231 core[i+1][1] = CoreFraction * ring[i][1];
232 corona[i][0] = ring[i][0];
233 corona[i][1] = ring[i][1];
234 }
235 }
236
237 textureColor[0] = 1.0f;
238 textureColor[1] = 1.0f;
239 textureColor[2] = 1.0f;
240 textureColor[3] = 1.0f;
241
242 setAnimation(1, 1);
243 }
244
~BoltRenderNode()245 BoltSceneNode::BoltRenderNode::~BoltRenderNode()
246 {
247 // do nothing
248 }
249
setAnimation(int _cu,int _cv)250 void BoltSceneNode::BoltRenderNode::setAnimation(
251 int _cu, int _cv)
252 {
253 cu = _cu;
254 cv = _cv;
255 du = 1.0f / (float)cu;
256 dv = 1.0f / (float)cv;
257
258 // pick a random start frame
259 const int index = (int)((float)cu * (float)cv * bzfrand());
260 u = index % cu;
261 v = index / cu;
262 if (v >= cv) v = 0;
263 }
setTextureColor(const GLfloat * rgba)264 void BoltSceneNode::BoltRenderNode::setTextureColor(const GLfloat* rgba)
265 {
266 textureColor[0] = rgba[0];
267 textureColor[1] = rgba[1];
268 textureColor[2] = rgba[2];
269 textureColor[3] = rgba[3];
270 }
271
272
setColor(const GLfloat * rgba)273 void BoltSceneNode::BoltRenderNode::setColor(
274 const GLfloat* rgba)
275 {
276 mainColor[0] = rgba[0];
277 mainColor[1] = rgba[1];
278 mainColor[2] = rgba[2];
279 mainColor[3] = rgba[3];
280
281 innerColor[0] = mainColor[0] + 0.5f * (1.0f - mainColor[0]);
282 innerColor[1] = mainColor[1] + 0.5f * (1.0f - mainColor[1]);
283 innerColor[2] = mainColor[2] + 0.5f * (1.0f - mainColor[2]);
284 innerColor[3] = rgba[3];
285
286 outerColor[0] = mainColor[0];
287 outerColor[1] = mainColor[1];
288 outerColor[2] = mainColor[2];
289 outerColor[3] = (rgba[3] == 1.0f )? 0.1f: rgba[3];
290
291 coronaColor[0] = mainColor[0];
292 coronaColor[1] = mainColor[1];
293 coronaColor[2] = mainColor[2];
294 coronaColor[3] = (rgba[3] == 1.0f )? 0.5f : rgba[3];
295
296 flareColor[0] = mainColor[0];
297 flareColor[1] = mainColor[1];
298 flareColor[2] = mainColor[2];
299 flareColor[3] = (rgba[3] == 1.0f )? 0.667f : rgba[3];
300 }
301
drawFin(float maxRad,float finRadius,float boosterLen,float finForeDelta,float finCapSize)302 void drawFin ( float maxRad, float finRadius, float boosterLen, float finForeDelta, float finCapSize)
303 {
304 glBegin(GL_TRIANGLE_STRIP);
305 glNormal3f(1,0,0);
306 glVertex3f(0,maxRad,0);
307 glVertex3f(0,maxRad,boosterLen);
308 glVertex3f(0,maxRad+finRadius,boosterLen-finForeDelta-finCapSize);
309 glVertex3f(0,maxRad+finRadius,boosterLen-finForeDelta);
310 glEnd();
311
312 glBegin(GL_TRIANGLE_STRIP);
313 glNormal3f(-1,0,0);
314 glVertex3f(0,maxRad+finRadius,boosterLen-finForeDelta-finCapSize);
315 glVertex3f(0,maxRad+finRadius,boosterLen-finForeDelta);
316 glVertex3f(0,maxRad,0);
317 glVertex3f(0,maxRad,boosterLen);
318 glEnd();
319 }
320
renderGeoGMBolt()321 void BoltSceneNode::BoltRenderNode::renderGeoGMBolt()
322 {
323 // bzdb these 2? they control the shot size
324 float gmMissleSize = BZDBCache::gmSize;
325
326 // parametrics
327 float maxRad = gmMissleSize * 0.16f;
328 float noseRad = gmMissleSize * 0.086f;
329 float waistRad = gmMissleSize * 0.125f;
330 float engineRad = gmMissleSize * 0.1f;
331
332 float noseLen = gmMissleSize * 0.1f;
333 float bodyLen = gmMissleSize * 0.44f;
334 float bevelLen = gmMissleSize * 0.02f;
335 float waistLen = gmMissleSize * 0.16f;
336 float boosterLen = gmMissleSize * 0.2f;
337 float engineLen = gmMissleSize * 0.08f;
338
339 float finRadius = gmMissleSize * 0.16f;
340 float finCapSize = gmMissleSize * 0.15f;
341 float finForeDelta = gmMissleSize * 0.02f;
342
343 int slices = 8;
344
345 float rotSpeed = 90.0f;
346
347 glDepthMask(GL_TRUE);
348 glPushMatrix();
349 glRotatef(sceneNode->azimuth, 0.0f, 0.0f, 1.0f);
350 glRotatef(sceneNode->elevation, 0.0f, 1.0f, 0.0f);
351 glRotatef(90, 0.0f, 1.0f, 0.0f);
352
353 glDisable(GL_TEXTURE_2D);
354 //glEnable(GL_LIGHTING);
355
356 fvec4 noseColor = sceneNode->teamColor;
357 fvec4 finColor(noseColor.r*0.5f,noseColor.g*0.5f,noseColor.b*0.5f,1);
358 fvec4 coneColor(0.125f,0.125f,0.125f,1);
359 fvec4 bodyColor(1,1,1,1);
360
361 glPushMatrix();
362
363 GLUquadric *q = gluNewQuadric();
364
365 glColor4f(noseColor.r,noseColor.g,noseColor.b,1.0f);
366 glTranslatef(0, 0, gmMissleSize);
367 glRotatef((float)TimeKeeper::getCurrent().getSeconds() * rotSpeed,0,0,1);
368
369 // nosecone
370 gluDisk(q,0,noseRad,slices,1);
371 glTranslatef(0, 0, -noseLen);
372 gluCylinder(q,maxRad,noseRad,noseLen,slices,1);
373 addTriangleCount(slices * 2);
374
375 // body
376 myColor4fv(bodyColor);
377 glTranslatef(0, 0, -bodyLen);
378 gluCylinder(q,maxRad,maxRad,bodyLen,slices,1);
379 addTriangleCount(slices);
380
381 glTranslatef(0, 0, -bevelLen);
382 gluCylinder(q,waistRad,maxRad,bevelLen,slices,1);
383 addTriangleCount(slices);
384
385 // waist
386 myColor4fv(coneColor);
387 glTranslatef(0, 0, -waistLen);
388 gluCylinder(q,waistRad,waistRad,waistLen,slices,1);
389 addTriangleCount(slices);
390
391 // booster
392 myColor3fv(bodyColor);
393 glTranslatef(0, 0, -bevelLen);
394 gluCylinder(q,maxRad,waistRad,bevelLen,slices,1);
395 addTriangleCount(slices);
396
397 glTranslatef(0, 0, -boosterLen);
398 gluCylinder(q,maxRad,maxRad,boosterLen,slices,1);
399 addTriangleCount(slices);
400
401 glTranslatef(0, 0, -bevelLen);
402 gluCylinder(q,waistRad,maxRad,bevelLen,slices,1);
403 addTriangleCount(slices);
404
405 // engine
406 myColor3fv(coneColor);
407 glTranslatef(0, 0, -engineLen);
408 gluCylinder(q,engineRad,waistRad,engineLen,slices,1);
409 addTriangleCount(slices);
410
411 // fins
412 myColor3fv(finColor);
413 glTranslatef(0, 0, engineLen + bevelLen);
414
415 for ( int i = 0; i < 4; i++)
416 {
417 glRotatef(i*90.0f,0,0,1);
418 drawFin ( maxRad, finRadius, boosterLen, finForeDelta, finCapSize);
419 }
420
421 glPopMatrix();
422
423 gluDeleteQuadric(q);
424
425 glEnable(GL_TEXTURE_2D);
426 // glDisable(GL_LIGHTING);
427
428 glPopMatrix();
429
430 glDepthMask(GL_FALSE);
431 }
432
433
renderGeoBolt()434 void BoltSceneNode::BoltRenderNode::renderGeoBolt()
435 {
436 // bzdb these 2? they control the shot size
437 float lenMod = 0.0675f + (BZDBCache::shotLength * 0.0125f);
438 float baseRadius = 0.225f;
439
440 float len = sceneNode->length * lenMod;
441 glPushMatrix();
442 glRotatef(sceneNode->azimuth, 0.0f, 0.0f, 1.0f);
443 glRotatef(sceneNode->elevation, 0.0f, 1.0f, 0.0f);
444 glRotatef(90, 0.0f, 1.0f, 0.0f);
445
446 float alphaMod = 1.0f;
447 // if (sceneNode->phasingShot)
448 // alphaMod = 0.85f;
449
450 glDisable(GL_TEXTURE_2D);
451
452 float coreBleed = 4.5f;
453 float minimumChannelVal = 0.45f;
454
455 fvec3 coreColor;
456 coreColor.r = sceneNode->color[0] * coreBleed;
457 coreColor.g = sceneNode->color[1] * coreBleed;
458 coreColor.b = sceneNode->color[2] * coreBleed;
459 if (coreColor.r < minimumChannelVal)
460 coreColor.r = minimumChannelVal;
461 if (coreColor.g < minimumChannelVal)
462 coreColor.g = minimumChannelVal;
463 if (coreColor.b < minimumChannelVal)
464 coreColor.b = minimumChannelVal;
465
466 myColor4fv(fvec4(coreColor, 0.85f * alphaMod));
467 renderGeoPill(baseRadius,len,16);
468
469 float radInc = 1.5f * baseRadius - baseRadius;
470 glPushMatrix();
471 glTranslatef(0, 0, -radInc * 0.5f);
472 fvec4 c;
473 c.x = sceneNode->color[0];
474 c.y = sceneNode->color[1];
475 c.z = sceneNode->color[2];
476 c.w = 0.5f;
477
478 myColor4fv(c);
479 renderGeoPill(1.5f * baseRadius, len + radInc, 25);
480 glPopMatrix();
481
482 radInc = 2.7f * baseRadius - baseRadius;
483 glPushMatrix();
484 glTranslatef(0, 0, -radInc*0.5f);
485 c.w = 0.25f;
486 myColor4fv(c);
487 renderGeoPill(2.7f * baseRadius, len + radInc, 32);
488 glPopMatrix();
489
490 radInc = 3.8f * baseRadius - baseRadius;
491 glPushMatrix();
492 glTranslatef(0, 0,-radInc*0.5f);
493 c.w = 0.125f;
494 myColor4fv(c);
495 renderGeoPill(3.8f * baseRadius, len + radInc, 48);
496 glPopMatrix();
497
498 glEnable(GL_TEXTURE_2D);
499
500 glPopMatrix();
501 }
502
503
renderGeoPill(float radius,float len,int segments,float endRad)504 void BoltSceneNode::BoltRenderNode::renderGeoPill(float radius, float len,
505 int segments, float endRad)
506 {
507 glPushMatrix();
508
509 float assRadius = radius;
510 if (endRad >= 0)
511 assRadius = endRad;
512
513 float lenMinusRads = len - (radius+assRadius);
514
515 GLUquadric *q = gluNewQuadric();
516 if (assRadius > 0)
517 {
518 // 4 parts of the first hemisphere
519 gluCylinder(q,0,assRadius*0.43589,assRadius*0.1f,segments,1);
520 addTriangleCount(segments);
521 glTranslatef(0,0,assRadius*0.1f);
522
523 gluCylinder(q,assRadius*0.43589,assRadius*0.66144,assRadius*0.15f,segments,1);
524 addTriangleCount(segments);
525 glTranslatef(0,0,assRadius*0.15f);
526
527 gluCylinder(q,assRadius*0.66144f,assRadius*0.86603f,assRadius*0.25f,segments,1);
528 addTriangleCount(segments);
529 glTranslatef(0,0,assRadius*0.25f);
530
531 gluCylinder(q,assRadius*0.86603,assRadius,assRadius*0.5f,segments,1);
532 addTriangleCount(segments);
533 glTranslatef(0,0,assRadius*0.5f);
534 }
535
536 // the "shaft"
537 if (lenMinusRads > 0)
538 {
539 gluCylinder(q,assRadius,radius,lenMinusRads,segments,1);
540 addTriangleCount(segments);
541 glTranslatef(0,0,lenMinusRads);
542 }
543
544 if (radius > 0)
545 {
546 // 4 parts of the last hemisphere
547 gluCylinder(q,radius,radius*0.86603,radius*0.5f,segments,1);
548 addTriangleCount(segments);
549 glTranslatef(0,0,radius*0.5f);
550
551 gluCylinder(q,radius*0.86603f,radius*0.66144f,radius*0.25f,segments,1);
552 addTriangleCount(segments);
553 glTranslatef(0,0,radius*0.25f);
554
555 gluCylinder(q,radius*0.66144,radius*0.43589,radius*0.15f,segments,1);
556 addTriangleCount(segments);
557 glTranslatef(0,0,radius*0.15f);
558
559 gluCylinder(q,radius*0.43589,0,radius*0.1f,segments,1);
560 addTriangleCount(segments);
561 glTranslatef(0,0,radius*0.1f);
562 }
563
564 gluDeleteQuadric(q);
565 glPopMatrix();
566 }
567
render()568 void BoltSceneNode::BoltRenderNode::render()
569 {
570 if (sceneNode->invisible)
571 return;
572 const float radius = sceneNode->size;
573 const int shotLength = (int)(BZDBCache::shotLength * 3.0f);
574 const bool experimental = (RENDERER.useQuality() >= 3);
575
576 const bool blackFog = RENDERER.isFogActive() && BZDBCache::blend &&
577 ((shotLength > 0) || experimental);
578 if (blackFog)
579 glFogfv(GL_FOG_COLOR, fvec4(0.0f, 0.0f, 0.0f, 0.0f));
580
581 const float* sphere = sceneNode->getSphere();
582 glPushMatrix();
583 glTranslatef(sphere[0], sphere[1], sphere[2]);
584
585 bool drawBillboardShot = false;
586 if (experimental)
587 {
588 if (sceneNode->isSuper)
589 renderGeoBolt();
590 else
591 {
592 if (sceneNode->drawFlares)
593 {
594 if (BZDBCache::shotLength > 0)
595 renderGeoGMBolt();
596 drawBillboardShot = true;
597 }
598 else
599 drawBillboardShot = true;
600 }
601 }
602 else
603 drawBillboardShot = true;
604
605 if (drawBillboardShot)
606 {
607 RENDERER.getViewFrustum().executeBillboard();
608 glScalef(radius, radius, radius);
609 // draw some flares
610 if (sceneNode->drawFlares)
611 {
612 if (!RENDERER.isSameFrame())
613 {
614 numFlares = 3 + int(3.0f * (float)bzfrand());
615 for (int i = 0; i < numFlares; i++)
616 {
617 theta[i] = (float)(2.0 * M_PI * bzfrand());
618 phi[i] = (float)bzfrand() - 0.5f;
619 phi[i] *= (float)(2.0 * M_PI * fabsf(phi[i]));
620 }
621 }
622
623 if (sceneNode->texturing) glDisable(GL_TEXTURE_2D);
624 myColor4fv(flareColor);
625 if (!BZDBCache::blend) myStipple(flareColor[3]);
626 for (int i = 0; i < numFlares; i++)
627 {
628 // pick random direction in 3-space. picking a random theta with
629 // a uniform distribution is fine, but doing so with phi biases
630 // the directions toward the poles. my correction doesn't remove
631 // the bias completely, but moves it towards the equator, which is
632 // really where i want it anyway cos the flares are more noticeable
633 // there.
634 const float c = FlareSize * cosf(phi[i]);
635 const float s = FlareSize * sinf(phi[i]);
636 const float ti = theta[i];
637 const float fs = FlareSpread;
638 glBegin(GL_TRIANGLE_STRIP);
639 glVertex3fv(core[0]);
640 glVertex3f(c * cosf(ti - fs), c * sinf(ti - fs), s);
641 glVertex3f(c * cosf(ti + fs), c * sinf(ti + fs), s);
642 glVertex3f(c * cosf(ti) * 2.0f, c * sinf(ti) * 2.0f, s * 2.0f);
643 glEnd();
644 }
645 if (sceneNode->texturing) glEnable(GL_TEXTURE_2D);
646
647 addTriangleCount(numFlares * 2);
648 }
649
650 if (sceneNode->texturing)
651 {
652 // draw billboard square
653 const float u0 = (float)u * du;
654 const float v0 = (float)v * dv;
655 const float u1 = u0 + du;
656 const float v1 = v0 + dv;
657 myColor4fv(textureColor); // 1.0f all
658 glBegin(GL_TRIANGLE_STRIP);
659 glTexCoord2f(u0, v0);
660 glVertex2f(-1.0f, -1.0f);
661 glTexCoord2f(u1, v0);
662 glVertex2f(+1.0f, -1.0f);
663 glTexCoord2f(u0, v1);
664 glVertex2f(-1.0f, +1.0f);
665 glTexCoord2f(u1, v1);
666 glVertex2f(+1.0f, +1.0f);
667 glEnd();
668 addTriangleCount(2);
669
670 // draw shot trail (more billboarded quads)
671 if ((shotLength > 0) && (sceneNode->length > 1.0e-6f))
672 {
673 const float startSize = 0.6f;
674 const float startAlpha = 0.8f;
675
676 glPushAttrib(GL_TEXTURE_BIT);
677 TextureManager &tm = TextureManager::instance();
678 const int texID = tm.getTextureID("shot_tail");
679 const ImageInfo& texInfo = tm.getInfo(texID);
680 if (texInfo.id >= 0)
681 texInfo.texture->execute();
682
683 fvec3 vel(sceneNode->velocity[0],sceneNode->velocity[1],sceneNode->velocity[2]);
684 const fvec3 dir = vel * (-1.0f / sceneNode->length);
685
686 const float invLenPlusOne = 1.0f / (float)(shotLength + 1);
687 const float shiftScale = 90.0f / (150.0f + (float)shotLength);
688 float Size = sceneNode->size * startSize;
689 float alpha = startAlpha;
690 const float sizeStep = Size * invLenPlusOne;
691 const float alphaStep = alpha * invLenPlusOne;
692
693 fvec3 pos;
694 pos.x = sphere[0];
695 pos.y = sphere[1];
696 pos.z = sphere[2];
697
698 int uvCell = rand() % 16;
699
700 for (int i = 0; i < shotLength; i++)
701 {
702 Size -= sizeStep;
703 const float s = Size * (0.65f + (1.0f * (float)bzfrand()));
704 const float shift = s * shiftScale;
705
706 pos += (shift * dir);
707 if (pos.z < 0.0f)
708 continue;
709
710 uvCell = (uvCell + 1) % 16;
711 const float U0 = (uvCell % 4 ) * 0.25f;
712 const float V0 = (uvCell / 4 ) * 0.25f;
713 const float U1 = U0 + 0.25f;
714 const float V1 = V0 + 0.25f;
715
716 alpha -= alphaStep;
717 glColor4f(mainColor[0],mainColor[1],mainColor[2], alpha);
718 glPopMatrix();
719 glPushMatrix();
720
721 glTranslatef(pos.x, pos.y, pos.z);
722 RENDERER.getViewFrustum().executeBillboard();
723 glScalef(s, s, s);
724
725 glBegin(GL_TRIANGLE_STRIP);
726 glTexCoord2f(U0, V0);
727 glVertex2f(-1.0f, -1.0f);
728 glTexCoord2f(U1, V0);
729 glVertex2f(+1.0f, -1.0f);
730 glTexCoord2f(U0, V1);
731 glVertex2f(-1.0f, +1.0f);
732 glTexCoord2f(U1, V1);
733 glVertex2f(+1.0f, +1.0f);
734 glEnd();
735 }
736
737 addTriangleCount(shotLength * 2);
738 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
739 glPopAttrib(); // revert the texture
740 }
741 }
742 else if (BZDBCache::blend)
743 {
744 // draw corona
745 glBegin(GL_TRIANGLE_STRIP);
746 myColor4fv(mainColor);
747 glVertex2fv(core[1]);
748 myColor4fv(outerColor);
749 glVertex2fv(corona[0]);
750 myColor4fv(mainColor);
751 glVertex2fv(core[2]);
752 myColor4fv(outerColor);
753 glVertex2fv(corona[1]);
754 myColor4fv(mainColor);
755 glVertex2fv(core[3]);
756 myColor4fv(outerColor);
757 glVertex2fv(corona[2]);
758 myColor4fv(mainColor);
759 glVertex2fv(core[4]);
760 myColor4fv(outerColor);
761 glVertex2fv(corona[3]);
762 myColor4fv(mainColor);
763 glVertex2fv(core[5]);
764 myColor4fv(outerColor);
765 glVertex2fv(corona[4]);
766 myColor4fv(mainColor);
767 glVertex2fv(core[6]);
768 myColor4fv(outerColor);
769 glVertex2fv(corona[5]);
770 myColor4fv(mainColor);
771 glVertex2fv(core[7]);
772 myColor4fv(outerColor);
773 glVertex2fv(corona[6]);
774 myColor4fv(mainColor);
775 glVertex2fv(core[8]);
776 myColor4fv(outerColor);
777 glVertex2fv(corona[7]);
778 myColor4fv(mainColor);
779 glVertex2fv(core[1]);
780 myColor4fv(outerColor);
781 glVertex2fv(corona[0]);
782 glEnd(); // 18 verts -> 16 tris
783
784 // draw core
785 glBegin(GL_TRIANGLE_FAN);
786 myColor4fv(innerColor);
787 glVertex2fv(core[0]);
788 myColor4fv(mainColor);
789 glVertex2fv(core[1]);
790 glVertex2fv(core[2]);
791 glVertex2fv(core[3]);
792 glVertex2fv(core[4]);
793 glVertex2fv(core[5]);
794 glVertex2fv(core[6]);
795 glVertex2fv(core[7]);
796 glVertex2fv(core[8]);
797 glVertex2fv(core[1]);
798 glEnd(); // 10 verts -> 8 tris
799
800 addTriangleCount(24);
801 }
802 else
803 {
804 // draw corona
805 myColor4fv(coronaColor);
806 myStipple(coronaColor[3]);
807 glBegin(GL_TRIANGLE_STRIP);
808 glVertex2fv(core[1]);
809 glVertex2fv(corona[0]);
810 glVertex2fv(core[2]);
811 glVertex2fv(corona[1]);
812 glVertex2fv(core[3]);
813 glVertex2fv(corona[2]);
814 glVertex2fv(core[4]);
815 glVertex2fv(corona[3]);
816 glVertex2fv(core[5]);
817 glVertex2fv(corona[4]);
818 glVertex2fv(core[6]);
819 glVertex2fv(corona[5]);
820 glVertex2fv(core[7]);
821 glVertex2fv(corona[6]);
822 glVertex2fv(core[8]);
823 glVertex2fv(corona[7]);
824 glVertex2fv(core[1]);
825 glVertex2fv(corona[0]);
826 glEnd(); // 18 verts -> 16 tris
827
828 // draw core
829 myStipple(1.0f);
830 glBegin(GL_TRIANGLE_FAN);
831 myColor4fv(innerColor);
832 glVertex2fv(core[0]);
833 myColor4fv(mainColor);
834 glVertex2fv(core[1]);
835 glVertex2fv(core[2]);
836 glVertex2fv(core[3]);
837 glVertex2fv(core[4]);
838 glVertex2fv(core[5]);
839 glVertex2fv(core[6]);
840 glVertex2fv(core[7]);
841 glVertex2fv(core[8]);
842 glVertex2fv(core[1]);
843 glEnd(); // 10 verts -> 8 tris
844
845 myStipple(0.5f);
846
847 addTriangleCount(24);
848 }
849
850 }
851
852 glPopMatrix();
853
854 if (blackFog)
855 glFogfv(GL_FOG_COLOR, RENDERER.getFogColor());
856
857 if (RENDERER.isLastFrame())
858 {
859 if (++u == cu)
860 {
861 u = 0;
862 if (++v == cv)
863 v = 0;
864 }
865 }
866 }
867
868 // Local Variables: ***
869 // mode: C++ ***
870 // tab-width: 4 ***
871 // c-basic-offset: 4 ***
872 // indent-tabs-mode: nil ***
873 // End: ***
874 // ex: shiftwidth=4 tabstop=4
875