Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Texture Animation #27

Merged
merged 2 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 81 additions & 55 deletions Source/FileFormat/FileFormat/Novus/Model/ComplexModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,17 @@ namespace Model
output.write(reinterpret_cast<const char*>(&flags), sizeof(ComplexModel::Flags));
}

// Write Global Loops
{
u32 numElements = static_cast<u32>(globalLoops.size());
output.write(reinterpret_cast<const char*>(&numElements), sizeof(u32));

if (numElements > 0)
{
output.write(reinterpret_cast<const char*>(&globalLoops[0]), numElements * sizeof(u32));
}
}

// Write Sequences
{
u32 numElements = modelHeader.numSequences;
Expand Down Expand Up @@ -433,6 +444,12 @@ namespace Model
return false;
}

// Read Global Loops
{
if (!ReadVectorFromBuffer(buffer, out.globalLoops))
return false;
}

// Read Sequences
{
if (!buffer->GetVector(out.sequences, out.modelHeader.numSequences))
Expand Down Expand Up @@ -764,23 +781,29 @@ namespace Model
template <typename T>
void GetAnimationTrack(std::shared_ptr<Bytebuffer>& rootBuffer, const Layout& file, ComplexModel::AnimationData<T>& animationData, M2Track<T>& m2Track)
{
i16 globalLoopIndex = m2Track.globalSequence;
u32 numTracks = m2Track.values.size;

animationData.interpolationType = static_cast<ComplexModel::AnimationInterpolationType>(m2Track.interpolationType);
animationData.isGlobalSequence = m2Track.globalSequence != -1;
animationData.globalLoopIndex = globalLoopIndex;
animationData.tracks.reserve(numTracks);

// Handle Global Sequence
if (animationData.isGlobalSequence)
if (globalLoopIndex != -1)
{
u32 sequenceID = file.md21.sequences.size + m2Track.globalSequence;

if (sequenceID < file.md21.sequences.size)
if (globalLoopIndex < static_cast<i32>(file.md21.sequences.size))
{
M2Sequence* m2Sequence = file.md21.sequences.GetElement(rootBuffer, sequenceID);
M2Sequence* m2Sequence = file.md21.sequences.GetElement(rootBuffer, globalLoopIndex);

while (m2Sequence->flags.IsAlias)
{
if (m2Sequence->nextAliasID >= file.md21.sequences.size)
break;

m2Sequence = file.md21.sequences.GetElement(rootBuffer, m2Sequence->nextAliasID);
}

bool hasExternalAnimationData = !m2Sequence->flags.HasEmbeddedAnimationData;
if (hasExternalAnimationData || m2Sequence->flags.IsAlias)
if (hasExternalAnimationData && !m2Sequence->flags.IsAlias)
{
// TODO : Animation is stored externally
return;
Expand All @@ -794,16 +817,13 @@ namespace Model
{
ComplexModel::AnimationTrack<T>& track = animationData.tracks.emplace_back();

track.sequenceID = sequenceID;

track.timestamps.resize(m2Timestamps->size);
memcpy(track.timestamps.data(), m2Timestamps->Get(rootBuffer), sizeof(u32) * m2Timestamps->size);

track.values.resize(m2Values->size);
memcpy(track.values.data(), m2Values->Get(rootBuffer), sizeof(T) * m2Values->size);
}
}
// Read All Sequence Tracks
else
{
for (u32 i = 0; i < numTracks; i++)
Expand All @@ -812,23 +832,29 @@ namespace Model
{
M2Sequence* m2Sequence = file.md21.sequences.GetElement(rootBuffer, i);

while (m2Sequence->flags.IsAlias)
{
if (m2Sequence->nextAliasID >= file.md21.sequences.size)
break;

m2Sequence = file.md21.sequences.GetElement(rootBuffer, m2Sequence->nextAliasID);
}

bool hasExternalAnimationData = !m2Sequence->flags.HasEmbeddedAnimationData;
if (hasExternalAnimationData || m2Sequence->flags.IsAlias)
if (hasExternalAnimationData && !m2Sequence->flags.IsAlias)
{
// TODO : Animation is stored externally
continue;
}
}

ComplexModel::AnimationTrack<T>& track = animationData.tracks.emplace_back();

M2Array<u32>* m2Timestamps = m2Track.timestamps.GetElement(rootBuffer, i);
M2Array<T>* m2Values = m2Track.values.GetElement(rootBuffer, i);

if (m2Timestamps->size > 0 && m2Values->size > 0)
{
ComplexModel::AnimationTrack<T>& track = animationData.tracks.emplace_back();

track.sequenceID = i;

track.timestamps.resize(m2Timestamps->size);
memcpy(track.timestamps.data(), m2Timestamps->Get(rootBuffer), sizeof(u32) * m2Timestamps->size);

Expand All @@ -843,16 +869,14 @@ namespace Model
u32 numTracks = static_cast<u32>(src.tracks.size());

dest.interpolationType = src.interpolationType;
dest.isGlobalSequence = src.isGlobalSequence;
dest.globalLoopIndex = src.globalLoopIndex;
dest.tracks.resize(numTracks);

for (u32 i = 0; i < numTracks; i++)
{
ComplexModel::AnimationTrack<M2CompressedQuaternion>& srcTrack = src.tracks[i];
ComplexModel::AnimationTrack<quat>& destTrack = dest.tracks[i];

destTrack.sequenceID = srcTrack.sequenceID;

// Copy Timestamps
{
u32 numTimestamps = static_cast<u32>(srcTrack.values.size());
Expand Down Expand Up @@ -880,12 +904,22 @@ namespace Model
out.flags = *reinterpret_cast<ComplexModel::Flags*>(&layout.md21.flags);
out.flags.IsConvertedMapObject = false;

u32 numGlobalSequences = layout.md21.loopingSequenceTimestamps.size;
u32 numSequences = layout.md21.sequences.size;

// Read Global Loops
{
out.globalLoops.resize(layout.md21.globalLoops.size);

for (u32 i = 0; i < layout.md21.globalLoops.size; i++)
{
u32* m2GlobalLoop = layout.md21.globalLoops.GetElement(rootBuffer, i);
out.globalLoops[i] = *m2GlobalLoop;
}
}

// Read Sequences
{
out.sequences.resize(numSequences + numGlobalSequences);
out.sequences.resize(numSequences);

for (u32 i = 0; i < layout.md21.sequences.size; i++)
{
Expand All @@ -898,7 +932,6 @@ namespace Model
sequence.duration = m2Sequence->duration;
sequence.moveSpeed = m2Sequence->moveSpeed;

sequence.flags.isAlwaysPlaying = false;
sequence.flags.isAlias = m2Sequence->flags.IsAlias;
sequence.flags.blendTransition = m2Sequence->flags.BlendTransition;
sequence.flags.blendTransitionIfActive = m2Sequence->flags.SetBlendTransitionOnLoad;
Expand All @@ -920,38 +953,6 @@ namespace Model
}
}

// Add Global Sequences (Important GlobalSequences are added at the end, otherwise we have to patch nextVariationId && nextAliasId
{
for (u32 i = 0; i < numGlobalSequences; i++)
{
ComplexModel::AnimationSequence& sequence = out.sequences[numSequences + i];
sequence.id = -1;
sequence.subID = -1;

sequence.duration = *layout.md21.loopingSequenceTimestamps.GetElement(rootBuffer, i);
sequence.moveSpeed = 0;

sequence.flags.isAlwaysPlaying = true;
sequence.flags.isAlias = false;
sequence.flags.blendTransition = false;

sequence.frequency = 0;
sequence.repetitionRange = uvec2(0, 0);
sequence.blendTimeStart = 0;
sequence.blendTimeEnd = 0;

vec3 aabbMin = CoordinateSpaces::ModelPosToNovus(layout.md21.cullingAABBBounds.aabb.min);
vec3 aabbMax = CoordinateSpaces::ModelPosToNovus(layout.md21.cullingAABBBounds.aabb.max);

sequence.aabbCenter = (aabbMin + aabbMax) * 0.5f;
sequence.aabbExtents = aabbMax - sequence.aabbCenter;
sequence.radius = 0;

sequence.nextVariationID = -1;
sequence.nextAliasID = -1;
}
}

// Read Bones
{
u32 numBones = layout.md21.bones.size;
Expand Down Expand Up @@ -1086,7 +1087,32 @@ namespace Model
memcpy(out.materials.data(), &rootBuffer->GetDataPointer()[materialsOffset], numMaterials * sizeof(ComplexModel::Material));
}

// TODO : Texture Transforms
// Read Texture Transforms
{
u32 numTextureTransforms = layout.md21.textureTransforms.size;

out.textureTransforms.resize(numTextureTransforms);
for (u32 i = 0; i < numTextureTransforms; i++)
{
ComplexModel::TextureTransform& textureTransform = out.textureTransforms[i];
M2TextureTransform* m2TextureTransform = layout.md21.textureTransforms.GetElement(rootBuffer, i);

// Read Translation Track
{
GetAnimationTrack(rootBuffer, layout, textureTransform.translation, m2TextureTransform->translation);
}

// Read Rotation Track
{
GetAnimationTrack(rootBuffer, layout, textureTransform.rotation, m2TextureTransform->rotation);
}

// Read Scale Track
{
GetAnimationTrack(rootBuffer, layout, textureTransform.scale, m2TextureTransform->scale);
}
}
}

// Read Texture Lookup Tables
{
Expand Down
26 changes: 9 additions & 17 deletions Source/FileFormat/FileFormat/Novus/Model/ComplexModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ namespace Model
struct ComplexModel
{
public:
static const u32 CURRENT_VERSION = 8;
static const u32 CURRENT_VERSION = 9;

struct Flags
{
Expand Down Expand Up @@ -54,7 +54,6 @@ namespace Model
struct AnimationTrack
{
public:
u32 sequenceID = 0;
std::vector<u32> timestamps = { };
std::vector<T> values = { };

Expand Down Expand Up @@ -87,11 +86,9 @@ namespace Model
}
}
}
AnimationTrack(AnimationTrack<T>&& other) : sequenceID(other.sequenceID), timestamps(std::move(other.timestamps)), values(std::move(other.values)) { }
AnimationTrack(AnimationTrack<T>&& other) : timestamps(std::move(other.timestamps)), values(std::move(other.values)) { }
AnimationTrack<T>& operator=(const AnimationTrack<T>& other)
{
sequenceID = other.sequenceID;

size_t numTimestamps = other.timestamps.size();
if (numTimestamps)
{
Expand Down Expand Up @@ -134,7 +131,7 @@ namespace Model
{
public:
AnimationInterpolationType interpolationType = AnimationInterpolationType::NONE;
bool isGlobalSequence = false;
i16 globalLoopIndex = -1;

std::vector<AnimationTrack<T>> tracks;

Expand All @@ -154,11 +151,11 @@ namespace Model
tracks[i] = other.tracks[i];
}
}
AnimationData(AnimationData<T>&& other) : interpolationType(other.interpolationType), isGlobalSequence(other.isGlobalSequence), tracks(std::move(other.tracks)) { }
AnimationData(AnimationData<T>&& other) : interpolationType(other.interpolationType), globalLoopIndex(other.globalLoopIndex), tracks(std::move(other.tracks)) { }
AnimationData<T>& operator=(const AnimationData<T>& other)
{
interpolationType = other.interpolationType;
isGlobalSequence = other.isGlobalSequence;
globalLoopIndex = other.globalLoopIndex;

size_t numTracks = other.tracks.size();
tracks.resize(numTracks);
Expand All @@ -174,7 +171,7 @@ namespace Model
void Serialize(std::ofstream& stream) const
{
stream.write(reinterpret_cast<char const*>(&interpolationType), sizeof(AnimationInterpolationType));
stream.write(reinterpret_cast<char const*>(&isGlobalSequence), sizeof(bool));
stream.write(reinterpret_cast<char const*>(&globalLoopIndex), sizeof(i16));

u32 numTracks = static_cast<u32>(tracks.size());
{
Expand All @@ -184,8 +181,6 @@ namespace Model
{
const AnimationTrack<T>& track = tracks[i];

stream.write(reinterpret_cast<char const*>(&track.sequenceID), sizeof(u32));

u32 numTimestamps = static_cast<u32>(track.timestamps.size());
{
stream.write(reinterpret_cast<char const*>(&numTimestamps), sizeof(u32));
Expand All @@ -205,7 +200,7 @@ namespace Model
if (!buffer->Get(interpolationType))
return false;

if (!buffer->Get(isGlobalSequence))
if (!buffer->Get(globalLoopIndex))
return false;

u32 numTracks = 0;
Expand All @@ -218,9 +213,6 @@ namespace Model
{
AnimationTrack<T>& track = tracks[i];

if (!buffer->GetU32(track.sequenceID))
return false;

u32 numTimestamps = 0;
if (!buffer->GetU32(numTimestamps))
return false;
Expand Down Expand Up @@ -418,7 +410,6 @@ namespace Model
public:
struct Flags
{
u32 isAlwaysPlaying : 1;
u32 isAlias : 1;
u32 blendTransition : 1; // (This applies if set on either side of the transition) If set we lerp between the end -> start states, but only if end != start (Compare Bone Values)
u32 blendTransitionIfActive : 1;
Expand Down Expand Up @@ -557,6 +548,7 @@ namespace Model

Flags flags = { };

std::vector<u32> globalLoops;
std::vector<AnimationSequence> sequences;
std::vector<Bone> bones;
robin_hood::unordered_map<u16, i16> keyBoneIDToBoneIndex;
Expand Down Expand Up @@ -600,4 +592,4 @@ namespace Model
static i8 GetVertexShaderID(i16 shaderID, u16 textureCount);
static i8 GetPixelShaderID(i16 shaderID, u16 textureCount);
};
}
}
2 changes: 1 addition & 1 deletion Source/FileFormat/FileFormat/Warcraft/M2/M2.h
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ namespace M2
M2Array<char> uniqueName = { };
Flags flags = { };

M2Array<u32> loopingSequenceTimestamps = { };
M2Array<u32> globalLoops = { };
M2Array<M2Sequence> sequences = { };
M2Array<u16> sequenceIDToAnimationID = { };
M2Array<M2CompBone> bones = { };
Expand Down
Loading
Loading