diff --git a/docs/SupportedAssetTypes.md b/docs/SupportedAssetTypes.md index 7bbf4154..aa503afb 100644 --- a/docs/SupportedAssetTypes.md +++ b/docs/SupportedAssetTypes.md @@ -18,7 +18,7 @@ The following section specify which assets are supported to be dumped to disk (u | MaterialTechniqueSet | ✅ | ✅ | For shaders: only dumps/loads shader bytecode. | | GfxImage | ✅ | ✅ | | | snd_alias_list_t | ❌ | ❌ | | -| SndCurve | ❌ | ❌ | | +| SndCurve | ✅ | ✅ | | | LoadedSound | ✅ | ❌ | | | clipMap_t | ❌ | ❌ | | | ComWorld | ❌ | ❌ | | @@ -93,7 +93,7 @@ The following section specify which assets are supported to be dumped to disk (u | MaterialTechniqueSet | ❌ | ❌ | | | GfxImage | ✅ | ✅ | A few special image encodings are not yet supported. | | snd_alias_list_t | ❌ | ❌ | | -| SndCurve | ❌ | ❌ | | +| SndCurve | ✅ | ✅ | | | LoadedSound | ✅ | ❌ | | | clipMap_t | ❌ | ❌ | | | ComWorld | ❌ | ❌ | | diff --git a/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp b/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp index b36c4e5a..f7532754 100644 --- a/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp +++ b/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp @@ -15,6 +15,7 @@ #include "PhysPreset/GdtLoaderPhysPresetIW3.h" #include "PhysPreset/RawLoaderPhysPresetIW3.h" #include "RawFile/AssetLoaderRawFileIW3.h" +#include "Sound/LoaderSoundCurveIW3.h" #include "StringTable/AssetLoaderStringTableIW3.h" #include @@ -104,7 +105,7 @@ namespace collection.AddAssetCreator(image::CreateLoaderEmbeddedIW3(memory, searchPath)); collection.AddAssetCreator(image::CreateLoaderExternalIW3(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); - // collection.AddAssetCreator(std::make_unique(memory)); + collection.AddAssetCreator(sound_curve::CreateLoaderIW3(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/IW3/Sound/LoaderSoundCurveIW3.cpp b/src/ObjLoading/Game/IW3/Sound/LoaderSoundCurveIW3.cpp new file mode 100644 index 00000000..fabbd089 --- /dev/null +++ b/src/ObjLoading/Game/IW3/Sound/LoaderSoundCurveIW3.cpp @@ -0,0 +1,80 @@ +#include "LoaderSoundCurveIW3.h" + +#include "Game/IW3/IW3.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 IW3; + +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> CreateLoaderIW3(MemoryManager& memory, ISearchPath& searchPath) + { + return std::make_unique(memory, searchPath); + } +} // namespace sound_curve diff --git a/src/ObjLoading/Game/IW3/Sound/LoaderSoundCurveIW3.h b/src/ObjLoading/Game/IW3/Sound/LoaderSoundCurveIW3.h new file mode 100644 index 00000000..08dae2ad --- /dev/null +++ b/src/ObjLoading/Game/IW3/Sound/LoaderSoundCurveIW3.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Game/IW3/IW3.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +namespace sound_curve +{ + std::unique_ptr> CreateLoaderIW3(MemoryManager& memory, ISearchPath& searchPath); +} // namespace sound_curve diff --git a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp index 8023011f..a015ee7d 100644 --- a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp +++ b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp @@ -18,6 +18,7 @@ #include "PhysPreset/RawLoaderPhysPresetIW5.h" #include "RawFile/LoaderRawFileIW5.h" #include "Script/LoaderScriptFileIW5.h" +#include "Sound/LoaderSoundCurveIW5.h" #include "StringTable/LoaderStringTableIW5.h" #include "Weapon/GdtLoaderWeaponIW5.h" #include "Weapon/LoaderAttachmentIW5.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/IW3/ObjWriterIW3.cpp b/src/ObjWriting/Game/IW3/ObjWriterIW3.cpp index dfaa23c9..e81c2c37 100644 --- a/src/ObjWriting/Game/IW3/ObjWriterIW3.cpp +++ b/src/ObjWriting/Game/IW3/ObjWriterIW3.cpp @@ -9,6 +9,7 @@ #include "PhysPreset/PhysPresetInfoStringDumperIW3.h" #include "RawFile/RawFileDumperIW3.h" #include "Sound/LoadedSoundDumperIW3.h" +#include "Sound/SndCurveDumperIW3.h" #include "StringTable/StringTableDumperIW3.h" using namespace IW3; @@ -28,7 +29,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) // REGISTER_DUMPER(AssetDumperComWorld) diff --git a/src/ObjWriting/Game/IW3/Sound/SndCurveDumperIW3.cpp b/src/ObjWriting/Game/IW3/Sound/SndCurveDumperIW3.cpp new file mode 100644 index 00000000..d3ab138e --- /dev/null +++ b/src/ObjWriting/Game/IW3/Sound/SndCurveDumperIW3.cpp @@ -0,0 +1,27 @@ +#include "SndCurveDumperIW3.h" + +#include "Sound/SndCurveDumper.h" +#include "Sound/SoundCurveCommon.h" + +using namespace IW3; + +namespace sound_curve +{ + void DumperIW3::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/IW3/Sound/SndCurveDumperIW3.h b/src/ObjWriting/Game/IW3/Sound/SndCurveDumperIW3.h new file mode 100644 index 00000000..20ba622c --- /dev/null +++ b/src/ObjWriting/Game/IW3/Sound/SndCurveDumperIW3.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/IW3/IW3.h" + +namespace sound_curve +{ + class DumperIW3 final : public AbstractAssetDumper + { + protected: + void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; + }; +} // namespace sound_curve diff --git a/src/ObjWriting/Game/IW5/ObjWriterIW5.cpp b/src/ObjWriting/Game/IW5/ObjWriterIW5.cpp index d720cecd..92e33973 100644 --- a/src/ObjWriting/Game/IW5/ObjWriterIW5.cpp +++ b/src/ObjWriting/Game/IW5/ObjWriterIW5.cpp @@ -15,6 +15,7 @@ #include "RawFile/RawFileDumperIW5.h" #include "Script/ScriptDumperIW5.h" #include "Sound/LoadedSoundDumperIW5.h" +#include "Sound/SndCurveDumperIW5.h" #include "StringTable/StringTableDumperIW5.h" #include "Weapon/AttachmentJsonDumperIW5.h" #include "Weapon/WeaponDumperIW5.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