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 #include "r_local.h"
23
24 #define MAX_PARTICLES 2048 // default max # of particles at one
25 // time
26 #define ABSOLUTE_MIN_PARTICLES 512 // no fewer than this no matter what's
27 // on the command line
28
29 int ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61};
30 int ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66};
31 int ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3};
32
33 particle_t *active_particles, *free_particles;
34
35 particle_t *particles;
36 int r_numparticles;
37
38 vec3_t r_pright, r_pup, r_ppn;
39
40
41 /*
42 ===============
43 R_InitParticles
44 ===============
45 */
R_InitParticles(void)46 void R_InitParticles (void)
47 {
48 int i;
49
50 i = COM_CheckParm ("-particles");
51
52 if (i)
53 {
54 r_numparticles = (int)(Q_atoi(com_argv[i+1]));
55 if (r_numparticles < ABSOLUTE_MIN_PARTICLES)
56 r_numparticles = ABSOLUTE_MIN_PARTICLES;
57 }
58 else
59 {
60 r_numparticles = MAX_PARTICLES;
61 }
62
63 particles = (particle_t *)
64 Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles");
65 }
66
67 #ifdef QUAKE2
R_DarkFieldParticles(entity_t * ent)68 void R_DarkFieldParticles (entity_t *ent)
69 {
70 int i, j, k;
71 particle_t *p;
72 float vel;
73 vec3_t dir;
74 vec3_t org;
75
76 org[0] = ent->origin[0];
77 org[1] = ent->origin[1];
78 org[2] = ent->origin[2];
79 for (i=-16 ; i<16 ; i+=8)
80 for (j=-16 ; j<16 ; j+=8)
81 for (k=0 ; k<32 ; k+=8)
82 {
83 if (!free_particles)
84 return;
85 p = free_particles;
86 free_particles = p->next;
87 p->next = active_particles;
88 active_particles = p;
89
90 p->die = cl.time + 0.2 + (rand()&7) * 0.02;
91 p->color = 150 + rand()%6;
92 p->type = pt_slowgrav;
93
94 dir[0] = j*8;
95 dir[1] = i*8;
96 dir[2] = k*8;
97
98 p->org[0] = org[0] + i + (rand()&3);
99 p->org[1] = org[1] + j + (rand()&3);
100 p->org[2] = org[2] + k + (rand()&3);
101
102 VectorNormalize (dir);
103 vel = 50 + (rand()&63);
104 VectorScale (dir, vel, p->vel);
105 }
106 }
107 #endif
108
109
110 /*
111 ===============
112 R_EntityParticles
113 ===============
114 */
115
116 #define NUMVERTEXNORMALS 162
117 extern float r_avertexnormals[NUMVERTEXNORMALS][3];
118 vec3_t avelocities[NUMVERTEXNORMALS];
119 float beamlength = 16;
120 vec3_t avelocity = {23, 7, 3};
121 float partstep = 0.01;
122 float timescale = 0.01;
123
R_EntityParticles(entity_t * ent)124 void R_EntityParticles (entity_t *ent)
125 {
126 int count;
127 int i;
128 particle_t *p;
129 float angle;
130 float sr, sp, sy, cr, cp, cy;
131 vec3_t forward;
132 float dist;
133
134 dist = 64;
135 count = 50;
136
137 if (!avelocities[0][0])
138 {
139 for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
140 avelocities[i/3][i%3] = (rand()&255) * 0.01;
141 }
142
143
144 for (i=0 ; i<NUMVERTEXNORMALS ; i++)
145 {
146 angle = cl.time * avelocities[i][0];
147 sy = sin(angle);
148 cy = cos(angle);
149 angle = cl.time * avelocities[i][1];
150 sp = sin(angle);
151 cp = cos(angle);
152 angle = cl.time * avelocities[i][2];
153 sr = sin(angle);
154 cr = cos(angle);
155
156 forward[0] = cp*cy;
157 forward[1] = cp*sy;
158 forward[2] = -sp;
159
160 if (!free_particles)
161 return;
162 p = free_particles;
163 free_particles = p->next;
164 p->next = active_particles;
165 active_particles = p;
166
167 p->die = cl.time + 0.01;
168 p->color = 0x6f;
169 p->type = pt_explode;
170
171 p->org[0] = ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength;
172 p->org[1] = ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength;
173 p->org[2] = ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength;
174 }
175 }
176
177
178 /*
179 ===============
180 R_ClearParticles
181 ===============
182 */
R_ClearParticles(void)183 void R_ClearParticles (void)
184 {
185 int i;
186
187 free_particles = &particles[0];
188 active_particles = NULL;
189
190 for (i=0 ;i<r_numparticles ; i++)
191 particles[i].next = &particles[i+1];
192 particles[r_numparticles-1].next = NULL;
193 }
194
195
R_ReadPointFile_f(void)196 void R_ReadPointFile_f (void)
197 {
198 FILE *f;
199 vec3_t org;
200 int r;
201 int c;
202 particle_t *p;
203 char name[MAX_OSPATH];
204
205 sprintf (name,"maps/%s.pts", sv.name);
206
207 COM_FOpenFile (name, &f);
208 if (!f)
209 {
210 Con_Printf ("couldn't open %s\n", name);
211 return;
212 }
213
214 Con_Printf ("Reading %s...\n", name);
215 c = 0;
216 for ( ;; )
217 {
218 r = fscanf (f,"%f %f %f\n", &org[0], &org[1], &org[2]);
219 if (r != 3)
220 break;
221 c++;
222
223 if (!free_particles)
224 {
225 Con_Printf ("Not enough free particles\n");
226 break;
227 }
228 p = free_particles;
229 free_particles = p->next;
230 p->next = active_particles;
231 active_particles = p;
232
233 p->die = 99999;
234 p->color = (-c)&15;
235 p->type = pt_static;
236 VectorCopy (vec3_origin, p->vel);
237 VectorCopy (org, p->org);
238 }
239
240 fclose (f);
241 Con_Printf ("%i points read\n", c);
242 }
243
244 /*
245 ===============
246 R_ParseParticleEffect
247
248 Parse an effect out of the server message
249 ===============
250 */
R_ParseParticleEffect(void)251 void R_ParseParticleEffect (void)
252 {
253 vec3_t org, dir;
254 int i, count, msgcount, color;
255
256 for (i=0 ; i<3 ; i++)
257 org[i] = MSG_ReadCoord ();
258 for (i=0 ; i<3 ; i++)
259 dir[i] = MSG_ReadChar () * (1.0/16);
260 msgcount = MSG_ReadByte ();
261 color = MSG_ReadByte ();
262
263 if (msgcount == 255)
264 count = 1024;
265 else
266 count = msgcount;
267
268 R_RunParticleEffect (org, dir, color, count);
269 }
270
271 /*
272 ===============
273 R_ParticleExplosion
274
275 ===============
276 */
R_ParticleExplosion(vec3_t org)277 void R_ParticleExplosion (vec3_t org)
278 {
279 int i, j;
280 particle_t *p;
281
282 for (i=0 ; i<1024 ; i++)
283 {
284 if (!free_particles)
285 return;
286 p = free_particles;
287 free_particles = p->next;
288 p->next = active_particles;
289 active_particles = p;
290
291 p->die = cl.time + 5;
292 p->color = ramp1[0];
293 p->ramp = rand()&3;
294 if (i & 1)
295 {
296 p->type = pt_explode;
297 for (j=0 ; j<3 ; j++)
298 {
299 p->org[j] = org[j] + ((rand()%32)-16);
300 p->vel[j] = (rand()%512)-256;
301 }
302 }
303 else
304 {
305 p->type = pt_explode2;
306 for (j=0 ; j<3 ; j++)
307 {
308 p->org[j] = org[j] + ((rand()%32)-16);
309 p->vel[j] = (rand()%512)-256;
310 }
311 }
312 }
313 }
314
315 /*
316 ===============
317 R_ParticleExplosion2
318
319 ===============
320 */
R_ParticleExplosion2(vec3_t org,int colorStart,int colorLength)321 void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
322 {
323 int i, j;
324 particle_t *p;
325 int colorMod = 0;
326
327 for (i=0; i<512; i++)
328 {
329 if (!free_particles)
330 return;
331 p = free_particles;
332 free_particles = p->next;
333 p->next = active_particles;
334 active_particles = p;
335
336 p->die = cl.time + 0.3;
337 p->color = colorStart + (colorMod % colorLength);
338 colorMod++;
339
340 p->type = pt_blob;
341 for (j=0 ; j<3 ; j++)
342 {
343 p->org[j] = org[j] + ((rand()%32)-16);
344 p->vel[j] = (rand()%512)-256;
345 }
346 }
347 }
348
349 /*
350 ===============
351 R_BlobExplosion
352
353 ===============
354 */
R_BlobExplosion(vec3_t org)355 void R_BlobExplosion (vec3_t org)
356 {
357 int i, j;
358 particle_t *p;
359
360 for (i=0 ; i<1024 ; i++)
361 {
362 if (!free_particles)
363 return;
364 p = free_particles;
365 free_particles = p->next;
366 p->next = active_particles;
367 active_particles = p;
368
369 p->die = cl.time + 1 + (rand()&8)*0.05;
370
371 if (i & 1)
372 {
373 p->type = pt_blob;
374 p->color = 66 + rand()%6;
375 for (j=0 ; j<3 ; j++)
376 {
377 p->org[j] = org[j] + ((rand()%32)-16);
378 p->vel[j] = (rand()%512)-256;
379 }
380 }
381 else
382 {
383 p->type = pt_blob2;
384 p->color = 150 + rand()%6;
385 for (j=0 ; j<3 ; j++)
386 {
387 p->org[j] = org[j] + ((rand()%32)-16);
388 p->vel[j] = (rand()%512)-256;
389 }
390 }
391 }
392 }
393
394 /*
395 ===============
396 R_RunParticleEffect
397
398 ===============
399 */
R_RunParticleEffect(vec3_t org,vec3_t dir,int color,int count)400 void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
401 {
402 int i, j;
403 particle_t *p;
404
405 for (i=0 ; i<count ; i++)
406 {
407 if (!free_particles)
408 return;
409 p = free_particles;
410 free_particles = p->next;
411 p->next = active_particles;
412 active_particles = p;
413
414 if (count == 1024)
415 { // rocket explosion
416 p->die = cl.time + 5;
417 p->color = ramp1[0];
418 p->ramp = rand()&3;
419 if (i & 1)
420 {
421 p->type = pt_explode;
422 for (j=0 ; j<3 ; j++)
423 {
424 p->org[j] = org[j] + ((rand()%32)-16);
425 p->vel[j] = (rand()%512)-256;
426 }
427 }
428 else
429 {
430 p->type = pt_explode2;
431 for (j=0 ; j<3 ; j++)
432 {
433 p->org[j] = org[j] + ((rand()%32)-16);
434 p->vel[j] = (rand()%512)-256;
435 }
436 }
437 }
438 else
439 {
440 p->die = cl.time + 0.1*(rand()%5);
441 p->color = (color&~7) + (rand()&7);
442 p->type = pt_slowgrav;
443 for (j=0 ; j<3 ; j++)
444 {
445 p->org[j] = org[j] + ((rand()&15)-8);
446 p->vel[j] = dir[j]*15;// + (rand()%300)-150;
447 }
448 }
449 }
450 }
451
452
453 /*
454 ===============
455 R_LavaSplash
456
457 ===============
458 */
R_LavaSplash(vec3_t org)459 void R_LavaSplash (vec3_t org)
460 {
461 int i, j, k;
462 particle_t *p;
463 float vel;
464 vec3_t dir;
465
466 for (i=-16 ; i<16 ; i++)
467 for (j=-16 ; j<16 ; j++)
468 for (k=0 ; k<1 ; k++)
469 {
470 if (!free_particles)
471 return;
472 p = free_particles;
473 free_particles = p->next;
474 p->next = active_particles;
475 active_particles = p;
476
477 p->die = cl.time + 2 + (rand()&31) * 0.02;
478 p->color = 224 + (rand()&7);
479 p->type = pt_slowgrav;
480
481 dir[0] = j*8 + (rand()&7);
482 dir[1] = i*8 + (rand()&7);
483 dir[2] = 256;
484
485 p->org[0] = org[0] + dir[0];
486 p->org[1] = org[1] + dir[1];
487 p->org[2] = org[2] + (rand()&63);
488
489 VectorNormalize (dir);
490 vel = 50 + (rand()&63);
491 VectorScale (dir, vel, p->vel);
492 }
493 }
494
495 /*
496 ===============
497 R_TeleportSplash
498
499 ===============
500 */
R_TeleportSplash(vec3_t org)501 void R_TeleportSplash (vec3_t org)
502 {
503 int i, j, k;
504 particle_t *p;
505 float vel;
506 vec3_t dir;
507
508 for (i=-16 ; i<16 ; i+=4)
509 for (j=-16 ; j<16 ; j+=4)
510 for (k=-24 ; k<32 ; k+=4)
511 {
512 if (!free_particles)
513 return;
514 p = free_particles;
515 free_particles = p->next;
516 p->next = active_particles;
517 active_particles = p;
518
519 p->die = cl.time + 0.2 + (rand()&7) * 0.02;
520 p->color = 7 + (rand()&7);
521 p->type = pt_slowgrav;
522
523 dir[0] = j*8;
524 dir[1] = i*8;
525 dir[2] = k*8;
526
527 p->org[0] = org[0] + i + (rand()&3);
528 p->org[1] = org[1] + j + (rand()&3);
529 p->org[2] = org[2] + k + (rand()&3);
530
531 VectorNormalize (dir);
532 vel = 50 + (rand()&63);
533 VectorScale (dir, vel, p->vel);
534 }
535 }
536
R_RocketTrail(vec3_t start,vec3_t end,int type)537 void R_RocketTrail (vec3_t start, vec3_t end, int type)
538 {
539 vec3_t vec;
540 float len;
541 int j;
542 particle_t *p;
543 int dec;
544 static int tracercount;
545
546 VectorSubtract (end, start, vec);
547 len = VectorNormalize (vec);
548 if (type < 128)
549 dec = 3;
550 else
551 {
552 dec = 1;
553 type -= 128;
554 }
555
556 while (len > 0)
557 {
558 len -= dec;
559
560 if (!free_particles)
561 return;
562 p = free_particles;
563 free_particles = p->next;
564 p->next = active_particles;
565 active_particles = p;
566
567 VectorCopy (vec3_origin, p->vel);
568 p->die = cl.time + 2;
569
570 switch (type)
571 {
572 case 0: // rocket trail
573 p->ramp = (rand()&3);
574 p->color = ramp3[(int)p->ramp];
575 p->type = pt_fire;
576 for (j=0 ; j<3 ; j++)
577 p->org[j] = start[j] + ((rand()%6)-3);
578 break;
579
580 case 1: // smoke smoke
581 p->ramp = (rand()&3) + 2;
582 p->color = ramp3[(int)p->ramp];
583 p->type = pt_fire;
584 for (j=0 ; j<3 ; j++)
585 p->org[j] = start[j] + ((rand()%6)-3);
586 break;
587
588 case 2: // blood
589 p->type = pt_grav;
590 p->color = 67 + (rand()&3);
591 for (j=0 ; j<3 ; j++)
592 p->org[j] = start[j] + ((rand()%6)-3);
593 break;
594
595 case 3:
596 case 5: // tracer
597 p->die = cl.time + 0.5;
598 p->type = pt_static;
599 if (type == 3)
600 p->color = 52 + ((tracercount&4)<<1);
601 else
602 p->color = 230 + ((tracercount&4)<<1);
603
604 tracercount++;
605
606 VectorCopy (start, p->org);
607 if (tracercount & 1)
608 {
609 p->vel[0] = 30*vec[1];
610 p->vel[1] = 30*-vec[0];
611 }
612 else
613 {
614 p->vel[0] = 30*-vec[1];
615 p->vel[1] = 30*vec[0];
616 }
617 break;
618
619 case 4: // slight blood
620 p->type = pt_grav;
621 p->color = 67 + (rand()&3);
622 for (j=0 ; j<3 ; j++)
623 p->org[j] = start[j] + ((rand()%6)-3);
624 len -= 3;
625 break;
626
627 case 6: // voor trail
628 p->color = 9*16 + 8 + (rand()&3);
629 p->type = pt_static;
630 p->die = cl.time + 0.3;
631 for (j=0 ; j<3 ; j++)
632 p->org[j] = start[j] + ((rand()&15)-8);
633 break;
634 }
635
636
637 VectorAdd (start, vec, start);
638 }
639 }
640
641
642 /*
643 ===============
644 R_DrawParticles
645 ===============
646 */
647 extern cvar_t sv_gravity;
648
R_DrawParticles(void)649 void R_DrawParticles (void)
650 {
651 particle_t *p, *kill;
652 float grav;
653 int i;
654 float time2, time3;
655 float time1;
656 float dvel;
657 float frametime;
658 #ifdef USE_OPENGLES
659 float* pPos = gVertexBuffer;
660 unsigned char* pColor = (unsigned char*) gColorBuffer;
661 unsigned char* pUV = (unsigned char*) gTexCoordBuffer;
662 int particleIndex = 0;
663 int maxParticleIndex = (int) sizeof(gVertexBuffer) / (sizeof(float) * 3) - 3;
664 #endif
665 #ifdef GLQUAKE
666 vec3_t up, right;
667 float scale;
668
669 GL_Bind(particletexture);
670
671 glEnable (GL_BLEND);
672 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
673
674 #ifdef USE_OPENGLES
675 glEnableClientState(GL_COLOR_ARRAY);
676 glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer);
677 glTexCoordPointer(2, GL_BYTE, 0, gTexCoordBuffer);
678 glColorPointer(4, GL_UNSIGNED_BYTE, 0, gColorBuffer);
679 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
680 #else
681 glBegin (GL_TRIANGLES);
682 #endif
683
684 VectorScale (vup, 1.5, up);
685 VectorScale (vright, 1.5, right);
686 #else
687 D_StartParticles ();
688
689 VectorScale (vright, xscaleshrink, r_pright);
690 VectorScale (vup, yscaleshrink, r_pup);
691 VectorCopy (vpn, r_ppn);
692 #endif
693 frametime = cl.time - cl.oldtime;
694 time3 = frametime * 15;
695 time2 = frametime * 10; // 15;
696 time1 = frametime * 5;
697 grav = frametime * sv_gravity.value * 0.05;
698 dvel = 4*frametime;
699
700 for ( ;; )
701 {
702 kill = active_particles;
703 if (kill && kill->die < cl.time)
704 {
705 active_particles = kill->next;
706 kill->next = free_particles;
707 free_particles = kill;
708 continue;
709 }
710 break;
711 }
712
713 for (p=active_particles ; p ; p=p->next)
714 {
715 for ( ;; )
716 {
717 kill = p->next;
718 if (kill && kill->die < cl.time)
719 {
720 p->next = kill->next;
721 kill->next = free_particles;
722 free_particles = kill;
723 continue;
724 }
725 break;
726 }
727
728 #ifdef GLQUAKE
729 // hack a scale up to keep particles from disapearing
730 scale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1]
731 + (p->org[2] - r_origin[2])*vpn[2];
732 if (scale < 20)
733 scale = 1;
734 else
735 scale = 1 + scale * 0.004;
736 #ifdef USE_OPENGLES
737
738 if(particleIndex >= maxParticleIndex)
739 {
740 glDrawArrays(GL_TRIANGLES, 0, particleIndex);
741 particleIndex = 0;
742 pPos = gVertexBuffer;
743 pColor = (unsigned char*) gColorBuffer;
744 pUV = (unsigned char*) gTexCoordBuffer;
745 }
746
747 memcpy(pColor, (byte *)&d_8to24table[(int)p->color], 3);
748 pColor[3] = 255;
749 pColor += 4;
750 *pUV++ = 0;
751 *pUV++ = 0;
752 *pPos++ = p->org[0];
753 *pPos++ = p->org[1];
754 *pPos++ = p->org[2];
755
756 memcpy(pColor, (byte *)&d_8to24table[(int)p->color], 3);
757 pColor[3] = 255;
758 pColor += 4;
759 *pUV++ = 1;
760 *pUV++ = 0;
761 *pPos++ = p->org[0] + up[0]*scale;
762 *pPos++ = p->org[1] + up[1]*scale;
763 *pPos++ = p->org[2] + up[2]*scale;
764
765 memcpy(pColor, (byte *)&d_8to24table[(int)p->color], 3);
766 pColor[3] = 255;
767 pColor += 4;
768 *pUV++ = 0;
769 *pUV++ = 1;
770 *pPos++ = p->org[0] + right[0]*scale;
771 *pPos++ = p->org[1] + right[1]*scale;
772 *pPos++ = p->org[2] + right[2]*scale;
773
774 particleIndex += 3;
775
776 #else
777 glColor3ubv ((byte *)&d_8to24table[(int)p->color]);
778 glTexCoord2f (0,0);
779 glVertex3fv (p->org);
780 glTexCoord2f (1,0);
781 glVertex3f (p->org[0] + up[0]*scale, p->org[1] + up[1]*scale, p->org[2] + up[2]*scale);
782 glTexCoord2f (0,1);
783 glVertex3f (p->org[0] + right[0]*scale, p->org[1] + right[1]*scale, p->org[2] + right[2]*scale);
784 #endif // !USE_OPENGLES
785 #else
786 D_DrawParticle (p);
787 #endif
788 p->org[0] += p->vel[0]*frametime;
789 p->org[1] += p->vel[1]*frametime;
790 p->org[2] += p->vel[2]*frametime;
791
792 switch (p->type)
793 {
794 case pt_static:
795 break;
796 case pt_fire:
797 p->ramp += time1;
798 if (p->ramp >= 6)
799 p->die = -1;
800 else
801 p->color = ramp3[(int)p->ramp];
802 p->vel[2] += grav;
803 break;
804
805 case pt_explode:
806 p->ramp += time2;
807 if (p->ramp >=8)
808 p->die = -1;
809 else
810 p->color = ramp1[(int)p->ramp];
811 for (i=0 ; i<3 ; i++)
812 p->vel[i] += p->vel[i]*dvel;
813 p->vel[2] -= grav;
814 break;
815
816 case pt_explode2:
817 p->ramp += time3;
818 if (p->ramp >=8)
819 p->die = -1;
820 else
821 p->color = ramp2[(int)p->ramp];
822 for (i=0 ; i<3 ; i++)
823 p->vel[i] -= p->vel[i]*frametime;
824 p->vel[2] -= grav;
825 break;
826
827 case pt_blob:
828 for (i=0 ; i<3 ; i++)
829 p->vel[i] += p->vel[i]*dvel;
830 p->vel[2] -= grav;
831 break;
832
833 case pt_blob2:
834 for (i=0 ; i<2 ; i++)
835 p->vel[i] -= p->vel[i]*dvel;
836 p->vel[2] -= grav;
837 break;
838
839 case pt_grav:
840 #ifdef QUAKE2
841 p->vel[2] -= grav * 20;
842 break;
843 #endif
844 case pt_slowgrav:
845 p->vel[2] -= grav;
846 break;
847 default:
848 break;
849 }
850 }
851
852 #ifdef GLQUAKE
853 #ifdef USE_OPENGLES
854 glDrawArrays(GL_TRIANGLES, 0, particleIndex);
855 glDisableClientState(GL_COLOR_ARRAY);
856 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
857 #else
858 glEnd ();
859 #endif
860 glDisable (GL_BLEND);
861 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
862 #else
863 D_EndParticles ();
864 #endif
865 }
866
867