1 /*
2 ===========================================================================
3
4 Return to Castle Wolfenstein single player GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Return to Castle Wolfenstein single player GPL Source Code (RTCW SP Source Code).
8
9 RTCW SP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 RTCW SP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with RTCW SP Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the RTCW SP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW SP Source Code. If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 // Ridah, cg_trails.c - draws a trail using multiple junction points
30
31 #include "cg_local.h"
32
33 typedef struct trailJunc_s
34 {
35 struct trailJunc_s *nextGlobal, *prevGlobal; // next junction in the global list it is in (free or used)
36 struct trailJunc_s *nextJunc; // next junction in the trail
37 struct trailJunc_s *nextHead, *prevHead; // next head junc in the world
38
39 qboolean inuse, freed;
40 int ownerIndex;
41 qhandle_t shader;
42
43 int sType;
44 int flags;
45 float sTex;
46 vec3_t pos;
47 int spawnTime, endTime;
48 float alphaStart, alphaEnd;
49 vec3_t colorStart, colorEnd;
50 float widthStart, widthEnd;
51
52 // current settings
53 float alpha;
54 float width;
55 vec3_t color;
56
57 } trailJunc_t;
58
59 #define MAX_TRAILJUNCS 4096
60
61 trailJunc_t trailJuncs[MAX_TRAILJUNCS];
62 trailJunc_t *freeTrails, *activeTrails;
63 trailJunc_t *headTrails;
64
65 qboolean initTrails = qfalse;
66
67 int numTrailsInuse;
68
69 /*
70 ===============
71 CG_ClearTrails
72 ===============
73 */
CG_ClearTrails(void)74 void CG_ClearTrails( void ) {
75 int i;
76
77 memset( trailJuncs, 0, sizeof( trailJunc_t ) * MAX_TRAILJUNCS );
78
79 freeTrails = trailJuncs;
80 activeTrails = NULL;
81 headTrails = NULL;
82
83 for ( i = 0 ; i < MAX_TRAILJUNCS ; i++ )
84 {
85 trailJuncs[i].nextGlobal = &trailJuncs[i + 1];
86
87 if ( i > 0 ) {
88 trailJuncs[i].prevGlobal = &trailJuncs[i - 1];
89 } else {
90 trailJuncs[i].prevGlobal = NULL;
91 }
92
93 trailJuncs[i].inuse = qfalse;
94 }
95 trailJuncs[MAX_TRAILJUNCS - 1].nextGlobal = NULL;
96
97 initTrails = qtrue;
98 numTrailsInuse = 0;
99 }
100
101 /*
102 ===============
103 CG_SpawnTrailJunc
104 ===============
105 */
CG_SpawnTrailJunc(trailJunc_t * headJunc)106 trailJunc_t *CG_SpawnTrailJunc( trailJunc_t *headJunc ) {
107 trailJunc_t *j;
108
109 if ( !freeTrails ) {
110 return NULL;
111 }
112
113 if ( cg_paused.integer ) {
114 return NULL;
115 }
116
117 // select the first free trail, and remove it from the list
118 j = freeTrails;
119 freeTrails = j->nextGlobal;
120 if ( freeTrails ) {
121 freeTrails->prevGlobal = NULL;
122 }
123
124 j->nextGlobal = activeTrails;
125 if ( activeTrails ) {
126 activeTrails->prevGlobal = j;
127 }
128 activeTrails = j;
129 j->prevGlobal = NULL;
130 j->inuse = qtrue;
131 j->freed = qfalse;
132
133 // if this owner has a headJunc, add us to the start
134 if ( headJunc ) {
135 // remove the headJunc from the list of heads
136 if ( headJunc == headTrails ) {
137 headTrails = headJunc->nextHead;
138 if ( headTrails ) {
139 headTrails->prevHead = NULL;
140 }
141 } else {
142 if ( headJunc->nextHead ) {
143 headJunc->nextHead->prevHead = headJunc->prevHead;
144 }
145 if ( headJunc->prevHead ) {
146 headJunc->prevHead->nextHead = headJunc->nextHead;
147 }
148 }
149 headJunc->prevHead = NULL;
150 headJunc->nextHead = NULL;
151 }
152 // make us the headTrail
153 if ( headTrails ) {
154 headTrails->prevHead = j;
155 }
156 j->nextHead = headTrails;
157 j->prevHead = NULL;
158 headTrails = j;
159
160 j->nextJunc = headJunc; // if headJunc is NULL, then we'll just be the end of the list
161
162 numTrailsInuse++;
163
164 // debugging
165 // CG_Printf( "NumTrails: %i\n", numTrailsInuse );
166
167 return j;
168 }
169
170
171 /*
172 ===============
173 CG_AddTrailJunc
174
175 returns the index of the trail junction created
176
177 Used for generic trails
178 ===============
179 */
CG_AddTrailJunc(int headJuncIndex,qhandle_t shader,int spawnTime,int sType,vec3_t pos,int trailLife,float alphaStart,float alphaEnd,float startWidth,float endWidth,int flags,vec3_t colorStart,vec3_t colorEnd,float sRatio,float animSpeed)180 int CG_AddTrailJunc( int headJuncIndex, qhandle_t shader, int spawnTime, int sType, vec3_t pos, int trailLife, float alphaStart, float alphaEnd, float startWidth, float endWidth, int flags, vec3_t colorStart, vec3_t colorEnd, float sRatio, float animSpeed ) {
181 trailJunc_t *j, *headJunc;
182
183 if ( headJuncIndex > 0 ) {
184 headJunc = &trailJuncs[headJuncIndex - 1];
185
186 if ( !headJunc->inuse ) {
187 headJunc = NULL;
188 }
189 } else {
190 headJunc = NULL;
191 }
192
193 j = CG_SpawnTrailJunc( headJunc );
194 if ( !j ) {
195 // CG_Printf("couldnt spawn trail junc\n");
196 return 0;
197 }
198
199 if ( alphaStart > 1.0 ) {
200 alphaStart = 1.0;
201 }
202 if ( alphaStart < 0.0 ) {
203 alphaStart = 0.0;
204 }
205 if ( alphaEnd > 1.0 ) {
206 alphaEnd = 1.0;
207 }
208 if ( alphaEnd < 0.0 ) {
209 alphaEnd = 0.0;
210 }
211
212 // setup the trail junction
213 j->shader = shader;
214 j->sType = sType;
215 VectorCopy( pos, j->pos );
216 j->flags = flags;
217
218 j->spawnTime = spawnTime;
219 j->endTime = spawnTime + trailLife;
220
221 VectorCopy( colorStart, j->colorStart );
222 VectorCopy( colorEnd, j->colorEnd );
223
224 j->alphaStart = alphaStart;
225 j->alphaEnd = alphaEnd;
226
227 j->widthStart = startWidth;
228 j->widthEnd = endWidth;
229
230 if ( sType == STYPE_REPEAT ) {
231 if ( headJunc ) {
232 j->sTex = headJunc->sTex + ( ( Distance( headJunc->pos, pos ) / sRatio ) / j->widthEnd );
233 } else {
234 // FIXME: need a way to specify offset timing
235 j->sTex = ( animSpeed * ( 1.0 - ( (float)( cg.time % 1000 ) / 1000.0 ) ) ) / ( sRatio );
236 // j->sTex = 0;
237 }
238 }
239
240 return ( (int)( j - trailJuncs ) + 1 );
241 }
242
243 /*
244 ===============
245 CG_AddSparkJunc
246
247 returns the index of the trail junction created
248 ===============
249 */
CG_AddSparkJunc(int headJuncIndex,qhandle_t shader,vec3_t pos,int trailLife,float alphaStart,float alphaEnd,float startWidth,float endWidth)250 int CG_AddSparkJunc( int headJuncIndex, qhandle_t shader, vec3_t pos, int trailLife, float alphaStart, float alphaEnd, float startWidth, float endWidth ) {
251 trailJunc_t *j, *headJunc;
252
253 if ( headJuncIndex > 0 ) {
254 headJunc = &trailJuncs[headJuncIndex - 1];
255
256 if ( !headJunc->inuse ) {
257 headJunc = NULL;
258 }
259 } else {
260 headJunc = NULL;
261 }
262
263 j = CG_SpawnTrailJunc( headJunc );
264 if ( !j ) {
265 return 0;
266 }
267
268 // setup the trail junction
269 j->shader = shader;
270 j->sType = STYPE_STRETCH;
271 VectorCopy( pos, j->pos );
272 j->flags = TJFL_NOCULL; // don't worry about fading up close
273
274 j->spawnTime = cg.time;
275 j->endTime = cg.time + trailLife;
276
277 VectorSet( j->colorStart, 1.0, 0.8 + 0.2 * alphaStart, 0.4 + 0.4 * alphaStart );
278 VectorSet( j->colorEnd, 1.0, 0.8 + 0.2 * alphaEnd, 0.4 + 0.4 * alphaEnd );
279 // VectorScale( j->colorStart, alphaStart, j->colorStart );
280 // VectorScale( j->colorEnd, alphaEnd, j->colorEnd );
281
282 j->alphaStart = alphaStart * 2;
283 j->alphaEnd = alphaEnd * 2;
284 // j->alphaStart = 1.0;
285 // j->alphaEnd = 1.0;
286
287 j->widthStart = startWidth;
288 j->widthEnd = endWidth;
289
290 return ( (int)( j - trailJuncs ) + 1 );
291 }
292
293 /*
294 ===============
295 CG_AddSmokeJunc
296
297 returns the index of the trail junction created
298 ===============
299 */
CG_AddSmokeJunc(int headJuncIndex,qhandle_t shader,vec3_t pos,int trailLife,float alpha,float startWidth,float endWidth)300 int CG_AddSmokeJunc( int headJuncIndex, qhandle_t shader, vec3_t pos, int trailLife, float alpha, float startWidth, float endWidth ) {
301 #define ST_RATIO 4.0 // sprite image: width / height
302 trailJunc_t *j, *headJunc;
303
304 if ( headJuncIndex > 0 ) {
305 headJunc = &trailJuncs[headJuncIndex - 1];
306
307 if ( !headJunc->inuse ) {
308 headJunc = NULL;
309 }
310 } else {
311 headJunc = NULL;
312 }
313
314 j = CG_SpawnTrailJunc( headJunc );
315 if ( !j ) {
316 return 0;
317 }
318
319 // setup the trail junction
320 j->shader = shader;
321 j->sType = STYPE_REPEAT;
322 VectorCopy( pos, j->pos );
323 j->flags = TJFL_FADEIN;
324
325 j->spawnTime = cg.time;
326 j->endTime = cg.time + trailLife;
327
328 // VectorSet( j->colorStart, 0.2, 0.2, 0.2 );
329 VectorSet( j->colorStart, 0.0, 0.0, 0.0 );
330 // VectorSet( j->colorEnd, 0.1, 0.1, 0.1 );
331 VectorSet( j->colorEnd, 0.0, 0.0, 0.0 );
332
333 j->alphaStart = alpha;
334 j->alphaEnd = 0.0;
335
336 j->widthStart = startWidth;
337 j->widthEnd = endWidth;
338
339 if ( headJunc ) {
340 j->sTex = headJunc->sTex + ( ( Distance( headJunc->pos, pos ) / ST_RATIO ) / j->widthEnd );
341 } else {
342 // first junction, so this will become the "tail" very soon, make it fade out
343 j->sTex = 0;
344 j->alphaStart = 0.0;
345 j->alphaEnd = 0.0;
346 }
347
348 return ( (int)( j - trailJuncs ) + 1 );
349 }
350
351 void CG_KillTrail( trailJunc_t *t );
352
353 /*
354 ===========
355 CG_FreeTrailJunc
356 ===========
357 */
CG_FreeTrailJunc(trailJunc_t * junc)358 void CG_FreeTrailJunc( trailJunc_t *junc ) {
359 // kill any juncs after us, so they aren't left hanging
360 if ( junc->nextJunc ) {
361 CG_KillTrail( junc );
362 }
363
364 // make it non-active
365 junc->inuse = qfalse;
366 junc->freed = qtrue;
367 if ( junc->nextGlobal ) {
368 junc->nextGlobal->prevGlobal = junc->prevGlobal;
369 }
370 if ( junc->prevGlobal ) {
371 junc->prevGlobal->nextGlobal = junc->nextGlobal;
372 }
373 if ( junc == activeTrails ) {
374 activeTrails = junc->nextGlobal;
375 }
376
377 // if it's a head, remove it
378 if ( junc == headTrails ) {
379 headTrails = junc->nextHead;
380 }
381 if ( junc->nextHead ) {
382 junc->nextHead->prevHead = junc->prevHead;
383 }
384 if ( junc->prevHead ) {
385 junc->prevHead->nextHead = junc->nextHead;
386 }
387 junc->nextHead = NULL;
388 junc->prevHead = NULL;
389
390 // stick it in the free list
391 junc->prevGlobal = NULL;
392 junc->nextGlobal = freeTrails;
393 if ( freeTrails ) {
394 freeTrails->prevGlobal = junc;
395 }
396 freeTrails = junc;
397
398 numTrailsInuse--;
399 }
400
401 /*
402 ===========
403 CG_KillTrail
404 ===========
405 */
CG_KillTrail(trailJunc_t * t)406 void CG_KillTrail( trailJunc_t *t ) {
407 trailJunc_t *next;
408
409 next = t->nextJunc;
410
411 // kill the trail here
412 t->nextJunc = NULL;
413
414 if ( next ) {
415 CG_FreeTrailJunc( next );
416 }
417 }
418
419 /*
420 ==============
421 CG_AddTrailToScene
422
423 TODO: this can do with some major optimization
424 ==============
425 */
426 struct {
427 vec3_t vforward, vright, vup;
428 } trailOrientation;
429 #define MAX_TRAIL_VERTS 2048
430 static polyVert_t verts[MAX_TRAIL_VERTS];
431 static polyVert_t outVerts[MAX_TRAIL_VERTS * 3];
432
CG_AddTrailToScene(trailJunc_t * trail,int iteration,int numJuncs)433 void CG_AddTrailToScene( trailJunc_t *trail, int iteration, int numJuncs ) {
434 int k, i, n, l, numOutVerts;
435 polyVert_t mid;
436 float mod[4];
437 float sInc = 0.0f, s = 0.0f; // TTimo: init
438 trailJunc_t *j, *jNext;
439 vec3_t up, p, v;
440 // clipping vars
441 #define TRAIL_FADE_CLOSE_DIST 64.0
442 #define TRAIL_FADE_FAR_SCALE 4.0
443 vec3_t viewProj;
444 float viewDist, fadeAlpha;
445
446 // add spark shader at head position
447 if ( trail->flags & TJFL_SPARKHEADFLARE ) {
448 j = trail;
449 VectorCopy( j->pos, p );
450 VectorMA( p, -j->width * 2, trailOrientation.vup, p );
451 VectorMA( p, -j->width * 2, trailOrientation.vright, p );
452 VectorCopy( p, verts[0].xyz );
453 verts[0].st[0] = 0;
454 verts[0].st[1] = 0;
455 verts[0].modulate[0] = 255;
456 verts[0].modulate[1] = 255;
457 verts[0].modulate[2] = 255;
458 verts[0].modulate[3] = ( unsigned char )( j->alpha * 255.0 );
459
460 VectorCopy( j->pos, p );
461 VectorMA( p, -j->width * 2, trailOrientation.vup, p );
462 VectorMA( p, j->width * 2, trailOrientation.vright, p );
463 VectorCopy( p, verts[1].xyz );
464 verts[1].st[0] = 0;
465 verts[1].st[1] = 1;
466 verts[1].modulate[0] = 255;
467 verts[1].modulate[1] = 255;
468 verts[1].modulate[2] = 255;
469 verts[1].modulate[3] = ( unsigned char )( j->alpha * 255.0 );
470
471 VectorCopy( j->pos, p );
472 VectorMA( p, j->width * 2, trailOrientation.vup, p );
473 VectorMA( p, j->width * 2, trailOrientation.vright, p );
474 VectorCopy( p, verts[2].xyz );
475 verts[2].st[0] = 1;
476 verts[2].st[1] = 1;
477 verts[2].modulate[0] = 255;
478 verts[2].modulate[1] = 255;
479 verts[2].modulate[2] = 255;
480 verts[2].modulate[3] = ( unsigned char )( j->alpha * 255.0 );
481
482 VectorCopy( j->pos, p );
483 VectorMA( p, j->width * 2, trailOrientation.vup, p );
484 VectorMA( p, -j->width * 2, trailOrientation.vright, p );
485 VectorCopy( p, verts[3].xyz );
486 verts[3].st[0] = 1;
487 verts[3].st[1] = 0;
488 verts[3].modulate[0] = 255;
489 verts[3].modulate[1] = 255;
490 verts[3].modulate[2] = 255;
491 verts[3].modulate[3] = ( unsigned char )( j->alpha * 255.0 );
492
493 trap_R_AddPolyToScene( cgs.media.sparkFlareShader, 4, verts );
494 }
495
496 // if (trail->flags & TJFL_CROSSOVER && iteration < 1) {
497 // iteration = 1;
498 // }
499
500 if ( !numJuncs ) {
501 // first count the number of juncs in the trail
502 j = trail;
503 numJuncs = 0;
504 sInc = 0;
505 while ( j ) {
506 numJuncs++;
507
508 // check for a dead next junc
509 if ( !j->inuse && j->nextJunc && !j->nextJunc->inuse ) {
510 CG_KillTrail( j );
511 } else if ( j->nextJunc && j->nextJunc->freed ) {
512 // not sure how this can happen, but it does, and causes infinite loops
513 j->nextJunc = NULL;
514 }
515
516 if ( j->nextJunc ) {
517 sInc += VectorDistance( j->nextJunc->pos, j->pos );
518 }
519
520 j = j->nextJunc;
521 }
522 }
523
524 if ( numJuncs < 2 ) {
525 return;
526 }
527
528 if ( trail->sType == STYPE_STRETCH ) {
529 //sInc = ((1.0 - 0.1) / (float)(numJuncs)); // hack, the end of funnel shows a bit of the start (looping)
530 s = 0.05;
531 //s = 0.05;
532 } else if ( trail->sType == STYPE_REPEAT ) {
533 s = trail->sTex;
534 }
535
536 // now traverse the list
537 j = trail;
538 jNext = j->nextJunc;
539 i = 0;
540 while ( jNext ) {
541
542 // first get the directional vectors to the next junc
543 GetPerpendicularViewVector( cg.refdef.vieworg, j->pos, jNext->pos, up );
544
545 // if it's a crossover, draw it twice
546 if ( j->flags & TJFL_CROSSOVER ) {
547 if ( iteration > 0 ) {
548 ProjectPointOntoVector( cg.refdef.vieworg, j->pos, jNext->pos, viewProj );
549 VectorSubtract( cg.refdef.vieworg, viewProj, v );
550 VectorNormalize( v );
551
552 if ( iteration == 1 ) {
553 VectorMA( up, 0.3, v, up );
554 } else {
555 VectorMA( up, -0.3, v, up );
556 }
557 VectorNormalize( up );
558 }
559 }
560 // do fading when moving towards the projection point onto the trail segment vector
561 else if ( !( j->flags & TJFL_NOCULL ) && ( j->widthEnd > 4 || jNext->widthEnd > 4 ) ) {
562 ProjectPointOntoVector( cg.refdef.vieworg, j->pos, jNext->pos, viewProj );
563 viewDist = Distance( viewProj, cg.refdef.vieworg );
564 if ( viewDist < ( TRAIL_FADE_CLOSE_DIST * TRAIL_FADE_FAR_SCALE ) ) {
565 if ( viewDist < TRAIL_FADE_CLOSE_DIST ) {
566 fadeAlpha = 0.0;
567 } else {
568 fadeAlpha = ( viewDist - TRAIL_FADE_CLOSE_DIST ) / ( TRAIL_FADE_CLOSE_DIST * TRAIL_FADE_FAR_SCALE );
569 }
570 if ( fadeAlpha < j->alpha ) {
571 j->alpha = fadeAlpha;
572 }
573 if ( fadeAlpha < jNext->alpha ) {
574 jNext->alpha = fadeAlpha;
575 }
576 }
577 }
578
579 // now output the QUAD for this segment
580
581 // 1 ----
582 VectorMA( j->pos, 0.5 * j->width, up, p );
583 VectorCopy( p, verts[i].xyz );
584 verts[i].st[0] = s;
585 verts[i].st[1] = 1.0;
586 for ( k = 0; k < 3; k++ )
587 verts[i].modulate[k] = ( unsigned char )( j->color[k] * 255.0 );
588 verts[i].modulate[3] = ( unsigned char )( j->alpha * 255.0 );
589
590 // blend this with the previous junc
591 if ( j != trail ) {
592 VectorAdd( verts[i].xyz, verts[i - 1].xyz, verts[i].xyz );
593 VectorScale( verts[i].xyz, 0.5, verts[i].xyz );
594 VectorCopy( verts[i].xyz, verts[i - 1].xyz );
595 } else if ( j->flags & TJFL_FADEIN ) {
596 verts[i].modulate[3] = 0; // fade in
597 }
598
599 i++;
600
601 // 2 ----
602 VectorMA( p, -1 * j->width, up, p );
603 VectorCopy( p, verts[i].xyz );
604 verts[i].st[0] = s;
605 verts[i].st[1] = 0.0;
606 for ( k = 0; k < 3; k++ )
607 verts[i].modulate[k] = ( unsigned char )( j->color[k] * 255.0 );
608 verts[i].modulate[3] = ( unsigned char )( j->alpha * 255.0 );
609
610 // blend this with the previous junc
611 if ( j != trail ) {
612 VectorAdd( verts[i].xyz, verts[i - 3].xyz, verts[i].xyz );
613 VectorScale( verts[i].xyz, 0.5, verts[i].xyz );
614 VectorCopy( verts[i].xyz, verts[i - 3].xyz );
615 } else if ( j->flags & TJFL_FADEIN ) {
616 verts[i].modulate[3] = 0; // fade in
617 }
618
619 i++;
620
621 if ( trail->sType == STYPE_REPEAT ) {
622 s = jNext->sTex;
623 } else {
624 //s += sInc;
625 s += VectorDistance( j->pos, jNext->pos ) / sInc;
626 if ( s > 1.0 ) {
627 s = 1.0;
628 }
629 }
630
631 // 3 ----
632 VectorMA( jNext->pos, -0.5 * jNext->width, up, p );
633 VectorCopy( p, verts[i].xyz );
634 verts[i].st[0] = s;
635 verts[i].st[1] = 0.0;
636 for ( k = 0; k < 3; k++ )
637 verts[i].modulate[k] = ( unsigned char )( jNext->color[k] * 255.0 );
638 verts[i].modulate[3] = ( unsigned char )( jNext->alpha * 255.0 );
639 i++;
640
641 // 4 ----
642 VectorMA( p, jNext->width, up, p );
643 VectorCopy( p, verts[i].xyz );
644 verts[i].st[0] = s;
645 verts[i].st[1] = 1.0;
646 for ( k = 0; k < 3; k++ )
647 verts[i].modulate[k] = ( unsigned char )( jNext->color[k] * 255.0 );
648 verts[i].modulate[3] = ( unsigned char )( jNext->alpha * 255.0 );
649 i++;
650
651 if ( i + 4 > MAX_TRAIL_VERTS ) {
652 break;
653 }
654
655 j = jNext;
656 jNext = j->nextJunc;
657 }
658
659 if ( trail->flags & TJFL_FIXDISTORT ) {
660 // build the list of outVerts, by dividing up the QUAD's into 4 Tri's each, so as to allow
661 // any shaped (convex) Quad without bilinear distortion
662 for ( k = 0, numOutVerts = 0; k < i; k += 4 ) {
663 VectorCopy( verts[k].xyz, mid.xyz );
664 mid.st[0] = verts[k].st[0];
665 mid.st[1] = verts[k].st[1];
666 for ( l = 0; l < 4; l++ ) {
667 mod[l] = (float)verts[k].modulate[l];
668 }
669 for ( n = 1; n < 4; n++ ) {
670 VectorAdd( verts[k + n].xyz, mid.xyz, mid.xyz );
671 mid.st[0] += verts[k + n].st[0];
672 mid.st[1] += verts[k + n].st[1];
673 for ( l = 0; l < 4; l++ ) {
674 mod[l] += (float)verts[k + n].modulate[l];
675 }
676 }
677 VectorScale( mid.xyz, 0.25, mid.xyz );
678 mid.st[0] *= 0.25;
679 mid.st[1] *= 0.25;
680 for ( l = 0; l < 4; l++ ) {
681 mid.modulate[l] = ( unsigned char )( mod[l] / 4.0 );
682 }
683
684 // now output the tri's
685 for ( n = 0; n < 4; n++ ) {
686 outVerts[numOutVerts++] = verts[k + n];
687 outVerts[numOutVerts++] = mid;
688 if ( n < 3 ) {
689 outVerts[numOutVerts++] = verts[k + n + 1];
690 } else {
691 outVerts[numOutVerts++] = verts[k];
692 }
693 }
694
695 }
696
697 if ( !( trail->flags & TJFL_NOPOLYMERGE ) ) {
698 trap_R_AddPolysToScene( trail->shader, 3, &outVerts[0], numOutVerts / 3 );
699 } else {
700 int k;
701 for ( k = 0; k < numOutVerts / 3; k++ ) {
702 trap_R_AddPolyToScene( trail->shader, 3, &outVerts[k * 3] );
703 }
704 }
705 } else
706 {
707 // send the polygons
708 // FIXME: is it possible to send a GL_STRIP here? We are actually sending 2x the verts we really need to
709 if ( !( trail->flags & TJFL_NOPOLYMERGE ) ) {
710 trap_R_AddPolysToScene( trail->shader, 4, &verts[0], i / 4 );
711 } else {
712 int k;
713 for ( k = 0; k < i / 4; k++ ) {
714 trap_R_AddPolyToScene( trail->shader, 4, &verts[k * 4] );
715 }
716 }
717 }
718
719 // do we need to make another pass?
720 if ( trail->flags & TJFL_CROSSOVER ) {
721 if ( iteration < 2 ) {
722 CG_AddTrailToScene( trail, iteration + 1, numJuncs );
723 }
724 }
725
726 }
727
728 /*
729 ===============
730 CG_AddTrails
731 ===============
732 */
CG_AddTrails(void)733 void CG_AddTrails( void ) {
734 float lifeFrac;
735 trailJunc_t *j, *jNext;
736
737 if ( !initTrails ) {
738 CG_ClearTrails();
739 }
740
741 //AngleVectors( cg.snap->ps.viewangles, trailOrientation.vforward, trailOrientation.vright, trailOrientation.vup );
742 VectorCopy( cg.refdef.viewaxis[0], trailOrientation.vforward );
743 VectorCopy( cg.refdef.viewaxis[1], trailOrientation.vright );
744 VectorCopy( cg.refdef.viewaxis[2], trailOrientation.vup );
745
746 // update the settings for each junc
747 j = activeTrails;
748 while ( j ) {
749 lifeFrac = (float)( cg.time - j->spawnTime ) / (float)( j->endTime - j->spawnTime );
750 if ( lifeFrac >= 1.0 ) {
751 j->inuse = qfalse; // flag it as dead
752 j->width = j->widthEnd;
753 j->alpha = j->alphaEnd;
754 if ( j->alpha > 1.0 ) {
755 j->alpha = 1.0;
756 } else if ( j->alpha < 0.0 ) {
757 j->alpha = 0.0;
758 }
759 VectorCopy( j->colorEnd, j->color );
760 } else {
761 j->width = j->widthStart + ( j->widthEnd - j->widthStart ) * lifeFrac;
762 j->alpha = j->alphaStart + ( j->alphaEnd - j->alphaStart ) * lifeFrac;
763 if ( j->alpha > 1.0 ) {
764 j->alpha = 1.0;
765 } else if ( j->alpha < 0.0 ) {
766 j->alpha = 0.0;
767 }
768 VectorSubtract( j->colorEnd, j->colorStart, j->color );
769 VectorMA( j->colorStart, lifeFrac, j->color, j->color );
770 }
771
772 j = j->nextGlobal;
773 }
774
775 // draw the trailHeads
776 j = headTrails;
777 while ( j ) {
778 jNext = j->nextHead; // in case it gets removed
779 if ( !j->inuse ) {
780 CG_FreeTrailJunc( j );
781 } else {
782 CG_AddTrailToScene( j, 0, 0 );
783 }
784 j = jNext;
785 }
786 }
787