/* =============== CG_GarbageCollectTrailSystems Destroy inactive trail systems =============== */ static void CG_GarbageCollectTrailSystems( void ) { int i, j, count; trailSystem_t *ts; trailBeam_t *tb; int centNum; for( i = 0; i < MAX_TRAIL_SYSTEMS; i++ ) { ts = &trailSystems[ i ]; count = 0; //don't bother checking already invalid systems if( !ts->valid ) continue; for( j = 0; j < MAX_TRAIL_BEAMS; j++ ) { tb = &trailBeams[ j ]; if( tb->valid && tb->parent == ts ) count++; } if( !count ) ts->valid = false; //check systems where the parent cent has left the PVS //( local player entity is always valid ) if( ( centNum = CG_AttachmentCentNum( &ts->frontAttachment ) ) >= 0 && centNum != cg.snap->ps.clientNum ) { trailSystem_t *tempTS = ts; if( !cg_entities[ centNum ].valid ) CG_DestroyTrailSystem( &tempTS ); } if( ( centNum = CG_AttachmentCentNum( &ts->backAttachment ) ) >= 0 && centNum != cg.snap->ps.clientNum ) { trailSystem_t *tempTS = ts; if( !cg_entities[ centNum ].valid ) CG_DestroyTrailSystem( &tempTS ); } if( cg_debugTrails.integer >= 1 && !ts->valid ) CG_Printf( "TS %s garbage collected\n", ts->_class->name ); } }
/* =============== CG_DestroyTestTS_f Destroy the test a trail system =============== */ void CG_DestroyTestTS_f() { if ( CG_IsTrailSystemValid( &testTS ) ) { CG_DestroyTrailSystem( &testTS ); } }
/* =============== CG_UpdateBeam Updates a beam =============== */ static void CG_UpdateBeam( trailBeam_t *tb ) { baseTrailBeam_t *btb; trailSystem_t *ts; trailBeamNode_t *i; int deltaTime; int nodesToAdd; int j; int numNodes; if ( !tb ) { return; } btb = tb->class_; ts = tb->parent; deltaTime = cg.time - tb->lastEvalTime; tb->lastEvalTime = cg.time; // first make sure this beam has enough nodes if ( ts->destroyTime <= 0 ) { nodesToAdd = btb->numSegments - CG_CountBeamNodes( tb ) + 1; while ( nodesToAdd-- ) { i = CG_AppendBeamNode( tb ); if ( !tb->nodes->next && CG_Attached( &ts->frontAttachment ) ) { // this is the first node to be added if ( !CG_AttachmentPoint( &ts->frontAttachment, i->refPosition ) ) { CG_DestroyTrailSystem( &ts ); } } else { VectorCopy( i->prev->refPosition, i->refPosition ); } } } numNodes = CG_CountBeamNodes( tb ); for ( i = tb->nodes; i; i = i->next ) { VectorCopy( i->refPosition, i->position ); } if ( CG_Attached( &ts->frontAttachment ) && CG_Attached( &ts->backAttachment ) ) { // beam between two attachments vec3_t dir, front, back; if ( ts->destroyTime > 0 && ( cg.time - ts->destroyTime ) >= btb->fadeOutTime ) { tb->valid = false; return; } if ( !CG_AttachmentPoint( &ts->frontAttachment, front ) ) { CG_DestroyTrailSystem( &ts ); } if ( !CG_AttachmentPoint( &ts->backAttachment, back ) ) { CG_DestroyTrailSystem( &ts ); } VectorSubtract( back, front, dir ); for ( j = 0, i = tb->nodes; i; i = i->next, j++ ) { float scale = ( float ) j / ( float )( numNodes - 1 ); VectorMA( front, scale, dir, i->position ); } } else if ( CG_Attached( &ts->frontAttachment ) ) { // beam from one attachment // cull the trail tail i = CG_FindLastBeamNode( tb ); if ( i && i->timeLeft >= 0 ) { i->timeLeft -= deltaTime; if ( i->timeLeft < 0 ) { tb->nodes = CG_DestroyBeamNode( i ); if ( !tb->nodes ) { tb->valid = false; return; } // if the ts has been destroyed, stop creating new nodes if ( ts->destroyTime <= 0 ) { CG_PrependBeamNode( tb ); } } else if ( i->timeLeft >= 0 && i->prev ) { vec3_t dir; float length; VectorSubtract( i->refPosition, i->prev->refPosition, dir ); length = VectorNormalize( dir ) * ( ( float ) i->timeLeft / ( float ) tb->class_->segmentTime ); VectorMA( i->prev->refPosition, length, dir, i->position ); } } if ( tb->nodes ) { if ( !CG_AttachmentPoint( &ts->frontAttachment, tb->nodes->refPosition ) ) { CG_DestroyTrailSystem( &ts ); } VectorCopy( tb->nodes->refPosition, tb->nodes->position ); } } CG_ApplyJitters( tb ); }
/* =============== CG_GarbageCollectTrailSystems Destroy inactive trail systems =============== */ static void CG_GarbageCollectTrailSystems() { int i, j, count; trailSystem_t *ts; trailBeam_t *tb; int centNum; for ( i = 0; i < MAX_TRAIL_SYSTEMS; i++ ) { ts = &trailSystems[ i ]; count = 0; //don't bother checking already invalid systems if ( !ts->valid ) { continue; } for ( j = 0; j < MAX_TRAIL_BEAMS; j++ ) { tb = &trailBeams[ j ]; if ( tb->valid && tb->parent == ts ) { count++; } } if ( !count ) { ts->valid = false; } //check systems where the parent cent has left the PVS //( local player entity is always valid ) if ( ( centNum = CG_AttachmentCentNum( &ts->frontAttachment ) ) >= 0 && centNum != cg.snap->ps.clientNum ) { trailSystem_t *tempTS = ts; if ( !cg_entities[ centNum ].valid ) { CG_DestroyTrailSystem( &tempTS ); } } if ( ( centNum = CG_AttachmentCentNum( &ts->backAttachment ) ) >= 0 && centNum != cg.snap->ps.clientNum ) { trailSystem_t *tempTS = ts; if ( !cg_entities[ centNum ].valid ) { CG_DestroyTrailSystem( &tempTS ); } } // lifetime expired if ( ts->destroyTime <= 0 && ts->class_->lifeTime && ts->birthTime + ts->class_->lifeTime < cg.time ) { trailSystem_t *tempTS = ts; CG_DestroyTrailSystem( &tempTS ); if ( cg_debugTrails.integer >= 1 ) { Log::Debug( "TS %s expired (born %d, lives %d, now %d)", ts->class_->name, ts->birthTime, ts->class_->lifeTime, cg.time ); } } if ( cg_debugTrails.integer >= 1 && !ts->valid ) { Log::Debug( "TS %s garbage collected", ts->class_->name ); } } }