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