diff --git a/rts/Lua/LuaSyncedCtrl.cpp b/rts/Lua/LuaSyncedCtrl.cpp index 2ff55114291..361d0dc8d6b 100644 --- a/rts/Lua/LuaSyncedCtrl.cpp +++ b/rts/Lua/LuaSyncedCtrl.cpp @@ -441,7 +441,7 @@ static bool ParseProjectileParams(lua_State* L, ProjectileParams& params, const if (lua_isstring(L, -1)) { if (key == "model") { - params.model = modelParser->Load3DModel(lua_tostring(L, -1)); + params.model = modelLoader.LoadModel(lua_tostring(L, -1)); } else if (key == "cegtag") { params.cegID = explGenHandler->LoadGeneratorID(lua_tostring(L, -1)); } diff --git a/rts/Lua/LuaUtils.cpp b/rts/Lua/LuaUtils.cpp index 1fef06eeecb..5fe895fc554 100644 --- a/rts/Lua/LuaUtils.cpp +++ b/rts/Lua/LuaUtils.cpp @@ -744,14 +744,14 @@ int LuaUtils::PushFeatureModelDrawType(lua_State* L, const FeatureDef* def) int LuaUtils::PushModelName(lua_State* L, const SolidObjectDef* def) { // redundant with model.path - // lua_pushsstring(L, modelParser->FindModelPath(def->modelName)); + // lua_pushsstring(L, modelLoader.FindModelPath(def->modelName)); lua_pushsstring(L, "deprecated! use def.model.path instead!"); return 1; } int LuaUtils::PushModelTable(lua_State* L, const SolidObjectDef* def) { - const std::string& modelPath = modelParser->FindModelPath(def->modelName); + const std::string& modelPath = modelLoader.FindModelPath(def->modelName); const std::string& modelType = StringToLower(FileSystem::GetExtension(modelPath)); const S3DModel* model = def->LoadModel(); diff --git a/rts/Lua/LuaWeaponDefs.cpp b/rts/Lua/LuaWeaponDefs.cpp index 40845a01f82..cd9131ed52a 100644 --- a/rts/Lua/LuaWeaponDefs.cpp +++ b/rts/Lua/LuaWeaponDefs.cpp @@ -267,7 +267,7 @@ static int VisualsTable(lua_State* L, const void* data) { const struct WeaponDef::Visuals& v = *static_cast(data); lua_newtable(L); - HSTR_PUSH_STRING(L, "modelName", modelParser->FindModelPath(v.modelName)); + HSTR_PUSH_STRING(L, "modelName", modelLoader.FindModelPath(v.modelName)); HSTR_PUSH_NUMBER(L, "colorR", v.color.x); HSTR_PUSH_NUMBER(L, "colorG", v.color.y); HSTR_PUSH_NUMBER(L, "colorB", v.color.z); diff --git a/rts/Rendering/Models/IModelParser.cpp b/rts/Rendering/Models/IModelParser.cpp index da99d8b3d6a..54b7f2fb385 100644 --- a/rts/Rendering/Models/IModelParser.cpp +++ b/rts/Rendering/Models/IModelParser.cpp @@ -22,10 +22,8 @@ #include "System/maindefines.h" #include "lib/assimp/include/assimp/Importer.hpp" -C3DModelLoader* modelParser = nullptr; - -static void RegisterAssimpModelFormats(C3DModelLoader::FormatMap& formats) { +static void RegisterAssimpModelFormats(CModelLoader::FormatMap& formats) { std::set whitelist; std::string extension; std::string extensions; @@ -113,11 +111,6 @@ void LoadQueue::Join() } } -LoadQueue::~LoadQueue() -{ - Join(); -} - __FORCE_ALIGN_STACK__ void LoadQueue::Pump() { @@ -131,7 +124,7 @@ void LoadQueue::Pump() FreeLock(); } - modelParser->Load3DModel(modelName, true); + modelLoader.LoadModel(modelName, true); { GrabLock(); @@ -169,7 +162,7 @@ void LoadQueue::Push(const std::string& modelName) } -C3DModelLoader::C3DModelLoader() +void CModelLoader::Init() { // file-extension should be lowercase formats["3do"] = MODELTYPE_3DO; @@ -189,12 +182,20 @@ C3DModelLoader::C3DModelLoader() models.push_back(nullptr); } - -C3DModelLoader::~C3DModelLoader() +void CModelLoader::Kill() { + // thread might be in LoadModel, but it doesn't matter loadQueue.Join(); - // delete model cache + KillModels(); + KillParsers(); + + cache.clear(); + formats.clear(); +} + +void CModelLoader::KillModels() +{ for (unsigned int n = 1; n < models.size(); n++) { S3DModel* model = models[n]; @@ -204,22 +205,30 @@ C3DModelLoader::~C3DModelLoader() model->DeletePieces(model->GetRootPiece()); model->SetRootPiece(nullptr); - delete model; + SafeDelete(model); } + models.clear(); +} +void CModelLoader::KillParsers() +{ for (auto it = parsers.cbegin(); it != parsers.cend(); ++it) { delete (it->second); } - parsers.clear(); - cache.clear(); + parsers.clear(); +} +CModelLoader& CModelLoader::GetInstance() +{ + static CModelLoader instance; + return instance; } -std::string C3DModelLoader::FindModelPath(std::string name) const +std::string CModelLoader::FindModelPath(std::string name) const { // check for empty string because we can be called // from Lua*Defs and certain features have no models @@ -249,7 +258,7 @@ std::string C3DModelLoader::FindModelPath(std::string name) const -S3DModel* C3DModelLoader::Load3DModel(std::string name, bool preload) +S3DModel* CModelLoader::LoadModel(std::string name, bool preload) { // cannot happen except through SpawnProjectile if (name.empty()) @@ -262,7 +271,7 @@ S3DModel* C3DModelLoader::Load3DModel(std::string name, bool preload) // search in cache first for (unsigned int n = 0; n < 2; n++) { - S3DModel* cachedModel = LoadCached3DModel(*refs[n], preload); + S3DModel* cachedModel = LoadCachedModel(*refs[n], preload); if (cachedModel != nullptr) return cachedModel; @@ -275,7 +284,7 @@ S3DModel* C3DModelLoader::Load3DModel(std::string name, bool preload) return (CreateModel(name, path, preload)); } -S3DModel* C3DModelLoader::LoadCached3DModel(const std::string& name, bool preload) +S3DModel* CModelLoader::LoadCachedModel(const std::string& name, bool preload) { S3DModel* cachedModel = nullptr; @@ -300,7 +309,7 @@ S3DModel* C3DModelLoader::LoadCached3DModel(const std::string& name, bool preloa -S3DModel* C3DModelLoader::CreateModel( +S3DModel* CModelLoader::CreateModel( const std::string& name, const std::string& path, bool preload @@ -321,7 +330,7 @@ S3DModel* C3DModelLoader::CreateModel( -IModelParser* C3DModelLoader::GetFormatParser(const std::string& pathExt) +IModelParser* CModelLoader::GetFormatParser(const std::string& pathExt) { const auto fi = formats.find(StringToLower(pathExt)); @@ -331,7 +340,7 @@ IModelParser* C3DModelLoader::GetFormatParser(const std::string& pathExt) return parsers[fi->second]; } -S3DModel* C3DModelLoader::ParseModel(const std::string& name, const std::string& path) +S3DModel* CModelLoader::ParseModel(const std::string& name, const std::string& path) { S3DModel* model = nullptr; IModelParser* parser = GetFormatParser(FileSystem::GetExtension(path)); @@ -351,7 +360,7 @@ S3DModel* C3DModelLoader::ParseModel(const std::string& name, const std::string& -void C3DModelLoader::AddModelToCache( +void CModelLoader::AddModelToCache( S3DModel* model, const std::string& name, const std::string& path @@ -373,7 +382,7 @@ void C3DModelLoader::AddModelToCache( -void C3DModelLoader::CreateListsNow(S3DModelPiece* o) +void CModelLoader::CreateListsNow(S3DModelPiece* o) { o->UploadGeometryVBOs(); o->CreateShatterPieces(); @@ -385,7 +394,7 @@ void C3DModelLoader::CreateListsNow(S3DModelPiece* o) } -void C3DModelLoader::CreateLists(S3DModel* model) { +void CModelLoader::CreateLists(S3DModel* model) { S3DModelPiece* rootPiece = model->GetRootPiece(); if (rootPiece->GetDisplayListID() != 0) diff --git a/rts/Rendering/Models/IModelParser.h b/rts/Rendering/Models/IModelParser.h index 49512d679aa..ad5a6de9d2b 100644 --- a/rts/Rendering/Models/IModelParser.h +++ b/rts/Rendering/Models/IModelParser.h @@ -28,7 +28,7 @@ class IModelParser struct LoadQueue { public: LoadQueue(): thread(nullptr) {} - ~LoadQueue(); + ~LoadQueue() { Join(); } void Pump(); void Push(const std::string& modelName); @@ -45,17 +45,20 @@ struct LoadQueue { -class C3DModelLoader +class CModelLoader { public: - C3DModelLoader(); - ~C3DModelLoader(); + static CModelLoader& GetInstance(); - S3DModel* Load3DModel(std::string name, bool preload = false); + void Init(); + void Kill(); + + S3DModel* LoadModel(std::string name, bool preload = false); std::string FindModelPath(std::string name) const; - void Preload3DModel(const std::string& name) { loadQueue.Push(name); } + bool IsValid() const { return (!formats.empty()); } + void PreloadModel(const std::string& name) { assert(IsValid()); loadQueue.Push(name); } public: typedef std::unordered_map ModelMap; // "armflash.3do" --> id @@ -63,12 +66,15 @@ class C3DModelLoader typedef std::unordered_map ParserMap; // MODELTYPE_3DO --> parser private: - S3DModel* LoadCached3DModel(const std::string& name, bool preload); + S3DModel* LoadCachedModel(const std::string& name, bool preload); S3DModel* CreateModel(const std::string& name, const std::string& path, bool preload); S3DModel* ParseModel(const std::string& name, const std::string& path); IModelParser* GetFormatParser(const std::string& pathExt); + void KillModels(); + void KillParsers(); + void AddModelToCache(S3DModel* model, const std::string& name, const std::string& path); void CreateLists(S3DModel* o); @@ -85,6 +91,6 @@ class C3DModelLoader std::vector models; }; -extern C3DModelLoader* modelParser; +#define modelLoader (CModelLoader::GetInstance()) #endif /* IMODELPARSER_H */ diff --git a/rts/Rendering/WorldDrawer.cpp b/rts/Rendering/WorldDrawer.cpp index c11be790287..2cd130883fe 100644 --- a/rts/Rendering/WorldDrawer.cpp +++ b/rts/Rendering/WorldDrawer.cpp @@ -60,7 +60,8 @@ CWorldDrawer::~CWorldDrawer() SafeDelete(featureDrawer); SafeDelete(unitDrawer); // depends on unitHandler, cubeMapHandler SafeDelete(projectileDrawer); - SafeDelete(modelParser); + + modelLoader.Kill(); SafeDelete(farTextureHandler); SafeDelete(heightMapTexture); @@ -82,7 +83,7 @@ void CWorldDrawer::LoadPre() const { // these need to be loaded before featureHandler is created // (maps with features have their models loaded at startup) - modelParser = new C3DModelLoader(); + modelLoader.Init(); loadscreen->SetLoadMessage("Creating Unit Textures"); texturehandler3DO = new C3DOTextureHandler(); diff --git a/rts/Sim/Objects/SolidObjectDef.cpp b/rts/Sim/Objects/SolidObjectDef.cpp index 312955fa4d1..f5b3b5cc722 100644 --- a/rts/Sim/Objects/SolidObjectDef.cpp +++ b/rts/Sim/Objects/SolidObjectDef.cpp @@ -64,7 +64,7 @@ SolidObjectDef::SolidObjectDef() void SolidObjectDef::PreloadModel() const { if (model == nullptr && !modelName.empty()) { - modelParser->Preload3DModel(modelName); + modelLoader.PreloadModel(modelName); } } @@ -72,7 +72,7 @@ S3DModel* SolidObjectDef::LoadModel() const { if (model == nullptr) { if (!modelName.empty()) { - model = modelParser->Load3DModel(modelName); + model = modelLoader.LoadModel(modelName); } else { // not useful, too much spam // LOG_L(L_WARNING, "[SolidObjectDef::%s] object \"%s\" has no model defined", __FUNCTION__, name.c_str()); diff --git a/rts/Sim/Weapons/WeaponDef.cpp b/rts/Sim/Weapons/WeaponDef.cpp index 5d30be06ab4..7a8c4c73e8e 100644 --- a/rts/Sim/Weapons/WeaponDef.cpp +++ b/rts/Sim/Weapons/WeaponDef.cpp @@ -589,7 +589,7 @@ S3DModel* WeaponDef::LoadModel() { if (visuals.model == NULL) { if (!visuals.modelName.empty()) { - visuals.model = modelParser->Load3DModel(visuals.modelName); + visuals.model = modelLoader.LoadModel(visuals.modelName); } else { // not useful, too much spam // LOG_L(L_WARNING, "[WeaponDef::%s] weapon \"%s\" has no model defined", __FUNCTION__, name.c_str());