1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4
5 This file is part of Quake III Arena source code.
6
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 ===========================================================================
21 */
22 // Rafael particles
23 // cg_particles.c
24
25 #include "cg_local.h"
26
27 #define BLOODRED 2
28 #define EMISIVEFADE 3
29 #define GREY75 4
30
31 typedef struct particle_s
32 {
33 struct particle_s *next;
34
35 float time;
36 float endtime;
37
38 vec3_t org;
39 vec3_t vel;
40 vec3_t accel;
41 int color;
42 float colorvel;
43 float alpha;
44 float alphavel;
45 int type;
46 qhandle_t pshader;
47
48 float height;
49 float width;
50
51 float endheight;
52 float endwidth;
53
54 float start;
55 float end;
56
57 float startfade;
58 qboolean rotate;
59 int snum;
60
61 qboolean link;
62
63 // Ridah
64 int shaderAnim;
65 int roll;
66
67 int accumroll;
68
69 } cparticle_t;
70
71 typedef enum
72 {
73 P_NONE,
74 P_WEATHER,
75 P_FLAT,
76 P_SMOKE,
77 P_ROTATE,
78 P_WEATHER_TURBULENT,
79 P_ANIM, // Ridah
80 P_BAT,
81 P_BLEED,
82 P_FLAT_SCALEUP,
83 P_FLAT_SCALEUP_FADE,
84 P_WEATHER_FLURRY,
85 P_SMOKE_IMPACT,
86 P_BUBBLE,
87 P_BUBBLE_TURBULENT,
88 P_SPRITE
89 } particle_type_t;
90
91 #define MAX_SHADER_ANIMS 32
92 #define MAX_SHADER_ANIM_FRAMES 64
93
94 static char *shaderAnimNames[MAX_SHADER_ANIMS] = {
95 "explode1",
96 "blacksmokeanim",
97 "twiltb2",
98 "expblue",
99 "blacksmokeanimb", // uses 'explode1' sequence
100 "blood",
101 NULL
102 };
103 static qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES];
104 static int shaderAnimCounts[MAX_SHADER_ANIMS] = {
105 23,
106 25,
107 45,
108 25,
109 23,
110 5,
111 };
112 static float shaderAnimSTRatio[MAX_SHADER_ANIMS] = {
113 1.405f,
114 1.0f,
115 1.0f,
116 1.0f,
117 1.0f,
118 1.0f,
119 };
120 static int numShaderAnims;
121 // done.
122
123 #define PARTICLE_GRAVITY 40
124 #define MAX_PARTICLES 1024 * 8
125
126 cparticle_t *active_particles, *free_particles;
127 cparticle_t particles[MAX_PARTICLES];
128 int cl_numparticles = MAX_PARTICLES;
129
130 qboolean initparticles = qfalse;
131 vec3_t vforward, vright, vup;
132 vec3_t rforward, rright, rup;
133
134 float oldtime;
135
136 /*
137 ===============
138 CL_ClearParticles
139 ===============
140 */
CG_ClearParticles(void)141 void CG_ClearParticles (void)
142 {
143 int i;
144
145 memset( particles, 0, sizeof(particles) );
146
147 free_particles = &particles[0];
148 active_particles = NULL;
149
150 for (i=0 ;i<cl_numparticles ; i++)
151 {
152 particles[i].next = &particles[i+1];
153 particles[i].type = 0;
154 }
155 particles[cl_numparticles-1].next = NULL;
156
157 oldtime = cg.time;
158
159 // Ridah, init the shaderAnims
160 for (i=0; shaderAnimNames[i]; i++) {
161 int j;
162
163 for (j=0; j<shaderAnimCounts[i]; j++) {
164 shaderAnims[i][j] = trap_R_RegisterShader( va("%s%i", shaderAnimNames[i], j+1) );
165 }
166 }
167 numShaderAnims = i;
168 // done.
169
170 initparticles = qtrue;
171 }
172
173
174 /*
175 =====================
176 CG_AddParticleToScene
177 =====================
178 */
CG_AddParticleToScene(cparticle_t * p,vec3_t org,float alpha)179 void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha)
180 {
181
182 vec3_t point;
183 polyVert_t verts[4];
184 float width;
185 float height;
186 float time, time2;
187 float ratio;
188 float invratio;
189 vec3_t color;
190 polyVert_t TRIverts[3];
191 vec3_t rright2, rup2;
192
193 if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY
194 || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
195 {// create a front facing polygon
196
197 if (p->type != P_WEATHER_FLURRY)
198 {
199 if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
200 {
201 if (org[2] > p->end)
202 {
203 p->time = cg.time;
204 VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
205
206 p->org[2] = ( p->start + crandom () * 4 );
207
208
209 if (p->type == P_BUBBLE_TURBULENT)
210 {
211 p->vel[0] = crandom() * 4;
212 p->vel[1] = crandom() * 4;
213 }
214
215 }
216 }
217 else
218 {
219 if (org[2] < p->end)
220 {
221 p->time = cg.time;
222 VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
223
224 while (p->org[2] < p->end)
225 {
226 p->org[2] += (p->start - p->end);
227 }
228
229
230 if (p->type == P_WEATHER_TURBULENT)
231 {
232 p->vel[0] = crandom() * 16;
233 p->vel[1] = crandom() * 16;
234 }
235
236 }
237 }
238
239
240 // Rafael snow pvs check
241 if (!p->link)
242 return;
243
244 p->alpha = 1;
245 }
246
247 // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp
248 if (Distance( cg.snap->ps.origin, org ) > 1024) {
249 return;
250 }
251 // done.
252
253 if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
254 {
255 VectorMA (org, -p->height, vup, point);
256 VectorMA (point, -p->width, vright, point);
257 VectorCopy (point, verts[0].xyz);
258 verts[0].st[0] = 0;
259 verts[0].st[1] = 0;
260 verts[0].modulate[0] = 255;
261 verts[0].modulate[1] = 255;
262 verts[0].modulate[2] = 255;
263 verts[0].modulate[3] = 255 * p->alpha;
264
265 VectorMA (org, -p->height, vup, point);
266 VectorMA (point, p->width, vright, point);
267 VectorCopy (point, verts[1].xyz);
268 verts[1].st[0] = 0;
269 verts[1].st[1] = 1;
270 verts[1].modulate[0] = 255;
271 verts[1].modulate[1] = 255;
272 verts[1].modulate[2] = 255;
273 verts[1].modulate[3] = 255 * p->alpha;
274
275 VectorMA (org, p->height, vup, point);
276 VectorMA (point, p->width, vright, point);
277 VectorCopy (point, verts[2].xyz);
278 verts[2].st[0] = 1;
279 verts[2].st[1] = 1;
280 verts[2].modulate[0] = 255;
281 verts[2].modulate[1] = 255;
282 verts[2].modulate[2] = 255;
283 verts[2].modulate[3] = 255 * p->alpha;
284
285 VectorMA (org, p->height, vup, point);
286 VectorMA (point, -p->width, vright, point);
287 VectorCopy (point, verts[3].xyz);
288 verts[3].st[0] = 1;
289 verts[3].st[1] = 0;
290 verts[3].modulate[0] = 255;
291 verts[3].modulate[1] = 255;
292 verts[3].modulate[2] = 255;
293 verts[3].modulate[3] = 255 * p->alpha;
294 }
295 else
296 {
297 VectorMA (org, -p->height, vup, point);
298 VectorMA (point, -p->width, vright, point);
299 VectorCopy( point, TRIverts[0].xyz );
300 TRIverts[0].st[0] = 1;
301 TRIverts[0].st[1] = 0;
302 TRIverts[0].modulate[0] = 255;
303 TRIverts[0].modulate[1] = 255;
304 TRIverts[0].modulate[2] = 255;
305 TRIverts[0].modulate[3] = 255 * p->alpha;
306
307 VectorMA (org, p->height, vup, point);
308 VectorMA (point, -p->width, vright, point);
309 VectorCopy (point, TRIverts[1].xyz);
310 TRIverts[1].st[0] = 0;
311 TRIverts[1].st[1] = 0;
312 TRIverts[1].modulate[0] = 255;
313 TRIverts[1].modulate[1] = 255;
314 TRIverts[1].modulate[2] = 255;
315 TRIverts[1].modulate[3] = 255 * p->alpha;
316
317 VectorMA (org, p->height, vup, point);
318 VectorMA (point, p->width, vright, point);
319 VectorCopy (point, TRIverts[2].xyz);
320 TRIverts[2].st[0] = 0;
321 TRIverts[2].st[1] = 1;
322 TRIverts[2].modulate[0] = 255;
323 TRIverts[2].modulate[1] = 255;
324 TRIverts[2].modulate[2] = 255;
325 TRIverts[2].modulate[3] = 255 * p->alpha;
326 }
327
328 }
329 else if (p->type == P_SPRITE)
330 {
331 vec3_t rr, ru;
332 vec3_t rotate_ang;
333
334 VectorSet (color, 1.0, 1.0, 1.0);
335 time = cg.time - p->time;
336 time2 = p->endtime - p->time;
337 ratio = time / time2;
338
339 width = p->width + ( ratio * ( p->endwidth - p->width) );
340 height = p->height + ( ratio * ( p->endheight - p->height) );
341
342 if (p->roll) {
343 vectoangles( cg.refdef.viewaxis[0], rotate_ang );
344 rotate_ang[ROLL] += p->roll;
345 AngleVectors ( rotate_ang, NULL, rr, ru);
346 }
347
348 if (p->roll) {
349 VectorMA (org, -height, ru, point);
350 VectorMA (point, -width, rr, point);
351 } else {
352 VectorMA (org, -height, vup, point);
353 VectorMA (point, -width, vright, point);
354 }
355 VectorCopy (point, verts[0].xyz);
356 verts[0].st[0] = 0;
357 verts[0].st[1] = 0;
358 verts[0].modulate[0] = 255;
359 verts[0].modulate[1] = 255;
360 verts[0].modulate[2] = 255;
361 verts[0].modulate[3] = 255;
362
363 if (p->roll) {
364 VectorMA (point, 2*height, ru, point);
365 } else {
366 VectorMA (point, 2*height, vup, point);
367 }
368 VectorCopy (point, verts[1].xyz);
369 verts[1].st[0] = 0;
370 verts[1].st[1] = 1;
371 verts[1].modulate[0] = 255;
372 verts[1].modulate[1] = 255;
373 verts[1].modulate[2] = 255;
374 verts[1].modulate[3] = 255;
375
376 if (p->roll) {
377 VectorMA (point, 2*width, rr, point);
378 } else {
379 VectorMA (point, 2*width, vright, point);
380 }
381 VectorCopy (point, verts[2].xyz);
382 verts[2].st[0] = 1;
383 verts[2].st[1] = 1;
384 verts[2].modulate[0] = 255;
385 verts[2].modulate[1] = 255;
386 verts[2].modulate[2] = 255;
387 verts[2].modulate[3] = 255;
388
389 if (p->roll) {
390 VectorMA (point, -2*height, ru, point);
391 } else {
392 VectorMA (point, -2*height, vup, point);
393 }
394 VectorCopy (point, verts[3].xyz);
395 verts[3].st[0] = 1;
396 verts[3].st[1] = 0;
397 verts[3].modulate[0] = 255;
398 verts[3].modulate[1] = 255;
399 verts[3].modulate[2] = 255;
400 verts[3].modulate[3] = 255;
401 }
402 else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT)
403 {// create a front rotating facing polygon
404
405 if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) {
406 return;
407 }
408
409 if (p->color == BLOODRED)
410 VectorSet (color, 0.22f, 0.0f, 0.0f);
411 else if (p->color == GREY75)
412 {
413 float len;
414 float greyit;
415 float val;
416 len = Distance (cg.snap->ps.origin, org);
417 if (!len)
418 len = 1;
419
420 val = 4096/len;
421 greyit = 0.25 * val;
422 if (greyit > 0.5)
423 greyit = 0.5;
424
425 VectorSet (color, greyit, greyit, greyit);
426 }
427 else
428 VectorSet (color, 1.0, 1.0, 1.0);
429
430 time = cg.time - p->time;
431 time2 = p->endtime - p->time;
432 ratio = time / time2;
433
434 if (cg.time > p->startfade)
435 {
436 invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) );
437
438 if (p->color == EMISIVEFADE)
439 {
440 float fval;
441 fval = (invratio * invratio);
442 if (fval < 0)
443 fval = 0;
444 VectorSet (color, fval , fval , fval );
445 }
446 invratio *= p->alpha;
447 }
448 else
449 invratio = 1 * p->alpha;
450
451 if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
452 invratio = 1;
453
454 if (invratio > 1)
455 invratio = 1;
456
457 width = p->width + ( ratio * ( p->endwidth - p->width) );
458 height = p->height + ( ratio * ( p->endheight - p->height) );
459
460 if (p->type != P_SMOKE_IMPACT)
461 {
462 vec3_t temp;
463
464 vectoangles (rforward, temp);
465 p->accumroll += p->roll;
466 temp[ROLL] += p->accumroll * 0.1;
467 AngleVectors ( temp, NULL, rright2, rup2);
468 }
469 else
470 {
471 VectorCopy (rright, rright2);
472 VectorCopy (rup, rup2);
473 }
474
475 if (p->rotate)
476 {
477 VectorMA (org, -height, rup2, point);
478 VectorMA (point, -width, rright2, point);
479 }
480 else
481 {
482 VectorMA (org, -p->height, vup, point);
483 VectorMA (point, -p->width, vright, point);
484 }
485 VectorCopy (point, verts[0].xyz);
486 verts[0].st[0] = 0;
487 verts[0].st[1] = 0;
488 verts[0].modulate[0] = 255 * color[0];
489 verts[0].modulate[1] = 255 * color[1];
490 verts[0].modulate[2] = 255 * color[2];
491 verts[0].modulate[3] = 255 * invratio;
492
493 if (p->rotate)
494 {
495 VectorMA (org, -height, rup2, point);
496 VectorMA (point, width, rright2, point);
497 }
498 else
499 {
500 VectorMA (org, -p->height, vup, point);
501 VectorMA (point, p->width, vright, point);
502 }
503 VectorCopy (point, verts[1].xyz);
504 verts[1].st[0] = 0;
505 verts[1].st[1] = 1;
506 verts[1].modulate[0] = 255 * color[0];
507 verts[1].modulate[1] = 255 * color[1];
508 verts[1].modulate[2] = 255 * color[2];
509 verts[1].modulate[3] = 255 * invratio;
510
511 if (p->rotate)
512 {
513 VectorMA (org, height, rup2, point);
514 VectorMA (point, width, rright2, point);
515 }
516 else
517 {
518 VectorMA (org, p->height, vup, point);
519 VectorMA (point, p->width, vright, point);
520 }
521 VectorCopy (point, verts[2].xyz);
522 verts[2].st[0] = 1;
523 verts[2].st[1] = 1;
524 verts[2].modulate[0] = 255 * color[0];
525 verts[2].modulate[1] = 255 * color[1];
526 verts[2].modulate[2] = 255 * color[2];
527 verts[2].modulate[3] = 255 * invratio;
528
529 if (p->rotate)
530 {
531 VectorMA (org, height, rup2, point);
532 VectorMA (point, -width, rright2, point);
533 }
534 else
535 {
536 VectorMA (org, p->height, vup, point);
537 VectorMA (point, -p->width, vright, point);
538 }
539 VectorCopy (point, verts[3].xyz);
540 verts[3].st[0] = 1;
541 verts[3].st[1] = 0;
542 verts[3].modulate[0] = 255 * color[0];
543 verts[3].modulate[1] = 255 * color[1];
544 verts[3].modulate[2] = 255 * color[2];
545 verts[3].modulate[3] = 255 * invratio;
546
547 }
548 else if (p->type == P_BLEED)
549 {
550 vec3_t rr, ru;
551 vec3_t rotate_ang;
552 float alpha;
553
554 alpha = p->alpha;
555
556 if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
557 alpha = 1;
558
559 if (p->roll)
560 {
561 vectoangles( cg.refdef.viewaxis[0], rotate_ang );
562 rotate_ang[ROLL] += p->roll;
563 AngleVectors ( rotate_ang, NULL, rr, ru);
564 }
565 else
566 {
567 VectorCopy (vup, ru);
568 VectorCopy (vright, rr);
569 }
570
571 VectorMA (org, -p->height, ru, point);
572 VectorMA (point, -p->width, rr, point);
573 VectorCopy (point, verts[0].xyz);
574 verts[0].st[0] = 0;
575 verts[0].st[1] = 0;
576 verts[0].modulate[0] = 111;
577 verts[0].modulate[1] = 19;
578 verts[0].modulate[2] = 9;
579 verts[0].modulate[3] = 255 * alpha;
580
581 VectorMA (org, -p->height, ru, point);
582 VectorMA (point, p->width, rr, point);
583 VectorCopy (point, verts[1].xyz);
584 verts[1].st[0] = 0;
585 verts[1].st[1] = 1;
586 verts[1].modulate[0] = 111;
587 verts[1].modulate[1] = 19;
588 verts[1].modulate[2] = 9;
589 verts[1].modulate[3] = 255 * alpha;
590
591 VectorMA (org, p->height, ru, point);
592 VectorMA (point, p->width, rr, point);
593 VectorCopy (point, verts[2].xyz);
594 verts[2].st[0] = 1;
595 verts[2].st[1] = 1;
596 verts[2].modulate[0] = 111;
597 verts[2].modulate[1] = 19;
598 verts[2].modulate[2] = 9;
599 verts[2].modulate[3] = 255 * alpha;
600
601 VectorMA (org, p->height, ru, point);
602 VectorMA (point, -p->width, rr, point);
603 VectorCopy (point, verts[3].xyz);
604 verts[3].st[0] = 1;
605 verts[3].st[1] = 0;
606 verts[3].modulate[0] = 111;
607 verts[3].modulate[1] = 19;
608 verts[3].modulate[2] = 9;
609 verts[3].modulate[3] = 255 * alpha;
610
611 }
612 else if (p->type == P_FLAT_SCALEUP)
613 {
614 float width, height;
615 float sinR, cosR;
616
617 if (p->color == BLOODRED)
618 VectorSet (color, 1, 1, 1);
619 else
620 VectorSet (color, 0.5, 0.5, 0.5);
621
622 time = cg.time - p->time;
623 time2 = p->endtime - p->time;
624 ratio = time / time2;
625
626 width = p->width + ( ratio * ( p->endwidth - p->width) );
627 height = p->height + ( ratio * ( p->endheight - p->height) );
628
629 if (width > p->endwidth)
630 width = p->endwidth;
631
632 if (height > p->endheight)
633 height = p->endheight;
634
635 sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2);
636 cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2);
637
638 VectorCopy (org, verts[0].xyz);
639 verts[0].xyz[0] -= sinR;
640 verts[0].xyz[1] -= cosR;
641 verts[0].st[0] = 0;
642 verts[0].st[1] = 0;
643 verts[0].modulate[0] = 255 * color[0];
644 verts[0].modulate[1] = 255 * color[1];
645 verts[0].modulate[2] = 255 * color[2];
646 verts[0].modulate[3] = 255;
647
648 VectorCopy (org, verts[1].xyz);
649 verts[1].xyz[0] -= cosR;
650 verts[1].xyz[1] += sinR;
651 verts[1].st[0] = 0;
652 verts[1].st[1] = 1;
653 verts[1].modulate[0] = 255 * color[0];
654 verts[1].modulate[1] = 255 * color[1];
655 verts[1].modulate[2] = 255 * color[2];
656 verts[1].modulate[3] = 255;
657
658 VectorCopy (org, verts[2].xyz);
659 verts[2].xyz[0] += sinR;
660 verts[2].xyz[1] += cosR;
661 verts[2].st[0] = 1;
662 verts[2].st[1] = 1;
663 verts[2].modulate[0] = 255 * color[0];
664 verts[2].modulate[1] = 255 * color[1];
665 verts[2].modulate[2] = 255 * color[2];
666 verts[2].modulate[3] = 255;
667
668 VectorCopy (org, verts[3].xyz);
669 verts[3].xyz[0] += cosR;
670 verts[3].xyz[1] -= sinR;
671 verts[3].st[0] = 1;
672 verts[3].st[1] = 0;
673 verts[3].modulate[0] = 255 * color[0];
674 verts[3].modulate[1] = 255 * color[1];
675 verts[3].modulate[2] = 255 * color[2];
676 verts[3].modulate[3] = 255;
677 }
678 else if (p->type == P_FLAT)
679 {
680
681 VectorCopy (org, verts[0].xyz);
682 verts[0].xyz[0] -= p->height;
683 verts[0].xyz[1] -= p->width;
684 verts[0].st[0] = 0;
685 verts[0].st[1] = 0;
686 verts[0].modulate[0] = 255;
687 verts[0].modulate[1] = 255;
688 verts[0].modulate[2] = 255;
689 verts[0].modulate[3] = 255;
690
691 VectorCopy (org, verts[1].xyz);
692 verts[1].xyz[0] -= p->height;
693 verts[1].xyz[1] += p->width;
694 verts[1].st[0] = 0;
695 verts[1].st[1] = 1;
696 verts[1].modulate[0] = 255;
697 verts[1].modulate[1] = 255;
698 verts[1].modulate[2] = 255;
699 verts[1].modulate[3] = 255;
700
701 VectorCopy (org, verts[2].xyz);
702 verts[2].xyz[0] += p->height;
703 verts[2].xyz[1] += p->width;
704 verts[2].st[0] = 1;
705 verts[2].st[1] = 1;
706 verts[2].modulate[0] = 255;
707 verts[2].modulate[1] = 255;
708 verts[2].modulate[2] = 255;
709 verts[2].modulate[3] = 255;
710
711 VectorCopy (org, verts[3].xyz);
712 verts[3].xyz[0] += p->height;
713 verts[3].xyz[1] -= p->width;
714 verts[3].st[0] = 1;
715 verts[3].st[1] = 0;
716 verts[3].modulate[0] = 255;
717 verts[3].modulate[1] = 255;
718 verts[3].modulate[2] = 255;
719 verts[3].modulate[3] = 255;
720
721 }
722 // Ridah
723 else if (p->type == P_ANIM) {
724 vec3_t rr, ru;
725 vec3_t rotate_ang;
726 int i, j;
727
728 time = cg.time - p->time;
729 time2 = p->endtime - p->time;
730 ratio = time / time2;
731 if (ratio >= 1.0f) {
732 ratio = 0.9999f;
733 }
734
735 width = p->width + ( ratio * ( p->endwidth - p->width) );
736 height = p->height + ( ratio * ( p->endheight - p->height) );
737
738 // if we are "inside" this sprite, don't draw
739 if (Distance( cg.snap->ps.origin, org ) < width/1.5) {
740 return;
741 }
742
743 i = p->shaderAnim;
744 j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]);
745 p->pshader = shaderAnims[i][j];
746
747 if (p->roll) {
748 vectoangles( cg.refdef.viewaxis[0], rotate_ang );
749 rotate_ang[ROLL] += p->roll;
750 AngleVectors ( rotate_ang, NULL, rr, ru);
751 }
752
753 if (p->roll) {
754 VectorMA (org, -height, ru, point);
755 VectorMA (point, -width, rr, point);
756 } else {
757 VectorMA (org, -height, vup, point);
758 VectorMA (point, -width, vright, point);
759 }
760 VectorCopy (point, verts[0].xyz);
761 verts[0].st[0] = 0;
762 verts[0].st[1] = 0;
763 verts[0].modulate[0] = 255;
764 verts[0].modulate[1] = 255;
765 verts[0].modulate[2] = 255;
766 verts[0].modulate[3] = 255;
767
768 if (p->roll) {
769 VectorMA (point, 2*height, ru, point);
770 } else {
771 VectorMA (point, 2*height, vup, point);
772 }
773 VectorCopy (point, verts[1].xyz);
774 verts[1].st[0] = 0;
775 verts[1].st[1] = 1;
776 verts[1].modulate[0] = 255;
777 verts[1].modulate[1] = 255;
778 verts[1].modulate[2] = 255;
779 verts[1].modulate[3] = 255;
780
781 if (p->roll) {
782 VectorMA (point, 2*width, rr, point);
783 } else {
784 VectorMA (point, 2*width, vright, point);
785 }
786 VectorCopy (point, verts[2].xyz);
787 verts[2].st[0] = 1;
788 verts[2].st[1] = 1;
789 verts[2].modulate[0] = 255;
790 verts[2].modulate[1] = 255;
791 verts[2].modulate[2] = 255;
792 verts[2].modulate[3] = 255;
793
794 if (p->roll) {
795 VectorMA (point, -2*height, ru, point);
796 } else {
797 VectorMA (point, -2*height, vup, point);
798 }
799 VectorCopy (point, verts[3].xyz);
800 verts[3].st[0] = 1;
801 verts[3].st[1] = 0;
802 verts[3].modulate[0] = 255;
803 verts[3].modulate[1] = 255;
804 verts[3].modulate[2] = 255;
805 verts[3].modulate[3] = 255;
806 }
807 // done.
808
809 if (!p->pshader) {
810 // (SA) temp commented out for DM
811 // CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type);
812 return;
813 }
814
815 if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY)
816 trap_R_AddPolyToScene( p->pshader, 3, TRIverts );
817 else
818 trap_R_AddPolyToScene( p->pshader, 4, verts );
819
820 }
821
822 // Ridah, made this static so it doesn't interfere with other files
823 static float roll = 0.0;
824
825 /*
826 ===============
827 CG_AddParticles
828 ===============
829 */
CG_AddParticles(void)830 void CG_AddParticles (void)
831 {
832 cparticle_t *p, *next;
833 float alpha;
834 float time, time2;
835 vec3_t org;
836 int color;
837 cparticle_t *active, *tail;
838 int type;
839 vec3_t rotate_ang;
840
841 if (!initparticles)
842 CG_ClearParticles ();
843
844 VectorCopy( cg.refdef.viewaxis[0], vforward );
845 VectorCopy( cg.refdef.viewaxis[1], vright );
846 VectorCopy( cg.refdef.viewaxis[2], vup );
847
848 vectoangles( cg.refdef.viewaxis[0], rotate_ang );
849 roll += ((cg.time - oldtime) * 0.1) ;
850 rotate_ang[ROLL] += (roll*0.9);
851 AngleVectors ( rotate_ang, rforward, rright, rup);
852
853 oldtime = cg.time;
854
855 active = NULL;
856 tail = NULL;
857
858 for (p=active_particles ; p ; p=next)
859 {
860
861 next = p->next;
862
863 time = (cg.time - p->time)*0.001;
864
865 alpha = p->alpha + time*p->alphavel;
866 if (alpha <= 0)
867 { // faded out
868 p->next = free_particles;
869 free_particles = p;
870 p->type = 0;
871 p->color = 0;
872 p->alpha = 0;
873 continue;
874 }
875
876 if (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT)
877 {
878 if (cg.time > p->endtime)
879 {
880 p->next = free_particles;
881 free_particles = p;
882 p->type = 0;
883 p->color = 0;
884 p->alpha = 0;
885
886 continue;
887 }
888
889 }
890
891 if (p->type == P_WEATHER_FLURRY)
892 {
893 if (cg.time > p->endtime)
894 {
895 p->next = free_particles;
896 free_particles = p;
897 p->type = 0;
898 p->color = 0;
899 p->alpha = 0;
900
901 continue;
902 }
903 }
904
905
906 if (p->type == P_FLAT_SCALEUP_FADE)
907 {
908 if (cg.time > p->endtime)
909 {
910 p->next = free_particles;
911 free_particles = p;
912 p->type = 0;
913 p->color = 0;
914 p->alpha = 0;
915 continue;
916 }
917
918 }
919
920 if ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) {
921 // temporary sprite
922 CG_AddParticleToScene (p, p->org, alpha);
923 p->next = free_particles;
924 free_particles = p;
925 p->type = 0;
926 p->color = 0;
927 p->alpha = 0;
928 continue;
929 }
930
931 p->next = NULL;
932 if (!tail)
933 active = tail = p;
934 else
935 {
936 tail->next = p;
937 tail = p;
938 }
939
940 if (alpha > 1.0)
941 alpha = 1;
942
943 color = p->color;
944
945 time2 = time*time;
946
947 org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;
948 org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;
949 org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;
950
951 type = p->type;
952
953 CG_AddParticleToScene (p, org, alpha);
954 }
955
956 active_particles = active;
957 }
958
959 /*
960 ======================
961 CG_AddParticles
962 ======================
963 */
CG_ParticleSnowFlurry(qhandle_t pshader,centity_t * cent)964 void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent)
965 {
966 cparticle_t *p;
967 qboolean turb = qtrue;
968
969 if (!pshader)
970 CG_Printf ("CG_ParticleSnowFlurry pshader == ZERO!\n");
971
972 if (!free_particles)
973 return;
974 p = free_particles;
975 free_particles = p->next;
976 p->next = active_particles;
977 active_particles = p;
978 p->time = cg.time;
979 p->color = 0;
980 p->alpha = 0.90f;
981 p->alphavel = 0;
982
983 p->start = cent->currentState.origin2[0];
984 p->end = cent->currentState.origin2[1];
985
986 p->endtime = cg.time + cent->currentState.time;
987 p->startfade = cg.time + cent->currentState.time2;
988
989 p->pshader = pshader;
990
991 if (rand()%100 > 90)
992 {
993 p->height = 32;
994 p->width = 32;
995 p->alpha = 0.10f;
996 }
997 else
998 {
999 p->height = 1;
1000 p->width = 1;
1001 }
1002
1003 p->vel[2] = -20;
1004
1005 p->type = P_WEATHER_FLURRY;
1006
1007 if (turb)
1008 p->vel[2] = -10;
1009
1010 VectorCopy(cent->currentState.origin, p->org);
1011
1012 p->org[0] = p->org[0];
1013 p->org[1] = p->org[1];
1014 p->org[2] = p->org[2];
1015
1016 p->vel[0] = p->vel[1] = 0;
1017
1018 p->accel[0] = p->accel[1] = p->accel[2] = 0;
1019
1020 p->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16);
1021 p->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16);
1022 p->vel[2] += cent->currentState.angles[2];
1023
1024 if (turb)
1025 {
1026 p->accel[0] = crandom () * 16;
1027 p->accel[1] = crandom () * 16;
1028 }
1029
1030 }
1031
CG_ParticleSnow(qhandle_t pshader,vec3_t origin,vec3_t origin2,int turb,float range,int snum)1032 void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
1033 {
1034 cparticle_t *p;
1035
1036 if (!pshader)
1037 CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
1038
1039 if (!free_particles)
1040 return;
1041 p = free_particles;
1042 free_particles = p->next;
1043 p->next = active_particles;
1044 active_particles = p;
1045 p->time = cg.time;
1046 p->color = 0;
1047 p->alpha = 0.40f;
1048 p->alphavel = 0;
1049 p->start = origin[2];
1050 p->end = origin2[2];
1051 p->pshader = pshader;
1052 p->height = 1;
1053 p->width = 1;
1054
1055 p->vel[2] = -50;
1056
1057 if (turb)
1058 {
1059 p->type = P_WEATHER_TURBULENT;
1060 p->vel[2] = -50 * 1.3;
1061 }
1062 else
1063 {
1064 p->type = P_WEATHER;
1065 }
1066
1067 VectorCopy(origin, p->org);
1068
1069 p->org[0] = p->org[0] + ( crandom() * range);
1070 p->org[1] = p->org[1] + ( crandom() * range);
1071 p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
1072
1073 p->vel[0] = p->vel[1] = 0;
1074
1075 p->accel[0] = p->accel[1] = p->accel[2] = 0;
1076
1077 if (turb)
1078 {
1079 p->vel[0] = crandom() * 16;
1080 p->vel[1] = crandom() * 16;
1081 }
1082
1083 // Rafael snow pvs check
1084 p->snum = snum;
1085 p->link = qtrue;
1086
1087 }
1088
CG_ParticleBubble(qhandle_t pshader,vec3_t origin,vec3_t origin2,int turb,float range,int snum)1089 void CG_ParticleBubble (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
1090 {
1091 cparticle_t *p;
1092 float randsize;
1093
1094 if (!pshader)
1095 CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
1096
1097 if (!free_particles)
1098 return;
1099 p = free_particles;
1100 free_particles = p->next;
1101 p->next = active_particles;
1102 active_particles = p;
1103 p->time = cg.time;
1104 p->color = 0;
1105 p->alpha = 0.40f;
1106 p->alphavel = 0;
1107 p->start = origin[2];
1108 p->end = origin2[2];
1109 p->pshader = pshader;
1110
1111 randsize = 1 + (crandom() * 0.5);
1112
1113 p->height = randsize;
1114 p->width = randsize;
1115
1116 p->vel[2] = 50 + ( crandom() * 10 );
1117
1118 if (turb)
1119 {
1120 p->type = P_BUBBLE_TURBULENT;
1121 p->vel[2] = 50 * 1.3;
1122 }
1123 else
1124 {
1125 p->type = P_BUBBLE;
1126 }
1127
1128 VectorCopy(origin, p->org);
1129
1130 p->org[0] = p->org[0] + ( crandom() * range);
1131 p->org[1] = p->org[1] + ( crandom() * range);
1132 p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
1133
1134 p->vel[0] = p->vel[1] = 0;
1135
1136 p->accel[0] = p->accel[1] = p->accel[2] = 0;
1137
1138 if (turb)
1139 {
1140 p->vel[0] = crandom() * 4;
1141 p->vel[1] = crandom() * 4;
1142 }
1143
1144 // Rafael snow pvs check
1145 p->snum = snum;
1146 p->link = qtrue;
1147
1148 }
1149
CG_ParticleSmoke(qhandle_t pshader,centity_t * cent)1150 void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent)
1151 {
1152
1153 // using cent->density = enttime
1154 // cent->frame = startfade
1155 cparticle_t *p;
1156
1157 if (!pshader)
1158 CG_Printf ("CG_ParticleSmoke == ZERO!\n");
1159
1160 if (!free_particles)
1161 return;
1162 p = free_particles;
1163 free_particles = p->next;
1164 p->next = active_particles;
1165 active_particles = p;
1166 p->time = cg.time;
1167
1168 p->endtime = cg.time + cent->currentState.time;
1169 p->startfade = cg.time + cent->currentState.time2;
1170
1171 p->color = 0;
1172 p->alpha = 1.0;
1173 p->alphavel = 0;
1174 p->start = cent->currentState.origin[2];
1175 p->end = cent->currentState.origin2[2];
1176 p->pshader = pshader;
1177 p->rotate = qfalse;
1178 p->height = 8;
1179 p->width = 8;
1180 p->endheight = 32;
1181 p->endwidth = 32;
1182 p->type = P_SMOKE;
1183
1184 VectorCopy(cent->currentState.origin, p->org);
1185
1186 p->vel[0] = p->vel[1] = 0;
1187 p->accel[0] = p->accel[1] = p->accel[2] = 0;
1188
1189 p->vel[2] = 5;
1190
1191 if (cent->currentState.frame == 1)// reverse gravity
1192 p->vel[2] *= -1;
1193
1194 p->roll = 8 + (crandom() * 4);
1195 }
1196
1197
CG_ParticleBulletDebris(vec3_t org,vec3_t vel,int duration)1198 void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration)
1199 {
1200
1201 cparticle_t *p;
1202
1203 if (!free_particles)
1204 return;
1205 p = free_particles;
1206 free_particles = p->next;
1207 p->next = active_particles;
1208 active_particles = p;
1209 p->time = cg.time;
1210
1211 p->endtime = cg.time + duration;
1212 p->startfade = cg.time + duration/2;
1213
1214 p->color = EMISIVEFADE;
1215 p->alpha = 1.0;
1216 p->alphavel = 0;
1217
1218 p->height = 0.5;
1219 p->width = 0.5;
1220 p->endheight = 0.5;
1221 p->endwidth = 0.5;
1222
1223 p->pshader = cgs.media.tracerShader;
1224
1225 p->type = P_SMOKE;
1226
1227 VectorCopy(org, p->org);
1228
1229 p->vel[0] = vel[0];
1230 p->vel[1] = vel[1];
1231 p->vel[2] = vel[2];
1232 p->accel[0] = p->accel[1] = p->accel[2] = 0;
1233
1234 p->accel[2] = -60;
1235 p->vel[2] += -20;
1236
1237 }
1238
1239 /*
1240 ======================
1241 CG_ParticleExplosion
1242 ======================
1243 */
1244
CG_ParticleExplosion(char * animStr,vec3_t origin,vec3_t vel,int duration,int sizeStart,int sizeEnd)1245 void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd)
1246 {
1247 cparticle_t *p;
1248 int anim;
1249
1250 if (animStr < (char *)10)
1251 CG_Error( "CG_ParticleExplosion: animStr is probably an index rather than a string" );
1252
1253 // find the animation string
1254 for (anim=0; shaderAnimNames[anim]; anim++) {
1255 if (!Q_stricmp( animStr, shaderAnimNames[anim] ))
1256 break;
1257 }
1258 if (!shaderAnimNames[anim]) {
1259 CG_Error("CG_ParticleExplosion: unknown animation string: %s\n", animStr);
1260 return;
1261 }
1262
1263 if (!free_particles)
1264 return;
1265 p = free_particles;
1266 free_particles = p->next;
1267 p->next = active_particles;
1268 active_particles = p;
1269 p->time = cg.time;
1270 p->alpha = 1.0;
1271 p->alphavel = 0;
1272
1273 if (duration < 0) {
1274 duration *= -1;
1275 p->roll = 0;
1276 } else {
1277 p->roll = crandom()*179;
1278 }
1279
1280 p->shaderAnim = anim;
1281
1282 p->width = sizeStart;
1283 p->height = sizeStart*shaderAnimSTRatio[anim]; // for sprites that are stretch in either direction
1284
1285 p->endheight = sizeEnd;
1286 p->endwidth = sizeEnd*shaderAnimSTRatio[anim];
1287
1288 p->endtime = cg.time + duration;
1289
1290 p->type = P_ANIM;
1291
1292 VectorCopy( origin, p->org );
1293 VectorCopy( vel, p->vel );
1294 VectorClear( p->accel );
1295
1296 }
1297
1298 // Rafael Shrapnel
CG_AddParticleShrapnel(localEntity_t * le)1299 void CG_AddParticleShrapnel (localEntity_t *le)
1300 {
1301 return;
1302 }
1303 // done.
1304
CG_NewParticleArea(int num)1305 int CG_NewParticleArea (int num)
1306 {
1307 // const char *str;
1308 char *str;
1309 char *token;
1310 int type;
1311 vec3_t origin, origin2;
1312 int i;
1313 float range = 0;
1314 int turb;
1315 int numparticles;
1316 int snum;
1317
1318 str = (char *) CG_ConfigString (num);
1319 if (!str[0])
1320 return (0);
1321
1322 // returns type 128 64 or 32
1323 token = COM_Parse (&str);
1324 type = atoi (token);
1325
1326 if (type == 1)
1327 range = 128;
1328 else if (type == 2)
1329 range = 64;
1330 else if (type == 3)
1331 range = 32;
1332 else if (type == 0)
1333 range = 256;
1334 else if (type == 4)
1335 range = 8;
1336 else if (type == 5)
1337 range = 16;
1338 else if (type == 6)
1339 range = 32;
1340 else if (type == 7)
1341 range = 64;
1342
1343
1344 for (i=0; i<3; i++)
1345 {
1346 token = COM_Parse (&str);
1347 origin[i] = atof (token);
1348 }
1349
1350 for (i=0; i<3; i++)
1351 {
1352 token = COM_Parse (&str);
1353 origin2[i] = atof (token);
1354 }
1355
1356 token = COM_Parse (&str);
1357 numparticles = atoi (token);
1358
1359 token = COM_Parse (&str);
1360 turb = atoi (token);
1361
1362 token = COM_Parse (&str);
1363 snum = atoi (token);
1364
1365 for (i=0; i<numparticles; i++)
1366 {
1367 if (type >= 4)
1368 CG_ParticleBubble (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
1369 else
1370 CG_ParticleSnow (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
1371 }
1372
1373 return (1);
1374 }
1375
CG_SnowLink(centity_t * cent,qboolean particleOn)1376 void CG_SnowLink (centity_t *cent, qboolean particleOn)
1377 {
1378 cparticle_t *p, *next;
1379 int id;
1380
1381 id = cent->currentState.frame;
1382
1383 for (p=active_particles ; p ; p=next)
1384 {
1385 next = p->next;
1386
1387 if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT)
1388 {
1389 if (p->snum == id)
1390 {
1391 if (particleOn)
1392 p->link = qtrue;
1393 else
1394 p->link = qfalse;
1395 }
1396 }
1397
1398 }
1399 }
1400
CG_ParticleImpactSmokePuff(qhandle_t pshader,vec3_t origin)1401 void CG_ParticleImpactSmokePuff (qhandle_t pshader, vec3_t origin)
1402 {
1403 cparticle_t *p;
1404
1405 if (!pshader)
1406 CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
1407
1408 if (!free_particles)
1409 return;
1410 p = free_particles;
1411 free_particles = p->next;
1412 p->next = active_particles;
1413 active_particles = p;
1414 p->time = cg.time;
1415 p->alpha = 0.25;
1416 p->alphavel = 0;
1417 p->roll = crandom()*179;
1418
1419 p->pshader = pshader;
1420
1421 p->endtime = cg.time + 1000;
1422 p->startfade = cg.time + 100;
1423
1424 p->width = rand()%4 + 8;
1425 p->height = rand()%4 + 8;
1426
1427 p->endheight = p->height *2;
1428 p->endwidth = p->width * 2;
1429
1430 p->endtime = cg.time + 500;
1431
1432 p->type = P_SMOKE_IMPACT;
1433
1434 VectorCopy( origin, p->org );
1435 VectorSet(p->vel, 0, 0, 20);
1436 VectorSet(p->accel, 0, 0, 20);
1437
1438 p->rotate = qtrue;
1439 }
1440
CG_Particle_Bleed(qhandle_t pshader,vec3_t start,vec3_t dir,int fleshEntityNum,int duration)1441 void CG_Particle_Bleed (qhandle_t pshader, vec3_t start, vec3_t dir, int fleshEntityNum, int duration)
1442 {
1443 cparticle_t *p;
1444
1445 if (!pshader)
1446 CG_Printf ("CG_Particle_Bleed pshader == ZERO!\n");
1447
1448 if (!free_particles)
1449 return;
1450 p = free_particles;
1451 free_particles = p->next;
1452 p->next = active_particles;
1453 active_particles = p;
1454 p->time = cg.time;
1455 p->alpha = 1.0;
1456 p->alphavel = 0;
1457 p->roll = 0;
1458
1459 p->pshader = pshader;
1460
1461 p->endtime = cg.time + duration;
1462
1463 if (fleshEntityNum)
1464 p->startfade = cg.time;
1465 else
1466 p->startfade = cg.time + 100;
1467
1468 p->width = 4;
1469 p->height = 4;
1470
1471 p->endheight = 4+rand()%3;
1472 p->endwidth = p->endheight;
1473
1474 p->type = P_SMOKE;
1475
1476 VectorCopy( start, p->org );
1477 p->vel[0] = 0;
1478 p->vel[1] = 0;
1479 p->vel[2] = -20;
1480 VectorClear( p->accel );
1481
1482 p->rotate = qfalse;
1483
1484 p->roll = rand()%179;
1485
1486 p->color = BLOODRED;
1487 p->alpha = 0.75;
1488
1489 }
1490
CG_Particle_OilParticle(qhandle_t pshader,centity_t * cent)1491 void CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent)
1492 {
1493 cparticle_t *p;
1494
1495 int time;
1496 int time2;
1497 float ratio;
1498
1499 float duration = 1500;
1500
1501 time = cg.time;
1502 time2 = cg.time + cent->currentState.time;
1503
1504 ratio =(float)1 - ((float)time / (float)time2);
1505
1506 if (!pshader)
1507 CG_Printf ("CG_Particle_OilParticle == ZERO!\n");
1508
1509 if (!free_particles)
1510 return;
1511 p = free_particles;
1512 free_particles = p->next;
1513 p->next = active_particles;
1514 active_particles = p;
1515 p->time = cg.time;
1516 p->alpha = 1.0;
1517 p->alphavel = 0;
1518 p->roll = 0;
1519
1520 p->pshader = pshader;
1521
1522 p->endtime = cg.time + duration;
1523
1524 p->startfade = p->endtime;
1525
1526 p->width = 1;
1527 p->height = 3;
1528
1529 p->endheight = 3;
1530 p->endwidth = 1;
1531
1532 p->type = P_SMOKE;
1533
1534 VectorCopy(cent->currentState.origin, p->org );
1535
1536 p->vel[0] = (cent->currentState.origin2[0] * (16 * ratio));
1537 p->vel[1] = (cent->currentState.origin2[1] * (16 * ratio));
1538 p->vel[2] = (cent->currentState.origin2[2]);
1539
1540 p->snum = 1.0f;
1541
1542 VectorClear( p->accel );
1543
1544 p->accel[2] = -20;
1545
1546 p->rotate = qfalse;
1547
1548 p->roll = rand()%179;
1549
1550 p->alpha = 0.75;
1551
1552 }
1553
1554
CG_Particle_OilSlick(qhandle_t pshader,centity_t * cent)1555 void CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent)
1556 {
1557 cparticle_t *p;
1558
1559 if (!pshader)
1560 CG_Printf ("CG_Particle_OilSlick == ZERO!\n");
1561
1562 if (!free_particles)
1563 return;
1564 p = free_particles;
1565 free_particles = p->next;
1566 p->next = active_particles;
1567 active_particles = p;
1568 p->time = cg.time;
1569
1570 if (cent->currentState.angles2[2])
1571 p->endtime = cg.time + cent->currentState.angles2[2];
1572 else
1573 p->endtime = cg.time + 60000;
1574
1575 p->startfade = p->endtime;
1576
1577 p->alpha = 1.0;
1578 p->alphavel = 0;
1579 p->roll = 0;
1580
1581 p->pshader = pshader;
1582
1583 if (cent->currentState.angles2[0] || cent->currentState.angles2[1])
1584 {
1585 p->width = cent->currentState.angles2[0];
1586 p->height = cent->currentState.angles2[0];
1587
1588 p->endheight = cent->currentState.angles2[1];
1589 p->endwidth = cent->currentState.angles2[1];
1590 }
1591 else
1592 {
1593 p->width = 8;
1594 p->height = 8;
1595
1596 p->endheight = 16;
1597 p->endwidth = 16;
1598 }
1599
1600 p->type = P_FLAT_SCALEUP;
1601
1602 p->snum = 1.0;
1603
1604 VectorCopy(cent->currentState.origin, p->org );
1605
1606 p->org[2]+= 0.55 + (crandom() * 0.5);
1607
1608 p->vel[0] = 0;
1609 p->vel[1] = 0;
1610 p->vel[2] = 0;
1611 VectorClear( p->accel );
1612
1613 p->rotate = qfalse;
1614
1615 p->roll = rand()%179;
1616
1617 p->alpha = 0.75;
1618
1619 }
1620
CG_OilSlickRemove(centity_t * cent)1621 void CG_OilSlickRemove (centity_t *cent)
1622 {
1623 cparticle_t *p, *next;
1624 int id;
1625
1626 id = 1.0f;
1627
1628 if (!id)
1629 CG_Printf ("CG_OilSlickRevove NULL id\n");
1630
1631 for (p=active_particles ; p ; p=next)
1632 {
1633 next = p->next;
1634
1635 if (p->type == P_FLAT_SCALEUP)
1636 {
1637 if (p->snum == id)
1638 {
1639 p->endtime = cg.time + 100;
1640 p->startfade = p->endtime;
1641 p->type = P_FLAT_SCALEUP_FADE;
1642
1643 }
1644 }
1645
1646 }
1647 }
1648
ValidBloodPool(vec3_t start)1649 qboolean ValidBloodPool (vec3_t start)
1650 {
1651 #define EXTRUDE_DIST 0.5
1652
1653 vec3_t angles;
1654 vec3_t right, up;
1655 vec3_t this_pos, x_pos, center_pos, end_pos;
1656 float x, y;
1657 float fwidth, fheight;
1658 trace_t trace;
1659 vec3_t normal;
1660
1661 fwidth = 16;
1662 fheight = 16;
1663
1664 VectorSet (normal, 0, 0, 1);
1665
1666 vectoangles (normal, angles);
1667 AngleVectors (angles, NULL, right, up);
1668
1669 VectorMA (start, EXTRUDE_DIST, normal, center_pos);
1670
1671 for (x= -fwidth/2; x<fwidth; x+= fwidth)
1672 {
1673 VectorMA (center_pos, x, right, x_pos);
1674
1675 for (y= -fheight/2; y<fheight; y+= fheight)
1676 {
1677 VectorMA (x_pos, y, up, this_pos);
1678 VectorMA (this_pos, -EXTRUDE_DIST*2, normal, end_pos);
1679
1680 CG_Trace (&trace, this_pos, NULL, NULL, end_pos, -1, CONTENTS_SOLID);
1681
1682
1683 if (trace.entityNum < (MAX_ENTITIES - 1)) // may only land on world
1684 return qfalse;
1685
1686 if (!(!trace.startsolid && trace.fraction < 1))
1687 return qfalse;
1688
1689 }
1690 }
1691
1692 return qtrue;
1693 }
1694
CG_BloodPool(localEntity_t * le,qhandle_t pshader,trace_t * tr)1695 void CG_BloodPool (localEntity_t *le, qhandle_t pshader, trace_t *tr)
1696 {
1697 cparticle_t *p;
1698 qboolean legit;
1699 vec3_t start;
1700 float rndSize;
1701
1702 if (!pshader)
1703 CG_Printf ("CG_BloodPool pshader == ZERO!\n");
1704
1705 if (!free_particles)
1706 return;
1707
1708 VectorCopy (tr->endpos, start);
1709 legit = ValidBloodPool (start);
1710
1711 if (!legit)
1712 return;
1713
1714 p = free_particles;
1715 free_particles = p->next;
1716 p->next = active_particles;
1717 active_particles = p;
1718 p->time = cg.time;
1719
1720 p->endtime = cg.time + 3000;
1721 p->startfade = p->endtime;
1722
1723 p->alpha = 1.0;
1724 p->alphavel = 0;
1725 p->roll = 0;
1726
1727 p->pshader = pshader;
1728
1729 rndSize = 0.4 + random()*0.6;
1730
1731 p->width = 8*rndSize;
1732 p->height = 8*rndSize;
1733
1734 p->endheight = 16*rndSize;
1735 p->endwidth = 16*rndSize;
1736
1737 p->type = P_FLAT_SCALEUP;
1738
1739 VectorCopy(start, p->org );
1740
1741 p->vel[0] = 0;
1742 p->vel[1] = 0;
1743 p->vel[2] = 0;
1744 VectorClear( p->accel );
1745
1746 p->rotate = qfalse;
1747
1748 p->roll = rand()%179;
1749
1750 p->alpha = 0.75;
1751
1752 p->color = BLOODRED;
1753 }
1754
1755 #define NORMALSIZE 16
1756 #define LARGESIZE 32
1757
CG_ParticleBloodCloud(centity_t * cent,vec3_t origin,vec3_t dir)1758 void CG_ParticleBloodCloud (centity_t *cent, vec3_t origin, vec3_t dir)
1759 {
1760 float length;
1761 float dist;
1762 float crittersize;
1763 vec3_t angles, forward;
1764 vec3_t point;
1765 cparticle_t *p;
1766 int i;
1767
1768 dist = 0;
1769
1770 length = VectorLength (dir);
1771 vectoangles (dir, angles);
1772 AngleVectors (angles, forward, NULL, NULL);
1773
1774 crittersize = LARGESIZE;
1775
1776 if (length)
1777 dist = length / crittersize;
1778
1779 if (dist < 1)
1780 dist = 1;
1781
1782 VectorCopy (origin, point);
1783
1784 for (i=0; i<dist; i++)
1785 {
1786 VectorMA (point, crittersize, forward, point);
1787
1788 if (!free_particles)
1789 return;
1790
1791 p = free_particles;
1792 free_particles = p->next;
1793 p->next = active_particles;
1794 active_particles = p;
1795
1796 p->time = cg.time;
1797 p->alpha = 1.0;
1798 p->alphavel = 0;
1799 p->roll = 0;
1800
1801 p->pshader = cgs.media.smokePuffShader;
1802
1803 p->endtime = cg.time + 350 + (crandom() * 100);
1804
1805 p->startfade = cg.time;
1806
1807 p->width = LARGESIZE;
1808 p->height = LARGESIZE;
1809 p->endheight = LARGESIZE;
1810 p->endwidth = LARGESIZE;
1811
1812 p->type = P_SMOKE;
1813
1814 VectorCopy( origin, p->org );
1815
1816 p->vel[0] = 0;
1817 p->vel[1] = 0;
1818 p->vel[2] = -1;
1819
1820 VectorClear( p->accel );
1821
1822 p->rotate = qfalse;
1823
1824 p->roll = rand()%179;
1825
1826 p->color = BLOODRED;
1827
1828 p->alpha = 0.75;
1829
1830 }
1831
1832
1833 }
1834
CG_ParticleSparks(vec3_t org,vec3_t vel,int duration,float x,float y,float speed)1835 void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
1836 {
1837 cparticle_t *p;
1838
1839 if (!free_particles)
1840 return;
1841 p = free_particles;
1842 free_particles = p->next;
1843 p->next = active_particles;
1844 active_particles = p;
1845 p->time = cg.time;
1846
1847 p->endtime = cg.time + duration;
1848 p->startfade = cg.time + duration/2;
1849
1850 p->color = EMISIVEFADE;
1851 p->alpha = 0.4f;
1852 p->alphavel = 0;
1853
1854 p->height = 0.5;
1855 p->width = 0.5;
1856 p->endheight = 0.5;
1857 p->endwidth = 0.5;
1858
1859 p->pshader = cgs.media.tracerShader;
1860
1861 p->type = P_SMOKE;
1862
1863 VectorCopy(org, p->org);
1864
1865 p->org[0] += (crandom() * x);
1866 p->org[1] += (crandom() * y);
1867
1868 p->vel[0] = vel[0];
1869 p->vel[1] = vel[1];
1870 p->vel[2] = vel[2];
1871
1872 p->accel[0] = p->accel[1] = p->accel[2] = 0;
1873
1874 p->vel[0] += (crandom() * 4);
1875 p->vel[1] += (crandom() * 4);
1876 p->vel[2] += (20 + (crandom() * 10)) * speed;
1877
1878 p->accel[0] = crandom () * 4;
1879 p->accel[1] = crandom () * 4;
1880
1881 }
1882
CG_ParticleDust(centity_t * cent,vec3_t origin,vec3_t dir)1883 void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir)
1884 {
1885 float length;
1886 float dist;
1887 float crittersize;
1888 vec3_t angles, forward;
1889 vec3_t point;
1890 cparticle_t *p;
1891 int i;
1892
1893 dist = 0;
1894
1895 VectorNegate (dir, dir);
1896 length = VectorLength (dir);
1897 vectoangles (dir, angles);
1898 AngleVectors (angles, forward, NULL, NULL);
1899
1900 crittersize = LARGESIZE;
1901
1902 if (length)
1903 dist = length / crittersize;
1904
1905 if (dist < 1)
1906 dist = 1;
1907
1908 VectorCopy (origin, point);
1909
1910 for (i=0; i<dist; i++)
1911 {
1912 VectorMA (point, crittersize, forward, point);
1913
1914 if (!free_particles)
1915 return;
1916
1917 p = free_particles;
1918 free_particles = p->next;
1919 p->next = active_particles;
1920 active_particles = p;
1921
1922 p->time = cg.time;
1923 p->alpha = 5.0;
1924 p->alphavel = 0;
1925 p->roll = 0;
1926
1927 p->pshader = cgs.media.smokePuffShader;
1928
1929 // RF, stay around for long enough to expand and dissipate naturally
1930 if (length)
1931 p->endtime = cg.time + 4500 + (crandom() * 3500);
1932 else
1933 p->endtime = cg.time + 750 + (crandom() * 500);
1934
1935 p->startfade = cg.time;
1936
1937 p->width = LARGESIZE;
1938 p->height = LARGESIZE;
1939
1940 // RF, expand while falling
1941 p->endheight = LARGESIZE*3.0;
1942 p->endwidth = LARGESIZE*3.0;
1943
1944 if (!length)
1945 {
1946 p->width *= 0.2f;
1947 p->height *= 0.2f;
1948
1949 p->endheight = NORMALSIZE;
1950 p->endwidth = NORMALSIZE;
1951 }
1952
1953 p->type = P_SMOKE;
1954
1955 VectorCopy( point, p->org );
1956
1957 p->vel[0] = crandom()*6;
1958 p->vel[1] = crandom()*6;
1959 p->vel[2] = random()*20;
1960
1961 // RF, add some gravity/randomness
1962 p->accel[0] = crandom()*3;
1963 p->accel[1] = crandom()*3;
1964 p->accel[2] = -PARTICLE_GRAVITY*0.4;
1965
1966 VectorClear( p->accel );
1967
1968 p->rotate = qfalse;
1969
1970 p->roll = rand()%179;
1971
1972 p->alpha = 0.75;
1973
1974 }
1975
1976
1977 }
1978
CG_ParticleMisc(qhandle_t pshader,vec3_t origin,int size,int duration,float alpha)1979 void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha)
1980 {
1981 cparticle_t *p;
1982
1983 if (!pshader)
1984 CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
1985
1986 if (!free_particles)
1987 return;
1988
1989 p = free_particles;
1990 free_particles = p->next;
1991 p->next = active_particles;
1992 active_particles = p;
1993 p->time = cg.time;
1994 p->alpha = 1.0;
1995 p->alphavel = 0;
1996 p->roll = rand()%179;
1997
1998 p->pshader = pshader;
1999
2000 if (duration > 0)
2001 p->endtime = cg.time + duration;
2002 else
2003 p->endtime = duration;
2004
2005 p->startfade = cg.time;
2006
2007 p->width = size;
2008 p->height = size;
2009
2010 p->endheight = size;
2011 p->endwidth = size;
2012
2013 p->type = P_SPRITE;
2014
2015 VectorCopy( origin, p->org );
2016
2017 p->rotate = qfalse;
2018 }
2019