8
8
9
9
#include " StdInc.h"
10
10
#include " CGameSA.h"
11
+ #include " CRenderWareSA.h"
11
12
#include " gamesa_renderware.h"
12
13
14
+ #include < map>
15
+ #include < unordered_map>
16
+ #include < unordered_set>
17
+ #include < utility>
18
+
13
19
extern CGameSA* pGame;
14
20
15
- //
16
- // Info about the current state of a model's txd textures
17
- //
18
- class CModelTexturesInfo
21
+ struct CModelTexturesInfo
19
22
{
20
- public:
21
- std::vector<RwTexture*> originalTextures;
23
+ ushort usTxdId = 0 ;
24
+ RwTexDictionary* pTxd = nullptr ;
25
+ std::vector<RwTexture*> originalTextures;
22
26
std::vector<SReplacementTextures*> usedByReplacements;
23
- ushort usTxdId;
24
- RwTexDictionary* pTxd;
25
27
};
26
28
27
- std::map<ushort, CModelTexturesInfo> ms_ModelTexturesInfoMap;
29
+ static std::map<ushort, CModelTexturesInfo> ms_ModelTexturesInfoMap;
30
+
31
+ namespace
32
+ {
33
+ using TextureSwapMap = std::unordered_map<RwTexture*, RwTexture*>;
34
+
35
+ void ReplaceTextureInGeometry (RpGeometry* pGeometry, const TextureSwapMap& swapMap)
36
+ {
37
+ if (!pGeometry || swapMap.empty ())
38
+ return ;
39
+
40
+ RpMaterials& materials = pGeometry->materials ;
41
+ if (!materials.materials )
42
+ return ;
43
+
44
+ for (int idx = 0 ; idx < materials.entries ; ++idx)
45
+ {
46
+ RpMaterial* pMaterial = materials.materials [idx];
47
+ if (!pMaterial)
48
+ continue ;
49
+
50
+ auto it = swapMap.find (pMaterial->texture );
51
+ if (it != swapMap.end ())
52
+ RpMaterialSetTexture (pMaterial, it->second );
53
+ }
54
+ }
55
+
56
+ bool ReplaceTextureInAtomicCB (RpAtomic* pAtomic, void * userData)
57
+ {
58
+ if (!pAtomic)
59
+ return true ;
60
+
61
+ auto * swapMap = static_cast <TextureSwapMap*>(userData);
62
+ if (!swapMap)
63
+ return true ;
64
+
65
+ ReplaceTextureInGeometry (pAtomic->geometry , *swapMap);
66
+ return true ;
67
+ }
68
+
69
+ void ReplaceTextureInModel (CModelInfoSA* pModelInfo, TextureSwapMap& swapMap)
70
+ {
71
+ if (!pModelInfo || swapMap.empty ())
72
+ return ;
73
+
74
+ RwObject* pRwObject = pModelInfo->GetRwObject ();
75
+ if (!pRwObject)
76
+ return ;
77
+
78
+ switch (pModelInfo->GetModelType ())
79
+ {
80
+ case eModelInfoType::ATOMIC:
81
+ case eModelInfoType::TIME:
82
+ case eModelInfoType::LOD_ATOMIC:
83
+ {
84
+ RpAtomic* pAtomic = reinterpret_cast <RpAtomic*>(pRwObject);
85
+ if (pAtomic)
86
+ ReplaceTextureInGeometry (pAtomic->geometry , swapMap);
87
+ break ;
88
+ }
89
+
90
+ case eModelInfoType::WEAPON:
91
+ case eModelInfoType::CLUMP:
92
+ case eModelInfoType::VEHICLE:
93
+ case eModelInfoType::PED:
94
+ case eModelInfoType::UNKNOWN:
95
+ default :
96
+ {
97
+ RpClump* pClump = reinterpret_cast <RpClump*>(pRwObject);
98
+ if (pClump)
99
+ RpClumpForAllAtomics (pClump, ReplaceTextureInAtomicCB, &swapMap);
100
+ break ;
101
+ }
102
+ }
103
+ }
104
+ }
28
105
29
106
// //////////////////////////////////////////////////////////////
30
107
//
@@ -192,6 +269,8 @@ bool CRenderWareSA::ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTe
192
269
RwTexDictionaryRemoveTexture (pInfo->pTxd , pExistingTexture);
193
270
}
194
271
272
+ perTxdInfo.replacedOriginals .push_back (pExistingTexture);
273
+
195
274
// Add the texture
196
275
dassert (!RwTexDictionaryContainsTexture (pInfo->pTxd , pNewTexture));
197
276
RwTexDictionaryAddTexture (pInfo->pTxd , pNewTexture);
@@ -226,6 +305,48 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
226
305
dassert (MapFind (ms_ModelTexturesInfoMap, usTxdId));
227
306
dassert (ListContains (pInfo->usedByReplacements , pReplacementTextures));
228
307
308
+ TextureSwapMap swapMap;
309
+ swapMap.reserve (perTxdInfo.usingTextures .size ());
310
+
311
+ for (size_t idx = 0 ; idx < perTxdInfo.usingTextures .size (); ++idx)
312
+ {
313
+ RwTexture* pOldTexture = perTxdInfo.usingTextures [idx];
314
+ if (!pOldTexture)
315
+ continue ;
316
+
317
+ RwTexture* pOriginalTexture = (idx < perTxdInfo.replacedOriginals .size ()) ? perTxdInfo.replacedOriginals [idx] : nullptr ;
318
+ swapMap[pOldTexture] = pOriginalTexture;
319
+
320
+ if (pOriginalTexture && !RwTexDictionaryContainsTexture (pInfo->pTxd , pOriginalTexture))
321
+ RwTexDictionaryAddTexture (pInfo->pTxd , pOriginalTexture);
322
+ }
323
+
324
+ if (!swapMap.empty ())
325
+ {
326
+ std::vector<CModelInfoSA*> targetModels;
327
+ targetModels.reserve (pReplacementTextures->usedInModelIds .size ());
328
+ std::unordered_set<CModelInfoSA*> seenModels;
329
+ seenModels.reserve (pReplacementTextures->usedInModelIds .size ());
330
+
331
+ for (ushort modelId : pReplacementTextures->usedInModelIds )
332
+ {
333
+ CModelInfoSA* pModelInfo = dynamic_cast <CModelInfoSA*>(pGame->GetModelInfo (modelId));
334
+ if (!pModelInfo)
335
+ continue ;
336
+
337
+ if (pModelInfo->GetTextureDictionaryID () != perTxdInfo.usTxdId )
338
+ continue ;
339
+
340
+ if (seenModels.insert (pModelInfo).second )
341
+ targetModels.push_back (pModelInfo);
342
+ }
343
+
344
+ for (CModelInfoSA* pModelInfo : targetModels)
345
+ {
346
+ ReplaceTextureInModel (pModelInfo, swapMap);
347
+ }
348
+ }
349
+
229
350
// Remove replacement textures
230
351
for (uint i = 0 ; i < perTxdInfo.usingTextures .size (); i++)
231
352
{
@@ -235,11 +356,14 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
235
356
if (perTxdInfo.bTexturesAreCopies )
236
357
{
237
358
// Destroy the copy (but not the raster as that was not copied)
238
- pOldTexture->raster = NULL ;
359
+ std::exchange ( pOldTexture->raster , nullptr ) ;
239
360
RwTextureDestroy (pOldTexture);
240
361
}
241
362
}
242
363
364
+ perTxdInfo.usingTextures .clear ();
365
+ perTxdInfo.replacedOriginals .clear ();
366
+
243
367
// Ensure there are original named textures in the txd
244
368
for (uint i = 0 ; i < pInfo->originalTextures .size (); i++)
245
369
{
0 commit comments