1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, 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 29int ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61}; 30int ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66}; 31int ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3}; 32 33particle_t *active_particles, *free_particles; 34 35particle_t *particles; 36int r_numparticles; 37 38vec3_t r_pright, r_pup, r_ppn; 39 40 41/* 42=============== 43R_InitParticles 44=============== 45*/ 46void 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 68/* 69=============== 70R_ClearParticles 71=============== 72*/ 73void R_ClearParticles (void) 74{ 75 int i; 76 77 free_particles = &particles[0]; 78 active_particles = NULL; 79 80 for (i=0 ;i<r_numparticles ; i++) 81 particles[i].next = &particles[i+1]; 82 particles[r_numparticles-1].next = NULL; 83} 84 85 86void R_ReadPointFile_f (void) 87{ 88 FILE *f; 89 vec3_t org; 90 int r; 91 int c; 92 particle_t *p; 93 char name[MAX_OSPATH]; 94 95// FIXME sprintf (name,"maps/%s.pts", sv.name); 96 97 COM_FOpenFile (name, &f); 98 if (!f) 99 { 100 Con_Printf ("couldn't open %s\n", name); 101 return; 102 } 103 104 Con_Printf ("Reading %s...\n", name); 105 c = 0; 106 for ( ;; ) 107 { 108 r = fscanf (f,"%f %f %f\n", &org[0], &org[1], &org[2]); 109 if (r != 3) 110 break; 111 c++; 112 113 if (!free_particles) 114 { 115 Con_Printf ("Not enough free particles\n"); 116 break; 117 } 118 p = free_particles; 119 free_particles = p->next; 120 p->next = active_particles; 121 active_particles = p; 122 123 p->die = 99999; 124 p->color = (-c)&15; 125 p->type = pt_static; 126 VectorCopy (vec3_origin, p->vel); 127 VectorCopy (org, p->org); 128 } 129 130 fclose (f); 131 Con_Printf ("%i points read\n", c); 132} 133 134/* 135=============== 136R_ParticleExplosion 137 138=============== 139*/ 140void R_ParticleExplosion (vec3_t org) 141{ 142 int i, j; 143 particle_t *p; 144 145 for (i=0 ; i<1024 ; i++) 146 { 147 if (!free_particles) 148 return; 149 p = free_particles; 150 free_particles = p->next; 151 p->next = active_particles; 152 active_particles = p; 153 154 p->die = cl.time + 5; 155 p->color = ramp1[0]; 156 p->ramp = rand()&3; 157 if (i & 1) 158 { 159 p->type = pt_explode; 160 for (j=0 ; j<3 ; j++) 161 { 162 p->org[j] = org[j] + ((rand()%32)-16); 163 p->vel[j] = (rand()%512)-256; 164 } 165 } 166 else 167 { 168 p->type = pt_explode2; 169 for (j=0 ; j<3 ; j++) 170 { 171 p->org[j] = org[j] + ((rand()%32)-16); 172 p->vel[j] = (rand()%512)-256; 173 } 174 } 175 } 176} 177 178/* 179=============== 180R_BlobExplosion 181 182=============== 183*/ 184void R_BlobExplosion (vec3_t org) 185{ 186 int i, j; 187 particle_t *p; 188 189 for (i=0 ; i<1024 ; i++) 190 { 191 if (!free_particles) 192 return; 193 p = free_particles; 194 free_particles = p->next; 195 p->next = active_particles; 196 active_particles = p; 197 198 p->die = cl.time + 1 + (rand()&8)*0.05; 199 200 if (i & 1) 201 { 202 p->type = pt_blob; 203 p->color = 66 + rand()%6; 204 for (j=0 ; j<3 ; j++) 205 { 206 p->org[j] = org[j] + ((rand()%32)-16); 207 p->vel[j] = (rand()%512)-256; 208 } 209 } 210 else 211 { 212 p->type = pt_blob2; 213 p->color = 150 + rand()%6; 214 for (j=0 ; j<3 ; j++) 215 { 216 p->org[j] = org[j] + ((rand()%32)-16); 217 p->vel[j] = (rand()%512)-256; 218 } 219 } 220 } 221} 222 223/* 224=============== 225R_RunParticleEffect 226 227=============== 228*/ 229void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count) 230{ 231 int i, j; 232 particle_t *p; 233 int scale; 234 235 if (count > 130) 236 scale = 3; 237 else if (count > 20) 238 scale = 2; 239 else 240 scale = 1; 241 242 for (i=0 ; i<count ; i++) 243 { 244 if (!free_particles) 245 return; 246 p = free_particles; 247 free_particles = p->next; 248 p->next = active_particles; 249 active_particles = p; 250 251 p->die = cl.time + 0.1*(rand()%5); 252 p->color = (color&~7) + (rand()&7); 253 p->type = pt_grav; 254 for (j=0 ; j<3 ; j++) 255 { 256 p->org[j] = org[j] + scale*((rand()&15)-8); 257 p->vel[j] = dir[j]*15;// + (rand()%300)-150; 258 } 259 } 260} 261 262 263/* 264=============== 265R_LavaSplash 266 267=============== 268*/ 269void R_LavaSplash (vec3_t org) 270{ 271 int i, j, k; 272 particle_t *p; 273 float vel; 274 vec3_t dir; 275 276 for (i=-16 ; i<16 ; i++) 277 for (j=-16 ; j<16 ; j++) 278 for (k=0 ; k<1 ; k++) 279 { 280 if (!free_particles) 281 return; 282 p = free_particles; 283 free_particles = p->next; 284 p->next = active_particles; 285 active_particles = p; 286 287 p->die = cl.time + 2 + (rand()&31) * 0.02; 288 p->color = 224 + (rand()&7); 289 p->type = pt_grav; 290 291 dir[0] = j*8 + (rand()&7); 292 dir[1] = i*8 + (rand()&7); 293 dir[2] = 256; 294 295 p->org[0] = org[0] + dir[0]; 296 p->org[1] = org[1] + dir[1]; 297 p->org[2] = org[2] + (rand()&63); 298 299 VectorNormalize (dir); 300 vel = 50 + (rand()&63); 301 VectorScale (dir, vel, p->vel); 302 } 303} 304 305/* 306=============== 307R_TeleportSplash 308 309=============== 310*/ 311void R_TeleportSplash (vec3_t org) 312{ 313 int i, j, k; 314 particle_t *p; 315 float vel; 316 vec3_t dir; 317 318 for (i=-16 ; i<16 ; i+=4) 319 for (j=-16 ; j<16 ; j+=4) 320 for (k=-24 ; k<32 ; k+=4) 321 { 322 if (!free_particles) 323 return; 324 p = free_particles; 325 free_particles = p->next; 326 p->next = active_particles; 327 active_particles = p; 328 329 p->die = cl.time + 0.2 + (rand()&7) * 0.02; 330 p->color = 7 + (rand()&7); 331 p->type = pt_grav; 332 333 dir[0] = j*8; 334 dir[1] = i*8; 335 dir[2] = k*8; 336 337 p->org[0] = org[0] + i + (rand()&3); 338 p->org[1] = org[1] + j + (rand()&3); 339 p->org[2] = org[2] + k + (rand()&3); 340 341 VectorNormalize (dir); 342 vel = 50 + (rand()&63); 343 VectorScale (dir, vel, p->vel); 344 } 345} 346 347void R_RocketTrail (vec3_t start, vec3_t end, int type) 348{ 349 vec3_t vec; 350 float len; 351 int j; 352 particle_t *p; 353 354 VectorSubtract (end, start, vec); 355 len = VectorNormalize (vec); 356 while (len > 0) 357 { 358 len -= 3; 359 360 if (!free_particles) 361 return; 362 p = free_particles; 363 free_particles = p->next; 364 p->next = active_particles; 365 active_particles = p; 366 367 VectorCopy (vec3_origin, p->vel); 368 p->die = cl.time + 2; 369 370 if (type == 4) 371 { // slight blood 372 p->type = pt_slowgrav; 373 p->color = 67 + (rand()&3); 374 for (j=0 ; j<3 ; j++) 375 p->org[j] = start[j] + ((rand()%6)-3); 376 len -= 3; 377 } 378 else if (type == 2) 379 { // blood 380 p->type = pt_slowgrav; 381 p->color = 67 + (rand()&3); 382 for (j=0 ; j<3 ; j++) 383 p->org[j] = start[j] + ((rand()%6)-3); 384 } 385 else if (type == 6) 386 { // voor trail 387 p->color = 9*16 + 8 + (rand()&3); 388 p->type = pt_static; 389 p->die = cl.time + 0.3; 390 for (j=0 ; j<3 ; j++) 391 p->org[j] = start[j] + ((rand()&15)-8); 392 } 393 else if (type == 1) 394 { // smoke smoke 395 p->ramp = (rand()&3) + 2; 396 p->color = ramp3[(int)p->ramp]; 397 p->type = pt_fire; 398 for (j=0 ; j<3 ; j++) 399 p->org[j] = start[j] + ((rand()%6)-3); 400 } 401 else if (type == 0) 402 { // rocket trail 403 p->ramp = (rand()&3); 404 p->color = ramp3[(int)p->ramp]; 405 p->type = pt_fire; 406 for (j=0 ; j<3 ; j++) 407 p->org[j] = start[j] + ((rand()%6)-3); 408 } 409 else if (type == 3 || type == 5) 410 { // tracer 411 static int tracercount; 412 413 p->die = cl.time + 0.5; 414 p->type = pt_static; 415 if (type == 3) 416 p->color = 52 + ((tracercount&4)<<1); 417 else 418 p->color = 230 + ((tracercount&4)<<1); 419 420 tracercount++; 421 422 VectorCopy (start, p->org); 423 if (tracercount & 1) 424 { 425 p->vel[0] = 30*vec[1]; 426 p->vel[1] = 30*-vec[0]; 427 } 428 else 429 { 430 p->vel[0] = 30*-vec[1]; 431 p->vel[1] = 30*vec[0]; 432 } 433 434 } 435 436 437 VectorAdd (start, vec, start); 438 } 439} 440 441 442/* 443=============== 444R_DrawParticles 445=============== 446*/ 447void R_DrawParticles (void) 448{ 449 particle_t *p, *kill; 450 float grav; 451 int i; 452 float time2, time3; 453 float time1; 454 float dvel; 455 float frametime; 456#ifdef GLQUAKE 457 unsigned char *at; 458 unsigned char theAlpha; 459 vec3_t up, right; 460 float scale; 461 qboolean alphaTestEnabled; 462 463 GL_Bind(particletexture); 464#ifdef USE_OPENGLES 465 // !!! Implement this 466 alphaTestEnabled = false; 467#else 468 alphaTestEnabled = glIsEnabled(GL_ALPHA_TEST); 469#endif 470 471 if (alphaTestEnabled) 472 glDisable(GL_ALPHA_TEST); 473 glEnable (GL_BLEND); 474 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 475 476#ifdef USE_OPENGLES 477 // !!! Implement this 478#else 479 glBegin (GL_TRIANGLES); 480#endif 481 482 VectorScale (vup, 1.5, up); 483 VectorScale (vright, 1.5, right); 484#else 485 D_StartParticles (); 486 487 VectorScale (vright, xscaleshrink, r_pright); 488 VectorScale (vup, yscaleshrink, r_pup); 489 VectorCopy (vpn, r_ppn); 490#endif 491 492 frametime = host_frametime; 493 time3 = frametime * 15; 494 time2 = frametime * 10; // 15; 495 time1 = frametime * 5; 496 grav = frametime * 800 * 0.05; 497 dvel = 4*frametime; 498 499 for ( ;; ) 500 { 501 kill = active_particles; 502 if (kill && kill->die < cl.time) 503 { 504 active_particles = kill->next; 505 kill->next = free_particles; 506 free_particles = kill; 507 continue; 508 } 509 break; 510 } 511 512 for (p=active_particles ; p ; p=p->next) 513 { 514 for ( ;; ) 515 { 516 kill = p->next; 517 if (kill && kill->die < cl.time) 518 { 519 p->next = kill->next; 520 kill->next = free_particles; 521 free_particles = kill; 522 continue; 523 } 524 break; 525 } 526 527#ifdef GLQUAKE 528 // hack a scale up to keep particles from disapearing 529 scale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1] 530 + (p->org[2] - r_origin[2])*vpn[2]; 531 if (scale < 20) 532 scale = 1; 533 else 534 scale = 1 + scale * 0.004; 535 at = (byte *)&d_8to24table[(int)p->color]; 536 if (p->type==pt_fire) 537 theAlpha = 255*(6-p->ramp)/6; 538// theAlpha = 192; 539// else if (p->type==pt_explode || p->type==pt_explode2) 540// theAlpha = 255*(8-p->ramp)/8; 541 else 542 theAlpha = 255; 543 544#ifdef USE_OPENGLES 545 // !!! Implement this 546#else 547 glColor4ub (*at, *(at+1), *(at+2), theAlpha); 548// glColor3ubv (at); 549// glColor3ubv ((byte *)&d_8to24table[(int)p->color]); 550 glTexCoord2f (0,0); 551 glVertex3fv (p->org); 552 glTexCoord2f (1,0); 553 glVertex3f (p->org[0] + up[0]*scale, p->org[1] + up[1]*scale, p->org[2] + up[2]*scale); 554 glTexCoord2f (0,1); 555 glVertex3f (p->org[0] + right[0]*scale, p->org[1] + right[1]*scale, p->org[2] + right[2]*scale); 556#endif 557 558#else 559 D_DrawParticle (p); 560#endif 561 562 p->org[0] += p->vel[0]*frametime; 563 p->org[1] += p->vel[1]*frametime; 564 p->org[2] += p->vel[2]*frametime; 565 566 switch (p->type) 567 { 568 case pt_static: 569 break; 570 case pt_fire: 571 p->ramp += time1; 572 if (p->ramp >= 6) 573 p->die = -1; 574 else 575 p->color = ramp3[(int)p->ramp]; 576 p->vel[2] += grav; 577 break; 578 579 case pt_explode: 580 p->ramp += time2; 581 if (p->ramp >=8) 582 p->die = -1; 583 else 584 p->color = ramp1[(int)p->ramp]; 585 for (i=0 ; i<3 ; i++) 586 p->vel[i] += p->vel[i]*dvel; 587 p->vel[2] -= grav; 588 break; 589 590 case pt_explode2: 591 p->ramp += time3; 592 if (p->ramp >=8) 593 p->die = -1; 594 else 595 p->color = ramp2[(int)p->ramp]; 596 for (i=0 ; i<3 ; i++) 597 p->vel[i] -= p->vel[i]*frametime; 598 p->vel[2] -= grav; 599 break; 600 601 case pt_blob: 602 for (i=0 ; i<3 ; i++) 603 p->vel[i] += p->vel[i]*dvel; 604 p->vel[2] -= grav; 605 break; 606 607 case pt_blob2: 608 for (i=0 ; i<2 ; i++) 609 p->vel[i] -= p->vel[i]*dvel; 610 p->vel[2] -= grav; 611 break; 612 613 case pt_slowgrav: 614 case pt_grav: 615 p->vel[2] -= grav; 616 break; 617 } 618 } 619 620#ifdef GLQUAKE 621#ifdef USE_OPENGLES 622 // !!! Implement this 623#else 624 glEnd (); 625#endif 626 glDisable (GL_BLEND); 627 if (alphaTestEnabled) 628 glEnable(GL_ALPHA_TEST); 629 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 630#else 631 D_EndParticles (); 632#endif 633} 634 635