Files
tech5/source/engine/gamelib/effects/effectsmodelmanager.cpp
T

155 lines
5.0 KiB
C++

#include "gamelib/effects/effectsmodelmanager.h"
#include "idlib/lib_print.h"
#include "idlib/text/str.h"
// Renderer/decl access remains behind explicit PC-port boundaries until the
// renderer and decl translation units join the production source target.
const char* GameLib_GetParticleDeclName(const idDeclParticle* particleDecl);
idRenderModelParticle* GameLib_AllocParticleRenderModel(
const char* modelName, const idDeclParticle* particleDecl);
void GameLib_RetireParticleRenderModel(idRenderModelParticle* model);
bool GameLib_ShowEffectsModelRecyclerStats();
namespace {
int ParticleNameHash(const char* const name) {
int hash = 0;
if (name != nullptr) {
for (const unsigned char* cursor =
reinterpret_cast<const unsigned char*>(name);
*cursor != 0; ++cursor) {
hash = 31 * hash + *cursor;
}
}
return hash;
}
void PrintRecyclerStats(const char* const action, const char* const name,
const idEffectsModelManager& manager) {
if (!GameLib_ShowEffectsModelRecyclerStats()) {
return;
}
idLibPrint::Printf(
"%s model %s, total models allocated %d inactive models spread %d "
"active models spread %d\n",
action, name, manager.fxPrtModels.Num(),
manager.inactivePrtModelHash.GetSpread(),
manager.activePrtModelHash.GetSpread());
}
} // namespace
idEffectsModelManager::idEffectsModelManager()
: fxPrtModels()
, activePrtModelHash(1024, 1024, TAG_HASHINDEX)
, inactivePrtModelHash(1024, 1024, TAG_HASHINDEX) {
}
idEffectsModelManager::~idEffectsModelManager() {
Shutdown();
}
void idEffectsModelManager::Init() {
fxPrtModels.Clear();
activePrtModelHash.Clear();
activePrtModelHash.memTag = TAG_PARTICLE;
inactivePrtModelHash.Clear();
inactivePrtModelHash.memTag = TAG_PARTICLE;
}
void idEffectsModelManager::Shutdown() {
activePrtModelHash.Clear();
inactivePrtModelHash.Clear();
for (int index = 0; index < fxPrtModels.Num(); ++index) {
fxPrtModel_t& item = fxPrtModels[index];
if (item.pmodel != nullptr) {
GameLib_RetireParticleRenderModel(item.pmodel);
item.pmodel = nullptr;
}
}
fxPrtModels.Clear();
}
void idEffectsModelManager::RecycleParticleFxModel(
const idDeclParticle* const particleDecl,
idRenderModelParticle* const model) {
if (model == nullptr || particleDecl == nullptr) {
idLibPrint::Warning(
"idFXModelRecycler::RecycleEffectModel : invalid model");
return;
}
const char* const name = GameLib_GetParticleDeclName(particleDecl);
const int key = ParticleNameHash(name);
int index = activePrtModelHash.First(key);
while (index != -1) {
const fxPrtModel_t& item = fxPrtModels[index];
if (item.pDecl == particleDecl && item.pmodel == model) {
break;
}
index = activePrtModelHash.Next(index);
}
if (index == -1) {
if (GameLib_ShowEffectsModelRecyclerStats()) {
idLibPrint::Printf(
"idEffectsModelManager::RecycleParticleFxModel : model %s "
"not found in active list for recycling\n", name);
}
return;
}
activePrtModelHash.Remove(key, index);
inactivePrtModelHash.Add(key, index);
PrintRecyclerStats("Recycling", name, *this);
}
idRenderModelParticle* idEffectsModelManager::GetNextParticleEffectModel(
const idDeclParticle* const particleDecl) {
if (particleDecl == nullptr) {
idLibPrint::Warning(
"idEffectsModelManager::GetNextParticleEffectModel : "
"particleDecl NULL");
return nullptr;
}
const char* const name = GameLib_GetParticleDeclName(particleDecl);
const int key = ParticleNameHash(name);
int index = inactivePrtModelHash.First(key);
while (index != -1) {
const fxPrtModel_t& item = fxPrtModels[index];
if (item.pDecl == particleDecl && item.pmodel != nullptr) {
inactivePrtModelHash.Remove(key, index);
activePrtModelHash.Add(key, index);
PrintRecyclerStats("Found inactive", name, *this);
return item.pmodel;
}
index = inactivePrtModelHash.Next(index);
}
if (fxPrtModels.Num() >= fxPrtModels.Max()) {
idLibPrint::Warning(
"idFXModelRecycler::GetParticleFxModel: Could not allocate "
"model %s, out of slots", name);
return nullptr;
}
idStr modelName(name);
modelName.SetFileExtension("prt");
idRenderModelParticle* const model = GameLib_AllocParticleRenderModel(
modelName.c_str(), particleDecl);
if (model == nullptr) {
idLibPrint::Warning(
"idFXModelRecycler::GetParticleFxModel: Could not allocate a "
"rendermodel for '%s'", name);
return nullptr;
}
const fxPrtModel_t item = {model, particleDecl};
index = fxPrtModels.Append(item);
activePrtModelHash.Add(key, index);
PrintRecyclerStats("Allocated new", name, *this);
return model;
}