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