1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19*/
20
21#include "quakedef.h"
22#include "r_local.h"
23
24#define MAX_PARTICLES			2048	// default max # of particles at one
25										//  time
26#define ABSOLUTE_MIN_PARTICLES	512		// no fewer than this no matter what's
27										//  on the command line
28
29int		ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61};
30int		ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66};
31int		ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3};
32
33particle_t	*active_particles, *free_particles;
34
35particle_t	*particles;
36int			r_numparticles;
37
38vec3_t			r_pright, r_pup, r_ppn;
39
40
41/*
42===============
43R_InitParticles
44===============
45*/
46void R_InitParticles (void)
47{
48	int		i;
49
50	i = COM_CheckParm ("-particles");
51
52	if (i)
53	{
54		r_numparticles = (int)(Q_atoi(com_argv[i+1]));
55		if (r_numparticles < ABSOLUTE_MIN_PARTICLES)
56			r_numparticles = ABSOLUTE_MIN_PARTICLES;
57	}
58	else
59	{
60		r_numparticles = MAX_PARTICLES;
61	}
62
63	particles = (particle_t *)
64			Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles");
65}
66
67
68/*
69===============
70R_ClearParticles
71===============
72*/
73void R_ClearParticles (void)
74{
75	int		i;
76
77	free_particles = &particles[0];
78	active_particles = NULL;
79
80	for (i=0 ;i<r_numparticles ; i++)
81		particles[i].next = &particles[i+1];
82	particles[r_numparticles-1].next = NULL;
83}
84
85
86void R_ReadPointFile_f (void)
87{
88	FILE	*f;
89	vec3_t	org;
90	int		r;
91	int		c;
92	particle_t	*p;
93	char	name[MAX_OSPATH];
94
95// FIXME	sprintf (name,"maps/%s.pts", sv.name);
96
97	COM_FOpenFile (name, &f);
98	if (!f)
99	{
100		Con_Printf ("couldn't open %s\n", name);
101		return;
102	}
103
104	Con_Printf ("Reading %s...\n", name);
105	c = 0;
106	for ( ;; )
107	{
108		r = fscanf (f,"%f %f %f\n", &org[0], &org[1], &org[2]);
109		if (r != 3)
110			break;
111		c++;
112
113		if (!free_particles)
114		{
115			Con_Printf ("Not enough free particles\n");
116			break;
117		}
118		p = free_particles;
119		free_particles = p->next;
120		p->next = active_particles;
121		active_particles = p;
122
123		p->die = 99999;
124		p->color = (-c)&15;
125		p->type = pt_static;
126		VectorCopy (vec3_origin, p->vel);
127		VectorCopy (org, p->org);
128	}
129
130	fclose (f);
131	Con_Printf ("%i points read\n", c);
132}
133
134/*
135===============
136R_ParticleExplosion
137
138===============
139*/
140void R_ParticleExplosion (vec3_t org)
141{
142	int			i, j;
143	particle_t	*p;
144
145	for (i=0 ; i<1024 ; i++)
146	{
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 = cl.time + 5;
155		p->color = ramp1[0];
156		p->ramp = rand()&3;
157		if (i & 1)
158		{
159			p->type = pt_explode;
160			for (j=0 ; j<3 ; j++)
161			{
162				p->org[j] = org[j] + ((rand()%32)-16);
163				p->vel[j] = (rand()%512)-256;
164			}
165		}
166		else
167		{
168			p->type = pt_explode2;
169			for (j=0 ; j<3 ; j++)
170			{
171				p->org[j] = org[j] + ((rand()%32)-16);
172				p->vel[j] = (rand()%512)-256;
173			}
174		}
175	}
176}
177
178/*
179===============
180R_BlobExplosion
181
182===============
183*/
184void R_BlobExplosion (vec3_t org)
185{
186	int			i, j;
187	particle_t	*p;
188
189	for (i=0 ; i<1024 ; i++)
190	{
191		if (!free_particles)
192			return;
193		p = free_particles;
194		free_particles = p->next;
195		p->next = active_particles;
196		active_particles = p;
197
198		p->die = cl.time + 1 + (rand()&8)*0.05;
199
200		if (i & 1)
201		{
202			p->type = pt_blob;
203			p->color = 66 + rand()%6;
204			for (j=0 ; j<3 ; j++)
205			{
206				p->org[j] = org[j] + ((rand()%32)-16);
207				p->vel[j] = (rand()%512)-256;
208			}
209		}
210		else
211		{
212			p->type = pt_blob2;
213			p->color = 150 + rand()%6;
214			for (j=0 ; j<3 ; j++)
215			{
216				p->org[j] = org[j] + ((rand()%32)-16);
217				p->vel[j] = (rand()%512)-256;
218			}
219		}
220	}
221}
222
223/*
224===============
225R_RunParticleEffect
226
227===============
228*/
229void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
230{
231	int			i, j;
232	particle_t	*p;
233	int			scale;
234
235	if (count > 130)
236		scale = 3;
237	else if (count > 20)
238		scale = 2;
239	else
240		scale = 1;
241
242	for (i=0 ; i<count ; i++)
243	{
244		if (!free_particles)
245			return;
246		p = free_particles;
247		free_particles = p->next;
248		p->next = active_particles;
249		active_particles = p;
250
251		p->die = cl.time + 0.1*(rand()%5);
252		p->color = (color&~7) + (rand()&7);
253		p->type = pt_grav;
254		for (j=0 ; j<3 ; j++)
255		{
256			p->org[j] = org[j] + scale*((rand()&15)-8);
257			p->vel[j] = dir[j]*15;// + (rand()%300)-150;
258		}
259	}
260}
261
262
263/*
264===============
265R_LavaSplash
266
267===============
268*/
269void R_LavaSplash (vec3_t org)
270{
271	int			i, j, k;
272	particle_t	*p;
273	float		vel;
274	vec3_t		dir;
275
276	for (i=-16 ; i<16 ; i++)
277		for (j=-16 ; j<16 ; j++)
278			for (k=0 ; k<1 ; k++)
279			{
280				if (!free_particles)
281					return;
282				p = free_particles;
283				free_particles = p->next;
284				p->next = active_particles;
285				active_particles = p;
286
287				p->die = cl.time + 2 + (rand()&31) * 0.02;
288				p->color = 224 + (rand()&7);
289				p->type = pt_grav;
290
291				dir[0] = j*8 + (rand()&7);
292				dir[1] = i*8 + (rand()&7);
293				dir[2] = 256;
294
295				p->org[0] = org[0] + dir[0];
296				p->org[1] = org[1] + dir[1];
297				p->org[2] = org[2] + (rand()&63);
298
299				VectorNormalize (dir);
300				vel = 50 + (rand()&63);
301				VectorScale (dir, vel, p->vel);
302			}
303}
304
305/*
306===============
307R_TeleportSplash
308
309===============
310*/
311void R_TeleportSplash (vec3_t org)
312{
313	int			i, j, k;
314	particle_t	*p;
315	float		vel;
316	vec3_t		dir;
317
318	for (i=-16 ; i<16 ; i+=4)
319		for (j=-16 ; j<16 ; j+=4)
320			for (k=-24 ; k<32 ; k+=4)
321			{
322				if (!free_particles)
323					return;
324				p = free_particles;
325				free_particles = p->next;
326				p->next = active_particles;
327				active_particles = p;
328
329				p->die = cl.time + 0.2 + (rand()&7) * 0.02;
330				p->color = 7 + (rand()&7);
331				p->type = pt_grav;
332
333				dir[0] = j*8;
334				dir[1] = i*8;
335				dir[2] = k*8;
336
337				p->org[0] = org[0] + i + (rand()&3);
338				p->org[1] = org[1] + j + (rand()&3);
339				p->org[2] = org[2] + k + (rand()&3);
340
341				VectorNormalize (dir);
342				vel = 50 + (rand()&63);
343				VectorScale (dir, vel, p->vel);
344			}
345}
346
347void R_RocketTrail (vec3_t start, vec3_t end, int type)
348{
349	vec3_t	vec;
350	float	len;
351	int			j;
352	particle_t	*p;
353
354	VectorSubtract (end, start, vec);
355	len = VectorNormalize (vec);
356	while (len > 0)
357	{
358		len -= 3;
359
360		if (!free_particles)
361			return;
362		p = free_particles;
363		free_particles = p->next;
364		p->next = active_particles;
365		active_particles = p;
366
367		VectorCopy (vec3_origin, p->vel);
368		p->die = cl.time + 2;
369
370		if (type == 4)
371		{	// slight blood
372			p->type = pt_slowgrav;
373			p->color = 67 + (rand()&3);
374			for (j=0 ; j<3 ; j++)
375				p->org[j] = start[j] + ((rand()%6)-3);
376			len -= 3;
377		}
378		else if (type == 2)
379		{	// blood
380			p->type = pt_slowgrav;
381			p->color = 67 + (rand()&3);
382			for (j=0 ; j<3 ; j++)
383				p->org[j] = start[j] + ((rand()%6)-3);
384		}
385		else if (type == 6)
386		{	// voor trail
387			p->color = 9*16 + 8 + (rand()&3);
388			p->type = pt_static;
389			p->die = cl.time + 0.3;
390			for (j=0 ; j<3 ; j++)
391				p->org[j] = start[j] + ((rand()&15)-8);
392		}
393		else if (type == 1)
394		{	// smoke smoke
395			p->ramp = (rand()&3) + 2;
396			p->color = ramp3[(int)p->ramp];
397			p->type = pt_fire;
398			for (j=0 ; j<3 ; j++)
399				p->org[j] = start[j] + ((rand()%6)-3);
400		}
401		else if (type == 0)
402		{	// rocket trail
403			p->ramp = (rand()&3);
404			p->color = ramp3[(int)p->ramp];
405			p->type = pt_fire;
406			for (j=0 ; j<3 ; j++)
407				p->org[j] = start[j] + ((rand()%6)-3);
408		}
409		else if (type == 3 || type == 5)
410		{	// tracer
411			static int tracercount;
412
413			p->die = cl.time + 0.5;
414			p->type = pt_static;
415			if (type == 3)
416				p->color = 52 + ((tracercount&4)<<1);
417			else
418				p->color = 230 + ((tracercount&4)<<1);
419
420			tracercount++;
421
422			VectorCopy (start, p->org);
423			if (tracercount & 1)
424			{
425				p->vel[0] = 30*vec[1];
426				p->vel[1] = 30*-vec[0];
427			}
428			else
429			{
430				p->vel[0] = 30*-vec[1];
431				p->vel[1] = 30*vec[0];
432			}
433
434		}
435
436
437		VectorAdd (start, vec, start);
438	}
439}
440
441
442/*
443===============
444R_DrawParticles
445===============
446*/
447void R_DrawParticles (void)
448{
449	particle_t		*p, *kill;
450	float			grav;
451	int				i;
452	float			time2, time3;
453	float			time1;
454	float			dvel;
455	float			frametime;
456#ifdef GLQUAKE
457	unsigned char	*at;
458	unsigned char	theAlpha;
459	vec3_t			up, right;
460	float			scale;
461	qboolean		alphaTestEnabled;
462
463	GL_Bind(particletexture);
464#ifdef USE_OPENGLES
465	// !!! Implement this
466	alphaTestEnabled = false;
467#else
468	alphaTestEnabled = glIsEnabled(GL_ALPHA_TEST);
469#endif
470
471	if (alphaTestEnabled)
472		glDisable(GL_ALPHA_TEST);
473	glEnable (GL_BLEND);
474	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
475
476#ifdef USE_OPENGLES
477	// !!! Implement this
478#else
479	glBegin (GL_TRIANGLES);
480#endif
481
482	VectorScale (vup, 1.5, up);
483	VectorScale (vright, 1.5, right);
484#else
485	D_StartParticles ();
486
487	VectorScale (vright, xscaleshrink, r_pright);
488	VectorScale (vup, yscaleshrink, r_pup);
489	VectorCopy (vpn, r_ppn);
490#endif
491
492	frametime = host_frametime;
493	time3 = frametime * 15;
494	time2 = frametime * 10; // 15;
495	time1 = frametime * 5;
496	grav = frametime * 800 * 0.05;
497	dvel = 4*frametime;
498
499	for ( ;; )
500	{
501		kill = active_particles;
502		if (kill && kill->die < cl.time)
503		{
504			active_particles = kill->next;
505			kill->next = free_particles;
506			free_particles = kill;
507			continue;
508		}
509		break;
510	}
511
512	for (p=active_particles ; p ; p=p->next)
513	{
514		for ( ;; )
515		{
516			kill = p->next;
517			if (kill && kill->die < cl.time)
518			{
519				p->next = kill->next;
520				kill->next = free_particles;
521				free_particles = kill;
522				continue;
523			}
524			break;
525		}
526
527#ifdef GLQUAKE
528		// hack a scale up to keep particles from disapearing
529		scale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1]
530			+ (p->org[2] - r_origin[2])*vpn[2];
531		if (scale < 20)
532			scale = 1;
533		else
534			scale = 1 + scale * 0.004;
535		at = (byte *)&d_8to24table[(int)p->color];
536		if (p->type==pt_fire)
537			theAlpha = 255*(6-p->ramp)/6;
538//			theAlpha = 192;
539//		else if (p->type==pt_explode || p->type==pt_explode2)
540//			theAlpha = 255*(8-p->ramp)/8;
541		else
542			theAlpha = 255;
543
544#ifdef USE_OPENGLES
545	// !!! Implement this
546#else
547		glColor4ub (*at, *(at+1), *(at+2), theAlpha);
548//		glColor3ubv (at);
549//		glColor3ubv ((byte *)&d_8to24table[(int)p->color]);
550		glTexCoord2f (0,0);
551		glVertex3fv (p->org);
552		glTexCoord2f (1,0);
553		glVertex3f (p->org[0] + up[0]*scale, p->org[1] + up[1]*scale, p->org[2] + up[2]*scale);
554		glTexCoord2f (0,1);
555		glVertex3f (p->org[0] + right[0]*scale, p->org[1] + right[1]*scale, p->org[2] + right[2]*scale);
556#endif
557
558#else
559		D_DrawParticle (p);
560#endif
561
562		p->org[0] += p->vel[0]*frametime;
563		p->org[1] += p->vel[1]*frametime;
564		p->org[2] += p->vel[2]*frametime;
565
566		switch (p->type)
567		{
568		case pt_static:
569			break;
570		case pt_fire:
571			p->ramp += time1;
572			if (p->ramp >= 6)
573				p->die = -1;
574			else
575				p->color = ramp3[(int)p->ramp];
576			p->vel[2] += grav;
577			break;
578
579		case pt_explode:
580			p->ramp += time2;
581			if (p->ramp >=8)
582				p->die = -1;
583			else
584				p->color = ramp1[(int)p->ramp];
585			for (i=0 ; i<3 ; i++)
586				p->vel[i] += p->vel[i]*dvel;
587			p->vel[2] -= grav;
588			break;
589
590		case pt_explode2:
591			p->ramp += time3;
592			if (p->ramp >=8)
593				p->die = -1;
594			else
595				p->color = ramp2[(int)p->ramp];
596			for (i=0 ; i<3 ; i++)
597				p->vel[i] -= p->vel[i]*frametime;
598			p->vel[2] -= grav;
599			break;
600
601		case pt_blob:
602			for (i=0 ; i<3 ; i++)
603				p->vel[i] += p->vel[i]*dvel;
604			p->vel[2] -= grav;
605			break;
606
607		case pt_blob2:
608			for (i=0 ; i<2 ; i++)
609				p->vel[i] -= p->vel[i]*dvel;
610			p->vel[2] -= grav;
611			break;
612
613		case pt_slowgrav:
614		case pt_grav:
615			p->vel[2] -= grav;
616			break;
617		}
618	}
619
620#ifdef GLQUAKE
621#ifdef USE_OPENGLES
622	// !!! Implement this
623#else
624	glEnd ();
625#endif
626	glDisable (GL_BLEND);
627	if (alphaTestEnabled)
628		glEnable(GL_ALPHA_TEST);
629	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
630#else
631	D_EndParticles ();
632#endif
633}
634
635