]> icculus.org git repositories - divverent/darkplaces.git/blob - r_part.c
almost compiles on linux again. also bring in the latest and_alsa*.c from
[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                   32768   // 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 /*
440 void R_BlastParticles(vec3_t org, vec_t radius, vec_t power)
441 {
442         vec3_t v;
443         particle_t *p;
444         vec_t radius2 = radius * radius, speed, dist, scale = 2.5 * power / radius;
445         p = active_particles;
446         if (!p)
447                 return;
448         while (p)
449         {
450                 VectorSubtract(p->org, org, v);
451                 dist = DotProduct(v,v);
452                 if (dist < radius2)
453                 {
454                         speed = (radius - sqrt(dist)) * scale;
455                         VectorNormalize(v);
456                         VectorMA(p->pushvel, speed, v, p->pushvel);
457                 }
458                 p = p->next;
459         }
460 }
461 */
462
463 /*
464 ===============
465 R_ParseParticleEffect
466
467 Parse an effect out of the server message
468 ===============
469 */
470 void R_ParseParticleEffect (void)
471 {
472         vec3_t          org, dir;
473         int                     i, count, msgcount, color;
474         
475         for (i=0 ; i<3 ; i++)
476                 org[i] = MSG_ReadCoord ();
477         for (i=0 ; i<3 ; i++)
478                 dir[i] = MSG_ReadChar () * (1.0/16);
479         msgcount = MSG_ReadByte ();
480         color = MSG_ReadByte ();
481
482 if (msgcount == 255)
483         count = 1024;
484 else
485         count = msgcount;
486         
487         R_RunParticleEffect (org, dir, color, count);
488 }
489         
490 /*
491 ===============
492 R_ParticleExplosion
493
494 ===============
495 */
496 void R_ParticleExplosion (vec3_t org, int smoke)
497 {
498         int                     i, j;
499         particle_t      *p;
500         if (!r_particles.value) return; // LordHavoc: particles are optional
501
502         /*
503         for (i=0 ; i<1024 ; i++)
504         {
505                 ALLOCPARTICLE
506
507 //              p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
508                 p->texnum = particletexture;
509                 p->scale = lhrandom(1,3);
510                 p->alpha = rand()&255;
511                 p->die = cl.time + 5;
512                 p->color = ramp1[0];
513                 p->ramp = lhrandom(0, 4);
514 //              if (i & 1)
515 //                      p->type = pt_explode;
516 //              else
517 //                      p->type = pt_explode2;
518                 p->color = ramp1[rand()&7];
519                 p->type = pt_fallfadespark;
520                 for (j=0 ; j<3 ; j++)
521                 {
522                         p->org[j] = org[j] + lhrandom(-8,8);
523                         p->vel[j] = lhrandom(-192, 192);
524                 }
525                 p->vel[2] += 160;
526         }
527         */
528
529         i = Mod_PointInLeaf(org, cl.worldmodel)->contents;
530         if (i == CONTENTS_SLIME || i == CONTENTS_WATER)
531         {
532                 for (i=0 ; i<32 ; i++)
533                 {
534                         ALLOCPARTICLE
535
536 //                      p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
537                         p->texnum = bubbleparticletexture;
538                         p->scale = lhrandom(1,2);
539                         p->alpha = 255;
540                         p->color = (rand()&3)+12;
541                         p->type = pt_bubble;
542                         p->die = cl.time + 2;
543                         for (j=0 ; j<3 ; j++)
544                         {
545                                 p->org[j] = org[j] + lhrandom(-16,16);
546                                 p->vel[j] = lhrandom(-16,16);
547                         }
548                 }
549         }
550         else // if (smoke)
551         {
552 //              for (i=0 ; i<32 ; i++)
553 //              {
554                         ALLOCPARTICLE
555
556 //                      p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
557                         p->texnum = smokeparticletexture[rand()&7];
558 //                      p->scale = 12;
559                         p->scale = 30;
560                         p->alpha = 96;
561                         p->die = cl.time + 2;
562                         p->type = pt_smokecloud;
563                         p->color = (rand()&7) + 8;
564                         for (j=0 ; j<3 ; j++)
565                         {
566 //                              p->org[j] = org[j] + ((rand()%96)-48);
567 //                              p->vel[j] = (rand()&63)-32;
568                                 p->org[j] = org[j];
569                                 p->vel[j] = 0;
570                         }
571                 }
572 //      }
573 }
574
575 /*
576 ===============
577 R_ParticleExplosion2
578
579 ===============
580 */
581 void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
582 {
583         int                     i, j;
584         particle_t      *p;
585         int                     colorMod = 0;
586         if (!r_particles.value) return; // LordHavoc: particles are optional
587
588         for (i=0; i<512; i++)
589         {
590                 ALLOCPARTICLE
591
592 //              p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
593                 p->texnum = particletexture;
594                 p->scale = 1.5;
595                 p->alpha = 255;
596                 p->die = cl.time + 0.3;
597                 p->color = colorStart + (colorMod % colorLength);
598                 colorMod++;
599
600                 p->type = pt_blob;
601                 for (j=0 ; j<3 ; j++)
602                 {
603                         p->org[j] = org[j] + ((rand()&15)-8);
604                         p->vel[j] = lhrandom(-192, 192);
605                 }
606         }
607 }
608
609 /*
610 ===============
611 R_BlobExplosion
612
613 ===============
614 */
615 void R_BlobExplosion (vec3_t org)
616 {
617         int                     i, j;
618         particle_t      *p;
619         if (!r_particles.value) return; // LordHavoc: particles are optional
620         
621         for (i=0 ; i<1024 ; i++)
622         {
623                 ALLOCPARTICLE
624
625 //              p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
626                 p->texnum = particletexture;
627                 p->scale = 2;
628                 p->alpha = 255;
629                 p->die = cl.time + 1 + (rand()&8)*0.05;
630
631                 if (i & 1)
632                 {
633                         p->type = pt_blob;
634                         p->color = 66 + rand()%6;
635                         for (j=0 ; j<3 ; j++)
636                         {
637                                 p->org[j] = org[j] + ((rand()%32)-16);
638                                 p->vel[j] = lhrandom(-128, 128);
639                         }
640                 }
641                 else
642                 {
643                         p->type = pt_blob2;
644                         p->color = 150 + rand()%6;
645                         for (j=0 ; j<3 ; j++)
646                         {
647                                 p->org[j] = org[j] + ((rand()%32)-16);
648                                 p->vel[j] = lhrandom(-128, 128);
649                         }
650                 }
651                 p->vel[0] *= 0.25;
652                 p->vel[1] *= 0.25;
653         }
654 }
655
656 /*
657 ===============
658 R_RunParticleEffect
659
660 ===============
661 */
662 void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
663 {
664         int                     j;
665         particle_t      *p;
666         if (!r_particles.value) return; // LordHavoc: particles are optional
667         
668         if (count == 1024)
669         {
670                 R_ParticleExplosion(org, false);
671                 return;
672         }
673         while (count)
674         {
675                 ALLOCPARTICLE
676                 if (count & 7)
677                 {
678                         p->alpha = (count & 7) * 16 + (rand()&15);
679                         count &= ~7;
680                 }
681                 else
682                 {
683                         p->alpha = 128;
684                         count -= 8;
685                 }
686
687 //              p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
688                 p->texnum = particletexture;
689                 p->scale = 6;
690                 p->die = cl.time + 1; //lhrandom(0.1, 0.5);
691                 p->color = (color&~7) + (rand()&7);
692                 p->type = pt_fade; //static; //slowgrav;
693                 for (j=0 ; j<3 ; j++)
694                 {
695                         p->org[j] = org[j] + ((rand()&15)-8);
696                         p->vel[j] = dir[j]*15;// + (rand()%300)-150;
697                 }
698         }
699 }
700
701 // LordHavoc: added this for spawning sparks/dust (which have strong gravity)
702 /*
703 ===============
704 R_SparkShower
705
706 ===============
707 */
708 void R_SparkShower (vec3_t org, vec3_t dir, int count, int type)
709 {
710         int                     i, j;
711         particle_t      *p;
712         if (!r_particles.value) return; // LordHavoc: particles are optional
713
714         ALLOCPARTICLE
715 //      p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
716         if (type == 0) // sparks
717         {
718                 p->texnum = smokeparticletexture[rand()&7];
719                 p->scale = 10;
720                 p->alpha = 48;
721                 p->color = (rand()&3)+12;
722                 p->type = pt_bulletpuff;
723                 p->die = cl.time + 1;
724                 VectorCopy(org, p->org);
725                 p->vel[0] = p->vel[1] = p->vel[2] = 0;
726         }
727         else // blood
728         {
729                 p->texnum = smokeparticletexture[rand()&7];
730                 p->scale = 12;
731                 p->alpha = 128;
732                 p->color = (rand()&3)+68;
733                 p->type = pt_bloodcloud;
734                 p->die = cl.time + 0.5;
735                 VectorCopy(org, p->org);
736                 p->vel[0] = p->vel[1] = p->vel[2] = 0;
737                 return;
738         }
739         for (i=0 ; i<count ; i++)
740         {
741                 ALLOCPARTICLE
742
743 //              p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
744                 p->texnum = flareparticletexture;
745                 p->scale = 2;
746                 p->alpha = 192;
747                 p->die = cl.time + 0.0625 * (rand()&15);
748                 /*
749                 if (type == 0) // sparks
750                 {
751                 */
752                         p->type = pt_dust;
753                         p->ramp = (rand()&3);
754                         p->color = ramp1[(int)p->ramp];
755                         for (j=0 ; j<3 ; j++)
756                         {
757                                 p->org[j] = org[j] + ((rand()&7)-4);
758                                 p->vel[j] = dir[j] + (rand()%192)-96;
759                         }
760                 /*
761                 }
762                 else // blood
763                 {
764                         p->type = pt_fadespark2;
765                         p->color = 67 + (rand()&3);
766                         for (j=0 ; j<3 ; j++)
767                         {
768                                 p->org[j] = org[j] + (rand()&7)-4;
769                                 p->vel[j] = dir[j] + (rand()&63)-32;
770                         }
771                 }
772                 */
773         }
774 }
775
776 void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count)
777 {
778         int                     i, j;
779         particle_t      *p;
780         vec3_t          diff;
781         vec3_t          center;
782         vec3_t          velscale;
783         if (!r_particles.value) return; // LordHavoc: particles are optional
784
785         VectorSubtract(maxs, mins, diff);
786         center[0] = (mins[0] + maxs[0]) * 0.5;
787         center[1] = (mins[1] + maxs[1]) * 0.5;
788         center[2] = (mins[2] + maxs[2]) * 0.5;
789         velscale[0] = velspeed * 2.0 / diff[0];
790         velscale[1] = velspeed * 2.0 / diff[1];
791         velscale[2] = velspeed * 2.0 / diff[2];
792         
793         for (i=0 ; i<count ; i++)
794         {
795                 ALLOCPARTICLE
796
797 //              p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
798                 p->texnum = bloodcloudparticletexture;
799                 p->scale = 12;
800                 p->alpha = 96 + (rand()&63);
801                 p->die = cl.time + 2; //0.015625 * (rand()%128);
802                 p->type = pt_fadespark;
803                 p->color = (rand()&3)+68;
804 //              p->color = 67 + (rand()&3);
805                 for (j=0 ; j<3 ; j++)
806                 {
807                         p->org[j] = diff[j] * (float) (rand()%1024) * (1.0 / 1024.0) + mins[j];
808                         p->vel[j] = (p->org[j] - center[j]) * velscale[j];
809                 }
810         }
811 }
812
813 void R_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int gravity, int randomvel)
814 {
815         int                     i, j;
816         particle_t      *p;
817         vec3_t          diff;
818         float           t;
819         if (!r_particles.value) return; // LordHavoc: particles are optional
820         if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
821         if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
822         if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
823
824         VectorSubtract(maxs, mins, diff);
825         
826         for (i=0 ; i<count ; i++)
827         {
828                 ALLOCPARTICLE
829
830 //              p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
831                 p->texnum = flareparticletexture;
832                 p->scale = 6;
833                 p->alpha = 255;
834                 p->die = cl.time + 1 + (rand()&15)*0.0625;
835                 if (gravity)
836                         p->type = pt_grav;
837                 else
838                         p->type = pt_static;
839                 p->color = colorbase + (rand()&3);
840                 for (j=0 ; j<3 ; j++)
841                 {
842                         p->org[j] = diff[j] * (float) (rand()&1023) * (1.0 / 1024.0) + mins[j];
843                         if (randomvel)
844                                 p->vel[j] = dir[j] + (rand()%randomvel)-(randomvel*0.5);
845                         else
846                                 p->vel[j] = 0;
847                 }
848         }
849 }
850
851 void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int type)
852 {
853         int                     i;
854         particle_t      *p;
855         vec3_t          diff;
856         vec3_t          org;
857         vec3_t          vel;
858         float           t, z;
859         if (!r_particles.value) return; // LordHavoc: particles are optional
860         if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
861         if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
862         if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
863         if (dir[2] < 0) // falling
864         {
865                 t = (maxs[2] - mins[2]) / -dir[2];
866                 z = maxs[2];
867         }
868         else // rising??
869         {
870                 t = (maxs[2] - mins[2]) / dir[2];
871                 z = mins[2];
872         }
873         if (t < 0 || t > 2) // sanity check
874                 t = 2;
875         t += cl.time;
876
877         VectorSubtract(maxs, mins, diff);
878         
879         for (i=0 ; i<count ; i++)
880         {
881                 ALLOCPARTICLE
882
883                 vel[0] = dir[0] + (rand()&31) - 16;
884                 vel[1] = dir[1] + (rand()&31) - 16;
885                 vel[2] = dir[2] + (rand()&63) - 32;
886                 org[0] = diff[0] * (float) (rand()&1023) * (1.0 / 1024.0) + mins[0];
887                 org[1] = diff[1] * (float) (rand()&1023) * (1.0 / 1024.0) + mins[1];
888                 org[2] = z;
889
890 //              p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
891                 p->scale = 1.5;
892                 p->alpha = 255;
893                 p->die = t;
894                 if (type == 1)
895                 {
896                         p->texnum = particletexture;
897                         p->type = pt_snow;
898                 }
899                 else // 0
900                 {
901                         p->texnum = rainparticletexture;
902                         p->type = pt_static;
903                 }
904                 p->color = colorbase + (rand()&3);
905                 VectorCopy(org, p->org);
906                 VectorCopy(vel, p->vel);
907                 VectorCopy(vel, p->vel2);
908         }
909 }
910
911
912 /*
913 ===============
914 R_LavaSplash
915
916 ===============
917 */
918 void R_LavaSplash (vec3_t org)
919 {
920         int                     i, j, k;
921         particle_t      *p;
922         float           vel;
923         vec3_t          dir;
924         if (!r_particles.value) return; // LordHavoc: particles are optional
925
926         for (i=-16 ; i<16 ; i+=2)
927                 for (j=-16 ; j<16 ; j+=2)
928                         for (k=0 ; k<1 ; k++)
929                         {
930                                 ALLOCPARTICLE
931                 
932 //                              p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
933                                 p->texnum = flareparticletexture;
934                                 p->scale = 10;
935                                 p->alpha = 128;
936                                 p->die = cl.time + 2 + (rand()&31) * 0.02;
937                                 p->color = 224 + (rand()&7);
938                                 p->type = pt_slowgrav;
939                                 
940                                 dir[0] = j*8 + (rand()&7);
941                                 dir[1] = i*8 + (rand()&7);
942                                 dir[2] = 256;
943         
944                                 p->org[0] = org[0] + dir[0];
945                                 p->org[1] = org[1] + dir[1];
946                                 p->org[2] = org[2] + (rand()&63);
947         
948                                 VectorNormalize (dir);                                          
949                                 vel = 50 + (rand()&63);
950                                 VectorScale (dir, vel, p->vel);
951                         }
952 }
953
954 /*
955 ===============
956 R_TeleportSplash
957
958 ===============
959 */
960 void R_TeleportSplash (vec3_t org)
961 {
962         int                     i, j, k;
963         particle_t      *p;
964 //      vec3_t          dir;
965         if (!r_particles.value) return; // LordHavoc: particles are optional
966
967         /*
968         for (i=-16 ; i<16 ; i+=4)
969                 for (j=-16 ; j<16 ; j+=4)
970                         for (k=-24 ; k<32 ; k+=4)
971                         {
972                                 ALLOCPARTICLE
973                 
974 //                              p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
975                                 p->contents = 0;
976                                 p->texnum = particletexture;
977                                 p->scale = 2;
978                                 p->alpha = 255;
979                                 p->die = cl.time + 0.2 + (rand()&7) * 0.02;
980                                 p->color = 7 + (rand()&7);
981                                 p->type = pt_slowgrav;
982                                 
983                                 dir[0] = j*8;
984                                 dir[1] = i*8;
985                                 dir[2] = k*8;
986         
987                                 p->org[0] = org[0] + i + (rand()&3);
988                                 p->org[1] = org[1] + j + (rand()&3);
989                                 p->org[2] = org[2] + k + (rand()&3);
990         
991                                 VectorNormalize (dir);                                          
992                                 vel = 50 + (rand()&63);
993                                 VectorScale (dir, vel, p->vel);
994                         }
995         */
996
997         for (i=-24 ; i<24 ; i+=8)
998                 for (j=-24 ; j<24 ; j+=8)
999                         for (k=-24 ; k<32 ; k+=8)
1000                         {
1001                                 ALLOCPARTICLE
1002                 
1003 //                              p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
1004                                 p->texnum = flareparticletexture;
1005                                 p->scale = 4;
1006                                 p->alpha = lhrandom(32,256);
1007                                 p->die = cl.time + 5;
1008                                 p->color = 254; //8 + (rand()&7);
1009                                 p->type = pt_fadespark;
1010                                 
1011                                 p->org[0] = org[0] + i + (rand()&7);
1012                                 p->org[1] = org[1] + j + (rand()&7);
1013                                 p->org[2] = org[2] + k + (rand()&7);
1014         
1015                                 p->vel[0] = i*2 + (rand()%25) - 12;
1016                                 p->vel[1] = j*2 + (rand()%25) - 12;
1017                                 p->vel[2] = k*2 + (rand()%25) - 12 + 40;
1018                         }
1019 }
1020
1021 void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
1022 {
1023         vec3_t          vec;
1024         float           len, dec = 0, t, nt, speed;
1025         int                     j, contents, bubbles;
1026         particle_t      *p;
1027         static int      tracercount;
1028         if (!r_particles.value) return; // LordHavoc: particles are optional
1029
1030         t = cl.oldtime;
1031         nt = cl.time;
1032         if (ent->trail_leftover < 0)
1033                 ent->trail_leftover = 0;
1034         t += ent->trail_leftover;
1035         ent->trail_leftover -= (cl.time - cl.oldtime);
1036         if (t >= cl.time)
1037                 return;
1038
1039         contents = Mod_PointInLeaf(start, cl.worldmodel)->contents;
1040         if (contents == CONTENTS_SKY || contents == CONTENTS_LAVA)
1041                 return;
1042
1043         VectorSubtract (end, start, vec);
1044         len = VectorNormalizeLength (vec);
1045         if (len <= 0.01f)
1046                 return;
1047         speed = len / (nt - t);
1048
1049         bubbles = (contents == CONTENTS_WATER || contents == CONTENTS_SLIME);
1050
1051         while (t < nt)
1052         {
1053                 ALLOCPARTICLE
1054                 
1055 //              p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
1056                 p->vel[0] = p->vel[1] = p->vel[2] = 0;
1057                 p->die = cl.time + 2;
1058
1059                 switch (type)
1060                 {
1061                         case 0: // rocket trail
1062                         case 1: // grenade trail
1063                                 if (bubbles)
1064                                 {
1065                                         dec = 0.005f;
1066                                         p->texnum = bubbleparticletexture;
1067                                         p->scale = lhrandom(1,2);
1068                                         p->alpha = 255;
1069                                         p->color = (rand()&3)+12;
1070                                         p->type = pt_bubble;
1071                                         p->die = cl.time + 2;
1072                                         for (j=0 ; j<3 ; j++)
1073                                         {
1074                                                 p->vel[j] = (rand()&31)-16;
1075                                                 p->org[j] = start[j] + ((rand()&3)-2);
1076                                         }
1077                                 }
1078                                 else
1079                                 {
1080                                         dec = 0.02f;
1081                                         p->texnum = smokeparticletexture[rand()&7];
1082                                         p->scale = lhrandom(8, 12);
1083                                         p->alpha = 64 + (rand()&31);
1084                                         p->color = (rand()&3)+12;
1085                                         p->type = pt_smoke;
1086                                         p->die = cl.time + 10000;
1087                                         VectorCopy(start, p->org);
1088                                 }
1089                                 break;
1090
1091                                 /*
1092                         case 1: // smoke smoke
1093                                 dec = 0.016f;
1094                                 p->texnum = smokeparticletexture;
1095                                 p->scale = lhrandom(6,9);
1096                                 p->alpha = 64;
1097                                 if (r_smokecolor.value)
1098                                         p->color = r_smokecolor.value;
1099                                 else
1100                                         p->color = (rand()&3)+12;
1101                                 p->type = pt_smoke;
1102                                 p->die = cl.time + 1;
1103                                 VectorCopy(start, p->org);
1104                                 break;
1105                                 */
1106
1107                         case 2: // blood
1108                                 dec = 0.025f;
1109                                 p->texnum = smokeparticletexture[rand()&7];
1110                                 p->scale = lhrandom(6, 8);
1111                                 p->alpha = 255;
1112                                 p->color = (rand()&3)+68;
1113                                 p->type = pt_bloodcloud;
1114                                 p->die = cl.time + 9999;
1115                                 for (j=0 ; j<3 ; j++)
1116                                 {
1117                                         p->vel[j] = (rand()&15)-8;
1118                                         p->org[j] = start[j] + ((rand()&3)-2);
1119                                 }
1120                                 break;
1121
1122                         case 3:
1123                         case 5: // tracer
1124                                 dec = 0.01f;
1125                                 p->texnum = flareparticletexture;
1126                                 p->scale = 2;
1127                                 p->alpha = 255;
1128                                 p->die = cl.time + 0.2; //5;
1129                                 p->type = pt_static;
1130                                 if (type == 3)
1131                                         p->color = 52 + ((tracercount&4)<<1);
1132                                 else
1133                                         p->color = 230 + ((tracercount&4)<<1);
1134
1135                                 tracercount++;
1136
1137                                 VectorCopy (start, p->org);
1138                                 if (tracercount & 1)
1139                                 {
1140                                         p->vel[0] = 30*vec[1];
1141                                         p->vel[1] = 30*-vec[0];
1142                                 }
1143                                 else
1144                                 {
1145                                         p->vel[0] = 30*-vec[1];
1146                                         p->vel[1] = 30*vec[0];
1147                                 }
1148                                 break;
1149
1150                         case 4: // slight blood
1151                                 dec = 0.025f; // sparse trail
1152                                 p->texnum = smokeparticletexture[rand()&7];
1153                                 p->scale = lhrandom(6, 8);
1154                                 p->alpha = 192;
1155                                 p->color = (rand()&3)+68;
1156                                 p->type = pt_fadespark2;
1157                                 p->die = cl.time + 9999;
1158                                 for (j=0 ; j<3 ; j++)
1159                                 {
1160                                         p->vel[j] = (rand()&15)-8;
1161                                         p->org[j] = start[j] + ((rand()&3)-2);
1162                                 }
1163                                 break;
1164
1165                         case 6: // voor trail
1166                                 dec = 0.05f; // sparse trail
1167                                 p->texnum = smokeparticletexture[rand()&7];
1168                                 p->scale = lhrandom(3, 5);
1169                                 p->alpha = 255;
1170                                 p->color = 9*16 + 8 + (rand()&3);
1171                                 p->type = pt_fadespark2;
1172                                 p->die = cl.time + 2;
1173                                 for (j=0 ; j<3 ; j++)
1174                                 {
1175                                         p->vel[j] = (rand()&15)-8;
1176                                         p->org[j] = start[j] + ((rand()&3)-2);
1177                                 }
1178                                 break;
1179
1180                         case 7: // Nehahra smoke tracer
1181                                 dec = 0.14f;
1182                                 p->texnum = smokeparticletexture[rand()&7];
1183                                 p->scale = lhrandom(8, 12);
1184                                 p->alpha = 64;
1185                                 p->color = (rand()&3)+12;
1186                                 p->type = pt_smoke;
1187                                 p->die = cl.time + 10000;
1188                                 for (j=0 ; j<3 ; j++)
1189                                         p->org[j] = start[j] + ((rand()&3)-2);
1190                                 break;
1191                 }
1192                 
1193                 t += dec;
1194                 dec *= speed;
1195                 VectorMA (start, dec, vec, start);
1196         }
1197         ent->trail_leftover = t - cl.time;
1198 }
1199
1200 void R_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent)
1201 {
1202         vec3_t          vec;
1203         float           len;
1204         particle_t      *p;
1205         if (!r_particles.value) return; // LordHavoc: particles are optional
1206
1207         VectorSubtract (end, start, vec);
1208         len = VectorNormalizeLength (vec);
1209         while (len > 0)
1210         {
1211                 len -= 3;
1212
1213                 ALLOCPARTICLE
1214                 
1215 //              p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
1216                 p->vel[0] = p->vel[1] = p->vel[2] = 0;
1217
1218                 p->texnum = flareparticletexture;
1219                 p->scale = 8;
1220                 p->alpha = 192;
1221                 p->color = color;
1222                 p->type = pt_smoke;
1223                 p->die = cl.time + 1;
1224                 VectorCopy(start, p->org);
1225 //              for (j=0 ; j<3 ; j++)
1226 //                      p->org[j] = start[j] + ((rand()&15)-8);
1227
1228                 VectorAdd (start, vec, start);
1229         }
1230 }
1231
1232
1233 extern qboolean lighthalf;
1234
1235 /*
1236 ===============
1237 R_DrawParticles
1238 ===============
1239 */
1240 extern  cvar_t  sv_gravity;
1241 void R_CompleteLightPoint (vec3_t color, vec3_t p);
1242
1243 void R_DrawParticles (void)
1244 {
1245         particle_t              *p, *kill;
1246         int                             i, r,g,b,a;
1247         float                   grav, grav1, time1, time2, time3, dvel, frametime, scale, scale2/*, f1, f2*/, minparticledist;
1248         byte                    *color24;
1249         vec3_t                  up, right, uprightangles, forward2, up2, right2, tempcolor;
1250
1251         // LordHavoc: early out condition
1252         if (!active_particles)
1253                 return;
1254
1255         VectorScale (vup, 1.5, up);
1256         VectorScale (vright, 1.5, right);
1257
1258         uprightangles[0] = 0;
1259         uprightangles[1] = r_refdef.viewangles[1];
1260         uprightangles[2] = 0;
1261         AngleVectors (uprightangles, forward2, right2, up2);
1262
1263         frametime = cl.time - cl.oldtime;
1264         time3 = frametime * 15;
1265         time2 = frametime * 10; // 15;
1266         time1 = frametime * 5;
1267         grav = (grav1 = frametime * sv_gravity.value) * 0.05;
1268         dvel = 1+4*frametime;
1269
1270         minparticledist = DotProduct(r_refdef.vieworg, vpn) + 16.0f;
1271
1272         // remove dead particles at beginning of list
1273         for ( ;; ) 
1274         {
1275                 kill = active_particles;
1276                 if (kill && kill->die < cl.time)
1277                 {
1278                         active_particles = kill->next;
1279                         kill->next = free_particles;
1280                         free_particles = kill;
1281                         continue;
1282                 }
1283                 break;
1284         }
1285
1286         for (p=active_particles ; p ; p=p->next)
1287         {
1288                 // remove dead particles following this one
1289                 for ( ;; )
1290                 {
1291                         kill = p->next;
1292                         if (kill && kill->die < cl.time)
1293                         {
1294                                 p->next = kill->next;
1295                                 kill->next = free_particles;
1296                                 free_particles = kill;
1297                                 continue;
1298                         }
1299                         break;
1300                 }
1301
1302                 // LordHavoc: only render if not too close
1303                 if (DotProduct(p->org, vpn) >= minparticledist)
1304                 {
1305                         color24 = (byte *) &d_8to24table[(int)p->color];
1306                         r = color24[0];
1307                         g = color24[1];
1308                         b = color24[2];
1309                         a = p->alpha;
1310                         if (lighthalf)
1311                         {
1312                                 r >>= 1;
1313                                 g >>= 1;
1314                                 b >>= 1;
1315                         }
1316                         if (r_dynamicparticles.value)
1317                         {
1318                                 R_CompleteLightPoint(tempcolor, p->org);
1319                                 r = (r * (int) tempcolor[0]) >> 7;
1320                                 g = (g * (int) tempcolor[1]) >> 7;
1321                                 b = (b * (int) tempcolor[2]) >> 7;
1322                         }
1323                         transpolybegin(p->texnum, 0, p->texnum, TPOLYTYPE_ALPHA);
1324                         scale = p->scale * -0.5;scale2 = p->scale * 0.5;
1325                         if (p->texnum == rainparticletexture) // rain streak
1326                         {
1327                                 transpolyvert(p->org[0] + up2[0]*scale  + right2[0]*scale , p->org[1] + up2[1]*scale  + right2[1]*scale , p->org[2] + up2[2]*scale  + right2[2]*scale , 0,1,r,g,b,a);
1328                                 transpolyvert(p->org[0] + up2[0]*scale2 + right2[0]*scale , p->org[1] + up2[1]*scale2 + right2[1]*scale , p->org[2] + up2[2]*scale2 + right2[2]*scale , 0,0,r,g,b,a);
1329                                 transpolyvert(p->org[0] + up2[0]*scale2 + right2[0]*scale2, p->org[1] + up2[1]*scale2 + right2[1]*scale2, p->org[2] + up2[2]*scale2 + right2[2]*scale2, 1,0,r,g,b,a);
1330                                 transpolyvert(p->org[0] + up2[0]*scale  + right2[0]*scale2, p->org[1] + up2[1]*scale  + right2[1]*scale2, p->org[2] + up2[2]*scale  + right2[2]*scale2, 1,1,r,g,b,a);
1331                         }
1332                         else
1333                         {
1334                                 transpolyvert(p->org[0] + up[0]*scale  + right[0]*scale , p->org[1] + up[1]*scale  + right[1]*scale , p->org[2] + up[2]*scale  + right[2]*scale , 0,1,r,g,b,a);
1335                                 transpolyvert(p->org[0] + up[0]*scale2 + right[0]*scale , p->org[1] + up[1]*scale2 + right[1]*scale , p->org[2] + up[2]*scale2 + right[2]*scale , 0,0,r,g,b,a);
1336                                 transpolyvert(p->org[0] + up[0]*scale2 + right[0]*scale2, p->org[1] + up[1]*scale2 + right[1]*scale2, p->org[2] + up[2]*scale2 + right[2]*scale2, 1,0,r,g,b,a);
1337                                 transpolyvert(p->org[0] + up[0]*scale  + right[0]*scale2, p->org[1] + up[1]*scale  + right[1]*scale2, p->org[2] + up[2]*scale  + right[2]*scale2, 1,1,r,g,b,a);
1338                         }
1339                         transpolyend();
1340                 }
1341
1342                 /*
1343                 if (p->pushvel[0] || p->pushvel[1] || p->pushvel[2])
1344                 {
1345                         p->org[0] += (p->vel[0]+p->pushvel[0])*frametime;
1346                         p->org[1] += (p->vel[1]+p->pushvel[1])*frametime;
1347                         p->org[2] += (p->vel[2]+p->pushvel[2])*frametime;
1348                         f1 = sqrt(DotProduct(p->pushvel,p->pushvel));
1349                         f2 = f1 - frametime * 32;
1350                         if (f2 <= 0)
1351                                 p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
1352                         else
1353                         {
1354                                 f2 /= f1;
1355                                 p->pushvel[0] *= f2;
1356                                 p->pushvel[1] *= f2;
1357                                 p->pushvel[2] *= f2;
1358                         }
1359                 }
1360                 else
1361                 {
1362                         if (p->type != pt_smokecloud)
1363                         {
1364                 */
1365                                 p->org[0] += p->vel[0]*frametime;
1366                                 p->org[1] += p->vel[1]*frametime;
1367                                 p->org[2] += p->vel[2]*frametime;
1368                 /*
1369                         }
1370                 }
1371                 */
1372                 
1373                 switch (p->type)
1374                 {
1375                 case pt_static:
1376                         break;
1377                 case pt_fire:
1378                         p->ramp += time1;
1379                         if (p->ramp >= 6)
1380                                 p->die = -1;
1381                         else
1382                                 p->color = ramp3[(int)p->ramp];
1383                         p->vel[2] += grav;
1384                         break;
1385
1386                 case pt_explode:
1387                         p->ramp += time2;
1388                         if (p->ramp >=8)
1389                                 p->die = -1;
1390                         else
1391                                 p->color = ramp1[(int)p->ramp];
1392 //                      p->vel[2] -= grav1; // LordHavoc: apply full gravity to explosion sparks
1393                         for (i=0 ; i<3 ; i++)
1394                                 p->vel[i] *= dvel;
1395 //                      p->vel[2] -= grav;
1396                         break;
1397
1398                 case pt_explode2:
1399                         p->ramp += time3;
1400                         if (p->ramp >= 8)
1401                                 p->die = -1;
1402                         else
1403                                 p->color = ramp2[(int)p->ramp];
1404 //                      p->vel[2] -= grav1; // LordHavoc: apply full gravity to explosion sparks
1405                         for (i=0 ; i<3 ; i++)
1406 //                              p->vel[i] -= p->vel[i]*frametime;
1407                                 p->vel[i] *= dvel;
1408 ////                    p->vel[2] -= grav;
1409                         break;
1410
1411                 case pt_blob:
1412                         for (i=0 ; i<3 ; i++)
1413                                 p->vel[i] += p->vel[i]*dvel;
1414                         p->vel[2] -= grav;
1415                         break;
1416
1417                 case pt_blob2:
1418                         for (i=0 ; i<2 ; i++)
1419                                 p->vel[i] -= p->vel[i]*dvel;
1420                         p->vel[2] -= grav;
1421                         break;
1422
1423                 case pt_grav:
1424                         p->vel[2] -= grav1;
1425                         break;
1426                 case pt_slowgrav:
1427                         p->vel[2] -= grav;
1428                         break;
1429 // LordHavoc: gunshot spark showers
1430                 case pt_dust:
1431                         p->ramp += time1;
1432                         p->scale -= frametime * 4;
1433                         p->alpha -= frametime * 48;
1434                         if (p->ramp >= 8 || p->scale < 1 || p->alpha < 1)
1435                                 p->die = -1;
1436                         else
1437                                 p->color = ramp3[(int)p->ramp];
1438                         p->vel[2] -= grav1;
1439                         break;
1440 // LordHavoc: for smoke trails
1441                 case pt_smoke:
1442                         p->scale += frametime * 6;
1443                         p->alpha -= frametime * 128;
1444 //                      p->vel[2] += grav;
1445                         if (p->alpha < 1)
1446                                 p->die = -1;
1447                         break;
1448                 case pt_snow:
1449                         if (cl.time > p->time2)
1450                         {
1451                                 p->time2 = cl.time + (rand() & 3) * 0.1;
1452                                 p->vel[0] = (rand()&63)-32 + p->vel2[0];
1453                                 p->vel[1] = (rand()&63)-32 + p->vel2[1];
1454                                 p->vel[2] = (rand()&63)-32 + p->vel2[2];
1455                         }
1456                         break;
1457                 case pt_bulletpuff:
1458                         p->scale -= frametime * 64;
1459                         p->alpha -= frametime * 1024;
1460                         p->vel[2] -= grav;
1461                         if (p->alpha < 1 || p->scale < 1)
1462                                 p->die = -1;
1463                         break;
1464                 case pt_bloodcloud:
1465                         if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents != CONTENTS_EMPTY)
1466                         {
1467                                 p->die = -1;
1468                                 break;
1469                         }
1470                         p->scale += frametime * 4;
1471                         p->alpha -= frametime * 64;
1472                         p->vel[2] -= grav;
1473                         if (p->alpha < 1 || p->scale < 1)
1474                                 p->die = -1;
1475                         break;
1476                 case pt_fadespark:
1477                         p->alpha -= frametime * 256;
1478                         p->vel[2] -= grav;
1479                         if (p->alpha < 1)
1480                                 p->die = -1;
1481                         break;
1482                 case pt_fadespark2:
1483                         p->alpha -= frametime * 512;
1484                         p->vel[2] -= grav;
1485                         if (p->alpha < 1)
1486                                 p->die = -1;
1487                         break;
1488                 case pt_fallfadespark:
1489                         p->alpha -= frametime * 256;
1490                         p->vel[2] -= grav1;
1491                         if (p->alpha < 1)
1492                                 p->die = -1;
1493                         break;
1494                 case pt_fallfadespark2:
1495                         p->alpha -= frametime * 512;
1496                         p->vel[2] -= grav1;
1497                         if (p->alpha < 1)
1498                                 p->die = -1;
1499                         break;
1500                 case pt_fade:
1501                         p->alpha -= frametime * 512;
1502                         if (p->alpha < 1)
1503                                 p->die = -1;
1504                         break;
1505                 case pt_bubble:
1506                         if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_EMPTY)
1507                                 p->die = -1;
1508                         p->vel[2] += grav1 * 2;
1509                         if (p->vel[2] >= 200)
1510                                 p->vel[2] = lhrandom(130, 200);
1511                         if (cl.time > p->time2)
1512                         {
1513                                 p->time2 = cl.time + lhrandom(0, 0.5);
1514                                 p->vel[0] = lhrandom(-32,32);
1515                                 p->vel[1] = lhrandom(-32,32);
1516                         }
1517                         p->alpha -= frametime * 64;
1518                         if (p->alpha < 1)
1519                                 p->die = -1;
1520                         break;
1521                 case pt_smokecloud:
1522                         p->scale += frametime * 60;
1523                         p->alpha -= frametime * 96;
1524                         if (p->alpha < 1)
1525                                 p->die = -1;
1526                         break;
1527                 }
1528         }
1529 }
1530