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