From 0eb1f9f978dba6b41d5c500dc9469437b97e0118 Mon Sep 17 00:00:00 2001 From: njohnson Date: Fri, 1 May 2026 16:32:51 -0400 Subject: [PATCH] Add IW5 SndCurve dumper. --- src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp | 3 +- .../Game/IW5/Sound/LoaderSoundCurveIW5.cpp | 80 +++++++++++++++++++ .../Game/IW5/Sound/LoaderSoundCurveIW5.h | 13 +++ src/ObjWriting/Game/IW5/ObjWriterIW5.cpp | 3 +- .../Game/IW5/Sound/SndCurveDumperIW5.cpp | 27 +++++++ .../Game/IW5/Sound/SndCurveDumperIW5.h | 13 +++ 6 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 src/ObjLoading/Game/IW5/Sound/LoaderSoundCurveIW5.cpp create mode 100644 src/ObjLoading/Game/IW5/Sound/LoaderSoundCurveIW5.h create mode 100644 src/ObjWriting/Game/IW5/Sound/SndCurveDumperIW5.cpp create mode 100644 src/ObjWriting/Game/IW5/Sound/SndCurveDumperIW5.h diff --git a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp index 8023011f..60a79733 100644 --- a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp +++ b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp @@ -6,6 +6,7 @@ #include "Game/IW5/IW5.h" #include "Game/IW5/Image/ImageLoaderEmbeddedIW5.h" #include "Game/IW5/Image/ImageLoaderExternalIW5.h" +#include "Sound/LoaderSoundCurveIW5.h" #include "Game/IW5/Techset/PixelShaderLoaderIW5.h" #include "Game/IW5/Techset/VertexShaderLoaderIW5.h" #include "Game/IW5/XModel/LoaderXModelIW5.h" @@ -140,7 +141,7 @@ namespace collection.AddAssetCreator(image::CreateLoaderEmbeddedIW5(memory, searchPath)); collection.AddAssetCreator(image::CreateLoaderExternalIW5(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); - // collection.AddAssetCreator(std::make_unique(memory)); + collection.AddAssetCreator(sound_curve::CreateLoaderIW5(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); diff --git a/src/ObjLoading/Game/IW5/Sound/LoaderSoundCurveIW5.cpp b/src/ObjLoading/Game/IW5/Sound/LoaderSoundCurveIW5.cpp new file mode 100644 index 00000000..5b197935 --- /dev/null +++ b/src/ObjLoading/Game/IW5/Sound/LoaderSoundCurveIW5.cpp @@ -0,0 +1,80 @@ +#include "LoaderSoundCurveIW5.h" + +#include "Game/IW5/IW5.h" +#include "ObjLoading.h" +#include "Parsing/Graph2D/Graph2DReader.h" +#include "Pool/GlobalAssetPool.h" +#include "Sound/SoundCurveCommon.h" +#include "Utils/Logging/Log.h" + +#include +#include +#include +#include + +using namespace IW5; + +namespace +{ + class LoaderSoundCurve final : public AssetCreator + { + public: + LoaderSoundCurve(MemoryManager& memory, ISearchPath& searchPath) + : m_memory(memory), + m_search_path(searchPath) + { + } + + AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override + { + const auto fileName = sound_curve::GetFileNameForAssetName(assetName); + const auto file = m_search_path.Open(fileName); + if (!file.IsOpen()) + return AssetCreationResult::NoAction(); + + const auto sndCurveData = graph2d::Read("sound curve", "SNDCURVE", *file.m_stream, fileName, assetName); + + if (!sndCurveData) + return AssetCreationResult::Failure(); + + if (sndCurveData->knots.size() > std::extent_v) + { + con::error("Failed to load SndCurve \"{}\": Too many knots ({})", assetName, sndCurveData->knots.size()); + return AssetCreationResult::Failure(); + } + + auto* sndCurve = m_memory.Alloc(); + sndCurve->filename = m_memory.Dup(assetName.c_str()); + sndCurve->knotCount = static_cast(sndCurveData->knots.size()); + + for (auto i = 0u; i < std::extent_v; i++) + { + if (i < sndCurveData->knots.size()) + { + const auto& [x, y] = sndCurveData->knots[i]; + sndCurve->knots[i][0] = static_cast(x); + sndCurve->knots[i][1] = static_cast(y); + } + else + { + sndCurve->knots[i][0] = 0; + sndCurve->knots[i][1] = 0; + } + } + + return AssetCreationResult::Success(context.AddAsset(assetName, sndCurve)); + } + + private: + MemoryManager& m_memory; + ISearchPath& m_search_path; + }; +} // namespace + +namespace sound_curve +{ + std::unique_ptr> CreateLoaderIW5(MemoryManager& memory, ISearchPath& searchPath) + { + return std::make_unique(memory, searchPath); + } +} // namespace sound_curve diff --git a/src/ObjLoading/Game/IW5/Sound/LoaderSoundCurveIW5.h b/src/ObjLoading/Game/IW5/Sound/LoaderSoundCurveIW5.h new file mode 100644 index 00000000..df7b320b --- /dev/null +++ b/src/ObjLoading/Game/IW5/Sound/LoaderSoundCurveIW5.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Game/IW5/IW5.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +namespace sound_curve +{ + std::unique_ptr> CreateLoaderIW5(MemoryManager& memory, ISearchPath& searchPath); +} // namespace sound_curve diff --git a/src/ObjWriting/Game/IW5/ObjWriterIW5.cpp b/src/ObjWriting/Game/IW5/ObjWriterIW5.cpp index d720cecd..ca09c0d8 100644 --- a/src/ObjWriting/Game/IW5/ObjWriterIW5.cpp +++ b/src/ObjWriting/Game/IW5/ObjWriterIW5.cpp @@ -6,6 +6,7 @@ #include "Game/IW5/Techset/VertexShaderDumperIW5.h" #include "Game/IW5/XModel/XModelDumperIW5.h" #include "Image/ImageDumperIW5.h" +#include "Sound/SndCurveDumperIW5.h" #include "Leaderboard/LeaderboardJsonDumperIW5.h" #include "Localize/LocalizeDumperIW5.h" #include "Maps/AddonMapEntsDumperIW5.h" @@ -40,7 +41,7 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context) )); RegisterAssetDumper(std::make_unique()); // REGISTER_DUMPER(AssetDumpersnd_alias_list_t) - // REGISTER_DUMPER(AssetDumperSndCurve) + RegisterAssetDumper(std::make_unique()); RegisterAssetDumper(std::make_unique()); // REGISTER_DUMPER(AssetDumperclipMap_t) // REGISTER_DUMPER(AssetDumperComWorld) diff --git a/src/ObjWriting/Game/IW5/Sound/SndCurveDumperIW5.cpp b/src/ObjWriting/Game/IW5/Sound/SndCurveDumperIW5.cpp new file mode 100644 index 00000000..d192a84a --- /dev/null +++ b/src/ObjWriting/Game/IW5/Sound/SndCurveDumperIW5.cpp @@ -0,0 +1,27 @@ +#include "SndCurveDumperIW5.h" + +#include "Sound/SndCurveDumper.h" +#include "Sound/SoundCurveCommon.h" + +using namespace IW5; + +namespace sound_curve +{ + void DumperIW5::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) + { + const auto* sndCurve = asset.Asset(); + + const auto assetFile = context.OpenAssetFile(GetFileNameForAssetName(sndCurve->filename)); + + if (!assetFile) + return; + + SndCurveDumper dumper(*assetFile); + + const auto knotCount = std::min(static_cast(sndCurve->knotCount), std::extent_v); + dumper.Init(knotCount); + + for (auto i = 0u; i < knotCount; i++) + dumper.WriteKnot(sndCurve->knots[i][0], sndCurve->knots[i][1]); + } +} // namespace sound_curve diff --git a/src/ObjWriting/Game/IW5/Sound/SndCurveDumperIW5.h b/src/ObjWriting/Game/IW5/Sound/SndCurveDumperIW5.h new file mode 100644 index 00000000..c0735968 --- /dev/null +++ b/src/ObjWriting/Game/IW5/Sound/SndCurveDumperIW5.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/IW5/IW5.h" + +namespace sound_curve +{ + class DumperIW5 final : public AbstractAssetDumper + { + protected: + void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; + }; +} // namespace sound_curve