mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2026-06-07 17:22:34 +00:00
feat: add binary xanim support for remaining games (#818)
* refactor: use generic loader for iw3 xanims * refactor: use generic dumper for iw3 xanims * chore: use templating on XAnimDumper * chore: use templating on XAnimLoader * feat: dump xanims for T5 * feat: load binary t5 xanims * feat: load and dump t6 xanims * feat: load and dump iw4,iw5 xanims * chore: make sure iw3 and t5 notify about unsupported delta3D * chore: also use CommonVec3U8 and CommonVec3U16 for non delta trans track
This commit is contained in:
@@ -3,6 +3,8 @@ SystemTests = {}
|
||||
function SystemTests:include(includes)
|
||||
if includes:handle(self:name()) then
|
||||
includedirs {
|
||||
"%{wks.location}/src/ObjLoading",
|
||||
"%{wks.location}/src/ObjWriting",
|
||||
path.join(TestFolder(), "SystemTests")
|
||||
}
|
||||
end
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,71 @@
|
||||
#include "Game/IW4/XAnim/XAnimDumperIW4.h"
|
||||
#include "Game/IW4/XAnim/XAnimLoaderIW4.h"
|
||||
#include "OatTestPaths.h"
|
||||
#include "SearchPath/MockOutputPath.h"
|
||||
#include "SearchPath/MockSearchPath.h"
|
||||
#include "ZoneLoading.h"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
using namespace std::literals;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace
|
||||
{
|
||||
TEST_CASE("XAnim Loading/Dumping (IW4)", "[iw4][system]")
|
||||
{
|
||||
MockSearchPath searchPath;
|
||||
|
||||
const auto [animName] = GENERATE(Catch::Generators::table<std::string>({
|
||||
{"test_anim"},
|
||||
{"test_anim2"},
|
||||
}));
|
||||
|
||||
CAPTURE(animName);
|
||||
|
||||
const auto filePath = oat::paths::GetTestDirectory() / std::format("SystemTests/Game/IW4/XAnim/{}", animName);
|
||||
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(std::format("xanim/{}", animName), std::string(data.get(), fileSize));
|
||||
|
||||
Zone zone("MockZone", 0, GameId::IW4, GamePlatform::PC);
|
||||
AssetCreatorCollection creatorCollection(zone);
|
||||
IgnoredAssetLookup ignoredAssetLookup;
|
||||
MemoryManager memoryManager;
|
||||
const auto loader = xanim::CreateLoaderIW4(memoryManager, searchPath, zone);
|
||||
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
|
||||
|
||||
const auto result = loader->CreateAsset(animName, context);
|
||||
|
||||
REQUIRE(result.HasBeenSuccessful());
|
||||
const auto* assetInfo = reinterpret_cast<XAssetInfo<IW4::AssetXAnim::Type>*>(result.GetAssetInfo());
|
||||
const auto* parts = assetInfo->Asset();
|
||||
|
||||
REQUIRE(parts->name == animName);
|
||||
REQUIRE(parts->numframes > 0);
|
||||
|
||||
MockSearchPath mockObjPath;
|
||||
MockOutputPath mockOutput;
|
||||
xanim::DumperIW4 dumper;
|
||||
AssetDumpingContext dumpingContext(zone, "", mockOutput, mockObjPath, std::nullopt);
|
||||
dumper.Dump(dumpingContext);
|
||||
|
||||
const auto* outAnimFile = mockOutput.GetMockedFile(std::format("xanim/{}", animName));
|
||||
REQUIRE(outAnimFile != nullptr);
|
||||
|
||||
REQUIRE(outAnimFile->m_data.size() == fileSize);
|
||||
REQUIRE(memcmp(outAnimFile->m_data.data(), data.get(), fileSize) == 0);
|
||||
}
|
||||
} // namespace
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,71 @@
|
||||
#include "Game/IW5/XAnim/XAnimDumperIW5.h"
|
||||
#include "Game/IW5/XAnim/XAnimLoaderIW5.h"
|
||||
#include "OatTestPaths.h"
|
||||
#include "SearchPath/MockOutputPath.h"
|
||||
#include "SearchPath/MockSearchPath.h"
|
||||
#include "ZoneLoading.h"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
using namespace std::literals;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace
|
||||
{
|
||||
TEST_CASE("XAnim Loading/Dumping (IW5)", "[iw5][system]")
|
||||
{
|
||||
MockSearchPath searchPath;
|
||||
|
||||
const auto [animName] = GENERATE(Catch::Generators::table<std::string>({
|
||||
{"test_anim"},
|
||||
{"test_anim2"},
|
||||
}));
|
||||
|
||||
CAPTURE(animName);
|
||||
|
||||
const auto filePath = oat::paths::GetTestDirectory() / std::format("SystemTests/Game/IW5/XAnim/{}", animName);
|
||||
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(std::format("xanim/{}", animName), std::string(data.get(), fileSize));
|
||||
|
||||
Zone zone("MockZone", 0, GameId::IW5, GamePlatform::PC);
|
||||
AssetCreatorCollection creatorCollection(zone);
|
||||
IgnoredAssetLookup ignoredAssetLookup;
|
||||
MemoryManager memoryManager;
|
||||
const auto loader = xanim::CreateLoaderIW5(memoryManager, searchPath, zone);
|
||||
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
|
||||
|
||||
const auto result = loader->CreateAsset(animName, context);
|
||||
|
||||
REQUIRE(result.HasBeenSuccessful());
|
||||
const auto* assetInfo = reinterpret_cast<XAssetInfo<IW5::AssetXAnim::Type>*>(result.GetAssetInfo());
|
||||
const auto* parts = assetInfo->Asset();
|
||||
|
||||
REQUIRE(parts->name == animName);
|
||||
REQUIRE(parts->numframes > 0);
|
||||
|
||||
MockSearchPath mockObjPath;
|
||||
MockOutputPath mockOutput;
|
||||
xanim::DumperIW5 dumper;
|
||||
AssetDumpingContext dumpingContext(zone, "", mockOutput, mockObjPath, std::nullopt);
|
||||
dumper.Dump(dumpingContext);
|
||||
|
||||
const auto* outAnimFile = mockOutput.GetMockedFile(std::format("xanim/{}", animName));
|
||||
REQUIRE(outAnimFile != nullptr);
|
||||
|
||||
REQUIRE(outAnimFile->m_data.size() == fileSize);
|
||||
REQUIRE(memcmp(outAnimFile->m_data.data(), data.get(), fileSize) == 0);
|
||||
}
|
||||
} // namespace
|
||||
Binary file not shown.
@@ -0,0 +1,62 @@
|
||||
#include "Game/T5/XAnim/XAnimDumperT5.h"
|
||||
#include "Game/T5/XAnim/XAnimLoaderT5.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 (T5)", "[t5][system]")
|
||||
{
|
||||
MockSearchPath searchPath;
|
||||
|
||||
const auto filePath = oat::paths::GetTestDirectory() / "SystemTests/Game/T5/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::T5, GamePlatform::PC);
|
||||
AssetCreatorCollection creatorCollection(zone);
|
||||
IgnoredAssetLookup ignoredAssetLookup;
|
||||
MemoryManager memoryManager;
|
||||
const auto loader = xanim::CreateLoaderT5(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<T5::AssetXAnim::Type>*>(result.GetAssetInfo());
|
||||
const auto* parts = assetInfo->Asset();
|
||||
|
||||
REQUIRE(parts->name == "test_anim"s);
|
||||
REQUIRE(parts->numframes > 0);
|
||||
|
||||
MockSearchPath mockObjPath;
|
||||
MockOutputPath mockOutput;
|
||||
xanim::DumperT5 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
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,71 @@
|
||||
#include "Game/T6/XAnim/XAnimDumperT6.h"
|
||||
#include "Game/T6/XAnim/XAnimLoaderT6.h"
|
||||
#include "OatTestPaths.h"
|
||||
#include "SearchPath/MockOutputPath.h"
|
||||
#include "SearchPath/MockSearchPath.h"
|
||||
#include "ZoneLoading.h"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
using namespace std::literals;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace
|
||||
{
|
||||
TEST_CASE("XAnim Loading/Dumping (T6)", "[t6][system]")
|
||||
{
|
||||
MockSearchPath searchPath;
|
||||
|
||||
const auto [animName] = GENERATE(Catch::Generators::table<std::string>({
|
||||
{"test_anim"},
|
||||
{"test_anim2"},
|
||||
}));
|
||||
|
||||
CAPTURE(animName);
|
||||
|
||||
const auto filePath = oat::paths::GetTestDirectory() / std::format("SystemTests/Game/T6/XAnim/{}", animName);
|
||||
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(std::format("xanim/{}", animName), std::string(data.get(), fileSize));
|
||||
|
||||
Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC);
|
||||
AssetCreatorCollection creatorCollection(zone);
|
||||
IgnoredAssetLookup ignoredAssetLookup;
|
||||
MemoryManager memoryManager;
|
||||
const auto loader = xanim::CreateLoaderT6(memoryManager, searchPath, zone);
|
||||
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
|
||||
|
||||
const auto result = loader->CreateAsset(animName, context);
|
||||
|
||||
REQUIRE(result.HasBeenSuccessful());
|
||||
const auto* assetInfo = reinterpret_cast<XAssetInfo<T6::AssetXAnim::Type>*>(result.GetAssetInfo());
|
||||
const auto* parts = assetInfo->Asset();
|
||||
|
||||
REQUIRE(parts->name == animName);
|
||||
REQUIRE(parts->numframes > 0);
|
||||
|
||||
MockSearchPath mockObjPath;
|
||||
MockOutputPath mockOutput;
|
||||
xanim::DumperT6 dumper;
|
||||
AssetDumpingContext dumpingContext(zone, "", mockOutput, mockObjPath, std::nullopt);
|
||||
dumper.Dump(dumpingContext);
|
||||
|
||||
const auto* outAnimFile = mockOutput.GetMockedFile(std::format("xanim/{}", animName));
|
||||
REQUIRE(outAnimFile != nullptr);
|
||||
|
||||
REQUIRE(outAnimFile->m_data.size() == fileSize);
|
||||
REQUIRE(memcmp(outAnimFile->m_data.data(), data.get(), fileSize) == 0);
|
||||
}
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user