Home | History | Annotate | Download | only in WinQuake
      1 /*
      2 Copyright (C) 1996-1997 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, 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 
     29 int		ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61};
     30 int		ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66};
     31 int		ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3};
     32 
     33 particle_t	*active_particles, *free_particles;
     34 
     35 particle_t	*particles;
     36 int			r_numparticles;
     37 
     38 vec3_t			r_pright, r_pup, r_ppn;
     39 
     40 
     41 /*
     42 ===============
     43 R_InitParticles
     44 ===============
     45 */
     46 void 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 #ifdef QUAKE2
     68 void R_DarkFieldParticles (entity_t *ent)
     69 {
     70 	int			i, j, k;
     71 	particle_t	*p;
     72 	float		vel;
     73 	vec3_t		dir;
     74 	vec3_t		org;
     75 
     76 	org[0] = ent->origin[0];
     77 	org[1] = ent->origin[1];
     78 	org[2] = ent->origin[2];
     79 	for (i=-16 ; i<16 ; i+=8)
     80 		for (j=-16 ; j<16 ; j+=8)
     81 			for (k=0 ; k<32 ; k+=8)
     82 			{
     83 				if (!free_particles)
     84 					return;
     85 				p = free_particles;
     86 				free_particles = p->next;
     87 				p->next = active_particles;
     88 				active_particles = p;
     89 
     90 				p->die = cl.time + 0.2 + (rand()&7) * 0.02;
     91 				p->color = 150 + rand()%6;
     92 				p->type = pt_slowgrav;
     93 
     94 				dir[0] = j*8;
     95 				dir[1] = i*8;
     96 				dir[2] = k*8;
     97 
     98 				p->org[0] = org[0] + i + (rand()&3);
     99 				p->org[1] = org[1] + j + (rand()&3);
    100 				p->org[2] = org[2] + k + (rand()&3);
    101 
    102 				VectorNormalize (dir);
    103 				vel = 50 + (rand()&63);
    104 				VectorScale (dir, vel, p->vel);
    105 			}
    106 }
    107 #endif
    108 
    109 
    110 /*
    111 ===============
    112 R_EntityParticles
    113 ===============
    114 */
    115 
    116 #define NUMVERTEXNORMALS	162
    117 extern	float	r_avertexnormals[NUMVERTEXNORMALS][3];
    118 vec3_t	avelocities[NUMVERTEXNORMALS];
    119 float	beamlength = 16;
    120 vec3_t	avelocity = {23, 7, 3};
    121 float	partstep = 0.01;
    122 float	timescale = 0.01;
    123 
    124 void R_EntityParticles (entity_t *ent)
    125 {
    126 	int			count;
    127 	int			i;
    128 	particle_t	*p;
    129 	float		angle;
    130 	float		sr, sp, sy, cr, cp, cy;
    131 	vec3_t		forward;
    132 	float		dist;
    133 
    134 	dist = 64;
    135 	count = 50;
    136 
    137 if (!avelocities[0][0])
    138 {
    139 for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
    140 avelocities[i/3][i%3] = (rand()&255) * 0.01;
    141 }
    142 
    143 
    144 	for (i=0 ; i<NUMVERTEXNORMALS ; i++)
    145 	{
    146 		angle = cl.time * avelocities[i][0];
    147 		sy = sin(angle);
    148 		cy = cos(angle);
    149 		angle = cl.time * avelocities[i][1];
    150 		sp = sin(angle);
    151 		cp = cos(angle);
    152 		angle = cl.time * avelocities[i][2];
    153 		sr = sin(angle);
    154 		cr = cos(angle);
    155 
    156 		forward[0] = cp*cy;
    157 		forward[1] = cp*sy;
    158 		forward[2] = -sp;
    159 
    160 		if (!free_particles)
    161 			return;
    162 		p = free_particles;
    163 		free_particles = p->next;
    164 		p->next = active_particles;
    165 		active_particles = p;
    166 
    167 		p->die = cl.time + 0.01;
    168 		p->color = 0x6f;
    169 		p->type = pt_explode;
    170 
    171 		p->org[0] = ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength;
    172 		p->org[1] = ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength;
    173 		p->org[2] = ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength;
    174 	}
    175 }
    176 
    177 
    178 /*
    179 ===============
    180 R_ClearParticles
    181 ===============
    182 */
    183 void R_ClearParticles (void)
    184 {
    185 	int		i;
    186 
    187 	free_particles = &particles[0];
    188 	active_particles = NULL;
    189 
    190 	for (i=0 ;i<r_numparticles ; i++)
    191 		particles[i].next = &particles[i+1];
    192 	particles[r_numparticles-1].next = NULL;
    193 }
    194 
    195 
    196 void R_ReadPointFile_f (void)
    197 {
    198 	FILE	*f;
    199 	vec3_t	org;
    200 	int		r;
    201 	int		c;
    202 	particle_t	*p;
    203 	char	name[MAX_OSPATH];
    204 
    205 	sprintf (name,"maps/%s.pts", sv.name);
    206 
    207 	COM_FOpenFile (name, &f);
    208 	if (!f)
    209 	{
    210 		Con_Printf ("couldn't open %s\n", name);
    211 		return;
    212 	}
    213 
    214 	Con_Printf ("Reading %s...\n", name);
    215 	c = 0;
    216 	for ( ;; )
    217 	{
    218 		r = fscanf (f,"%f %f %f\n", &org[0], &org[1], &org[2]);
    219 		if (r != 3)
    220 			break;
    221 		c++;
    222 
    223 		if (!free_particles)
    224 		{
    225 			Con_Printf ("Not enough free particles\n");
    226 			break;
    227 		}
    228 		p = free_particles;
    229 		free_particles = p->next;
    230 		p->next = active_particles;
    231 		active_particles = p;
    232 
    233 		p->die = 99999;
    234 		p->color = (-c)&15;
    235 		p->type = pt_static;
    236 		VectorCopy (vec3_origin, p->vel);
    237 		VectorCopy (org, p->org);
    238 	}
    239 
    240 	fclose (f);
    241 	Con_Printf ("%i points read\n", c);
    242 }
    243 
    244 /*
    245 ===============
    246 R_ParseParticleEffect
    247 
    248 Parse an effect out of the server message
    249 ===============
    250 */
    251 void R_ParseParticleEffect (void)
    252 {
    253 	vec3_t		org, dir;
    254 	int			i, count, msgcount, color;
    255 
    256 	for (i=0 ; i<3 ; i++)
    257 		org[i] = MSG_ReadCoord ();
    258 	for (i=0 ; i<3 ; i++)
    259 		dir[i] = MSG_ReadChar () * (1.0/16);
    260 	msgcount = MSG_ReadByte ();
    261 	color = MSG_ReadByte ();
    262 
    263 if (msgcount == 255)
    264 	count = 1024;
    265 else
    266 	count = msgcount;
    267 
    268 	R_RunParticleEffect (org, dir, color, count);
    269 }
    270 
    271 /*
    272 ===============
    273 R_ParticleExplosion
    274 
    275 ===============
    276 */
    277 void R_ParticleExplosion (vec3_t org)
    278 {
    279 	int			i, j;
    280 	particle_t	*p;
    281 
    282 	for (i=0 ; i<1024 ; i++)
    283 	{
    284 		if (!free_particles)
    285 			return;
    286 		p = free_particles;
    287 		free_particles = p->next;
    288 		p->next = active_particles;
    289 		active_particles = p;
    290 
    291 		p->die = cl.time + 5;
    292 		p->color = ramp1[0];
    293 		p->ramp = rand()&3;
    294 		if (i & 1)
    295 		{
    296 			p->type = pt_explode;
    297 			for (j=0 ; j<3 ; j++)
    298 			{
    299 				p->org[j] = org[j] + ((rand()%32)-16);
    300 				p->vel[j] = (rand()%512)-256;
    301 			}
    302 		}
    303 		else
    304 		{
    305 			p->type = pt_explode2;
    306 			for (j=0 ; j<3 ; j++)
    307 			{
    308 				p->org[j] = org[j] + ((rand()%32)-16);
    309 				p->vel[j] = (rand()%512)-256;
    310 			}
    311 		}
    312 	}
    313 }
    314 
    315 /*
    316 ===============
    317 R_ParticleExplosion2
    318 
    319 ===============
    320 */
    321 void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
    322 {
    323 	int			i, j;
    324 	particle_t	*p;
    325 	int			colorMod = 0;
    326 
    327 	for (i=0; i<512; i++)
    328 	{
    329 		if (!free_particles)
    330 			return;
    331 		p = free_particles;
    332 		free_particles = p->next;
    333 		p->next = active_particles;
    334 		active_particles = p;
    335 
    336 		p->die = cl.time + 0.3;
    337 		p->color = colorStart + (colorMod % colorLength);
    338 		colorMod++;
    339 
    340 		p->type = pt_blob;
    341 		for (j=0 ; j<3 ; j++)
    342 		{
    343 			p->org[j] = org[j] + ((rand()%32)-16);
    344 			p->vel[j] = (rand()%512)-256;
    345 		}
    346 	}
    347 }
    348 
    349 /*
    350 ===============
    351 R_BlobExplosion
    352 
    353 ===============
    354 */
    355 void R_BlobExplosion (vec3_t org)
    356 {
    357 	int			i, j;
    358 	particle_t	*p;
    359 
    360 	for (i=0 ; i<1024 ; i++)
    361 	{
    362 		if (!free_particles)
    363 			return;
    364 		p = free_particles;
    365 		free_particles = p->next;
    366 		p->next = active_particles;
    367 		active_particles = p;
    368 
    369 		p->die = cl.time + 1 + (rand()&8)*0.05;
    370 
    371 		if (i & 1)
    372 		{
    373 			p->type = pt_blob;
    374 			p->color = 66 + rand()%6;
    375 			for (j=0 ; j<3 ; j++)
    376 			{
    377 				p->org[j] = org[j] + ((rand()%32)-16);
    378 				p->vel[j] = (rand()%512)-256;
    379 			}
    380 		}
    381 		else
    382 		{
    383 			p->type = pt_blob2;
    384 			p->color = 150 + rand()%6;
    385 			for (j=0 ; j<3 ; j++)
    386 			{
    387 				p->org[j] = org[j] + ((rand()%32)-16);
    388 				p->vel[j] = (rand()%512)-256;
    389 			}
    390 		}
    391 	}
    392 }
    393 
    394 /*
    395 ===============
    396 R_RunParticleEffect
    397 
    398 ===============
    399 */
    400 void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
    401 {
    402 	int			i, j;
    403 	particle_t	*p;
    404 
    405 	for (i=0 ; i<count ; i++)
    406 	{
    407 		if (!free_particles)
    408 			return;
    409 		p = free_particles;
    410 		free_particles = p->next;
    411 		p->next = active_particles;
    412 		active_particles = p;
    413 
    414 		if (count == 1024)
    415 		{	// rocket explosion
    416 			p->die = cl.time + 5;
    417 			p->color = ramp1[0];
    418 			p->ramp = rand()&3;
    419 			if (i & 1)
    420 			{
    421 				p->type = pt_explode;
    422 				for (j=0 ; j<3 ; j++)
    423 				{
    424 					p->org[j] = org[j] + ((rand()%32)-16);
    425 					p->vel[j] = (rand()%512)-256;
    426 				}
    427 			}
    428 			else
    429 			{
    430 				p->type = pt_explode2;
    431 				for (j=0 ; j<3 ; j++)
    432 				{
    433 					p->org[j] = org[j] + ((rand()%32)-16);
    434 					p->vel[j] = (rand()%512)-256;
    435 				}
    436 			}
    437 		}
    438 		else
    439 		{
    440 			p->die = cl.time + 0.1*(rand()%5);
    441 			p->color = (color&~7) + (rand()&7);
    442 			p->type = pt_slowgrav;
    443 			for (j=0 ; j<3 ; j++)
    444 			{
    445 				p->org[j] = org[j] + ((rand()&15)-8);
    446 				p->vel[j] = dir[j]*15;// + (rand()%300)-150;
    447 			}
    448 		}
    449 	}
    450 }
    451 
    452 
    453 /*
    454 ===============
    455 R_LavaSplash
    456 
    457 ===============
    458 */
    459 void R_LavaSplash (vec3_t org)
    460 {
    461 	int			i, j, k;
    462 	particle_t	*p;
    463 	float		vel;
    464 	vec3_t		dir;
    465 
    466 	for (i=-16 ; i<16 ; i++)
    467 		for (j=-16 ; j<16 ; j++)
    468 			for (k=0 ; k<1 ; k++)
    469 			{
    470 				if (!free_particles)
    471 					return;
    472 				p = free_particles;
    473 				free_particles = p->next;
    474 				p->next = active_particles;
    475 				active_particles = p;
    476 
    477 				p->die = cl.time + 2 + (rand()&31) * 0.02;
    478 				p->color = 224 + (rand()&7);
    479 				p->type = pt_slowgrav;
    480 
    481 				dir[0] = j*8 + (rand()&7);
    482 				dir[1] = i*8 + (rand()&7);
    483 				dir[2] = 256;
    484 
    485 				p->org[0] = org[0] + dir[0];
    486 				p->org[1] = org[1] + dir[1];
    487 				p->org[2] = org[2] + (rand()&63);
    488 
    489 				VectorNormalize (dir);
    490 				vel = 50 + (rand()&63);
    491 				VectorScale (dir, vel, p->vel);
    492 			}
    493 }
    494 
    495 /*
    496 ===============
    497 R_TeleportSplash
    498 
    499 ===============
    500 */
    501 void R_TeleportSplash (vec3_t org)
    502 {
    503 	int			i, j, k;
    504 	particle_t	*p;
    505 	float		vel;
    506 	vec3_t		dir;
    507 
    508 	for (i=-16 ; i<16 ; i+=4)
    509 		for (j=-16 ; j<16 ; j+=4)
    510 			for (k=-24 ; k<32 ; k+=4)
    511 			{
    512 				if (!free_particles)
    513 					return;
    514 				p = free_particles;
    515 				free_particles = p->next;
    516 				p->next = active_particles;
    517 				active_particles = p;
    518 
    519 				p->die = cl.time + 0.2 + (rand()&7) * 0.02;
    520 				p->color = 7 + (rand()&7);
    521 				p->type = pt_slowgrav;
    522 
    523 				dir[0] = j*8;
    524 				dir[1] = i*8;
    525 				dir[2] = k*8;
    526 
    527 				p->org[0] = org[0] + i + (rand()&3);
    528 				p->org[1] = org[1] + j + (rand()&3);
    529 				p->org[2] = org[2] + k + (rand()&3);
    530 
    531 				VectorNormalize (dir);
    532 				vel = 50 + (rand()&63);
    533 				VectorScale (dir, vel, p->vel);
    534 			}
    535 }
    536 
    537 void R_RocketTrail (vec3_t start, vec3_t end, int type)
    538 {
    539 	vec3_t		vec;
    540 	float		len;
    541 	int			j;
    542 	particle_t	*p;
    543 	int			dec;
    544 	static int	tracercount;
    545 
    546 	VectorSubtract (end, start, vec);
    547 	len = VectorNormalize (vec);
    548 	if (type < 128)
    549 		dec = 3;
    550 	else
    551 	{
    552 		dec = 1;
    553 		type -= 128;
    554 	}
    555 
    556 	while (len > 0)
    557 	{
    558 		len -= dec;
    559 
    560 		if (!free_particles)
    561 			return;
    562 		p = free_particles;
    563 		free_particles = p->next;
    564 		p->next = active_particles;
    565 		active_particles = p;
    566 
    567 		VectorCopy (vec3_origin, p->vel);
    568 		p->die = cl.time + 2;
    569 
    570 		switch (type)
    571 		{
    572 			case 0:	// rocket trail
    573 				p->ramp = (rand()&3);
    574 				p->color = ramp3[(int)p->ramp];
    575 				p->type = pt_fire;
    576 				for (j=0 ; j<3 ; j++)
    577 					p->org[j] = start[j] + ((rand()%6)-3);
    578 				break;
    579 
    580 			case 1:	// smoke smoke
    581 				p->ramp = (rand()&3) + 2;
    582 				p->color = ramp3[(int)p->ramp];
    583 				p->type = pt_fire;
    584 				for (j=0 ; j<3 ; j++)
    585 					p->org[j] = start[j] + ((rand()%6)-3);
    586 				break;
    587 
    588 			case 2:	// blood
    589 				p->type = pt_grav;
    590 				p->color = 67 + (rand()&3);
    591 				for (j=0 ; j<3 ; j++)
    592 					p->org[j] = start[j] + ((rand()%6)-3);
    593 				break;
    594 
    595 			case 3:
    596 			case 5:	// tracer
    597 				p->die = cl.time + 0.5;
    598 				p->type = pt_static;
    599 				if (type == 3)
    600 					p->color = 52 + ((tracercount&4)<<1);
    601 				else
    602 					p->color = 230 + ((tracercount&4)<<1);
    603 
    604 				tracercount++;
    605 
    606 				VectorCopy (start, p->org);
    607 				if (tracercount & 1)
    608 				{
    609 					p->vel[0] = 30*vec[1];
    610 					p->vel[1] = 30*-vec[0];
    611 				}
    612 				else
    613 				{
    614 					p->vel[0] = 30*-vec[1];
    615 					p->vel[1] = 30*vec[0];
    616 				}
    617 				break;
    618 
    619 			case 4:	// slight blood
    620 				p->type = pt_grav;
    621 				p->color = 67 + (rand()&3);
    622 				for (j=0 ; j<3 ; j++)
    623 					p->org[j] = start[j] + ((rand()%6)-3);
    624 				len -= 3;
    625 				break;
    626 
    627 			case 6:	// voor trail
    628 				p->color = 9*16 + 8 + (rand()&3);
    629 				p->type = pt_static;
    630 				p->die = cl.time + 0.3;
    631 				for (j=0 ; j<3 ; j++)
    632 					p->org[j] = start[j] + ((rand()&15)-8);
    633 				break;
    634 		}
    635 
    636 
    637 		VectorAdd (start, vec, start);
    638 	}
    639 }
    640 
    641 
    642 /*
    643 ===============
    644 R_DrawParticles
    645 ===============
    646 */
    647 extern	cvar_t	sv_gravity;
    648 
    649 void R_DrawParticles (void)
    650 {
    651 	particle_t		*p, *kill;
    652 	float			grav;
    653 	int				i;
    654 	float			time2, time3;
    655 	float			time1;
    656 	float			dvel;
    657 	float			frametime;
    658 #ifdef USE_OPENGLES
    659 	float*			pPos = gVertexBuffer;
    660 	unsigned char*	pColor = (unsigned char*) gColorBuffer;
    661 	unsigned char*  pUV = (unsigned char*) gTexCoordBuffer;
    662 	int				particleIndex = 0;
    663 	int				maxParticleIndex = (int) sizeof(gVertexBuffer) / (sizeof(float) * 3) - 3;
    664 #endif
    665 #ifdef GLQUAKE
    666 	vec3_t			up, right;
    667 	float			scale;
    668 
    669 	GL_Bind(particletexture);
    670 
    671 	glEnable (GL_BLEND);
    672 	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    673 
    674 #ifdef USE_OPENGLES
    675 	glEnableClientState(GL_COLOR_ARRAY);
    676 	glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer);
    677 	glTexCoordPointer(2, GL_BYTE, 0, gTexCoordBuffer);
    678 	glColorPointer(4, GL_UNSIGNED_BYTE, 0, gColorBuffer);
    679 	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
    680 #else
    681 	glBegin (GL_TRIANGLES);
    682 #endif
    683 
    684 	VectorScale (vup, 1.5, up);
    685 	VectorScale (vright, 1.5, right);
    686 #else
    687 	D_StartParticles ();
    688 
    689 	VectorScale (vright, xscaleshrink, r_pright);
    690 	VectorScale (vup, yscaleshrink, r_pup);
    691 	VectorCopy (vpn, r_ppn);
    692 #endif
    693 	frametime = cl.time - cl.oldtime;
    694 	time3 = frametime * 15;
    695 	time2 = frametime * 10; // 15;
    696 	time1 = frametime * 5;
    697 	grav = frametime * sv_gravity.value * 0.05;
    698 	dvel = 4*frametime;
    699 
    700 	for ( ;; )
    701 	{
    702 		kill = active_particles;
    703 		if (kill && kill->die < cl.time)
    704 		{
    705 			active_particles = kill->next;
    706 			kill->next = free_particles;
    707 			free_particles = kill;
    708 			continue;
    709 		}
    710 		break;
    711 	}
    712 
    713 	for (p=active_particles ; p ; p=p->next)
    714 	{
    715 		for ( ;; )
    716 		{
    717 			kill = p->next;
    718 			if (kill && kill->die < cl.time)
    719 			{
    720 				p->next = kill->next;
    721 				kill->next = free_particles;
    722 				free_particles = kill;
    723 				continue;
    724 			}
    725 			break;
    726 		}
    727 
    728 #ifdef GLQUAKE
    729 		// hack a scale up to keep particles from disapearing
    730 		scale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1]
    731 			+ (p->org[2] - r_origin[2])*vpn[2];
    732 		if (scale < 20)
    733 			scale = 1;
    734 		else
    735 			scale = 1 + scale * 0.004;
    736 #ifdef USE_OPENGLES
    737 
    738 		if(particleIndex >= maxParticleIndex)
    739 		{
    740 			glDrawArrays(GL_TRIANGLES, 0, particleIndex);
    741 			particleIndex = 0;
    742 			pPos = gVertexBuffer;
    743 			pColor = (unsigned char*) gColorBuffer;
    744 			pUV = (unsigned char*) gTexCoordBuffer;
    745 		}
    746 
    747 		memcpy(pColor, (byte *)&d_8to24table[(int)p->color], 3);
    748 		pColor[3] = 255;
    749 		pColor += 4;
    750 		*pUV++ = 0;
    751 		*pUV++ = 0;
    752 		*pPos++ = p->org[0];
    753 		*pPos++ = p->org[1];
    754 		*pPos++ = p->org[2];
    755 
    756 		memcpy(pColor, (byte *)&d_8to24table[(int)p->color], 3);
    757 		pColor[3] = 255;
    758 		pColor += 4;
    759 		*pUV++ = 1;
    760 		*pUV++ = 0;
    761 		*pPos++ = p->org[0] + up[0]*scale;
    762 		*pPos++ = p->org[1] + up[1]*scale;
    763 		*pPos++ = p->org[2] + up[2]*scale;
    764 
    765 		memcpy(pColor, (byte *)&d_8to24table[(int)p->color], 3);
    766 		pColor[3] = 255;
    767 		pColor += 4;
    768 		*pUV++ = 0;
    769 		*pUV++ = 1;
    770 		*pPos++ = p->org[0] + right[0]*scale;
    771 		*pPos++ = p->org[1] + right[1]*scale;
    772 		*pPos++ = p->org[2] + right[2]*scale;
    773 
    774 		particleIndex += 3;
    775 
    776 #else
    777 		glColor3ubv ((byte *)&d_8to24table[(int)p->color]);
    778 		glTexCoord2f (0,0);
    779 		glVertex3fv (p->org);
    780 		glTexCoord2f (1,0);
    781 		glVertex3f (p->org[0] + up[0]*scale, p->org[1] + up[1]*scale, p->org[2] + up[2]*scale);
    782 		glTexCoord2f (0,1);
    783 		glVertex3f (p->org[0] + right[0]*scale, p->org[1] + right[1]*scale, p->org[2] + right[2]*scale);
    784 #endif // !USE_OPENGLES
    785 #else
    786 		D_DrawParticle (p);
    787 #endif
    788 		p->org[0] += p->vel[0]*frametime;
    789 		p->org[1] += p->vel[1]*frametime;
    790 		p->org[2] += p->vel[2]*frametime;
    791 
    792 		switch (p->type)
    793 		{
    794 		case pt_static:
    795 			break;
    796 		case pt_fire:
    797 			p->ramp += time1;
    798 			if (p->ramp >= 6)
    799 				p->die = -1;
    800 			else
    801 				p->color = ramp3[(int)p->ramp];
    802 			p->vel[2] += grav;
    803 			break;
    804 
    805 		case pt_explode:
    806 			p->ramp += time2;
    807 			if (p->ramp >=8)
    808 				p->die = -1;
    809 			else
    810 				p->color = ramp1[(int)p->ramp];
    811 			for (i=0 ; i<3 ; i++)
    812 				p->vel[i] += p->vel[i]*dvel;
    813 			p->vel[2] -= grav;
    814 			break;
    815 
    816 		case pt_explode2:
    817 			p->ramp += time3;
    818 			if (p->ramp >=8)
    819 				p->die = -1;
    820 			else
    821 				p->color = ramp2[(int)p->ramp];
    822 			for (i=0 ; i<3 ; i++)
    823 				p->vel[i] -= p->vel[i]*frametime;
    824 			p->vel[2] -= grav;
    825 			break;
    826 
    827 		case pt_blob:
    828 			for (i=0 ; i<3 ; i++)
    829 				p->vel[i] += p->vel[i]*dvel;
    830 			p->vel[2] -= grav;
    831 			break;
    832 
    833 		case pt_blob2:
    834 			for (i=0 ; i<2 ; i++)
    835 				p->vel[i] -= p->vel[i]*dvel;
    836 			p->vel[2] -= grav;
    837 			break;
    838 
    839 		case pt_grav:
    840 #ifdef QUAKE2
    841 			p->vel[2] -= grav * 20;
    842 			break;
    843 #endif
    844 		case pt_slowgrav:
    845 			p->vel[2] -= grav;
    846 			break;
    847 	    default:
    848 	        break;
    849 		}
    850 	}
    851 
    852 #ifdef GLQUAKE
    853 #ifdef USE_OPENGLES
    854 	glDrawArrays(GL_TRIANGLES, 0, particleIndex);
    855 	glDisableClientState(GL_COLOR_ARRAY);
    856 	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    857 #else
    858 	glEnd ();
    859 #endif
    860 	glDisable (GL_BLEND);
    861 	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    862 #else
    863 	D_EndParticles ();
    864 #endif
    865 }
    866 
    867