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