1 /*
2 	sw32_rpart.c
3 
4 	24 bit color software renderer particle effects.
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 #include <stdlib.h>
35 #ifdef HAVE_STRING_H
36 # include <string.h>
37 #endif
38 #ifdef HAVE_STRINGS_H
39 # include <strings.h>
40 #endif
41 
42 #include "QF/cvar.h"
43 #include "QF/mersenne.h"
44 #include "QF/qargs.h"
45 #include "QF/quakefs.h"
46 #include "QF/render.h"
47 #include "QF/sys.h"
48 #include "QF/va.h"
49 
50 #include "compat.h"
51 #include "r_internal.h"
52 
53 static int		ramp1[8] = { 0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61 };
54 //static int	ramp2[8] = { 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66 };
55 static int		ramp3[8] = { 0x6d, 0x6b, 6, 5, 4, 3 };
56 
57 static mtstate_t mt;	// private PRNG state
58 
59 
60 void
sw32_R_InitParticles(void)61 sw32_R_InitParticles (void)
62 {
63 	mtwist_seed (&mt, 0xdeadbeef);
64 }
65 
66 void
sw32_R_ClearParticles(void)67 sw32_R_ClearParticles (void)
68 {
69 	unsigned int i;
70 
71 	free_particles = &particles[0];
72 	active_particles = NULL;
73 
74 	for (i = 0; i < r_maxparticles; i++)
75 		particles[i].next = &particles[i + 1];
76 	if (r_maxparticles)
77 		particles[r_maxparticles - 1].next = NULL;
78 }
79 
80 void
sw32_R_ReadPointFile_f(void)81 sw32_R_ReadPointFile_f (void)
82 {
83 	QFile      *f;
84 	vec3_t      org;
85 	int         r;
86 	int         c;
87 	particle_t *p;
88 	const char *name;
89 	char       *mapname;
90 
91 	mapname = strdup (r_worldentity.model->name);
92 	if (!mapname)
93 		Sys_Error ("Can't duplicate mapname!");
94 	QFS_StripExtension (mapname, mapname);
95 
96 	name = va ("maps/%s.pts", mapname);
97 	free (mapname);
98 
99 	QFS_FOpenFile (name, &f);
100 	if (!f) {
101 		Sys_Printf ("couldn't open %s\n", name);
102 		return;
103 	}
104 
105 	Sys_Printf ("Reading %s...\n", name);
106 	c = 0;
107 	for (;;) {
108 		char        buf[64];
109 
110 		Qgets (f, buf, sizeof (buf));
111 		r = sscanf (buf, "%f %f %f\n", &org[0], &org[1], &org[2]);
112 		if (r != 3)
113 			break;
114 		c++;
115 
116 		if (!free_particles) {
117 			Sys_Printf ("Not enough free particles\n");
118 			break;
119 		}
120 		p = free_particles;
121 		free_particles = p->next;
122 		p->next = active_particles;
123 		active_particles = p;
124 
125 		p->die = 99999;
126 		p->color = (-c) & 15;
127 		p->type = pt_static;
128 		p->phys = R_ParticlePhysics (p->type);
129 		VectorZero (p->vel);
130 		VectorCopy (org, p->org);
131 	}
132 
133 	Qclose (f);
134 	Sys_Printf ("%i points read\n", c);
135 }
136 
137 static void
R_ParticleExplosion_QF(const vec3_t org)138 R_ParticleExplosion_QF (const vec3_t org)
139 {
140 	int         i, j;
141 	particle_t *p;
142 
143 	if (!r_particles->int_val)
144 		return;
145 
146 	for (i = 0; i < 1024; i++) {
147 		if (!free_particles)
148 			return;
149 		p = free_particles;
150 		free_particles = p->next;
151 		p->next = active_particles;
152 		active_particles = p;
153 
154 		p->die = vr_data.realtime + 5;
155 		p->color = ramp1[0];
156 		p->ramp = mtwist_rand (&mt) & 3;
157 		if (i & 1) {
158 			p->type = pt_explode;
159 			for (j = 0; j < 3; j++) {
160 				p->org[j] = org[j] + ((mtwist_rand (&mt) % 32) - 16);
161 				p->vel[j] = (mtwist_rand (&mt) % 512) - 256;
162 			}
163 		} else {
164 			p->type = pt_explode2;
165 			for (j = 0; j < 3; j++) {
166 				p->org[j] = org[j] + ((mtwist_rand (&mt) % 32) - 16);
167 				p->vel[j] = (mtwist_rand (&mt) % 512) - 256;
168 			}
169 		}
170 		p->phys = R_ParticlePhysics (p->type);
171 	}
172 }
173 
174 static void
R_ParticleExplosion2_QF(const vec3_t org,int colorStart,int colorLength)175 R_ParticleExplosion2_QF (const vec3_t org, int colorStart, int colorLength)
176 {
177 	int              i, j;
178 	particle_t      *p;
179 	int              colorMod = 0;
180 
181 	for (i=0; i<512; i++)
182 	{
183 		if (!free_particles)
184 			return;
185 		p = free_particles;
186 		free_particles = p->next;
187 		p->next = active_particles;
188 		active_particles = p;
189 
190 		p->die = vr_data.realtime + 0.3;
191 		p->color = colorStart + (colorMod % colorLength);
192 		colorMod++;
193 
194 		p->type = pt_blob;
195 		p->phys = R_ParticlePhysics (p->type);
196 		for (j=0 ; j<3 ; j++)
197 		{
198 			p->org[j] = org[j] + ((mtwist_rand (&mt)%32)-16);
199 			p->vel[j] = (mtwist_rand (&mt)%512)-256;
200 		}
201 	}
202 }
203 
204 static void
R_BlobExplosion_QF(const vec3_t org)205 R_BlobExplosion_QF (const vec3_t org)
206 {
207 	int         i, j;
208 	particle_t *p;
209 
210 	if (!r_particles->int_val)
211 		return;
212 
213 	for (i = 0; i < 1024; i++) {
214 		if (!free_particles)
215 			return;
216 		p = free_particles;
217 		free_particles = p->next;
218 		p->next = active_particles;
219 		active_particles = p;
220 
221 		p->die = vr_data.realtime + 1 + (mtwist_rand (&mt) & 8) * 0.05;
222 
223 		if (i & 1) {
224 			p->type = pt_blob;
225 			p->color = 66 + mtwist_rand (&mt) % 6;
226 			for (j = 0; j < 3; j++) {
227 				p->org[j] = org[j] + ((mtwist_rand (&mt) % 32) - 16);
228 				p->vel[j] = (mtwist_rand (&mt) % 512) - 256;
229 			}
230 		} else {
231 			p->type = pt_blob2;
232 			p->color = 150 + mtwist_rand (&mt) % 6;
233 			for (j = 0; j < 3; j++) {
234 				p->org[j] = org[j] + ((mtwist_rand (&mt) % 32) - 16);
235 				p->vel[j] = (mtwist_rand (&mt) % 512) - 256;
236 			}
237 		}
238 		p->phys = R_ParticlePhysics (p->type);
239 	}
240 }
241 
242 static void
R_LavaSplash_QF(const vec3_t org)243 R_LavaSplash_QF (const vec3_t org)
244 {
245 	int         i, j, k;
246 	particle_t *p;
247 	float       vel;
248 	vec3_t      dir;
249 
250 	if (!r_particles->int_val)
251 		return;
252 
253 	for (i = -16; i < 16; i++)
254 		for (j = -16; j < 16; j++)
255 			for (k = 0; k < 1; k++) {
256 				if (!free_particles)
257 					return;
258 				p = free_particles;
259 				free_particles = p->next;
260 				p->next = active_particles;
261 				active_particles = p;
262 
263 				p->die = vr_data.realtime + 2 + (mtwist_rand (&mt) & 31) * 0.02;
264 				p->color = 224 + (mtwist_rand (&mt) & 7);
265 				p->type = pt_grav;
266 				p->phys = R_ParticlePhysics (p->type);
267 
268 				dir[0] = j * 8 + (mtwist_rand (&mt) & 7);
269 				dir[1] = i * 8 + (mtwist_rand (&mt) & 7);
270 				dir[2] = 256;
271 
272 				p->org[0] = org[0] + dir[0];
273 				p->org[1] = org[1] + dir[1];
274 				p->org[2] = org[2] + (mtwist_rand (&mt) & 63);
275 
276 				VectorNormalize (dir);
277 				vel = 50 + (mtwist_rand (&mt) & 63);
278 				VectorScale (dir, vel, p->vel);
279 			}
280 }
281 
282 static void
R_TeleportSplash_QF(const vec3_t org)283 R_TeleportSplash_QF (const vec3_t org)
284 {
285 	float		vel;
286 	int	        i, j, k;
287 	particle_t *p;
288 	vec3_t		dir;
289 
290 	if (!r_particles->int_val)
291 		return;
292 
293 	for (i = -16; i < 16; i += 4) {
294 		for (j = -16; j < 16; j += 4) {
295 			for (k = -24; k < 32; k += 4) {
296 				if (!free_particles)
297 					return;
298 				p = free_particles;
299 				free_particles = p->next;
300 				p->next = active_particles;
301 				active_particles = p;
302 
303 				p->die = vr_data.realtime + 0.2 + (mtwist_rand (&mt) & 7) * 0.02;
304 				p->color = 7 + (mtwist_rand (&mt) & 7);
305 				p->type = pt_grav;
306 				p->phys = R_ParticlePhysics (p->type);
307 
308 				dir[0] = j * 8;
309 				dir[1] = i * 8;
310 				dir[2] = k * 8;
311 
312 				p->org[0] = org[0] + i + (mtwist_rand (&mt) & 3);
313 				p->org[1] = org[1] + j + (mtwist_rand (&mt) & 3);
314 				p->org[2] = org[2] + k + (mtwist_rand (&mt) & 3);
315 
316 				VectorNormalize (dir);
317 				vel = 50 + (mtwist_rand (&mt) & 63);
318 				VectorScale (dir, vel, p->vel);
319 			}
320 		}
321 	}
322 }
323 
324 static void
R_DarkFieldParticles_ID(const entity_t * ent)325 R_DarkFieldParticles_ID (const entity_t *ent)
326 {
327 	int				i, j, k;
328 	unsigned int	rnd;
329 	float			vel;
330 	particle_t	   *p;
331 	vec3_t			dir, org;
332 
333 	org[0] = ent->origin[0];
334 	org[1] = ent->origin[1];
335 	org[2] = ent->origin[2];
336 	for (i = -16; i < 16; i += 8) {
337 		for (j = -16; j < 16; j += 8) {
338 			for (k = 0; k < 32; k += 8) {
339 				if (!free_particles)
340 					return;
341 				p = free_particles;
342 				free_particles = p->next;
343 				p->next = active_particles;
344 				active_particles = p;
345 
346 				rnd = mtwist_rand (&mt);
347 
348 				p->die = vr_data.realtime + 0.2 + (rnd & 7) * 0.02;
349 				p->color = 150 + mtwist_rand (&mt) % 6;
350 				p->type = pt_slowgrav;
351 				p->phys = R_ParticlePhysics (p->type);
352 
353 				dir[0] = j * 8;
354 				dir[1] = i * 8;
355 				dir[2] = k * 8;
356 
357 				p->org[0] = org[0] + i + ((rnd >> 3) & 3);
358 				p->org[1] = org[1] + j + ((rnd >> 5) & 3);
359 				p->org[2] = org[2] + k + ((rnd >> 7) & 3);
360 
361 				VectorNormalize (dir);
362 				vel = 50 + ((rnd >> 9) & 63);
363 				VectorScale (dir, vel, p->vel);
364 			}
365 		}
366 	}
367 }
368 
369 static vec3_t		avelocities[NUMVERTEXNORMALS];
370 
371 static void
R_EntityParticles_ID(const entity_t * ent)372 R_EntityParticles_ID (const entity_t *ent)
373 {
374 	int			i;
375 	float		angle, sp, sy, cp, cy; // cr, sr
376 	float		beamlength = 16.0, dist = 64.0;
377 	particle_t *p;
378 	vec3_t		forward;
379 
380 	if (!avelocities[0][0]) {
381 		for (i = 0; i < NUMVERTEXNORMALS * 3; i++)
382 			avelocities[0][i] = (mtwist_rand (&mt) & 255) * 0.01;
383 	}
384 
385 	for (i = 0; i < NUMVERTEXNORMALS; i++) {
386 		angle = vr_data.realtime * avelocities[i][0];
387 		cy = cos (angle);
388 		sy = sin (angle);
389 		angle = vr_data.realtime * avelocities[i][1];
390 		cp = cos (angle);
391 		sp = sin (angle);
392 // Next 3 lines results aren't currently used, may be in future. --Despair
393 //		angle = vr_data.realtime * avelocities[i][2];
394 //		sr = sin (angle);
395 //		cr = cos (angle);
396 
397 		forward[0] = cp * cy;
398 		forward[1] = cp * sy;
399 		forward[2] = -sp;
400 
401 		if (!free_particles)
402 			return;
403 		p = free_particles;
404 		free_particles = p->next;
405 		p->next = active_particles;
406 		active_particles = p;
407 
408 		p->die = vr_data.realtime + 0.01;
409 		p->color = 0x6f;
410 		p->type = pt_explode;
411 		p->phys = R_ParticlePhysics (p->type);
412 
413 		p->org[0] = ent->origin[0] + r_avertexnormals[i][0] * dist +
414 			forward[0] * beamlength;
415 		p->org[1] = ent->origin[1] + r_avertexnormals[i][1] * dist +
416 			forward[1] * beamlength;
417 		p->org[2] = ent->origin[2] + r_avertexnormals[i][2] * dist +
418 			forward[2] * beamlength;
419 	}
420 }
421 
422 static void
R_RunParticleEffect_QF(const vec3_t org,const vec3_t dir,int color,int count)423 R_RunParticleEffect_QF (const vec3_t org, const vec3_t dir, int color,
424 						int count)
425 {
426 	int         i, j;
427 	particle_t *p;
428 
429 	if (!r_particles->int_val)
430 		return;
431 
432 	for (i = 0; i < count; i++) {
433 		if (!free_particles)
434 			return;
435 		p = free_particles;
436 		free_particles = p->next;
437 		p->next = active_particles;
438 		active_particles = p;
439 
440 		p->die = vr_data.realtime + 0.1 * (mtwist_rand (&mt) % 5);
441 		p->color = (color & ~7) + (mtwist_rand (&mt) & 7);
442 		p->type = pt_slowgrav;
443 		p->phys = R_ParticlePhysics (p->type);
444 		for (j = 0; j < 3; j++) {
445 			p->org[j] = org[j] + ((mtwist_rand (&mt) & 15) - 8);
446 			p->vel[j] = dir[j];	// + (mtwist_rand (&mt)%300)-150;
447 		}
448 	}
449 }
450 
451 static void
R_SpikeEffect_QF(const vec3_t org)452 R_SpikeEffect_QF (const vec3_t org)
453 {
454 	R_RunParticleEffect_QF (org, vec3_origin, 0, 10);
455 }
456 
457 static void
R_SuperSpikeEffect_QF(const vec3_t org)458 R_SuperSpikeEffect_QF (const vec3_t org)
459 {
460 	R_RunParticleEffect_QF (org, vec3_origin, 0, 20);
461 }
462 
463 static void
R_KnightSpikeEffect_QF(const vec3_t org)464 R_KnightSpikeEffect_QF (const vec3_t org)
465 {
466 	R_RunParticleEffect_QF (org, vec3_origin, 226, 20);
467 }
468 
469 static void
R_WizSpikeEffect_QF(const vec3_t org)470 R_WizSpikeEffect_QF (const vec3_t org)
471 {
472 	R_RunParticleEffect_QF (org, vec3_origin, 20, 30);
473 }
474 
475 static void
R_BloodPuffEffect_QF(const vec3_t org,int count)476 R_BloodPuffEffect_QF (const vec3_t org, int count)
477 {
478 	R_RunParticleEffect_QF (org, vec3_origin, 73, count);
479 }
480 
481 static void
R_GunshotEffect_QF(const vec3_t org,int count)482 R_GunshotEffect_QF (const vec3_t org, int count)
483 {
484 	R_RunParticleEffect_QF (org, vec3_origin, 0, count);
485 }
486 
487 static void
R_LightningBloodEffect_QF(const vec3_t org)488 R_LightningBloodEffect_QF (const vec3_t org)
489 {
490 	R_RunParticleEffect_QF (org, vec3_origin, 225, 50);
491 }
492 
493 static void
R_RocketTrail_QF(const entity_t * ent)494 R_RocketTrail_QF (const entity_t *ent)
495 {
496 	float		len;
497 	int			j;
498 	particle_t *p;
499 	vec3_t		old_origin, vec;
500 
501 	if (!r_particles->int_val)
502 		return;
503 
504 	VectorCopy (ent->old_origin, old_origin);
505 	VectorSubtract (ent->origin, ent->old_origin, vec);
506 	len = VectorNormalize (vec);
507 
508 	while (len > 0) {
509 		len -= 3;
510 
511 		if (!free_particles)
512 			return;
513 		p = free_particles;
514 		free_particles = p->next;
515 		p->next = active_particles;
516 		active_particles = p;
517 
518 		VectorZero (p->vel);
519 
520 		p->die = vr_data.realtime + 2;
521 		p->ramp = (mtwist_rand (&mt) & 3);
522 		p->color = ramp3[(int) p->ramp];
523 		p->type = pt_fire;
524 		p->phys = R_ParticlePhysics (p->type);
525 		for (j = 0; j < 3; j++)
526 			p->org[j] = old_origin[j] + ((mtwist_rand (&mt) % 6) - 3);
527 
528 		VectorAdd (old_origin, vec, old_origin);
529 	}
530 }
531 
532 static void
R_GrenadeTrail_QF(const entity_t * ent)533 R_GrenadeTrail_QF (const entity_t *ent)
534 {
535 	float		len;
536 	int			j;
537 	particle_t *p;
538 	vec3_t		old_origin, vec;
539 
540 	if (!r_particles->int_val)
541 		return;
542 
543 	VectorCopy (ent->old_origin, old_origin);
544 	VectorSubtract (ent->origin, old_origin, vec);
545 	len = VectorNormalize (vec);
546 
547 	while (len > 0) {
548 		len -= 3;
549 
550 		if (!free_particles)
551 			return;
552 		p = free_particles;
553 		free_particles = p->next;
554 		p->next = active_particles;
555 		active_particles = p;
556 
557 		VectorZero (p->vel);
558 
559 		p->die = vr_data.realtime + 2;
560 		p->ramp = (mtwist_rand (&mt) & 3) + 2;
561 		p->color = ramp3[(int) p->ramp];
562 		p->type = pt_fire;
563 		p->phys = R_ParticlePhysics (p->type);
564 		for (j = 0; j < 3; j++)
565 			p->org[j] = old_origin[j] + ((mtwist_rand (&mt) % 6) - 3);
566 
567 		VectorAdd (old_origin, vec, old_origin);
568 	}
569 }
570 
571 static void
R_BloodTrail_QF(const entity_t * ent)572 R_BloodTrail_QF (const entity_t *ent)
573 {
574 	float		len;
575 	int			j;
576 	particle_t *p;
577 	vec3_t		old_origin, vec;
578 
579 	if (!r_particles->int_val)
580 		return;
581 
582 	VectorCopy (ent->old_origin, old_origin);
583 	VectorSubtract (ent->origin, old_origin, vec);
584 	len = VectorNormalize (vec);
585 
586 	while (len > 0) {
587 		len -= 3;
588 
589 		if (!free_particles)
590 			return;
591 		p = free_particles;
592 		free_particles = p->next;
593 		p->next = active_particles;
594 		active_particles = p;
595 
596 		VectorZero (p->vel);
597 
598 		p->die = vr_data.realtime + 2;
599 		p->type = pt_slowgrav;
600 		p->phys = R_ParticlePhysics (p->type);
601 		p->color = 67 + (mtwist_rand (&mt) & 3);
602 		for (j = 0; j < 3; j++)
603 			p->org[j] = old_origin[j] + ((mtwist_rand (&mt) % 6) - 3);
604 		break;
605 
606 		VectorAdd (old_origin, vec, old_origin);
607 	}
608 }
609 
610 static void
R_SlightBloodTrail_QF(const entity_t * ent)611 R_SlightBloodTrail_QF (const entity_t *ent)
612 {
613 	float		len;
614 	int			j;
615 	particle_t *p;
616 	vec3_t		old_origin, vec;
617 
618 	if (!r_particles->int_val)
619 		return;
620 
621 	VectorCopy (ent->old_origin, old_origin);
622 	VectorSubtract (ent->origin, old_origin, vec);
623 	len = VectorNormalize (vec);
624 
625 	while (len > 0) {
626 		len -= 6;
627 
628 		if (!free_particles)
629 			return;
630 		p = free_particles;
631 		free_particles = p->next;
632 		p->next = active_particles;
633 		active_particles = p;
634 
635 		VectorZero (p->vel);
636 
637 		p->die = vr_data.realtime + 2;
638 		p->type = pt_slowgrav;
639 		p->phys = R_ParticlePhysics (p->type);
640 		p->color = 67 + (mtwist_rand (&mt) & 3);
641 		for (j = 0; j < 3; j++)
642 			p->org[j] = old_origin[j] + ((mtwist_rand (&mt) % 6) - 3);
643 
644 		VectorAdd (old_origin, vec, old_origin);
645 	}
646 }
647 
648 static void
R_WizTrail_QF(const entity_t * ent)649 R_WizTrail_QF (const entity_t *ent)
650 {
651 	float		len;
652 	particle_t *p;
653 	vec3_t		old_origin, vec;
654 
655 	if (!r_particles->int_val)
656 		return;
657 
658 	VectorCopy (ent->old_origin, old_origin);
659 	VectorSubtract (ent->origin, old_origin, vec);
660 	len = VectorNormalize (vec);
661 
662 	while (len > 0) {
663 		static int  tracercount;
664 
665 		len -= 3;
666 
667 		if (!free_particles)
668 			return;
669 		p = free_particles;
670 		free_particles = p->next;
671 		p->next = active_particles;
672 		active_particles = p;
673 
674 		p->die = vr_data.realtime + 0.5;
675 		p->type = pt_static;
676 		p->phys = R_ParticlePhysics (p->type);
677 		p->color = 52 + ((tracercount & 4) << 1);
678 
679 		tracercount++;
680 
681         VectorCopy (old_origin, p->org);
682         if (tracercount & 1) {
683             p->vel[0] = 30.0 * vec[1];
684             p->vel[1] = 30.0 * -vec[0];
685         } else {
686             p->vel[0] = 30.0 * -vec[1];
687             p->vel[1] = 30.0 * vec[0];
688         }
689 		p->vel[2] = 0.0;
690 
691 		VectorAdd (old_origin, vec, old_origin);
692 	}
693 }
694 
695 static void
R_FlameTrail_QF(const entity_t * ent)696 R_FlameTrail_QF (const entity_t *ent)
697 {
698 	float		len;
699 	particle_t *p;
700 	vec3_t		old_origin, vec;
701 
702 	if (!r_particles->int_val)
703 		return;
704 
705 	VectorCopy (ent->old_origin, old_origin);
706 	VectorSubtract (ent->origin, old_origin, vec);
707 	len = VectorNormalize (vec);
708 
709 	while (len > 0) {
710 		static int tracercount;
711 
712 		len -= 3;
713 
714 		if (!free_particles)
715 			return;
716 		p = free_particles;
717 		free_particles = p->next;
718 		p->next = active_particles;
719 		active_particles = p;
720 
721 		p->die = vr_data.realtime + 0.5;
722 		p->type = pt_static;
723 		p->phys = R_ParticlePhysics (p->type);
724 		p->color = 230 + ((tracercount & 4) << 1);
725 
726 		tracercount++;
727 
728 		VectorCopy (old_origin, p->org);
729 		if (tracercount & 1) {
730 			p->vel[0] = 30.0 * vec[1];
731 			p->vel[1] = 30.0 * -vec[0];
732 		} else {
733 			p->vel[0] = 30.0 * -vec[1];
734 			p->vel[1] = 30.0 * vec[0];
735 		}
736 		p->vel[2] = 0.0;
737 
738 		VectorAdd (old_origin, vec, old_origin);
739 	}
740 }
741 
742 static void
R_VoorTrail_QF(const entity_t * ent)743 R_VoorTrail_QF (const entity_t *ent)
744 {
745 	float		len;
746 	int			j;
747 	particle_t *p;
748 	vec3_t		old_origin, vec;
749 
750 	if (!r_particles->int_val)
751 		return;
752 
753 	VectorCopy (ent->old_origin, old_origin);
754 	VectorSubtract (ent->origin, old_origin, vec);
755 	len = VectorNormalize (vec);
756 
757 	while (len > 0) {
758 		len -= 3;
759 
760 		if (!free_particles)
761 			return;
762 		p = free_particles;
763 		free_particles = p->next;
764 		p->next = active_particles;
765 		active_particles = p;
766 
767 		VectorZero (p->vel);
768 
769 		p->die = vr_data.realtime + 0.3;
770 		p->type = pt_static;
771 		p->phys = R_ParticlePhysics (p->type);
772 		p->color = 9 * 16 + 8 + (mtwist_rand (&mt) & 3);
773 		for (j = 0; j < 3; j++)
774 			p->org[j] = old_origin[j] + ((mtwist_rand (&mt) & 15) - 8);
775 
776 		VectorAdd (old_origin, vec, old_origin);
777 	}
778 }
779 
780 void
sw32_R_DrawParticles(void)781 sw32_R_DrawParticles (void)
782 {
783 	particle_t *p, **particle;
784 
785 	VectorScale (vright, sw32_xscaleshrink, r_pright);
786 	VectorScale (vup, sw32_yscaleshrink, r_pup);
787 	VectorCopy (vpn, r_ppn);
788 
789 	for (particle = &active_particles; *particle;) {
790 		if ((*particle)->die < vr_data.realtime) {
791 			p = (*particle)->next;
792 			(*particle)->next = free_particles;
793 			free_particles = (*particle);
794 			(*particle) = p;
795 		} else {
796 			p = *particle;
797 			particle = &(*particle)->next;
798 
799 			sw32_D_DrawParticle (p);
800 
801 			p->phys (p);
802 		}
803 	}
804 }
805 
806 void
sw32_r_easter_eggs_f(cvar_t * var)807 sw32_r_easter_eggs_f (cvar_t *var)
808 {
809 }
810 
811 void
sw32_r_particles_style_f(cvar_t * var)812 sw32_r_particles_style_f (cvar_t *var)
813 {
814 }
815 
816 static vid_particle_funcs_t particles_QF = {
817 	R_RocketTrail_QF,
818 	R_GrenadeTrail_QF,
819 	R_BloodTrail_QF,
820 	R_SlightBloodTrail_QF,
821 	R_WizTrail_QF,
822 	R_FlameTrail_QF,
823 	R_VoorTrail_QF,
824 	0,//R_GlowTrail_QF,
825 	R_RunParticleEffect_QF,
826 	R_BloodPuffEffect_QF,
827 	R_GunshotEffect_QF,
828 	R_LightningBloodEffect_QF,
829 	R_SpikeEffect_QF,
830 	R_KnightSpikeEffect_QF,
831 	R_SuperSpikeEffect_QF,
832 	R_WizSpikeEffect_QF,
833 	R_BlobExplosion_QF,
834 	R_ParticleExplosion_QF,
835 	R_ParticleExplosion2_QF,
836 	R_LavaSplash_QF,
837 	R_TeleportSplash_QF,
838 	R_DarkFieldParticles_ID,
839 	R_EntityParticles_ID,
840 	R_Particle_New,
841 	R_Particle_NewRandom,
842 };
843 
844 static void
R_ParticleFunctionInit(void)845 R_ParticleFunctionInit (void)
846 {
847 	sw32_vid_render_funcs.particles = &particles_QF;
848 }
849 
850 static void
r_particles_nearclip_f(cvar_t * var)851 r_particles_nearclip_f (cvar_t *var)
852 {
853 	Cvar_SetValue (r_particles_nearclip, bound (r_nearclip->value, var->value,
854 												r_farclip->value));
855 }
856 
857 static void
r_particles_f(cvar_t * var)858 r_particles_f (cvar_t *var)
859 {
860 	R_MaxParticlesCheck (var, r_particles_max);
861 }
862 
863 static void
r_particles_max_f(cvar_t * var)864 r_particles_max_f (cvar_t *var)
865 {
866 	R_MaxParticlesCheck (r_particles, var);
867 }
868 
869 void
sw32_R_Particles_Init_Cvars(void)870 sw32_R_Particles_Init_Cvars (void)
871 {
872 	easter_eggs = Cvar_Get ("easter_eggs", "0", CVAR_NONE, r_easter_eggs_f,
873 							"Enables easter eggs.");
874 	r_particles = Cvar_Get ("r_particles", "1", CVAR_ARCHIVE, r_particles_f,
875 							"Toggles drawing of particles.");
876 	r_particles_max = Cvar_Get ("r_particles_max", "2048", CVAR_ARCHIVE,
877 								r_particles_max_f, "Maximum amount of "
878 								"particles to display. No maximum, minimum "
879 								"is 0.");
880 	r_particles_nearclip = Cvar_Get ("r_particles_nearclip", "32",
881 									 CVAR_ARCHIVE, r_particles_nearclip_f,
882 									 "Distance of the particle near clipping "
883 									 "plane from the player.");
884 	r_particles_style = Cvar_Get ("r_particles_style", "1", CVAR_ARCHIVE,
885 								  r_particles_style_f, "Sets particle style. "
886 								  "0 for Id, 1 for QF.");
887 	R_ParticleFunctionInit ();
888 }
889 
890 void
sw32_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)891 sw32_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale,
892 					 const vec3_t vel, float die, int color, float alpha,
893 					 float ramp)
894 {
895 	particle_t *p;
896 
897 	if (!free_particles)
898 		return;
899 	p = free_particles;
900 	free_particles = p->next;
901 	p->next = active_particles;
902 	active_particles = p;
903 
904 	VectorCopy (org, p->org);
905 	p->color = color;
906 	p->tex = texnum;
907 	p->scale = scale;
908 	p->alpha = alpha;
909 	VectorCopy (vel, p->vel);
910 	p->type = type;
911 	p->phys = R_ParticlePhysics (p->type);
912 	p->die = die;
913 	p->ramp = ramp;
914 }
915 
916 void
sw32_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)917 sw32_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org,
918 						   int org_fuzz, float scale, int vel_fuzz, float die,
919 						   int color, float alpha, float ramp)
920 {
921 	float       o_fuzz = org_fuzz, v_fuzz = vel_fuzz;
922 	int         rnd;
923 	vec3_t      porg, pvel;
924 
925 	rnd = mtwist_rand (&mt);
926 	porg[0] = o_fuzz * ((rnd & 63) - 31.5) / 63.0 + org[0];
927 	porg[1] = o_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0 + org[1];
928 	porg[2] = o_fuzz * (((rnd >> 12) & 63) - 31.5) / 63.0 + org[2];
929 	rnd = mtwist_rand (&mt);
930 	pvel[0] = v_fuzz * ((rnd & 63) - 31.5) / 63.0;
931 	pvel[1] = v_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0;
932 	pvel[2] = v_fuzz * (((rnd >> 12) & 63) - 31.5) / 63.0;
933 
934 	sw32_R_Particle_New (type, texnum, porg, scale, pvel, die, color, alpha, ramp);
935 }
936