5c822d9b8f82d59f27c5a28bdc957f99e7851ece
[xonotic/darkplaces.git] / r_part.c
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
23 #define MAX_PARTICLES                   2048    // default max # of particles at one
24                                                                                 //  time
25 #define ABSOLUTE_MIN_PARTICLES  512             // no fewer than this no matter what's
26                                                                                 //  on the command line
27
28 int             ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61};
29 int             ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66};
30 int             ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3};
31
32 int             particletexture;
33 int             smokeparticletexture;
34 int             flareparticletexture;
35 int             rainparticletexture;
36 int             bloodcloudparticletexture;
37 int             bubbleparticletexture;
38
39 particle_t      *active_particles, *free_particles;
40
41 particle_t      *particles;
42 int                     r_numparticles;
43
44 vec3_t                  r_pright, r_pup, r_ppn;
45
46 //extern cvar_t r_particles/*, r_smoke*/, r_smokealpha;
47 //cvar_t r_smokecolor = {"r_smokecolor", "0"};
48
49 void fractalnoise(char *noise, int size);
50 void fractalnoise_zeroedge(char *noise, int size);
51
52 void R_InitParticleTexture (void)
53 {
54         int             x,y,d;
55         float   dx, dy, dz, f, dot;
56         byte    data[64][64][4], noise1[64][64], noise2[64][64];
57         vec3_t  normal, light;
58
59         particletexture = texture_extension_number++;
60     glBindTexture(GL_TEXTURE_2D, particletexture);
61
62         for (x=0 ; x<64 ; x++)
63         {
64                 for (y=0 ; y<64 ; y++)
65                 {
66                         data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
67                         dx = x - 16;
68                         dy = y - 16;
69                         d = (255 - (dx*dx+dy*dy));
70                         if (d < 0) d = 0;
71                         data[y][x][3] = (byte) d;
72                 }
73         }
74         glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
75
76         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
77
78         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
79         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
80
81
82         fractalnoise(&noise1[0][0], 64);
83         fractalnoise(&noise2[0][0], 64);
84         for (y = 0;y < 64;y++)
85                 for (x = 0;x < 64;x++)
86                 {
87                         data[y][x][0] = data[y][x][1] = data[y][x][2] = (noise1[y][x] >> 1) + 128;
88                         dx = x - 16;
89                         dy = y - 16;
90                         d = (noise2[y][x] * (255 - (dx*dx+dy*dy))) * (1.0f / 255.0f);
91                         if (d < 0) d = 0;
92                         if (d > 255) d = 255;
93                         data[y][x][3] = (byte) d;
94                 }
95
96         /*
97         for (x=0 ; x<34 ; x+=2)
98                 for (y=0 ; y<34 ; y+=2)
99                         data[y][x][0] = data[y][x][1] = data[y][x][2] = (rand()%64)+192;
100         for (x=0 ; x<32 ; x+=2)
101                 for (y=0 ; y<32 ; y+=2)
102                 {
103                         data[y  ][x+1][0] = data[y  ][x+1][1] = data[y  ][x+1][2] = (int) (data[y  ][x  ][0] + data[y  ][x+2][0]) >> 1;
104                         data[y+1][x  ][0] = data[y+1][x  ][1] = data[y+1][x  ][2] = (int) (data[y  ][x  ][0] + data[y+2][x  ][0]) >> 1;
105                         data[y+1][x+1][0] = data[y+1][x+1][1] = data[y+1][x+1][2] = (int) (data[y  ][x  ][0] + data[y  ][x+2][0] + data[y+2][x  ][0] + data[y+2][x+2][0]) >> 2;
106                 }
107         for (x=0 ; x<64 ; x++)
108         {
109                 for (y=0 ; y<64 ; y++)
110                 {
111                         //data[y][x][0] = data[y][x][1] = data[y][x][2] = (rand()%192)+64;
112                         dx = x - 16;
113                         dy = y - 16;
114                         d = (255 - (dx*dx+dy*dy));
115                         if (d < 0) d = 0;
116                         data[y][x][3] = (byte) d;
117                 }
118         }
119         */
120         smokeparticletexture = texture_extension_number++;
121         glBindTexture(GL_TEXTURE_2D, smokeparticletexture);
122         glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
123         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
124         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
125         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
126
127         fractalnoise(&noise1[0][0], 64);
128         fractalnoise(&noise2[0][0], 64);
129         for (y = 0;y < 64;y++)
130                 for (x = 0;x < 64;x++)
131                 {
132                         data[y][x][0] = data[y][x][1] = data[y][x][2] = (noise1[y][x] >> 1) + 128;
133                         dx = x - 16;
134                         dy = y - 16;
135                         d = (noise2[y][x] * (255 - (dx*dx+dy*dy))) * (1.0f / 255.0f);
136                         if (d < 0) d = 0;
137                         if (d > 255) d = 255;
138                         data[y][x][3] = (byte) d;
139                 }
140
141         bloodcloudparticletexture = texture_extension_number++;
142         glBindTexture(GL_TEXTURE_2D, bloodcloudparticletexture);
143         glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
144         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
145         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
146         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
147
148         flareparticletexture = texture_extension_number++;
149     glBindTexture(GL_TEXTURE_2D, flareparticletexture);
150
151         for (x=0 ; x<64 ; x++)
152         {
153                 for (y=0 ; y<64 ; y++)
154                 {
155                         data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
156                         dx = x - 16;
157                         dy = y - 16;
158                         d = 2048 / (dx*dx+dy*dy+1) - 32;
159                         d = bound(0, d, 255);
160                         data[y][x][3] = (byte) d;
161                 }
162         }
163         glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
164
165         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
166
167         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
168         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
169
170         rainparticletexture = texture_extension_number++;
171     glBindTexture(GL_TEXTURE_2D, rainparticletexture);
172
173         for (x=0 ; x<64 ; x++)
174         {
175                 for (y=0 ; y<64 ; y++)
176                 {
177                         data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
178                         if (y < 24) // stretch the upper half to make a raindrop
179                         {
180                                 dx = (x - 16)*2;
181                                 dy = (y - 24)*2/3;
182                                 d = (255 - (dx*dx+dy*dy))/2;
183                         }
184                         else
185                         {
186                                 dx = (x - 16)*2;
187                                 dy = (y - 24)*2;
188                                 d = (255 - (dx*dx+dy*dy))/2;
189                         }
190                         if (d < 0) d = 0;
191                         data[y][x][3] = (byte) d;
192                 }
193         }
194         glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
195
196         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
197
198         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
199         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
200
201         bubbleparticletexture = texture_extension_number++;
202     glBindTexture(GL_TEXTURE_2D, bubbleparticletexture);
203
204         light[0] = 1;light[1] = 1;light[2] = 1;
205         VectorNormalize(light);
206         for (x=0 ; x<64 ; x++)
207         {
208                 for (y=0 ; y<64 ; y++)
209                 {
210                         data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
211                         dx = x * (1.0 / 16.0) - 1.0;
212                         dy = y * (1.0 / 16.0) - 1.0;
213                         if (dx*dx+dy*dy < 1) // it does hit the sphere
214                         {
215                                 dz = 1 - (dx*dx+dy*dy);
216                                 f = 0;
217                                 // back side
218                                 normal[0] = dx;normal[1] = dy;normal[2] = dz;
219                                 VectorNormalize(normal);
220                                 dot = DotProduct(normal, light);
221                                 if (dot > 0.5) // interior reflection
222                                         f += ((dot *  2) - 1);
223                                 else if (dot < -0.5) // exterior reflection
224                                         f += ((dot * -2) - 1);
225                                 // front side
226                                 normal[0] = dx;normal[1] = dy;normal[2] = -dz;
227                                 VectorNormalize(normal);
228                                 dot = DotProduct(normal, light);
229                                 if (dot > 0.5) // interior reflection
230                                         f += ((dot *  2) - 1);
231                                 else if (dot < -0.5) // exterior reflection
232                                         f += ((dot * -2) - 1);
233                                 f *= 255;
234                                 f = bound(0, f, 255);
235                                 data[y][x][3] = (byte) d;
236                         }
237                         else
238                                 data[y][x][3] = 0;
239                 }
240         }
241         glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
242
243         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
244
245         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
246         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
247 }
248
249 /*
250 ===============
251 R_InitParticles
252 ===============
253 */
254 void R_InitParticles (void)
255 {
256         int             i;
257
258         i = COM_CheckParm ("-particles");
259
260         if (i)
261         {
262                 r_numparticles = (int)(atoi(com_argv[i+1]));
263                 if (r_numparticles < ABSOLUTE_MIN_PARTICLES)
264                         r_numparticles = ABSOLUTE_MIN_PARTICLES;
265         }
266         else
267         {
268                 r_numparticles = MAX_PARTICLES;
269         }
270
271         particles = (particle_t *) Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles");
272
273 //      Cvar_RegisterVariable (&r_smokecolor);
274         R_InitParticleTexture ();
275 }
276
277 /*
278 ===============
279 R_EntityParticles
280 ===============
281 */
282
283 #define NUMVERTEXNORMALS        162
284 extern  float   r_avertexnormals[NUMVERTEXNORMALS][3];
285 vec3_t  avelocities[NUMVERTEXNORMALS];
286 float   beamlength = 16;
287 vec3_t  avelocity = {23, 7, 3};
288 float   partstep = 0.01;
289 float   timescale = 0.01;
290
291 void R_EntityParticles (entity_t *ent)
292 {
293         int                     count;
294         int                     i;
295         particle_t      *p;
296         float           angle;
297         float           sr, sp, sy, cr, cp, cy;
298         vec3_t          forward;
299         float           dist;
300 //      if (!r_particles.value) return; // LordHavoc: particles are optional
301         
302         dist = 64;
303         count = 50;
304
305 if (!avelocities[0][0])
306 {
307 for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
308 avelocities[0][i] = (rand()&255) * 0.01;
309 }
310
311
312         for (i=0 ; i<NUMVERTEXNORMALS ; i++)
313         {
314                 angle = cl.time * avelocities[i][0];
315                 sy = sin(angle);
316                 cy = cos(angle);
317                 angle = cl.time * avelocities[i][1];
318                 sp = sin(angle);
319                 cp = cos(angle);
320                 angle = cl.time * avelocities[i][2];
321                 sr = sin(angle);
322                 cr = cos(angle);
323         
324                 forward[0] = cp*cy;
325                 forward[1] = cp*sy;
326                 forward[2] = -sp;
327
328                 if (!free_particles)
329                         return;
330                 p = free_particles;
331                 free_particles = p->next;
332                 p->next = active_particles;
333                 active_particles = p;
334
335                 p->texnum = flareparticletexture;
336                 p->scale = 2;
337                 p->alpha = 255;
338                 p->die = cl.time + 0.01;
339                 p->color = 0x6f;
340                 p->type = pt_explode;
341                 
342                 p->org[0] = ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength;                       
343                 p->org[1] = ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength;                       
344                 p->org[2] = ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength;                       
345         }
346 }
347
348
349 /*
350 ===============
351 R_ClearParticles
352 ===============
353 */
354 void R_ClearParticles (void)
355 {
356         int             i;
357         
358         free_particles = &particles[0];
359         active_particles = NULL;
360
361         for (i=0 ;i<r_numparticles ; i++)
362                 particles[i].next = &particles[i+1];
363         particles[r_numparticles-1].next = NULL;
364 }
365
366
367 void R_ReadPointFile_f (void)
368 {
369         FILE    *f;
370         vec3_t  org;
371         int             r;
372         int             c;
373         particle_t      *p;
374         char    name[MAX_OSPATH];
375         
376         sprintf (name,"maps/%s.pts", sv.name);
377
378         COM_FOpenFile (name, &f, false);
379         if (!f)
380         {
381                 Con_Printf ("couldn't open %s\n", name);
382                 return;
383         }
384         
385         Con_Printf ("Reading %s...\n", name);
386         c = 0;
387         for ( ;; )
388         {
389                 r = fscanf (f,"%f %f %f\n", &org[0], &org[1], &org[2]);
390                 if (r != 3)
391                         break;
392                 c++;
393                 
394                 if (!free_particles)
395                 {
396                         Con_Printf ("Not enough free particles\n");
397                         break;
398                 }
399                 p = free_particles;
400                 free_particles = p->next;
401                 p->next = active_particles;
402                 active_particles = p;
403                 
404                 p->texnum = particletexture;
405                 p->scale = 2;
406                 p->alpha = 255;
407                 p->die = 99999;
408                 p->color = (-c)&15;
409                 p->type = pt_static;
410                 VectorCopy (vec3_origin, p->vel);
411                 VectorCopy (org, p->org);
412         }
413
414         fclose (f);
415         Con_Printf ("%i points read\n", c);
416 }
417
418 /*
419 ===============
420 R_ParseParticleEffect
421
422 Parse an effect out of the server message
423 ===============
424 */
425 void R_ParseParticleEffect (void)
426 {
427         vec3_t          org, dir;
428         int                     i, count, msgcount, color;
429         
430         for (i=0 ; i<3 ; i++)
431                 org[i] = MSG_ReadCoord ();
432         for (i=0 ; i<3 ; i++)
433                 dir[i] = MSG_ReadChar () * (1.0/16);
434         msgcount = MSG_ReadByte ();
435         color = MSG_ReadByte ();
436
437 if (msgcount == 255)
438         count = 1024;
439 else
440         count = msgcount;
441         
442         R_RunParticleEffect (org, dir, color, count);
443 }
444         
445 /*
446 ===============
447 R_ParticleExplosion
448
449 ===============
450 */
451 void R_ParticleExplosion (vec3_t org, int smoke)
452 {
453         int                     i, j;
454         particle_t      *p;
455 //      if (!r_particles.value) return; // LordHavoc: particles are optional
456         
457         for (i=0 ; i<1024 ; i++)
458         {
459                 if (!free_particles)
460                         return;
461                 p = free_particles;
462                 free_particles = p->next;
463                 p->next = active_particles;
464                 active_particles = p;
465
466                 p->texnum = flareparticletexture;
467                 p->scale = 4+(rand()&7);
468                 p->alpha = rand()&255;
469                 p->die = cl.time + 5;
470                 p->color = ramp1[0];
471                 p->ramp = rand()&3;
472                 /*
473                 if (i & 1)
474                         p->type = pt_explode;
475                 else
476                         p->type = pt_explode2;
477                 */
478                 p->color = ramp1[rand()&7];
479                 p->type = pt_fallfadespark;
480                 for (j=0 ; j<3 ; j++)
481                 {
482                         p->org[j] = org[j] + ((rand()&63)-32);
483                         p->vel[j] = (rand()&511)-256;
484                 }
485                 p->vel[j] += 200;
486         }
487
488         if (smoke)
489         {
490                 for (i=0 ; i<32 ; i++)
491                 {
492                         if (!free_particles)
493                                 return;
494                         p = free_particles;
495                         free_particles = p->next;
496                         p->next = active_particles;
497                         active_particles = p;
498
499                         p->texnum = smokeparticletexture;
500                         p->scale = 24;
501                         p->alpha = 80;
502                         p->die = cl.time + 2;
503                         p->type = pt_smoke;
504                         p->color = (rand()&7) + 8;
505                         for (j=0 ; j<3 ; j++)
506                         {
507                                 p->org[j] = org[j] + ((rand()%96)-48);
508                                 p->vel[j] = (rand()&63)-32;
509                         }
510                 }
511         }
512 }
513
514 /*
515 ===============
516 R_ParticleExplosion2
517
518 ===============
519 */
520 void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
521 {
522         int                     i, j;
523         particle_t      *p;
524         int                     colorMod = 0;
525 //      if (!r_particles.value) return; // LordHavoc: particles are optional
526
527         for (i=0; i<512; i++)
528         {
529                 if (!free_particles)
530                         return;
531                 p = free_particles;
532                 free_particles = p->next;
533                 p->next = active_particles;
534                 active_particles = p;
535
536                 p->texnum = flareparticletexture;
537                 p->scale = 8;
538                 p->alpha = 255;
539                 p->die = cl.time + 0.3;
540                 p->color = colorStart + (colorMod % colorLength);
541                 colorMod++;
542
543                 p->type = pt_blob;
544                 for (j=0 ; j<3 ; j++)
545                 {
546                         p->org[j] = org[j] + ((rand()%32)-16);
547                         p->vel[j] = (rand()%512)-256;
548                 }
549         }
550 }
551
552 /*
553 ===============
554 R_BlobExplosion
555
556 ===============
557 */
558 void R_BlobExplosion (vec3_t org)
559 {
560         int                     i, j;
561         particle_t      *p;
562 //      if (!r_particles.value) return; // LordHavoc: particles are optional
563         
564         for (i=0 ; i<1024 ; i++)
565         {
566                 if (!free_particles)
567                         return;
568                 p = free_particles;
569                 free_particles = p->next;
570                 p->next = active_particles;
571                 active_particles = p;
572
573                 p->texnum = flareparticletexture;
574                 p->scale = 8;
575                 p->alpha = 255;
576                 p->die = cl.time + 1 + (rand()&8)*0.05;
577
578                 if (i & 1)
579                 {
580                         p->type = pt_blob;
581                         p->color = 66 + rand()%6;
582                         for (j=0 ; j<3 ; j++)
583                         {
584                                 p->org[j] = org[j] + ((rand()%32)-16);
585                                 p->vel[j] = (rand()%512)-256;
586                         }
587                 }
588                 else
589                 {
590                         p->type = pt_blob2;
591                         p->color = 150 + rand()%6;
592                         for (j=0 ; j<3 ; j++)
593                         {
594                                 p->org[j] = org[j] + ((rand()%32)-16);
595                                 p->vel[j] = (rand()%512)-256;
596                         }
597                 }
598         }
599 }
600
601 /*
602 ===============
603 R_RunParticleEffect
604
605 ===============
606 */
607 void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
608 {
609         int                     i, j;
610         particle_t      *p;
611 //      if (!r_particles.value) return; // LordHavoc: particles are optional
612         
613         for (i=0 ; i<count ; i++)
614         {
615                 if (!free_particles)
616                         return;
617                 p = free_particles;
618                 free_particles = p->next;
619                 p->next = active_particles;
620                 active_particles = p;
621
622                 if (count == 1024)
623                 {       // rocket explosion
624                         p->texnum = flareparticletexture;
625                         p->scale = 8;
626                         p->alpha = 255;
627                         p->die = cl.time + 5;
628                         p->color = ramp1[0];
629                         p->ramp = rand()&3;
630                         if (i & 1)
631                         {
632                                 p->type = pt_explode;
633                                 for (j=0 ; j<3 ; j++)
634                                 {
635                                         p->org[j] = org[j] + ((rand()%32)-16);
636                                         p->vel[j] = (rand()%512)-256;
637                                 }
638                         }
639                         else
640                         {
641                                 p->type = pt_explode2;
642                                 for (j=0 ; j<3 ; j++)
643                                 {
644                                         p->org[j] = org[j] + ((rand()%32)-16);
645                                         p->vel[j] = (rand()%512)-256;
646                                 }
647                         }
648                 }
649                 else
650                 {
651                         p->texnum = flareparticletexture;
652                         p->scale = 8;
653                         p->alpha = 255;
654                         p->die = cl.time + 0.1*(rand()%5);
655                         p->color = (color&~7) + (rand()&7);
656                         p->type = pt_static; //slowgrav;
657                         for (j=0 ; j<3 ; j++)
658                         {
659                                 p->org[j] = org[j] + ((rand()&15)-8);
660                                 p->vel[j] = dir[j]*15;// + (rand()%300)-150;
661                         }
662                 }
663         }
664 }
665
666 // LordHavoc: added this for spawning sparks/dust (which have strong gravity)
667 /*
668 ===============
669 R_SparkShower
670
671 ===============
672 */
673 void R_SparkShower (vec3_t org, vec3_t dir, int count, int type)
674 {
675         int                     i, j;
676         particle_t      *p;
677 //      if (!r_particles.value) return; // LordHavoc: particles are optional
678
679         if (!free_particles)
680                 return;
681         p = free_particles;
682         free_particles = p->next;
683         p->next = active_particles;
684         active_particles = p;
685         if (type == 0) // sparks
686         {
687                 p->texnum = smokeparticletexture;
688                 p->scale = 20;
689                 p->alpha = 64;
690                 p->color = (rand()&3)+12;
691                 p->type = pt_bulletpuff;
692                 p->die = cl.time + 1;
693                 VectorCopy(org, p->org);
694                 p->vel[0] = p->vel[1] = p->vel[2] = 0;
695         }
696         else // blood
697         {
698                 p->texnum = bloodcloudparticletexture;
699                 p->scale = 24;
700                 p->alpha = 128;
701                 p->color = (rand()&3)+68;
702                 p->type = pt_bloodcloud;
703                 p->die = cl.time + 0.5;
704                 VectorCopy(org, p->org);
705                 p->vel[0] = p->vel[1] = p->vel[2] = 0;
706                 return;
707         }
708         for (i=0 ; i<count ; i++)
709         {
710                 if (!free_particles)
711                         return;
712                 p = free_particles;
713                 free_particles = p->next;
714                 p->next = active_particles;
715                 active_particles = p;
716
717                 p->texnum = flareparticletexture;
718                 p->scale = 5;
719                 p->alpha = 255;
720                 p->die = cl.time + 0.0625 * (rand()&15);
721                 /*
722                 if (type == 0) // sparks
723                 {
724                 */
725                         p->type = pt_dust;
726                         p->ramp = (rand()&3);
727                         p->color = ramp1[(int)p->ramp];
728                         for (j=0 ; j<3 ; j++)
729                         {
730                                 p->org[j] = org[j] + ((rand()&7)-4);
731                                 p->vel[j] = dir[j] + (rand()%192)-96;
732                         }
733                 /*
734                 }
735                 else // blood
736                 {
737                         p->type = pt_fadespark2;
738                         p->color = 67 + (rand()&3);
739                         for (j=0 ; j<3 ; j++)
740                         {
741                                 p->org[j] = org[j] + (rand()&7)-4;
742                                 p->vel[j] = dir[j] + (rand()&63)-32;
743                         }
744                 }
745                 */
746         }
747 }
748
749 void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count)
750 {
751         int                     i, j;
752         particle_t      *p;
753         vec3_t          diff;
754         vec3_t          center;
755         vec3_t          velscale;
756 //      if (!r_particles.value) return; // LordHavoc: particles are optional
757
758         VectorSubtract(maxs, mins, diff);
759         center[0] = (mins[0] + maxs[0]) * 0.5;
760         center[1] = (mins[1] + maxs[1]) * 0.5;
761         center[2] = (mins[2] + maxs[2]) * 0.5;
762         velscale[0] = velspeed * 2.0 / diff[0];
763         velscale[1] = velspeed * 2.0 / diff[1];
764         velscale[2] = velspeed * 2.0 / diff[2];
765         
766         for (i=0 ; i<count ; i++)
767         {
768                 if (!free_particles)
769                         return;
770                 p = free_particles;
771                 free_particles = p->next;
772                 p->next = active_particles;
773                 active_particles = p;
774
775                 p->texnum = bloodcloudparticletexture;
776                 p->scale = 24;
777                 p->alpha = 96 + (rand()&63);
778                 p->die = cl.time + 2; //0.015625 * (rand()%128);
779                 p->type = pt_fadespark;
780                 p->color = (rand()&3)+68;
781 //              p->color = 67 + (rand()&3);
782                 for (j=0 ; j<3 ; j++)
783                 {
784                         p->org[j] = diff[j] * (float) (rand()%1024) * (1.0 / 1024.0) + mins[j];
785                         p->vel[j] = (p->org[j] - center[j]) * velscale[j];
786                 }
787         }
788 }
789
790 void R_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int gravity, int randomvel)
791 {
792         int                     i, j;
793         particle_t      *p;
794         vec3_t          diff;
795         float           t;
796 //      if (!r_particles.value) return; // LordHavoc: particles are optional
797         if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
798         if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
799         if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
800
801         VectorSubtract(maxs, mins, diff);
802         
803         for (i=0 ; i<count ; i++)
804         {
805                 if (!free_particles)
806                         return;
807                 p = free_particles;
808                 free_particles = p->next;
809                 p->next = active_particles;
810                 active_particles = p;
811
812                 p->texnum = flareparticletexture;
813                 p->scale = 12;
814                 p->alpha = 255;
815                 p->die = cl.time + 1 + (rand()&15)*0.0625;
816                 if (gravity)
817                         p->type = pt_grav;
818                 else
819                         p->type = pt_static;
820                 p->color = colorbase + (rand()&3);
821                 for (j=0 ; j<3 ; j++)
822                 {
823                         p->org[j] = diff[j] * (float) (rand()&1023) * (1.0 / 1024.0) + mins[j];
824                         if (randomvel)
825                                 p->vel[j] = dir[j] + (rand()%randomvel)-(randomvel*0.5);
826                         else
827                                 p->vel[j] = 0;
828                 }
829         }
830 }
831
832 void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int type)
833 {
834         int                     i;
835         particle_t      *p;
836         vec3_t          diff;
837         vec3_t          org;
838         vec3_t          vel;
839         float           t, z;
840 //      if (!r_particles.value) return; // LordHavoc: particles are optional
841         if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
842         if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
843         if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
844         if (dir[2] < 0) // falling
845         {
846                 t = (maxs[2] - mins[2]) / -dir[2];
847                 z = maxs[2];
848         }
849         else // rising??
850         {
851                 t = (maxs[2] - mins[2]) / dir[2];
852                 z = mins[2];
853         }
854         if (t < 0 || t > 2) // sanity check
855                 t = 2;
856         t += cl.time;
857
858         VectorSubtract(maxs, mins, diff);
859         
860         for (i=0 ; i<count ; i++)
861         {
862                 if (!free_particles)
863                         return;
864                 p = free_particles;
865                 free_particles = p->next;
866                 p->next = active_particles;
867                 active_particles = p;
868
869                 vel[0] = dir[0] + (rand()&31) - 16;
870                 vel[1] = dir[1] + (rand()&31) - 16;
871                 vel[2] = dir[2] + (rand()&63) - 32;
872                 org[0] = diff[0] * (float) (rand()&1023) * (1.0 / 1024.0) + mins[0];
873                 org[1] = diff[1] * (float) (rand()&1023) * (1.0 / 1024.0) + mins[1];
874                 org[2] = z;
875
876                 p->scale = 6;
877                 p->alpha = 255;
878                 p->die = t;
879                 if (type == 1)
880                 {
881                         p->texnum = particletexture;
882                         p->type = pt_snow;
883                 }
884                 else // 0
885                 {
886                         p->texnum = rainparticletexture;
887                         p->type = pt_static;
888                 }
889                 p->color = colorbase + (rand()&3);
890                 VectorCopy(org, p->org);
891                 VectorCopy(vel, p->vel);
892         }
893 }
894
895
896 /*
897 ===============
898 R_LavaSplash
899
900 ===============
901 */
902 void R_LavaSplash (vec3_t org)
903 {
904         int                     i, j, k;
905         particle_t      *p;
906         float           vel;
907         vec3_t          dir;
908 //      if (!r_particles.value) return; // LordHavoc: particles are optional
909
910         for (i=-16 ; i<16 ; i+=2)
911                 for (j=-16 ; j<16 ; j+=2)
912                         for (k=0 ; k<1 ; k++)
913                         {
914                                 if (!free_particles)
915                                         return;
916                                 p = free_particles;
917                                 free_particles = p->next;
918                                 p->next = active_particles;
919                                 active_particles = p;
920                 
921                                 p->texnum = flareparticletexture;
922                                 p->scale = 24;
923                                 p->alpha = 255;
924                                 p->die = cl.time + 2 + (rand()&31) * 0.02;
925                                 p->color = 224 + (rand()&7);
926                                 p->type = pt_slowgrav;
927                                 
928                                 dir[0] = j*8 + (rand()&7);
929                                 dir[1] = i*8 + (rand()&7);
930                                 dir[2] = 256;
931         
932                                 p->org[0] = org[0] + dir[0];
933                                 p->org[1] = org[1] + dir[1];
934                                 p->org[2] = org[2] + (rand()&63);
935         
936                                 VectorNormalize (dir);                                          
937                                 vel = 50 + (rand()&63);
938                                 VectorScale (dir, vel, p->vel);
939                         }
940 }
941
942 /*
943 ===============
944 R_TeleportSplash
945
946 ===============
947 */
948 void R_TeleportSplash (vec3_t org)
949 {
950         int                     i, j, k;
951         particle_t      *p;
952 //      vec3_t          dir;
953 //      if (!r_particles.value) return; // LordHavoc: particles are optional
954
955         /*
956         for (i=-16 ; i<16 ; i+=4)
957                 for (j=-16 ; j<16 ; j+=4)
958                         for (k=-24 ; k<32 ; k+=4)
959                         {
960                                 if (!free_particles)
961                                         return;
962                                 p = free_particles;
963                                 free_particles = p->next;
964                                 p->next = active_particles;
965                                 active_particles = p;
966                 
967                                 p->texnum = particletexture;
968                                 p->scale = 2;
969                                 p->alpha = 255;
970                                 p->die = cl.time + 0.2 + (rand()&7) * 0.02;
971                                 p->color = 7 + (rand()&7);
972                                 p->type = pt_slowgrav;
973                                 
974                                 dir[0] = j*8;
975                                 dir[1] = i*8;
976                                 dir[2] = k*8;
977         
978                                 p->org[0] = org[0] + i + (rand()&3);
979                                 p->org[1] = org[1] + j + (rand()&3);
980                                 p->org[2] = org[2] + k + (rand()&3);
981         
982                                 VectorNormalize (dir);                                          
983                                 vel = 50 + (rand()&63);
984                                 VectorScale (dir, vel, p->vel);
985                         }
986         */
987
988         for (i=-24 ; i<24 ; i+=8)
989                 for (j=-24 ; j<24 ; j+=8)
990                         for (k=-24 ; k<32 ; k+=8)
991                         {
992                                 if (!free_particles)
993                                         return;
994                                 p = free_particles;
995                                 free_particles = p->next;
996                                 p->next = active_particles;
997                                 active_particles = p;
998                 
999                                 p->texnum = flareparticletexture;
1000                                 p->scale = 8;
1001                                 p->alpha = (1 + rand()&7) * 32;
1002                                 p->die = cl.time + 5;
1003                                 p->color = 254; //8 + (rand()&7);
1004                                 p->type = pt_fadespark;
1005                                 
1006                                 p->org[0] = org[0] + i + (rand()&7);
1007                                 p->org[1] = org[1] + j + (rand()&7);
1008                                 p->org[2] = org[2] + k + (rand()&7);
1009         
1010                                 p->vel[0] = i*2 + (rand()%25) - 12;
1011                                 p->vel[1] = j*2 + (rand()%25) - 12;
1012                                 p->vel[2] = k*2 + (rand()%25) - 12 + 40;
1013                         }
1014 }
1015
1016 void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
1017 {
1018         vec3_t          vec;
1019         float           len, dec, t, nt, speed;
1020         int                     j, contents, bubbles;
1021         particle_t      *p;
1022         static int      tracercount;
1023 //      if (!r_particles.value) return; // LordHavoc: particles are optional
1024
1025         t = cl.oldtime;
1026         nt = cl.time;
1027         if (ent->trail_leftover < 0)
1028                 ent->trail_leftover = 0;
1029         t += ent->trail_leftover;
1030         ent->trail_leftover -= (cl.time - cl.oldtime);
1031         if (t >= cl.time)
1032                 return;
1033
1034         contents = Mod_PointInLeaf(start, cl.worldmodel)->contents;
1035         if (contents == CONTENTS_SKY || contents == CONTENTS_LAVA)
1036                 return;
1037
1038         VectorSubtract (end, start, vec);
1039         len = VectorNormalizeLength (vec);
1040         if (len <= 0.01f)
1041                 return;
1042         speed = len / (nt - t);
1043
1044         bubbles = (contents == CONTENTS_WATER || contents == CONTENTS_SLIME);
1045
1046         while (t < nt)
1047         {
1048                 if (!free_particles)
1049                         return;
1050                 p = free_particles;
1051                 free_particles = p->next;
1052                 p->next = active_particles;
1053                 active_particles = p;
1054                 
1055                 p->vel[0] = p->vel[1] = p->vel[2] = 0;
1056                 p->die = cl.time + 2;
1057
1058                 switch (type)
1059                 {
1060                         case 0: // rocket trail
1061                         case 1: // grenade trail
1062                                 if (bubbles)
1063                                 {
1064                                         dec = 0.01f;
1065                                         p->texnum = bubbleparticletexture;
1066                                         p->scale = 6+(rand()&3);
1067                                         p->alpha = 255;
1068 //                                      if (r_smokecolor.value)
1069 //                                              p->color = r_smokecolor.value;
1070 //                                      else
1071                                                 p->color = (rand()&3)+12;
1072                                         p->type = pt_bubble;
1073                                         p->die = cl.time + 2;
1074                                         for (j=0 ; j<3 ; j++)
1075                                         {
1076                                                 p->vel[j] = (rand()&31)-16;
1077                                                 p->org[j] = start[j] + ((rand()&3)-2);
1078                                         }
1079                                 }
1080                                 else
1081                                 {
1082                                         dec = 0.03f;
1083                                         p->texnum = smokeparticletexture;
1084                                         p->scale = 12+(rand()&7);
1085                                         p->alpha = 64 + (rand()&31);
1086 //                                      if (r_smokecolor.value)
1087 //                                              p->color = r_smokecolor.value;
1088 //                                      else
1089                                                 p->color = (rand()&3)+12;
1090                                         p->type = pt_smoke;
1091                                         p->die = cl.time + 2;
1092                                         VectorCopy(start, p->org);
1093                                 }
1094                                 break;
1095
1096                                 /*
1097                         case 1: // smoke smoke
1098                                 dec = 0.016f;
1099                                 p->texnum = smokeparticletexture;
1100                                 p->scale = 12+rand()&7;
1101                                 p->alpha = 64;
1102                                 if (r_smokecolor.value)
1103                                         p->color = r_smokecolor.value;
1104                                 else
1105                                         p->color = (rand()&3)+12;
1106                                 p->type = pt_smoke;
1107                                 p->die = cl.time + 1;
1108                                 VectorCopy(start, p->org);
1109                                 break;
1110                                 */
1111
1112                         case 2: // blood
1113                                 dec = 0.03f;
1114                                 p->texnum = bloodcloudparticletexture;
1115                                 p->scale = 20+(rand()&7);
1116                                 p->alpha = 255;
1117                                 p->color = (rand()&3)+68;
1118                                 p->type = pt_bloodcloud;
1119                                 p->die = cl.time + 2;
1120                                 for (j=0 ; j<3 ; j++)
1121                                 {
1122                                         p->vel[j] = (rand()&15)-8;
1123                                         p->org[j] = start[j] + ((rand()&3)-2);
1124                                 }
1125                                 break;
1126
1127                         case 3:
1128                         case 5: // tracer
1129                                 dec = 0.01f;
1130                                 p->texnum = flareparticletexture;
1131                                 p->scale = 4;
1132                                 p->alpha = 255;
1133                                 p->die = cl.time + 0.2; //5;
1134                                 p->type = pt_static;
1135                                 if (type == 3)
1136                                         p->color = 52 + ((tracercount&4)<<1);
1137                                 else
1138                                         p->color = 230 + ((tracercount&4)<<1);
1139
1140                                 tracercount++;
1141
1142                                 VectorCopy (start, p->org);
1143                                 if (tracercount & 1)
1144                                 {
1145                                         p->vel[0] = 30*vec[1];
1146                                         p->vel[1] = 30*-vec[0];
1147                                 }
1148                                 else
1149                                 {
1150                                         p->vel[0] = 30*-vec[1];
1151                                         p->vel[1] = 30*vec[0];
1152                                 }
1153                                 break;
1154
1155                         case 4: // slight blood
1156                                 dec = 0.03f; // sparse trail
1157                                 p->texnum = bloodcloudparticletexture;
1158                                 p->scale = 20+(rand()&7);
1159                                 p->alpha = 255;
1160                                 p->color = (rand()&3)+68;
1161                                 p->type = pt_fadespark2;
1162                                 p->die = cl.time + 2;
1163                                 for (j=0 ; j<3 ; j++)
1164                                 {
1165                                         p->vel[j] = (rand()&15)-8;
1166                                         p->org[j] = start[j] + ((rand()&3)-2);
1167                                 }
1168                                 break;
1169
1170                         case 6: // voor trail
1171                                 dec = 0.05f; // sparse trail
1172                                 p->texnum = flareparticletexture;
1173                                 p->scale = 20+(rand()&7);
1174                                 p->alpha = 255;
1175                                 p->color = 9*16 + 8 + (rand()&3);
1176                                 p->type = pt_fadespark2;
1177                                 p->die = cl.time + 2;
1178                                 for (j=0 ; j<3 ; j++)
1179                                 {
1180                                         p->vel[j] = (rand()&15)-8;
1181                                         p->org[j] = start[j] + ((rand()&3)-2);
1182                                 }
1183                                 break;
1184
1185                         case 7: // Nehahra smoke tracer
1186                                 dec = 0.14f;
1187                                 p->texnum = smokeparticletexture;
1188                                 p->scale = 12+(rand()&7);
1189                                 p->alpha = 64;
1190                                 p->color = (rand()&3)+12;
1191                                 p->type = pt_smoke;
1192                                 p->die = cl.time + 1;
1193                                 for (j=0 ; j<3 ; j++)
1194                                         p->org[j] = start[j] + ((rand()&3)-2);
1195                                 break;
1196                 }
1197                 
1198                 t += dec;
1199                 dec *= speed;
1200                 VectorMA (start, dec, vec, start);
1201         }
1202         ent->trail_leftover = t - cl.time;
1203 }
1204
1205 void R_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent)
1206 {
1207         vec3_t          vec;
1208         float           len;
1209         particle_t      *p;
1210         static int      tracercount;
1211 //      if (!r_particles.value) return; // LordHavoc: particles are optional
1212
1213         VectorSubtract (end, start, vec);
1214         len = VectorNormalizeLength (vec);
1215         while (len > 0)
1216         {
1217                 len -= 3;
1218
1219                 if (!free_particles)
1220                         return;
1221                 p = free_particles;
1222                 free_particles = p->next;
1223                 p->next = active_particles;
1224                 active_particles = p;
1225                 
1226                 VectorCopy (vec3_origin, p->vel);
1227
1228                 p->texnum = flareparticletexture;
1229                 p->scale = 16;
1230                 p->alpha = 192;
1231                 p->color = color;
1232                 p->type = pt_smoke;
1233                 p->die = cl.time + 1;
1234                 VectorCopy(start, p->org);
1235 //              for (j=0 ; j<3 ; j++)
1236 //                      p->org[j] = start[j] + ((rand()&15)-8);
1237
1238                 VectorAdd (start, vec, start);
1239         }
1240 }
1241
1242
1243 //extern qboolean isG200, isATI, isRagePro;
1244 extern qboolean lighthalf;
1245
1246 /*
1247 ===============
1248 R_DrawParticles
1249 ===============
1250 */
1251 extern  cvar_t  sv_gravity;
1252
1253 void R_DrawParticles (void)
1254 {
1255         particle_t              *p, *kill;
1256         int                             i, /*texnum, */r,g,b,a;
1257         float                   grav, grav1, time1, time2, time3, dvel, frametime, scale, scale2;
1258         byte                    *color24;
1259         vec3_t                  up, right, uprightangles, forward2, up2, right2, v;
1260
1261         // LordHavoc: early out condition
1262         if (!active_particles)
1263                 return;
1264
1265         /*
1266         texnum = particletexture;
1267     glBindTexture(GL_TEXTURE_2D, texnum);
1268         glEnable (GL_BLEND);
1269         // LordHavoc: Matrox G200 cards can't handle per pixel alpha at all...
1270         // and ATI Rage Pro can't modulate a per pixel alpha texture
1271         if (isG200 || isRagePro)
1272                 glEnable(GL_ALPHA_TEST);
1273         else
1274                 glDisable(GL_ALPHA_TEST);
1275         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1276         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1277         glDepthMask(0); // disable zbuffer updates
1278         glShadeModel(GL_FLAT);
1279         glBegin (GL_TRIANGLES);
1280         */
1281
1282         VectorScale (vup, 1.5, up);
1283         VectorScale (vright, 1.5, right);
1284
1285         uprightangles[0] = 0;
1286         uprightangles[1] = r_refdef.viewangles[1];
1287         uprightangles[2] = 0;
1288         AngleVectors (uprightangles, forward2, right2, up2);
1289
1290         frametime = cl.time - cl.oldtime;
1291         time3 = frametime * 15;
1292         time2 = frametime * 10; // 15;
1293         time1 = frametime * 5;
1294         grav = (grav1 = frametime * sv_gravity.value) * 0.05;
1295         dvel = 1+4*frametime;
1296
1297         for ( ;; ) 
1298         {
1299                 kill = active_particles;
1300                 if (kill && kill->die < cl.time)
1301                 {
1302                         active_particles = kill->next;
1303                         kill->next = free_particles;
1304                         free_particles = kill;
1305                         continue;
1306                 }
1307                 break;
1308         }
1309
1310         for (p=active_particles ; p ; p=p->next)
1311         {
1312                 for ( ;; )
1313                 {
1314                         kill = p->next;
1315                         if (kill && kill->die < cl.time)
1316                         {
1317                                 p->next = kill->next;
1318                                 kill->next = free_particles;
1319                                 free_particles = kill;
1320                                 continue;
1321                         }
1322                         break;
1323                 }
1324                 // LordHavoc: 'removed last in list' condition
1325                 if (!p)
1326                         break;
1327
1328                 VectorSubtract(p->org, r_refdef.vieworg, v);
1329                 if (DotProduct(v, v) >= 256.0f)
1330                 {
1331                         scale = p->scale * -0.25;scale2 = p->scale * 0.75;
1332                         /*
1333                         if (p->texnum != texnum)
1334                         {
1335                                 texnum = p->texnum;
1336                                 glEnd();
1337                                 glBindTexture(GL_TEXTURE_2D, texnum);
1338                                 glBegin(GL_TRIANGLES);
1339                         }
1340                         if (lighthalf)
1341                         {
1342                                 color24 = (byte *)&d_8to24table[(int)p->color];
1343                                 if (p->texnum == smokeparticletexture)
1344                                         glColor4ub((byte) (color24[0] >> 1), (byte) (color24[1] >> 1), (byte) (color24[2] >> 1), (byte) (p->alpha*r_smokealpha.value));
1345                                 else
1346                                         glColor4ub((byte) (color24[0] >> 1), (byte) (color24[1] >> 1), (byte) (color24[2] >> 1), (byte) p->alpha);
1347                         }
1348                         else
1349                         {
1350                                 color24 = (byte *) &d_8to24table[(int)p->color];
1351                                 if (p->texnum == smokeparticletexture)
1352                                         glColor4ub(color24[0], color24[1], color24[2], (byte) (p->alpha*r_smokealpha.value));
1353                                 else
1354                                         glColor4ub(color24[0], color24[1], color24[2], (byte) p->alpha);
1355                         }
1356                         if (p->texnum == rainparticletexture) // rain streak
1357                         {
1358                                 glTexCoord2f (0,0);
1359                                 glVertex3f (p->org[0] + right2[0]*scale , p->org[1] + right2[1]*scale , p->org[2] + right2[2]*scale );
1360                                 glTexCoord2f (1,0);
1361                                 glVertex3f (p->org[0] + right2[0]*scale , p->org[1] + right2[1]*scale , p->org[2] + right2[2]*scale );
1362                                 glTexCoord2f (0,1);
1363                                 glVertex3f (p->org[0] + right2[0]*scale2, p->org[1] + right2[1]*scale2, p->org[2] + right2[2]*scale2);
1364                         }
1365                         else
1366                         {
1367                                 glTexCoord2f (0,0);
1368                                 // LordHavoc: centered particle sprites
1369                                 glVertex3f (p->org[0] + up[0]*scale  + right[0]*scale , p->org[1] + up[1]*scale  + right[1]*scale , p->org[2] + up[2]*scale  + right[2]*scale );
1370                                 glTexCoord2f (1,0);
1371                                 glVertex3f (p->org[0] + up[0]*scale2 + right[0]*scale , p->org[1] + up[1]*scale2 + right[1]*scale , p->org[2] + up[2]*scale2 + right[2]*scale );
1372                                 glTexCoord2f (0,1);
1373                                 glVertex3f (p->org[0] + up[0]*scale  + right[0]*scale2, p->org[1] + up[1]*scale  + right[1]*scale2, p->org[2] + up[2]*scale  + right[2]*scale2);
1374                         }
1375                         */
1376                         color24 = (byte *) &d_8to24table[(int)p->color];
1377                         r = color24[0];
1378                         g = color24[1];
1379                         b = color24[2];
1380                         a = p->alpha;
1381                         if (lighthalf)
1382                         {
1383                                 r >>= 1;
1384                                 g >>= 1;
1385                                 b >>= 1;
1386                         }
1387                         transpolybegin(p->texnum, 0, p->texnum, TPOLYTYPE_ALPHA);
1388                         if (p->texnum == rainparticletexture) // rain streak
1389                         {
1390                                 transpolyvert(p->org[0] + right2[0]*scale , p->org[1] + right2[1]*scale , p->org[2] + right2[2]*scale , 0,0,r,g,b,a);
1391                                 transpolyvert(p->org[0] + right2[0]*scale , p->org[1] + right2[1]*scale , p->org[2] + right2[2]*scale , 1,0,r,g,b,a);
1392                                 transpolyvert(p->org[0] + right2[0]*scale2, p->org[1] + right2[1]*scale2, p->org[2] + right2[2]*scale2, 0,1,r,g,b,a);
1393                         }
1394                         else
1395                         {
1396                                 transpolyvert(p->org[0] + up[0]*scale  + right[0]*scale , p->org[1] + up[1]*scale  + right[1]*scale , p->org[2] + up[2]*scale  + right[2]*scale , 0,0,r,g,b,a);
1397                                 transpolyvert(p->org[0] + up[0]*scale2 + right[0]*scale , p->org[1] + up[1]*scale2 + right[1]*scale , p->org[2] + up[2]*scale2 + right[2]*scale , 1,0,r,g,b,a);
1398                                 transpolyvert(p->org[0] + up[0]*scale  + right[0]*scale2, p->org[1] + up[1]*scale  + right[1]*scale2, p->org[2] + up[2]*scale  + right[2]*scale2, 0,1,r,g,b,a);
1399                         }
1400                         transpolyend();
1401                 }
1402
1403                 p->org[0] += p->vel[0]*frametime;
1404                 p->org[1] += p->vel[1]*frametime;
1405                 p->org[2] += p->vel[2]*frametime;
1406                 
1407                 switch (p->type)
1408                 {
1409                 case pt_static:
1410                         break;
1411                 case pt_fire:
1412                         p->ramp += time1;
1413                         if (p->ramp >= 6)
1414                                 p->die = -1;
1415                         else
1416                                 p->color = ramp3[(int)p->ramp];
1417                         p->vel[2] += grav;
1418                         break;
1419
1420                 case pt_explode:
1421                         p->ramp += time2;
1422                         if (p->ramp >=8)
1423                                 p->die = -1;
1424                         else
1425                                 p->color = ramp1[(int)p->ramp];
1426 //                      p->vel[2] -= grav1; // LordHavoc: apply full gravity to explosion sparks
1427                         for (i=0 ; i<3 ; i++)
1428                                 p->vel[i] *= dvel;
1429 //                      p->vel[2] -= grav;
1430                         break;
1431
1432                 case pt_explode2:
1433                         p->ramp += time3;
1434                         if (p->ramp >=8)
1435                                 p->die = -1;
1436                         else
1437                                 p->color = ramp2[(int)p->ramp];
1438 //                      p->vel[2] -= grav1; // LordHavoc: apply full gravity to explosion sparks
1439                         for (i=0 ; i<3 ; i++)
1440                                 p->vel[i] -= p->vel[i]*frametime;
1441 //                      p->vel[2] -= grav;
1442                         break;
1443
1444                 case pt_blob:
1445                         for (i=0 ; i<3 ; i++)
1446                                 p->vel[i] += p->vel[i]*dvel;
1447                         p->vel[2] -= grav;
1448                         break;
1449
1450                 case pt_blob2:
1451                         for (i=0 ; i<2 ; i++)
1452                                 p->vel[i] -= p->vel[i]*dvel;
1453                         p->vel[2] -= grav;
1454                         break;
1455
1456                 case pt_grav:
1457                         p->vel[2] -= grav1;
1458                         break;
1459                 case pt_slowgrav:
1460                         p->vel[2] -= grav;
1461                         break;
1462 // LordHavoc: gunshot spark showers
1463                 case pt_dust:
1464                         p->ramp += time1;
1465                         p->scale -= frametime * 4;
1466                         if (p->ramp >= 8 || p->scale <= 0)
1467                                 p->die = -1;
1468                         else
1469                                 p->color = ramp3[(int)p->ramp];
1470                         p->vel[2] -= grav1;
1471                         break;
1472 // LordHavoc: for smoke trails
1473                 case pt_smoke:
1474                         p->scale += frametime * 16;
1475                         p->alpha -= frametime * 64;
1476                         p->vel[2] += grav;
1477                         if (p->alpha < 1)
1478                                 p->die = -1;
1479                         break;
1480                 case pt_snow:
1481                         if (cl.time > p->time2)
1482                         {
1483                                 p->time2 = cl.time + 0.4;
1484                                 p->vel[0] = (rand()&63)-32;
1485                                 p->vel[1] = (rand()&63)-32;
1486                         }
1487                         break;
1488                 case pt_bulletpuff:
1489                         p->scale -= frametime * 64;
1490                         p->alpha -= frametime * 1024;
1491                         p->vel[2] -= grav;
1492                         if (p->alpha < 1 || p->scale < 1)
1493                                 p->die = -1;
1494                         break;
1495                 case pt_bloodcloud:
1496                         p->scale -= frametime * 24;
1497                         p->alpha -= frametime * 128;
1498                         p->vel[2] -= grav;
1499                         if (p->alpha < 1 || p->scale < 1)
1500                                 p->die = -1;
1501                         break;
1502                 case pt_fadespark:
1503                         p->alpha -= frametime * 256;
1504                         p->vel[2] -= grav;
1505                         if (p->alpha < 1)
1506                                 p->die = -1;
1507                         break;
1508                 case pt_fadespark2:
1509                         p->alpha -= frametime * 512;
1510                         p->vel[2] -= grav;
1511                         if (p->alpha < 1)
1512                                 p->die = -1;
1513                         break;
1514                 case pt_fallfadespark:
1515                         p->alpha -= frametime * 256;
1516                         p->vel[2] -= grav1;
1517                         if (p->alpha < 1)
1518                                 p->die = -1;
1519                         break;
1520                 case pt_fallfadespark2:
1521                         p->alpha -= frametime * 512;
1522                         p->vel[2] -= grav1;
1523                         if (p->alpha < 1)
1524                                 p->die = -1;
1525                         break;
1526                 case pt_bubble:
1527                         p->vel[2] += grav1;
1528                         if (p->vel[2] >= 100)
1529                                 p->vel[2] = 68+rand()&31;
1530                         if (cl.time > p->time2)
1531                         {
1532                                 p->time2 = cl.time + (rand()&7)*0.0625;
1533                                 p->vel[0] = (rand()&63)-32;
1534                                 p->vel[1] = (rand()&63)-32;
1535                         }
1536                         p->alpha -= frametime * 32;
1537                         if (p->alpha < 1)
1538                                 p->die = -1;
1539                         break;
1540                 }
1541         }
1542
1543         /*
1544         glEnd ();
1545         glShadeModel(GL_SMOOTH);
1546         glDepthMask(1); // enable zbuffer updates
1547         glDisable (GL_BLEND);
1548         */
1549 }
1550