00001
00002
00003
00004
00005
00006
00007 #include "cg_local.h"
00008
00009 #define MAX_LOCAL_ENTITIES 512
00010 localEntity_t cg_localEntities[MAX_LOCAL_ENTITIES];
00011 localEntity_t cg_activeLocalEntities;
00012 localEntity_t *cg_freeLocalEntities;
00013
00014
00015
00016
00017
00018
00019
00020
00021 void CG_InitLocalEntities( void ) {
00022 int i;
00023
00024 memset( cg_localEntities, 0, sizeof( cg_localEntities ) );
00025 cg_activeLocalEntities.next = &cg_activeLocalEntities;
00026 cg_activeLocalEntities.prev = &cg_activeLocalEntities;
00027 cg_freeLocalEntities = cg_localEntities;
00028 for ( i = 0 ; i < MAX_LOCAL_ENTITIES - 1 ; i++ ) {
00029 cg_localEntities[i].next = &cg_localEntities[i+1];
00030 }
00031 }
00032
00033
00034
00035
00036
00037
00038
00039 void CG_FreeLocalEntity( localEntity_t *le ) {
00040 if ( !le->prev ) {
00041 CG_Error( "CG_FreeLocalEntity: not active" );
00042 }
00043
00044
00045 le->prev->next = le->next;
00046 le->next->prev = le->prev;
00047
00048
00049 le->next = cg_freeLocalEntities;
00050 cg_freeLocalEntities = le;
00051 }
00052
00053
00054
00055
00056
00057
00058
00059
00060 localEntity_t *CG_AllocLocalEntity( void ) {
00061 localEntity_t *le;
00062
00063 if ( !cg_freeLocalEntities ) {
00064
00065
00066 CG_FreeLocalEntity( cg_activeLocalEntities.prev );
00067 }
00068
00069 le = cg_freeLocalEntities;
00070 cg_freeLocalEntities = cg_freeLocalEntities->next;
00071
00072 memset( le, 0, sizeof( *le ) );
00073
00074
00075 le->next = cg_activeLocalEntities.next;
00076 le->prev = &cg_activeLocalEntities;
00077 cg_activeLocalEntities.next->prev = le;
00078 cg_activeLocalEntities.next = le;
00079 return le;
00080 }
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101 void CG_BloodTrail( localEntity_t *le ) {
00102 int t;
00103 int t2;
00104 int step;
00105 vec3_t newOrigin;
00106 localEntity_t *blood;
00107
00108 step = 150;
00109 t = step * ( (cg.time - cg.frametime + step ) / step );
00110 t2 = step * ( cg.time / step );
00111
00112 for ( ; t <= t2; t += step ) {
00113 BG_EvaluateTrajectory( &le->pos, t, newOrigin );
00114
00115 blood = CG_SmokePuff( newOrigin, vec3_origin,
00116 20,
00117 1, 1, 1, 1,
00118 2000,
00119 t,
00120 0,
00121 0,
00122 0 );
00123
00124 blood->leType = LE_FALL_SCALE_FADE;
00125
00126 blood->pos.trDelta[2] = 40;
00127 }
00128 }
00129
00130
00131
00132
00133
00134
00135
00136 void CG_FragmentBounceMark( localEntity_t *le, trace_t *trace ) {
00137 int radius;
00138
00139 if ( le->leMarkType == LEMT_BLOOD ) {
00140
00141 radius = 16 + (rand()&31);
00142
00143
00144 } else if ( le->leMarkType == LEMT_BURN ) {
00145
00146 radius = 8 + (rand()&15);
00147
00148
00149 }
00150
00151
00152
00153
00154 le->leMarkType = LEMT_NONE;
00155 }
00156
00157
00158
00159
00160
00161
00162 void CG_FragmentBounceSound( localEntity_t *le, trace_t *trace ) {
00163
00164 if ( rand() & 1 )
00165 {
00166 sfxHandle_t s = 0;
00167
00168 switch( le->leBounceSoundType )
00169 {
00170 case LEBS_ROCK:
00171 s = cgs.media.rockBounceSound[Q_irand(0,1)];
00172 break;
00173 case LEBS_METAL:
00174 s = cgs.media.metalBounceSound[Q_irand(0,1)];
00175 break;
00176 default:
00177 return;
00178 }
00179
00180 if ( s )
00181 {
00182 trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s );
00183 }
00184
00185
00186
00187 le->leBounceSoundType = LEBS_NONE;
00188 }
00189 else if ( rand() & 1 )
00190 {
00191
00192
00193 le->leBounceSoundType = LEBS_NONE;
00194 }
00195 }
00196
00197
00198
00199
00200
00201
00202
00203 void CG_ReflectVelocity( localEntity_t *le, trace_t *trace ) {
00204 vec3_t velocity;
00205 float dot;
00206 int hitTime;
00207
00208
00209 hitTime = cg.time - cg.frametime + cg.frametime * trace->fraction;
00210 BG_EvaluateTrajectoryDelta( &le->pos, hitTime, velocity );
00211 dot = DotProduct( velocity, trace->plane.normal );
00212 VectorMA( velocity, -2*dot, trace->plane.normal, le->pos.trDelta );
00213
00214 VectorScale( le->pos.trDelta, le->bounceFactor, le->pos.trDelta );
00215
00216 VectorCopy( trace->endpos, le->pos.trBase );
00217 le->pos.trTime = cg.time;
00218
00219
00220 if ( trace->allsolid ||
00221 ( trace->plane.normal[2] > 0 &&
00222 ( le->pos.trDelta[2] < 40 || le->pos.trDelta[2] < -cg.frametime * le->pos.trDelta[2] ) ) ) {
00223 le->pos.trType = TR_STATIONARY;
00224 } else {
00225
00226 }
00227 }
00228
00229
00230
00231
00232
00233
00234 void CG_AddFragment( localEntity_t *le ) {
00235 vec3_t newOrigin;
00236 trace_t trace;
00237
00238 if (le->forceAlpha)
00239 {
00240 le->refEntity.renderfx |= RF_FORCE_ENT_ALPHA;
00241 le->refEntity.shaderRGBA[3] = le->forceAlpha;
00242 }
00243
00244 if ( le->pos.trType == TR_STATIONARY ) {
00245
00246 int t;
00247 float t_e;
00248
00249 t = le->endTime - cg.time;
00250 if ( t < (SINK_TIME*2) ) {
00251 le->refEntity.renderfx |= RF_FORCE_ENT_ALPHA;
00252 t_e = (float)((float)(le->endTime - cg.time)/(SINK_TIME*2));
00253 t_e = (int)((t_e)*255);
00254
00255 if (t_e > 255)
00256 {
00257 t_e = 255;
00258 }
00259 if (t_e < 1)
00260 {
00261 t_e = 1;
00262 }
00263
00264 if (le->refEntity.shaderRGBA[3] && t_e > le->refEntity.shaderRGBA[3])
00265 {
00266 t_e = le->refEntity.shaderRGBA[3];
00267 }
00268
00269 le->refEntity.shaderRGBA[3] = t_e;
00270
00271 trap_R_AddRefEntityToScene( &le->refEntity );
00272 } else {
00273 trap_R_AddRefEntityToScene( &le->refEntity );
00274 }
00275
00276 return;
00277 }
00278
00279
00280 BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin );
00281
00282
00283 CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
00284 if ( trace.fraction == 1.0 ) {
00285
00286 VectorCopy( newOrigin, le->refEntity.origin );
00287
00288 if ( le->leFlags & LEF_TUMBLE ) {
00289 vec3_t angles;
00290
00291 BG_EvaluateTrajectory( &le->angles, cg.time, angles );
00292 AnglesToAxis( angles, le->refEntity.axis );
00293 ScaleModelAxis(&le->refEntity);
00294 }
00295
00296 trap_R_AddRefEntityToScene( &le->refEntity );
00297
00298
00299 if ( le->leBounceSoundType == LEBS_BLOOD ) {
00300 CG_BloodTrail( le );
00301 }
00302
00303 return;
00304 }
00305
00306
00307
00308
00309 if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
00310 CG_FreeLocalEntity( le );
00311 return;
00312 }
00313
00314 if (!trace.startsolid)
00315 {
00316
00317 CG_FragmentBounceMark( le, &trace );
00318
00319
00320 CG_FragmentBounceSound( le, &trace );
00321
00322 if (le->bounceSound)
00323 {
00324 trap_S_StartSound(le->pos.trBase, ENTITYNUM_WORLD, CHAN_AUTO, le->bounceSound);
00325 }
00326
00327
00328 CG_ReflectVelocity( le, &trace );
00329
00330 trap_R_AddRefEntityToScene( &le->refEntity );
00331 }
00332 }
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348 void CG_AddFadeRGB( localEntity_t *le ) {
00349 refEntity_t *re;
00350 float c;
00351
00352 re = &le->refEntity;
00353
00354 c = ( le->endTime - cg.time ) * le->lifeRate;
00355 c *= 0xff;
00356
00357 re->shaderRGBA[0] = le->color[0] * c;
00358 re->shaderRGBA[1] = le->color[1] * c;
00359 re->shaderRGBA[2] = le->color[2] * c;
00360 re->shaderRGBA[3] = le->color[3] * c;
00361
00362 trap_R_AddRefEntityToScene( re );
00363 }
00364
00365 static void CG_AddFadeScaleModel( localEntity_t *le )
00366 {
00367 refEntity_t *ent = &le->refEntity;
00368
00369 float frac = ( cg.time - le->startTime )/((float)( le->endTime - le->startTime ));
00370
00371 frac *= frac * frac;
00372
00373 ent->nonNormalizedAxes = qtrue;
00374
00375 AxisCopy( axisDefault, ent->axis );
00376
00377 VectorScale( ent->axis[0], le->radius * frac, ent->axis[0] );
00378 VectorScale( ent->axis[1], le->radius * frac, ent->axis[1] );
00379 VectorScale( ent->axis[2], le->radius * 0.5f * frac, ent->axis[2] );
00380
00381 frac = 1.0f - frac;
00382
00383 ent->shaderRGBA[0] = le->color[0] * frac;
00384 ent->shaderRGBA[1] = le->color[1] * frac;
00385 ent->shaderRGBA[2] = le->color[2] * frac;
00386 ent->shaderRGBA[3] = le->color[3] * frac;
00387
00388
00389 trap_R_AddRefEntityToScene( ent );
00390 }
00391
00392
00393
00394
00395
00396
00397 static void CG_AddMoveScaleFade( localEntity_t *le ) {
00398 refEntity_t *re;
00399 float c;
00400 vec3_t delta;
00401 float len;
00402
00403 re = &le->refEntity;
00404
00405 if ( le->fadeInTime > le->startTime && cg.time < le->fadeInTime ) {
00406
00407 c = 1.0 - (float) ( le->fadeInTime - cg.time ) / ( le->fadeInTime - le->startTime );
00408 }
00409 else {
00410
00411 c = ( le->endTime - cg.time ) * le->lifeRate;
00412 }
00413
00414 re->shaderRGBA[3] = 0xff * c * le->color[3];
00415
00416 if ( !( le->leFlags & LEF_PUFF_DONT_SCALE ) ) {
00417 re->radius = le->radius * ( 1.0 - c ) + 8;
00418 }
00419
00420 BG_EvaluateTrajectory( &le->pos, cg.time, re->origin );
00421
00422
00423
00424 VectorSubtract( re->origin, cg.refdef.vieworg, delta );
00425 len = VectorLength( delta );
00426 if ( len < le->radius ) {
00427 CG_FreeLocalEntity( le );
00428 return;
00429 }
00430
00431 trap_R_AddRefEntityToScene( re );
00432 }
00433
00434
00435
00436
00437
00438
00439 static void CG_AddPuff( localEntity_t *le ) {
00440 refEntity_t *re;
00441 float c;
00442 vec3_t delta;
00443 float len;
00444
00445 re = &le->refEntity;
00446
00447
00448 c = ( le->endTime - cg.time ) / (float)( le->endTime - le->startTime );
00449
00450 re->shaderRGBA[0] = le->color[0] * c;
00451 re->shaderRGBA[1] = le->color[1] * c;
00452 re->shaderRGBA[2] = le->color[2] * c;
00453
00454 if ( !( le->leFlags & LEF_PUFF_DONT_SCALE ) ) {
00455 re->radius = le->radius * ( 1.0 - c ) + 8;
00456 }
00457
00458 BG_EvaluateTrajectory( &le->pos, cg.time, re->origin );
00459
00460
00461
00462 VectorSubtract( re->origin, cg.refdef.vieworg, delta );
00463 len = VectorLength( delta );
00464 if ( len < le->radius ) {
00465 CG_FreeLocalEntity( le );
00466 return;
00467 }
00468
00469 trap_R_AddRefEntityToScene( re );
00470 }
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481 static void CG_AddScaleFade( localEntity_t *le ) {
00482 refEntity_t *re;
00483 float c;
00484 vec3_t delta;
00485 float len;
00486
00487 re = &le->refEntity;
00488
00489
00490 c = ( le->endTime - cg.time ) * le->lifeRate;
00491
00492 re->shaderRGBA[3] = 0xff * c * le->color[3];
00493 re->radius = le->radius * ( 1.0 - c ) + 8;
00494
00495
00496
00497 VectorSubtract( re->origin, cg.refdef.vieworg, delta );
00498 len = VectorLength( delta );
00499 if ( len < le->radius ) {
00500 CG_FreeLocalEntity( le );
00501 return;
00502 }
00503
00504 trap_R_AddRefEntityToScene( re );
00505 }
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518 static void CG_AddFallScaleFade( localEntity_t *le ) {
00519 refEntity_t *re;
00520 float c;
00521 vec3_t delta;
00522 float len;
00523
00524 re = &le->refEntity;
00525
00526
00527 c = ( le->endTime - cg.time ) * le->lifeRate;
00528
00529 re->shaderRGBA[3] = 0xff * c * le->color[3];
00530
00531 re->origin[2] = le->pos.trBase[2] - ( 1.0 - c ) * le->pos.trDelta[2];
00532
00533 re->radius = le->radius * ( 1.0 - c ) + 16;
00534
00535
00536
00537 VectorSubtract( re->origin, cg.refdef.vieworg, delta );
00538 len = VectorLength( delta );
00539 if ( len < le->radius ) {
00540 CG_FreeLocalEntity( le );
00541 return;
00542 }
00543
00544 trap_R_AddRefEntityToScene( re );
00545 }
00546
00547
00548
00549
00550
00551
00552
00553
00554 static void CG_AddExplosion( localEntity_t *ex ) {
00555 refEntity_t *ent;
00556
00557 ent = &ex->refEntity;
00558
00559
00560 trap_R_AddRefEntityToScene(ent);
00561
00562
00563 if ( ex->light ) {
00564 float light;
00565
00566 light = (float)( cg.time - ex->startTime ) / ( ex->endTime - ex->startTime );
00567 if ( light < 0.5 ) {
00568 light = 1.0;
00569 } else {
00570 light = 1.0 - ( light - 0.5 ) * 2;
00571 }
00572 light = ex->light * light;
00573 trap_R_AddLightToScene(ent->origin, light, ex->lightColor[0], ex->lightColor[1], ex->lightColor[2] );
00574 }
00575 }
00576
00577
00578
00579
00580
00581
00582 static void CG_AddSpriteExplosion( localEntity_t *le ) {
00583 refEntity_t re;
00584 float c;
00585
00586 re = le->refEntity;
00587
00588 c = ( le->endTime - cg.time ) / ( float ) ( le->endTime - le->startTime );
00589 if ( c > 1 ) {
00590 c = 1.0;
00591 }
00592
00593 re.shaderRGBA[0] = 0xff;
00594 re.shaderRGBA[1] = 0xff;
00595 re.shaderRGBA[2] = 0xff;
00596 re.shaderRGBA[3] = 0xff * c * 0.33;
00597
00598 re.reType = RT_SPRITE;
00599 re.radius = 42 * ( 1.0 - c ) + 30;
00600
00601 trap_R_AddRefEntityToScene( &re );
00602
00603
00604 if ( le->light ) {
00605 float light;
00606
00607 light = (float)( cg.time - le->startTime ) / ( le->endTime - le->startTime );
00608 if ( light < 0.5 ) {
00609 light = 1.0;
00610 } else {
00611 light = 1.0 - ( light - 0.5 ) * 2;
00612 }
00613 light = le->light * light;
00614 trap_R_AddLightToScene(re.origin, light, le->lightColor[0], le->lightColor[1], le->lightColor[2] );
00615 }
00616 }
00617
00618
00619
00620
00621
00622
00623
00624 void CG_AddRefEntity( localEntity_t *le ) {
00625 if (le->endTime < cg.time) {
00626 CG_FreeLocalEntity( le );
00627 return;
00628 }
00629 trap_R_AddRefEntityToScene( &le->refEntity );
00630 }
00631
00632
00633
00634
00635
00636
00637 #define NUMBER_SIZE 8
00638
00639 void CG_AddScorePlum( localEntity_t *le ) {
00640 refEntity_t *re;
00641 vec3_t origin, delta, dir, vec, up = {0, 0, 1};
00642 float c, len;
00643 int i, score, digits[10], numdigits, negative;
00644
00645 re = &le->refEntity;
00646
00647 c = ( le->endTime - cg.time ) * le->lifeRate;
00648
00649 score = le->radius;
00650 if (score < 0) {
00651 re->shaderRGBA[0] = 0xff;
00652 re->shaderRGBA[1] = 0x11;
00653 re->shaderRGBA[2] = 0x11;
00654 }
00655 else {
00656 re->shaderRGBA[0] = 0xff;
00657 re->shaderRGBA[1] = 0xff;
00658 re->shaderRGBA[2] = 0xff;
00659 if (score >= 50) {
00660 re->shaderRGBA[1] = 0;
00661 } else if (score >= 20) {
00662 re->shaderRGBA[0] = re->shaderRGBA[1] = 0;
00663 } else if (score >= 10) {
00664 re->shaderRGBA[2] = 0;
00665 } else if (score >= 2) {
00666 re->shaderRGBA[0] = re->shaderRGBA[2] = 0;
00667 }
00668
00669 }
00670 if (c < 0.25)
00671 re->shaderRGBA[3] = 0xff * 4 * c;
00672 else
00673 re->shaderRGBA[3] = 0xff;
00674
00675 re->radius = NUMBER_SIZE / 2;
00676
00677 VectorCopy(le->pos.trBase, origin);
00678 origin[2] += 110 - c * 100;
00679
00680 VectorSubtract(cg.refdef.vieworg, origin, dir);
00681 CrossProduct(dir, up, vec);
00682 VectorNormalize(vec);
00683
00684 VectorMA(origin, -10 + 20 * sin(c * 2 * M_PI), vec, origin);
00685
00686
00687
00688 VectorSubtract( origin, cg.refdef.vieworg, delta );
00689 len = VectorLength( delta );
00690 if ( len < 20 ) {
00691 CG_FreeLocalEntity( le );
00692 return;
00693 }
00694
00695 negative = qfalse;
00696 if (score < 0) {
00697 negative = qtrue;
00698 score = -score;
00699 }
00700
00701 for (numdigits = 0; !(numdigits && !score); numdigits++) {
00702 digits[numdigits] = score % 10;
00703 score = score / 10;
00704 }
00705
00706 if (negative) {
00707 digits[numdigits] = 10;
00708 numdigits++;
00709 }
00710
00711 for (i = 0; i < numdigits; i++) {
00712 VectorMA(origin, (float) (((float) numdigits / 2) - i) * NUMBER_SIZE, vec, re->origin);
00713 re->customShader = cgs.media.numberShaders[digits[numdigits-1-i]];
00714 trap_R_AddRefEntityToScene( re );
00715 }
00716 }
00717
00718
00719
00720
00721
00722
00723
00724
00725 void CG_AddOLine( localEntity_t *le )
00726 {
00727 refEntity_t *re;
00728 float frac, alpha;
00729
00730 re = &le->refEntity;
00731
00732 frac = (cg.time - le->startTime) / ( float ) ( le->endTime - le->startTime );
00733 if ( frac > 1 )
00734 frac = 1.0;
00735 else if (frac < 0)
00736 frac = 0.0;
00737
00738
00739 re->data.line.width = le->data.line.width + (le->data.line.dwidth * frac);
00740 if (re->data.line.width <= 0)
00741 {
00742 CG_FreeLocalEntity( le );
00743 return;
00744 }
00745
00746
00747 alpha = le->alpha + (le->dalpha * frac);
00748 re->shaderRGBA[0] = 0xff * alpha;
00749 re->shaderRGBA[1] = 0xff * alpha;
00750 re->shaderRGBA[2] = 0xff * alpha;
00751 re->shaderRGBA[3] = 0xff * alpha;
00752
00753 re->shaderTexCoord[0] = 1;
00754 re->shaderTexCoord[1] = 1;
00755
00756 re->rotation = 90;
00757
00758 re->reType = RT_ORIENTEDLINE;
00759
00760 trap_R_AddRefEntityToScene( re );
00761 }
00762
00763
00764
00765
00766
00767
00768
00769
00770 void CG_AddLine( localEntity_t *le )
00771 {
00772 refEntity_t *re;
00773
00774 re = &le->refEntity;
00775
00776 re->reType = RT_LINE;
00777
00778 trap_R_AddRefEntityToScene( re );
00779 }
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789 void CG_AddLocalEntities( void ) {
00790 localEntity_t *le, *next;
00791
00792
00793
00794 le = cg_activeLocalEntities.prev;
00795 for ( ; le != &cg_activeLocalEntities ; le = next ) {
00796
00797
00798 next = le->prev;
00799
00800 if ( cg.time >= le->endTime ) {
00801 CG_FreeLocalEntity( le );
00802 continue;
00803 }
00804 switch ( le->leType ) {
00805 default:
00806 CG_Error( "Bad leType: %i", le->leType );
00807 break;
00808
00809 case LE_MARK:
00810 break;
00811
00812 case LE_SPRITE_EXPLOSION:
00813 CG_AddSpriteExplosion( le );
00814 break;
00815
00816 case LE_EXPLOSION:
00817 CG_AddExplosion( le );
00818 break;
00819
00820 case LE_FADE_SCALE_MODEL:
00821 CG_AddFadeScaleModel( le );
00822 break;
00823
00824 case LE_FRAGMENT:
00825 CG_AddFragment( le );
00826 break;
00827
00828 case LE_PUFF:
00829 CG_AddPuff( le );
00830 break;
00831
00832 case LE_MOVE_SCALE_FADE:
00833 CG_AddMoveScaleFade( le );
00834 break;
00835
00836 case LE_FADE_RGB:
00837 CG_AddFadeRGB( le );
00838 break;
00839
00840 case LE_FALL_SCALE_FADE:
00841 CG_AddFallScaleFade( le );
00842 break;
00843
00844 case LE_SCALE_FADE:
00845 CG_AddScaleFade( le );
00846 break;
00847
00848 case LE_SCOREPLUM:
00849 CG_AddScorePlum( le );
00850 break;
00851
00852 case LE_OLINE:
00853 CG_AddOLine( le );
00854 break;
00855
00856 case LE_SHOWREFENTITY:
00857 CG_AddRefEntity( le );
00858 break;
00859
00860 case LE_LINE:
00861 CG_AddLine( le );
00862 break;
00863 }
00864 }
00865 }
00866
00867
00868
00869