diff --git a/Source/Contents/Models/ModelAnimation.cpp b/Source/Contents/Models/ModelAnimation.cpp index 84b6659ee..17c1bbca3 100644 --- a/Source/Contents/Models/ModelAnimation.cpp +++ b/Source/Contents/Models/ModelAnimation.cpp @@ -1,6 +1,7 @@ #include "Contents/Models/ModelAnimation.h" #include +#include namespace { __declspec(noinline) ModelRotationKey MatrixQuaternion(const matrix& matrix); @@ -24,11 +25,12 @@ namespace { // OFFSET: 0x00540370 // FUNCTION: fn_01721 -void SampleLegacyPosition(const std::vector& keys, int frame, matrix& output) { +void LegacyPositionTrack::Sample(int frame, matrix& output) const { + const std::vector& keys = *this; const unsigned count = keys.size(); if (count == 0) { - output.Identity(); + std::memcpy(output.values, g_identityMatrix, sizeof(g_identityMatrix)); return; } @@ -53,11 +55,12 @@ void SampleLegacyPosition(const std::vector& keys, int frame, // OFFSET: 0x00540670 // FUNCTION: fn_01723 -void SampleLegacyRotation(const std::vector& keys, int frame, matrix& output) { +void LegacyRotationTrack::Sample(int frame, matrix& output) const { + const std::vector& keys = *this; const unsigned count = keys.size(); if (count == 0) { - output.Identity(); + std::memcpy(output.values, g_identityMatrix, sizeof(g_identityMatrix)); return; } @@ -82,7 +85,7 @@ void SampleLegacyRotation(const std::vector& keys, int frame, const auto& b = keys[next]; if (a.rotation[3] == 1.0f && b.rotation[3] == 1.0f) { - output.Identity(); + std::memcpy(output.values, g_identityMatrix, sizeof(g_identityMatrix)); return; } @@ -94,11 +97,12 @@ void SampleLegacyRotation(const std::vector& keys, int frame, // OFFSET: 0x00540BF0 // FUNCTION: fn_01725 -void SampleLegacyScale(const std::vector& keys, int, matrix& output) { +void LegacyScaleTrack::Sample(int, matrix& output) const { + const std::vector& keys = *this; const unsigned count = keys.size(); if (count == 0) { - output.Identity(); + std::memcpy(output.values, g_identityMatrix, sizeof(g_identityMatrix)); } else if (count == 1) { output.SetScale(keys[0].scale[0], keys[0].scale[1], keys[0].scale[2]); } @@ -106,11 +110,12 @@ void SampleLegacyScale(const std::vector& keys, int, matrix& outp // OFFSET: 0x00540C60 // FUNCTION: fn_01726 -void SampleModelScale(const std::vector& keys, float frame, matrix& output) { +void ModelScaleTrack::Sample(float frame, matrix& output) const { + const std::vector& keys = *this; const unsigned count = keys.size(); if (count == 0) { - output.Identity(); + std::memcpy(output.values, g_identityMatrix, sizeof(g_identityMatrix)); return; } @@ -127,7 +132,7 @@ void SampleModelScale(const std::vector& keys, float frame, ma } matrix scale; - scale.Identity(); + std::memcpy(scale.values, g_identityMatrix, sizeof(g_identityMatrix)); ModelRotationKey first{0, {1, 1, 1, 1}}; ModelRotationKey second{0, {1, 1, 1, 1}}; @@ -152,7 +157,8 @@ void SampleModelScale(const std::vector& keys, float frame, ma // OFFSET: 0x005404A0 // FUNCTION: fn_01722 -void SampleModelPosition(const std::vector& keys, float frame, const matrix& base, matrix& output) { +void ModelPositionTrack::Sample(float frame, const matrix& base, matrix& output) const { + const std::vector& keys = *this; const unsigned count = keys.size(); if (count == 0) { @@ -176,13 +182,18 @@ void SampleModelPosition(const std::vector& keys, float frame, return; } - ModelRotationKey first; - ModelRotationKey second; + ModelPositionKey first; + ModelPositionKey second; for (unsigned next = 0; next < count; ++next) { if (static_cast(keys[next].frame) > frame) { - first = next ? keys[next - 1] : ModelRotationKey{0, {base.values[9], base.values[10], base.values[11], 0}}; - second = keys[next]; + if (next == 0) { + first = ModelPositionKey{0, {base.values[9], base.values[10], base.values[11]}}; + } else { + std::memcpy(&first, &keys[next - 1], sizeof(first)); + } + + std::memcpy(&second, &keys[next], sizeof(second)); break; } } @@ -190,16 +201,17 @@ void SampleModelPosition(const std::vector& keys, float frame, const float amount = (frame - static_cast(first.frame)) / static_cast((second.frame - first.frame)); const float previous = 1.0f - amount; - output.values[9] = first.rotation[0] * previous + second.rotation[0] * amount; - output.values[10] = first.rotation[1] * previous + second.rotation[1] * amount; - output.values[11] = first.rotation[2] * previous + second.rotation[2] * amount; + output.values[9] = first.position[0] * previous + second.position[0] * amount; + output.values[10] = first.position[1] * previous + second.position[1] * amount; + output.values[11] = first.position[2] * previous + second.position[2] * amount; } // OFFSET: 0x005407A0 // FUNCTION: fn_01724 -void SampleModelRotation(const std::vector& keys, float frame, const matrix& base, matrix& output) { +void ModelRotationTrack::Sample(float frame, const matrix& base, matrix& output) const { + const std::vector& keys = *this; matrix rotation; - rotation.Identity(); + std::memcpy(rotation.values, g_identityMatrix, sizeof(g_identityMatrix)); const unsigned count = keys.size(); if (count == 0) { @@ -239,21 +251,23 @@ void SampleModelRotation(const std::vector& keys, float frame, float firstWeight; float secondWeight; - if (!(dot > -0.95f)) { + if (dot > -0.95f) { + if (dot <= 0.95f) { + const float angle = static_cast(std::acos(static_cast(dot))); + const float denominator = ClientSin(angle); + firstWeight = ClientSin((1.0f - amount) * angle) / denominator; + secondWeight = ClientSin(angle * amount) / denominator; + } else { + firstWeight = 1.0f - amount; + secondWeight = amount; + } + } else { b.rotation[0] = -a.rotation[1]; b.rotation[1] = a.rotation[0]; b.rotation[2] = -a.rotation[3]; b.rotation[3] = a.rotation[2]; firstWeight = ClientSin((0.5f - amount) * 3.141592f); secondWeight = ClientSin(amount * 3.141592f); - } else if (dot > 0.95f) { - firstWeight = 1.0f - amount; - secondWeight = amount; - } else { - const float angle = static_cast(std::acos(static_cast(dot))); - const float denominator = ClientSin(angle); - firstWeight = ClientSin((1.0f - amount) * angle) / denominator; - secondWeight = ClientSin(angle * amount) / denominator; } ModelRotationKey result{0, {}}; diff --git a/Source/Contents/Models/ModelAnimation.h b/Source/Contents/Models/ModelAnimation.h index cd2e9ccfd..c7587e7df 100644 --- a/Source/Contents/Models/ModelAnimation.h +++ b/Source/Contents/Models/ModelAnimation.h @@ -6,12 +6,41 @@ #include -void SampleLegacyPosition(const std::vector& keys, int frame, matrix& output); -void SampleLegacyRotation(const std::vector& keys, int frame, matrix& output); -void SampleLegacyScale(const std::vector& keys, int frame, matrix& output); -void SampleModelScale(const std::vector& keys, float frame, matrix& output); -void SampleModelPosition(const std::vector& keys, float frame, const matrix& base, matrix& output); -void SampleModelRotation(const std::vector& keys, float frame, const matrix& base, matrix& output); +class LegacyPositionTrack : public std::vector { +public: + using std::vector::operator=; + void Sample(int frame, matrix& output) const; +}; + +class LegacyRotationTrack : public std::vector { +public: + using std::vector::operator=; + void Sample(int frame, matrix& output) const; +}; + +class LegacyScaleTrack : public std::vector { +public: + using std::vector::operator=; + void Sample(int frame, matrix& output) const; +}; + +class ModelScaleTrack : public std::vector { +public: + using std::vector::operator=; + void Sample(float frame, matrix& output) const; +}; + +class ModelPositionTrack : public std::vector { +public: + using std::vector::operator=; + void Sample(float frame, const matrix& base, matrix& output) const; +}; + +class ModelRotationTrack : public std::vector { +public: + using std::vector::operator=; + void Sample(float frame, const matrix& base, matrix& output) const; +}; void QuaternionMatrix(const ModelRotationKey& key, matrix& output); void InterpolateModelRotation(float amount, const ModelRotationKey& first, const ModelRotationKey& second, int spins, ModelRotationKey& output); diff --git a/Source/Contents/Models/ModelNode.cpp b/Source/Contents/Models/ModelNode.cpp index b2176b840..ff3bec59c 100644 --- a/Source/Contents/Models/ModelNode.cpp +++ b/Source/Contents/Models/ModelNode.cpp @@ -127,12 +127,12 @@ void C3dNodeV1::Animate(double frame) { matrix position; matrix scale; matrix rotation; - position.Identity(); - scale.Identity(); - rotation.Identity(); - SampleLegacyPosition(this->positionKeys, selected, position); - SampleLegacyRotation(this->rotationKeys, selected, rotation); - SampleLegacyScale(this->scaleKeys, selected, scale); + std::memcpy(position.values, g_identityMatrix, sizeof(g_identityMatrix)); + std::memcpy(scale.values, g_identityMatrix, sizeof(g_identityMatrix)); + std::memcpy(rotation.values, g_identityMatrix, sizeof(g_identityMatrix)); + this->positionKeys.Sample(selected, position); + this->rotationKeys.Sample(selected, rotation); + this->scaleKeys.Sample(selected, scale); matrix combined; combined.Compose(scale, rotation); this->transform.Compose(combined, position); @@ -145,11 +145,11 @@ void C3dNodeV1::Animate(double frame) { // OFFSET: 0x00AB9210 // FUNCTION: fn_17508 void C3dNodeV2::Animate(double frame) { - this->transform.Identity(); + std::memcpy(this->transform.values, g_identityMatrix, sizeof(g_identityMatrix)); const float selected = static_cast(frame); - SampleModelScale(this->scaleKeys, selected, this->transform); - SampleModelRotation(this->rotationKeys, selected, this->localTransform, this->transform); - SampleModelPosition(this->positionKeys, selected, this->localTransform, this->transform); + this->scaleKeys.Sample(selected, this->transform); + this->rotationKeys.Sample(selected, this->localTransform, this->transform); + this->positionKeys.Sample(selected, this->localTransform, this->transform); this->textureTransforms.clear(); for (auto it = this->textureKeys.begin(); it != this->textureKeys.end(); ++it) { diff --git a/Source/Contents/Models/ModelNode.h b/Source/Contents/Models/ModelNode.h index b36e8ce7e..0b5d44dba 100644 --- a/Source/Contents/Models/ModelNode.h +++ b/Source/Contents/Models/ModelNode.h @@ -51,9 +51,9 @@ public: void Animate(double frame) override; void Draw(const float* matrix, unsigned char reversed, bool clip, unsigned char commandMode) override; - /* 008C */ std::vector scaleKeys; - /* 0098 */ std::vector rotationKeys; - /* 00A4 */ std::vector positionKeys; + /* 008C */ LegacyScaleTrack scaleKeys; + /* 0098 */ LegacyRotationTrack rotationKeys; + /* 00A4 */ LegacyPositionTrack positionKeys; }; class C3dNodeV2 : public C3dNode { @@ -66,9 +66,9 @@ public: /* 008C */ matrix resourceTransform; /* 00BC */ matrix localTransform; - /* 00EC */ std::vector scaleKeys; - /* 00F8 */ std::vector rotationKeys; - /* 0104 */ std::vector positionKeys; + /* 00EC */ ModelScaleTrack scaleKeys; + /* 00F8 */ ModelRotationTrack rotationKeys; + /* 0104 */ ModelPositionTrack positionKeys; /* 0110 */ std::map textureKeys; /* 0118 */ std::map textureTransforms; };