/* =============== 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_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 ); } } }
/* =============== CG_RenderBeam Renders a beam =============== */ static void CG_RenderBeam( trailBeam_t *tb ) { trailBeamNode_t *i = nullptr; trailBeamNode_t *prev = nullptr; trailBeamNode_t *next = nullptr; vec3_t up; polyVert_t verts[( MAX_TRAIL_BEAM_NODES - 1 ) * 4 ]; int numVerts = 0; baseTrailBeam_t *btb; trailSystem_t *ts; baseTrailSystem_t *bts; if ( !tb || !tb->nodes ) { return; } btb = tb->class_; ts = tb->parent; bts = ts->class_; if ( bts->thirdPersonOnly && ( CG_AttachmentCentNum( &ts->frontAttachment ) == cg.snap->ps.clientNum || CG_AttachmentCentNum( &ts->backAttachment ) == cg.snap->ps.clientNum ) && !cg.renderingThirdPerson ) { return; } CG_CalculateBeamNodeProperties( tb ); i = tb->nodes; do { prev = i->prev; next = i->next; if ( prev && next ) { //this node has two neighbours GetPerpendicularViewVector( cg.refdef.vieworg, next->position, prev->position, up ); } else if ( !prev && next ) { //this is the front GetPerpendicularViewVector( cg.refdef.vieworg, next->position, i->position, up ); } else if ( prev && !next ) { //this is the back GetPerpendicularViewVector( cg.refdef.vieworg, i->position, prev->position, up ); } else { break; } if ( prev ) { VectorMA( i->position, i->halfWidth, up, verts[ numVerts ].xyz ); verts[ numVerts ].st[ 0 ] = i->textureCoord; verts[ numVerts ].st[ 1 ] = 1.0f; if ( btb->realLight ) { CG_LightVertex( verts[ numVerts ].xyz, i->alpha, verts[ numVerts ].modulate ); } else { VectorCopy( i->color, verts[ numVerts ].modulate ); verts[ numVerts ].modulate[ 3 ] = i->alpha; } numVerts++; VectorMA( i->position, -i->halfWidth, up, verts[ numVerts ].xyz ); verts[ numVerts ].st[ 0 ] = i->textureCoord; verts[ numVerts ].st[ 1 ] = 0.0f; if ( btb->realLight ) { CG_LightVertex( verts[ numVerts ].xyz, i->alpha, verts[ numVerts ].modulate ); } else { VectorCopy( i->color, verts[ numVerts ].modulate ); verts[ numVerts ].modulate[ 3 ] = i->alpha; } numVerts++; } if ( next ) { VectorMA( i->position, -i->halfWidth, up, verts[ numVerts ].xyz ); verts[ numVerts ].st[ 0 ] = i->textureCoord; verts[ numVerts ].st[ 1 ] = 0.0f; if ( btb->realLight ) { CG_LightVertex( verts[ numVerts ].xyz, i->alpha, verts[ numVerts ].modulate ); } else { VectorCopy( i->color, verts[ numVerts ].modulate ); verts[ numVerts ].modulate[ 3 ] = i->alpha; } numVerts++; VectorMA( i->position, i->halfWidth, up, verts[ numVerts ].xyz ); verts[ numVerts ].st[ 0 ] = i->textureCoord; verts[ numVerts ].st[ 1 ] = 1.0f; if ( btb->realLight ) { CG_LightVertex( verts[ numVerts ].xyz, i->alpha, verts[ numVerts ].modulate ); } else { VectorCopy( i->color, verts[ numVerts ].modulate ); verts[ numVerts ].modulate[ 3 ] = i->alpha; } numVerts++; } if( btb->dynamicLight ) { trap_R_AddLightToScene( i->position, btb->dLightRadius, 3, ( float ) btb->dLightColor[ 0 ] / ( float ) 0xFF, ( float ) btb->dLightColor[ 1 ] / ( float ) 0xFF, ( float ) btb->dLightColor[ 2 ] / ( float ) 0xFF, 0, 0 ); } i = i->next; } while ( i ); trap_R_AddPolysToScene( tb->class_->shader, 4, &verts[ 0 ], numVerts / 4 ); }