1212#include " gamesa_renderware.h"
1313
1414#include < map>
15- #include < sstream>
1615#include < unordered_map>
1716#include < unordered_set>
1817#include < utility>
@@ -113,49 +112,50 @@ namespace
113112// //////////////////////////////////////////////////////////////
114113CModelTexturesInfo* CRenderWareSA::GetModelTexturesInfo (ushort usModelId)
115114{
116- auto * pModelInfo = dynamic_cast <CModelInfoSA*>(pGame->GetModelInfo (usModelId));
115+ CModelInfoSA * pModelInfo = dynamic_cast <CModelInfoSA*>(pGame->GetModelInfo (usModelId));
117116 if (!pModelInfo)
118- return nullptr ;
117+ return NULL ;
119118
120- const ushort usTxdId = pModelInfo->GetTextureDictionaryID ();
119+ ushort usTxdId = pModelInfo->GetTextureDictionaryID ();
121120
122- if (auto it = ms_ModelTexturesInfoMap.find (usTxdId); it != ms_ModelTexturesInfoMap.end ())
123- return &it->second ;
124-
125- // Get txd
126- RwTexDictionary* pTxd = CTxdStore_GetTxd (usTxdId);
127-
128- if (!pTxd)
129- {
130- pModelInfo->Request (BLOCKING, " CRenderWareSA::GetModelTexturesInfo" );
131- CTxdStore_AddRef (usTxdId);
132- ((void (__cdecl*)(unsigned short ))FUNC_RemoveModel)(usModelId);
133- pTxd = CTxdStore_GetTxd (usTxdId);
134- }
135- else
121+ CModelTexturesInfo* pInfo = MapFind (ms_ModelTexturesInfoMap, usTxdId);
122+ if (!pInfo)
136123 {
137- CTxdStore_AddRef (usTxdId);
138- if (pModelInfo->GetModelType () == eModelInfoType::PED)
124+ // Get txd
125+ RwTexDictionary* pTxd = CTxdStore_GetTxd (usTxdId);
126+
127+ if (!pTxd)
139128 {
140- // Mystery fix for #9336: (MTA sometimes fails at loading custom textures)
141- // Possibly forces the ped model to be reloaded in some way
129+ pModelInfo-> Request (BLOCKING, " CRenderWareSA::GetModelTexturesInfo " );
130+ CTxdStore_AddRef (usTxdId);
142131 ((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)
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+ }
143143 }
144- }
145144
146- if (!pTxd)
147- return nullptr ;
145+ if (!pTxd)
146+ return NULL ;
148147
149- // Add new info
150- auto [it, inserted] = ms_ModelTexturesInfoMap. emplace ( usTxdId, CModelTexturesInfo{} );
151- auto & newInfo = it-> second ;
152- newInfo. usTxdId = usTxdId;
153- newInfo. pTxd = pTxd;
148+ // Add new info
149+ MapSet (ms_ModelTexturesInfoMap, usTxdId, CModelTexturesInfo () );
150+ pInfo = MapFind (ms_ModelTexturesInfoMap, usTxdId) ;
151+ pInfo-> usTxdId = usTxdId;
152+ pInfo-> pTxd = pTxd;
154153
155- // Save original textures
156- GetTxdTextures (newInfo.originalTextures , newInfo.pTxd );
157-
158- return &newInfo;
154+ // Save original textures
155+ GetTxdTextures (pInfo->originalTextures , pInfo->pTxd );
156+ }
157+
158+ return pInfo;
159159}
160160
161161// //////////////////////////////////////////////////////////////
@@ -173,29 +173,27 @@ bool CRenderWareSA::ModelInfoTXDLoadTextures(SReplacementTextures* pReplacementT
173173 return false ;
174174
175175 // Try to load it
176- if (auto * pTxd = ReadTXD (strFilename, buffer); pTxd)
176+ RwTexDictionary* pTxd = ReadTXD (strFilename, buffer);
177+ if (pTxd)
177178 {
178179 // Get the list of textures into our own list
179180 GetTxdTextures (pReplacementTextures->textures , pTxd);
180181
181- for (RwTexture* pTexture : pReplacementTextures->textures )
182+ for (uint i = 0 ; i < pReplacementTextures->textures . size (); i++ )
182183 {
183- if (!pTexture)
184- continue ;
185-
186- pTexture->txd = nullptr ;
184+ pReplacementTextures->textures [i]->txd = NULL ;
187185 if (bFilteringEnabled)
188- pTexture-> flags = 0x1102 ; // Enable filtering (otherwise textures are pixely)
186+ pReplacementTextures-> textures [i]-> flags = 0x1102 ; // Enable filtering (otherwise textures are pixely)
189187 }
190188
191189 // Make the txd forget it has any textures and destroy it
192190 pTxd->textures .root .next = &pTxd->textures .root ;
193191 pTxd->textures .root .prev = &pTxd->textures .root ;
194192 RwTexDictionaryDestroy (pTxd);
195- pTxd = nullptr ;
193+ pTxd = NULL ;
196194
197195 // We succeeded if we got any textures
198- return ! pReplacementTextures->textures .empty () ;
196+ return pReplacementTextures->textures .size () > 0 ;
199197 }
200198
201199 return false ;
@@ -230,14 +228,17 @@ bool CRenderWareSA::ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTe
230228 //
231229 // Add section for this txd
232230 //
233- auto & perTxdInfo = pReplacementTextures->perTxdList .emplace_back ();
231+ pReplacementTextures->perTxdList .push_back (SReplacementTextures::SPerTxd ());
232+ SReplacementTextures::SPerTxd& perTxdInfo = pReplacementTextures->perTxdList .back ();
234233
235234 perTxdInfo.usTxdId = pInfo->usTxdId ;
236- perTxdInfo.bTexturesAreCopies = ! pReplacementTextures->usedInTxdIds .empty ( );
235+ perTxdInfo.bTexturesAreCopies = ( pReplacementTextures->usedInTxdIds .size () > 0 );
237236
238237 // Copy / clone textures
239- for (RwTexture* pNewTexture : pReplacementTextures->textures )
238+ for (std::vector< RwTexture*>::iterator iter = pReplacementTextures->textures . begin (); iter != pReplacementTextures-> textures . end (); iter++ )
240239 {
240+ RwTexture* pNewTexture = *iter;
241+
241242 // Use a copy if not first txd
242243 if (perTxdInfo.bTexturesAreCopies )
243244 {
@@ -257,8 +258,10 @@ bool CRenderWareSA::ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTe
257258 //
258259 // Add each texture to the target txd
259260 //
260- for (RwTexture* pNewTexture : perTxdInfo.usingTextures )
261+ for (std::vector< RwTexture*>::iterator iter = perTxdInfo.usingTextures . begin (); iter != perTxdInfo. usingTextures . end (); iter++ )
261262 {
263+ RwTexture* pNewTexture = *iter;
264+
262265 // If there is a name clash with an existing texture, replace it
263266 RwTexture* pExistingTexture = RwTexDictionaryFindNamedTexture (pInfo->pTxd , pNewTexture->name );
264267 if (pExistingTexture)
@@ -290,8 +293,10 @@ bool CRenderWareSA::ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTe
290293void CRenderWareSA::ModelInfoTXDRemoveTextures (SReplacementTextures* pReplacementTextures)
291294{
292295 // For each using txd
293- for (auto & perTxdInfo : pReplacementTextures->perTxdList )
296+ for (uint i = 0 ; i < pReplacementTextures->perTxdList . size (); i++ )
294297 {
298+ SReplacementTextures::SPerTxd& perTxdInfo = pReplacementTextures->perTxdList [i];
299+
295300 // Get textures info
296301 ushort usTxdId = perTxdInfo.usTxdId ;
297302 CModelTexturesInfo* pInfo = MapFind (ms_ModelTexturesInfoMap, usTxdId);
@@ -303,21 +308,15 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
303308 TextureSwapMap swapMap;
304309 swapMap.reserve (perTxdInfo.usingTextures .size ());
305310
306- for (std:: size_t idx = 0 ; idx < perTxdInfo.usingTextures .size (); ++idx)
311+ for (size_t idx = 0 ; idx < perTxdInfo.usingTextures .size (); ++idx)
307312 {
308313 RwTexture* pOldTexture = perTxdInfo.usingTextures [idx];
309314 if (!pOldTexture)
310315 continue ;
311316
312317 RwTexture* pOriginalTexture = (idx < perTxdInfo.replacedOriginals .size ()) ? perTxdInfo.replacedOriginals [idx] : nullptr ;
313-
314- if (pOriginalTexture && !SharedUtil::IsReadablePointer (pOriginalTexture, sizeof (RwTexture)))
315- pOriginalTexture = nullptr ;
316-
317318 swapMap[pOldTexture] = pOriginalTexture;
318319
319- // Always restore original textures to prevent them from becoming orphaned and GC'd
320- // This is crucial for proper cleanup even when multiple replacement sets use the same TXD
321320 if (pOriginalTexture && !RwTexDictionaryContainsTexture (pInfo->pTxd , pOriginalTexture))
322321 RwTexDictionaryAddTexture (pInfo->pTxd , pOriginalTexture);
323322 }
@@ -331,7 +330,7 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
331330
332331 for (ushort modelId : pReplacementTextures->usedInModelIds )
333332 {
334- auto * pModelInfo = dynamic_cast <CModelInfoSA*>(pGame->GetModelInfo (modelId));
333+ CModelInfoSA * pModelInfo = dynamic_cast <CModelInfoSA*>(pGame->GetModelInfo (modelId));
335334 if (!pModelInfo)
336335 continue ;
337336
@@ -349,14 +348,9 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
349348 }
350349
351350 // Remove replacement textures
352- for (RwTexture* pOldTexture : perTxdInfo.usingTextures )
351+ for (uint i = 0 ; i < perTxdInfo.usingTextures . size (); i++ )
353352 {
354- if (!pOldTexture)
355- continue ;
356-
357- if (!SharedUtil::IsReadablePointer (pOldTexture, sizeof (RwTexture)))
358- continue ;
359-
353+ RwTexture* pOldTexture = perTxdInfo.usingTextures [i];
360354 RwTexDictionaryRemoveTexture (pInfo->pTxd , pOldTexture);
361355 dassert (!RwTexDictionaryContainsTexture (pInfo->pTxd , pOldTexture));
362356 if (perTxdInfo.bTexturesAreCopies )
@@ -368,23 +362,12 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
368362 }
369363
370364 perTxdInfo.usingTextures .clear ();
371-
372- // Free replaced textures that aren't in originalTextures (prevents leak)
373- for (RwTexture* pReplacedTexture : perTxdInfo.replacedOriginals )
374- {
375- if (pReplacedTexture && SharedUtil::IsReadablePointer (pReplacedTexture, sizeof (RwTexture)) && !ListContains (pInfo->originalTextures , pReplacedTexture))
376- RwTextureDestroy (pReplacedTexture);
377- }
378-
379365 perTxdInfo.replacedOriginals .clear ();
380366
381367 // Ensure there are original named textures in the txd
382- for (RwTexture* pOriginalTexture : pInfo->originalTextures )
368+ for (uint i = 0 ; i < pInfo->originalTextures . size (); i++ )
383369 {
384- // Skip null/invalid textures (can happen during shutdown)
385- if (!pOriginalTexture)
386- continue ;
387-
370+ RwTexture* pOriginalTexture = pInfo->originalTextures [i];
388371 if (!RwTexDictionaryFindNamedTexture (pInfo->pTxd , pOriginalTexture->name ))
389372 RwTexDictionaryAddTexture (pInfo->pTxd , pOriginalTexture);
390373 }
@@ -399,101 +382,29 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
399382 #ifdef MTA_DEBUG
400383 std::vector<RwTexture*> currentTextures;
401384 GetTxdTextures (currentTextures, pInfo->pTxd );
402-
403- auto formatTextures = [](const std::vector<RwTexture*>& textures) -> std::string {
404- std::ostringstream result;
405- for (size_t i = 0 ; i < textures.size (); ++i)
406- {
407- const auto * pTex = textures[i];
408- const bool isValid = pTex && SharedUtil::IsReadablePointer (pTex, sizeof (RwTexture));
409- const bool isLast = (i == textures.size () - 1 );
410-
411- if (isValid)
412- result << pTex->name << " [0x" << std::hex << pTex << std::dec << " ]" ;
413- else
414- result << " INVALID[0x" << std::hex << pTex << std::dec << " ]" ;
415-
416- if (!isLast)
417- result << " , " ;
418- }
419- return result.str ();
420- };
421-
422- // Allow size mismatch in case texture removal was skipped due to invalid pointers
423- if (currentTextures.size () != pInfo->originalTextures .size ())
385+ assert (currentTextures.size () == pInfo->originalTextures .size ());
386+ for (uint i = 0 ; i < pInfo->originalTextures .size (); i++)
424387 {
425- std::ostringstream debugMsg;
426- debugMsg << " TXD " << pInfo->usTxdId << " : texture count mismatch (current="
427- << currentTextures.size () << " , expected=" << pInfo->originalTextures .size () << " )\n " ;
428- debugMsg << " Current textures: " << formatTextures (currentTextures);
429- debugMsg << " \n Expected textures: " << formatTextures (pInfo->originalTextures );
430- debugMsg << " \n " ;
431- OutputDebugString (debugMsg.str ().c_str ());
432- }
433- else
434- {
435- // First pass: validate all original textures are present
436- for (const auto * pOriginalTexture : pInfo->originalTextures )
437- {
438- if (!pOriginalTexture)
439- continue ;
440- if (!ListContains (currentTextures, pOriginalTexture))
441- {
442- const char * texName = SharedUtil::IsReadablePointer (pOriginalTexture, sizeof (RwTexture))
443- ? pOriginalTexture->name : " INVALID" ;
444- std::ostringstream oss;
445- oss << " Original texture not found in TXD " << pInfo->usTxdId
446- << " - texture '" << texName << " ' [0x" << std::hex << pOriginalTexture << std::dec
447- << " ] was removed or replaced unexpectedly" ;
448- const std::string assertMsg = oss.str ();
449- assert (false && assertMsg.c_str ());
450- }
451- }
452-
453- // Second pass: remove original textures from current list to find extras
454- for (auto * pOriginalTexture : pInfo->originalTextures )
455- {
456- if (pOriginalTexture)
457- ListRemove (currentTextures, pOriginalTexture);
458- }
459-
460- // Check for leaked textures
461- if (!currentTextures.empty ())
462- {
463- std::ostringstream oss;
464- oss << " Extra textures remain in TXD " << pInfo->usTxdId
465- << " after removing all originals - indicates texture leak. Remaining: "
466- << formatTextures (currentTextures);
467- const std::string assertMsg = oss.str ();
468- assert (false && assertMsg.c_str ());
469- }
388+ RwTexture* pOriginalTexture = pInfo->originalTextures [i];
389+ assert (ListContains (currentTextures, pOriginalTexture));
390+ ListRemove (currentTextures, pOriginalTexture);
470391 }
392+ assert (currentTextures.empty ());
471393
472- const int32_t refsCount = CTxdStore_GetNumRefs (pInfo->usTxdId );
473- if (refsCount <= 0 )
474- {
475- std::ostringstream oss;
476- oss << " TXD " << pInfo->usTxdId << " has invalid ref count "
477- << refsCount << " - should be > 0 before cleanup" ;
478- const std::string assertMsg = oss.str ();
479- assert (false && assertMsg.c_str ());
480- }
394+ int32_t refsCount = CTxdStore_GetNumRefs (pInfo->usTxdId );
395+ assert (refsCount > 0 && " Should have at least one TXD reference here" );
481396 #endif
482- // Clear original textures to prevent dangling pointers after TXD ref removal
483- // The textures themselves are owned by the TXD and will be cleaned up when ref count hits zero
484- pInfo->originalTextures .clear ();
485-
486397 // Remove info
487398 CTxdStore_RemoveRef (pInfo->usTxdId );
488399 MapRemove (ms_ModelTexturesInfoMap, usTxdId);
489400 }
490401 }
491402
492403 // Destroy replacement textures
493- for (RwTexture* pTexture : pReplacementTextures->textures )
404+ for (uint i = 0 ; i < pReplacementTextures->textures . size (); i++ )
494405 {
495- if (pTexture)
496- DestroyTexture (pTexture );
406+ RwTexture* pOldTexture = pReplacementTextures-> textures [i];
407+ DestroyTexture (pOldTexture );
497408 }
498409 pReplacementTextures->textures .clear ();
499410}
0 commit comments