Skip to content

Commit e213e61

Browse files
Synchronize changes from 1.6 branch [ci skip]
c92a4ad 1.6: FIx build errors (convert back to C++ 14 where applicable, due to recent backports) b17e00a Rework clipboard handling and add SharedUtil::MakeGlobalUnlockGuard
2 parents bd8533d + c92a4ad commit e213e61

File tree

7 files changed

+571
-264
lines changed

7 files changed

+571
-264
lines changed

Client/core/CGraphStats.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
*
99
*****************************************************************************/
1010

11+
#ifndef CGRAPHSTATS_H
12+
#define CGRAPHSTATS_H
13+
1114
#define TIMING_GRAPH(name) \
1215
GetGraphStats()->AddTimingPoint( name );
1316

@@ -27,3 +30,5 @@ class CGraphStatsInterface
2730
};
2831

2932
CGraphStatsInterface* GetGraphStats();
33+
34+
#endif // CGRAPHSTATS_H

Client/game_sa/CRenderWareSA.TextureReplacing.cpp

Lines changed: 113 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#include <map>
2020
#include <mutex>
2121
#include <string>
22-
#include <string_view>
2322
#include <unordered_map>
2423
#include <unordered_set>
2524
#include <utility>
@@ -29,59 +28,79 @@ extern CGameSA* pGame;
2928

3029
namespace TextureIndex
3130
{
31+
inline std::size_t ComputeLength(const char* value) noexcept
32+
{
33+
if (!value)
34+
return 0;
35+
36+
std::size_t result = 0;
37+
while (result < RW_TEXTURE_NAME_LENGTH && value[result] != '\0')
38+
++result;
39+
return result;
40+
}
41+
3242
struct Name
3343
{
3444
std::array<char, RW_TEXTURE_NAME_LENGTH + 1> data{};
3545
std::size_t length = 0;
3646

37-
void Assign(std::string_view value) noexcept
47+
void Assign(const char* value, std::size_t valueLength) noexcept
3848
{
39-
const std::size_t copyLength = std::min<std::size_t>(value.size(), RW_TEXTURE_NAME_LENGTH);
40-
if (copyLength > 0)
41-
std::memmove(data.data(), value.data(), copyLength);
49+
const std::size_t copyLength = std::min<std::size_t>(valueLength, RW_TEXTURE_NAME_LENGTH);
50+
if (copyLength > 0 && value)
51+
std::memmove(data.data(), value, copyLength);
4252
if (copyLength < data.size())
4353
std::fill(data.begin() + copyLength, data.end(), '\0');
4454
length = copyLength;
4555
}
4656

47-
[[nodiscard]] std::string_view View() const noexcept { return std::string_view(data.data(), length); }
57+
void Assign(const char* value) noexcept
58+
{
59+
Assign(value, ComputeLength(value));
60+
}
4861

49-
[[nodiscard]] const char* CStr() const noexcept { return data.data(); }
62+
void Assign(const std::string& value) noexcept
63+
{
64+
Assign(value.c_str(), value.size());
65+
}
66+
67+
const char* CStr() const noexcept { return data.data(); }
5068

51-
[[nodiscard]] bool Empty() const noexcept { return length == 0; }
69+
std::size_t Length() const noexcept { return length; }
70+
71+
bool Empty() const noexcept { return length == 0; }
5272
};
5373

54-
[[nodiscard]] inline char ToLowerAscii(char ch) noexcept
74+
inline char ToLowerAscii(char ch) noexcept
5575
{
5676
return static_cast<char>(std::tolower(static_cast<unsigned char>(ch)));
5777
}
5878

59-
[[nodiscard]] inline std::string_view ToView(const Name& value) noexcept
60-
{
61-
return value.View();
62-
}
63-
[[nodiscard]] inline std::string_view ToView(const std::string& value) noexcept
79+
inline bool IsEqualCanonical(const char* lhs, std::size_t lhsLength, const char* rhs, std::size_t rhsLength) noexcept
6480
{
65-
return value;
66-
}
67-
[[nodiscard]] inline std::string_view ToView(std::string_view value) noexcept
68-
{
69-
return value;
70-
}
71-
[[nodiscard]] inline std::string_view ToView(const char* value) noexcept
72-
{
73-
return value ? std::string_view(value) : std::string_view();
81+
if (lhsLength != rhsLength)
82+
return false;
83+
84+
for (std::size_t idx = 0; idx < lhsLength; ++idx)
85+
{
86+
if (ToLowerAscii(lhs[idx]) != ToLowerAscii(rhs[idx]))
87+
return false;
88+
}
89+
return true;
7490
}
7591

76-
[[nodiscard]] inline std::size_t HashCanonical(std::string_view view) noexcept
92+
inline std::size_t HashCanonical(const char* data, std::size_t length) noexcept
7793
{
7894
constexpr std::size_t kFnvOffset = 2166136261u;
7995
constexpr std::size_t kFnvPrime = 16777619u;
8096

8197
std::size_t hash = kFnvOffset;
82-
for (char ch : view)
98+
if (!data)
99+
return hash;
100+
101+
for (std::size_t idx = 0; idx < length; ++idx)
83102
{
84-
hash ^= static_cast<unsigned char>(ToLowerAscii(ch));
103+
hash ^= static_cast<unsigned char>(ToLowerAscii(data[idx]));
85104
hash *= kFnvPrime;
86105
}
87106
return hash;
@@ -91,32 +110,49 @@ namespace TextureIndex
91110
{
92111
using is_transparent = void;
93112

94-
template <typename T>
95-
std::size_t operator()(const T& value) const noexcept
113+
std::size_t operator()(const Name& value) const noexcept
114+
{
115+
return HashCanonical(value.CStr(), value.Length());
116+
}
117+
118+
std::size_t operator()(const char* value) const noexcept
119+
{
120+
return HashCanonical(value, ComputeLength(value));
121+
}
122+
123+
std::size_t operator()(const std::string& value) const noexcept
96124
{
97-
return HashCanonical(ToView(value));
125+
return HashCanonical(value.c_str(), value.size());
98126
}
99127
};
100128

101129
struct Equal
102130
{
103131
using is_transparent = void;
104132

105-
template <typename LHS, typename RHS>
106-
bool operator()(const LHS& lhs, const RHS& rhs) const noexcept
133+
bool operator()(const Name& lhs, const Name& rhs) const noexcept
107134
{
108-
const std::string_view lhsView = ToView(lhs);
109-
const std::string_view rhsView = ToView(rhs);
135+
return IsEqualCanonical(lhs.CStr(), lhs.Length(), rhs.CStr(), rhs.Length());
136+
}
110137

111-
if (lhsView.size() != rhsView.size())
112-
return false;
138+
bool operator()(const Name& lhs, const char* rhs) const noexcept
139+
{
140+
return IsEqualCanonical(lhs.CStr(), lhs.Length(), rhs, ComputeLength(rhs));
141+
}
113142

114-
for (std::size_t idx = 0; idx < lhsView.size(); ++idx)
115-
{
116-
if (ToLowerAscii(lhsView[idx]) != ToLowerAscii(rhsView[idx]))
117-
return false;
118-
}
119-
return true;
143+
bool operator()(const char* lhs, const Name& rhs) const noexcept
144+
{
145+
return IsEqualCanonical(lhs, ComputeLength(lhs), rhs.CStr(), rhs.Length());
146+
}
147+
148+
bool operator()(const std::string& lhs, const Name& rhs) const noexcept
149+
{
150+
return IsEqualCanonical(lhs.c_str(), lhs.size(), rhs.CStr(), rhs.Length());
151+
}
152+
153+
bool operator()(const Name& lhs, const std::string& rhs) const noexcept
154+
{
155+
return IsEqualCanonical(lhs.CStr(), lhs.Length(), rhs.c_str(), rhs.size());
120156
}
121157
};
122158
} // namespace TextureIndex
@@ -296,9 +332,9 @@ namespace
296332
perTxdInfo.usTxdId = txdId;
297333
perTxdInfo.bTexturesAreCopies = (replacementTextures.usedInTxdIdLookup.size() > 1);
298334

299-
auto [indexInsertIt, indexInserted] = replacementTextures.perTxdIndexLookup.emplace(txdId, newIndex);
300-
if (!indexInserted)
301-
indexInsertIt->second = newIndex;
335+
auto indexInsertResult = replacementTextures.perTxdIndexLookup.emplace(txdId, newIndex);
336+
if (!indexInsertResult.second)
337+
indexInsertResult.first->second = newIndex;
302338

303339
isNewEntry = true;
304340
return &perTxdInfo;
@@ -316,8 +352,10 @@ namespace
316352
dassert(replacementTextures.usedInTxdIdLookup.find(txdId) != replacementTextures.usedInTxdIdLookup.end());
317353

318354
dassert(replacementTextures.perTxdIndexLookup.size() == replacementTextures.perTxdList.size());
319-
for (const auto& [txdId, index] : replacementTextures.perTxdIndexLookup)
355+
for (const auto& pair : replacementTextures.perTxdIndexLookup)
320356
{
357+
const ushort txdId = pair.first;
358+
const std::size_t index = pair.second;
321359
dassert(index < replacementTextures.perTxdList.size());
322360
dassert(replacementTextures.perTxdList[index].usTxdId == txdId);
323361
}
@@ -340,17 +378,17 @@ namespace
340378
}
341379
}
342380

343-
[[nodiscard]] inline bool IsValidTexDictionary(const RwTexDictionary* const pTxd)
381+
inline bool IsValidTexDictionary(const RwTexDictionary* const pTxd)
344382
{
345383
return pTxd && SharedUtil::IsReadablePointer(pTxd, sizeof(*pTxd));
346384
}
347385

348-
[[nodiscard]] inline bool IsValidTexturePtr(const RwTexture* const pTexture)
386+
inline bool IsValidTexturePtr(const RwTexture* const pTexture)
349387
{
350388
return pTexture && SharedUtil::IsReadablePointer(pTexture, sizeof(*pTexture));
351389
}
352390

353-
[[nodiscard]] size_t GetTextureNameLength(const RwTexture* const pTexture)
391+
size_t GetTextureNameLength(const RwTexture* const pTexture)
354392
{
355393
if (!pTexture)
356394
return 0;
@@ -361,28 +399,22 @@ namespace
361399
return length;
362400
}
363401

364-
[[nodiscard]] std::string_view GetTextureNameView(const RwTexture* const pTexture)
365-
{
366-
if (!pTexture)
367-
return {};
368-
369-
const size_t length = GetTextureNameLength(pTexture);
370-
return std::string_view(pTexture->name, length);
371-
}
372-
373402
TextureIndex::Name ExtractTextureName(const RwTexture* pTexture)
374403
{
375404
TextureIndex::Name name;
376-
name.Assign(GetTextureNameView(pTexture));
405+
if (pTexture)
406+
name.Assign(pTexture->name, GetTextureNameLength(pTexture));
377407
return name;
378408
}
379409

380-
RwTexture* LookupOriginalTexture(CModelTexturesInfo& info, std::string_view name)
410+
RwTexture* LookupOriginalTexture(CModelTexturesInfo& info, const char* name)
381411
{
382-
if (name.empty())
412+
if (!name || name[0] == '\0')
383413
return nullptr;
384414

385-
auto it = info.originalTextureIndex.find(name);
415+
TextureIndex::Name lookupKey;
416+
lookupKey.Assign(name);
417+
auto it = info.originalTextureIndex.find(lookupKey);
386418
if (it == info.originalTextureIndex.end())
387419
return nullptr;
388420

@@ -413,12 +445,12 @@ namespace
413445
RebuildOriginalLookup(info);
414446
}
415447

416-
RwTexture* ResolveOriginalTexture(CModelTexturesInfo& info, RwTexDictionary* pTxd, RwTexture* pCandidate, std::string_view replacementName)
448+
RwTexture* ResolveOriginalTexture(CModelTexturesInfo& info, RwTexDictionary* pTxd, RwTexture* pCandidate, const char* replacementName)
417449
{
418450
if (IsValidTexturePtr(pCandidate))
419451
return pCandidate;
420452

421-
if (replacementName.empty())
453+
if (!replacementName || replacementName[0] == '\0')
422454
return nullptr;
423455

424456
const bool canReload = IsValidTexDictionary(pTxd);
@@ -435,14 +467,17 @@ namespace
435467
return IsValidTexturePtr(record.texture) ? record.texture : nullptr;
436468
};
437469

438-
auto mapIt = info.originalTextureIndex.find(replacementName);
470+
TextureIndex::Name replacementKey;
471+
replacementKey.Assign(replacementName);
472+
473+
auto mapIt = info.originalTextureIndex.find(replacementKey);
439474
if (mapIt != info.originalTextureIndex.end())
440475
{
441476
if (RwTexture* resolved = tryResolve(mapIt->second))
442477
return resolved;
443478

444479
RebuildOriginalLookup(info);
445-
mapIt = info.originalTextureIndex.find(replacementName);
480+
mapIt = info.originalTextureIndex.find(replacementKey);
446481
if (mapIt != info.originalTextureIndex.end())
447482
{
448483
if (RwTexture* resolved = tryResolve(mapIt->second))
@@ -501,7 +536,9 @@ namespace
501536
if (!IsValidTexturePtr(pReplacementTexture) || !IsValidTexturePtr(pOriginalTexture))
502537
continue;
503538

504-
swapMap.insert_or_assign(pOriginalTexture, pReplacementTexture);
539+
auto insertResult = swapMap.insert(std::make_pair(pOriginalTexture, pReplacementTexture));
540+
if (!insertResult.second)
541+
insertResult.first->second = pReplacementTexture;
505542
}
506543

507544
return !swapMap.empty();
@@ -518,11 +555,13 @@ namespace
518555
if (!IsValidTexturePtr(pOldTexture))
519556
continue;
520557

521-
RwTexture* pOriginalTexture = (idx < perTxdInfo.replacedOriginals.size()) ? perTxdInfo.replacedOriginals[idx] : nullptr;
522-
const std::string_view replacementName = GetTextureNameView(pOldTexture);
523-
RwTexture* pResolvedOriginal = ResolveOriginalTexture(info, pTxd, pOriginalTexture, replacementName);
558+
RwTexture* pOriginalTexture = (idx < perTxdInfo.replacedOriginals.size()) ? perTxdInfo.replacedOriginals[idx] : nullptr;
559+
const char* replacementName = pOldTexture ? pOldTexture->name : nullptr;
560+
RwTexture* pResolvedOriginal = ResolveOriginalTexture(info, pTxd, pOriginalTexture, replacementName);
524561

525-
swapMap.insert_or_assign(pOldTexture, pResolvedOriginal);
562+
auto insertResult = swapMap.insert(std::make_pair(pOldTexture, pResolvedOriginal));
563+
if (!insertResult.second)
564+
insertResult.first->second = pResolvedOriginal;
526565

527566
if (pResolvedOriginal && !CRenderWareSA::RwTexDictionaryContainsTexture(pTxd, pResolvedOriginal))
528567
{
@@ -669,8 +708,8 @@ ModelTexturesInfoGuard AcquireModelTexturesInfo(ushort usModelId)
669708
}
670709
}
671710

672-
auto [insertIt, inserted] = ms_ModelTexturesInfoMap.emplace(usTxdId, CModelTexturesInfo());
673-
guard.info = &insertIt->second;
711+
auto insertResult = ms_ModelTexturesInfoMap.emplace(usTxdId, CModelTexturesInfo());
712+
guard.info = &insertResult.first->second;
674713

675714
guard.info->usTxdId = usTxdId;
676715
guard.info->pTxd = pTxd;
@@ -845,10 +884,10 @@ bool CRenderWareSA::ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTe
845884
dassert(bHasValidTxd);
846885
for (RwTexture* pNewTexture : pPerTxdInfo->usingTextures)
847886
{
848-
const std::string_view replacementName = GetTextureNameView(pNewTexture);
887+
const char* replacementName = pNewTexture ? pNewTexture->name : nullptr;
849888

850889
RwTexture* pExistingTexture = LookupOriginalTexture(*pInfo, replacementName);
851-
if (!pExistingTexture && bHasValidTxd && !replacementName.empty())
890+
if (!pExistingTexture && bHasValidTxd && replacementName && replacementName[0] != '\0')
852891
pExistingTexture = RwTexDictionaryFindNamedTexture(pInfo->pTxd, pNewTexture->name);
853892

854893
if (pExistingTexture && bHasValidTxd)

0 commit comments

Comments
 (0)