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:
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xanim
|
||||
{
|
||||
enum class CompiledXAnimVersion : uint8_t
|
||||
{
|
||||
// IW3, T4
|
||||
VERSION_17 = 17,
|
||||
// IW4, IW5
|
||||
VERSION_18 = 18,
|
||||
// T5, T6 (slightly different format however)
|
||||
VERSION_19 = 19
|
||||
};
|
||||
|
||||
namespace binary17
|
||||
{
|
||||
constexpr uint8_t FLAG_LOOPED = 0x1;
|
||||
constexpr uint8_t FLAG_DELTA = 0x2;
|
||||
} // namespace binary17
|
||||
|
||||
namespace binary18
|
||||
{
|
||||
constexpr uint8_t FLAG_LOOPED = 0x1;
|
||||
constexpr uint8_t FLAG_DELTA = 0x2;
|
||||
constexpr uint8_t FLAG_DELTA_3D = 0x4;
|
||||
} // namespace binary18
|
||||
|
||||
namespace binary19
|
||||
{
|
||||
constexpr uint8_t FLAG_LOOPED = 0x1;
|
||||
constexpr uint8_t FLAG_DELTA = 0x2;
|
||||
|
||||
constexpr uint8_t FLAG_T5_LEFT_HAND_GRIP_IK = 0x4;
|
||||
constexpr uint8_t FLAG_T5_STREAMABLE = 0x8;
|
||||
|
||||
constexpr uint8_t FLAG_T6_DELTA_3D = 0x4;
|
||||
constexpr uint8_t FLAG_T6_LEFT_HAND_GRIP_IK = 0x8;
|
||||
|
||||
// This flag is not part of the official format.
|
||||
// T5 and T6 use the same XAnim version, even though the format is different:
|
||||
// * Flags have slightly different values
|
||||
// * T6 does not support "streamable"
|
||||
// * T5 does not support delta3D
|
||||
// So this flag value is added to be able to identify whether the file should use
|
||||
// T5 or T6 parsing behavior.
|
||||
constexpr uint8_t FLAG_T6_COMPATIBILITY = 0x80;
|
||||
} // namespace binary19
|
||||
} // namespace xanim
|
||||
@@ -1,9 +1,146 @@
|
||||
#include "XAnimCommon.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <format>
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xanim
|
||||
{
|
||||
CommonXQuat::CommonXQuat()
|
||||
: value{}
|
||||
{
|
||||
}
|
||||
|
||||
CommonXQuat::CommonXQuat(const int16_t v0, const int16_t v1, const int16_t v2, const int16_t v3)
|
||||
: value{v0, v1, v2, v3}
|
||||
{
|
||||
}
|
||||
|
||||
CommonXQuat2::CommonXQuat2()
|
||||
: value{}
|
||||
{
|
||||
}
|
||||
|
||||
CommonXQuat2::CommonXQuat2(const int16_t v0, const int16_t v1)
|
||||
: value{v0, v1}
|
||||
{
|
||||
}
|
||||
|
||||
CommonVec3U8::CommonVec3U8()
|
||||
: value{}
|
||||
{
|
||||
}
|
||||
|
||||
CommonVec3U8::CommonVec3U8(const uint8_t x, const uint8_t y, const uint8_t z)
|
||||
: value{x, y, z}
|
||||
{
|
||||
}
|
||||
|
||||
CommonVec3U16::CommonVec3U16()
|
||||
: value{}
|
||||
{
|
||||
}
|
||||
|
||||
CommonVec3U16::CommonVec3U16(const uint16_t x, const uint16_t y, const uint16_t z)
|
||||
: value{x, y, z}
|
||||
{
|
||||
}
|
||||
|
||||
QuatTrack::QuatTrack()
|
||||
: m_type(QuatType::NO_QUAT)
|
||||
{
|
||||
}
|
||||
|
||||
TransTrack::TransTrack()
|
||||
: m_type(TransType::NO_TRANS),
|
||||
m_mins({}),
|
||||
m_size({}),
|
||||
m_constant({})
|
||||
{
|
||||
}
|
||||
|
||||
CommonXAnimNotifyInfo::CommonXAnimNotifyInfo()
|
||||
: m_time(0)
|
||||
{
|
||||
}
|
||||
|
||||
CommonXAnimNotifyInfo::CommonXAnimNotifyInfo(std::string name, const float time)
|
||||
: m_name(std::move(name)),
|
||||
m_time(time)
|
||||
{
|
||||
}
|
||||
|
||||
bool CommonDeltaQuatTrack::Is3DTrack() const
|
||||
{
|
||||
return !m_frames.empty();
|
||||
}
|
||||
|
||||
CommonDeltaTransTrack::CommonDeltaTransTrack()
|
||||
: m_constant(std::nullopt),
|
||||
m_small_trans(false),
|
||||
m_mins({}),
|
||||
m_size({})
|
||||
{
|
||||
}
|
||||
|
||||
CommonXAnimParts::CommonXAnimParts()
|
||||
: m_num_frames(0),
|
||||
m_looped(false),
|
||||
m_left_hand_grip_ik(false),
|
||||
m_streamable(false),
|
||||
m_frame_rate(0),
|
||||
m_primed_length(0),
|
||||
m_asset_type(0)
|
||||
{
|
||||
}
|
||||
|
||||
void CommonXAnimParts::SortBoneTracksForQuats()
|
||||
{
|
||||
std::vector<size_t> boneOrder(m_bone_tracks.size());
|
||||
std::ranges::iota(boneOrder, 0);
|
||||
|
||||
std::ranges::sort(boneOrder,
|
||||
[this](const size_t i0, const size_t i1)
|
||||
{
|
||||
const auto type0 = std::to_underlying(m_bone_tracks[i0].m_quat.m_type);
|
||||
const auto type1 = std::to_underlying(m_bone_tracks[i1].m_quat.m_type);
|
||||
if (type0 != type1)
|
||||
return type0 < type1;
|
||||
|
||||
return i0 < i1;
|
||||
});
|
||||
|
||||
std::vector<BoneTrack> boneTrackCopies(m_bone_tracks.size());
|
||||
for (size_t i = 0u; i < boneOrder.size(); ++i)
|
||||
{
|
||||
boneTrackCopies[i] = std::move(m_bone_tracks[boneOrder[i]]);
|
||||
}
|
||||
|
||||
m_bone_tracks = std::move(boneTrackCopies);
|
||||
}
|
||||
|
||||
std::vector<size_t> CommonXAnimParts::GetBoneTrackOrderForTrans() const
|
||||
{
|
||||
// This assumes the bone tracks were already sorted for quats
|
||||
std::vector<size_t> boneOrder(m_bone_tracks.size());
|
||||
std::ranges::iota(boneOrder, 0);
|
||||
|
||||
std::ranges::sort(boneOrder,
|
||||
[this](const size_t i0, const size_t i1)
|
||||
{
|
||||
const auto type0 = std::to_underlying(m_bone_tracks[i0].m_trans.m_type);
|
||||
const auto type1 = std::to_underlying(m_bone_tracks[i1].m_trans.m_type);
|
||||
if (type0 != type1)
|
||||
return type0 < type1;
|
||||
|
||||
return i0 < i1;
|
||||
});
|
||||
|
||||
return boneOrder;
|
||||
}
|
||||
|
||||
std::string GetCompiledFileNameForAssetName(const std::string& assetName)
|
||||
{
|
||||
return std::format("xanim/{}", assetName);
|
||||
|
||||
@@ -1,8 +1,163 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace xanim
|
||||
{
|
||||
enum class QuatType : uint8_t
|
||||
{
|
||||
NO_QUAT = 0,
|
||||
HALF_QUAT = 1,
|
||||
FULL_QUAT = 2,
|
||||
HALF_QUAT_NO_SIZE = 3,
|
||||
FULL_QUAT_NO_SIZE = 4,
|
||||
};
|
||||
|
||||
enum class TransType : uint8_t
|
||||
{
|
||||
SMALL_TRANS = 5,
|
||||
FULL_TRANS = 6,
|
||||
TRANS_NO_SIZE = 7,
|
||||
NO_TRANS = 8,
|
||||
};
|
||||
|
||||
struct CommonXQuat
|
||||
{
|
||||
CommonXQuat();
|
||||
CommonXQuat(int16_t v0, int16_t v1, int16_t v2, int16_t v3);
|
||||
|
||||
int16_t value[4];
|
||||
};
|
||||
|
||||
struct CommonXQuat2
|
||||
{
|
||||
CommonXQuat2();
|
||||
CommonXQuat2(int16_t v0, int16_t v1);
|
||||
|
||||
int16_t value[2];
|
||||
};
|
||||
|
||||
struct CommonVec3U8
|
||||
{
|
||||
CommonVec3U8();
|
||||
CommonVec3U8(uint8_t x, uint8_t y, uint8_t z);
|
||||
|
||||
uint8_t value[3];
|
||||
};
|
||||
|
||||
struct CommonVec3U16
|
||||
{
|
||||
CommonVec3U16();
|
||||
CommonVec3U16(uint16_t x, uint16_t y, uint16_t z);
|
||||
|
||||
uint16_t value[3];
|
||||
};
|
||||
|
||||
class QuatTrack
|
||||
{
|
||||
public:
|
||||
QuatTrack();
|
||||
|
||||
QuatType m_type;
|
||||
std::vector<uint16_t> m_indices;
|
||||
std::vector<CommonXQuat> m_frames;
|
||||
std::vector<CommonXQuat2> m_frames2;
|
||||
};
|
||||
|
||||
class TransTrack
|
||||
{
|
||||
public:
|
||||
TransTrack();
|
||||
|
||||
TransType m_type;
|
||||
std::vector<uint16_t> m_indices;
|
||||
std::array<float, 3> m_mins;
|
||||
std::array<float, 3> m_size;
|
||||
std::vector<CommonVec3U8> m_frames_u8;
|
||||
std::vector<CommonVec3U16> m_frames_u16;
|
||||
std::array<float, 3> m_constant;
|
||||
};
|
||||
|
||||
class BoneTrack
|
||||
{
|
||||
public:
|
||||
BoneTrack() = default;
|
||||
|
||||
std::string m_name;
|
||||
QuatTrack m_quat;
|
||||
TransTrack m_trans;
|
||||
};
|
||||
|
||||
class CommonXAnimNotifyInfo
|
||||
{
|
||||
public:
|
||||
CommonXAnimNotifyInfo();
|
||||
CommonXAnimNotifyInfo(std::string name, float time);
|
||||
|
||||
std::string m_name;
|
||||
float m_time;
|
||||
};
|
||||
|
||||
class CommonDeltaQuatTrack
|
||||
{
|
||||
public:
|
||||
CommonDeltaQuatTrack() = default;
|
||||
|
||||
[[nodiscard]] bool Is3DTrack() const;
|
||||
|
||||
std::vector<uint16_t> m_indices;
|
||||
std::vector<CommonXQuat> m_frames;
|
||||
std::vector<CommonXQuat2> m_frames2;
|
||||
};
|
||||
|
||||
class CommonDeltaTransTrack
|
||||
{
|
||||
public:
|
||||
CommonDeltaTransTrack();
|
||||
|
||||
std::optional<std::array<float, 3>> m_constant;
|
||||
|
||||
bool m_small_trans;
|
||||
std::vector<uint16_t> m_indices;
|
||||
std::array<float, 3> m_mins;
|
||||
std::array<float, 3> m_size;
|
||||
std::vector<CommonVec3U8> m_frames_u8;
|
||||
std::vector<CommonVec3U16> m_frames_u16;
|
||||
};
|
||||
|
||||
class CommonXAnimDeltaTrack
|
||||
{
|
||||
public:
|
||||
CommonXAnimDeltaTrack() = default;
|
||||
|
||||
std::optional<CommonDeltaQuatTrack> m_quat;
|
||||
std::optional<CommonDeltaTransTrack> m_trans;
|
||||
};
|
||||
|
||||
class CommonXAnimParts
|
||||
{
|
||||
public:
|
||||
CommonXAnimParts();
|
||||
|
||||
void SortBoneTracksForQuats();
|
||||
[[nodiscard]] std::vector<size_t> GetBoneTrackOrderForTrans() const;
|
||||
|
||||
size_t m_num_frames;
|
||||
bool m_looped;
|
||||
bool m_left_hand_grip_ik;
|
||||
bool m_streamable;
|
||||
float m_frame_rate;
|
||||
float m_primed_length;
|
||||
uint8_t m_asset_type;
|
||||
std::vector<BoneTrack> m_bone_tracks;
|
||||
std::vector<CommonXAnimNotifyInfo> m_notifies;
|
||||
std::unique_ptr<CommonXAnimDeltaTrack> m_delta_track;
|
||||
};
|
||||
|
||||
[[nodiscard]] std::string GetCompiledFileNameForAssetName(const std::string& assetName);
|
||||
}
|
||||
} // namespace xanim
|
||||
|
||||
Reference in New Issue
Block a user