mirror of
https://github.com/ENSL/NS.git
synced 2024-12-16 15:42:09 +00:00
5dcc163bd5
git-svn-id: https://unknownworlds.svn.cloudforge.com/ns1@379 67975925-1194-0748-b3d5-c16f83f1a3a1
590 lines
No EOL
16 KiB
C++
590 lines
No EOL
16 KiB
C++
//======== (C) Copyright 2001 Charles G. Cleveland All rights reserved. =========
|
|
//
|
|
// The copyright to the contents herein is the property of Charles G. Cleveland.
|
|
// The contents may be used and/or copied only with the written permission of
|
|
// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in
|
|
// the agreement/contract under which the contents have been supplied.
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $Workfile: AvHParticleSystemManager.cpp $
|
|
// $Date: 2002/10/28 20:36:06 $
|
|
//
|
|
//-------------------------------------------------------------------------------
|
|
// $Log: AvHParticleSystemManager.cpp,v $
|
|
// Revision 1.14 2002/10/28 20:36:06 Flayra
|
|
// - Tweaked particle culling time to work with umbra and spores
|
|
//
|
|
// Revision 1.13 2002/10/24 21:34:46 Flayra
|
|
// - Fixes for particle culling again!
|
|
//
|
|
// Revision 1.12 2002/07/10 14:44:10 Flayra
|
|
// - Visibility fixes (too many PSs drawing, now they expire when not visible for awhile)
|
|
//
|
|
// Revision 1.11 2002/05/23 02:33:20 Flayra
|
|
// - Post-crash checkin. Restored @Backup from around 4/16. Contains changes for last four weeks of development.
|
|
//
|
|
//===============================================================================
|
|
#include "mod/AvHParticleSystemManager.h"
|
|
|
|
#ifdef AVH_CLIENT
|
|
#include "cl_dll/hud.h"
|
|
#include "cl_dll/cl_util.h"
|
|
|
|
// Triangle rendering apis are in gEngfuncs.pTriAPI
|
|
#include "common/const.h"
|
|
#include "common/entity_state.h"
|
|
#include "common/cl_entity.h"
|
|
#include "common/triangleapi.h"
|
|
#include <papi.h>
|
|
#include "mod/AvHParticleTemplateClient.h"
|
|
|
|
#else
|
|
#include "mod/AvHParticleTemplate.h"
|
|
#include "mod/AvHParticleTemplateServer.h"
|
|
#include "dlls/util.h"
|
|
#endif
|
|
|
|
#include "pm_shared/pm_debug.h"
|
|
|
|
#ifdef AVH_CLIENT
|
|
AvHParticleTemplateListClient gParticleTemplateList;
|
|
extern DebugEntityListType gCubeDebugEntities;
|
|
#else
|
|
//AvHParticleTemplateList gParticleTemplateList;
|
|
AvHParticleTemplateListServer gParticleTemplateList;
|
|
#endif
|
|
|
|
AvHParticleSystemManager* AvHParticleSystemManager::sInstance = NULL;
|
|
const float kUpdateIncrement = 0.0f;
|
|
|
|
AvHParticleSystemManager*
|
|
AvHParticleSystemManager::Instance()
|
|
{
|
|
if(!sInstance)
|
|
{
|
|
sInstance = new AvHParticleSystemManager();
|
|
}
|
|
return sInstance;
|
|
}
|
|
|
|
void AvHParticleSystemManager::Init()
|
|
{
|
|
#ifdef AVH_CLIENT
|
|
this->mStarted = false;
|
|
#else
|
|
this->mStarted = true;
|
|
#endif
|
|
|
|
this->mReloadFromTemplates = false;
|
|
|
|
this->mUpdatedTime = 0.0f;
|
|
this->mTimePassed = 0.0f;
|
|
}
|
|
|
|
AvHParticleSystemManager::AvHParticleSystemManager()
|
|
{
|
|
this->Init();
|
|
}
|
|
|
|
void
|
|
AvHParticleSystemManager::CreateParticleSystem(uint32 inTemplateIndex, int inParentEntityIndex, ParticleSystemHandle inHandle)
|
|
{
|
|
this->mQueuedCreateList.push_back(QueuedParticleSystem(inTemplateIndex, this->GetTime(), inParentEntityIndex, inHandle));
|
|
}
|
|
|
|
void
|
|
AvHParticleSystemManager::CreateParticleSystem(uint32 inTemplateIndex, vec3_t inOrigin, vec3_t* inNormal)
|
|
{
|
|
QueuedParticleSystem theParticleSystem(inTemplateIndex, this->GetTime(), inOrigin);
|
|
if(inNormal)
|
|
{
|
|
theParticleSystem.SetNormal(*inNormal);
|
|
}
|
|
this->mQueuedCreateList.push_back(theParticleSystem);
|
|
}
|
|
|
|
bool
|
|
AvHParticleSystemManager::CreateParticleSystem(const string& inTemplateName, vec3_t inOrigin, vec3_t* inNormal)
|
|
{
|
|
bool theSuccess = false;
|
|
|
|
// Lookup template by name
|
|
uint32 theTemplateIndex = 0;
|
|
|
|
if(::gParticleTemplateList.GetTemplateIndexWithName(inTemplateName, theTemplateIndex))
|
|
{
|
|
this->CreateParticleSystem(theTemplateIndex, inOrigin, inNormal);
|
|
theSuccess = true;
|
|
}
|
|
|
|
return theSuccess;
|
|
}
|
|
|
|
void
|
|
AvHParticleSystemManager::CreateParticleSystemIfNotCreated(int inIndex, int inTemplateIndex, int inHandle)
|
|
{
|
|
bool theEntityHasParticles = false;
|
|
|
|
// Look in list of entities, see if we've created one for this entity
|
|
for(ParticleEntityList::iterator theIter = this->mParticleEntities.begin(); theIter != this->mParticleEntities.end(); theIter++)
|
|
{
|
|
if(*theIter == inIndex)
|
|
{
|
|
theEntityHasParticles = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!theEntityHasParticles)
|
|
{
|
|
// If not, create one
|
|
this->CreateParticleSystem(inTemplateIndex, inIndex, (ParticleSystemHandle)inHandle);
|
|
|
|
// Add entity to list
|
|
this->mParticleEntities.push_back(inIndex);
|
|
}
|
|
}
|
|
|
|
void
|
|
AvHParticleSystemManager::DestroyParticleSystemIfNotDestroyed(int inIndex, ParticleSystemHandle inHandle)
|
|
{
|
|
// Look in list of entities, see if we've created one for this entity
|
|
for(ParticleEntityList::iterator theIter = this->mParticleEntities.begin(); theIter != this->mParticleEntities.end(); theIter++)
|
|
{
|
|
if(*theIter == inIndex)
|
|
{
|
|
// If so, destroy this particle system. Note that this particle system could have already
|
|
// expired, that's ok. The list of particle entities just needs to be kept up to date.
|
|
this->DestroyParticleSystem(inHandle);
|
|
|
|
// Remove entity from list
|
|
this->mParticleEntities.erase(theIter);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
AvHParticleSystemManager::DestroyParticleSystem(ParticleSystemHandle inHandle)
|
|
{
|
|
InternalDestroyParticleSystem(inHandle);
|
|
}
|
|
|
|
void
|
|
AvHParticleSystemManager::Draw(const pVector& inView)
|
|
{
|
|
if(this->mStarted)
|
|
{
|
|
ParticleSystemList::iterator theIterator;
|
|
for(theIterator = this->mParticleSystemList.begin(); theIterator != this->mParticleSystemList.end(); theIterator++)
|
|
{
|
|
theIterator->Draw(inView);
|
|
}
|
|
}
|
|
}
|
|
|
|
AvHParticleSystem*
|
|
AvHParticleSystemManager::GetParticleSystem(ParticleSystemHandle inHandle)
|
|
{
|
|
AvHParticleSystem* theParticleSystem = NULL;
|
|
|
|
for(ParticleSystemList::iterator theIterator = this->mParticleSystemList.begin(); theIterator != this->mParticleSystemList.end(); theIterator++)
|
|
{
|
|
if(theIterator->GetHandle() == inHandle)
|
|
{
|
|
theParticleSystem = &*theIterator;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return theParticleSystem;
|
|
}
|
|
|
|
int
|
|
AvHParticleSystemManager::GetNumberParticleSystems()
|
|
{
|
|
return (int)this->mParticleSystemList.size();
|
|
}
|
|
|
|
#ifdef AVH_CLIENT
|
|
int AvHParticleSystemManager::GetNumberVisibleParticleSystems()
|
|
{
|
|
int theNumVisibleSystems = 0;
|
|
|
|
for(ParticleSystemList::iterator theIterator = this->mParticleSystemList.begin(); theIterator != this->mParticleSystemList.end(); theIterator++)
|
|
{
|
|
if(theIterator->GetIsVisible())
|
|
{
|
|
theNumVisibleSystems++;
|
|
}
|
|
}
|
|
return theNumVisibleSystems;
|
|
}
|
|
#endif
|
|
|
|
float
|
|
AvHParticleSystemManager::GetTime(void) const
|
|
{
|
|
float theTime = 0;
|
|
|
|
#ifdef AVH_CLIENT
|
|
theTime = gEngfuncs.GetClientTime();
|
|
#else
|
|
theTime = gpGlobals->time;
|
|
#endif
|
|
|
|
return theTime;
|
|
}
|
|
|
|
bool
|
|
AvHParticleSystemManager::InternalDestroyParticleSystem(ParticleSystemHandle inHandle)
|
|
{
|
|
bool theDestroyed = false;
|
|
|
|
for(ParticleSystemList::iterator theIterator = this->mParticleSystemList.begin(); theIterator != this->mParticleSystemList.end(); theIterator++)
|
|
{
|
|
if(theIterator->GetHandle() == inHandle)
|
|
{
|
|
// Tell it to kill its particles and clean up
|
|
theIterator->Kill();
|
|
|
|
// Remove it from the list
|
|
theIterator = this->mParticleSystemList.erase(theIterator);
|
|
|
|
// We're successful and done
|
|
theDestroyed = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return theDestroyed;
|
|
}
|
|
|
|
bool
|
|
AvHParticleSystemManager::InternalCreateParticleSystem(const QueuedParticleSystem& inParticleSystem)
|
|
{
|
|
bool theSuccess = false;
|
|
|
|
// add new particle system to list
|
|
AvHParticleTemplate* theTemplate = ::gParticleTemplateList.GetTemplateAtIndex(inParticleSystem.mTemplateIndex);
|
|
if(theTemplate)
|
|
{
|
|
AvHParticleSystem theNewParticleSystem(theTemplate, inParticleSystem.mTemplateIndex);
|
|
|
|
// set it's template handle
|
|
int theHandle = inParticleSystem.mHandle;
|
|
if(theHandle)
|
|
{
|
|
theNewParticleSystem.SetHandle(theHandle);
|
|
}
|
|
else
|
|
{
|
|
// TODO: Check to be sure it has a lifetime, because it won't be able to be deleted
|
|
}
|
|
|
|
// Bind it to an entity if it was specified
|
|
//if(inParticleSystem.mEntity)
|
|
//{
|
|
// theNewParticleSystem.SetEntity(inParticleSystem.mEntity);
|
|
//}
|
|
|
|
theNewParticleSystem.SetPosition(inParticleSystem.mOrigin);
|
|
|
|
// Set time created
|
|
theNewParticleSystem.SetTimeCreated(this->GetTime());
|
|
|
|
// Set normal if specified
|
|
if(inParticleSystem.mHasNormal)
|
|
{
|
|
theNewParticleSystem.SetNormal(inParticleSystem.mNormal);
|
|
}
|
|
|
|
this->mParticleSystemList.push_back(theNewParticleSystem);
|
|
|
|
#ifdef AVH_CLIENT
|
|
//int theGenerationEntityIndex;
|
|
//if(theNewParticleSystem.GetGenerationEntity(theGenerationEntityIndex))
|
|
//{
|
|
// gCubeDebugEntities.push_back(theGenerationEntityIndex);
|
|
//}
|
|
//else
|
|
//{
|
|
int theParentEntityIndex = inParticleSystem.GetParentEntityIndex();
|
|
if(theParentEntityIndex > 0)
|
|
{
|
|
gCubeDebugEntities.push_back(theParentEntityIndex);
|
|
}
|
|
//}
|
|
#endif
|
|
|
|
theSuccess = true;
|
|
}
|
|
|
|
return theSuccess;
|
|
}
|
|
|
|
void
|
|
AvHParticleSystemManager::ProcessQueuedList()
|
|
{
|
|
// Process pending creates
|
|
for(QueuedCreateList::iterator theCreateIter = this->mQueuedCreateList.begin(); theCreateIter != this->mQueuedCreateList.end(); /* no increment */)
|
|
{
|
|
// Run through the list, creating each queued particle system. If a system couldn't be created, we probably
|
|
// don't have that particle template yet, so just skip it for now and try to create it next frame.
|
|
|
|
// Add code that detects how long a queued particle system has been in?
|
|
const float kTimeOut = 20.0f;
|
|
float theCurrentTime = this->GetTime();
|
|
|
|
bool theCreateTimedOut = theCurrentTime - theCreateIter->mTimeQueued > kTimeOut;
|
|
if(theCreateTimedOut)
|
|
{
|
|
//ASSERT(!theCreateTimedOut);
|
|
theCreateIter = this->mQueuedCreateList.erase(theCreateIter);
|
|
}
|
|
else
|
|
{
|
|
bool theCreated = this->InternalCreateParticleSystem(*theCreateIter);
|
|
if(theCreated)
|
|
{
|
|
theCreateIter = this->mQueuedCreateList.erase(theCreateIter);
|
|
}
|
|
else
|
|
{
|
|
theCreateIter++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Process pending destroys
|
|
for(QueuedDestroyList::iterator theDestroyIter = this->mQueuedDestroyList.begin(); theDestroyIter != this->mQueuedDestroyList.end(); /* no increment */)
|
|
{
|
|
ParticleSystemHandle theHandle = *theDestroyIter;
|
|
|
|
// Try to delete it. If it hasn't been created yet, keep the pending destruction around
|
|
bool theDestroyed = this->InternalDestroyParticleSystem(theHandle);
|
|
if(theDestroyed)
|
|
{
|
|
theDestroyIter = this->mQueuedDestroyList.erase(theDestroyIter);
|
|
}
|
|
else
|
|
{
|
|
theDestroyIter++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
AvHParticleSystemManager::QueueParticleSystem(const QueuedParticleSystem& inParticleSystem)
|
|
{
|
|
this->mQueuedCreateList.push_back(inParticleSystem);
|
|
}
|
|
|
|
void
|
|
AvHParticleSystemManager::ReloadFromTemplates()
|
|
{
|
|
this->mReloadFromTemplates = true;
|
|
}
|
|
|
|
void
|
|
AvHParticleSystemManager::Reset()
|
|
{
|
|
// Clear out alive particle systems
|
|
for(ParticleSystemList::iterator theIterator = this->mParticleSystemList.begin(); theIterator != this->mParticleSystemList.end(); theIterator++)
|
|
{
|
|
theIterator->Kill();
|
|
}
|
|
this->mParticleSystemList.clear();
|
|
|
|
// Clear out queued particle systems
|
|
this->mQueuedCreateList.clear();
|
|
this->mQueuedDestroyList.clear();
|
|
|
|
// Clear entities we're tracking
|
|
this->mParticleEntities.clear();
|
|
|
|
// Init list again so it's just like we just built a new one
|
|
this->Init();
|
|
}
|
|
|
|
bool AvHParticleSystemManager::SetParticleSystemCustomData(uint16 inCustomData, ParticleSystemHandle inHandle)
|
|
{
|
|
bool theSuccess = false;
|
|
|
|
for(ParticleSystemList::iterator theIterator = this->mParticleSystemList.begin(); theIterator != this->mParticleSystemList.end(); theIterator++)
|
|
{
|
|
if(theIterator->GetHandle() == inHandle)
|
|
{
|
|
theIterator->SetCustomData(inCustomData);
|
|
theSuccess = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return theSuccess;
|
|
}
|
|
|
|
void
|
|
AvHParticleSystemManager::MarkParticleSystemForDeletion(int inIndex, ParticleSystemHandle inHandle)
|
|
{
|
|
for(ParticleEntityList::iterator theIter = this->mParticleEntities.begin(); theIter != this->mParticleEntities.end(); theIter++)
|
|
{
|
|
if(*theIter == inIndex)
|
|
{
|
|
// Remove it from the list
|
|
theIter = this->mParticleEntities.erase(theIter);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Mark it for deletion
|
|
for(ParticleSystemList::iterator theIterator = this->mParticleSystemList.begin(); theIterator != this->mParticleSystemList.end(); theIterator++)
|
|
{
|
|
if(theIterator->GetHandle() == inHandle)
|
|
{
|
|
theIterator->SetIsMarkedForDeletion();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef AVH_CLIENT
|
|
int AvHParticleSystemManager::GetNumVisibleParticleSystems() const
|
|
{
|
|
int theNumVisible = 0;
|
|
|
|
for(ParticleSystemList::const_iterator theIterator = this->mParticleSystemList.begin(); theIterator != this->mParticleSystemList.end(); theIterator++)
|
|
{
|
|
if(theIterator->GetIsVisible())
|
|
{
|
|
theNumVisible++;
|
|
}
|
|
}
|
|
|
|
return theNumVisible;
|
|
}
|
|
|
|
void
|
|
AvHParticleSystemManager::SetParticleSystemGenerationEntityExtents(vec3_t& inMin, vec3_t& inMax, ParticleSystemHandle inHandle)
|
|
{
|
|
for(ParticleSystemList::iterator theIterator = this->mParticleSystemList.begin(); theIterator != this->mParticleSystemList.end(); theIterator++)
|
|
{
|
|
if(theIterator->GetHandle() == inHandle)
|
|
{
|
|
theIterator->SetGenerationEntityExtents(inMin, inMax);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
AvHParticleSystemManager::SetParticleSystemPosition(vec3_t& inPos, ParticleSystemHandle inHandle)
|
|
{
|
|
for(ParticleSystemList::iterator theIterator = this->mParticleSystemList.begin(); theIterator != this->mParticleSystemList.end(); theIterator++)
|
|
{
|
|
if(theIterator->GetHandle() == inHandle)
|
|
{
|
|
theIterator->SetPosition(inPos);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
AvHParticleSystemManager::SetParticleSystemVisibility(bool inVisibility, ParticleSystemHandle inHandle)
|
|
{
|
|
for(ParticleSystemList::iterator theIterator = this->mParticleSystemList.begin(); theIterator != this->mParticleSystemList.end(); theIterator++)
|
|
{
|
|
if(theIterator->GetHandle() == inHandle)
|
|
{
|
|
theIterator->SetIsVisible(inVisibility, this->GetTime());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void
|
|
AvHParticleSystemManager::Start()
|
|
{
|
|
if(!this->mStarted)
|
|
{
|
|
this->mStarted = true;
|
|
this->mUpdatedTime = this->mTimePassed = 0.0f;
|
|
}
|
|
}
|
|
|
|
void
|
|
AvHParticleSystemManager::Update(double inTime)
|
|
{
|
|
if(this->mStarted)
|
|
{
|
|
this->ProcessQueuedList();
|
|
|
|
ASSERT(inTime >= 0.0f);
|
|
|
|
this->mTimePassed += (float)inTime;
|
|
if(this->mTimePassed - this->mUpdatedTime > kUpdateIncrement)
|
|
{
|
|
float theTimeToUpdate = this->mTimePassed - this->mUpdatedTime;
|
|
|
|
// Run through list, updating each one
|
|
ParticleSystemList::iterator theIterator;
|
|
for(theIterator = this->mParticleSystemList.begin(); theIterator != this->mParticleSystemList.end(); /* notice: no increment */ )
|
|
{
|
|
if(this->mReloadFromTemplates)
|
|
{
|
|
AvHParticleTemplate* theTemplate = gParticleTemplateList.GetTemplateAtIndex(theIterator->GetTemplateIndex());
|
|
ASSERT(theTemplate);
|
|
theIterator->LoadFromTemplate(theTemplate);
|
|
}
|
|
|
|
// Always update particle systems
|
|
theIterator->Update(theTimeToUpdate);
|
|
|
|
// If the particle system has lived long enough, mark it for deletion
|
|
float theCurrentTime = this->GetTime();
|
|
float theParticleSystemLifetime = theIterator->GetParticleSystemLifetime();
|
|
if(!theIterator->GetIsMarkedForDeletion())
|
|
{
|
|
if((theParticleSystemLifetime != -1) && theIterator->GetHasGeneratedParticles())
|
|
{
|
|
if(theCurrentTime > (theIterator->GetTimeCreated() + theParticleSystemLifetime))
|
|
{
|
|
theIterator->SetIsMarkedForDeletion();
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef AVH_CLIENT
|
|
// Expire visibility of particle systems. The server sends down particle entities as they're updated, but we need
|
|
// a way to expire them.
|
|
if(theIterator->GetIsVisible())
|
|
{
|
|
const float kExpireTime = 6.0f;
|
|
if((theIterator->GetLastTimeVisibilityLastSetTrue() == -1) || (this->mTimePassed > (theIterator->GetLastTimeVisibilityLastSetTrue() + kExpireTime)))
|
|
{
|
|
theIterator->SetIsVisible(false, inTime);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// If a particle system is marked for deletion and it has no more particles, delete it
|
|
if(theIterator->GetIsMarkedForDeletion() && (theIterator->GetNumberOfParticles() == 0) )
|
|
{
|
|
theIterator->Kill();
|
|
theIterator = this->mParticleSystemList.erase(theIterator);
|
|
}
|
|
else
|
|
{
|
|
theIterator++;
|
|
}
|
|
}
|
|
|
|
this->mUpdatedTime = this->mTimePassed;
|
|
}
|
|
}
|
|
this->mReloadFromTemplates = false;
|
|
} |