From 3233186d8be3aa81b05410f5a6a0b44f102b7822 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 22 Aug 2023 17:20:43 +0200 Subject: [PATCH] Add AssetLoader for IW5 StringTable --- src/Common/Game/IW5/CommonIW5.cpp | 16 ++++ src/Common/Game/IW5/CommonIW5.h | 2 + .../AssetLoaders/AssetLoaderStringTable.cpp | 79 +++++++++++++++++++ .../IW5/AssetLoaders/AssetLoaderStringTable.h | 16 ++++ src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp | 3 +- 5 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderStringTable.cpp create mode 100644 src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderStringTable.h diff --git a/src/Common/Game/IW5/CommonIW5.cpp b/src/Common/Game/IW5/CommonIW5.cpp index 569399aa..de2fc41e 100644 --- a/src/Common/Game/IW5/CommonIW5.cpp +++ b/src/Common/Game/IW5/CommonIW5.cpp @@ -4,6 +4,22 @@ using namespace IW5; +int Common::StringTable_HashString(const char* str) +{ + if (!str) + return 0; + + auto result = 0; + auto offset = 0; + while (str[offset]) + { + const auto c = tolower(str[offset++]); + result = c + 31 * result; + } + + return result; +} + PackedTexCoords Common::Vec2PackTexCoords(const vec2_t* in) { return PackedTexCoords{ Pack32::Vec2PackTexCoords(reinterpret_cast(in)) }; diff --git a/src/Common/Game/IW5/CommonIW5.h b/src/Common/Game/IW5/CommonIW5.h index a081144c..818c5066 100644 --- a/src/Common/Game/IW5/CommonIW5.h +++ b/src/Common/Game/IW5/CommonIW5.h @@ -7,6 +7,8 @@ namespace IW5 class Common { public: + static int StringTable_HashString(const char* str); + static PackedTexCoords Vec2PackTexCoords(const vec2_t* in); static PackedUnitVec Vec3PackUnitVec(const vec3_t* in); static GfxColor Vec4PackGfxColor(const vec4_t* in); diff --git a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderStringTable.cpp b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderStringTable.cpp new file mode 100644 index 00000000..95171e8f --- /dev/null +++ b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderStringTable.cpp @@ -0,0 +1,79 @@ +#include "AssetLoaderStringTable.h" + +#include + +#include "ObjLoading.h" +#include "Csv/CsvStream.h" +#include "Game/IW5/CommonIW5.h" +#include "Game/IW5/IW5.h" +#include "Pool/GlobalAssetPool.h" + +using namespace IW5; + +void* AssetLoaderStringTable::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) +{ + auto* stringTable = memory->Create(); + memset(stringTable, 0, sizeof(StringTable)); + stringTable->name = memory->Dup(assetName.c_str()); + return stringTable; +} + +bool AssetLoaderStringTable::CanLoadFromRaw() const +{ + return true; +} + +bool AssetLoaderStringTable::LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const +{ + const auto file = searchPath->Open(assetName); + if (!file.IsOpen()) + return false; + + auto* stringTable = memory->Create(); + stringTable->name = memory->Dup(assetName.c_str()); + + std::vector> csvLines; + std::vector currentLine; + auto maxCols = 0u; + const CsvInputStream csv(*file.m_stream); + + while (csv.NextRow(currentLine)) + { + if (currentLine.size() > maxCols) + maxCols = currentLine.size(); + csvLines.emplace_back(std::move(currentLine)); + currentLine = std::vector(); + } + + stringTable->columnCount = static_cast(maxCols); + stringTable->rowCount = static_cast(csvLines.size()); + const auto cellCount = static_cast(stringTable->rowCount) * static_cast(stringTable->columnCount); + + if (cellCount) + { + stringTable->values = static_cast(memory->Alloc(sizeof(StringTableCell) * cellCount)); + + for (auto row = 0u; row < csvLines.size(); row++) + { + const auto& rowValues = csvLines[row]; + for (auto col = 0u; col < maxCols; col++) + { + auto& cell = stringTable->values[row * maxCols + col]; + if (col >= rowValues.size() || rowValues[col].empty()) + cell.string = ""; + else + cell.string = memory->Dup(rowValues[col].c_str()); + + cell.hash = Common::StringTable_HashString(cell.string); + } + } + } + else + { + stringTable->values = nullptr; + } + + manager->AddAsset(ASSET_TYPE_STRINGTABLE, assetName, stringTable); + + return true; +} diff --git a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderStringTable.h b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderStringTable.h new file mode 100644 index 00000000..428d03f3 --- /dev/null +++ b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderStringTable.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Game/IW5/IW5.h" +#include "AssetLoading/BasicAssetLoader.h" +#include "SearchPath/ISearchPath.h" + +namespace IW5 +{ + class AssetLoaderStringTable final : public BasicAssetLoader + { + public: + _NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override; + _NODISCARD bool CanLoadFromRaw() const override; + bool LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; + }; +} diff --git a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp index 804c3c4c..b67726dd 100644 --- a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp +++ b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp @@ -6,6 +6,7 @@ #include "ObjLoading.h" #include "AssetLoaders/AssetLoaderLocalizeEntry.h" #include "AssetLoaders/AssetLoaderRawFile.h" +#include "AssetLoaders/AssetLoaderStringTable.h" #include "AssetLoading/AssetLoadingManager.h" #include "Image/Dx9TextureLoader.h" #include "Image/Texture.h" @@ -53,7 +54,7 @@ ObjLoader::ObjLoader() REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_SURFACE_FX, SurfaceFxTable)) REGISTER_ASSET_LOADER(AssetLoaderRawFile) REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_SCRIPTFILE, ScriptFile)) - REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_STRINGTABLE, StringTable)) + REGISTER_ASSET_LOADER(AssetLoaderStringTable) REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_LEADERBOARD, LeaderboardDef)) REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_STRUCTURED_DATA_DEF, StructuredDataDefSet)) REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_TRACER, TracerDef))