2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-06-06 08:42:35 +00:00

feat: load binary t5 xanims

This commit is contained in:
Jan Laupetin
2026-06-05 22:36:07 +02:00
parent 6b0681f27f
commit 645a1629a6
6 changed files with 144 additions and 9 deletions
+2 -1
View File
@@ -8,6 +8,7 @@
#include "Game/T5/T5.h"
#include "Game/T5/Techset/PixelShaderLoaderT5.h"
#include "Game/T5/Techset/VertexShaderLoaderT5.h"
#include "Game/T5/XAnim/XAnimLoaderT5.h"
#include "Game/T5/XModel/LoaderXModelT5.h"
#include "LightDef/LightDefLoaderT5.h"
#include "Localize/LoaderLocalizeT5.h"
@@ -112,7 +113,7 @@ namespace
collection.AddAssetCreator(phys_preset::CreateGdtLoaderT5(memory, gdt, zone));
// collection.AddAssetCreator(std::make_unique<AssetLoaderPhysConstraints>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderDestructibleDef>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderXAnim>(memory));
collection.AddAssetCreator(xanim::CreateLoaderT5(memory, searchPath, zone));
collection.AddAssetCreator(xmodel::CreateLoaderT5(memory, searchPath, zone));
collection.AddAssetCreator(material::CreateLoaderT5(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderTechniqueSet>(memory));
+59 -6
View File
@@ -14,9 +14,6 @@ using namespace xanim;
namespace
{
constexpr uint8_t FLAG_LOOPED = 1u;
constexpr uint8_t FLAG_DELTA = 2u;
// The linker decodes raw trans size[] with these exact float literals.
// They correspond to 1.0f / 255.0f and 1.0f / 65535.0f, but we keep the
// decompiled values to preserve binary-stable round trips.
@@ -30,6 +27,8 @@ namespace
{
case CompiledXAnimVersion::VERSION_17:
return CompiledXAnimVersion::VERSION_17;
case CompiledXAnimVersion::VERSION_19:
return CompiledXAnimVersion::VERSION_19;
default:
return std::unexpected(std::format("Version {} is not supported", fileVersion));
}
@@ -347,6 +346,54 @@ namespace
// This notify is always automatically added
parts.m_notifies.emplace_back("end", 1.0f);
}
bool IsLooped(const uint8_t flags, const CompiledXAnimVersion version)
{
switch (version)
{
case CompiledXAnimVersion::VERSION_17:
return (flags & binary17::FLAG_LOOPED) > 0;
case CompiledXAnimVersion::VERSION_19:
return (flags & binary19::FLAG_LOOPED) > 0;
}
return false;
}
bool HasDelta(const uint8_t flags, const CompiledXAnimVersion version)
{
switch (version)
{
case CompiledXAnimVersion::VERSION_17:
return (flags & binary17::FLAG_DELTA) > 0;
case CompiledXAnimVersion::VERSION_19:
return (flags & binary19::FLAG_DELTA) > 0;
}
return false;
}
bool IsLeftHandGripIk(const uint8_t flags, const CompiledXAnimVersion version)
{
switch (version)
{
case CompiledXAnimVersion::VERSION_19:
return (flags & binary19::FLAG_LEFT_HAND_GRIP_IK) > 0;
default:
return false;
}
}
bool IsStreamable(const uint8_t flags, const CompiledXAnimVersion version)
{
switch (version)
{
case CompiledXAnimVersion::VERSION_19:
return (flags & binary19::FLAG_STREAMABLE) > 0;
default:
return false;
}
}
} // namespace
namespace xanim
@@ -360,7 +407,6 @@ namespace xanim
auto parts = std::make_unique<CommonXAnimParts>();
const auto version = maybeVersion.value();
assert(version == CompiledXAnimVersion::VERSION_17);
const auto numFrames = stream::ReadValue<uint16_t>(stream);
const auto boneCount = stream::ReadValue<uint16_t>(stream);
@@ -370,15 +416,22 @@ namespace xanim
if (stream.fail())
return std::unexpected("Truncated file");
const bool isLooped = flags & FLAG_LOOPED;
const bool hasDelta = flags & FLAG_DELTA;
const bool isLooped = IsLooped(flags, version);
const bool hasDelta = HasDelta(flags, version);
const bool leftHandGripIk = IsLeftHandGripIk(flags, version);
const bool streamable = IsStreamable(flags, version);
const uint16_t numLoopFrames = isLooped ? numFrames + 1u : numFrames;
parts->m_num_frames = numLoopFrames - 1;
parts->m_looped = isLooped;
parts->m_left_hand_grip_ik = leftHandGripIk;
parts->m_streamable = streamable;
parts->m_asset_type = assetType;
parts->m_frame_rate = static_cast<float>(framerate);
if (version == CompiledXAnimVersion::VERSION_19 && streamable)
parts->m_primed_length = stream::ReadValue<float>(stream);
const auto useByteIndices = parts->m_num_frames < 256;
if (hasDelta)
+20 -1
View File
@@ -1,4 +1,4 @@
#options GAME(IW3)
#options GAME(IW3, T5)
#filename "Game/" + GAME + "/XAnim/XAnimLoader" + GAME + ".cpp"
@@ -70,6 +70,18 @@ namespace
notify.time = commonNotify.m_time;
}
#ifdef FEATURE_T5
const auto loopBegin = std::ranges::find_if(commonParts.m_notifies, [](const xanim::CommonXAnimNotifyInfo& notify)
{
return notify.m_name == "loop_begin";
});
if (loopBegin != commonParts.m_notifies.end())
parts.loopEntryTime = loopBegin->m_time;
else
parts.loopEntryTime = 0;
#endif
}
template<typename T> void ConvertIndices(T& indices, const std::vector<uint16_t>& commonIndices, const bool useByteIndices)
@@ -279,9 +291,16 @@ namespace
{
parts.numframes = static_cast<decltype(XAnimParts::numframes)>(commonParts.m_num_frames);
parts.bLoop = commonParts.m_looped;
#ifdef FEATURE_T5
parts.bLeftHandGripIK = commonParts.m_left_hand_grip_ik;
parts.bStreamable = commonParts.m_streamable;
#endif
parts.assetType = commonParts.m_asset_type;
parts.framerate = commonParts.m_frame_rate;
parts.frequency = parts.numframes > 0 ? parts.framerate / static_cast<float>(parts.numframes) : 0;
#ifdef FEATURE_T5
parts.primedLength = commonParts.m_primed_length;
#endif
const auto useByteIndices = parts.numframes < 256;
+1 -1
View File
@@ -1,4 +1,4 @@
#options GAME(IW3)
#options GAME(IW3, T5)
#filename "Game/" + GAME + "/XAnim/XAnimLoader" + GAME + ".h"