mirror of
https://github.com/dhewm/dhewm3-sdk.git
synced 2024-12-18 08:32:37 +00:00
980 lines
25 KiB
C++
980 lines
25 KiB
C++
|
// Created by ivan_the_B
|
||
|
//
|
||
|
|
||
|
#include "../idlib/precompiled.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include "Game_local.h"
|
||
|
|
||
|
//uncomment those to enable debug
|
||
|
//#define _DEBUG_CUSTOM_GEOM
|
||
|
//#define _DEBUG_TRAIL
|
||
|
|
||
|
static const dword trailGenerator_vertexColor = PackColor( idVec4( 1,1,1,1 ) );
|
||
|
static const char *trailGenerator_SnapshotName = "_TrailGenerator_Snapshot_"; //Note: all the trail models use this name. It's not used so it's ok.
|
||
|
|
||
|
static const int TRAIL_ID_INVALID_UNIQUE = 0;
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
idTrailManager
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailManager::idTrailManager
|
||
|
================
|
||
|
*/
|
||
|
idTrailManager::idTrailManager( void ) {
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("idTrailManager::idTrailManager\n");
|
||
|
#endif
|
||
|
initialized = false;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailManager::Init
|
||
|
================
|
||
|
*/
|
||
|
void idTrailManager::Init( void ) {
|
||
|
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("idTrailManager::Init\n");
|
||
|
#endif
|
||
|
|
||
|
Shutdown();
|
||
|
|
||
|
memset( trails, 0, sizeof( trails ) );
|
||
|
memset( uniqueIds, TRAIL_ID_INVALID_UNIQUE, sizeof( uniqueIds ) );
|
||
|
|
||
|
lastUniqueId = TRAIL_ID_INVALID_UNIQUE;
|
||
|
|
||
|
minFreePos = 0; //first slot will be empty here
|
||
|
maxAllocPos = -1; //no one
|
||
|
|
||
|
initialized = true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailManager::~idTrailManager
|
||
|
================
|
||
|
*/
|
||
|
idTrailManager::~idTrailManager( void ) {
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("idTrailManager::~idTrailManager\n");
|
||
|
#endif
|
||
|
|
||
|
if(!initialized) return;
|
||
|
|
||
|
for ( int i = 0; i < MAX_TRAILS; i++ ) {
|
||
|
if( trails[ i ] ){
|
||
|
delete trails[ i ];
|
||
|
trails[ i ] = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailManager::Shutdown
|
||
|
================
|
||
|
*/
|
||
|
void idTrailManager::Shutdown( void ) {
|
||
|
if( !initialized ) return;
|
||
|
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("idTrailManager::Shutdown\n");
|
||
|
#endif
|
||
|
|
||
|
//deallocate all the trails that are still in memory
|
||
|
for ( int i = 0; i < MAX_TRAILS; i++ ) {
|
||
|
if( trails[ i ] ){
|
||
|
gameLocal.Warning("Someone created a trail (uid: %d), but never removed it!\TrailManager will now take care to free the memory...but check your code!", trails[ i ]->GetUniqueId() );
|
||
|
delete trails[ i ];
|
||
|
trails[ i ] = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
initialized = false;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailManager::Save
|
||
|
================
|
||
|
*/
|
||
|
void idTrailManager::Save( idSaveGame *savefile ) const {
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("idTrailManager::Save\n");
|
||
|
#endif
|
||
|
savefile->WriteBool( initialized );
|
||
|
savefile->WriteInt( lastUniqueId );
|
||
|
|
||
|
savefile->WriteInt( minFreePos );
|
||
|
savefile->WriteInt( maxAllocPos );
|
||
|
|
||
|
for ( int i = 0; i <= maxAllocPos; i++ ) { //only stuff before 'maxAllocPos'
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("saving int %d\n", uniqueIds[ i ]);
|
||
|
#endif
|
||
|
savefile->WriteInt( uniqueIds[ i ] );
|
||
|
if( uniqueIds[ i ] != TRAIL_ID_INVALID_UNIQUE ){
|
||
|
trails[ i ]->Save( savefile );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailManager::Restore
|
||
|
================
|
||
|
*/
|
||
|
void idTrailManager::Restore( idRestoreGame *savefile ) {
|
||
|
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("idTrailManager::Restore\n");
|
||
|
#endif
|
||
|
|
||
|
savefile->ReadBool( initialized );
|
||
|
savefile->ReadInt( lastUniqueId );
|
||
|
|
||
|
savefile->ReadInt( minFreePos );
|
||
|
savefile->ReadInt( maxAllocPos );
|
||
|
|
||
|
//load the ones before 'maxAllocPos'
|
||
|
for( int i = 0; i <= maxAllocPos; i++ ) { //only stuff before 'maxAllocPos'
|
||
|
savefile->ReadInt( uniqueIds[ i ] );
|
||
|
if( uniqueIds[ i ] != TRAIL_ID_INVALID_UNIQUE ){ //it was there. NOTE: same local pos!
|
||
|
trails[i] = new idTrailGenerator;
|
||
|
trails[i]->Restore( savefile );
|
||
|
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
//test only
|
||
|
if( trails[ i ]->GetLocalPos() != i ){
|
||
|
gameLocal.Error("localPos != array position! (%d)", i);
|
||
|
}
|
||
|
gameLocal.Printf("restored: - localPos: %d, uniId: %d\n", trails[ i ]->GetLocalPos(), trails[ i ]->GetUniqueId() );
|
||
|
#endif
|
||
|
}else{
|
||
|
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("restored: NULL at pos %d\n", i);
|
||
|
#endif
|
||
|
trails[i] = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//null the others
|
||
|
for( int i = maxAllocPos+1; i < MAX_TRAILS; i++ ) {
|
||
|
uniqueIds[ i ] = TRAIL_ID_INVALID_UNIQUE;
|
||
|
trails[i] = NULL;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailManager::FindTrailByUniqueId
|
||
|
================
|
||
|
*/
|
||
|
int idTrailManager::GetSafeUniqueId( idTrailGenerator* trailGen ){
|
||
|
return ( trailGen ? trailGen->GetUniqueId() : TRAIL_ID_INVALID_UNIQUE );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailManager::FindTrailByUniqueId
|
||
|
================
|
||
|
*/
|
||
|
idTrailGenerator* idTrailManager::FindTrailByLocalPos( int pos ) { //fast
|
||
|
if( pos < 0 || pos >= MAX_TRAILS ){
|
||
|
return NULL;
|
||
|
}
|
||
|
return trails[ pos ];
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailManager::FindTrailByUniqueId
|
||
|
================
|
||
|
*/
|
||
|
idTrailGenerator* idTrailManager::FindTrailByUniqueId( int id ) { //slow, but ensure it's not another trail at the same pos
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("idTrailManager::FindTrailById...\n");
|
||
|
#endif
|
||
|
|
||
|
if( id == TRAIL_ID_INVALID_UNIQUE ){ return NULL; }
|
||
|
|
||
|
for ( int i = 0; i < MAX_TRAILS; i++ ) {
|
||
|
if( trails[ i ] && trails[ i ]->GetUniqueId() == id ){
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("...found at pos: %d\n", i);
|
||
|
#endif
|
||
|
return trails[ i ];
|
||
|
}
|
||
|
}
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("...not found\n");
|
||
|
#endif
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailManager::Think
|
||
|
================
|
||
|
*/
|
||
|
void idTrailManager::Think( void ) {
|
||
|
for ( int i = 0; i <= maxAllocPos; i++ ) { //don't even check beyond 'maxAllocPos' because they all are null
|
||
|
if( trails[ i ] && trails[ i ]->fading ){ //->IsFading()
|
||
|
trails[ i ]->Fade();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailManager::GetTrailGen
|
||
|
================
|
||
|
*/
|
||
|
idTrailGenerator* idTrailManager::NewTrailGen( void ) {
|
||
|
int i;
|
||
|
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("idTrailManager::NewTrailGen\n");
|
||
|
#endif
|
||
|
|
||
|
if( minFreePos == MAX_TRAILS ){
|
||
|
gameLocal.Error("No free slots for another trail!");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
idTrailGenerator* myGen = new idTrailGenerator;
|
||
|
|
||
|
//set an unique id
|
||
|
lastUniqueId++;
|
||
|
myGen->Init( lastUniqueId, minFreePos );
|
||
|
|
||
|
|
||
|
//add it to list
|
||
|
trails[ minFreePos ] = myGen;
|
||
|
uniqueIds[ minFreePos ] = lastUniqueId;
|
||
|
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("Added trail 'uid: %d' at pos: %d\n", lastUniqueId, minFreePos );
|
||
|
#endif
|
||
|
|
||
|
//-- upd max pos allocated --
|
||
|
if( minFreePos > maxAllocPos ){ //note: minFreePos is were it was placed
|
||
|
maxAllocPos = minFreePos;
|
||
|
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("new maxAllocPos: %d\n", maxAllocPos);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
//-- upd min pos free -- (we are sure no one is free before 'minFreePos')
|
||
|
for ( i = minFreePos+1; i < MAX_TRAILS; i++ ) { //from here (well, next one) to max
|
||
|
if( !trails[ i ] ){ break; } //null
|
||
|
}
|
||
|
minFreePos = i; // MAX_TRAILS if full array
|
||
|
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("new minFreePos: %d\n", minFreePos);
|
||
|
|
||
|
if( minFreePos == MAX_TRAILS ){
|
||
|
gameLocal.Warning("This was the last free slot for a trail!");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return myGen;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailManager::RemoveTrailGen
|
||
|
================
|
||
|
*/
|
||
|
void idTrailManager::RemoveTrailGen( idTrailGenerator* trailGen ) {
|
||
|
int i;
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("idTrailManager::RemoveTrailGen\n");
|
||
|
#endif
|
||
|
if( !trailGen ){ return; }
|
||
|
|
||
|
//delete
|
||
|
int localPos = trailGen->GetLocalPos();
|
||
|
delete trails[ localPos ];
|
||
|
trails[ localPos ] = NULL;
|
||
|
|
||
|
//clear id
|
||
|
uniqueIds[ localPos ] = TRAIL_ID_INVALID_UNIQUE;
|
||
|
|
||
|
//-- upd min pos free --
|
||
|
if( localPos < minFreePos ){ //if this one is now the first NULL
|
||
|
minFreePos = localPos;
|
||
|
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("new minFreePos: %d\n", minFreePos);
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
//-- upd max pos allocated --
|
||
|
if( localPos == maxAllocPos ){ //if this one was the last allocated... go back until we find the first used slot
|
||
|
for ( i = maxAllocPos-1; i >= 0; i-- ) { //from prev one to 0
|
||
|
if( trails[ i ] ){ break; } //used
|
||
|
}
|
||
|
maxAllocPos = i; // -1 if empty array
|
||
|
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("new maxAllocPos: %d\n", maxAllocPos);
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("Removed trail at pos: %d\n", minFreePos );
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
idTrailGenerator
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailGenerator::idTrailGenerator
|
||
|
================
|
||
|
*/
|
||
|
idTrailGenerator::idTrailGenerator( void ) {
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("idTrailGenerator::idTrailGenerator\n");
|
||
|
#endif
|
||
|
|
||
|
initialized = false;
|
||
|
|
||
|
//new
|
||
|
uniqueId = TRAIL_ID_INVALID_UNIQUE;
|
||
|
localPos = MAX_TRAILS;
|
||
|
//thinkFlags = 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailGenerator::Init
|
||
|
================
|
||
|
*/
|
||
|
void idTrailGenerator::Init( int uniId, int locPos ) {
|
||
|
//gameLocal.Printf("idTrailGenerator::Init\n");
|
||
|
|
||
|
if( initialized ){
|
||
|
gameLocal.Error("Cannot initialize the same trail twice");
|
||
|
}
|
||
|
|
||
|
uniqueId = uniId; //used for restoring references!
|
||
|
localPos = locPos; //used for callback! It's faster but cannot identify it univocally
|
||
|
//thinkFlags = 0;
|
||
|
|
||
|
//settings
|
||
|
enabled = false;
|
||
|
fading = false;
|
||
|
fadingTime = 0;
|
||
|
fadingEndTime = 0;
|
||
|
fadingColorStep.Zero();
|
||
|
maxPoints = 0;
|
||
|
material = NULL;
|
||
|
trailDef = NULL;
|
||
|
trailDefName = "";
|
||
|
points.SetGranularity( 2 ); //use 2 because we always add/remove couple of points.
|
||
|
|
||
|
|
||
|
//rendering
|
||
|
memset( &renderEntity, 0, sizeof( renderEntity ) );
|
||
|
|
||
|
renderEntity.entityNum = localPos;
|
||
|
renderEntity.bounds.Clear();
|
||
|
renderEntity.axis = mat3_identity;
|
||
|
renderEntity.shaderParms[ SHADERPARM_RED ] = 1;
|
||
|
renderEntity.shaderParms[ SHADERPARM_GREEN ] = 1;
|
||
|
renderEntity.shaderParms[ SHADERPARM_BLUE ] = 1;
|
||
|
renderEntity.shaderParms[3] = 1;
|
||
|
renderEntity.hModel = renderModelManager->AllocModel();
|
||
|
renderEntity.hModel->InitEmpty( trailGenerator_SnapshotName );
|
||
|
renderEntity.noShadow = 1;
|
||
|
renderEntity.callback = idTrailGenerator::ModelCallback;
|
||
|
renderEntity.bounds.AddPoint( idVec3(-100000, -100000, -100000) ); // huge bounds, so it will be present in every world area
|
||
|
renderEntity.bounds.AddPoint( idVec3( 100000, 100000, 100000) );
|
||
|
|
||
|
// add to renderer list
|
||
|
//renderEntityHandle = gameRenderWorld->AddEntityDef( &renderEntity );
|
||
|
renderEntityHandle = -1; //don't add it to renderworld until it's disabled
|
||
|
|
||
|
lastRenderEntityUpdate = -1;
|
||
|
modelChanged = false;
|
||
|
|
||
|
initialized = true;
|
||
|
}
|
||
|
|
||
|
//always call this after color/flags change on renderEntity
|
||
|
void idTrailGenerator::UpdateVisuals( void ) {
|
||
|
// add to refresh list
|
||
|
if ( renderEntityHandle == -1 ) {
|
||
|
renderEntityHandle = gameRenderWorld->AddEntityDef( &renderEntity );
|
||
|
} else {
|
||
|
gameRenderWorld->UpdateEntityDef( renderEntityHandle, &renderEntity ); //save colors and other flags on renderEntity
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//remove it from RenderWorld when disabled
|
||
|
void idTrailGenerator::FreeEntityDef( void ) {
|
||
|
if ( renderEntityHandle != -1 ) {
|
||
|
gameRenderWorld->FreeEntityDef( renderEntityHandle );
|
||
|
renderEntityHandle = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailGenerator::~idTrailGenerator
|
||
|
================
|
||
|
*/
|
||
|
idTrailGenerator::~idTrailGenerator( void ) {
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("idTrailGenerator::~idTrailGenerator\n");
|
||
|
#endif
|
||
|
|
||
|
if(!initialized){ return; }
|
||
|
|
||
|
// make sure the render entity is freed before the model is freed
|
||
|
if ( renderEntityHandle != -1 ) {
|
||
|
gameRenderWorld->FreeEntityDef( renderEntityHandle );
|
||
|
renderEntityHandle = -1;
|
||
|
}
|
||
|
if ( renderEntity.hModel != NULL ) {
|
||
|
renderModelManager->FreeModel( renderEntity.hModel );
|
||
|
renderEntity.hModel = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailGenerator::Save
|
||
|
================
|
||
|
*/
|
||
|
void idTrailGenerator::Save( idSaveGame *savefile ) const {
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("idTrailGenerator::Save\n");
|
||
|
#endif
|
||
|
//global
|
||
|
savefile->WriteInt( uniqueId );
|
||
|
savefile->WriteInt( localPos );
|
||
|
savefile->WriteBool( initialized );
|
||
|
|
||
|
// settings
|
||
|
savefile->WriteBool( enabled );
|
||
|
savefile->WriteBool( fading );
|
||
|
savefile->WriteVec3( fadingColorStep );
|
||
|
savefile->WriteInt( fadingTime );
|
||
|
savefile->WriteInt( fadingEndTime );
|
||
|
savefile->WriteInt( maxPoints );
|
||
|
savefile->WriteMaterial( material );
|
||
|
|
||
|
//trail def
|
||
|
//trailDef is NOT saved, but can be retrieved from trailDefName
|
||
|
savefile->WriteString( trailDefName );
|
||
|
|
||
|
//points are NOT saved!! The trail will be be empty.
|
||
|
//idList<idVec3> points;
|
||
|
|
||
|
//rendering
|
||
|
savefile->WriteRenderEntity( renderEntity );
|
||
|
savefile->WriteInt( renderEntityHandle );
|
||
|
savefile->WriteInt( lastRenderEntityUpdate );
|
||
|
savefile->WriteBool( modelChanged );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailGenerator::Restore
|
||
|
================
|
||
|
*/
|
||
|
void idTrailGenerator::Restore( idRestoreGame *savefile ) {
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("idTrailGenerator::Restore\n");
|
||
|
#endif
|
||
|
//global
|
||
|
savefile->ReadInt( uniqueId ); //used for restoring references!
|
||
|
savefile->ReadInt( localPos );
|
||
|
savefile->ReadBool( initialized );
|
||
|
|
||
|
// settings
|
||
|
savefile->ReadBool( enabled );
|
||
|
savefile->ReadBool( fading );
|
||
|
savefile->ReadVec3( fadingColorStep );
|
||
|
savefile->ReadInt( fadingTime );
|
||
|
savefile->ReadInt( fadingEndTime );
|
||
|
savefile->ReadInt( maxPoints );
|
||
|
savefile->ReadMaterial( material );
|
||
|
|
||
|
//trail def
|
||
|
savefile->ReadString( trailDefName );
|
||
|
if ( trailDefName.Length() ) {
|
||
|
trailDef = gameLocal.FindEntityDefDict( trailDefName );
|
||
|
} else {
|
||
|
trailDef = NULL;
|
||
|
//gameLocal.Warning("trailDef not found!");
|
||
|
}
|
||
|
|
||
|
//points are NOT saved!!
|
||
|
points.Clear();
|
||
|
points.SetGranularity( 2 );
|
||
|
|
||
|
//rendering
|
||
|
savefile->ReadRenderEntity( renderEntity );
|
||
|
savefile->ReadInt( renderEntityHandle );
|
||
|
savefile->ReadInt( lastRenderEntityUpdate );
|
||
|
savefile->ReadBool( modelChanged );
|
||
|
|
||
|
//fix - reallocate the model ( this was created on init )
|
||
|
renderEntity.entityNum = localPos; //used for callback!
|
||
|
renderEntity.hModel = renderModelManager->AllocModel();
|
||
|
renderEntity.hModel->InitEmpty( trailGenerator_SnapshotName );
|
||
|
renderEntity.callback = idTrailGenerator::ModelCallback;
|
||
|
renderEntity.noShadow = true;
|
||
|
renderEntity.noSelfShadow = true;
|
||
|
renderEntity.noDynamicInteractions = false;
|
||
|
|
||
|
/*
|
||
|
// restore must retrieve renderEntityHandle from the renderer
|
||
|
if ( renderEntityHandle != -1 ) {
|
||
|
renderEntityHandle = gameRenderWorld->AddEntityDef( &renderEntity );
|
||
|
}
|
||
|
*/
|
||
|
if ( renderEntityHandle != -1 ) {
|
||
|
renderEntityHandle = gameRenderWorld->AddEntityDef( &renderEntity );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailGenerator::RestartTrail
|
||
|
================
|
||
|
*/
|
||
|
void idTrailGenerator::RestartTrail( void ){
|
||
|
idVec3 color;
|
||
|
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("RestartTrail %s\n", trailDefName.c_str() );
|
||
|
#endif
|
||
|
|
||
|
if( trailDef ){
|
||
|
//restore the old color
|
||
|
trailDef->GetVector( "color", "1 1 1", color );
|
||
|
renderEntity.shaderParms[ SHADERPARM_RED ] = color[ 0 ];
|
||
|
renderEntity.shaderParms[ SHADERPARM_GREEN ] = color[ 1 ];
|
||
|
renderEntity.shaderParms[ SHADERPARM_BLUE ] = color[ 2 ];
|
||
|
}else{
|
||
|
gameLocal.Warning("Trying to restart a trail without a def!\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//state
|
||
|
enabled = true; //weapon will upd the position
|
||
|
fading = false;
|
||
|
modelChanged = true; //upd renderer
|
||
|
UpdateVisuals(); //make sure it's in the world and updated
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailGenerator::StartTrail
|
||
|
================
|
||
|
*/
|
||
|
void idTrailGenerator::StartTrail( const char *newTrailDefName ){
|
||
|
const char *materialName;
|
||
|
idVec3 color;
|
||
|
const idDict *newTrailDef;
|
||
|
|
||
|
#ifdef _DEBUG_TRAIL
|
||
|
gameLocal.Printf("StartTrail %s\n", newTrailDefName );
|
||
|
#endif
|
||
|
|
||
|
newTrailDef = gameLocal.FindEntityDefDict( newTrailDefName, false );
|
||
|
if ( !newTrailDef ) {
|
||
|
gameLocal.Error( "Unknown def '%s'", newTrailDefName );
|
||
|
}
|
||
|
|
||
|
//NOTE: this works, but we assume that if it's the same def, RestartTrail() will be called instead.
|
||
|
if( trailDef && newTrailDef && (newTrailDef == trailDef) ){
|
||
|
//gameLocal.Warning("Started a new Trail with the same def! use RestartTrail() instead to save performance!");
|
||
|
RestartTrail();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//remove the points
|
||
|
//points.Clear(); //we can keep the old ones so, if we already are active the trail goes on.
|
||
|
|
||
|
//fadingTime
|
||
|
newTrailDef->GetInt( "fadeTime", "200", fadingTime );
|
||
|
if( fadingTime < 0 ) fadingTime = 0;
|
||
|
|
||
|
//maxPoints
|
||
|
newTrailDef->GetInt( "numFrames", "10", maxPoints );
|
||
|
maxPoints = ( maxPoints < 1 ) ? 4 : ( maxPoints*2+2 ); //1frame -> 4points, 2frame -> 6points, ...
|
||
|
|
||
|
//color
|
||
|
newTrailDef->GetVector( "color", "1 1 1", color );
|
||
|
renderEntity.shaderParms[ SHADERPARM_RED ] = color[ 0 ];
|
||
|
renderEntity.shaderParms[ SHADERPARM_GREEN ] = color[ 1 ];
|
||
|
renderEntity.shaderParms[ SHADERPARM_BLUE ] = color[ 2 ];
|
||
|
|
||
|
//material
|
||
|
materialName = newTrailDef->GetString( "mtr_surface", "" );
|
||
|
material = declManager->FindMaterial( materialName );
|
||
|
|
||
|
//remember the new trail def
|
||
|
trailDef = newTrailDef;
|
||
|
trailDefName = newTrailDefName;
|
||
|
|
||
|
//state
|
||
|
enabled = true; //weapon will upd the position
|
||
|
fading = false;
|
||
|
modelChanged = true; //upd renderer
|
||
|
UpdateVisuals(); //make sure it's in the world and updated
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailGenerator::FadeTrail
|
||
|
================
|
||
|
*/
|
||
|
void idTrailGenerator::FadeTrail( void ){
|
||
|
idVec3 colorNow;
|
||
|
|
||
|
if( fadingTime <= 0 ){
|
||
|
StopTrail();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//color
|
||
|
colorNow[ 0 ] = renderEntity.shaderParms[ SHADERPARM_RED ];
|
||
|
colorNow[ 1 ] = renderEntity.shaderParms[ SHADERPARM_GREEN ];
|
||
|
colorNow[ 2 ] = renderEntity.shaderParms[ SHADERPARM_BLUE ];
|
||
|
|
||
|
//color step for each frame
|
||
|
fadingColorStep = ( vec3_zero - colorNow)*USERCMD_MSEC/fadingTime;
|
||
|
|
||
|
//time
|
||
|
fadingEndTime = gameLocal.time + fadingTime;
|
||
|
|
||
|
//state
|
||
|
enabled = true; //weapon will upd the position
|
||
|
fading = true;
|
||
|
UpdateVisuals(); //make sure it's in the world and updated
|
||
|
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailGenerator::StopTrail
|
||
|
================
|
||
|
*/
|
||
|
void idTrailGenerator::StopTrail( void ){
|
||
|
if(!enabled) return;
|
||
|
|
||
|
//remove points
|
||
|
points.Clear();
|
||
|
|
||
|
//state
|
||
|
enabled = false;
|
||
|
fading = false;
|
||
|
modelChanged = true; //upd renderer
|
||
|
|
||
|
FreeEntityDef(); //remove from world
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailGenerator::AddNewPoints
|
||
|
================
|
||
|
*/
|
||
|
void idTrailGenerator::AddNewPoints( const idVec3 &newPosL, const idVec3 &newPosH ) {
|
||
|
|
||
|
if( !enabled ){
|
||
|
gameLocal.Warning("Cannot add points to a disabled trail!");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
//NOTE: this is commented out because we assume that sword is moving while trail is active.
|
||
|
if( points.Num() >= 2 ){
|
||
|
if( points[0].Compare( newPosL ) && points[1].Compare( newPosH ) ){
|
||
|
return; //if points did not change don't upd anything
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
//remove oldest points
|
||
|
while( points.Num() >= maxPoints ){ //example: maxPoints 6 and we have 6 -> remove 2 so we can add the new ones
|
||
|
points.RemoveIndex(0);
|
||
|
points.RemoveIndex(0);
|
||
|
}
|
||
|
|
||
|
points.Append( newPosL );
|
||
|
points.Append( newPosH );
|
||
|
|
||
|
modelChanged = true; //upd renderer
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailGenerator::RemoveOldestPoints
|
||
|
================
|
||
|
*/
|
||
|
void idTrailGenerator::RemoveOldestPoints( void ) {
|
||
|
|
||
|
if( !enabled ){
|
||
|
gameLocal.Warning("Cannot remove points to a disabled trail!");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
//NOTE: this is commented out because we assume that sword is moving while trail is active.
|
||
|
if( points.Num() >= 2 ){
|
||
|
if( points[0].Compare( newPosL ) && points[1].Compare( newPosH ) ){
|
||
|
return; //if points did not change don't upd anything
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
//remove oldest points
|
||
|
if( points.Num() >= 2 ){
|
||
|
points.RemoveIndex(0);
|
||
|
points.RemoveIndex(0);
|
||
|
modelChanged = true; //upd renderer
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailGenerator::UpdateRenderEntity
|
||
|
================
|
||
|
*/
|
||
|
bool idTrailGenerator::UpdateRenderEntity( renderEntity_s *renderEntity, const renderView_t *renderView ) const {
|
||
|
int i, j, numTris, numPoints;
|
||
|
float fitpct, fitoffset;
|
||
|
srfTriangles_t *tris;
|
||
|
modelSurface_t surface;
|
||
|
idDrawVert *v;
|
||
|
idPlane plane;
|
||
|
idMat3 tangents;
|
||
|
idFixedWinding winding; //TODO: this is big...promote it to class member to save perf?
|
||
|
|
||
|
// this may be triggered by a model trace or other non-view related source,
|
||
|
// to which we should look like an empty model
|
||
|
if ( !renderView ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// regenerate only if modelChanged. Only one per frame.
|
||
|
//was: if ( !modelChanged || lastRenderEntityUpdate == gameLocal.time ) {
|
||
|
if ( lastRenderEntityUpdate == gameLocal.time ) { //moved the "modelChanged" check in callback to save perf.
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
lastRenderEntityUpdate = gameLocal.time;
|
||
|
modelChanged = false;
|
||
|
//gameLocal.Printf("UpdateRenderEntity at time: %d\n", lastRenderEntityUpdate);
|
||
|
|
||
|
//we need at least 4 points + even number
|
||
|
numPoints = points.Num();
|
||
|
if( numPoints < 4 ){ //|| (numPoints % 2 != 0) //number is always even thanks to creation policy.
|
||
|
//clean the model and return.
|
||
|
renderEntity->hModel->InitEmpty( trailGenerator_SnapshotName );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//calculate number of tris and materialOffset-per-coupleOfTris pct
|
||
|
numTris = numPoints - 2; //examples: 4p -> 2t, 6p -> 4t, 8p ->6t
|
||
|
fitpct = 1.0f / ( numTris /2.0f ); // numTris/2 is the number of steps. 4p -> 2t -> 1step, 6p -> 4t -> 2steps, 8p ->6t -> 3steps
|
||
|
|
||
|
// FIXME: re-use model surfaces? <-- we cannot do that: we would need to remove the oldest piece and shift the texture.
|
||
|
renderEntity->hModel->InitEmpty( trailGenerator_SnapshotName );
|
||
|
|
||
|
#ifdef _DEBUG_CUSTOM_GEOM
|
||
|
//debug
|
||
|
idBounds bbox;
|
||
|
bbox.Zero();
|
||
|
bbox.ExpandSelf(1);
|
||
|
idVec4 color;
|
||
|
color[3] = 1; //alpha
|
||
|
for( i = 0; i < numPoints; i++ ){
|
||
|
if( i % 2 == 0){
|
||
|
color[0] = gameLocal.random.RandomFloat();
|
||
|
color[1] = gameLocal.random.RandomFloat();
|
||
|
color[2] = gameLocal.random.RandomFloat();
|
||
|
}
|
||
|
gameRenderWorld->DebugBounds( color, bbox, points[i], 20000);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// allocate triangle surfaces for the fractures and decals
|
||
|
tris = renderEntity->hModel->AllocSurfaceTriangles( numTris * 3, material->ShouldCreateBackSides() ? numTris * 6 : numTris * 3 );
|
||
|
|
||
|
//packedColor = PackColor( idVec4( 1,1,1,1 ) );
|
||
|
|
||
|
/*
|
||
|
gameLocal.Printf("color found: %f, %f, %f\n", renderEntity->shaderParms[ SHADERPARM_RED ], renderEntity->shaderParms[ SHADERPARM_GREEN ], renderEntity->shaderParms[ SHADERPARM_BLUE ] );
|
||
|
if( &(this->renderEntity) == renderEntity ){
|
||
|
gameLocal.Printf("Stesso renderEntity!\n");
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
//gameLocal.Printf("iteration starts...\n ");
|
||
|
fitoffset = 1.0f;
|
||
|
for( i = 0; i < (numPoints - 3); i += 2 ){
|
||
|
//gameLocal.Printf(",%d",i);
|
||
|
|
||
|
//re-use the same winding every time
|
||
|
winding.Clear();
|
||
|
|
||
|
//points closer to the sword
|
||
|
winding.AddPoint( idVec5( points[i], idVec2(0, fitoffset )) ); //Lower point
|
||
|
winding.AddPoint( idVec5( points[i+1], idVec2(1, fitoffset)) ); //Higher point
|
||
|
|
||
|
//gameLocal.Printf("fitoffset: %f, fitoffset-fitpct: %f\n", fitoffset, (fitoffset-fitpct) );
|
||
|
fitoffset -= fitpct; //decrease the texture offset so that the texture is correctly fit
|
||
|
if( fitoffset < 0.0f ){ fitoffset = 0.0f; } //solve approximation issues
|
||
|
|
||
|
//previous points
|
||
|
winding.AddPoint( idVec5( points[i+3], idVec2(1, fitoffset)) ); //Higher point
|
||
|
winding.AddPoint( idVec5( points[i+2], idVec2(0, fitoffset)) ); //Lower point
|
||
|
|
||
|
//get info from windings
|
||
|
winding.GetPlane( plane );
|
||
|
tangents = ( plane.Normal() ).ToMat3(); //was: ( plane.Normal() * axis ).ToMat3();
|
||
|
|
||
|
//create tris given points in winding. Usually we have 4 points -> 2tris
|
||
|
for ( j = 2; j < winding.GetNumPoints(); j++ ) {
|
||
|
|
||
|
//first vertex is always placed at the first point
|
||
|
v = &tris->verts[tris->numVerts++];
|
||
|
v->Clear();
|
||
|
v->xyz = winding[0].ToVec3();
|
||
|
v->st[0] = winding[0].s;
|
||
|
v->st[1] = winding[0].t;
|
||
|
v->normal = tangents[0];
|
||
|
v->tangents[0] = tangents[1];
|
||
|
v->tangents[1] = tangents[2];
|
||
|
v->SetColor( trailGenerator_vertexColor );
|
||
|
|
||
|
//second vertex
|
||
|
v = &tris->verts[tris->numVerts++];
|
||
|
v->Clear();
|
||
|
v->xyz = winding[j-1].ToVec3();
|
||
|
v->st[0] = winding[j-1].s;
|
||
|
v->st[1] = winding[j-1].t;
|
||
|
v->normal = tangents[0];
|
||
|
v->tangents[0] = tangents[1];
|
||
|
v->tangents[1] = tangents[2];
|
||
|
v->SetColor( trailGenerator_vertexColor );
|
||
|
|
||
|
//third vertex
|
||
|
v = &tris->verts[tris->numVerts++];
|
||
|
v->Clear();
|
||
|
v->xyz = winding[j].ToVec3();
|
||
|
v->st[0] = winding[j].s;
|
||
|
v->st[1] = winding[j].t;
|
||
|
v->normal = tangents[0];
|
||
|
v->tangents[0] = tangents[1];
|
||
|
v->tangents[1] = tangents[2];
|
||
|
v->SetColor( trailGenerator_vertexColor );
|
||
|
|
||
|
//set the index for each tris
|
||
|
tris->indexes[tris->numIndexes++] = tris->numVerts - 3;
|
||
|
tris->indexes[tris->numIndexes++] = tris->numVerts - 2;
|
||
|
tris->indexes[tris->numIndexes++] = tris->numVerts - 1;
|
||
|
|
||
|
if ( material->ShouldCreateBackSides() ) {
|
||
|
|
||
|
tris->indexes[tris->numIndexes++] = tris->numVerts - 2;
|
||
|
tris->indexes[tris->numIndexes++] = tris->numVerts - 3;
|
||
|
tris->indexes[tris->numIndexes++] = tris->numVerts - 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tris->tangentsCalculated = true;
|
||
|
|
||
|
SIMDProcessor->MinMax( tris->bounds[0], tris->bounds[1], tris->verts, tris->numVerts );
|
||
|
|
||
|
memset( &surface, 0, sizeof( surface ) );
|
||
|
surface.shader = material;
|
||
|
surface.id = 0;
|
||
|
surface.geometry = tris;
|
||
|
renderEntity->hModel->AddSurface( surface );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailGenerator::ModelCallback
|
||
|
================
|
||
|
*/
|
||
|
bool idTrailGenerator::ModelCallback( renderEntity_s *renderEntity, const renderView_t *renderView ) {
|
||
|
//gameLocal.Printf("idTrailGenerator::ModelCallback\n");
|
||
|
|
||
|
const idTrailGenerator *trailGen;
|
||
|
|
||
|
trailGen = gameLocal.trailsManager->trails[ renderEntity->entityNum ];
|
||
|
if ( !trailGen ) {
|
||
|
gameLocal.Error( "idTrailGenerator::ModelCallback: callback with NULL trailGen" );
|
||
|
}
|
||
|
|
||
|
if ( !trailGen->modelChanged ){
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return trailGen->UpdateRenderEntity( renderEntity, renderView );
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idTrailGenerator::Think
|
||
|
================
|
||
|
*/
|
||
|
void idTrailGenerator::Fade( void ) { //TrailGenerator thinks before all the other entities.
|
||
|
//gameLocal.Printf("idTrailGenerator::Fade\n");
|
||
|
|
||
|
//if ( fading ) {
|
||
|
if( fadingEndTime > gameLocal.time ){
|
||
|
//gameLocal.Printf("fading...\n");
|
||
|
renderEntity.shaderParms[ SHADERPARM_RED ] += fadingColorStep[ 0 ];
|
||
|
renderEntity.shaderParms[ SHADERPARM_GREEN ] += fadingColorStep[ 1 ];
|
||
|
renderEntity.shaderParms[ SHADERPARM_BLUE ] += fadingColorStep[ 2 ];
|
||
|
UpdateVisuals(); //make sure it's in the world and updated
|
||
|
}else{
|
||
|
StopTrail();
|
||
|
}
|
||
|
//}
|
||
|
}
|