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 #include "te_scripts.h"
24
25 #define MAX_PARTICLES 2048 // default max # of particles at one
26 // time
27 #define MAX_EMITTERS 256 // maximum number of particle emitters
28 #define ABSOLUTE_MIN_PARTICLES 512 // no fewer than this no matter what's
29 // on the command line
30
31 typedef struct particleemitter_s {
32 ParticleEffect_t *effect; //what to spawn?
33 float die; //when to die?
34 float tick; //time between spawns
35 float nexttick; //time of next tick
36 int count; //how many to spawn on tick
37 vec3_t origin; //where to spawn
38 vec3_t vel; //velocity to base on
39 struct particleemitter_s* next;
40 } ParticleEmitter_t;
41
42 int ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61};
43 int ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66};
44 int ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3};
45
46 particle_t *active_particles, *free_particles;
47
48 particle_t *particles;
49 int r_numparticles;
50
51 ParticleEmitter_t *emitters, *active_emitters, *free_emitters;
52 ParticleEffect_t *particleEffects;
53
54 vec3_t r_pright, r_pup, r_ppn;
55
56 // <AWE> missing prototypes
57 extern qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace);
58
59
60 ParticleEffect_t *ParticleEffectDefinedForName(const char *name);
61 ParticleEffect_t *ParticleEffectForName(const char *name);
62
63 //fill an effect with default values
DefaultEffect(ParticleEffect_t * eff)64 void DefaultEffect(ParticleEffect_t *eff) {
65
66 int i;
67
68 strcpy(eff->name,"noname");
69 for (i=0; i<3; i++) {
70 eff->emmiterParams1[i] = -16;
71 eff->emmiterParams2[i] = 16;
72 eff->endcolormax[i] = 1;
73 eff->endcolormin[i] = 1;
74 eff->startcolormax[i] = 1;
75 eff->startcolormin[i] = 1;
76 eff->gravity[i] = 0;
77 eff->velocitymax[i] = 0;
78 eff->velocitymin[i] = 0;
79 eff->drag[i] = 1;
80 }
81
82 eff->emmiterType = emt_box; //currently only box is supported
83 eff->lifemin = 1;
84 eff->lifemax = 1;
85 eff->rotmin = 0;
86 eff->rotmax = 0;
87 eff->growmin = 0;
88 eff->growmax = 0;
89 eff->sizemin = 10;
90 eff->sizemax = 10;
91 eff->srcblend = GL_ONE;
92 eff->dstblend = GL_ONE;
93 eff->numbounces = 1;
94 eff->texture = 0;
95 eff->align = align_view;
96 eff->next = 0;
97 eff->velscale = 1/64;
98 eff->spawn = NULL;
99 }
100 /*
101 =====================
102 R_InitParticleEffects
103
104 Parse the particle effects out of the script file
105 =====================
106 */
R_AddEffectsScript(const char * filename)107 void R_AddEffectsScript(const char *filename) {
108
109 FILE *fin;
110 int token, var, i;
111 ParticleEffect_t *effect;
112 char *buffer;
113 //char newname[256];
114 char* str;
115
116 buffer = COM_LoadTempFile (filename);
117
118 if (!buffer) {
119 Con_Printf("\002Can't load particle effects from: %s\n",filename);
120 return;
121 }
122
123 SC_Start(buffer,strlen(buffer));
124
125 Con_Printf("Loading particle effects from: %s\n",filename);
126
127 while ( (token = SC_ParseToken()) != TOK_FILE_END) {
128
129 if (token == TOK_PARTICLE) {
130 str = SC_ParseIdent();
131
132 //if it already exists just overwrite the old one...
133 effect = ParticleEffectDefinedForName(str);
134 if (!effect) {
135 effect = (ParticleEffect_t *)Hunk_Alloc(sizeof(ParticleEffect_t));
136 DefaultEffect(effect);
137 effect->next = particleEffects;
138 particleEffects = effect;
139 strcpy(effect->name,str);
140 //Con_Printf("effect %s\n",effect->name);
141 } else {
142 //Con_Printf("redifinition %s\n",effect->name);
143 }
144
145 if (SC_ParseToken() != '{') PARSERERROR("'{' expected");
146
147 while ((var = SC_ParseToken()) != '}' && (var != TOK_FILE_END) ) {
148 switch (var) {
149 case TOK_EMITTER:
150 //parse emmiter shape
151 str = SC_ParseIdent();
152
153 if (!strcmp(str,"box")) {
154 effect->emmiterType = emt_box;
155 } else {
156 PARSERERROR("Unknown emmiter shape");
157 }
158
159 //parse emmiter values
160 for (i=0; i<3; i++)
161 effect->emmiterParams1[i] = SC_ParseFloat();
162
163 for (i=0; i<3; i++)
164 effect->emmiterParams2[i] = SC_ParseFloat();
165 break;
166 case TOK_VELOCITY:
167 //parse velocity mins maxs
168 for (i=0; i<3; i++)
169 effect->velocitymin[i] = SC_ParseFloat();
170 for (i=0; i<3; i++)
171 effect->velocitymax[i] = SC_ParseFloat();
172 break;
173 case TOK_STARTCOLOR:
174 //parse color mins maxs
175 for (i=0; i<3; i++)
176 effect->startcolormin[i] = SC_ParseFloat();
177 for (i=0; i<3; i++)
178 effect->startcolormax[i] = SC_ParseFloat();
179 break;
180 case TOK_ENDCOLOR:
181 //parse color mins maxs
182 for (i=0; i<3; i++)
183 effect->endcolormin[i] = SC_ParseFloat();
184 for (i=0; i<3; i++)
185 effect->endcolormax[i] = SC_ParseFloat();
186 break;
187 case TOK_LIFETIME:
188 //parse lifetime mins maxs
189 effect->lifemin = SC_ParseFloat();
190 effect->lifemax = SC_ParseFloat();
191 break;
192 case TOK_FLAGS:
193 str = SC_ParseIdent();
194 break;
195 case TOK_GRAVITY:
196 for (i=0; i<3; i++)
197 effect->gravity[i] = SC_ParseFloat();
198 break;
199 case TOK_ROTATION:
200 effect->rotmin = SC_ParseFloat();
201 effect->rotmax = SC_ParseFloat();
202 break;
203 case TOK_GROW:
204 effect->growmin = SC_ParseFloat();
205 effect->growmax = SC_ParseFloat();
206 break;
207 case TOK_SIZE:
208 effect->sizemin = SC_ParseFloat();
209 effect->sizemax = SC_ParseFloat();
210 break;
211 case TOK_DRAG:
212 for (i=0; i<3; i++)
213 effect->drag[i] = SC_ParseFloat();
214 break;
215 case TOK_BLENDFUNC:
216 effect->srcblend = SC_BlendModeForName(SC_ParseIdent());
217 effect->dstblend = SC_BlendModeForName(SC_ParseIdent());
218 break;
219 case TOK_BOUNCES:
220 effect->numbounces = (int)SC_ParseFloat();
221 break;
222 case TOK_MAP:
223 effect->texture = EasyTgaLoad(SC_ParseString());
224 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
225 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
226 break;
227 case TOK_ORIENTATION:
228 str = SC_ParseIdent();
229 if (!strcmp(str,"view")) {
230 effect->align = align_view;
231 } else if (!strcmp(str,"vel")) {
232 //Con_Printf("Velocity aligned\n");
233 effect->align = align_vel;
234 effect->velscale = SC_ParseFloat();
235 } else if (!strcmp(str,"surface")) {
236 //Con_Printf("Velocity aligned\n");
237 effect->align = align_surf;
238 } else {
239 Con_Printf("\002Script error at line %i: Unknown orientation type %s\n",line_num,str);
240 }
241 break;
242 case TOK_ONHIT:
243 str = SC_ParseIdent();
244 effect->spawn = ParticleEffectForName(str);
245 if (!effect->spawn)
246 printf("\002Script error at line %i: Particle %s not defined yet \n",line_num,str);
247 break;
248 default:
249 Con_Printf("\002Script error at line %i: Unknown field (id%i/%s) for particle definition\n",line_num,var,str);
250 }
251 }
252 } else if (token == TOK_DECAL) {
253 while ((var = yylex()) != '}') {
254 //do nothing yet...
255 }
256 } else {
257 Con_Printf("\002Script error at line %i: Expected definiton (found id%i/%s)\n",line_num,var,str);
258 }
259 }
260
261 SC_End();
262 }
263
R_InitParticleEffects()264 void R_InitParticleEffects() {
265 //clear list
266 particleEffects = NULL;
267 //load all scripts
268 COM_FindAllExt("particles","particle",R_AddEffectsScript);
269 }
270
ParticleEffectDefinedForName(const char * name)271 ParticleEffect_t *ParticleEffectDefinedForName(const char *name) {
272
273 ParticleEffect_t *current;
274
275 current = particleEffects;
276
277 while (current) {
278 if (!strcmp(current->name,name)) {
279 return current;
280 }
281 current = current->next;
282 }
283 return NULL;
284 }
285
ParticleEffectForName(const char * name)286 ParticleEffect_t *ParticleEffectForName(const char *name) {
287
288 ParticleEffect_t *current;
289
290 current = ParticleEffectDefinedForName(name);
291 if (!current) Con_Printf("Effect not defined: %s\n",name);
292 return current;
293 }
294
295
RandomMinMax(float min,float max)296 float RandomMinMax(float min, float max) {
297 return min+((rand()%10000)/10000.0)*(max-min);
298 }
299
InitParticleFromEffect(ParticleEffect_t * effect,vec3_t org)300 particle_t *InitParticleFromEffect(ParticleEffect_t *effect, vec3_t org) {
301
302 particle_t *p;
303 int i;
304
305 if (!effect) return NULL;
306
307 if (effect->align == align_surf) {
308 //we can't spawn them here since we need extra information like the surface normal and such...
309 return NULL;
310 }
311
312 //allocate it
313 if (!free_particles)
314 return NULL;
315 p = free_particles;
316 free_particles = p->next;
317 p->next = active_particles;
318 active_particles = p;
319
320 //initialize the fields
321 p->lifetime = RandomMinMax(effect->lifemin,effect->lifemax);
322 p->die = cl.time + p->lifetime;
323 for (i=0; i<3; i++) {
324 p->vel[i] = RandomMinMax(effect->velocitymin[i],effect->velocitymax[i]);
325 p->startcolor[i] = RandomMinMax(effect->startcolormin[i],effect->startcolormax[i]);
326 p->endcolor[i] = RandomMinMax(effect->endcolormin[i],effect->endcolormax[i]);
327 p->org[i] = RandomMinMax(effect->emmiterParams1[i],effect->emmiterParams2[i])+org[i];
328 }
329
330 p->numbounces = effect->numbounces;
331 p->srcblend = effect->srcblend;
332 p->dstblend = effect->dstblend;
333 p->rspeed = RandomMinMax(effect->rotmin,effect->rotmax);
334 p->growspeed = RandomMinMax(effect->growmin,effect->growmax);
335 p->size = RandomMinMax(effect->sizemin,effect->sizemax);
336 if (effect->align == align_vel) {
337 p->velaligned = true;
338 } else {
339 p->velaligned = false;
340 }
341 p->velscale = effect->velscale;
342 p->texture = effect->texture;
343 p->spawn = effect->spawn;
344 VectorCopy(effect->gravity,p->gravity);
345 VectorCopy(effect->drag,p->drag);
346 return p;
347 }
348
349 /*
350 ===============
351 R_InitParticles
352 ===============
353 */
R_InitParticles(void)354 void R_InitParticles (void)
355 {
356 int i;
357
358 i = COM_CheckParm ("-particles");
359
360 if (i)
361 {
362 r_numparticles = (int)(Q_atoi(com_argv[i+1]));
363 if (r_numparticles < ABSOLUTE_MIN_PARTICLES)
364 r_numparticles = ABSOLUTE_MIN_PARTICLES;
365 }
366 else
367 {
368 r_numparticles = MAX_PARTICLES;
369 }
370
371 particles = (particle_t *)
372 Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles");
373
374 emitters = (ParticleEmitter_t *)
375 Hunk_AllocName (MAX_EMITTERS * sizeof(ParticleEmitter_t), "emitters");
376 }
377
378 /*
379 ===============
380 R_ParseBasicEmitter
381
382 Parse an emitter out of the server message
383 Basic emitters don't actually spawn an emitter...
384 ===============
385 */
R_ParseBasicEmitter(void)386 void R_ParseBasicEmitter (void)
387 {
388 vec3_t org;
389 int i, count;
390 char *name;
391 ParticleEffect_t *eff;
392 particle_t *p;
393
394 //Con_Printf("Particle effect!!\n");
395 //origin to spawn on
396 for (i=0 ; i<3 ; i++)
397 org[i] = MSG_ReadCoord ();
398
399 //number of particles to spawn
400 count = MSG_ReadByte ();
401
402 //name of effect to spawn
403 name = MSG_ReadString();
404
405 eff = ParticleEffectForName(name);
406 if (!eff) return;
407
408 for (i=0; i<count; i++) {
409 p = InitParticleFromEffect(eff,org);
410 }
411 }
412
R_ParseExtendedEmitter(void)413 void R_ParseExtendedEmitter (void)
414 {
415 vec3_t org, vel;
416 int i, count;
417 char *name;
418 ParticleEffect_t *eff;
419 ParticleEmitter_t *emt;
420 float lifetime, tick;
421
422 //Con_Printf("Particle effect22!!\n");
423 //origin to spawn on
424 for (i=0 ; i<3 ; i++)
425 org[i] = MSG_ReadCoord ();
426
427 //velocity to spawn on
428 for (i=0 ; i<3 ; i++)
429 vel[i] = MSG_ReadCoord ();
430
431 //number of particles to spawn
432 count = MSG_ReadByte ();
433
434 //duration to live
435 lifetime = MSG_ReadLong () / 100.0;
436
437 //animation time
438 tick = MSG_ReadLong () / 100.0;
439
440 //name of effect to spawn
441 name = MSG_ReadString();
442
443 eff = ParticleEffectForName(name);
444 if (!eff) return;
445
446 //allocate it
447 if (!free_emitters)
448 return;
449 emt = free_emitters;
450 free_emitters = emt->next;
451 emt->next = active_emitters;
452 active_emitters = emt;
453
454 emt->effect = eff;
455 VectorCopy(org,emt->origin);
456 VectorCopy(vel,emt->vel);
457 emt->die = cl.time+lifetime;
458 emt->tick = tick;
459 emt->count = count;
460 emt->nexttick = 0;
461 }
462
463
464
465
466
467
468
469
470 /*
471 ===============
472 R_EntityParticles
473 ===============
474 */
475
476 #define NUMVERTEXNORMALS 162
477 extern float r_avertexnormals[NUMVERTEXNORMALS][3];
478 vec3_t avelocities[NUMVERTEXNORMALS];
479 float beamlength = 16;
480 vec3_t avelocity = {23, 7, 3};
481 float partstep = 0.01;
482 float timescale = 0.01;
483
R_EntityParticles(entity_t * ent)484 void R_EntityParticles (entity_t *ent)
485 {
486 int count;
487 int i;
488 particle_t *p;
489 float angle;
490 float sr, sp, sy, cr, cp, cy;
491 vec3_t forward;
492 float dist;
493 ParticleEffect_t *eff;
494
495 dist = 64;
496 count = 50;
497
498 if (!avelocities[0][0])
499 {
500 for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
501 avelocities[0][i] = (rand()&255) * 0.01;
502 }
503
504
505 eff = ParticleEffectForName("pt_entityparticles");
506 if (!eff) return;
507
508 for (i=0 ; i<NUMVERTEXNORMALS ; i++)
509 {
510 angle = cl.time * avelocities[i][0];
511 sy = sin(angle);
512 cy = cos(angle);
513 angle = cl.time * avelocities[i][1];
514 sp = sin(angle);
515 cp = cos(angle);
516 angle = cl.time * avelocities[i][2];
517 sr = sin(angle);
518 cr = cos(angle);
519
520 forward[0] = cp*cy;
521 forward[1] = cp*sy;
522 forward[2] = -sp;
523
524 p = InitParticleFromEffect(eff,ent->origin);
525 if (!p) return;
526
527 p->org[0] = ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength;
528 p->org[1] = ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength;
529 p->org[2] = ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength;
530 }
531 }
532
533
534 /*
535 ===============
536 R_ClearParticles
537 ===============
538 */
R_ClearParticles(void)539 void R_ClearParticles (void)
540 {
541 int i;
542
543 //remove all particles
544 free_particles = &particles[0];
545 active_particles = NULL;
546
547 for (i=0 ;i<r_numparticles ; i++)
548 particles[i].next = &particles[i+1];
549 particles[r_numparticles-1].next = NULL;
550
551 //remove all emitters
552 free_emitters = &emitters[0];
553 active_emitters = NULL;
554
555 for (i=0 ;i<MAX_EMITTERS ; i++)
556 emitters[i].next = &emitters[i+1];
557 emitters[MAX_EMITTERS-1].next = NULL;
558 }
559
560
R_ReadPointFile_f(void)561 void R_ReadPointFile_f (void)
562 {
563 FILE *f;
564 vec3_t org;
565 int r;
566 int c;
567 particle_t *p;
568 char name[MAX_OSPATH];
569 ParticleEffect_t *eff;
570
571 sprintf (name,"maps/%s.pts", sv.name);
572
573 COM_FOpenFile (name, &f);
574 if (!f)
575 {
576 Con_Printf ("couldn't open %s\n", name);
577 return;
578 }
579
580 eff = ParticleEffectForName("pt_pointfile");
581 if (!eff) return;
582
583 Con_Printf ("Reading %s...\n", name);
584 c = 0;
585 for ( ;; )
586 {
587 r = fscanf (f,"%f %f %f\n", &org[0], &org[1], &org[2]);
588 if (r != 3)
589 break;
590 c++;
591
592 p = InitParticleFromEffect(eff,org);
593 if (!p) return;
594 VectorCopy (vec3_origin, p->vel);
595 }
596
597 fclose (f);
598 Con_Printf ("%i points read\n", c);
599 }
600
601 /*
602 ===============
603 R_ParseParticleEffect
604
605 Parse an effect out of the server message
606 ===============
607 */
R_ParseParticleEffect(void)608 void R_ParseParticleEffect (void)
609 {
610 vec3_t org, dir;
611 int i, count, msgcount, color;
612
613 for (i=0 ; i<3 ; i++)
614 org[i] = MSG_ReadCoord ();
615 for (i=0 ; i<3 ; i++)
616 dir[i] = MSG_ReadChar () * (1.0/16);
617 msgcount = MSG_ReadByte ();
618 color = MSG_ReadByte ();
619
620 if (msgcount == 255)
621 count = 1024;
622 else
623 count = msgcount;
624
625 R_RunParticleEffect (org, dir, color, count);
626 }
627
628 /*
629 ===============
630 R_ParticleGunHits
631
632 PENTA: When a gun hits the wall
633 ===============
634 */
R_ParticleGunHits(vec3_t org,int type)635 void R_ParticleGunHits (vec3_t org, int type)
636 {
637 int i, j;
638 particle_t *p;
639 ParticleEffect_t *eff;
640 /*
641 #define TE_SPIKE 0
642 #define TE_SUPERSPIKE 1
643
644 #define TE_EXPLOSION 3
645 #define TE_TAREXPLOSION 4
646 #define TE_LIGHTNING1 5
647 #define TE_LIGHTNING2 6
648 #define TE_WIZSPIKE 7
649 #define TE_KNIGHTSPIKE 8
650 #define TE_LIGHTNING3 9
651 #define TE_LAVASPLASH 10
652 #define TE_TELEPORT 11
653 #define TE_EXPLOSION2 12
654 */
655 switch (type) {
656
657 //Shotgun hitting wall
658 case TE_GUNSHOT:
659
660 eff = ParticleEffectForName("pt_gunshot");
661 for (i=0; i<2; i++) {
662 InitParticleFromEffect(eff,org);
663 }
664
665 eff = ParticleEffectForName("pt_gunshotsmoke");
666 for (i=0; i<1; i++) {
667 InitParticleFromEffect(eff,org);
668 }
669 break;
670 //Nails hitting wall
671 case TE_SPIKE:
672 case TE_SUPERSPIKE:
673 for (i=0 ; i<6 ; i++)
674 {
675
676 eff = ParticleEffectForName("pt_spike");
677 for (i=0; i<6; i++) {
678 InitParticleFromEffect(eff,org);
679 }
680 }
681 break;
682 //lightining hitting wall
683 case TE_LIGHTNING1:
684 case TE_LIGHTNING2:
685 case TE_LIGHTNING3:
686 eff = ParticleEffectForName("pt_lightning");
687 for (i=0; i<6; i++) {
688 InitParticleFromEffect(eff,org);
689 }
690 break;
691 default:
692 break;
693 }
694 }
695
696 /*
697 ===============
698 R_ParticleHitBlood
699
700 PENTA: Changes
701 ===============
702 */
R_ParticleHitBlood(vec3_t org,int color)703 void R_ParticleHitBlood (vec3_t org, int color)
704 {
705 int i, j;
706 particle_t *p;
707 ParticleEffect_t *eff;
708
709 //Con_Printf("blood\n");
710
711
712 eff = ParticleEffectForName("pt_hitblood1");
713 for (i=0 ; i<1 ; i++)
714 {
715 InitParticleFromEffect(eff,org);
716 }
717
718 eff = ParticleEffectForName("pt_hitblood2");
719 for (i=0 ; i<2 ; i++)
720 {
721 InitParticleFromEffect(eff,org);
722 }
723 }
724 /*
725 ===============
726 R_ParticleExplosion
727
728 PENTA: Changes
729 ===============
730 */
R_ParticleExplosion(vec3_t org)731 void R_ParticleExplosion (vec3_t org)
732 {
733 int i, j;
734 particle_t *p;
735 ParticleEffect_t *eff;
736
737 eff = ParticleEffectForName("pt_explosion1");
738 for (i=0 ; i<128 ; i++)
739 {
740 InitParticleFromEffect(eff,org);
741 }
742
743 eff = ParticleEffectForName("pt_explosion2");
744 for (i=0 ; i<128 ; i++)
745 {
746 InitParticleFromEffect(eff,org);
747 }
748 }
749
750 /*
751 ===============
752 R_ParticleExplosion2
753
754 ===============
755 */
R_ParticleExplosion2(vec3_t org,int colorStart,int colorLength)756 void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
757 {
758 int i, j;
759 particle_t *p;
760 int colorMod = 0;
761 ParticleEffect_t *eff;
762
763 eff = ParticleEffectForName("pt_explosion1");
764 for (i=0 ; i<64 ; i++)
765 {
766 InitParticleFromEffect(eff,org);
767 }
768
769 }
770
771 /*
772 ===============
773 R_BlobExplosion
774
775 ===============
776 */
R_BlobExplosion(vec3_t org)777 void R_BlobExplosion (vec3_t org)
778 {
779 int i, j;
780 particle_t *p;
781 ParticleEffect_t *eff;
782
783 eff = ParticleEffectForName("pt_voreexplosion1");
784 for (i=0 ; i<64 ; i++)
785 {
786 InitParticleFromEffect(eff,org);
787 }
788
789 eff = ParticleEffectForName("pt_voreexplosion2");
790 for (i=0 ; i<64 ; i++)
791 {
792 InitParticleFromEffect(eff,org);
793 }
794 }
795
796 /*
797 ===============
798 R_RunParticleEffect
799
800 ===============
801 */
R_RunParticleEffect(vec3_t org,vec3_t dir,int color,int count)802 void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
803 {
804 int i, j;
805 particle_t *p;
806 ParticleEffect_t *eff;
807
808 if ((color == 225) || (color == 73)) {
809 R_ParticleHitBlood (org, color);
810 return;
811 }
812
813 if (count == 1024) {
814 R_ParticleExplosion(org);
815 }
816
817 eff = ParticleEffectForName("pt_genericsmoke");
818 for (i=0; i<count; i++) {
819 InitParticleFromEffect(eff,org);
820 }
821 }
822
823
824 /*
825 ===============
826 R_LavaSplash
827
828 ===============
829 */
R_LavaSplash(vec3_t org)830 void R_LavaSplash (vec3_t org)
831 {
832 int i, j, k;
833 particle_t *p;
834 float vel;
835 vec3_t dir;
836 ParticleEffect_t *eff;
837
838 eff = ParticleEffectForName("pt_lavasplash");
839 for (i=-16 ; i<16 ; i++)
840 for (j=-16 ; j<16 ; j++)
841 for (k=0 ; k<1 ; k++)
842 {
843 p = InitParticleFromEffect(eff,org);
844 if (!p) return;
845
846 dir[0] = j*8 + (rand()&7);
847 dir[1] = i*8 + (rand()&7);
848 dir[2] = 256;
849
850 p->org[0] = org[0] + dir[0];
851 p->org[1] = org[1] + dir[1];
852 p->org[2] = org[2] + (rand()&63);
853
854 VectorNormalize (dir);
855 vel = 50 + (rand()&63);
856 VectorScale (dir, vel, p->vel);
857 }
858 }
859
860 /*
861 ===============
862 R_TeleportSplash
863
864 ===============
865 */
R_TeleportSplash(vec3_t org)866 void R_TeleportSplash (vec3_t org)
867 {
868 int i, j, k;
869 particle_t *p;
870 float vel;
871 vec3_t dir;
872 ParticleEffect_t *eff;
873
874 eff = ParticleEffectForName("teleportsplash");
875 for (i=-16 ; i<16 ; i+=4)
876 for (j=-16 ; j<16 ; j+=4)
877 for (k=-24 ; k<32 ; k+=4)
878 {
879 p = InitParticleFromEffect(eff,org);
880 if (!p) return;
881
882 dir[0] = j*8;
883 dir[1] = i*8;
884 dir[2] = k*8;
885
886 p->org[0] = org[0] + i + (rand()&3);
887 p->org[1] = org[1] + j + (rand()&3);
888 p->org[2] = org[2] + k + (rand()&3);
889
890 VectorNormalize (dir);
891 vel = 50 + (rand()&63);
892 VectorScale (dir, vel, p->vel);
893 }
894 }
895
R_RocketTrail(vec3_t start,vec3_t end,int type)896 void R_RocketTrail (vec3_t start, vec3_t end, int type)
897 {
898 vec3_t vec;
899 float len;
900 int j;
901 particle_t *p;
902 int dec;
903 static int tracercount;
904 ParticleEffect_t *eff;
905
906 VectorSubtract (end, start, vec);
907 len = VectorNormalize (vec);
908 if (type < 128)
909
910 if ((type == 6) || (type == 5))
911 dec = 1;
912 else
913 dec = 10;
914 else
915 {
916 Con_Printf("ypt\n");
917 dec = 1;
918 type -= 128;
919 }
920
921
922 switch (type)
923 {
924 case 0: // rocket trail
925 eff = ParticleEffectForName("pt_rockettrail");
926 break;
927 case 1: // smoke smoke
928 eff = ParticleEffectForName("pt_smoke");
929 break;
930 case 2: // blood
931 eff = ParticleEffectForName("pt_bloodtrail");
932 break;
933 case 4: // slight blood
934 eff = ParticleEffectForName("pt_bloodtrail");
935 break;
936 case 3:
937 eff = ParticleEffectForName("pt_wizzardtrail");
938 break;
939 case 5: // tracer
940 eff = ParticleEffectForName("pt_hknighttrail");
941 break;
942 case 6: // voor trail
943 eff = ParticleEffectForName("pt_voretrail");
944 break;
945 default:
946 eff = ParticleEffectForName("pt_genericsmoke");
947 break;
948 }
949
950
951 while (len > 0)
952 {
953 len -= dec;
954
955 p = InitParticleFromEffect(eff,start);
956 if (!p) return;
957
958 switch (type)
959 {
960 case 0: // rocket trail
961 for (j=0 ; j<3 ; j++)
962 p->org[j] = start[j] + ((rand()%6)-3);
963 break;
964 case 1: // smoke smoke
965 for (j=0 ; j<3 ; j++)
966 p->org[j] = start[j] + ((rand()%6)-3);
967 break;
968 case 2: // blood
969 case 4: // slight blood
970 for (j=0 ; j<3 ; j++)
971 p->org[j] = start[j] + ((rand()%6)-3);
972 break;
973 case 6: // voor trail
974 for (j=0 ; j<3 ; j++) {
975 p->org[j] = start[j] + ((rand()%8)-4);
976 }
977 break;
978 }
979
980 VectorAdd (start, vec, start);
981 }
982 }
983
984
985 /*
986 ===============
987 R_DrawParticles
988 ===============
989
990 extern cvar_t sv_gravity;
991
992 void R_DrawParticles (void)
993 {
994 particle_t *p, *kill;
995 float grav;
996 int i;
997 float time2, time3;
998 float time1;
999 float dvel;
1000 float frametime;
1001
1002 #ifdef GLQUAKE
1003 vec3_t up, right, neworg;
1004 float scale, sscale;
1005
1006 glFogfv(GL_FOG_COLOR, color_black); //Done in actual function now (stops "triangle effect") - Eradicator
1007 glEnable (GL_BLEND);
1008 glBlendFunc (GL_ONE, GL_ONE);
1009 glEnable(GL_ALPHA_TEST);
1010 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1011 glDepthMask(0);
1012
1013 VectorScale (vup, 1, up);
1014 VectorScale (vright, 1, right);
1015 glMatrixMode(GL_TEXTURE);
1016 #else
1017 D_StartParticles ();
1018
1019 VectorScale (vright, xscaleshrink, r_pright);
1020 VectorScale (vup, yscaleshrink, r_pup);
1021 VectorCopy (vpn, r_ppn);
1022 #endif
1023 frametime = cl.time - cl.oldtime;
1024 time3 = frametime * 15;
1025 time2 = frametime * 10; // 15;
1026 time1 = frametime * 5;
1027 grav = frametime * sv_gravity.value * 0.05;
1028 dvel = 4*frametime;
1029
1030 for ( ;; )
1031 {
1032 kill = active_particles;
1033 if (kill && kill->die < cl.time)
1034 {
1035 active_particles = kill->next;
1036 kill->next = free_particles;
1037 free_particles = kill;
1038 continue;
1039 }
1040 break;
1041 }
1042
1043 for (p=active_particles ; p ; p=p->next)
1044 {
1045 for ( ;; )
1046 {
1047 kill = p->next;
1048 //XYZ
1049 if (kill && ((kill->die < cl.time) || (kill->numbounces <= 0)))
1050 {
1051 p->next = kill->next;
1052 kill->next = free_particles;
1053 free_particles = kill;
1054 continue;
1055 }
1056 break;
1057 }
1058
1059 #ifdef GLQUAKE
1060 // hack a scale up to keep particles from disapearing
1061
1062 //scale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1]
1063 // + (p->org[2] - r_origin[2])*vpn[2];
1064 //if (scale < 20)
1065 // scale = 1;
1066 //else
1067 // scale = 1 + scale * 0.004;
1068 //
1069 scale = 10;
1070
1071 if ((p->die - cl.time) < 0.5) {
1072 byte *c = (byte *)&d_8to24table[(int)p->color];
1073 float scale = 2*(p->die - cl.time);
1074 glColor3ub((byte)(c[0]*scale), (byte)(c[1]*scale), (byte)(c[2]*scale));
1075 } else {
1076 glColor3ubv ((byte *)&d_8to24table[(int)p->color]);
1077 }
1078
1079 GL_Bind(p->texture);
1080
1081 if ((p->texture == particletexture_smoke) ||
1082 (p->texture == particletexture_blood) ) scale = 50;
1083
1084 if (p->blendfunc == pb_add) {
1085 glBlendFunc (GL_ONE, GL_ONE);
1086 } else {
1087 glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
1088 }
1089 //XYZ
1090 if ((p->texture == particletexture_glow) ||
1091 (p->texture == particletexture_dirblood)){
1092 float lscale;
1093 VectorCopy (p->vel, up);
1094 VectorNormalize(up);
1095 CrossProduct(vpn,up,right);
1096 lscale = (Length(p->vel)/64);
1097 VectorScale(up,lscale,up);
1098 } else {
1099 VectorCopy (vup, up);
1100 VectorCopy (vright, right);
1101 }
1102
1103 glLoadIdentity();
1104 glTranslatef(0.5,0.5,0);
1105 glRotatef(p->rot,0,0,1);
1106 glTranslatef(-0.5,-0.5,0);
1107
1108 glBegin(GL_TRIANGLES);
1109 glTexCoord2f (0,0);
1110
1111 sscale = -scale/4;
1112 VectorMA(p->org,sscale,up,neworg);
1113 VectorMA(neworg,sscale,right,neworg);
1114
1115 glVertex3fv (neworg);
1116 glTexCoord2f (2,0);
1117 glVertex3f (neworg[0] + up[0]*scale, neworg[1] + up[1]*scale, neworg[2] + up[2]*scale);
1118 glTexCoord2f (0,2);
1119 glVertex3f (neworg[0] + right[0]*scale, neworg[1] + right[1]*scale, neworg[2] + right[2]*scale);
1120 glEnd();
1121 #else
1122 D_DrawParticle (p);
1123 #endif
1124
1125 neworg[0] = p->org[0]+p->vel[0]*frametime;
1126 neworg[1] = p->org[1]+p->vel[1]*frametime;
1127 neworg[2] = p->org[2]+p->vel[2]*frametime;
1128 p->rot = p->rot+p->rspeed*frametime;
1129
1130 {
1131 trace_t trace;
1132 float d;
1133
1134 memset (&trace, 0, sizeof(trace));
1135 trace.fraction = 1;
1136 SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, p->org, neworg, &trace);
1137
1138 if (trace.fraction < 1) {
1139 vec3_t tangent;
1140 //calc reflection vector
1141 d = DotProduct (p->vel, trace.plane.normal);
1142 VectorMA (p->vel, -2*d, trace.plane.normal, p->vel);
1143 VectorScale(p->vel,0.33,p->vel);
1144 VectorCopy(trace.endpos,p->org);
1145 //XYZ
1146 p->numbounces--;
1147
1148 CrossProduct(trace.plane.normal,p->vel,tangent);
1149 R_SpawnDecal(trace.endpos, trace.plane.normal, tangent, dt_blood);
1150 } else {
1151 VectorCopy(neworg,p->org);
1152 }
1153 }
1154
1155
1156
1157 switch (p->type)
1158 {
1159 case pt_static:
1160 break;
1161 case pt_fire:
1162 p->ramp += time1;
1163 if (p->ramp >= 6)
1164 p->die = -1;
1165 else
1166 p->color = ramp3[(int)p->ramp];
1167 p->vel[2] += grav;
1168 break;
1169
1170 case pt_explode:
1171 p->ramp += time2;
1172 if (p->ramp >=8)
1173 p->die = -1;
1174 else
1175 p->color = ramp1[(int)p->ramp];
1176 for (i=0 ; i<3 ; i++)
1177 p->vel[i] += p->vel[i]*dvel;
1178 p->vel[2] -= grav;
1179 break;
1180
1181 case pt_explode2:
1182 p->ramp += time3;
1183 if (p->ramp >=8)
1184 p->die = -1;
1185 else
1186 p->color = ramp2[(int)p->ramp];
1187 for (i=0 ; i<3 ; i++)
1188 p->vel[i] -= p->vel[i]*frametime;
1189 p->vel[2] -= grav;
1190 break;
1191
1192 case pt_blob:
1193 for (i=0 ; i<3 ; i++)
1194 p->vel[i] += p->vel[i]*dvel;
1195 p->vel[2] -= grav;
1196 break;
1197
1198 case pt_blob2:
1199 for (i=0 ; i<2 ; i++)
1200 p->vel[i] -= p->vel[i]*dvel;
1201 p->vel[2] -= grav;
1202 break;
1203
1204 case pt_grav:
1205 #ifdef QUAKE2
1206 p->vel[2] -= grav * 20;
1207 break;
1208 #endif
1209 case pt_slowgrav:
1210 p->vel[2] -= grav*6;
1211 break;
1212 }
1213 }
1214
1215 #ifdef GLQUAKE
1216 glDepthMask(1);
1217 glDisable (GL_BLEND);
1218 glDisable(GL_ALPHA_TEST);
1219 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1220 //XYZ
1221 glLoadIdentity();
1222 glMatrixMode(GL_MODELVIEW);
1223 glFogfv(GL_FOG_COLOR, fog_color); //Done in actual function now (stops "triangle effect") - Eradicator
1224 #else
1225 D_EndParticles ();
1226 #endif
1227 }
1228
1229 */
1230 extern cvar_t sv_gravity;
1231
R_DrawParticles(void)1232 void R_DrawParticles (void)
1233 {
1234 particle_t *p, *kill;
1235 float grav;
1236 int i;
1237 float time2, time3;
1238 float time1;
1239 float dvel, blend, blend1;
1240 float frametime;
1241 vec3_t up, right, neworg;
1242 float scale, sscale;
1243 ParticleEmitter_t *ekill, *emt;
1244
1245 if (gl_wireframe.value)
1246 return;
1247
1248 glFogfv(GL_FOG_COLOR, color_black); //Done in actual function now (stops "triangle effect") - Eradicator
1249 glEnable (GL_BLEND);
1250 glBlendFunc (GL_ONE, GL_ONE);
1251 glEnable(GL_ALPHA_TEST);
1252 glAlphaFunc(GL_GREATER,0.01);
1253 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1254 glDepthMask(0);
1255
1256 VectorScale (vup, 1, up);
1257 VectorScale (vright, 1, right);
1258 glMatrixMode(GL_TEXTURE);
1259
1260 frametime = cl.time - cl.oldtime;
1261 time3 = frametime * 15;
1262 time2 = frametime * 10; // 15;
1263 time1 = frametime * 5;
1264 grav = frametime * sv_gravity.value * 0.05;
1265 dvel = 4*frametime;
1266
1267 //remove expired emitters
1268 for ( ;; )
1269 {
1270 ekill = active_emitters;
1271 if (ekill && ekill->die < cl.time)
1272 {
1273 active_emitters = ekill->next;
1274 ekill->next = free_emitters;
1275 free_emitters = ekill;
1276 continue;
1277 }
1278 break;
1279 }
1280
1281 //Do the particle logic/drawing
1282 for (emt=active_emitters ; emt ; emt=emt->next)
1283 {
1284 for ( ;; )
1285 {
1286 ekill = emt->next;
1287 //XYZ
1288 if (ekill && (ekill->die < cl.time))
1289 {
1290 emt->next = ekill->next;
1291 ekill->next = free_emitters;
1292 free_emitters = ekill;
1293 continue;
1294 }
1295 break;
1296 }
1297
1298 if (emt->nexttick < cl.time) {
1299 vec3_t length;
1300 VectorSubtract(emt->origin, r_refdef.vieworg, length);
1301 //dont emit if we are to far away to see it
1302 if (Length(length) < 600.0f) {
1303 for (i=0; i<emt->count; i++) {
1304 InitParticleFromEffect(emt->effect,emt->origin);
1305 }
1306 }
1307 emt->nexttick = cl.time + emt->tick;
1308 }
1309 }
1310
1311 //remove expired particles
1312 for ( ;; )
1313 {
1314 kill = active_particles;
1315 if (kill && kill->die < cl.time)
1316 {
1317 active_particles = kill->next;
1318 kill->next = free_particles;
1319 free_particles = kill;
1320 continue;
1321 }
1322 break;
1323 }
1324
1325 //Do the particle logic/drawing
1326 for (p=active_particles ; p ; p=p->next)
1327 {
1328 for ( ;; )
1329 {
1330 kill = p->next;
1331 //XYZ
1332 if (kill && ((kill->die < cl.time) || (kill->numbounces <= 0)))
1333 {
1334 p->next = kill->next;
1335 kill->next = free_particles;
1336 free_particles = kill;
1337 continue;
1338 }
1339 break;
1340 }
1341
1342 scale = p->size;
1343 p->size += p->growspeed*frametime;
1344
1345 //calculate color based on life ...
1346 blend = (p->die-cl.time)/p->lifetime;
1347 blend1 = 1-blend;
1348 for (i=0; i<3; i++) {
1349 p->color[i] = p->startcolor[i] * blend + p->endcolor[i] * blend1;
1350 }
1351
1352 if ((p->die - cl.time) < 0.5) {
1353 float fade = 2*(p->die - cl.time);
1354 glColor4f(p->color[0]*fade, p->color[1]*fade, p->color[2]*fade, fade);
1355 } else {
1356 glColor3fv(&p->color[0]);
1357 }
1358
1359 GL_Bind(p->texture);
1360 glBlendFunc (p->srcblend, p->dstblend);
1361
1362 //Align with velocity
1363 if (p->velaligned){
1364 float lscale;
1365 VectorCopy (p->vel, up);
1366 VectorNormalize(up);
1367 CrossProduct(vpn,up,right);
1368 VectorNormalize(right);
1369 lscale = (Length(p->vel)*p->velscale);
1370 VectorScale(up,lscale,up);
1371 } else {
1372 VectorCopy (vup, up);
1373 VectorCopy (vright, right);
1374 }
1375
1376 glLoadIdentity();
1377 glTranslatef(0.5,0.5,0);
1378 glRotatef(p->rot,0,0,1);
1379 glTranslatef(-0.5,-0.5,0);
1380
1381 sscale = -scale/4;
1382 VectorMA(p->org,sscale,up,neworg);
1383 VectorMA(neworg,sscale,right,neworg);
1384
1385 // draw the particle as two triangles
1386 scale /= 2;
1387 glBegin(GL_TRIANGLE_FAN);
1388 glTexCoord2f (0,0);
1389 glVertex3fv (neworg);
1390 glTexCoord2f (0,1);
1391 glVertex3f (neworg[0] + up[0]*scale, neworg[1] + up[1]*scale,
1392 neworg[2] + up[2]*scale);
1393 glTexCoord2f (1,1);
1394 glVertex3f (neworg[0] + up[0]*scale + right[0]*scale, neworg[1] + up[1]*scale + right[1]*scale,
1395 neworg[2] + up[2]*scale + right[2]*scale);
1396 glTexCoord2f (1,0);
1397 glVertex3f (neworg[0] + right[0]*scale, neworg[1] + right[1]*scale,
1398 neworg[2] + right[2]*scale);
1399 glEnd();
1400 scale *= 2;
1401
1402 //calculate new position/rotation
1403 neworg[0] = p->org[0]+p->vel[0]*frametime;
1404 neworg[1] = p->org[1]+p->vel[1]*frametime;
1405 neworg[2] = p->org[2]+p->vel[2]*frametime;
1406 p->rot = p->rot+p->rspeed*frametime;
1407
1408 //do collision detection
1409 {
1410 trace_t trace;
1411 float d;
1412
1413 memset (&trace, 0, sizeof(trace));
1414 trace.fraction = 1;
1415 SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, p->org, neworg, &trace);
1416
1417 if (trace.fraction < 1) {
1418 vec3_t tangent;
1419 //calc reflection vector
1420 d = DotProduct (p->vel, trace.plane.normal);
1421 VectorMA (p->vel, -2*d, trace.plane.normal, p->vel);
1422 VectorScale(p->vel,0.33,p->vel);
1423 VectorCopy(trace.endpos,p->org);
1424 //XYZ
1425 p->numbounces--;
1426
1427 if (p->spawn) {
1428 CrossProduct(trace.plane.normal,p->vel,tangent);
1429 if (p->spawn->align == align_surf) {
1430 R_SpawnDecal(p->org, trace.plane.normal, tangent, p->spawn);
1431 } else {
1432 InitParticleFromEffect(p->spawn, p->org);
1433 }
1434 }
1435 } else {
1436 VectorCopy(neworg,p->org);
1437 }
1438 }
1439
1440 for (i=0; i<3; i++) {
1441 p->vel[i] += p->gravity[i]*frametime;
1442 }
1443
1444 for (i=0; i<3; i++) {
1445 p->vel[i] *= p->drag[i];
1446 }
1447 }
1448
1449 glDepthMask(1);
1450 glDisable (GL_BLEND);
1451 glDisable(GL_ALPHA_TEST);
1452 glAlphaFunc(GL_GREATER,0.666);
1453 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1454 //XYZ
1455 glLoadIdentity();
1456 glMatrixMode(GL_MODELVIEW);
1457 glFogfv(GL_FOG_COLOR, fog_color); //Done in actual function now (stops "triangle effect") - Eradicator
1458 }
1459