codemp/cgame/cg_localents.c

Go to the documentation of this file.
00001 // Copyright (C) 1999-2000 Id Software, Inc.
00002 //
00003 
00004 // cg_localents.c -- every frame, generate renderer commands for locally
00005 // processed entities, like smoke puffs, gibs, shells, etc.
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;         // double linked list
00012 localEntity_t   *cg_freeLocalEntities;          // single linked list
00013 
00014 /*
00015 ===================
00016 CG_InitLocalEntities
00017 
00018 This is called at startup and for tournement restarts
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 CG_FreeLocalEntity
00037 ==================
00038 */
00039 void CG_FreeLocalEntity( localEntity_t *le ) {
00040         if ( !le->prev ) {
00041                 CG_Error( "CG_FreeLocalEntity: not active" );
00042         }
00043 
00044         // remove from the doubly linked active list
00045         le->prev->next = le->next;
00046         le->next->prev = le->prev;
00047 
00048         // the free list is only singly linked
00049         le->next = cg_freeLocalEntities;
00050         cg_freeLocalEntities = le;
00051 }
00052 
00053 /*
00054 ===================
00055 CG_AllocLocalEntity
00056 
00057 Will allways succeed, even if it requires freeing an old active entity
00058 ===================
00059 */
00060 localEntity_t   *CG_AllocLocalEntity( void ) {
00061         localEntity_t   *le;
00062 
00063         if ( !cg_freeLocalEntities ) {
00064                 // no free entities, so free the one at the end of the chain
00065                 // remove the oldest active entity
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         // link into the active list
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 FRAGMENT PROCESSING
00087 
00088 A fragment localentity interacts with the environment in some way (hitting walls),
00089 or generates more localentities along a trail.
00090 
00091 ====================================================================================
00092 */
00093 
00094 /*
00095 ================
00096 CG_BloodTrail
00097 
00098 Leave expanding blood puffs behind gibs
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,           // radius
00117                                           1, 1, 1, 1,   // color
00118                                           2000,         // trailTime
00119                                           t,            // startTime
00120                                           0,            // fadeInTime
00121                                           0,            // flags
00122                                           /*cgs.media.bloodTrailShader*/0 );
00123                 // use the optimized version
00124                 blood->leType = LE_FALL_SCALE_FADE;
00125                 // drop a total of 40 units over its lifetime
00126                 blood->pos.trDelta[2] = 40;
00127         }
00128 }
00129 
00130 
00131 /*
00132 ================
00133 CG_FragmentBounceMark
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 //              CG_ImpactMark( cgs.media.bloodMarkShader, trace->endpos, trace->plane.normal, random()*360,
00143 //                      1,1,1,1, qtrue, radius, qfalse );
00144         } else if ( le->leMarkType == LEMT_BURN ) {
00145 
00146                 radius = 8 + (rand()&15);
00147 //              CG_ImpactMark( cgs.media.burnMarkShader, trace->endpos, trace->plane.normal, random()*360,
00148 //                      1,1,1,1, qtrue, radius, qfalse );
00149         }
00150 
00151 
00152         // don't allow a fragment to make multiple marks, or they
00153         // pile up while settling
00154         le->leMarkType = LEMT_NONE;
00155 }
00156 
00157 /*
00158 ================
00159 CG_FragmentBounceSound
00160 ================
00161 */
00162 void CG_FragmentBounceSound( localEntity_t *le, trace_t *trace ) {
00163         // half the fragments will make a bounce sounds
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)];// FIXME: make sure that this sound is registered properly...might still be rock bounce sound....
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                 // bouncers only make the sound once...
00186                 // FIXME: arbitrary...change if it bugs you
00187                 le->leBounceSoundType = LEBS_NONE;
00188         } 
00189         else if ( rand() & 1 )
00190         {
00191                 // we may end up bouncing again, but each bounce reduces the chance of playing the sound again or they may make a lot of noise when they settle
00192                 // FIXME: maybe just always do this??
00193                 le->leBounceSoundType = LEBS_NONE;
00194         }
00195 }
00196 
00197 
00198 /*
00199 ================
00200 CG_ReflectVelocity
00201 ================
00202 */
00203 void CG_ReflectVelocity( localEntity_t *le, trace_t *trace ) {
00204         vec3_t  velocity;
00205         float   dot;
00206         int             hitTime;
00207 
00208         // reflect the velocity on the trace plane
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         // check for stop, making sure that even on low FPS systems it doesn't bobble
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 CG_AddFragment
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                 // sink into the ground if near the removal time
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         // calculate new position
00280         BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin );
00281 
00282         // trace a line from previous position to new position
00283         CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
00284         if ( trace.fraction == 1.0 ) {
00285                 // still in free fall
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                 // add a blood trail
00299                 if ( le->leBounceSoundType == LEBS_BLOOD ) {
00300                         CG_BloodTrail( le );
00301                 }
00302 
00303                 return;
00304         }
00305 
00306         // if it is in a nodrop zone, remove it
00307         // this keeps gibs from waiting at the bottom of pits of death
00308         // and floating levels
00309         if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
00310                 CG_FreeLocalEntity( le );
00311                 return;
00312         }
00313 
00314         if (!trace.startsolid)
00315         {
00316                 // leave a mark
00317                 CG_FragmentBounceMark( le, &trace );
00318 
00319                 // do a bouncy sound
00320                 CG_FragmentBounceSound( le, &trace );
00321 
00322                 if (le->bounceSound)
00323                 { //specified bounce sound (debris)
00324                         trap_S_StartSound(le->pos.trBase, ENTITYNUM_WORLD, CHAN_AUTO, le->bounceSound);
00325                 }
00326 
00327                 // reflect the velocity on the trace plane
00328                 CG_ReflectVelocity( le, &trace );
00329 
00330                 trap_R_AddRefEntityToScene( &le->refEntity );
00331         }
00332 }
00333 
00334 /*
00335 =====================================================================
00336 
00337 TRIVIAL LOCAL ENTITIES
00338 
00339 These only do simple scaling or modulation before passing to the renderer
00340 =====================================================================
00341 */
00342 
00343 /*
00344 ====================
00345 CG_AddFadeRGB
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; // yes, this is completely ridiculous...but it causes the shell to grow slowly then "explode" at the end
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         // add the entity
00389         trap_R_AddRefEntityToScene( ent );
00390 }
00391 
00392 /*
00393 ==================
00394 CG_AddMoveScaleFade
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                 // fade / grow time
00407                 c = 1.0 - (float) ( le->fadeInTime - cg.time ) / ( le->fadeInTime - le->startTime );
00408         }
00409         else {
00410                 // fade / grow time
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         // if the view would be "inside" the sprite, kill the sprite
00423         // so it doesn't add too much overdraw
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 CG_AddPuff
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         // fade / grow time
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         // if the view would be "inside" the sprite, kill the sprite
00461         // so it doesn't add too much overdraw
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 CG_AddScaleFade
00475 
00476 For rocket smokes that hang in place, fade out, and are
00477 removed if the view passes through them.
00478 There are often many of these, so it needs to be simple.
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         // fade / grow time
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         // if the view would be "inside" the sprite, kill the sprite
00496         // so it doesn't add too much overdraw
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 CG_AddFallScaleFade
00511 
00512 This is just an optimized CG_AddMoveScaleFade
00513 For blood mists that drift down, fade out, and are
00514 removed if the view passes through them.
00515 There are often 100+ of these, so it needs to be simple.
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         // fade time
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         // if the view would be "inside" the sprite, kill the sprite
00536         // so it doesn't add too much overdraw
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 CG_AddExplosion
00552 ================
00553 */
00554 static void CG_AddExplosion( localEntity_t *ex ) {
00555         refEntity_t     *ent;
00556 
00557         ent = &ex->refEntity;
00558 
00559         // add the entity
00560         trap_R_AddRefEntityToScene(ent);
00561 
00562         // add the dlight
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 CG_AddSpriteExplosion
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;        // can happen during connection problems
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         // add the dlight
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 CG_AddRefEntity
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 CG_AddScorePlum
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         // if the view would be "inside" the sprite, kill the sprite
00687         // so it doesn't add too much overdraw
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 CG_AddOLine
00721 
00722 For forcefields/other rectangular things
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;     // can happen during connection problems
00735         else if (frac < 0)
00736                 frac = 0.0;
00737 
00738         // Use the liferate to set the scale over time.
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         // We will assume here that we want additive transparency effects.
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;       // Yes, we could apply c to this too, but fading the color is better for lines.
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 CG_AddLine
00766 
00767 for beams and the like.
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 CG_AddLocalEntities
00786 
00787 ===================
00788 */
00789 void CG_AddLocalEntities( void ) {
00790         localEntity_t   *le, *next;
00791 
00792         // walk the list backwards, so any new local entities generated
00793         // (trails, marks, etc) will be present this frame
00794         le = cg_activeLocalEntities.prev;
00795         for ( ; le != &cg_activeLocalEntities ; le = next ) {
00796                 // grab next now, so if the local entity is freed we
00797                 // still have it
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:                       // gibs and brass
00825                         CG_AddFragment( le );
00826                         break;
00827 
00828                 case LE_PUFF:
00829                         CG_AddPuff( le );
00830                         break;
00831 
00832                 case LE_MOVE_SCALE_FADE:                // water bubbles
00833                         CG_AddMoveScaleFade( le );
00834                         break;
00835 
00836                 case LE_FADE_RGB:                               // teleporters, railtrails
00837                         CG_AddFadeRGB( le );
00838                         break;
00839 
00840                 case LE_FALL_SCALE_FADE: // gib blood trails
00841                         CG_AddFallScaleFade( le );
00842                         break;
00843 
00844                 case LE_SCALE_FADE:             // rocket trails
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:                                   // oriented lines for FX
00861                         CG_AddLine( le );
00862                         break;
00863                 }
00864         }
00865 }
00866 
00867 
00868 
00869