@@ -112,50 +112,49 @@ namespace
112112// //////////////////////////////////////////////////////////////
113113CModelTexturesInfo* CRenderWareSA::GetModelTexturesInfo (ushort usModelId)
114114{
115- CModelInfoSA * pModelInfo = dynamic_cast <CModelInfoSA*>(pGame->GetModelInfo (usModelId));
115+ auto * pModelInfo = dynamic_cast <CModelInfoSA*>(pGame->GetModelInfo (usModelId));
116116 if (!pModelInfo)
117- return NULL ;
117+ return nullptr ;
118118
119- ushort usTxdId = pModelInfo->GetTextureDictionaryID ();
119+ const ushort usTxdId = pModelInfo->GetTextureDictionaryID ();
120120
121- CModelTexturesInfo* pInfo = MapFind (ms_ModelTexturesInfoMap, usTxdId);
122- if (!pInfo)
123- {
124- // Get txd
125- RwTexDictionary* pTxd = CTxdStore_GetTxd (usTxdId);
121+ if (auto it = ms_ModelTexturesInfoMap.find (usTxdId); it != ms_ModelTexturesInfoMap.end ())
122+ return &it->second ;
126123
127- if (!pTxd)
124+ // Get txd
125+ RwTexDictionary* pTxd = CTxdStore_GetTxd (usTxdId);
126+
127+ if (!pTxd)
128+ {
129+ pModelInfo->Request (BLOCKING, " CRenderWareSA::GetModelTexturesInfo" );
130+ CTxdStore_AddRef (usTxdId);
131+ ((void (__cdecl*)(unsigned short ))FUNC_RemoveModel)(usModelId);
132+ pTxd = CTxdStore_GetTxd (usTxdId);
133+ }
134+ else
135+ {
136+ CTxdStore_AddRef (usTxdId);
137+ if (pModelInfo->GetModelType () == eModelInfoType::PED)
128138 {
129- pModelInfo-> Request (BLOCKING, " CRenderWareSA::GetModelTexturesInfo " );
130- CTxdStore_AddRef (usTxdId);
139+ // Mystery fix for #9336: (MTA sometimes fails at loading custom textures)
140+ // Possibly forces the ped model to be reloaded in some way
131141 ((void (__cdecl*)(unsigned short ))FUNC_RemoveModel)(usModelId);
132- pTxd = CTxdStore_GetTxd (usTxdId);
133142 }
134- else
135- {
136- CTxdStore_AddRef (usTxdId);
137- if (pModelInfo->GetModelType () == eModelInfoType::PED)
138- {
139- // Mystery fix for #9336: (MTA sometimes fails at loading custom textures)
140- // Possibly forces the ped model to be reloaded in some way
141- ((void (__cdecl*)(unsigned short ))FUNC_RemoveModel)(usModelId);
142- }
143- }
144-
145- if (!pTxd)
146- return NULL ;
143+ }
147144
148- // Add new info
149- MapSet (ms_ModelTexturesInfoMap, usTxdId, CModelTexturesInfo ());
150- pInfo = MapFind (ms_ModelTexturesInfoMap, usTxdId);
151- pInfo->usTxdId = usTxdId;
152- pInfo->pTxd = pTxd;
145+ if (!pTxd)
146+ return nullptr ;
153147
154- // Save original textures
155- GetTxdTextures (pInfo->originalTextures , pInfo->pTxd );
156- }
148+ // Add new info
149+ auto [it, inserted] = ms_ModelTexturesInfoMap.emplace (usTxdId, CModelTexturesInfo{});
150+ auto & newInfo = it->second ;
151+ newInfo.usTxdId = usTxdId;
152+ newInfo.pTxd = pTxd;
157153
158- return pInfo;
154+ // Save original textures
155+ GetTxdTextures (newInfo.originalTextures , newInfo.pTxd );
156+
157+ return &newInfo;
159158}
160159
161160// //////////////////////////////////////////////////////////////
@@ -173,27 +172,29 @@ bool CRenderWareSA::ModelInfoTXDLoadTextures(SReplacementTextures* pReplacementT
173172 return false ;
174173
175174 // Try to load it
176- RwTexDictionary* pTxd = ReadTXD (strFilename, buffer);
177- if (pTxd)
175+ if (auto * pTxd = ReadTXD (strFilename, buffer); pTxd)
178176 {
179177 // Get the list of textures into our own list
180178 GetTxdTextures (pReplacementTextures->textures , pTxd);
181179
182- for (uint i = 0 ; i < pReplacementTextures->textures . size (); i++ )
180+ for (RwTexture* pTexture : pReplacementTextures->textures )
183181 {
184- pReplacementTextures->textures [i]->txd = NULL ;
182+ if (!pTexture)
183+ continue ;
184+
185+ pTexture->txd = nullptr ;
185186 if (bFilteringEnabled)
186- pReplacementTextures-> textures [i]-> flags = 0x1102 ; // Enable filtering (otherwise textures are pixely)
187+ pTexture-> flags = 0x1102 ; // Enable filtering (otherwise textures are pixely)
187188 }
188189
189190 // Make the txd forget it has any textures and destroy it
190191 pTxd->textures .root .next = &pTxd->textures .root ;
191192 pTxd->textures .root .prev = &pTxd->textures .root ;
192193 RwTexDictionaryDestroy (pTxd);
193- pTxd = NULL ;
194+ pTxd = nullptr ;
194195
195196 // We succeeded if we got any textures
196- return pReplacementTextures->textures .size () > 0 ;
197+ return ! pReplacementTextures->textures .empty () ;
197198 }
198199
199200 return false ;
@@ -228,17 +229,14 @@ bool CRenderWareSA::ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTe
228229 //
229230 // Add section for this txd
230231 //
231- pReplacementTextures->perTxdList .push_back (SReplacementTextures::SPerTxd ());
232- SReplacementTextures::SPerTxd& perTxdInfo = pReplacementTextures->perTxdList .back ();
232+ auto & perTxdInfo = pReplacementTextures->perTxdList .emplace_back ();
233233
234234 perTxdInfo.usTxdId = pInfo->usTxdId ;
235- perTxdInfo.bTexturesAreCopies = ( pReplacementTextures->usedInTxdIds .size () > 0 );
235+ perTxdInfo.bTexturesAreCopies = ! pReplacementTextures->usedInTxdIds .empty ( );
236236
237237 // Copy / clone textures
238- for (std::vector< RwTexture*>::iterator iter = pReplacementTextures->textures . begin (); iter != pReplacementTextures-> textures . end (); iter++ )
238+ for (RwTexture* pNewTexture : pReplacementTextures->textures )
239239 {
240- RwTexture* pNewTexture = *iter;
241-
242240 // Use a copy if not first txd
243241 if (perTxdInfo.bTexturesAreCopies )
244242 {
@@ -258,10 +256,8 @@ bool CRenderWareSA::ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTe
258256 //
259257 // Add each texture to the target txd
260258 //
261- for (std::vector< RwTexture*>::iterator iter = perTxdInfo.usingTextures . begin (); iter != perTxdInfo. usingTextures . end (); iter++ )
259+ for (RwTexture* pNewTexture : perTxdInfo.usingTextures )
262260 {
263- RwTexture* pNewTexture = *iter;
264-
265261 // If there is a name clash with an existing texture, replace it
266262 RwTexture* pExistingTexture = RwTexDictionaryFindNamedTexture (pInfo->pTxd , pNewTexture->name );
267263 if (pExistingTexture)
@@ -293,10 +289,8 @@ bool CRenderWareSA::ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTe
293289void CRenderWareSA::ModelInfoTXDRemoveTextures (SReplacementTextures* pReplacementTextures)
294290{
295291 // For each using txd
296- for (uint i = 0 ; i < pReplacementTextures->perTxdList . size (); i++ )
292+ for (auto & perTxdInfo : pReplacementTextures->perTxdList )
297293 {
298- SReplacementTextures::SPerTxd& perTxdInfo = pReplacementTextures->perTxdList [i];
299-
300294 // Get textures info
301295 ushort usTxdId = perTxdInfo.usTxdId ;
302296 CModelTexturesInfo* pInfo = MapFind (ms_ModelTexturesInfoMap, usTxdId);
@@ -308,7 +302,7 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
308302 TextureSwapMap swapMap;
309303 swapMap.reserve (perTxdInfo.usingTextures .size ());
310304
311- for (size_t idx = 0 ; idx < perTxdInfo.usingTextures .size (); ++idx)
305+ for (std:: size_t idx = 0 ; idx < perTxdInfo.usingTextures .size (); ++idx)
312306 {
313307 RwTexture* pOldTexture = perTxdInfo.usingTextures [idx];
314308 if (!pOldTexture)
@@ -330,7 +324,7 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
330324
331325 for (ushort modelId : pReplacementTextures->usedInModelIds )
332326 {
333- CModelInfoSA * pModelInfo = dynamic_cast <CModelInfoSA*>(pGame->GetModelInfo (modelId));
327+ auto * pModelInfo = dynamic_cast <CModelInfoSA*>(pGame->GetModelInfo (modelId));
334328 if (!pModelInfo)
335329 continue ;
336330
@@ -348,9 +342,11 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
348342 }
349343
350344 // Remove replacement textures
351- for (uint i = 0 ; i < perTxdInfo.usingTextures . size (); i++ )
345+ for (RwTexture* pOldTexture : perTxdInfo.usingTextures )
352346 {
353- RwTexture* pOldTexture = perTxdInfo.usingTextures [i];
347+ if (!pOldTexture)
348+ continue ;
349+
354350 RwTexDictionaryRemoveTexture (pInfo->pTxd , pOldTexture);
355351 dassert (!RwTexDictionaryContainsTexture (pInfo->pTxd , pOldTexture));
356352 if (perTxdInfo.bTexturesAreCopies )
@@ -362,12 +358,23 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
362358 }
363359
364360 perTxdInfo.usingTextures .clear ();
361+
362+ // Free replaced textures that aren't in originalTextures (prevents leak)
363+ for (RwTexture* pReplacedTexture : perTxdInfo.replacedOriginals )
364+ {
365+ if (pReplacedTexture && !ListContains (pInfo->originalTextures , pReplacedTexture))
366+ RwTextureDestroy (pReplacedTexture);
367+ }
368+
365369 perTxdInfo.replacedOriginals .clear ();
366370
367371 // Ensure there are original named textures in the txd
368- for (uint i = 0 ; i < pInfo->originalTextures . size (); i++ )
372+ for (RwTexture* pOriginalTexture : pInfo->originalTextures )
369373 {
370- RwTexture* pOriginalTexture = pInfo->originalTextures [i];
374+ // Skip null/invalid textures (can happen during shutdown)
375+ if (!pOriginalTexture)
376+ continue ;
377+
371378 if (!RwTexDictionaryFindNamedTexture (pInfo->pTxd , pOriginalTexture->name ))
372379 RwTexDictionaryAddTexture (pInfo->pTxd , pOriginalTexture);
373380 }
@@ -383,9 +390,10 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
383390 std::vector<RwTexture*> currentTextures;
384391 GetTxdTextures (currentTextures, pInfo->pTxd );
385392 assert (currentTextures.size () == pInfo->originalTextures .size ());
386- for (uint i = 0 ; i < pInfo->originalTextures . size (); i++ )
393+ for (RwTexture* pOriginalTexture : pInfo->originalTextures )
387394 {
388- RwTexture* pOriginalTexture = pInfo->originalTextures [i];
395+ if (!pOriginalTexture)
396+ continue ;
389397 assert (ListContains (currentTextures, pOriginalTexture));
390398 ListRemove (currentTextures, pOriginalTexture);
391399 }
@@ -394,17 +402,21 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
394402 int32_t refsCount = CTxdStore_GetNumRefs (pInfo->usTxdId );
395403 assert (refsCount > 0 && " Should have at least one TXD reference here" );
396404 #endif
405+ // Clear original textures to prevent dangling pointers after TXD ref removal
406+ // The textures themselves are owned by the TXD and will be cleaned up when ref count hits zero
407+ pInfo->originalTextures .clear ();
408+
397409 // Remove info
398410 CTxdStore_RemoveRef (pInfo->usTxdId );
399411 MapRemove (ms_ModelTexturesInfoMap, usTxdId);
400412 }
401413 }
402414
403415 // Destroy replacement textures
404- for (uint i = 0 ; i < pReplacementTextures->textures . size (); i++ )
416+ for (RwTexture* pTexture : pReplacementTextures->textures )
405417 {
406- RwTexture* pOldTexture = pReplacementTextures-> textures [i];
407- DestroyTexture (pOldTexture );
418+ if (pTexture)
419+ DestroyTexture (pTexture );
408420 }
409421 pReplacementTextures->textures .clear ();
410422}
0 commit comments