2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-05-12 21:31:43 +00:00

Add IW3 & IW5 SndCurve Dumping & Loading Logic (#766)

* Add dumper and loader call to parents.

* Update docs.

* Add loader logic from IW4.

* Add dumper logic from IW4.

* Update docs.

* Add IW5 SndCurve dumper.

* Clang format.

---------

Co-authored-by: njohnson <gitea.nicholasjohnson.info>
This commit is contained in:
Jan
2026-05-02 12:52:19 +02:00
committed by GitHub
13 changed files with 276 additions and 6 deletions
+2 -2
View File
@@ -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. | | MaterialTechniqueSet | ✅ | ✅ | For shaders: only dumps/loads shader bytecode. |
| GfxImage | ✅ | ✅ | | | GfxImage | ✅ | ✅ | |
| snd_alias_list_t | ❌ | ❌ | | | snd_alias_list_t | ❌ | ❌ | |
| SndCurve | | | | | SndCurve | | | |
| LoadedSound | ✅ | ❌ | | | LoadedSound | ✅ | ❌ | |
| clipMap_t | ❌ | ❌ | | | clipMap_t | ❌ | ❌ | |
| ComWorld | ❌ | ❌ | | | ComWorld | ❌ | ❌ | |
@@ -93,7 +93,7 @@ The following section specify which assets are supported to be dumped to disk (u
| MaterialTechniqueSet | ❌ | ❌ | | | MaterialTechniqueSet | ❌ | ❌ | |
| GfxImage | ✅ | ✅ | A few special image encodings are not yet supported. | | GfxImage | ✅ | ✅ | A few special image encodings are not yet supported. |
| snd_alias_list_t | ❌ | ❌ | | | snd_alias_list_t | ❌ | ❌ | |
| SndCurve | | | | | SndCurve | | | |
| LoadedSound | ✅ | ❌ | | | LoadedSound | ✅ | ❌ | |
| clipMap_t | ❌ | ❌ | | | clipMap_t | ❌ | ❌ | |
| ComWorld | ❌ | ❌ | | | ComWorld | ❌ | ❌ | |
+2 -1
View File
@@ -15,6 +15,7 @@
#include "PhysPreset/GdtLoaderPhysPresetIW3.h" #include "PhysPreset/GdtLoaderPhysPresetIW3.h"
#include "PhysPreset/RawLoaderPhysPresetIW3.h" #include "PhysPreset/RawLoaderPhysPresetIW3.h"
#include "RawFile/AssetLoaderRawFileIW3.h" #include "RawFile/AssetLoaderRawFileIW3.h"
#include "Sound/LoaderSoundCurveIW3.h"
#include "StringTable/AssetLoaderStringTableIW3.h" #include "StringTable/AssetLoaderStringTableIW3.h"
#include <memory> #include <memory>
@@ -104,7 +105,7 @@ namespace
collection.AddAssetCreator(image::CreateLoaderEmbeddedIW3(memory, searchPath)); collection.AddAssetCreator(image::CreateLoaderEmbeddedIW3(memory, searchPath));
collection.AddAssetCreator(image::CreateLoaderExternalIW3(memory, searchPath)); collection.AddAssetCreator(image::CreateLoaderExternalIW3(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderSound>(memory)); // collection.AddAssetCreator(std::make_unique<AssetLoaderSound>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderSoundCurve>(memory)); collection.AddAssetCreator(sound_curve::CreateLoaderIW3(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderLoadedSound>(memory)); // collection.AddAssetCreator(std::make_unique<AssetLoaderLoadedSound>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderClipMapPvs>(memory)); // collection.AddAssetCreator(std::make_unique<AssetLoaderClipMapPvs>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderComWorld>(memory)); // collection.AddAssetCreator(std::make_unique<AssetLoaderComWorld>(memory));
@@ -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 <cstring>
#include <format>
#include <iostream>
#include <sstream>
using namespace IW3;
namespace
{
class LoaderSoundCurve final : public AssetCreator<AssetSoundCurve>
{
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<decltype(SndCurve::knots)>)
{
con::error("Failed to load SndCurve \"{}\": Too many knots ({})", assetName, sndCurveData->knots.size());
return AssetCreationResult::Failure();
}
auto* sndCurve = m_memory.Alloc<SndCurve>();
sndCurve->filename = m_memory.Dup(assetName.c_str());
sndCurve->knotCount = static_cast<uint16_t>(sndCurveData->knots.size());
for (auto i = 0u; i < std::extent_v<decltype(SndCurve::knots)>; i++)
{
if (i < sndCurveData->knots.size())
{
const auto& [x, y] = sndCurveData->knots[i];
sndCurve->knots[i][0] = static_cast<float>(x);
sndCurve->knots[i][1] = static_cast<float>(y);
}
else
{
sndCurve->knots[i][0] = 0;
sndCurve->knots[i][1] = 0;
}
}
return AssetCreationResult::Success(context.AddAsset<AssetSoundCurve>(assetName, sndCurve));
}
private:
MemoryManager& m_memory;
ISearchPath& m_search_path;
};
} // namespace
namespace sound_curve
{
std::unique_ptr<AssetCreator<AssetSoundCurve>> CreateLoaderIW3(MemoryManager& memory, ISearchPath& searchPath)
{
return std::make_unique<LoaderSoundCurve>(memory, searchPath);
}
} // namespace sound_curve
@@ -0,0 +1,13 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "Game/IW3/IW3.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
namespace sound_curve
{
std::unique_ptr<AssetCreator<IW3::AssetSoundCurve>> CreateLoaderIW3(MemoryManager& memory, ISearchPath& searchPath);
} // namespace sound_curve
+2 -1
View File
@@ -18,6 +18,7 @@
#include "PhysPreset/RawLoaderPhysPresetIW5.h" #include "PhysPreset/RawLoaderPhysPresetIW5.h"
#include "RawFile/LoaderRawFileIW5.h" #include "RawFile/LoaderRawFileIW5.h"
#include "Script/LoaderScriptFileIW5.h" #include "Script/LoaderScriptFileIW5.h"
#include "Sound/LoaderSoundCurveIW5.h"
#include "StringTable/LoaderStringTableIW5.h" #include "StringTable/LoaderStringTableIW5.h"
#include "Weapon/GdtLoaderWeaponIW5.h" #include "Weapon/GdtLoaderWeaponIW5.h"
#include "Weapon/LoaderAttachmentIW5.h" #include "Weapon/LoaderAttachmentIW5.h"
@@ -140,7 +141,7 @@ namespace
collection.AddAssetCreator(image::CreateLoaderEmbeddedIW5(memory, searchPath)); collection.AddAssetCreator(image::CreateLoaderEmbeddedIW5(memory, searchPath));
collection.AddAssetCreator(image::CreateLoaderExternalIW5(memory, searchPath)); collection.AddAssetCreator(image::CreateLoaderExternalIW5(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderSound>(memory)); // collection.AddAssetCreator(std::make_unique<AssetLoaderSound>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderSoundCurve>(memory)); collection.AddAssetCreator(sound_curve::CreateLoaderIW5(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderLoadedSound>(memory)); // collection.AddAssetCreator(std::make_unique<AssetLoaderLoadedSound>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderClipMap>(memory)); // collection.AddAssetCreator(std::make_unique<AssetLoaderClipMap>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderComWorld>(memory)); // collection.AddAssetCreator(std::make_unique<AssetLoaderComWorld>(memory));
@@ -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 <cstring>
#include <format>
#include <iostream>
#include <sstream>
using namespace IW5;
namespace
{
class LoaderSoundCurve final : public AssetCreator<AssetSoundCurve>
{
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<decltype(SndCurve::knots)>)
{
con::error("Failed to load SndCurve \"{}\": Too many knots ({})", assetName, sndCurveData->knots.size());
return AssetCreationResult::Failure();
}
auto* sndCurve = m_memory.Alloc<SndCurve>();
sndCurve->filename = m_memory.Dup(assetName.c_str());
sndCurve->knotCount = static_cast<uint16_t>(sndCurveData->knots.size());
for (auto i = 0u; i < std::extent_v<decltype(SndCurve::knots)>; i++)
{
if (i < sndCurveData->knots.size())
{
const auto& [x, y] = sndCurveData->knots[i];
sndCurve->knots[i][0] = static_cast<float>(x);
sndCurve->knots[i][1] = static_cast<float>(y);
}
else
{
sndCurve->knots[i][0] = 0;
sndCurve->knots[i][1] = 0;
}
}
return AssetCreationResult::Success(context.AddAsset<AssetSoundCurve>(assetName, sndCurve));
}
private:
MemoryManager& m_memory;
ISearchPath& m_search_path;
};
} // namespace
namespace sound_curve
{
std::unique_ptr<AssetCreator<AssetSoundCurve>> CreateLoaderIW5(MemoryManager& memory, ISearchPath& searchPath)
{
return std::make_unique<LoaderSoundCurve>(memory, searchPath);
}
} // namespace sound_curve
@@ -0,0 +1,13 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "Game/IW5/IW5.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
namespace sound_curve
{
std::unique_ptr<AssetCreator<IW5::AssetSoundCurve>> CreateLoaderIW5(MemoryManager& memory, ISearchPath& searchPath);
} // namespace sound_curve
+2 -1
View File
@@ -9,6 +9,7 @@
#include "PhysPreset/PhysPresetInfoStringDumperIW3.h" #include "PhysPreset/PhysPresetInfoStringDumperIW3.h"
#include "RawFile/RawFileDumperIW3.h" #include "RawFile/RawFileDumperIW3.h"
#include "Sound/LoadedSoundDumperIW3.h" #include "Sound/LoadedSoundDumperIW3.h"
#include "Sound/SndCurveDumperIW3.h"
#include "StringTable/StringTableDumperIW3.h" #include "StringTable/StringTableDumperIW3.h"
using namespace IW3; using namespace IW3;
@@ -28,7 +29,7 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context)
)); ));
RegisterAssetDumper(std::make_unique<image::DumperIW3>()); RegisterAssetDumper(std::make_unique<image::DumperIW3>());
// REGISTER_DUMPER(AssetDumpersnd_alias_list_t) // REGISTER_DUMPER(AssetDumpersnd_alias_list_t)
// REGISTER_DUMPER(AssetDumperSndCurve) RegisterAssetDumper(std::make_unique<sound_curve::DumperIW3>());
RegisterAssetDumper(std::make_unique<sound::LoadedSoundDumperIW3>()); RegisterAssetDumper(std::make_unique<sound::LoadedSoundDumperIW3>());
// REGISTER_DUMPER(AssetDumperClipMap) // REGISTER_DUMPER(AssetDumperClipMap)
// REGISTER_DUMPER(AssetDumperComWorld) // REGISTER_DUMPER(AssetDumperComWorld)
@@ -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<AssetSoundCurve::Type>& 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<size_t>(sndCurve->knotCount), std::extent_v<decltype(SndCurve::knots)>);
dumper.Init(knotCount);
for (auto i = 0u; i < knotCount; i++)
dumper.WriteKnot(sndCurve->knots[i][0], sndCurve->knots[i][1]);
}
} // namespace sound_curve
@@ -0,0 +1,13 @@
#pragma once
#include "Dumping/AbstractAssetDumper.h"
#include "Game/IW3/IW3.h"
namespace sound_curve
{
class DumperIW3 final : public AbstractAssetDumper<IW3::AssetSoundCurve>
{
protected:
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<IW3::AssetSoundCurve::Type>& asset) override;
};
} // namespace sound_curve
+2 -1
View File
@@ -15,6 +15,7 @@
#include "RawFile/RawFileDumperIW5.h" #include "RawFile/RawFileDumperIW5.h"
#include "Script/ScriptDumperIW5.h" #include "Script/ScriptDumperIW5.h"
#include "Sound/LoadedSoundDumperIW5.h" #include "Sound/LoadedSoundDumperIW5.h"
#include "Sound/SndCurveDumperIW5.h"
#include "StringTable/StringTableDumperIW5.h" #include "StringTable/StringTableDumperIW5.h"
#include "Weapon/AttachmentJsonDumperIW5.h" #include "Weapon/AttachmentJsonDumperIW5.h"
#include "Weapon/WeaponDumperIW5.h" #include "Weapon/WeaponDumperIW5.h"
@@ -40,7 +41,7 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context)
)); ));
RegisterAssetDumper(std::make_unique<image::DumperIW5>()); RegisterAssetDumper(std::make_unique<image::DumperIW5>());
// REGISTER_DUMPER(AssetDumpersnd_alias_list_t) // REGISTER_DUMPER(AssetDumpersnd_alias_list_t)
// REGISTER_DUMPER(AssetDumperSndCurve) RegisterAssetDumper(std::make_unique<sound_curve::DumperIW5>());
RegisterAssetDumper(std::make_unique<sound::LoadedSoundDumperIW5>()); RegisterAssetDumper(std::make_unique<sound::LoadedSoundDumperIW5>());
// REGISTER_DUMPER(AssetDumperclipMap_t) // REGISTER_DUMPER(AssetDumperclipMap_t)
// REGISTER_DUMPER(AssetDumperComWorld) // REGISTER_DUMPER(AssetDumperComWorld)
@@ -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<AssetSoundCurve::Type>& 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<size_t>(sndCurve->knotCount), std::extent_v<decltype(SndCurve::knots)>);
dumper.Init(knotCount);
for (auto i = 0u; i < knotCount; i++)
dumper.WriteKnot(sndCurve->knots[i][0], sndCurve->knots[i][1]);
}
} // namespace sound_curve
@@ -0,0 +1,13 @@
#pragma once
#include "Dumping/AbstractAssetDumper.h"
#include "Game/IW5/IW5.h"
namespace sound_curve
{
class DumperIW5 final : public AbstractAssetDumper<IW5::AssetSoundCurve>
{
protected:
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<IW5::AssetSoundCurve::Type>& asset) override;
};
} // namespace sound_curve