From b282e611fc16484934bd8fa4754f2a9c21ac92c7 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 9 Sep 2024 18:46:39 +0200 Subject: [PATCH] refactor: extract PartClassificationState from JsonXModelLoader --- .../Game/T6/XModel/JsonXModelLoader.cpp | 82 +------------------ .../XModel/PartClassificationState.cpp | 79 ++++++++++++++++++ .../XModel/PartClassificationState.h | 24 ++++++ 3 files changed, 105 insertions(+), 80 deletions(-) create mode 100644 src/ObjLoading/XModel/PartClassificationState.cpp create mode 100644 src/ObjLoading/XModel/PartClassificationState.h diff --git a/src/ObjLoading/Game/T6/XModel/JsonXModelLoader.cpp b/src/ObjLoading/Game/T6/XModel/JsonXModelLoader.cpp index bb8d40cd..2f0639c1 100644 --- a/src/ObjLoading/Game/T6/XModel/JsonXModelLoader.cpp +++ b/src/ObjLoading/Game/T6/XModel/JsonXModelLoader.cpp @@ -15,6 +15,7 @@ #include #pragma warning(pop) +#include "XModel/PartClassificationState.h" #include "XModel/Tangentspace.h" #include @@ -59,85 +60,6 @@ namespace }; static_assert(std::extent_v == HITLOC_COUNT); - class PartClassificationState final : public IZoneAssetLoaderState - { - // TODO: Use MP part classifications when building an mp fastfile - static constexpr auto PART_CLASSIFICATION_FILE = "partclassification.csv"; - - public: - PartClassificationState() - : m_loaded(false) - { - } - - bool Load(const IAssetLoadingManager& manager) - { - if (m_loaded) - return true; - - if (ObjLoading::Configuration.Verbose) - std::cout << "Loading part classification...\n"; - - const auto file = manager.GetAssetLoadingContext()->m_raw_search_path->Open(PART_CLASSIFICATION_FILE); - if (!file.IsOpen()) - { - std::cerr << std::format("Could not load part classification: Failed to open {}\n", PART_CLASSIFICATION_FILE); - return false; - } - - CsvInputStream csvStream(*file.m_stream); - std::vector row; - auto rowIndex = 0u; - while (csvStream.NextRow(row)) - { - if (!LoadRow(rowIndex++, row)) - return false; - } - - m_loaded = true; - - return false; - } - - [[nodiscard]] unsigned GetPartClassificationForBoneName(const std::string& boneName) const - { - const auto entry = m_part_classifications.find(boneName); - - return entry != m_part_classifications.end() ? entry->second : HITLOC_NONE; - } - - private: - bool LoadRow(const unsigned rowIndex, std::vector& row) - { - if (row.empty()) - return true; - - if (row.size() != 2) - { - std::cerr << "Could not load part classification: Invalid row\n"; - return false; - } - - utils::MakeStringLowerCase(row[0]); - utils::MakeStringLowerCase(row[1]); - - const auto foundHitLoc = std::ranges::find(HITLOC_NAMES, row[1]); - if (foundHitLoc == std::end(HITLOC_NAMES)) - { - std::cerr << std::format("Invalid hitloc name in row {}: {}\n", rowIndex + 1, row[1]); - return false; - } - - const auto hitLocNum = std::distance(std::begin(HITLOC_NAMES), foundHitLoc); - - m_part_classifications.emplace(row[0], hitLocNum); - return true; - } - - bool m_loaded; - std::unordered_map m_part_classifications; - }; - class TangentData { public: @@ -362,7 +284,7 @@ namespace if (common.m_bones.empty()) return true; - m_part_classification_state.Load(m_manager); + m_part_classification_state.Load(HITLOC_NAMES, std::extent_v, m_manager); const auto boneCount = common.m_bones.size(); constexpr auto maxBones = std::numeric_limits::max(); diff --git a/src/ObjLoading/XModel/PartClassificationState.cpp b/src/ObjLoading/XModel/PartClassificationState.cpp new file mode 100644 index 00000000..a09e3374 --- /dev/null +++ b/src/ObjLoading/XModel/PartClassificationState.cpp @@ -0,0 +1,79 @@ +#include "PartClassificationState.h" + +#include "Csv/CsvStream.h" +#include "ObjLoading.h" +#include "Utils/StringUtils.h" + +#include +#include + +PartClassificationState::PartClassificationState() + : m_loaded(false) +{ +} + +bool PartClassificationState::Load(const char** hitLocNames, const size_t hitLocNameCount, const IAssetLoadingManager& manager) +{ + if (m_loaded) + return true; + + if (ObjLoading::Configuration.Verbose) + std::cout << "Loading part classification...\n"; + + const auto file = manager.GetAssetLoadingContext()->m_raw_search_path->Open(PART_CLASSIFICATION_FILE); + if (!file.IsOpen()) + { + std::cerr << std::format("Could not load part classification: Failed to open {}\n", PART_CLASSIFICATION_FILE); + return false; + } + + const auto hitLocStart = hitLocNames; + const auto hitLocEnd = &hitLocNames[hitLocNameCount]; + + const CsvInputStream csvStream(*file.m_stream); + std::vector row; + auto rowIndex = 0u; + while (csvStream.NextRow(row)) + { + if (!LoadRow(hitLocStart, hitLocEnd, rowIndex++, row)) + return false; + } + + m_loaded = true; + + return false; +} + +[[nodiscard]] unsigned PartClassificationState::GetPartClassificationForBoneName(const std::string& boneName) const +{ + const auto entry = m_part_classifications.find(boneName); + + return entry != m_part_classifications.end() ? entry->second : HITLOC_NONE; +} + +bool PartClassificationState::LoadRow(const char** hitLocStart, const char** hitLocEnd, const unsigned rowIndex, std::vector& row) +{ + if (row.empty()) + return true; + + if (row.size() != 2) + { + std::cerr << "Could not load part classification: Invalid row\n"; + return false; + } + + utils::MakeStringLowerCase(row[0]); + utils::MakeStringLowerCase(row[1]); + + const auto foundHitLoc = std::find(hitLocStart, hitLocEnd, row[1]); + if (foundHitLoc == hitLocEnd) + { + std::cerr << std::format("Invalid hitloc name in row {}: {}\n", rowIndex + 1, row[1]); + return false; + } + + const auto hitLocNum = std::distance(hitLocStart, foundHitLoc); + + m_part_classifications.emplace(row[0], hitLocNum); + return true; +} diff --git a/src/ObjLoading/XModel/PartClassificationState.h b/src/ObjLoading/XModel/PartClassificationState.h new file mode 100644 index 00000000..32bd4afc --- /dev/null +++ b/src/ObjLoading/XModel/PartClassificationState.h @@ -0,0 +1,24 @@ +#pragma once +#include "AssetLoading/IAssetLoadingManager.h" +#include "AssetLoading/IZoneAssetLoaderState.h" + +class PartClassificationState final : public IZoneAssetLoaderState +{ + // TODO: Use MP part classifications when building an mp fastfile + static constexpr auto PART_CLASSIFICATION_FILE = "partclassification.csv"; + + static constexpr auto HITLOC_NONE = 0u; + +public: + PartClassificationState(); + + bool Load(const char** hitLocNames, size_t hitLocNameCount, const IAssetLoadingManager& manager); + + [[nodiscard]] unsigned GetPartClassificationForBoneName(const std::string& boneName) const; + +private: + bool LoadRow(const char** hitLocStart, const char** hitLocEnd, unsigned rowIndex, std::vector& row); + + bool m_loaded; + std::unordered_map m_part_classifications; +};