2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-06-03 07:12:33 +00:00

feat: IW3 xanim dumping/loading in CoD4 Mod Tools raw binary format (#768)

* feat: IW3 dump xanim to cod4 mod tools compatible binary

* chore: add XAnimPartType enum to game headers

* chore: use XAnimPartType in XAnimDumperIW3

* chore: extract xanim filename into XAnimCommon

* chore: prefer emplace_back over push_back

* chore: small code style improvements

* chore: use proper unsigned types for XAnimParts structs

* chore: use better understandable calculations for bitfields

* chore: use game names for parts

* chore: rename method to WriteNoteTracks

* chore: adds comments and improve clearity of what the game does

* chore: extract stream writing methods into StreamUtils

* chore: use vec3 for XAnimPartTransFrames mins and size

* chore: properly differ between XQuat and XQuat2 structs

* chore: use constants for xanim flags

* chore: use optional for delta track quats and trans

* chore: split delta track writing methods into quat and trans

* chore: add assertion for bDelta

* chore: simplify quat frame encoding indexing

* chore: simplify float to int bit casting

* chore: do not throw exception on failing to reconstruct bone tracks

* feat: add xanim loader for iw3

* fix: make sure to sort quats and trans like the game

* chore: prevent empty dumped files on bad xanim data

* chore: ensure no exception on zero frames in xanim notifies

* test: add system test for iw3 xanims

---------

Co-authored-by: Jan Laupetin <jan@laupetin.net>
This commit is contained in:
mo
2026-06-01 21:52:49 +01:00
committed by GitHub
parent f7be1ac9c1
commit 0c22dddd0e
19 changed files with 2044 additions and 55 deletions
+2
View File
@@ -41,6 +41,7 @@ function SystemTests:project()
Utils:include(includes)
ZoneLoading:include(includes)
ZoneWriting:include(includes)
ObjCommonTestUtils:include(includes)
ObjLoading:include(includes)
ObjCompiling:include(includes)
ObjWriting:include(includes)
@@ -53,6 +54,7 @@ function SystemTests:project()
links:linkto(Utils)
links:linkto(ZoneLoading)
links:linkto(ZoneWriting)
links:linkto(ObjCommonTestUtils)
links:linkto(ObjLoading)
links:linkto(ObjCompiling)
links:linkto(ObjWriting)
Binary file not shown.
+62
View File
@@ -0,0 +1,62 @@
#include "Game/IW3/XAnim/XAnimDumperIW3.h"
#include "Game/IW3/XAnim/XAnimLoaderIW3.h"
#include "OatTestPaths.h"
#include "SearchPath/MockOutputPath.h"
#include "SearchPath/MockSearchPath.h"
#include "ZoneLoading.h"
#include <catch2/catch_test_macros.hpp>
#include <filesystem>
#include <fstream>
#include <memory>
#include <string>
using namespace std::literals;
namespace fs = std::filesystem;
namespace
{
TEST_CASE("XAnim Loading/Dumping (IW3)", "[iw3][system]")
{
MockSearchPath searchPath;
const auto filePath = oat::paths::GetTestDirectory() / "SystemTests/Game/IW3/XAnim/test_anim";
const auto fileSize = static_cast<size_t>(fs::file_size(filePath));
std::ifstream file(filePath, std::ios::binary);
REQUIRE(file.is_open());
const auto data = std::make_unique<char[]>(fileSize);
file.read(data.get(), fileSize);
searchPath.AddFileData("xanim/test_anim", std::string(data.get(), fileSize));
Zone zone("MockZone", 0, GameId::IW3, GamePlatform::PC);
AssetCreatorCollection creatorCollection(zone);
IgnoredAssetLookup ignoredAssetLookup;
MemoryManager memoryManager;
const auto loader = xanim::CreateLoaderIW3(memoryManager, searchPath, zone);
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
const auto result = loader->CreateAsset("test_anim", context);
REQUIRE(result.HasBeenSuccessful());
const auto* assetInfo = reinterpret_cast<XAssetInfo<IW3::AssetXAnim::Type>*>(result.GetAssetInfo());
const auto* parts = assetInfo->Asset();
REQUIRE(parts->name == "test_anim"s);
REQUIRE(parts->numframes > 0);
MockSearchPath mockObjPath;
MockOutputPath mockOutput;
xanim::DumperIW3 dumper;
AssetDumpingContext dumpingContext(zone, "", mockOutput, mockObjPath, std::nullopt);
dumper.Dump(dumpingContext);
const auto* outAnimFile = mockOutput.GetMockedFile("xanim/test_anim");
REQUIRE(outAnimFile != nullptr);
REQUIRE(outAnimFile->m_data.size() == fileSize);
REQUIRE(memcmp(outAnimFile->m_data.data(), data.get(), fileSize) == 0);
}
} // namespace