diff --git a/model/AnimModel.cpp b/model/AnimModel.cpp index 7cdbc3d7..52917a66 100644 --- a/model/AnimModel.cpp +++ b/model/AnimModel.cpp @@ -257,7 +257,20 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable asText = asReplacableTexture.substr( 1, asReplacableTexture.length() - 1 ); // zapamiętanie tekstu } else if( asReplacableTexture != "none" ) { - m_materialdata.assign( asReplacableTexture ); + // the same skin is typically shared by lots of instances, and locating its files takes a couple dozen disk lookups. + // NOTE: only located skins are kept, so a missing one is still searched for each time, the way it used to be + static std::unordered_map skins; + auto const skinkey { Global.asCurrentTexturePath + '|' + asReplacableTexture }; + auto const lookup { skins.find( skinkey ) }; + if( lookup != skins.end() ) { + m_materialdata = lookup->second; + } + else { + m_materialdata.assign( asReplacableTexture ); + if( m_materialdata.replacable_skins[ 1 ] != null_handle ) { + skins.emplace( skinkey, m_materialdata ); + } + } } // TODO: redo the random timer initialization @@ -304,26 +317,14 @@ bool TAnimModel::Load(cParser *parser, bool ter) } else { // wiązanie świateł, o ile model wczytany - LightsOn[0] = pModel->GetFromName("Light_On00"); - LightsOn[1] = pModel->GetFromName("Light_On01"); - LightsOn[2] = pModel->GetFromName("Light_On02"); - LightsOn[3] = pModel->GetFromName("Light_On03"); - LightsOn[4] = pModel->GetFromName("Light_On04"); - LightsOn[5] = pModel->GetFromName("Light_On05"); - LightsOn[6] = pModel->GetFromName("Light_On06"); - LightsOn[7] = pModel->GetFromName("Light_On07"); - LightsOff[0] = pModel->GetFromName("Light_Off00"); - LightsOff[1] = pModel->GetFromName("Light_Off01"); - LightsOff[2] = pModel->GetFromName("Light_Off02"); - LightsOff[3] = pModel->GetFromName("Light_Off03"); - LightsOff[4] = pModel->GetFromName("Light_Off04"); - LightsOff[5] = pModel->GetFromName("Light_Off05"); - LightsOff[6] = pModel->GetFromName("Light_Off06"); - LightsOff[7] = pModel->GetFromName("Light_Off07"); - sm_winter_variant = pModel->GetFromName("winter_variant"); - sm_spring_variant = pModel->GetFromName("spring_variant"); - sm_summer_variant = pModel->GetFromName("summer_variant"); - sm_autumn_variant = pModel->GetFromName("autumn_variant"); + // the submodels are located once for the model and shared by its instances + auto const &submodels { pModel->instance_parts() }; + LightsOn = submodels.lights_on; + LightsOff = submodels.lights_off; + sm_winter_variant = submodels.variants[ 0 ]; + sm_spring_variant = submodels.variants[ 1 ]; + sm_summer_variant = submodels.variants[ 2 ]; + sm_autumn_variant = submodels.variants[ 3 ]; } for (int i = 0; i < iMaxNumLights; ++i) if (LightsOn[i] || LightsOff[i]) // Ra: zlikwidowałem wymóg istnienia obu diff --git a/model/Model3d.cpp b/model/Model3d.cpp index fba07446..cb9c0793 100644 --- a/model/Model3d.cpp +++ b/model/Model3d.cpp @@ -1567,6 +1567,23 @@ TSubModel *TModel3d::GetFromName(std::string const &Name) const } }; +// returns submodels which scenery instances of the model refer to by name, locating them on first use +TModel3d::instance_submodels const &TModel3d::instance_parts() +{ + if (false == m_instancesubmodelslocated) + { + for (std::size_t idx = 0; idx < m_instancesubmodels.lights_on.size(); ++idx) + { + auto const index{(idx < 10 ? "0" : "") + std::to_string(idx)}; + m_instancesubmodels.lights_on[idx] = GetFromName("Light_On" + index); + m_instancesubmodels.lights_off[idx] = GetFromName("Light_Off" + index); + } + m_instancesubmodels.variants = {GetFromName("winter_variant"), GetFromName("spring_variant"), GetFromName("summer_variant"), GetFromName("autumn_variant")}; + m_instancesubmodelslocated = true; + } + return m_instancesubmodels; +} + // locates particle source submodels and stores them on internal list nameoffset_sequence const &TModel3d::find_smoke_sources() { diff --git a/model/Model3d.h b/model/Model3d.h index 0e053609..c8c2fc9a 100644 --- a/model/Model3d.h +++ b/model/Model3d.h @@ -267,6 +267,12 @@ class TModel3d friend opengl33_renderer; public: + // submodels which scenery instances of the model refer to by name + struct instance_submodels { + std::array lights_on {}; // Light_On00 - Light_On07 + std::array lights_off {}; // Light_Off00 - Light_Off07 + std::array variants {}; // winter_variant, spring_variant, summer_variant, autumn_variant + }; TSubModel *Root { nullptr }; // drzewo submodeli uint32_t iFlags { 0 }; // Ra: czy submodele mają przezroczyste tekstury public: // Ra: tymczasowo @@ -281,6 +287,8 @@ private: std::string asBinary; // nazwa pod którą zapisać model binarny std::string m_filename; nameoffset_sequence m_smokesources; // list of particle sources defined in the model + instance_submodels m_instancesubmodels; // filled on first use, see instance_parts() + bool m_instancesubmodelslocated { false }; public: TModel3d() = default; @@ -289,6 +297,9 @@ public: return Root ? Root->m_boundingradius : 0.f; } inline TSubModel * GetSMRoot() { return Root; }; TSubModel * GetFromName(std::string const &Name) const; + // returns submodels which scenery instances of the model refer to by name. the search for a name goes through the whole + // submodel tree, so it's done once for the model instead of once for each of its instances + instance_submodels const & instance_parts(); TSubModel * AddToNamed(const char *Name, TSubModel *SubModel); nameoffset_sequence const & find_smoke_sources(); void AddTo(TSubModel *tmp, TSubModel *SubModel);