1 /*
2 	gl_dyn_part.c
3 
4 	OpenGL particle system.
5 
6 	Copyright (C) 1996-1997  Id Software, Inc.
7 
8 	This program is free software; you can redistribute it and/or
9 	modify it under the terms of the GNU General Public License
10 	as published by the Free Software Foundation; either version 2
11 	of the License, or (at your option) any later version.
12 
13 	This program is distributed in the hope that it will be useful,
14 	but WITHOUT ANY WARRANTY; without even the implied warranty of
15 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 	See the GNU General Public License for more details.
18 
19 	You should have received a copy of the GNU General Public License
20 	along with this program; if not, write to:
21 
22 		Free Software Foundation, Inc.
23 		59 Temple Place - Suite 330
24 		Boston, MA  02111-1307, USA
25 
26 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 
31 #define NH_DEFINE
32 #include "namehack.h"
33 
34 #ifdef HAVE_STRING_H
35 # include <string.h>
36 #endif
37 #ifdef HAVE_STRINGS_H
38 # include <strings.h>
39 #endif
40 
41 #include <stdlib.h>
42 
43 #include "QF/cmd.h"
44 #include "QF/cvar.h"
45 #include "QF/mersenne.h"
46 #include "QF/qargs.h"
47 #include "QF/quakefs.h"
48 #include "QF/render.h"
49 #include "QF/sys.h"
50 #include "QF/va.h"
51 #include "QF/GL/defines.h"
52 #include "QF/GL/funcs.h"
53 #include "QF/GL/qf_explosions.h"
54 #include "QF/GL/qf_textures.h"
55 #include "QF/GL/qf_vid.h"
56 
57 #include "compat.h"
58 #include "r_internal.h"
59 #include "varrays.h"
60 
61 static int		ramp1[8] = { 0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61 };
62 //static int	ramp2[8] = { 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66 };
63 static int		ramp3[8] = { 0x6d, 0x6b, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
64 
65 static int						partUseVA;
66 static int						pVAsize;
67 static int					   *pVAindices;
68 static varray_t2f_c4ub_v3f_t   *particleVertexArray;
69 
70 static mtstate_t mt;	// private PRNG state
71 
72 inline static void
particle_new(ptype_t type,int texnum,const vec3_t org,float scale,const vec3_t vel,float die,int color,float alpha,float ramp)73 particle_new (ptype_t type, int texnum, const vec3_t org, float scale,
74 			  const vec3_t vel, float die, int color, float alpha, float ramp)
75 {
76 	particle_t *part;
77 
78 /*
79 	// Uncomment this for particle debugging!
80 	if (numparticles >= r_maxparticles) {
81 		Sys_Error  ("FAILED PARTICLE ALLOC!");
82 		return NULL;
83 	}
84 */
85 
86 	part = &particles[numparticles++];
87 
88 	VectorCopy (org, part->org);
89 	part->color = color;
90 	part->tex = texnum;
91 	part->scale = scale;
92 	part->alpha = alpha;
93 	VectorCopy (vel, part->vel);
94 	part->type = type;
95 	part->die = die;
96 	part->ramp = ramp;
97 	part->phys = R_ParticlePhysics (type);
98 }
99 
100 /*
101 	particle_new_random
102 
103 	note that org_fuzz & vel_fuzz should be ints greater than 0 if you are
104 	going to bother using this function.
105 */
106 inline static void
particle_new_random(ptype_t type,int texnum,const vec3_t org,int org_fuzz,float scale,int vel_fuzz,float die,int color,float alpha,float ramp)107 particle_new_random (ptype_t type, int texnum, const vec3_t org, int org_fuzz,
108 					 float scale, int vel_fuzz, float die, int color,
109 					 float alpha, float ramp)
110 {
111 	float		o_fuzz = org_fuzz, v_fuzz = vel_fuzz;
112 	int         rnd;
113 	vec3_t      porg, pvel;
114 
115 	rnd = mtwist_rand (&mt);
116 	porg[0] = o_fuzz * ((rnd & 63) - 31.5) / 63.0 + org[0];
117 	porg[1] = o_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0 + org[1];
118 	porg[2] = o_fuzz * (((rnd >> 10) & 63) - 31.5) / 63.0 + org[2];
119 	rnd = mtwist_rand (&mt);
120 	pvel[0] = v_fuzz * ((rnd & 63) - 31.5) / 63.0;
121 	pvel[1] = v_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0;
122 	pvel[2] = v_fuzz * (((rnd >> 10) & 63) - 31.5) / 63.0;
123 
124 	particle_new (type, texnum, porg, scale, pvel, die, color, alpha, ramp);
125 }
126 
127 /*
128 inline static void
129 particle_new_veryrandom (ptype_t type, int texnum, const vec3_t org,
130 						 int org_fuzz, float scale, int vel_fuzz, float die,
131 						 int color, float alpha, float ramp)
132 {
133 	vec3_t		porg, pvel;
134 
135 	porg[0] = qfrandom (org_fuzz * 2) - org_fuzz + org[0];
136 	porg[1] = qfrandom (org_fuzz * 2) - org_fuzz + org[1];
137 	porg[2] = qfrandom (org_fuzz * 2) - org_fuzz + org[2];
138 	pvel[0] = qfrandom (vel_fuzz * 2) - vel_fuzz;
139 	pvel[1] = qfrandom (vel_fuzz * 2) - vel_fuzz;
140 	pvel[2] = qfrandom (vel_fuzz * 2) - vel_fuzz;
141 	particle_new (type, texnum, porg, scale, pvel, die, color, alpha, ramp);
142 }
143 */
144 
145 void
gl_R_ClearParticles(void)146 gl_R_ClearParticles (void)
147 {
148 	numparticles = 0;
149 }
150 
151 void
gl_R_InitParticles(void)152 gl_R_InitParticles (void)
153 {
154 	int		i;
155 
156 	mtwist_seed (&mt, 0xdeadbeef);
157 
158 	if (r_maxparticles && r_init) {
159 		if (vaelements) {
160 			partUseVA = 0;
161 			pVAsize = r_maxparticles * 4;
162 			Sys_MaskPrintf (SYS_DEV,
163 							"Particles: Vertex Array use disabled.\n");
164 		} else {
165 			if (vaelements > 3)
166 				pVAsize = min ((unsigned int) (vaelements - (vaelements % 4)),
167 							   r_maxparticles * 4);
168 			else if (vaelements >= 0)
169 				pVAsize = r_maxparticles * 4;
170 			Sys_MaskPrintf (SYS_DEV,
171 							"Particles: %i maximum vertex elements.\n",
172 							pVAsize);
173 		}
174 		if (particleVertexArray)
175 			free (particleVertexArray);
176 		particleVertexArray = (varray_t2f_c4ub_v3f_t *)
177 			calloc (pVAsize, sizeof (varray_t2f_c4ub_v3f_t));
178 
179 		if (partUseVA)
180 			qfglInterleavedArrays (GL_T2F_C4UB_V3F, 0, particleVertexArray);
181 
182 		if (pVAindices)
183 			free (pVAindices);
184 		pVAindices = (int *) calloc (pVAsize, sizeof (int));
185 		for (i = 0; i < pVAsize; i++)
186 			pVAindices[i] = i;
187 	} else {
188 		if (particleVertexArray) {
189 			free (particleVertexArray);
190 			particleVertexArray = 0;
191 		}
192 		if (pVAindices) {
193 			free (pVAindices);
194 			pVAindices = 0;
195 		}
196 	}
197 }
198 
199 void
gl_R_ReadPointFile_f(void)200 gl_R_ReadPointFile_f (void)
201 {
202 	const char *name;
203 	char       *mapname;
204 	int         c, r;
205 	vec3_t      org;
206 	QFile      *f;
207 
208 	mapname = strdup (r_worldentity.model->name);
209 	if (!mapname)
210 		Sys_Error ("Can't duplicate mapname!");
211 	QFS_StripExtension (mapname, mapname);
212 
213 	name = va ("%s.pts", mapname);
214 	free (mapname);
215 
216 	QFS_FOpenFile (name, &f);
217 	if (!f) {
218 		Sys_Printf ("couldn't open %s\n", name);
219 		return;
220 	}
221 
222 	Sys_MaskPrintf (SYS_DEV, "Reading %s...\n", name);
223 	c = 0;
224 	for (;;) {
225 		char        buf[64];
226 
227 		Qgets (f, buf, sizeof (buf));
228 		r = sscanf (buf, "%f %f %f\n", &org[0], &org[1], &org[2]);
229 		if (r != 3)
230 			break;
231 		c++;
232 
233 		if (numparticles >= r_maxparticles) {
234 			Sys_MaskPrintf (SYS_DEV, "Not enough free particles\n");
235 			break;
236 		} else {
237 			particle_new (pt_static, part_tex_dot, org, 1.5, vec3_origin,
238 						  99999, (-c) & 15, 1.0, 0.0);
239 		}
240 	}
241 	Qclose (f);
242 	Sys_MaskPrintf (SYS_DEV, "%i points read\n", c);
243 }
244 
245 static void
R_ParticleExplosion_QF(const vec3_t org)246 R_ParticleExplosion_QF (const vec3_t org)
247 {
248 //	R_NewExplosion (org);
249 	if (numparticles >= r_maxparticles)
250 		return;
251 	particle_new_random (pt_smokecloud, part_tex_smoke, org, 4, 30, 8,
252 						 vr_data.realtime + 5.0, (mtwist_rand (&mt) & 7) + 8,
253 						 0.5 + qfrandom (0.25), 0.0);
254 }
255 
256 static void
R_ParticleExplosion2_QF(const vec3_t org,int colorStart,int colorLength)257 R_ParticleExplosion2_QF (const vec3_t org, int colorStart, int colorLength)
258 {
259 	unsigned int	i, j = 512;
260 
261 	if (numparticles >= r_maxparticles)
262 		return;
263 	else if (numparticles + j >= r_maxparticles)
264 		j = r_maxparticles - numparticles;
265 
266 	for (i = 0; i < j; i++) {
267 		particle_new_random (pt_blob, part_tex_dot, org, 16, 2, 256,
268 							 vr_data.realtime + 0.3,
269 							 								 colorStart + (i % colorLength), 1.0, 0.0);
270 	}
271 }
272 
273 static void
R_BlobExplosion_QF(const vec3_t org)274 R_BlobExplosion_QF (const vec3_t org)
275 {
276 	unsigned int	i;
277 	unsigned int	j = 1024;
278 
279 	if (numparticles >= r_maxparticles)
280 		return;
281 	else if (numparticles + j >= r_maxparticles)
282 		j = r_maxparticles - numparticles;
283 
284 	for (i = 0; i < j >> 1; i++) {
285 		particle_new_random (pt_blob, part_tex_dot, org, 12, 2, 256,
286 							 vr_data.realtime + 1.0 + (mtwist_rand (&mt) & 7) * 0.05,
287 							 66 + i % 6, 1.0, 0.0);
288 	}
289 	for (i = 0; i < j / 2; i++) {
290 		particle_new_random (pt_blob2, part_tex_dot, org, 12, 2, 256,
291 							 vr_data.realtime + 1.0 + (mtwist_rand (&mt) & 7) * 0.05,
292 							 150 + i % 6, 1.0, 0.0);
293 	}
294 }
295 
296 static inline void
R_RunSparkEffect_QF(const vec3_t org,int count,int ofuzz)297 R_RunSparkEffect_QF (const vec3_t org, int count, int ofuzz)
298 {
299 	if (numparticles >= r_maxparticles)
300 		return;
301 	particle_new (pt_smokecloud, part_tex_smoke, org, ofuzz * 0.08,
302 				  vec3_origin, vr_data.realtime + 9, 12 + (mtwist_rand (&mt) & 3),
303 				  0.25 + qfrandom (0.125), 0.0);
304 
305 	if (numparticles + count >= r_maxparticles)
306 		count = r_maxparticles - numparticles;
307 	if (count) {
308 		int orgfuzz = ofuzz * 3 / 4;
309 		if (orgfuzz < 1)
310 			orgfuzz = 1;
311 
312 		while (count--) {
313 			int		color = mtwist_rand (&mt) & 7;
314 
315 			particle_new_random (pt_fallfadespark, part_tex_dot, org, orgfuzz,
316 								 0.7, 96, vr_data.realtime + 5.0, ramp1[color],
317 								 1.0, color);
318 		}
319 	}
320 }
321 
322 static inline void
R_BloodPuff_QF(const vec3_t org,int count)323 R_BloodPuff_QF (const vec3_t org, int count)
324 {
325 	if (numparticles >= r_maxparticles)
326 		return;
327 
328 	particle_new (pt_bloodcloud, part_tex_smoke, org, count / 5, vec3_origin,
329 				  vr_data.realtime + 99.0, 70 + (mtwist_rand (&mt) & 3), 0.5, 0.0);
330 }
331 
332 static void
R_BloodPuffEffect_QF(const vec3_t org,int count)333 R_BloodPuffEffect_QF (const vec3_t org, int count)
334 {
335 	R_BloodPuff_QF (org, count);
336 }
337 
338 static void
R_GunshotEffect_QF(const vec3_t org,int count)339 R_GunshotEffect_QF (const vec3_t org, int count)
340 {
341 	int scale = 16;
342 
343 	scale += count / 15;
344 	R_RunSparkEffect_QF (org, count >> 1, scale);
345 }
346 
347 static void
R_LightningBloodEffect_QF(const vec3_t org)348 R_LightningBloodEffect_QF (const vec3_t org)
349 {
350 	int		count = 7;
351 
352 	R_BloodPuff_QF (org, 50);
353 
354 	if (numparticles >= r_maxparticles)
355 		return;
356 	particle_new (pt_smokecloud, part_tex_smoke, org, 3.0, vec3_origin,
357 				  vr_data.realtime + 9.0, 12 + (mtwist_rand (&mt) & 3),
358 				  0.25 + qfrandom (0.125), 0.0);
359 
360 	if (numparticles + count >= r_maxparticles)
361 		count = r_maxparticles - numparticles;
362 	while (count--)
363 		particle_new_random (pt_fallfade, part_tex_spark, org, 12, 2.0, 128,
364 							 vr_data.realtime + 5.0, 244 + (count % 3), 1.0,
365 							 0.0);
366 }
367 
368 static void
R_RunParticleEffect_QF(const vec3_t org,const vec3_t dir,int color,int count)369 R_RunParticleEffect_QF (const vec3_t org, const vec3_t dir, int color,
370 						int count)
371 {
372 	float       scale;
373 	int         i;
374 	vec3_t      porg;
375 
376 	if (numparticles >= r_maxparticles)
377 		return;
378 
379 	scale = pow (count, 0.23); // calculate scale before clipping to part. max
380 
381 	if (numparticles + count >= r_maxparticles)
382 		count = r_maxparticles - numparticles;
383 
384 	for (i = 0; i < count; i++) {
385 		int 	rnd = mtwist_rand (&mt);
386 
387 		porg[0] = org[0] + scale * (((rnd >> 3) & 15) - 7.5);
388 		porg[1] = org[1] + scale * (((rnd >> 7) & 15) - 7.5);
389 		porg[2] = org[2] + scale * (((rnd >> 11) & 15) - 7.5);
390 		// Note that ParseParticleEffect handles (dir * 15)
391 		particle_new (pt_grav, part_tex_dot, porg, 1.5, dir,
392 					  vr_data.realtime + 0.1 * (i % 5),
393 					  (color & ~7) + (rnd & 7), 1.0, 0.0);
394 	}
395 }
396 
397 static void
R_SpikeEffect_QF(const vec3_t org)398 R_SpikeEffect_QF (const vec3_t org)
399 {
400 	R_RunSparkEffect_QF (org, 5, 8);
401 }
402 
403 static void
R_SuperSpikeEffect_QF(const vec3_t org)404 R_SuperSpikeEffect_QF (const vec3_t org)
405 {
406 	R_RunSparkEffect_QF (org, 10, 8);
407 }
408 
409 static void
R_KnightSpikeEffect_QF(const vec3_t org)410 R_KnightSpikeEffect_QF (const vec3_t org)
411 {
412 	unsigned int	count = 10;
413 
414 	if (numparticles >= r_maxparticles)
415 		return;
416 	particle_new (pt_smokecloud, part_tex_smoke, org, 1.0, vec3_origin,
417 				  vr_data.realtime + 9.0, 234, 0.25 + qfrandom (0.125), 0.0);
418 
419 	if (numparticles + count >= r_maxparticles)
420 		count = r_maxparticles - numparticles;
421 	while (count--)
422 		particle_new_random (pt_fallfade, part_tex_dot, org, 6, 0.7, 96,
423 							 vr_data.realtime + 5.0, 234, 1.0, 0.0);
424 }
425 
426 static void
R_WizSpikeEffect_QF(const vec3_t org)427 R_WizSpikeEffect_QF (const vec3_t org)
428 {
429 	unsigned int	count = 15;
430 
431 	if (numparticles >= r_maxparticles)
432 		return;
433 	particle_new (pt_smokecloud, part_tex_smoke, org, 2.0, vec3_origin,
434 				  vr_data.realtime + 9.0, 63, 0.25 + qfrandom (0.125), 0.0);
435 
436 	if (numparticles + count >= r_maxparticles)
437 		count = r_maxparticles - numparticles;
438 	while (count--)
439 		particle_new_random (pt_fallfade, part_tex_dot, org, 12, 0.7, 96,
440 							 vr_data.realtime + 5.0, 63, 1.0, 0.0);
441 }
442 
443 static void
R_LavaSplash_QF(const vec3_t org)444 R_LavaSplash_QF (const vec3_t org)
445 {
446 	float       vel;
447 	int         rnd, i, j;
448 	int			k = 256;
449 	vec3_t      dir, porg, pvel;
450 
451 	if (numparticles + k >= r_maxparticles) {
452 		return;
453 	} // else if (numparticles + k >= r_maxparticles) {
454 //		k = r_maxparticles - numparticles;
455 //	}
456 
457 	dir[2] = 256;
458 	for (i = -128; i < 128; i += 16) {
459 		for (j = -128; j < 128; j += 16) {
460 			rnd = mtwist_rand (&mt);
461 			dir[0] = j + (rnd & 7);
462 			dir[1] = i + ((rnd >> 6) & 7);
463 
464 			porg[0] = org[0] + dir[0];
465 			porg[1] = org[1] + dir[1];
466 			porg[2] = org[2] + ((rnd >> 9) & 63);
467 
468 			VectorNormalize (dir);
469 			rnd = mtwist_rand (&mt);
470 			vel = 50.0 + 0.5 * (float) (rnd & 127);
471 			VectorScale (dir, vel, pvel);
472 			particle_new (pt_grav, part_tex_dot, porg, 3, pvel,
473 						  vr_data.realtime + 2.0 + ((rnd >> 7) & 31) * 0.02,
474 						  224 + ((rnd >> 12) & 7), 0.75, 0.0);
475 		}
476 	}
477 }
478 
479 static void
R_TeleportSplash_QF(const vec3_t org)480 R_TeleportSplash_QF (const vec3_t org)
481 {
482 	float       vel;
483 	int         rnd, i, j, k;
484 	int			l = 896;
485 	vec3_t      dir, pdir, porg, pvel;
486 
487 	if (numparticles + l >= r_maxparticles) {
488 		return;
489 	} // else if (numparticles + l >= r_maxparticles) {
490 //		l = r_maxparticles - numparticles;
491 //	}
492 
493 	for (k = -24; k < 32; k += 4) {
494 		dir[2] = k * 8;
495 		for (i = -16; i < 16; i += 4) {
496 			dir[1] = i * 8;
497 			for (j = -16; j < 16; j += 4) {
498 				dir[0] = j * 8;
499 
500 				VectorCopy (dir, pdir);
501 				VectorNormalize (pdir);
502 
503 				rnd = mtwist_rand (&mt);
504 				porg[0] = org[0] + i + (rnd & 3);
505 				porg[1] = org[1] + j + ((rnd >> 2) & 3);
506 				porg[2] = org[2] + k + ((rnd >> 4) & 3);
507 
508 				vel = 50 + ((rnd >> 6) & 63);
509 				VectorScale (pdir, vel, pvel);
510 				particle_new (pt_grav, part_tex_spark, porg, 0.6, pvel,
511 							  (vr_data.realtime + 0.2 + (mtwist_rand (&mt) & 15) * 0.01),
512 							  (7 + ((rnd >> 12) & 7)), 1.0, 0.0);
513 			}
514 		}
515 	}
516 }
517 
518 static void
R_RocketTrail_QF(const entity_t * ent)519 R_RocketTrail_QF (const entity_t *ent)
520 {
521 	float		dist, maxlen, origlen, percent, pscale, pscalenext;
522 	float		len = 0.0;
523 	vec3_t		old_origin, vec;
524 
525 	if (numparticles >= r_maxparticles)
526 		return;
527 
528 	VectorCopy (ent->old_origin, old_origin);
529 	VectorSubtract (ent->origin, old_origin, vec);
530 	maxlen = VectorNormalize (vec);
531 	origlen = vr_data.frametime / maxlen;
532 	pscale = 1.5 + qfrandom (1.5);
533 
534 	while (len < maxlen) {
535 		pscalenext = 1.5 + qfrandom (1.5);
536 		dist = (pscale + pscalenext) * 3.0;
537 		percent = len * origlen;
538 
539 		particle_new (pt_smoke, part_tex_smoke, old_origin,
540 					  pscale + percent * 4.0, vec3_origin,
541 					  vr_data.realtime + 2.0 - percent * 2.0,
542 					  12 + (mtwist_rand (&mt) & 3),
543 					  0.5 + qfrandom (0.125) - percent * 0.40, 0.0);
544 		if (numparticles >= r_maxparticles)
545 			break;
546 		len += dist;
547 		VectorMultAdd (old_origin, len, vec, old_origin);
548 		pscale = pscalenext;
549 	}
550 }
551 
552 static void
R_GrenadeTrail_QF(const entity_t * ent)553 R_GrenadeTrail_QF (const entity_t *ent)
554 {
555 	float		dist, maxlen, origlen, percent, pscale, pscalenext;
556 	float		len = 0.0;
557 	vec3_t		old_origin, vec;
558 
559 	if (numparticles >= r_maxparticles)
560 		return;
561 
562 	VectorCopy (ent->old_origin, old_origin);
563 	VectorSubtract (ent->origin, old_origin, vec);
564 	maxlen = VectorNormalize (vec);
565 	origlen = vr_data.frametime / maxlen;
566 	pscale = 6.0 + qfrandom (7.0);
567 
568 	while (len < maxlen) {
569 		pscalenext = 6.0 + qfrandom (7.0);
570 		dist = (pscale + pscalenext) * 2.0;
571 		percent = len * origlen;
572 
573 		particle_new (pt_smoke, part_tex_smoke, old_origin,
574 					  pscale + percent * 4.0, vec3_origin,
575 					  vr_data.realtime + 2.0 - percent * 2.0,
576 					  1 + (mtwist_rand (&mt) & 3),
577 					  0.625 + qfrandom (0.125) - percent * 0.40, 0.0);
578 		if (numparticles >= r_maxparticles)
579 			break;
580 		len += dist;
581 		VectorMultAdd (old_origin, len, vec, old_origin);
582 		pscale = pscalenext;
583 	}
584 }
585 
586 static void
R_BloodTrail_QF(const entity_t * ent)587 R_BloodTrail_QF (const entity_t *ent)
588 {
589 	float		dist, maxlen, origlen, percent, pscale, pscalenext;
590 	float		len = 0.0;
591 	int			j;
592 	vec3_t		old_origin, porg, pvel, vec;
593 
594 	if (numparticles >= r_maxparticles)
595 		return;
596 
597 	VectorCopy (ent->old_origin, old_origin);
598 	VectorSubtract (ent->origin, old_origin, vec);
599 	maxlen = VectorNormalize (vec);
600 	origlen = vr_data.frametime / maxlen;
601 	pscale = 5.0 + qfrandom (10.0);
602 
603 	while (len < maxlen) {
604 		pscalenext = 5.0 + qfrandom (10.0);
605 		dist = (pscale + pscalenext) * 1.5;
606 
607 		for (j = 0; j < 3; j++) {
608 			pvel[j] = qfrandom (24.0) - 12.0;
609 			porg[j] = old_origin[j] + qfrandom (3.0) - 1.5;
610 		}
611 
612 		percent = len * origlen;
613 		pvel[2] -= percent * 40.0;
614 
615 		particle_new (pt_grav, part_tex_smoke, porg, pscale, pvel,
616 					  vr_data.realtime + 2.0 - percent * 2.0,
617 					  68 + (mtwist_rand (&mt) & 3), 1.0, 0.0);
618 		if (numparticles >= r_maxparticles)
619 			break;
620 		len += dist;
621 		VectorMultAdd (old_origin, len, vec, old_origin);
622 		pscale = pscalenext;
623 	}
624 }
625 
626 static void
R_SlightBloodTrail_QF(const entity_t * ent)627 R_SlightBloodTrail_QF (const entity_t *ent)
628 {
629 	float		dist, maxlen, origlen, percent, pscale, pscalenext;
630 	float		len = 0.0;
631 	int			j;
632 	vec3_t      old_origin, porg, pvel, vec;
633 
634 	if (numparticles >= r_maxparticles)
635 		return;
636 
637 	VectorCopy (ent->old_origin, old_origin);
638 	VectorSubtract (ent->origin, old_origin, vec);
639 	maxlen = VectorNormalize (vec);
640 	origlen = vr_data.frametime / maxlen;
641 	pscale = 1.5 + qfrandom (7.5);
642 
643 	while (len < maxlen) {
644 		pscalenext = 1.5 + qfrandom (7.5);
645 		dist = (pscale + pscalenext) * 1.5;
646 
647 		for (j = 0; j < 3; j++) {
648 			pvel[j] = (qfrandom (12.0) - 6.0);
649 			porg[j] = old_origin[j] + qfrandom (3.0) - 1.5;
650 		}
651 
652 		percent = len * origlen;
653 		pvel[2] -= percent * 40;
654 
655 		particle_new (pt_grav, part_tex_smoke, porg, pscale, pvel,
656 					  vr_data.realtime + 1.5 - percent * 1.5,
657 					  68 + (mtwist_rand (&mt) & 3), 0.75, 0.0);
658 		if (numparticles >= r_maxparticles)
659 			break;
660 		len += dist;
661 		VectorMultAdd (old_origin, len, vec, old_origin);
662 		pscale = pscalenext;
663 	}
664 }
665 
666 static void
R_WizTrail_QF(const entity_t * ent)667 R_WizTrail_QF (const entity_t *ent)
668 {
669 	float		maxlen, origlen, percent;
670 	float		dist = 3.0, len = 0.0;
671 	static int	tracercount;
672 	vec3_t		old_origin, pvel, subtract, vec;
673 
674 	if (numparticles >= r_maxparticles)
675 		return;
676 
677 	VectorCopy (ent->old_origin, old_origin);
678 	VectorSubtract (ent->origin, old_origin, vec);
679 	maxlen = VectorNormalize (vec);
680 	origlen = vr_data.frametime / maxlen;
681 	VectorScale (vec, maxlen - dist, subtract);
682 
683 	while (len < maxlen) {
684 		percent = len * origlen;
685 
686 		tracercount++;
687 		if (tracercount & 1) {
688 			pvel[0] = 30.0 * vec[1];
689 			pvel[1] = 30.0 * -vec[0];
690 		} else {
691 			pvel[0] = 30.0 * -vec[1];
692 			pvel[1] = 30.0 * vec[0];
693 		}
694 		pvel[2] = 0.0;
695 
696 		particle_new (pt_flame, part_tex_smoke, old_origin,
697 					  2.0 + qfrandom (1.0) - percent * 2.0, pvel,
698 					  vr_data.realtime + 0.5 - percent * 0.5,
699 					  52 + (mtwist_rand (&mt) & 4), 1.0 - percent * 0.125, 0.0);
700 		if (numparticles >= r_maxparticles)
701 			break;
702 		len += dist;
703 		VectorAdd (old_origin, subtract, old_origin);
704 	}
705 }
706 
707 static void
R_FlameTrail_QF(const entity_t * ent)708 R_FlameTrail_QF (const entity_t *ent)
709 {
710 	float		maxlen, origlen, percent;
711 	float		dist = 3.0, len = 0.0;
712 	static int	tracercount;
713 	vec3_t		old_origin, pvel, subtract, vec;
714 
715 	if (numparticles >= r_maxparticles)
716 		return;
717 
718 	VectorCopy (ent->old_origin, old_origin);
719 	VectorSubtract (ent->origin, old_origin, vec);
720 	maxlen = VectorNormalize (vec);
721 	origlen = vr_data.frametime / maxlen;
722 	VectorScale (vec, maxlen - dist, subtract);
723 
724 	while (len < maxlen) {
725 		percent = len * origlen;
726 
727 		tracercount++;
728 		if (tracercount & 1) {
729 			pvel[0] = 30.0 * vec[1];
730 			pvel[1] = 30.0 * -vec[0];
731 		} else {
732 			pvel[0] = 30.0 * -vec[1];
733 			pvel[1] = 30.0 * vec[0];
734 		}
735 		pvel[2] = 0.0;
736 
737 		particle_new (pt_flame, part_tex_smoke, old_origin,
738 					  2.0 + qfrandom (1.0) - percent * 2.0, pvel,
739 					  vr_data.realtime + 0.5 - percent * 0.5, 234,
740 					  1.0 - percent * 0.125, 0.0);
741 		if (numparticles >= r_maxparticles)
742 			break;
743 		len += dist;
744 		VectorAdd (old_origin, subtract, old_origin);
745 	}
746 }
747 
748 static void
R_VoorTrail_QF(const entity_t * ent)749 R_VoorTrail_QF (const entity_t *ent)
750 {
751 	float		maxlen, origlen, percent;
752 	float		dist = 3.0, len = 0.0;
753 	int			j;
754 	vec3_t		subtract, old_origin, porg, vec;
755 
756 	if (numparticles >= r_maxparticles)
757 		return;
758 
759 	VectorCopy (ent->old_origin, old_origin);
760 	VectorSubtract (ent->origin, old_origin, vec);
761 	maxlen = VectorNormalize (vec);
762 	origlen = vr_data.frametime / maxlen;
763 	VectorScale (vec, maxlen - dist, subtract);
764 
765 	while (len < maxlen) {
766 		percent = len * origlen;
767 
768 		for (j = 0; j < 3; j++)
769 			porg[j] = old_origin[j] + qfrandom (16.0) - 8.0;
770 
771 		particle_new (pt_static, part_tex_dot, porg, 1.0 + qfrandom (1.0),
772 					  vec3_origin, vr_data.realtime + 0.3 - percent * 0.3,
773 					  9 * 16 + 8 + (mtwist_rand (&mt) & 3), 1.0, 0.0);
774 		if (numparticles >= r_maxparticles)
775 			break;
776 		len += dist;
777 		VectorAdd (old_origin, subtract, old_origin);
778 	}
779 }
780 
781 static void
R_GlowTrail_QF(const entity_t * ent,int glow_color)782 R_GlowTrail_QF (const entity_t *ent, int glow_color)
783 {
784 	float		maxlen, origlen, percent;
785 	float		dist = 3.0, len = 0.0;
786 	int			rnd;
787 	vec3_t		old_origin, org, subtract, vec;
788 
789 	if (numparticles >= r_maxparticles)
790 		return;
791 
792 	VectorCopy (ent->old_origin, old_origin);
793 	VectorSubtract (ent->origin, old_origin, vec);
794 	maxlen = VectorNormalize (vec);
795 	origlen = vr_data.frametime / maxlen;
796 	VectorScale (vec, (maxlen - dist), subtract);
797 
798 	while (len < maxlen) {
799 		percent = len * origlen;
800 
801 		rnd = mtwist_rand (&mt);
802 		org[0] = old_origin[0] + ((rnd >> 12) & 7) * (5.0/7.0) - 2.5;
803 		org[1] = old_origin[1] + ((rnd >> 9) & 7) * (5.0/7.0) - 2.5;
804 		org[2] = old_origin[2] + ((rnd >> 6) & 7) * (5.0/7.0) - 2.5;
805 
806 		particle_new (pt_smoke, part_tex_dot, org, 1.0, vec3_origin,
807 					  vr_data.realtime + 2.0 - percent * 0.2,
808 					  glow_color, 1.0, 0.0);
809 		if (numparticles >= r_maxparticles)
810 			break;
811 		len += dist;
812 		VectorAdd (old_origin, subtract, old_origin);
813 	}
814 }
815 
816 static void
R_ParticleExplosion_EE(const vec3_t org)817 R_ParticleExplosion_EE (const vec3_t org)
818 {
819 /*
820 	R_NewExplosion (org);
821 */
822 	if (numparticles >= r_maxparticles)
823 		return;
824 	particle_new_random (pt_smokecloud, part_tex_smoke, org, 4, 30, 8,
825 						 vr_data.realtime + 5.0, mtwist_rand (&mt) & 255,
826 						 0.5 + qfrandom (0.25), 0.0);
827 }
828 
829 static void
R_TeleportSplash_EE(const vec3_t org)830 R_TeleportSplash_EE (const vec3_t org)
831 {
832 	float       vel;
833 	int         rnd, i, j, k;
834 	int			l = 896;
835 	vec3_t      dir, porg, pvel;
836 
837 	if (numparticles + l >= r_maxparticles) {
838 		return;
839 	} // else if (numparticles + l >= r_maxparticles) {
840 //		l = r_maxparticles - numparticles;
841 //	}
842 
843 	for (k = -24; k < 32; k += 4) {
844 		dir[2] = k * 8;
845 		for (i = -16; i < 16; i += 4) {
846 			dir[1] = i * 8;
847 			for (j = -16; j < 16; j += 4) {
848 				dir[0] = j * 8;
849 
850 				rnd = mtwist_rand (&mt);
851 				porg[0] = org[0] + i + (rnd & 3);
852 				porg[1] = org[1] + j + ((rnd >> 2) & 3);
853 				porg[2] = org[2] + k + ((rnd >> 4) & 3);
854 
855 				VectorNormalize (dir);
856 				vel = 50 + ((rnd >> 6) & 63);
857 				VectorScale (dir, vel, pvel);
858 				particle_new (pt_grav, part_tex_spark, porg, 0.6, pvel,
859 							  (vr_data.realtime + 0.2 + (mtwist_rand (&mt) & 15) * 0.01),
860 							  qfrandom (1.0), 1.0, 0.0);
861 			}
862 		}
863 	}
864 }
865 
866 static void
R_RocketTrail_EE(const entity_t * ent)867 R_RocketTrail_EE (const entity_t *ent)
868 {
869 	float		dist, maxlen, origlen, percent, pscale, pscalenext;
870 	float		len = 0.0;
871 	vec3_t		old_origin, subtract, vec;
872 
873 	if (numparticles >= r_maxparticles)
874 		return;
875 
876 	VectorCopy (ent->old_origin, old_origin);
877 	VectorSubtract (ent->origin, old_origin, vec);
878 	maxlen = VectorNormalize (vec);
879 	origlen = vr_data.frametime / maxlen;
880 	pscale = 1.5 + qfrandom (1.5);
881 
882 	while (len < maxlen) {
883 		pscalenext = 1.5 + qfrandom (1.5);
884 		dist = (pscale + pscalenext) * 3.0;
885 		percent = len * origlen;
886 
887 		particle_new (pt_smoke, part_tex_smoke, old_origin,
888 					  pscale + percent * 4.0, vec3_origin,
889 					  vr_data.realtime + 2.0 - percent * 2.0,
890 					  mtwist_rand (&mt) & 255,
891 					  0.5 + qfrandom (0.125) - percent * 0.40, 0.0);
892 		if (numparticles >= r_maxparticles)
893 			break;
894 		len += dist;
895 		VectorScale (vec, len, subtract);
896 		VectorAdd (old_origin, subtract, old_origin);
897 		pscale = pscalenext;
898 	}
899 }
900 
901 static void
R_GrenadeTrail_EE(const entity_t * ent)902 R_GrenadeTrail_EE (const entity_t *ent)
903 {
904 	float		dist, maxlen, origlen, percent, pscale, pscalenext;
905 	float		len = 0.0;
906 	vec3_t		old_origin, subtract, vec;
907 
908 	if (numparticles >= r_maxparticles)
909 		return;
910 
911 	VectorCopy (ent->old_origin, old_origin);
912 	VectorSubtract (ent->origin, ent->old_origin, vec);
913 	maxlen = VectorNormalize (vec);
914 	origlen = vr_data.frametime / maxlen;
915 	pscale = 6.0 + qfrandom (7.0);
916 
917 	while (len < maxlen) {
918 		pscalenext = 6.0 + qfrandom (7.0);
919 		dist = (pscale + pscalenext) * 2.0;
920 		percent = len * origlen;
921 
922 		particle_new (pt_smoke, part_tex_smoke, old_origin,
923 					  pscale + percent * 4.0, vec3_origin,
924 					  vr_data.realtime + 2.0 - percent * 2.0,
925 					  mtwist_rand (&mt) & 255,
926 					  0.625 + qfrandom (0.125) - percent * 0.40, 0.0);
927 		if (numparticles >= r_maxparticles)
928 			break;
929 		len += dist;
930 		VectorScale (vec, len, subtract);
931 		VectorAdd (old_origin, subtract, old_origin);
932 		pscale = pscalenext;
933 	}
934 }
935 
936 static void
R_ParticleExplosion_ID(const vec3_t org)937 R_ParticleExplosion_ID (const vec3_t org)
938 {
939 	unsigned int	i;
940 	unsigned int	j = 1024;
941 
942 	if (numparticles >= r_maxparticles)
943 		return;
944 	else if (numparticles + j >= r_maxparticles)
945 		j = r_maxparticles - numparticles;
946 
947 	for (i = 0; i < j >> 1; i++) {
948 		particle_new_random (pt_explode, part_tex_dot, org, 16, 1.0, 256,
949 							 vr_data.realtime + 5.0, ramp1[0], 1.0, i & 3);
950 	}
951 	for (i = 0; i < j / 2; i++) {
952 		particle_new_random (pt_explode2, part_tex_dot, org, 16, 1.0, 256,
953                              vr_data.realtime + 5.0, ramp1[0], 1.0, i & 3);
954 	}
955 }
956 
957 static void
R_BlobExplosion_ID(const vec3_t org)958 R_BlobExplosion_ID (const vec3_t org)
959 {
960 	unsigned int	i;
961 	unsigned int	j = 1024;
962 
963 	if (numparticles >= r_maxparticles)
964 		return;
965 	else if (numparticles + j >= r_maxparticles)
966 		j = r_maxparticles - numparticles;
967 
968 	for (i = 0; i < j >> 1; i++) {
969 		particle_new_random (pt_blob, part_tex_dot, org, 12, 1.0, 256,
970 							 vr_data.realtime + 1.0 + (mtwist_rand (&mt) & 8) * 0.05,
971 							 66 + i % 6, 1.0, 0.0);
972 	}
973 	for (i = 0; i < j / 2; i++) {
974 		particle_new_random (pt_blob2, part_tex_dot, org, 12, 1.0, 256,
975 							 vr_data.realtime + 1.0 + (mtwist_rand (&mt) & 8) * 0.05,
976 							 150 + i % 6, 1.0, 0.0);
977 	}
978 }
979 
980 static inline void		// FIXME: inline?
R_RunParticleEffect_ID(const vec3_t org,const vec3_t dir,int color,int count)981 R_RunParticleEffect_ID (const vec3_t org, const vec3_t dir, int color,
982 						int count)
983 {
984 	float			scale;
985 	int             i;
986 	vec3_t			porg;
987 
988 	if (numparticles >= r_maxparticles)
989 		return;
990 
991 	if (count > 130) // calculate scale before clipping to particle max
992 		scale = 3.0;
993 	else if (count > 20)
994 		scale = 2.0;
995 	else
996 		scale = 1.0;
997 
998 	if (numparticles + count >= r_maxparticles)
999 		count = r_maxparticles - numparticles;
1000 
1001 	for (i = 0; i < count; i++) {
1002 		int rnd = mtwist_rand (&mt);
1003 
1004 		porg[0] = org[0] + scale * (((rnd >> 3) & 15) - 8);
1005 		porg[1] = org[1] + scale * (((rnd >> 7) & 15) - 8);
1006 		porg[2] = org[2] + scale * (((rnd >> 11) & 15) - 8);
1007 
1008 		// Note that ParseParticleEffect handles (dir * 15)
1009 		particle_new (pt_grav, part_tex_dot, porg, 1.0, dir,
1010 					  vr_data.realtime + 0.1 * (i % 5),
1011 					  (color & ~7) + (rnd & 7), 1.0, 0.0);
1012 	}
1013 }
1014 
1015 static void
R_BloodPuffEffect_ID(const vec3_t org,int count)1016 R_BloodPuffEffect_ID (const vec3_t org, int count)
1017 {
1018 	R_RunParticleEffect_ID (org, vec3_origin, 73, count);
1019 }
1020 
1021 static void
R_GunshotEffect_ID(const vec3_t org,int count)1022 R_GunshotEffect_ID (const vec3_t org, int count)
1023 {
1024 	R_RunParticleEffect_ID (org, vec3_origin, 0, count);
1025 }
1026 
1027 static void
R_LightningBloodEffect_ID(const vec3_t org)1028 R_LightningBloodEffect_ID (const vec3_t org)
1029 {
1030 	R_RunParticleEffect_ID (org, vec3_origin, 225, 50);
1031 }
1032 
1033 static void
R_SpikeEffect_ID(const vec3_t org)1034 R_SpikeEffect_ID (const vec3_t org)
1035 {
1036 	R_RunParticleEffect_ID (org, vec3_origin, 0, 10);
1037 }
1038 
1039 static void
R_SuperSpikeEffect_ID(const vec3_t org)1040 R_SuperSpikeEffect_ID (const vec3_t org)
1041 {
1042 	R_RunParticleEffect_ID (org, vec3_origin, 0, 20);
1043 }
1044 
1045 static void
R_KnightSpikeEffect_ID(const vec3_t org)1046 R_KnightSpikeEffect_ID (const vec3_t org)
1047 {
1048 	R_RunParticleEffect_ID (org, vec3_origin, 226, 20);
1049 }
1050 
1051 static void
R_WizSpikeEffect_ID(const vec3_t org)1052 R_WizSpikeEffect_ID (const vec3_t org)
1053 {
1054 	R_RunParticleEffect_ID (org, vec3_origin, 20, 30);
1055 }
1056 
1057 static void
R_LavaSplash_ID(const vec3_t org)1058 R_LavaSplash_ID (const vec3_t org)
1059 {
1060 	float       vel;
1061 	int         rnd, i, j;
1062 	int			k = 256;
1063 	vec3_t      dir, porg, pvel;
1064 
1065 	if (numparticles + k >= r_maxparticles) {
1066 		return;
1067 	} // else if (numparticles + k >= r_maxparticles) {
1068 //		k = r_maxparticles - numparticles;
1069 //	}
1070 
1071 	dir[2] = 256;
1072 	for (i = -128; i < 128; i += 16) {
1073 		for (j = -128; j < 128; j += 16) {
1074 			rnd = mtwist_rand (&mt);
1075 			dir[0] = j + (rnd & 7);
1076 			dir[1] = i + ((rnd >> 6) & 7);
1077 
1078 			porg[0] = org[0] + dir[0];
1079 			porg[1] = org[1] + dir[1];
1080 			porg[2] = org[2] + ((rnd >> 9) & 63);
1081 
1082 			VectorNormalize (dir);
1083 			rnd = mtwist_rand (&mt);
1084 			vel = 50 + (rnd & 63);
1085 			VectorScale (dir, vel, pvel);
1086 			particle_new (pt_grav, part_tex_dot, porg, 1.0, pvel,
1087 						  vr_data.realtime + 2 + ((rnd >> 7) & 31) * 0.02,
1088 						  224 + ((rnd >> 12) & 7), 1.0, 0.0);
1089 		}
1090 	}
1091 }
1092 
1093 static void
R_TeleportSplash_ID(const vec3_t org)1094 R_TeleportSplash_ID (const vec3_t org)
1095 {
1096 	float       vel;
1097 	int         rnd, i, j, k;
1098 	int			l = 896;
1099 	vec3_t      dir, pdir, porg, pvel;
1100 
1101 	if (numparticles + l >= r_maxparticles) {
1102 		return;
1103 	} // else if (numparticles + l >= r_maxparticles) {
1104 //		l = r_maxparticles - numparticles;
1105 //	}
1106 
1107 	for (k = -24; k < 32; k += 4) {
1108 		dir[2] = k * 8;
1109 		for (i = -16; i < 16; i += 4) {
1110 			dir[1] = i * 8;
1111 			for (j = -16; j < 16; j += 4) {
1112 				dir[0] = j * 8;
1113 
1114 				VectorCopy (dir, pdir);
1115 				VectorNormalize (pdir);
1116 
1117 				rnd = mtwist_rand (&mt);
1118 				porg[0] = org[0] + i + (rnd & 3);
1119 				porg[1] = org[1] + j + ((rnd >> 2) & 3);
1120 				porg[2] = org[2] + k + ((rnd >> 4) & 3);
1121 
1122 				vel = 50 + ((rnd >> 6) & 63);
1123 				VectorScale (pdir, vel, pvel);
1124 				particle_new (pt_grav, part_tex_dot, porg, 1.0, pvel,
1125 							  (vr_data.realtime + 0.2 + (mtwist_rand (&mt) & 7) * 0.02),
1126 							  (7 + ((rnd >> 12) & 7)), 1.0, 0.0);
1127 			}
1128 		}
1129 	}
1130 }
1131 
1132 static void
R_DarkFieldParticles_ID(const entity_t * ent)1133 R_DarkFieldParticles_ID (const entity_t *ent)
1134 {
1135 	int				i, j, k, l = 64;
1136 	unsigned int	rnd;
1137 	float			vel;
1138 	vec3_t			dir, org, porg, pvel;
1139 
1140 	if (numparticles + l >= r_maxparticles) {
1141 		return;
1142 	} // else if (numparticles + l >= r_maxparticles) {
1143 //		l = r_maxparticles - numparticles;
1144 //	}
1145 
1146 	VectorCopy (ent->origin, org);
1147 
1148 	for (i = -16; i < 16; i += 8) {
1149 		dir [1] = i * 8;
1150 		for (j = -16; j < 16; j += 8) {
1151 			dir [0] = j * 8;
1152 			for (k = 0; k < 32; k += 8) {
1153 				dir [2] = k * 8;
1154 				rnd = mtwist_rand (&mt);
1155 
1156 				porg[0] = org[0] + i + ((rnd >> 3) & 3);
1157 				porg[1] = org[1] + j + ((rnd >> 5) & 3);
1158 				porg[2] = org[2] + k + ((rnd >> 7) & 3);
1159 
1160 				VectorNormalize (dir);
1161 				vel = 50 + ((rnd >> 9) & 63);
1162 				VectorScale (dir, vel, pvel);
1163 				particle_new (pt_slowgrav, part_tex_dot, porg, 1.5, pvel,
1164 							  (vr_data.realtime + 0.2 + (rnd & 7) * 0.02),
1165 							  (150 + mtwist_rand (&mt) % 6), 1.0, 0.0);
1166             }
1167 		}
1168 	}
1169 }
1170 
1171 static vec3_t		avelocities[NUMVERTEXNORMALS];
1172 
1173 static void
R_EntityParticles_ID(const entity_t * ent)1174 R_EntityParticles_ID (const entity_t *ent)
1175 {
1176 	int         i, j = NUMVERTEXNORMALS;
1177 	float       angle, sp, sy, cp, cy; // cr, sr
1178 	float       beamlength = 16.0, dist = 64.0;
1179 	vec3_t      forward, porg;
1180 
1181 	if (numparticles + j >= r_maxparticles) {
1182 		return;
1183 	} else if (numparticles + j >= r_maxparticles) {
1184 		j = r_maxparticles - numparticles;
1185 	}
1186 
1187 	if (!avelocities[0][0]) {
1188 		for (i = 0; i < NUMVERTEXNORMALS * 3; i++)
1189 			avelocities[0][i] = (mtwist_rand (&mt) & 255) * 0.01;
1190 	}
1191 
1192 	for (i = 0; i < j; i++) {
1193 		angle = vr_data.realtime * avelocities[i][0];
1194 		cy = cos (angle);
1195 		sy = sin (angle);
1196 		angle = vr_data.realtime * avelocities[i][1];
1197 		cp = cos (angle);
1198 		sp = sin (angle);
1199 // Next 3 lines results aren't currently used, may be in future. --Despair
1200 //		angle = vr_data.realtime * avelocities[i][2];
1201 //		sr = sin (angle);
1202 //		cr = cos (angle);
1203 
1204 		forward[0] = cp * cy;
1205 		forward[1] = cp * sy;
1206 		forward[2] = -sp;
1207 
1208 		porg[0] = ent->origin[0] + r_avertexnormals[i][0] * dist +
1209 			forward[0] * beamlength;
1210 		porg[1] = ent->origin[1] + r_avertexnormals[i][1] * dist +
1211 			forward[1] * beamlength;
1212 		porg[2] = ent->origin[2] + r_avertexnormals[i][2] * dist +
1213 			forward[2] * beamlength;
1214 		particle_new (pt_explode, part_tex_dot, porg, 1.0, vec3_origin,
1215 					  vr_data.realtime + 0.01, 0x6f, 1.0, 0);
1216 	}
1217 }
1218 
1219 static void
R_RocketTrail_ID(const entity_t * ent)1220 R_RocketTrail_ID (const entity_t *ent)
1221 {
1222 	float		maxlen;
1223 	float		dist = 3.0, len = 0.0;
1224 	int			ramp, rnd;
1225 	vec3_t		old_origin, org, subtract, vec;
1226 
1227 	if (numparticles >= r_maxparticles)
1228 		return;
1229 
1230 	VectorCopy (ent->old_origin, old_origin);
1231 	VectorSubtract (ent->origin, ent->old_origin, vec);
1232 	maxlen = VectorNormalize (vec);
1233 	VectorScale (vec, (maxlen - dist), subtract);
1234 
1235 	while (len < maxlen) {
1236 		rnd = mtwist_rand (&mt);
1237 		org[0] = old_origin[0] + ((rnd >> 12) & 7) * (5.0/7.0) - 2.5;
1238 		org[1] = old_origin[1] + ((rnd >> 9) & 7) * (5.0/7.0) - 2.5;
1239 		org[2] = old_origin[2] + ((rnd >> 6) & 7) * (5.0/7.0) - 2.5;
1240 		ramp = rnd & 3;
1241 
1242 		particle_new (pt_fire, part_tex_dot, org, 1.0, vec3_origin,
1243 					  vr_data.realtime + 2.0, ramp3[ramp], 1.0, ramp);
1244 		if (numparticles >= r_maxparticles)
1245 			break;
1246 		len += dist;
1247 		VectorAdd (old_origin, subtract, old_origin);
1248 	}
1249 }
1250 
1251 static void
R_GrenadeTrail_ID(const entity_t * ent)1252 R_GrenadeTrail_ID (const entity_t *ent)
1253 {
1254 	float			maxlen;
1255 	float			dist = 3.0, len = 0.0;
1256 	unsigned int	ramp, rnd;
1257 	vec3_t			old_origin, org, subtract, vec;
1258 
1259 	if (numparticles >= r_maxparticles)
1260 		return;
1261 
1262 	VectorCopy (ent->old_origin, old_origin);
1263 	VectorSubtract (ent->origin, ent->old_origin, vec);
1264 	maxlen = VectorNormalize (vec);
1265 	VectorScale (vec, maxlen - dist, subtract);
1266 
1267 	while (len < maxlen) {
1268 		rnd = mtwist_rand (&mt);
1269 		org[0] = old_origin[0] + ((rnd >> 12) & 7) * (5.0/7.0) - 2.5;
1270 		org[1] = old_origin[1] + ((rnd >> 9) & 7) * (5.0/7.0) - 2.5;
1271 		org[2] = old_origin[2] + ((rnd >> 6) & 7) * (5.0/7.0) - 2.5;
1272 		ramp = (rnd & 3) + 2;
1273 
1274 		particle_new (pt_fire, part_tex_dot, org, 1.0, vec3_origin,
1275 					  vr_data.realtime + 2.0, ramp3[ramp], 1.0, ramp);
1276 		if (numparticles >= r_maxparticles)
1277 			break;
1278 		len += dist;
1279 		VectorAdd (old_origin, subtract, old_origin);
1280 	}
1281 }
1282 
1283 static void
R_BloodTrail_ID(const entity_t * ent)1284 R_BloodTrail_ID (const entity_t *ent)
1285 {
1286 	float			maxlen;
1287 	float			dist = 3.0, len = 0.0;
1288 	unsigned int	rnd;
1289 	vec3_t			old_origin, subtract, vec, porg;
1290 
1291 	if (numparticles >= r_maxparticles)
1292 		return;
1293 
1294 	VectorCopy (ent->old_origin, old_origin);
1295 	VectorSubtract (ent->origin, old_origin, vec);
1296 	maxlen = VectorNormalize (vec);
1297 	VectorScale (vec, maxlen - dist, subtract);
1298 
1299 	while (len < maxlen) {
1300 		rnd = mtwist_rand (&mt);
1301 		porg[0] = old_origin[0] + ((rnd >> 12) & 7) * (5.0/7.0) - 2.5;
1302 		porg[1] = old_origin[1] + ((rnd >> 9) & 7) * (5.0/7.0) - 2.5;
1303 		porg[2] = old_origin[2] + ((rnd >> 6) & 7) * (5.0/7.0) - 2.5;
1304 
1305 		particle_new (pt_grav, part_tex_dot, porg, 1.0, vec3_origin,
1306 					  vr_data.realtime + 2.0, 67 + (rnd & 3), 1.0, 0.0);
1307 		if (numparticles >= r_maxparticles)
1308 			break;
1309 		len += dist;
1310 		VectorAdd (old_origin, subtract, old_origin);
1311 	}
1312 }
1313 
1314 static void
R_SlightBloodTrail_ID(const entity_t * ent)1315 R_SlightBloodTrail_ID (const entity_t *ent)
1316 {
1317 	float			maxlen;
1318 	float			dist = 6.0, len = 0.0;
1319 	unsigned int	rnd;
1320 	vec3_t			old_origin, porg, subtract, vec;
1321 
1322 	if (numparticles >= r_maxparticles)
1323 		return;
1324 
1325 	VectorCopy (ent->old_origin, old_origin);
1326 	VectorSubtract (ent->origin, old_origin, vec);
1327 	maxlen = VectorNormalize (vec);
1328 	VectorScale (vec, maxlen - dist, subtract);
1329 
1330 	while (len < maxlen) {
1331 		rnd = mtwist_rand (&mt);
1332 		porg[0] = old_origin[0] + ((rnd >> 12) & 7) * (5.0/7.0) - 2.5;
1333 		porg[1] = old_origin[1] + ((rnd >> 9) & 7) * (5.0/7.0) - 2.5;
1334 		porg[2] = old_origin[2] + ((rnd >> 6) & 7) * (5.0/7.0) - 2.5;
1335 
1336 		particle_new (pt_grav, part_tex_dot, porg, 1.0, vec3_origin,
1337 					  vr_data.realtime + 1.5, 67 + (rnd & 3), 1.0, 0.0);
1338 		if (numparticles >= r_maxparticles)
1339 			break;
1340 		len += dist;
1341 		VectorAdd (old_origin, subtract, old_origin);
1342 	}
1343 }
1344 
1345 static void
R_WizTrail_ID(const entity_t * ent)1346 R_WizTrail_ID (const entity_t *ent)
1347 {
1348 	float		maxlen;
1349 	float		dist = 3.0, len = 0.0;
1350 	static int	tracercount;
1351 	vec3_t		old_origin, pvel, subtract, vec;
1352 
1353 	if (numparticles >= r_maxparticles)
1354 		return;
1355 
1356 	VectorCopy (ent->old_origin, old_origin);
1357 	VectorSubtract (ent->origin, old_origin, vec);
1358 	maxlen = VectorNormalize (vec);
1359 	VectorScale (vec, maxlen - dist, subtract);
1360 
1361 	while (len < maxlen) {
1362 		tracercount++;
1363 		if (tracercount & 1) {
1364 			pvel[0] = 30.0 * vec[1];
1365 			pvel[1] = 30.0 * -vec[0];
1366 		} else {
1367 			pvel[0] = 30.0 * -vec[1];
1368 			pvel[1] = 30.0 * vec[0];
1369 		}
1370 		pvel[2] = 0.0;
1371 
1372 		particle_new (pt_static, part_tex_dot, old_origin, 1.0, pvel,
1373 					  vr_data.realtime + 0.5, 52 + ((tracercount & 4) << 1),
1374 					  1.0, 0.0);
1375 		if (numparticles >= r_maxparticles)
1376 			break;
1377 		len += dist;
1378 		VectorAdd (old_origin, subtract, old_origin);
1379 	}
1380 }
1381 
1382 static void
R_FlameTrail_ID(const entity_t * ent)1383 R_FlameTrail_ID (const entity_t *ent)
1384 {
1385 	float		maxlen;
1386 	float		dist = 3.0, len = 0.0;
1387 	static int	tracercount;
1388 	vec3_t		old_origin, pvel, subtract, vec;
1389 
1390 	if (numparticles >= r_maxparticles)
1391 		return;
1392 
1393 	VectorCopy (ent->old_origin, old_origin);
1394 	VectorSubtract (ent->origin, old_origin, vec);
1395 	maxlen = VectorNormalize (vec);
1396 	VectorScale (vec, maxlen - dist, subtract);
1397 
1398 	while (len < maxlen) {
1399 		tracercount++;
1400 		if (tracercount & 1) {
1401 			pvel[0] = 30.0 * vec[1];
1402 			pvel[1] = 30.0 * -vec[0];
1403 		} else {
1404 			pvel[0] = 30.0 * -vec[1];
1405 			pvel[1] = 30.0 * vec[0];
1406 		}
1407 		pvel[2] = 0.0;
1408 
1409 		particle_new (pt_static, part_tex_dot, old_origin, 1.0, pvel,
1410 					  vr_data.realtime + 0.5, 230 + ((tracercount & 4) << 1),
1411 					  1.0, 0.0);
1412 		if (numparticles >= r_maxparticles)
1413 			break;
1414 		len += dist;
1415 		VectorAdd (old_origin, subtract, old_origin);
1416 	}
1417 }
1418 
1419 static void
R_VoorTrail_ID(const entity_t * ent)1420 R_VoorTrail_ID (const entity_t *ent)
1421 {
1422 	float			maxlen;
1423 	float			dist = 3.0, len = 0.0;
1424 	unsigned int	rnd;
1425 	vec3_t			old_origin, porg, subtract, vec;
1426 
1427 	if (numparticles >= r_maxparticles)
1428 		return;
1429 
1430 	VectorCopy (ent->old_origin, old_origin);
1431 	VectorSubtract (ent->origin, old_origin, vec);
1432 	maxlen = VectorNormalize (vec);
1433 	VectorScale (vec, maxlen - dist, subtract);
1434 
1435 	while (len < maxlen) {
1436 		rnd = mtwist_rand (&mt);
1437 		porg[0] = old_origin[0] + ((rnd >> 3) & 15) - 7.5;
1438 		porg[1] = old_origin[1] + ((rnd >> 7) & 15) - 7.5;
1439 		porg[2] = old_origin[2] + ((rnd >> 11) & 15) - 7.5;
1440 
1441 		particle_new (pt_static, part_tex_dot, porg, 1.0, vec3_origin,
1442 					  vr_data.realtime + 0.3, 9 * 16 + 8 + (rnd & 3),
1443 					  1.0, 0.0);
1444 		if (numparticles >= r_maxparticles)
1445 			break;
1446 		len += dist;
1447 		VectorAdd (old_origin, subtract, old_origin);
1448 	}
1449 }
1450 
1451 void
gl_R_DrawParticles(void)1452 gl_R_DrawParticles (void)
1453 {
1454 	unsigned char  *at;
1455 	int				activeparticles, maxparticle, j, vacount;
1456 	unsigned int	k;
1457 	float		minparticledist, scale;
1458 	particle_t	   *part;
1459 	vec3_t			up_scale, right_scale, up_right_scale, down_right_scale;
1460 	varray_t2f_c4ub_v3f_t		*VA;
1461 
1462 	if (!r_particles->int_val)
1463 		return;
1464 
1465 	qfglBindTexture (GL_TEXTURE_2D, gl_part_tex);
1466 	// LordHavoc: particles should not affect zbuffer
1467 	qfglDepthMask (GL_FALSE);
1468 	qfglInterleavedArrays (GL_T2F_C4UB_V3F, 0, particleVertexArray);
1469 
1470 	minparticledist = DotProduct (r_refdef.vieworg, vpn) +
1471 		r_particles_nearclip->value;
1472 
1473 	activeparticles = 0;
1474 	vacount = 0;
1475 	VA = particleVertexArray;
1476 	maxparticle = -1;
1477 	j = 0;
1478 
1479 	for (k = 0, part = particles; k < numparticles; k++, part++) {
1480 		// Don't render particles too close to us.
1481 		// Note, we must still do physics and such on them.
1482 		if (!(DotProduct (part->org, vpn) < minparticledist)) {
1483 			at = (byte *) &d_8to24table[(byte) part->color];
1484 			VA[0].color[0] = at[0];
1485 			VA[0].color[1] = at[1];
1486 			VA[0].color[2] = at[2];
1487 			VA[0].color[3] = part->alpha * 255;
1488 			memcpy (VA[1].color, VA[0].color, sizeof (VA[0].color));
1489 			memcpy (VA[2].color, VA[0].color, sizeof (VA[0].color));
1490 			memcpy (VA[3].color, VA[0].color, sizeof (VA[0].color));
1491 
1492 			switch (part->tex) {
1493 				case part_tex_dot:
1494 					VA[0].texcoord[0] = 0.0;
1495 					VA[0].texcoord[1] = 0.0;
1496 					VA[1].texcoord[0] = 0.5;
1497 					VA[1].texcoord[1] = 0.0;
1498 					VA[2].texcoord[0] = 0.5;
1499 					VA[2].texcoord[1] = 0.5;
1500 					VA[3].texcoord[0] = 0.0;
1501 					VA[3].texcoord[1] = 0.5;
1502 					break;
1503 				case part_tex_spark:
1504 					VA[0].texcoord[0] = 0.5;
1505 					VA[0].texcoord[1] = 0.0;
1506 					VA[1].texcoord[0] = 1.0;
1507 					VA[1].texcoord[1] = 0.0;
1508 					VA[2].texcoord[0] = 1.0;
1509 					VA[2].texcoord[1] = 0.5;
1510 					VA[3].texcoord[0] = 0.5;
1511 					VA[3].texcoord[1] = 0.5;
1512 					break;
1513 				case part_tex_smoke:
1514 					VA[0].texcoord[0] = 0.0;
1515 					VA[0].texcoord[1] = 0.5;
1516 					VA[1].texcoord[0] = 0.5;
1517 					VA[1].texcoord[1] = 0.5;
1518 					VA[2].texcoord[0] = 0.5;
1519 					VA[2].texcoord[1] = 1.0;
1520 					VA[3].texcoord[0] = 0.0;
1521 					VA[3].texcoord[1] = 1.0;
1522 					break;
1523 			}
1524 
1525 			scale = part->scale;
1526 
1527 			VectorScale (vup, scale, up_scale);
1528 			VectorScale (vright, scale, right_scale);
1529 
1530 			VectorAdd (right_scale, up_scale, up_right_scale);
1531 			VectorSubtract (right_scale, up_scale, down_right_scale);
1532 
1533 			VectorAdd (part->org, down_right_scale, VA[0].vertex);
1534 			VectorSubtract (part->org, up_right_scale, VA[1].vertex);
1535 			VectorSubtract (part->org, down_right_scale, VA[2].vertex);
1536 			VectorAdd (part->org, up_right_scale, VA[3].vertex);
1537 
1538 			VA += 4;
1539 			vacount += 4;
1540 			if (vacount + 4 > pVAsize) {
1541 				// never reached if partUseVA is false
1542 				qfglDrawElements (GL_QUADS, vacount, GL_UNSIGNED_INT,
1543 								  pVAindices);
1544 				vacount = 0;
1545 				VA = particleVertexArray;
1546 			}
1547 		}
1548 
1549 		part->phys (part);
1550 
1551 		// LordHavoc: immediate removal of unnecessary particles (must be done
1552 		// to ensure compactor below operates properly in all cases)
1553 		if (part->die < vr_data.realtime) {
1554 			freeparticles[j++] = part;
1555 		} else {
1556 			maxparticle = k;
1557 			activeparticles++;
1558 		}
1559 	}
1560 	if (vacount) {
1561 		if (partUseVA) {
1562 			qfglDrawElements (GL_QUADS, vacount, GL_UNSIGNED_INT, pVAindices);
1563 		} else {
1564 			varray_t2f_c4ub_v3f_t *va = particleVertexArray;
1565 			int         i;
1566 
1567 			qfglBegin (GL_QUADS);
1568 			for (i = 0; i < vacount; i++, va++) {
1569 				qfglTexCoord2fv (va->texcoord);
1570 				qfglColor4ubv (va->color);
1571 				qfglVertex3fv (va->vertex);
1572 			}
1573 			qfglEnd ();
1574 		}
1575 	}
1576 
1577 	k = 0;
1578 	while (maxparticle >= activeparticles) {
1579 		*freeparticles[k++] = particles[maxparticle--];
1580 		while (maxparticle >= activeparticles &&
1581 			   particles[maxparticle].die <= vr_data.realtime)
1582 			maxparticle--;
1583 	}
1584 	numparticles = activeparticles;
1585 
1586 	qfglColor3ubv (color_white);
1587 	qfglDepthMask (GL_TRUE);
1588 }
1589 
1590 static vid_particle_funcs_t particles_QF = {
1591 	R_RocketTrail_QF,
1592 	R_GrenadeTrail_QF,
1593 	R_BloodTrail_QF,
1594 	R_SlightBloodTrail_QF,
1595 	R_WizTrail_QF,
1596 	R_FlameTrail_QF,
1597 	R_VoorTrail_QF,
1598 	R_GlowTrail_QF,
1599 	R_RunParticleEffect_QF,
1600 	R_BloodPuffEffect_QF,
1601 	R_GunshotEffect_QF,
1602 	R_LightningBloodEffect_QF,
1603 	R_SpikeEffect_QF,
1604 	R_KnightSpikeEffect_QF,
1605 	R_SuperSpikeEffect_QF,
1606 	R_WizSpikeEffect_QF,
1607 	R_BlobExplosion_QF,
1608 	R_ParticleExplosion_QF,
1609 	R_ParticleExplosion2_QF,
1610 	R_LavaSplash_QF,
1611 	R_TeleportSplash_QF,
1612 	R_DarkFieldParticles_ID,
1613 	R_EntityParticles_ID,
1614 	R_Particle_New,
1615 	R_Particle_NewRandom,
1616 };
1617 
1618 static vid_particle_funcs_t particles_ID = {
1619 	R_RocketTrail_ID,
1620 	R_GrenadeTrail_ID,
1621 	R_BloodTrail_ID,
1622 	R_SlightBloodTrail_ID,
1623 	R_WizTrail_ID,
1624 	R_FlameTrail_ID,
1625 	R_VoorTrail_ID,
1626 	R_GlowTrail_QF,
1627 	R_RunParticleEffect_ID,
1628 	R_BloodPuffEffect_ID,
1629 	R_GunshotEffect_ID,
1630 	R_LightningBloodEffect_ID,
1631 	R_SpikeEffect_ID,
1632 	R_KnightSpikeEffect_ID,
1633 	R_SuperSpikeEffect_ID,
1634 	R_WizSpikeEffect_ID,
1635 	R_BlobExplosion_ID,
1636 	R_ParticleExplosion_ID,
1637 	R_ParticleExplosion2_QF,
1638 	R_LavaSplash_ID,
1639 	R_TeleportSplash_ID,
1640 	R_DarkFieldParticles_ID,
1641 	R_EntityParticles_ID,
1642 	R_Particle_New,
1643 	R_Particle_NewRandom,
1644 };
1645 
1646 static vid_particle_funcs_t particles_QF_egg = {
1647 	R_RocketTrail_EE,
1648 	R_GrenadeTrail_EE,
1649 	R_BloodTrail_QF,
1650 	R_SlightBloodTrail_QF,
1651 	R_WizTrail_QF,
1652 	R_FlameTrail_QF,
1653 	R_VoorTrail_QF,
1654 	R_GlowTrail_QF,
1655 	R_RunParticleEffect_QF,
1656 	R_BloodPuffEffect_QF,
1657 	R_GunshotEffect_QF,
1658 	R_LightningBloodEffect_QF,
1659 	R_SpikeEffect_QF,
1660 	R_KnightSpikeEffect_QF,
1661 	R_SuperSpikeEffect_QF,
1662 	R_WizSpikeEffect_QF,
1663 	R_BlobExplosion_QF,
1664 	R_ParticleExplosion_EE,
1665 	R_ParticleExplosion2_QF,
1666 	R_LavaSplash_QF,
1667 	R_TeleportSplash_EE,
1668 	R_DarkFieldParticles_ID,
1669 	R_EntityParticles_ID,
1670 	R_Particle_New,
1671 	R_Particle_NewRandom,
1672 };
1673 
1674 static vid_particle_funcs_t particles_ID_egg = {
1675 	R_RocketTrail_EE,
1676 	R_GrenadeTrail_EE,
1677 	R_BloodTrail_ID,
1678 	R_SlightBloodTrail_ID,
1679 	R_WizTrail_ID,
1680 	R_FlameTrail_ID,
1681 	R_VoorTrail_ID,
1682 	R_GlowTrail_QF,
1683 	R_RunParticleEffect_ID,
1684 	R_BloodPuffEffect_ID,
1685 	R_GunshotEffect_ID,
1686 	R_LightningBloodEffect_ID,
1687 	R_SpikeEffect_ID,
1688 	R_KnightSpikeEffect_ID,
1689 	R_SuperSpikeEffect_ID,
1690 	R_WizSpikeEffect_ID,
1691 	R_BlobExplosion_ID,
1692 	R_ParticleExplosion_EE,
1693 	R_ParticleExplosion2_QF,
1694 	R_LavaSplash_ID,
1695 	R_TeleportSplash_EE,
1696 	R_DarkFieldParticles_ID,
1697 	R_EntityParticles_ID,
1698 	R_Particle_New,
1699 	R_Particle_NewRandom,
1700 };
1701 
1702 void
gl_r_easter_eggs_f(cvar_t * var)1703 gl_r_easter_eggs_f (cvar_t *var)
1704 {
1705 	if (easter_eggs && !gl_feature_mach64) {
1706 		if (easter_eggs->int_val) {
1707 			if (r_particles_style->int_val) {
1708 				gl_vid_render_funcs.particles = &particles_QF_egg;
1709 			} else {
1710 				gl_vid_render_funcs.particles = &particles_ID_egg;
1711 			}
1712 		} else if (r_particles_style) {
1713 			if (r_particles_style->int_val) {
1714 				gl_vid_render_funcs.particles = &particles_QF;
1715 			} else {
1716 				gl_vid_render_funcs.particles = &particles_ID;
1717 			}
1718 		}
1719 	}
1720 }
1721 
1722 void
gl_r_particles_style_f(cvar_t * var)1723 gl_r_particles_style_f (cvar_t *var)
1724 {
1725 	gl_r_easter_eggs_f (easter_eggs);
1726 }
1727 
1728 static void
R_ParticleFunctionInit(void)1729 R_ParticleFunctionInit (void)
1730 {
1731 	gl_r_particles_style_f (r_particles_style);
1732 	gl_r_easter_eggs_f (easter_eggs);
1733 }
1734 
1735 static void
r_particles_nearclip_f(cvar_t * var)1736 r_particles_nearclip_f (cvar_t *var)
1737 {
1738 	Cvar_SetValue (r_particles_nearclip, bound (r_nearclip->value, var->value,
1739 												r_farclip->value));
1740 }
1741 
1742 static void
r_particles_f(cvar_t * var)1743 r_particles_f (cvar_t *var)
1744 {
1745 	R_MaxParticlesCheck (var, r_particles_max);
1746 }
1747 
1748 static void
r_particles_max_f(cvar_t * var)1749 r_particles_max_f (cvar_t *var)
1750 {
1751 	R_MaxParticlesCheck (r_particles, var);
1752 }
1753 
1754 void
gl_R_Particles_Init_Cvars(void)1755 gl_R_Particles_Init_Cvars (void)
1756 {
1757 	easter_eggs = Cvar_Get ("easter_eggs", "0", CVAR_NONE, r_easter_eggs_f,
1758 							"Enables easter eggs.");
1759 	r_particles = Cvar_Get ("r_particles", "1", CVAR_ARCHIVE, r_particles_f,
1760 							"Toggles drawing of particles.");
1761 	r_particles_max = Cvar_Get ("r_particles_max", "2048", CVAR_ARCHIVE,
1762 								r_particles_max_f, "Maximum amount of "
1763 								"particles to display. No maximum, minimum "
1764 								"is 0.");
1765 	r_particles_nearclip = Cvar_Get ("r_particles_nearclip", "32",
1766 									 CVAR_ARCHIVE, r_particles_nearclip_f,
1767 									 "Distance of the particle near clipping "
1768 									 "plane from the player.");
1769 	r_particles_style = Cvar_Get ("r_particles_style", "1", CVAR_ARCHIVE,
1770 								  r_particles_style_f, "Sets particle style. "
1771 								  "0 for Id, 1 for QF.");
1772 	R_ParticleFunctionInit ();
1773 }
1774 
1775 void
gl_R_Particle_New(ptype_t type,int texnum,const vec3_t org,float scale,const vec3_t vel,float die,int color,float alpha,float ramp)1776 gl_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale,
1777 				   const vec3_t vel, float die, int color, float alpha,
1778 				   float ramp)
1779 {
1780 	if (numparticles >= r_maxparticles)
1781 		return;
1782 	particle_new (type, texnum, org, scale, vel, die, color, alpha, ramp);
1783 }
1784 
1785 void
gl_R_Particle_NewRandom(ptype_t type,int texnum,const vec3_t org,int org_fuzz,float scale,int vel_fuzz,float die,int color,float alpha,float ramp)1786 gl_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org,
1787 						 int org_fuzz, float scale, int vel_fuzz, float die,
1788 						 int color, float alpha, float ramp)
1789 {
1790 	if (numparticles >= r_maxparticles)
1791 		return;
1792 	particle_new_random (type, texnum, org, org_fuzz, scale, vel_fuzz, die,
1793 						 color, alpha, ramp);
1794 }
1795