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