cg_particles.c (40763B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 // Rafael particles 23 // cg_particles.c 24 25 #include "cg_local.h" 26 27 #define BLOODRED 2 28 #define EMISIVEFADE 3 29 #define GREY75 4 30 31 typedef struct particle_s 32 { 33 struct particle_s *next; 34 35 float time; 36 float endtime; 37 38 vec3_t org; 39 vec3_t vel; 40 vec3_t accel; 41 int color; 42 float colorvel; 43 float alpha; 44 float alphavel; 45 int type; 46 qhandle_t pshader; 47 48 float height; 49 float width; 50 51 float endheight; 52 float endwidth; 53 54 float start; 55 float end; 56 57 float startfade; 58 qboolean rotate; 59 int snum; 60 61 qboolean link; 62 63 // Ridah 64 int shaderAnim; 65 int roll; 66 67 int accumroll; 68 69 } cparticle_t; 70 71 typedef enum 72 { 73 P_NONE, 74 P_WEATHER, 75 P_FLAT, 76 P_SMOKE, 77 P_ROTATE, 78 P_WEATHER_TURBULENT, 79 P_ANIM, // Ridah 80 P_BAT, 81 P_BLEED, 82 P_FLAT_SCALEUP, 83 P_FLAT_SCALEUP_FADE, 84 P_WEATHER_FLURRY, 85 P_SMOKE_IMPACT, 86 P_BUBBLE, 87 P_BUBBLE_TURBULENT, 88 P_SPRITE 89 } particle_type_t; 90 91 #define MAX_SHADER_ANIMS 32 92 #define MAX_SHADER_ANIM_FRAMES 64 93 94 static char *shaderAnimNames[MAX_SHADER_ANIMS] = { 95 "explode1", 96 "blacksmokeanim", 97 "twiltb2", 98 "expblue", 99 "blacksmokeanimb", // uses 'explode1' sequence 100 "blood", 101 NULL 102 }; 103 static qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES]; 104 static int shaderAnimCounts[MAX_SHADER_ANIMS] = { 105 23, 106 25, 107 45, 108 25, 109 23, 110 5, 111 }; 112 static float shaderAnimSTRatio[MAX_SHADER_ANIMS] = { 113 1.405f, 114 1.0f, 115 1.0f, 116 1.0f, 117 1.0f, 118 1.0f, 119 }; 120 static int numShaderAnims; 121 // done. 122 123 #define PARTICLE_GRAVITY 40 124 #define MAX_PARTICLES 1024 * 8 125 126 cparticle_t *active_particles, *free_particles; 127 cparticle_t particles[MAX_PARTICLES]; 128 int cl_numparticles = MAX_PARTICLES; 129 130 qboolean initparticles = qfalse; 131 vec3_t vforward, vright, vup; 132 vec3_t rforward, rright, rup; 133 134 float oldtime; 135 136 /* 137 =============== 138 CL_ClearParticles 139 =============== 140 */ 141 void CG_ClearParticles (void) 142 { 143 int i; 144 145 memset( particles, 0, sizeof(particles) ); 146 147 free_particles = &particles[0]; 148 active_particles = NULL; 149 150 for (i=0 ;i<cl_numparticles ; i++) 151 { 152 particles[i].next = &particles[i+1]; 153 particles[i].type = 0; 154 } 155 particles[cl_numparticles-1].next = NULL; 156 157 oldtime = cg.time; 158 159 // Ridah, init the shaderAnims 160 for (i=0; shaderAnimNames[i]; i++) { 161 int j; 162 163 for (j=0; j<shaderAnimCounts[i]; j++) { 164 shaderAnims[i][j] = trap_R_RegisterShader( va("%s%i", shaderAnimNames[i], j+1) ); 165 } 166 } 167 numShaderAnims = i; 168 // done. 169 170 initparticles = qtrue; 171 } 172 173 174 /* 175 ===================== 176 CG_AddParticleToScene 177 ===================== 178 */ 179 void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha) 180 { 181 182 vec3_t point; 183 polyVert_t verts[4]; 184 float width; 185 float height; 186 float time, time2; 187 float ratio; 188 float invratio; 189 vec3_t color; 190 polyVert_t TRIverts[3]; 191 vec3_t rright2, rup2; 192 193 if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY 194 || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) 195 {// create a front facing polygon 196 197 if (p->type != P_WEATHER_FLURRY) 198 { 199 if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) 200 { 201 if (org[2] > p->end) 202 { 203 p->time = cg.time; 204 VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground 205 206 p->org[2] = ( p->start + crandom () * 4 ); 207 208 209 if (p->type == P_BUBBLE_TURBULENT) 210 { 211 p->vel[0] = crandom() * 4; 212 p->vel[1] = crandom() * 4; 213 } 214 215 } 216 } 217 else 218 { 219 if (org[2] < p->end) 220 { 221 p->time = cg.time; 222 VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground 223 224 while (p->org[2] < p->end) 225 { 226 p->org[2] += (p->start - p->end); 227 } 228 229 230 if (p->type == P_WEATHER_TURBULENT) 231 { 232 p->vel[0] = crandom() * 16; 233 p->vel[1] = crandom() * 16; 234 } 235 236 } 237 } 238 239 240 // Rafael snow pvs check 241 if (!p->link) 242 return; 243 244 p->alpha = 1; 245 } 246 247 // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp 248 if (Distance( cg.snap->ps.origin, org ) > 1024) { 249 return; 250 } 251 // done. 252 253 if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) 254 { 255 VectorMA (org, -p->height, vup, point); 256 VectorMA (point, -p->width, vright, point); 257 VectorCopy (point, verts[0].xyz); 258 verts[0].st[0] = 0; 259 verts[0].st[1] = 0; 260 verts[0].modulate[0] = 255; 261 verts[0].modulate[1] = 255; 262 verts[0].modulate[2] = 255; 263 verts[0].modulate[3] = 255 * p->alpha; 264 265 VectorMA (org, -p->height, vup, point); 266 VectorMA (point, p->width, vright, point); 267 VectorCopy (point, verts[1].xyz); 268 verts[1].st[0] = 0; 269 verts[1].st[1] = 1; 270 verts[1].modulate[0] = 255; 271 verts[1].modulate[1] = 255; 272 verts[1].modulate[2] = 255; 273 verts[1].modulate[3] = 255 * p->alpha; 274 275 VectorMA (org, p->height, vup, point); 276 VectorMA (point, p->width, vright, point); 277 VectorCopy (point, verts[2].xyz); 278 verts[2].st[0] = 1; 279 verts[2].st[1] = 1; 280 verts[2].modulate[0] = 255; 281 verts[2].modulate[1] = 255; 282 verts[2].modulate[2] = 255; 283 verts[2].modulate[3] = 255 * p->alpha; 284 285 VectorMA (org, p->height, vup, point); 286 VectorMA (point, -p->width, vright, point); 287 VectorCopy (point, verts[3].xyz); 288 verts[3].st[0] = 1; 289 verts[3].st[1] = 0; 290 verts[3].modulate[0] = 255; 291 verts[3].modulate[1] = 255; 292 verts[3].modulate[2] = 255; 293 verts[3].modulate[3] = 255 * p->alpha; 294 } 295 else 296 { 297 VectorMA (org, -p->height, vup, point); 298 VectorMA (point, -p->width, vright, point); 299 VectorCopy( point, TRIverts[0].xyz ); 300 TRIverts[0].st[0] = 1; 301 TRIverts[0].st[1] = 0; 302 TRIverts[0].modulate[0] = 255; 303 TRIverts[0].modulate[1] = 255; 304 TRIverts[0].modulate[2] = 255; 305 TRIverts[0].modulate[3] = 255 * p->alpha; 306 307 VectorMA (org, p->height, vup, point); 308 VectorMA (point, -p->width, vright, point); 309 VectorCopy (point, TRIverts[1].xyz); 310 TRIverts[1].st[0] = 0; 311 TRIverts[1].st[1] = 0; 312 TRIverts[1].modulate[0] = 255; 313 TRIverts[1].modulate[1] = 255; 314 TRIverts[1].modulate[2] = 255; 315 TRIverts[1].modulate[3] = 255 * p->alpha; 316 317 VectorMA (org, p->height, vup, point); 318 VectorMA (point, p->width, vright, point); 319 VectorCopy (point, TRIverts[2].xyz); 320 TRIverts[2].st[0] = 0; 321 TRIverts[2].st[1] = 1; 322 TRIverts[2].modulate[0] = 255; 323 TRIverts[2].modulate[1] = 255; 324 TRIverts[2].modulate[2] = 255; 325 TRIverts[2].modulate[3] = 255 * p->alpha; 326 } 327 328 } 329 else if (p->type == P_SPRITE) 330 { 331 vec3_t rr, ru; 332 vec3_t rotate_ang; 333 334 VectorSet (color, 1.0, 1.0, 1.0); 335 time = cg.time - p->time; 336 time2 = p->endtime - p->time; 337 ratio = time / time2; 338 339 width = p->width + ( ratio * ( p->endwidth - p->width) ); 340 height = p->height + ( ratio * ( p->endheight - p->height) ); 341 342 if (p->roll) { 343 vectoangles( cg.refdef.viewaxis[0], rotate_ang ); 344 rotate_ang[ROLL] += p->roll; 345 AngleVectors ( rotate_ang, NULL, rr, ru); 346 } 347 348 if (p->roll) { 349 VectorMA (org, -height, ru, point); 350 VectorMA (point, -width, rr, point); 351 } else { 352 VectorMA (org, -height, vup, point); 353 VectorMA (point, -width, vright, point); 354 } 355 VectorCopy (point, verts[0].xyz); 356 verts[0].st[0] = 0; 357 verts[0].st[1] = 0; 358 verts[0].modulate[0] = 255; 359 verts[0].modulate[1] = 255; 360 verts[0].modulate[2] = 255; 361 verts[0].modulate[3] = 255; 362 363 if (p->roll) { 364 VectorMA (point, 2*height, ru, point); 365 } else { 366 VectorMA (point, 2*height, vup, point); 367 } 368 VectorCopy (point, verts[1].xyz); 369 verts[1].st[0] = 0; 370 verts[1].st[1] = 1; 371 verts[1].modulate[0] = 255; 372 verts[1].modulate[1] = 255; 373 verts[1].modulate[2] = 255; 374 verts[1].modulate[3] = 255; 375 376 if (p->roll) { 377 VectorMA (point, 2*width, rr, point); 378 } else { 379 VectorMA (point, 2*width, vright, point); 380 } 381 VectorCopy (point, verts[2].xyz); 382 verts[2].st[0] = 1; 383 verts[2].st[1] = 1; 384 verts[2].modulate[0] = 255; 385 verts[2].modulate[1] = 255; 386 verts[2].modulate[2] = 255; 387 verts[2].modulate[3] = 255; 388 389 if (p->roll) { 390 VectorMA (point, -2*height, ru, point); 391 } else { 392 VectorMA (point, -2*height, vup, point); 393 } 394 VectorCopy (point, verts[3].xyz); 395 verts[3].st[0] = 1; 396 verts[3].st[1] = 0; 397 verts[3].modulate[0] = 255; 398 verts[3].modulate[1] = 255; 399 verts[3].modulate[2] = 255; 400 verts[3].modulate[3] = 255; 401 } 402 else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT) 403 {// create a front rotating facing polygon 404 405 if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) { 406 return; 407 } 408 409 if (p->color == BLOODRED) 410 VectorSet (color, 0.22f, 0.0f, 0.0f); 411 else if (p->color == GREY75) 412 { 413 float len; 414 float greyit; 415 float val; 416 len = Distance (cg.snap->ps.origin, org); 417 if (!len) 418 len = 1; 419 420 val = 4096/len; 421 greyit = 0.25 * val; 422 if (greyit > 0.5) 423 greyit = 0.5; 424 425 VectorSet (color, greyit, greyit, greyit); 426 } 427 else 428 VectorSet (color, 1.0, 1.0, 1.0); 429 430 time = cg.time - p->time; 431 time2 = p->endtime - p->time; 432 ratio = time / time2; 433 434 if (cg.time > p->startfade) 435 { 436 invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) ); 437 438 if (p->color == EMISIVEFADE) 439 { 440 float fval; 441 fval = (invratio * invratio); 442 if (fval < 0) 443 fval = 0; 444 VectorSet (color, fval , fval , fval ); 445 } 446 invratio *= p->alpha; 447 } 448 else 449 invratio = 1 * p->alpha; 450 451 if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) 452 invratio = 1; 453 454 if (invratio > 1) 455 invratio = 1; 456 457 width = p->width + ( ratio * ( p->endwidth - p->width) ); 458 height = p->height + ( ratio * ( p->endheight - p->height) ); 459 460 if (p->type != P_SMOKE_IMPACT) 461 { 462 vec3_t temp; 463 464 vectoangles (rforward, temp); 465 p->accumroll += p->roll; 466 temp[ROLL] += p->accumroll * 0.1; 467 AngleVectors ( temp, NULL, rright2, rup2); 468 } 469 else 470 { 471 VectorCopy (rright, rright2); 472 VectorCopy (rup, rup2); 473 } 474 475 if (p->rotate) 476 { 477 VectorMA (org, -height, rup2, point); 478 VectorMA (point, -width, rright2, point); 479 } 480 else 481 { 482 VectorMA (org, -p->height, vup, point); 483 VectorMA (point, -p->width, vright, point); 484 } 485 VectorCopy (point, verts[0].xyz); 486 verts[0].st[0] = 0; 487 verts[0].st[1] = 0; 488 verts[0].modulate[0] = 255 * color[0]; 489 verts[0].modulate[1] = 255 * color[1]; 490 verts[0].modulate[2] = 255 * color[2]; 491 verts[0].modulate[3] = 255 * invratio; 492 493 if (p->rotate) 494 { 495 VectorMA (org, -height, rup2, point); 496 VectorMA (point, width, rright2, point); 497 } 498 else 499 { 500 VectorMA (org, -p->height, vup, point); 501 VectorMA (point, p->width, vright, point); 502 } 503 VectorCopy (point, verts[1].xyz); 504 verts[1].st[0] = 0; 505 verts[1].st[1] = 1; 506 verts[1].modulate[0] = 255 * color[0]; 507 verts[1].modulate[1] = 255 * color[1]; 508 verts[1].modulate[2] = 255 * color[2]; 509 verts[1].modulate[3] = 255 * invratio; 510 511 if (p->rotate) 512 { 513 VectorMA (org, height, rup2, point); 514 VectorMA (point, width, rright2, point); 515 } 516 else 517 { 518 VectorMA (org, p->height, vup, point); 519 VectorMA (point, p->width, vright, point); 520 } 521 VectorCopy (point, verts[2].xyz); 522 verts[2].st[0] = 1; 523 verts[2].st[1] = 1; 524 verts[2].modulate[0] = 255 * color[0]; 525 verts[2].modulate[1] = 255 * color[1]; 526 verts[2].modulate[2] = 255 * color[2]; 527 verts[2].modulate[3] = 255 * invratio; 528 529 if (p->rotate) 530 { 531 VectorMA (org, height, rup2, point); 532 VectorMA (point, -width, rright2, point); 533 } 534 else 535 { 536 VectorMA (org, p->height, vup, point); 537 VectorMA (point, -p->width, vright, point); 538 } 539 VectorCopy (point, verts[3].xyz); 540 verts[3].st[0] = 1; 541 verts[3].st[1] = 0; 542 verts[3].modulate[0] = 255 * color[0]; 543 verts[3].modulate[1] = 255 * color[1]; 544 verts[3].modulate[2] = 255 * color[2]; 545 verts[3].modulate[3] = 255 * invratio; 546 547 } 548 else if (p->type == P_BLEED) 549 { 550 vec3_t rr, ru; 551 vec3_t rotate_ang; 552 float alpha; 553 554 alpha = p->alpha; 555 556 if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) 557 alpha = 1; 558 559 if (p->roll) 560 { 561 vectoangles( cg.refdef.viewaxis[0], rotate_ang ); 562 rotate_ang[ROLL] += p->roll; 563 AngleVectors ( rotate_ang, NULL, rr, ru); 564 } 565 else 566 { 567 VectorCopy (vup, ru); 568 VectorCopy (vright, rr); 569 } 570 571 VectorMA (org, -p->height, ru, point); 572 VectorMA (point, -p->width, rr, point); 573 VectorCopy (point, verts[0].xyz); 574 verts[0].st[0] = 0; 575 verts[0].st[1] = 0; 576 verts[0].modulate[0] = 111; 577 verts[0].modulate[1] = 19; 578 verts[0].modulate[2] = 9; 579 verts[0].modulate[3] = 255 * alpha; 580 581 VectorMA (org, -p->height, ru, point); 582 VectorMA (point, p->width, rr, point); 583 VectorCopy (point, verts[1].xyz); 584 verts[1].st[0] = 0; 585 verts[1].st[1] = 1; 586 verts[1].modulate[0] = 111; 587 verts[1].modulate[1] = 19; 588 verts[1].modulate[2] = 9; 589 verts[1].modulate[3] = 255 * alpha; 590 591 VectorMA (org, p->height, ru, point); 592 VectorMA (point, p->width, rr, point); 593 VectorCopy (point, verts[2].xyz); 594 verts[2].st[0] = 1; 595 verts[2].st[1] = 1; 596 verts[2].modulate[0] = 111; 597 verts[2].modulate[1] = 19; 598 verts[2].modulate[2] = 9; 599 verts[2].modulate[3] = 255 * alpha; 600 601 VectorMA (org, p->height, ru, point); 602 VectorMA (point, -p->width, rr, point); 603 VectorCopy (point, verts[3].xyz); 604 verts[3].st[0] = 1; 605 verts[3].st[1] = 0; 606 verts[3].modulate[0] = 111; 607 verts[3].modulate[1] = 19; 608 verts[3].modulate[2] = 9; 609 verts[3].modulate[3] = 255 * alpha; 610 611 } 612 else if (p->type == P_FLAT_SCALEUP) 613 { 614 float width, height; 615 float sinR, cosR; 616 617 if (p->color == BLOODRED) 618 VectorSet (color, 1, 1, 1); 619 else 620 VectorSet (color, 0.5, 0.5, 0.5); 621 622 time = cg.time - p->time; 623 time2 = p->endtime - p->time; 624 ratio = time / time2; 625 626 width = p->width + ( ratio * ( p->endwidth - p->width) ); 627 height = p->height + ( ratio * ( p->endheight - p->height) ); 628 629 if (width > p->endwidth) 630 width = p->endwidth; 631 632 if (height > p->endheight) 633 height = p->endheight; 634 635 sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2); 636 cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2); 637 638 VectorCopy (org, verts[0].xyz); 639 verts[0].xyz[0] -= sinR; 640 verts[0].xyz[1] -= cosR; 641 verts[0].st[0] = 0; 642 verts[0].st[1] = 0; 643 verts[0].modulate[0] = 255 * color[0]; 644 verts[0].modulate[1] = 255 * color[1]; 645 verts[0].modulate[2] = 255 * color[2]; 646 verts[0].modulate[3] = 255; 647 648 VectorCopy (org, verts[1].xyz); 649 verts[1].xyz[0] -= cosR; 650 verts[1].xyz[1] += sinR; 651 verts[1].st[0] = 0; 652 verts[1].st[1] = 1; 653 verts[1].modulate[0] = 255 * color[0]; 654 verts[1].modulate[1] = 255 * color[1]; 655 verts[1].modulate[2] = 255 * color[2]; 656 verts[1].modulate[3] = 255; 657 658 VectorCopy (org, verts[2].xyz); 659 verts[2].xyz[0] += sinR; 660 verts[2].xyz[1] += cosR; 661 verts[2].st[0] = 1; 662 verts[2].st[1] = 1; 663 verts[2].modulate[0] = 255 * color[0]; 664 verts[2].modulate[1] = 255 * color[1]; 665 verts[2].modulate[2] = 255 * color[2]; 666 verts[2].modulate[3] = 255; 667 668 VectorCopy (org, verts[3].xyz); 669 verts[3].xyz[0] += cosR; 670 verts[3].xyz[1] -= sinR; 671 verts[3].st[0] = 1; 672 verts[3].st[1] = 0; 673 verts[3].modulate[0] = 255 * color[0]; 674 verts[3].modulate[1] = 255 * color[1]; 675 verts[3].modulate[2] = 255 * color[2]; 676 verts[3].modulate[3] = 255; 677 } 678 else if (p->type == P_FLAT) 679 { 680 681 VectorCopy (org, verts[0].xyz); 682 verts[0].xyz[0] -= p->height; 683 verts[0].xyz[1] -= p->width; 684 verts[0].st[0] = 0; 685 verts[0].st[1] = 0; 686 verts[0].modulate[0] = 255; 687 verts[0].modulate[1] = 255; 688 verts[0].modulate[2] = 255; 689 verts[0].modulate[3] = 255; 690 691 VectorCopy (org, verts[1].xyz); 692 verts[1].xyz[0] -= p->height; 693 verts[1].xyz[1] += p->width; 694 verts[1].st[0] = 0; 695 verts[1].st[1] = 1; 696 verts[1].modulate[0] = 255; 697 verts[1].modulate[1] = 255; 698 verts[1].modulate[2] = 255; 699 verts[1].modulate[3] = 255; 700 701 VectorCopy (org, verts[2].xyz); 702 verts[2].xyz[0] += p->height; 703 verts[2].xyz[1] += p->width; 704 verts[2].st[0] = 1; 705 verts[2].st[1] = 1; 706 verts[2].modulate[0] = 255; 707 verts[2].modulate[1] = 255; 708 verts[2].modulate[2] = 255; 709 verts[2].modulate[3] = 255; 710 711 VectorCopy (org, verts[3].xyz); 712 verts[3].xyz[0] += p->height; 713 verts[3].xyz[1] -= p->width; 714 verts[3].st[0] = 1; 715 verts[3].st[1] = 0; 716 verts[3].modulate[0] = 255; 717 verts[3].modulate[1] = 255; 718 verts[3].modulate[2] = 255; 719 verts[3].modulate[3] = 255; 720 721 } 722 // Ridah 723 else if (p->type == P_ANIM) { 724 vec3_t rr, ru; 725 vec3_t rotate_ang; 726 int i, j; 727 728 time = cg.time - p->time; 729 time2 = p->endtime - p->time; 730 ratio = time / time2; 731 if (ratio >= 1.0f) { 732 ratio = 0.9999f; 733 } 734 735 width = p->width + ( ratio * ( p->endwidth - p->width) ); 736 height = p->height + ( ratio * ( p->endheight - p->height) ); 737 738 // if we are "inside" this sprite, don't draw 739 if (Distance( cg.snap->ps.origin, org ) < width/1.5) { 740 return; 741 } 742 743 i = p->shaderAnim; 744 j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]); 745 p->pshader = shaderAnims[i][j]; 746 747 if (p->roll) { 748 vectoangles( cg.refdef.viewaxis[0], rotate_ang ); 749 rotate_ang[ROLL] += p->roll; 750 AngleVectors ( rotate_ang, NULL, rr, ru); 751 } 752 753 if (p->roll) { 754 VectorMA (org, -height, ru, point); 755 VectorMA (point, -width, rr, point); 756 } else { 757 VectorMA (org, -height, vup, point); 758 VectorMA (point, -width, vright, point); 759 } 760 VectorCopy (point, verts[0].xyz); 761 verts[0].st[0] = 0; 762 verts[0].st[1] = 0; 763 verts[0].modulate[0] = 255; 764 verts[0].modulate[1] = 255; 765 verts[0].modulate[2] = 255; 766 verts[0].modulate[3] = 255; 767 768 if (p->roll) { 769 VectorMA (point, 2*height, ru, point); 770 } else { 771 VectorMA (point, 2*height, vup, point); 772 } 773 VectorCopy (point, verts[1].xyz); 774 verts[1].st[0] = 0; 775 verts[1].st[1] = 1; 776 verts[1].modulate[0] = 255; 777 verts[1].modulate[1] = 255; 778 verts[1].modulate[2] = 255; 779 verts[1].modulate[3] = 255; 780 781 if (p->roll) { 782 VectorMA (point, 2*width, rr, point); 783 } else { 784 VectorMA (point, 2*width, vright, point); 785 } 786 VectorCopy (point, verts[2].xyz); 787 verts[2].st[0] = 1; 788 verts[2].st[1] = 1; 789 verts[2].modulate[0] = 255; 790 verts[2].modulate[1] = 255; 791 verts[2].modulate[2] = 255; 792 verts[2].modulate[3] = 255; 793 794 if (p->roll) { 795 VectorMA (point, -2*height, ru, point); 796 } else { 797 VectorMA (point, -2*height, vup, point); 798 } 799 VectorCopy (point, verts[3].xyz); 800 verts[3].st[0] = 1; 801 verts[3].st[1] = 0; 802 verts[3].modulate[0] = 255; 803 verts[3].modulate[1] = 255; 804 verts[3].modulate[2] = 255; 805 verts[3].modulate[3] = 255; 806 } 807 // done. 808 809 if (!p->pshader) { 810 // (SA) temp commented out for DM 811 // CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type); 812 return; 813 } 814 815 if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY) 816 trap_R_AddPolyToScene( p->pshader, 3, TRIverts ); 817 else 818 trap_R_AddPolyToScene( p->pshader, 4, verts ); 819 820 } 821 822 // Ridah, made this static so it doesn't interfere with other files 823 static float roll = 0.0; 824 825 /* 826 =============== 827 CG_AddParticles 828 =============== 829 */ 830 void CG_AddParticles (void) 831 { 832 cparticle_t *p, *next; 833 float alpha; 834 float time, time2; 835 vec3_t org; 836 int color; 837 cparticle_t *active, *tail; 838 int type; 839 vec3_t rotate_ang; 840 841 if (!initparticles) 842 CG_ClearParticles (); 843 844 VectorCopy( cg.refdef.viewaxis[0], vforward ); 845 VectorCopy( cg.refdef.viewaxis[1], vright ); 846 VectorCopy( cg.refdef.viewaxis[2], vup ); 847 848 vectoangles( cg.refdef.viewaxis[0], rotate_ang ); 849 roll += ((cg.time - oldtime) * 0.1) ; 850 rotate_ang[ROLL] += (roll*0.9); 851 AngleVectors ( rotate_ang, rforward, rright, rup); 852 853 oldtime = cg.time; 854 855 active = NULL; 856 tail = NULL; 857 858 for (p=active_particles ; p ; p=next) 859 { 860 861 next = p->next; 862 863 time = (cg.time - p->time)*0.001; 864 865 alpha = p->alpha + time*p->alphavel; 866 if (alpha <= 0) 867 { // faded out 868 p->next = free_particles; 869 free_particles = p; 870 p->type = 0; 871 p->color = 0; 872 p->alpha = 0; 873 continue; 874 } 875 876 if (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT) 877 { 878 if (cg.time > p->endtime) 879 { 880 p->next = free_particles; 881 free_particles = p; 882 p->type = 0; 883 p->color = 0; 884 p->alpha = 0; 885 886 continue; 887 } 888 889 } 890 891 if (p->type == P_WEATHER_FLURRY) 892 { 893 if (cg.time > p->endtime) 894 { 895 p->next = free_particles; 896 free_particles = p; 897 p->type = 0; 898 p->color = 0; 899 p->alpha = 0; 900 901 continue; 902 } 903 } 904 905 906 if (p->type == P_FLAT_SCALEUP_FADE) 907 { 908 if (cg.time > p->endtime) 909 { 910 p->next = free_particles; 911 free_particles = p; 912 p->type = 0; 913 p->color = 0; 914 p->alpha = 0; 915 continue; 916 } 917 918 } 919 920 if ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) { 921 // temporary sprite 922 CG_AddParticleToScene (p, p->org, alpha); 923 p->next = free_particles; 924 free_particles = p; 925 p->type = 0; 926 p->color = 0; 927 p->alpha = 0; 928 continue; 929 } 930 931 p->next = NULL; 932 if (!tail) 933 active = tail = p; 934 else 935 { 936 tail->next = p; 937 tail = p; 938 } 939 940 if (alpha > 1.0) 941 alpha = 1; 942 943 color = p->color; 944 945 time2 = time*time; 946 947 org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2; 948 org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2; 949 org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2; 950 951 type = p->type; 952 953 CG_AddParticleToScene (p, org, alpha); 954 } 955 956 active_particles = active; 957 } 958 959 /* 960 ====================== 961 CG_AddParticles 962 ====================== 963 */ 964 void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent) 965 { 966 cparticle_t *p; 967 qboolean turb = qtrue; 968 969 if (!pshader) 970 CG_Printf ("CG_ParticleSnowFlurry pshader == ZERO!\n"); 971 972 if (!free_particles) 973 return; 974 p = free_particles; 975 free_particles = p->next; 976 p->next = active_particles; 977 active_particles = p; 978 p->time = cg.time; 979 p->color = 0; 980 p->alpha = 0.90f; 981 p->alphavel = 0; 982 983 p->start = cent->currentState.origin2[0]; 984 p->end = cent->currentState.origin2[1]; 985 986 p->endtime = cg.time + cent->currentState.time; 987 p->startfade = cg.time + cent->currentState.time2; 988 989 p->pshader = pshader; 990 991 if (rand()%100 > 90) 992 { 993 p->height = 32; 994 p->width = 32; 995 p->alpha = 0.10f; 996 } 997 else 998 { 999 p->height = 1; 1000 p->width = 1; 1001 } 1002 1003 p->vel[2] = -20; 1004 1005 p->type = P_WEATHER_FLURRY; 1006 1007 if (turb) 1008 p->vel[2] = -10; 1009 1010 VectorCopy(cent->currentState.origin, p->org); 1011 1012 p->org[0] = p->org[0]; 1013 p->org[1] = p->org[1]; 1014 p->org[2] = p->org[2]; 1015 1016 p->vel[0] = p->vel[1] = 0; 1017 1018 p->accel[0] = p->accel[1] = p->accel[2] = 0; 1019 1020 p->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16); 1021 p->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16); 1022 p->vel[2] += cent->currentState.angles[2]; 1023 1024 if (turb) 1025 { 1026 p->accel[0] = crandom () * 16; 1027 p->accel[1] = crandom () * 16; 1028 } 1029 1030 } 1031 1032 void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum) 1033 { 1034 cparticle_t *p; 1035 1036 if (!pshader) 1037 CG_Printf ("CG_ParticleSnow pshader == ZERO!\n"); 1038 1039 if (!free_particles) 1040 return; 1041 p = free_particles; 1042 free_particles = p->next; 1043 p->next = active_particles; 1044 active_particles = p; 1045 p->time = cg.time; 1046 p->color = 0; 1047 p->alpha = 0.40f; 1048 p->alphavel = 0; 1049 p->start = origin[2]; 1050 p->end = origin2[2]; 1051 p->pshader = pshader; 1052 p->height = 1; 1053 p->width = 1; 1054 1055 p->vel[2] = -50; 1056 1057 if (turb) 1058 { 1059 p->type = P_WEATHER_TURBULENT; 1060 p->vel[2] = -50 * 1.3; 1061 } 1062 else 1063 { 1064 p->type = P_WEATHER; 1065 } 1066 1067 VectorCopy(origin, p->org); 1068 1069 p->org[0] = p->org[0] + ( crandom() * range); 1070 p->org[1] = p->org[1] + ( crandom() * range); 1071 p->org[2] = p->org[2] + ( crandom() * (p->start - p->end)); 1072 1073 p->vel[0] = p->vel[1] = 0; 1074 1075 p->accel[0] = p->accel[1] = p->accel[2] = 0; 1076 1077 if (turb) 1078 { 1079 p->vel[0] = crandom() * 16; 1080 p->vel[1] = crandom() * 16; 1081 } 1082 1083 // Rafael snow pvs check 1084 p->snum = snum; 1085 p->link = qtrue; 1086 1087 } 1088 1089 void CG_ParticleBubble (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum) 1090 { 1091 cparticle_t *p; 1092 float randsize; 1093 1094 if (!pshader) 1095 CG_Printf ("CG_ParticleSnow pshader == ZERO!\n"); 1096 1097 if (!free_particles) 1098 return; 1099 p = free_particles; 1100 free_particles = p->next; 1101 p->next = active_particles; 1102 active_particles = p; 1103 p->time = cg.time; 1104 p->color = 0; 1105 p->alpha = 0.40f; 1106 p->alphavel = 0; 1107 p->start = origin[2]; 1108 p->end = origin2[2]; 1109 p->pshader = pshader; 1110 1111 randsize = 1 + (crandom() * 0.5); 1112 1113 p->height = randsize; 1114 p->width = randsize; 1115 1116 p->vel[2] = 50 + ( crandom() * 10 ); 1117 1118 if (turb) 1119 { 1120 p->type = P_BUBBLE_TURBULENT; 1121 p->vel[2] = 50 * 1.3; 1122 } 1123 else 1124 { 1125 p->type = P_BUBBLE; 1126 } 1127 1128 VectorCopy(origin, p->org); 1129 1130 p->org[0] = p->org[0] + ( crandom() * range); 1131 p->org[1] = p->org[1] + ( crandom() * range); 1132 p->org[2] = p->org[2] + ( crandom() * (p->start - p->end)); 1133 1134 p->vel[0] = p->vel[1] = 0; 1135 1136 p->accel[0] = p->accel[1] = p->accel[2] = 0; 1137 1138 if (turb) 1139 { 1140 p->vel[0] = crandom() * 4; 1141 p->vel[1] = crandom() * 4; 1142 } 1143 1144 // Rafael snow pvs check 1145 p->snum = snum; 1146 p->link = qtrue; 1147 1148 } 1149 1150 void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent) 1151 { 1152 1153 // using cent->density = enttime 1154 // cent->frame = startfade 1155 cparticle_t *p; 1156 1157 if (!pshader) 1158 CG_Printf ("CG_ParticleSmoke == ZERO!\n"); 1159 1160 if (!free_particles) 1161 return; 1162 p = free_particles; 1163 free_particles = p->next; 1164 p->next = active_particles; 1165 active_particles = p; 1166 p->time = cg.time; 1167 1168 p->endtime = cg.time + cent->currentState.time; 1169 p->startfade = cg.time + cent->currentState.time2; 1170 1171 p->color = 0; 1172 p->alpha = 1.0; 1173 p->alphavel = 0; 1174 p->start = cent->currentState.origin[2]; 1175 p->end = cent->currentState.origin2[2]; 1176 p->pshader = pshader; 1177 p->rotate = qfalse; 1178 p->height = 8; 1179 p->width = 8; 1180 p->endheight = 32; 1181 p->endwidth = 32; 1182 p->type = P_SMOKE; 1183 1184 VectorCopy(cent->currentState.origin, p->org); 1185 1186 p->vel[0] = p->vel[1] = 0; 1187 p->accel[0] = p->accel[1] = p->accel[2] = 0; 1188 1189 p->vel[2] = 5; 1190 1191 if (cent->currentState.frame == 1)// reverse gravity 1192 p->vel[2] *= -1; 1193 1194 p->roll = 8 + (crandom() * 4); 1195 } 1196 1197 1198 void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration) 1199 { 1200 1201 cparticle_t *p; 1202 1203 if (!free_particles) 1204 return; 1205 p = free_particles; 1206 free_particles = p->next; 1207 p->next = active_particles; 1208 active_particles = p; 1209 p->time = cg.time; 1210 1211 p->endtime = cg.time + duration; 1212 p->startfade = cg.time + duration/2; 1213 1214 p->color = EMISIVEFADE; 1215 p->alpha = 1.0; 1216 p->alphavel = 0; 1217 1218 p->height = 0.5; 1219 p->width = 0.5; 1220 p->endheight = 0.5; 1221 p->endwidth = 0.5; 1222 1223 p->pshader = cgs.media.tracerShader; 1224 1225 p->type = P_SMOKE; 1226 1227 VectorCopy(org, p->org); 1228 1229 p->vel[0] = vel[0]; 1230 p->vel[1] = vel[1]; 1231 p->vel[2] = vel[2]; 1232 p->accel[0] = p->accel[1] = p->accel[2] = 0; 1233 1234 p->accel[2] = -60; 1235 p->vel[2] += -20; 1236 1237 } 1238 1239 /* 1240 ====================== 1241 CG_ParticleExplosion 1242 ====================== 1243 */ 1244 1245 void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd) 1246 { 1247 cparticle_t *p; 1248 int anim; 1249 1250 if (animStr < (char *)10) 1251 CG_Error( "CG_ParticleExplosion: animStr is probably an index rather than a string" ); 1252 1253 // find the animation string 1254 for (anim=0; shaderAnimNames[anim]; anim++) { 1255 if (!stricmp( animStr, shaderAnimNames[anim] )) 1256 break; 1257 } 1258 if (!shaderAnimNames[anim]) { 1259 CG_Error("CG_ParticleExplosion: unknown animation string: %s\n", animStr); 1260 return; 1261 } 1262 1263 if (!free_particles) 1264 return; 1265 p = free_particles; 1266 free_particles = p->next; 1267 p->next = active_particles; 1268 active_particles = p; 1269 p->time = cg.time; 1270 p->alpha = 1.0; 1271 p->alphavel = 0; 1272 1273 if (duration < 0) { 1274 duration *= -1; 1275 p->roll = 0; 1276 } else { 1277 p->roll = crandom()*179; 1278 } 1279 1280 p->shaderAnim = anim; 1281 1282 p->width = sizeStart; 1283 p->height = sizeStart*shaderAnimSTRatio[anim]; // for sprites that are stretch in either direction 1284 1285 p->endheight = sizeEnd; 1286 p->endwidth = sizeEnd*shaderAnimSTRatio[anim]; 1287 1288 p->endtime = cg.time + duration; 1289 1290 p->type = P_ANIM; 1291 1292 VectorCopy( origin, p->org ); 1293 VectorCopy( vel, p->vel ); 1294 VectorClear( p->accel ); 1295 1296 } 1297 1298 // Rafael Shrapnel 1299 void CG_AddParticleShrapnel (localEntity_t *le) 1300 { 1301 return; 1302 } 1303 // done. 1304 1305 int CG_NewParticleArea (int num) 1306 { 1307 // const char *str; 1308 char *str; 1309 char *token; 1310 int type; 1311 vec3_t origin, origin2; 1312 int i; 1313 float range = 0; 1314 int turb; 1315 int numparticles; 1316 int snum; 1317 1318 str = (char *) CG_ConfigString (num); 1319 if (!str[0]) 1320 return (0); 1321 1322 // returns type 128 64 or 32 1323 token = COM_Parse (&str); 1324 type = atoi (token); 1325 1326 if (type == 1) 1327 range = 128; 1328 else if (type == 2) 1329 range = 64; 1330 else if (type == 3) 1331 range = 32; 1332 else if (type == 0) 1333 range = 256; 1334 else if (type == 4) 1335 range = 8; 1336 else if (type == 5) 1337 range = 16; 1338 else if (type == 6) 1339 range = 32; 1340 else if (type == 7) 1341 range = 64; 1342 1343 1344 for (i=0; i<3; i++) 1345 { 1346 token = COM_Parse (&str); 1347 origin[i] = atof (token); 1348 } 1349 1350 for (i=0; i<3; i++) 1351 { 1352 token = COM_Parse (&str); 1353 origin2[i] = atof (token); 1354 } 1355 1356 token = COM_Parse (&str); 1357 numparticles = atoi (token); 1358 1359 token = COM_Parse (&str); 1360 turb = atoi (token); 1361 1362 token = COM_Parse (&str); 1363 snum = atoi (token); 1364 1365 for (i=0; i<numparticles; i++) 1366 { 1367 if (type >= 4) 1368 CG_ParticleBubble (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum); 1369 else 1370 CG_ParticleSnow (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum); 1371 } 1372 1373 return (1); 1374 } 1375 1376 void CG_SnowLink (centity_t *cent, qboolean particleOn) 1377 { 1378 cparticle_t *p, *next; 1379 int id; 1380 1381 id = cent->currentState.frame; 1382 1383 for (p=active_particles ; p ; p=next) 1384 { 1385 next = p->next; 1386 1387 if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT) 1388 { 1389 if (p->snum == id) 1390 { 1391 if (particleOn) 1392 p->link = qtrue; 1393 else 1394 p->link = qfalse; 1395 } 1396 } 1397 1398 } 1399 } 1400 1401 void CG_ParticleImpactSmokePuff (qhandle_t pshader, vec3_t origin) 1402 { 1403 cparticle_t *p; 1404 1405 if (!pshader) 1406 CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n"); 1407 1408 if (!free_particles) 1409 return; 1410 p = free_particles; 1411 free_particles = p->next; 1412 p->next = active_particles; 1413 active_particles = p; 1414 p->time = cg.time; 1415 p->alpha = 0.25; 1416 p->alphavel = 0; 1417 p->roll = crandom()*179; 1418 1419 p->pshader = pshader; 1420 1421 p->endtime = cg.time + 1000; 1422 p->startfade = cg.time + 100; 1423 1424 p->width = rand()%4 + 8; 1425 p->height = rand()%4 + 8; 1426 1427 p->endheight = p->height *2; 1428 p->endwidth = p->width * 2; 1429 1430 p->endtime = cg.time + 500; 1431 1432 p->type = P_SMOKE_IMPACT; 1433 1434 VectorCopy( origin, p->org ); 1435 VectorSet(p->vel, 0, 0, 20); 1436 VectorSet(p->accel, 0, 0, 20); 1437 1438 p->rotate = qtrue; 1439 } 1440 1441 void CG_Particle_Bleed (qhandle_t pshader, vec3_t start, vec3_t dir, int fleshEntityNum, int duration) 1442 { 1443 cparticle_t *p; 1444 1445 if (!pshader) 1446 CG_Printf ("CG_Particle_Bleed pshader == ZERO!\n"); 1447 1448 if (!free_particles) 1449 return; 1450 p = free_particles; 1451 free_particles = p->next; 1452 p->next = active_particles; 1453 active_particles = p; 1454 p->time = cg.time; 1455 p->alpha = 1.0; 1456 p->alphavel = 0; 1457 p->roll = 0; 1458 1459 p->pshader = pshader; 1460 1461 p->endtime = cg.time + duration; 1462 1463 if (fleshEntityNum) 1464 p->startfade = cg.time; 1465 else 1466 p->startfade = cg.time + 100; 1467 1468 p->width = 4; 1469 p->height = 4; 1470 1471 p->endheight = 4+rand()%3; 1472 p->endwidth = p->endheight; 1473 1474 p->type = P_SMOKE; 1475 1476 VectorCopy( start, p->org ); 1477 p->vel[0] = 0; 1478 p->vel[1] = 0; 1479 p->vel[2] = -20; 1480 VectorClear( p->accel ); 1481 1482 p->rotate = qfalse; 1483 1484 p->roll = rand()%179; 1485 1486 p->color = BLOODRED; 1487 p->alpha = 0.75; 1488 1489 } 1490 1491 void CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent) 1492 { 1493 cparticle_t *p; 1494 1495 int time; 1496 int time2; 1497 float ratio; 1498 1499 float duration = 1500; 1500 1501 time = cg.time; 1502 time2 = cg.time + cent->currentState.time; 1503 1504 ratio =(float)1 - ((float)time / (float)time2); 1505 1506 if (!pshader) 1507 CG_Printf ("CG_Particle_OilParticle == ZERO!\n"); 1508 1509 if (!free_particles) 1510 return; 1511 p = free_particles; 1512 free_particles = p->next; 1513 p->next = active_particles; 1514 active_particles = p; 1515 p->time = cg.time; 1516 p->alpha = 1.0; 1517 p->alphavel = 0; 1518 p->roll = 0; 1519 1520 p->pshader = pshader; 1521 1522 p->endtime = cg.time + duration; 1523 1524 p->startfade = p->endtime; 1525 1526 p->width = 1; 1527 p->height = 3; 1528 1529 p->endheight = 3; 1530 p->endwidth = 1; 1531 1532 p->type = P_SMOKE; 1533 1534 VectorCopy(cent->currentState.origin, p->org ); 1535 1536 p->vel[0] = (cent->currentState.origin2[0] * (16 * ratio)); 1537 p->vel[1] = (cent->currentState.origin2[1] * (16 * ratio)); 1538 p->vel[2] = (cent->currentState.origin2[2]); 1539 1540 p->snum = 1.0f; 1541 1542 VectorClear( p->accel ); 1543 1544 p->accel[2] = -20; 1545 1546 p->rotate = qfalse; 1547 1548 p->roll = rand()%179; 1549 1550 p->alpha = 0.75; 1551 1552 } 1553 1554 1555 void CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent) 1556 { 1557 cparticle_t *p; 1558 1559 if (!pshader) 1560 CG_Printf ("CG_Particle_OilSlick == ZERO!\n"); 1561 1562 if (!free_particles) 1563 return; 1564 p = free_particles; 1565 free_particles = p->next; 1566 p->next = active_particles; 1567 active_particles = p; 1568 p->time = cg.time; 1569 1570 if (cent->currentState.angles2[2]) 1571 p->endtime = cg.time + cent->currentState.angles2[2]; 1572 else 1573 p->endtime = cg.time + 60000; 1574 1575 p->startfade = p->endtime; 1576 1577 p->alpha = 1.0; 1578 p->alphavel = 0; 1579 p->roll = 0; 1580 1581 p->pshader = pshader; 1582 1583 if (cent->currentState.angles2[0] || cent->currentState.angles2[1]) 1584 { 1585 p->width = cent->currentState.angles2[0]; 1586 p->height = cent->currentState.angles2[0]; 1587 1588 p->endheight = cent->currentState.angles2[1]; 1589 p->endwidth = cent->currentState.angles2[1]; 1590 } 1591 else 1592 { 1593 p->width = 8; 1594 p->height = 8; 1595 1596 p->endheight = 16; 1597 p->endwidth = 16; 1598 } 1599 1600 p->type = P_FLAT_SCALEUP; 1601 1602 p->snum = 1.0; 1603 1604 VectorCopy(cent->currentState.origin, p->org ); 1605 1606 p->org[2]+= 0.55 + (crandom() * 0.5); 1607 1608 p->vel[0] = 0; 1609 p->vel[1] = 0; 1610 p->vel[2] = 0; 1611 VectorClear( p->accel ); 1612 1613 p->rotate = qfalse; 1614 1615 p->roll = rand()%179; 1616 1617 p->alpha = 0.75; 1618 1619 } 1620 1621 void CG_OilSlickRemove (centity_t *cent) 1622 { 1623 cparticle_t *p, *next; 1624 int id; 1625 1626 id = 1.0f; 1627 1628 if (!id) 1629 CG_Printf ("CG_OilSlickRevove NULL id\n"); 1630 1631 for (p=active_particles ; p ; p=next) 1632 { 1633 next = p->next; 1634 1635 if (p->type == P_FLAT_SCALEUP) 1636 { 1637 if (p->snum == id) 1638 { 1639 p->endtime = cg.time + 100; 1640 p->startfade = p->endtime; 1641 p->type = P_FLAT_SCALEUP_FADE; 1642 1643 } 1644 } 1645 1646 } 1647 } 1648 1649 qboolean ValidBloodPool (vec3_t start) 1650 { 1651 #define EXTRUDE_DIST 0.5 1652 1653 vec3_t angles; 1654 vec3_t right, up; 1655 vec3_t this_pos, x_pos, center_pos, end_pos; 1656 float x, y; 1657 float fwidth, fheight; 1658 trace_t trace; 1659 vec3_t normal; 1660 1661 fwidth = 16; 1662 fheight = 16; 1663 1664 VectorSet (normal, 0, 0, 1); 1665 1666 vectoangles (normal, angles); 1667 AngleVectors (angles, NULL, right, up); 1668 1669 VectorMA (start, EXTRUDE_DIST, normal, center_pos); 1670 1671 for (x= -fwidth/2; x<fwidth; x+= fwidth) 1672 { 1673 VectorMA (center_pos, x, right, x_pos); 1674 1675 for (y= -fheight/2; y<fheight; y+= fheight) 1676 { 1677 VectorMA (x_pos, y, up, this_pos); 1678 VectorMA (this_pos, -EXTRUDE_DIST*2, normal, end_pos); 1679 1680 CG_Trace (&trace, this_pos, NULL, NULL, end_pos, -1, CONTENTS_SOLID); 1681 1682 1683 if (trace.entityNum < (MAX_ENTITIES - 1)) // may only land on world 1684 return qfalse; 1685 1686 if (!(!trace.startsolid && trace.fraction < 1)) 1687 return qfalse; 1688 1689 } 1690 } 1691 1692 return qtrue; 1693 } 1694 1695 void CG_BloodPool (localEntity_t *le, qhandle_t pshader, trace_t *tr) 1696 { 1697 cparticle_t *p; 1698 qboolean legit; 1699 vec3_t start; 1700 float rndSize; 1701 1702 if (!pshader) 1703 CG_Printf ("CG_BloodPool pshader == ZERO!\n"); 1704 1705 if (!free_particles) 1706 return; 1707 1708 VectorCopy (tr->endpos, start); 1709 legit = ValidBloodPool (start); 1710 1711 if (!legit) 1712 return; 1713 1714 p = free_particles; 1715 free_particles = p->next; 1716 p->next = active_particles; 1717 active_particles = p; 1718 p->time = cg.time; 1719 1720 p->endtime = cg.time + 3000; 1721 p->startfade = p->endtime; 1722 1723 p->alpha = 1.0; 1724 p->alphavel = 0; 1725 p->roll = 0; 1726 1727 p->pshader = pshader; 1728 1729 rndSize = 0.4 + random()*0.6; 1730 1731 p->width = 8*rndSize; 1732 p->height = 8*rndSize; 1733 1734 p->endheight = 16*rndSize; 1735 p->endwidth = 16*rndSize; 1736 1737 p->type = P_FLAT_SCALEUP; 1738 1739 VectorCopy(start, p->org ); 1740 1741 p->vel[0] = 0; 1742 p->vel[1] = 0; 1743 p->vel[2] = 0; 1744 VectorClear( p->accel ); 1745 1746 p->rotate = qfalse; 1747 1748 p->roll = rand()%179; 1749 1750 p->alpha = 0.75; 1751 1752 p->color = BLOODRED; 1753 } 1754 1755 #define NORMALSIZE 16 1756 #define LARGESIZE 32 1757 1758 void CG_ParticleBloodCloud (centity_t *cent, vec3_t origin, vec3_t dir) 1759 { 1760 float length; 1761 float dist; 1762 float crittersize; 1763 vec3_t angles, forward; 1764 vec3_t point; 1765 cparticle_t *p; 1766 int i; 1767 1768 dist = 0; 1769 1770 length = VectorLength (dir); 1771 vectoangles (dir, angles); 1772 AngleVectors (angles, forward, NULL, NULL); 1773 1774 crittersize = LARGESIZE; 1775 1776 if (length) 1777 dist = length / crittersize; 1778 1779 if (dist < 1) 1780 dist = 1; 1781 1782 VectorCopy (origin, point); 1783 1784 for (i=0; i<dist; i++) 1785 { 1786 VectorMA (point, crittersize, forward, point); 1787 1788 if (!free_particles) 1789 return; 1790 1791 p = free_particles; 1792 free_particles = p->next; 1793 p->next = active_particles; 1794 active_particles = p; 1795 1796 p->time = cg.time; 1797 p->alpha = 1.0; 1798 p->alphavel = 0; 1799 p->roll = 0; 1800 1801 p->pshader = cgs.media.smokePuffShader; 1802 1803 p->endtime = cg.time + 350 + (crandom() * 100); 1804 1805 p->startfade = cg.time; 1806 1807 p->width = LARGESIZE; 1808 p->height = LARGESIZE; 1809 p->endheight = LARGESIZE; 1810 p->endwidth = LARGESIZE; 1811 1812 p->type = P_SMOKE; 1813 1814 VectorCopy( origin, p->org ); 1815 1816 p->vel[0] = 0; 1817 p->vel[1] = 0; 1818 p->vel[2] = -1; 1819 1820 VectorClear( p->accel ); 1821 1822 p->rotate = qfalse; 1823 1824 p->roll = rand()%179; 1825 1826 p->color = BLOODRED; 1827 1828 p->alpha = 0.75; 1829 1830 } 1831 1832 1833 } 1834 1835 void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed) 1836 { 1837 cparticle_t *p; 1838 1839 if (!free_particles) 1840 return; 1841 p = free_particles; 1842 free_particles = p->next; 1843 p->next = active_particles; 1844 active_particles = p; 1845 p->time = cg.time; 1846 1847 p->endtime = cg.time + duration; 1848 p->startfade = cg.time + duration/2; 1849 1850 p->color = EMISIVEFADE; 1851 p->alpha = 0.4f; 1852 p->alphavel = 0; 1853 1854 p->height = 0.5; 1855 p->width = 0.5; 1856 p->endheight = 0.5; 1857 p->endwidth = 0.5; 1858 1859 p->pshader = cgs.media.tracerShader; 1860 1861 p->type = P_SMOKE; 1862 1863 VectorCopy(org, p->org); 1864 1865 p->org[0] += (crandom() * x); 1866 p->org[1] += (crandom() * y); 1867 1868 p->vel[0] = vel[0]; 1869 p->vel[1] = vel[1]; 1870 p->vel[2] = vel[2]; 1871 1872 p->accel[0] = p->accel[1] = p->accel[2] = 0; 1873 1874 p->vel[0] += (crandom() * 4); 1875 p->vel[1] += (crandom() * 4); 1876 p->vel[2] += (20 + (crandom() * 10)) * speed; 1877 1878 p->accel[0] = crandom () * 4; 1879 p->accel[1] = crandom () * 4; 1880 1881 } 1882 1883 void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir) 1884 { 1885 float length; 1886 float dist; 1887 float crittersize; 1888 vec3_t angles, forward; 1889 vec3_t point; 1890 cparticle_t *p; 1891 int i; 1892 1893 dist = 0; 1894 1895 VectorNegate (dir, dir); 1896 length = VectorLength (dir); 1897 vectoangles (dir, angles); 1898 AngleVectors (angles, forward, NULL, NULL); 1899 1900 crittersize = LARGESIZE; 1901 1902 if (length) 1903 dist = length / crittersize; 1904 1905 if (dist < 1) 1906 dist = 1; 1907 1908 VectorCopy (origin, point); 1909 1910 for (i=0; i<dist; i++) 1911 { 1912 VectorMA (point, crittersize, forward, point); 1913 1914 if (!free_particles) 1915 return; 1916 1917 p = free_particles; 1918 free_particles = p->next; 1919 p->next = active_particles; 1920 active_particles = p; 1921 1922 p->time = cg.time; 1923 p->alpha = 5.0; 1924 p->alphavel = 0; 1925 p->roll = 0; 1926 1927 p->pshader = cgs.media.smokePuffShader; 1928 1929 // RF, stay around for long enough to expand and dissipate naturally 1930 if (length) 1931 p->endtime = cg.time + 4500 + (crandom() * 3500); 1932 else 1933 p->endtime = cg.time + 750 + (crandom() * 500); 1934 1935 p->startfade = cg.time; 1936 1937 p->width = LARGESIZE; 1938 p->height = LARGESIZE; 1939 1940 // RF, expand while falling 1941 p->endheight = LARGESIZE*3.0; 1942 p->endwidth = LARGESIZE*3.0; 1943 1944 if (!length) 1945 { 1946 p->width *= 0.2f; 1947 p->height *= 0.2f; 1948 1949 p->endheight = NORMALSIZE; 1950 p->endwidth = NORMALSIZE; 1951 } 1952 1953 p->type = P_SMOKE; 1954 1955 VectorCopy( point, p->org ); 1956 1957 p->vel[0] = crandom()*6; 1958 p->vel[1] = crandom()*6; 1959 p->vel[2] = random()*20; 1960 1961 // RF, add some gravity/randomness 1962 p->accel[0] = crandom()*3; 1963 p->accel[1] = crandom()*3; 1964 p->accel[2] = -PARTICLE_GRAVITY*0.4; 1965 1966 VectorClear( p->accel ); 1967 1968 p->rotate = qfalse; 1969 1970 p->roll = rand()%179; 1971 1972 p->alpha = 0.75; 1973 1974 } 1975 1976 1977 } 1978 1979 void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha) 1980 { 1981 cparticle_t *p; 1982 1983 if (!pshader) 1984 CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n"); 1985 1986 if (!free_particles) 1987 return; 1988 1989 p = free_particles; 1990 free_particles = p->next; 1991 p->next = active_particles; 1992 active_particles = p; 1993 p->time = cg.time; 1994 p->alpha = 1.0; 1995 p->alphavel = 0; 1996 p->roll = rand()%179; 1997 1998 p->pshader = pshader; 1999 2000 if (duration > 0) 2001 p->endtime = cg.time + duration; 2002 else 2003 p->endtime = duration; 2004 2005 p->startfade = cg.time; 2006 2007 p->width = size; 2008 p->height = size; 2009 2010 p->endheight = size; 2011 p->endwidth = size; 2012 2013 p->type = P_SPRITE; 2014 2015 VectorCopy( origin, p->org ); 2016 2017 p->rotate = qfalse; 2018 }