diff --git a/Assets/Animation Clips/MD_RigTest01_SkinningTestAnims.shanimcontainer b/Assets/Animation Clips/MD_RigTest01_SkinningTestAnims.shanimcontainer index 5d6924e2..c14d75f4 100644 Binary files a/Assets/Animation Clips/MD_RigTest01_SkinningTestAnims.shanimcontainer and b/Assets/Animation Clips/MD_RigTest01_SkinningTestAnims.shanimcontainer differ diff --git a/Assets/Animation Clips/racoonAnims.shanimcontainer b/Assets/Animation Clips/racoonAnims.shanimcontainer index c0b335cf..2cd47693 100644 Binary files a/Assets/Animation Clips/racoonAnims.shanimcontainer and b/Assets/Animation Clips/racoonAnims.shanimcontainer differ diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 3943b34d..42e112b8 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -180,8 +180,8 @@ namespace Sandbox // Link up SHDebugDraw SHDebugDraw::Init(SHSystemManager::GetSystem()); - auto clip = SHResourceManager::LoadOrGet(77816045); - auto rig = SHResourceManager::LoadOrGet(77816045); + //auto clip = SHResourceManager::LoadOrGet(77816045); + //auto rig = SHResourceManager::LoadOrGet(77816045); } void SBApplication::Update(void) diff --git a/SHADE_Engine/src/Animation/SHAnimationClip.cpp b/SHADE_Engine/src/Animation/SHAnimationClip.cpp index 2066506f..b45701d8 100644 --- a/SHADE_Engine/src/Animation/SHAnimationClip.cpp +++ b/SHADE_Engine/src/Animation/SHAnimationClip.cpp @@ -20,12 +20,13 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ /* Constructors */ /*-----------------------------------------------------------------------------------*/ - SHAnimationClip::SHAnimationClip(Handle rawAnimHandle, int firstFrame, int lastFrame) - : rawAnim { rawAnimHandle } - , startFrameIndex { firstFrame } - , endFrameIndex { lastFrame } - , duration { 0.0f } - , startTimeStamp { 0.0f } + SHAnimationClip::SHAnimationClip(Handle rawAnimHandle, int firstFrame, int lastFrame, float playbackMultiplier) + : rawAnim { rawAnimHandle } + , startFrameIndex { firstFrame } + , endFrameIndex { lastFrame } + , duration { 0.0f } + , startTimeStamp { 0.0f } + , playbackSpeedMultiplier { playbackMultiplier } { if (!rawAnim) return; diff --git a/SHADE_Engine/src/Animation/SHAnimationClip.h b/SHADE_Engine/src/Animation/SHAnimationClip.h index 6b97c955..2c6b6561 100644 --- a/SHADE_Engine/src/Animation/SHAnimationClip.h +++ b/SHADE_Engine/src/Animation/SHAnimationClip.h @@ -41,25 +41,39 @@ namespace SHADE /// Handle to the raw animation data. /// First frame to be played. /// Last frame to be played. - SHAnimationClip(Handle rawAnimHandle, int firstFrame, int lastFrame); + /// Multiplier for the playback speed. + SHAnimationClip(Handle rawAnimHandle, int firstFrame, int lastFrame, float playbackMultiplier = 1.0f); /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ inline Handle GetRawAnimation() const noexcept { return rawAnim; } inline int GetStartFrameIndex() const noexcept { return startFrameIndex; } - inline int GetEndFrameIndex() const noexcept { return endFrameIndex; } - inline float GetTotalDuration() const noexcept { return duration; } + inline int GetEndFrameIndex() const noexcept { return endFrameIndex; }\ inline float GetStartTimeStamp() const noexcept { return startTimeStamp; } + inline float GetPlaybackSpeedMultiplier() const noexcept { return playbackSpeedMultiplier; } + /// + /// Retrieves the duration of the animation as if the playback speed multiplier is + /// in it's default value of 1.0f. + /// + /// Duration of the animation in seconds. + inline float GetTotalDuration() const noexcept { return duration; } + /// + /// Retrieves the duration of the animation with the playback speed multiplier + /// taken into account. + /// + /// True duration of the animation in seconds. + inline float GetTrueDuration() const noexcept { return duration / playbackSpeedMultiplier; } private: /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ Handle rawAnim; - int startFrameIndex; // First Frame - int endFrameIndex; // Last Frame (inclusive) - float duration; // Total playback time - float startTimeStamp; // Starting time stamp of the raw anim + int startFrameIndex; // First Frame + int endFrameIndex; // Last Frame (inclusive) + float duration; // Total playback time + float startTimeStamp; // Starting time stamp of the raw anim + float playbackSpeedMultiplier; // Multiplier applied to the playback of an animation clip }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Animation/SHAnimationController.cpp b/SHADE_Engine/src/Animation/SHAnimationController.cpp index 3c04614a..e105c0da 100644 --- a/SHADE_Engine/src/Animation/SHAnimationController.cpp +++ b/SHADE_Engine/src/Animation/SHAnimationController.cpp @@ -62,18 +62,21 @@ namespace SHADE if (!instData.CurrentNode) return; + // Get the clip + Handle clip = instData.CurrentNode->Clip; + // Update the current playback - instData.ClipPlaybackTime += dt; + instData.ClipPlaybackTime += dt * clip->GetPlaybackSpeedMultiplier(); // Check if we finished playing - const float CLIP_CURR_PLAYED_TIME = instData.ClipPlaybackTime - instData.CurrentNode->Clip->GetStartTimeStamp(); - if (CLIP_CURR_PLAYED_TIME > instData.CurrentNode->Clip->GetTotalDuration()) + const float CLIP_CURR_PLAYED_TIME = instData.ClipPlaybackTime - clip->GetStartTimeStamp(); + if (CLIP_CURR_PLAYED_TIME > clip->GetTotalDuration()) { // Clamp - instData.ClipPlaybackTime = instData.CurrentNode->Clip->GetStartTimeStamp() + instData.CurrentNode->Clip->GetTotalDuration(); + instData.ClipPlaybackTime = clip->GetStartTimeStamp() + clip->GetTotalDuration(); // Go to next state - Handle originalClip = instData.CurrentNode->Clip; + Handle originalClip = clip; bool stateChanged = false; for (const auto& transition : instData.CurrentNode->Transitions) { diff --git a/SHADE_Engine/src/Animation/SHAnimatorComponent.cpp b/SHADE_Engine/src/Animation/SHAnimatorComponent.cpp index 294d8098..923fb876 100644 --- a/SHADE_Engine/src/Animation/SHAnimatorComponent.cpp +++ b/SHADE_Engine/src/Animation/SHAnimatorComponent.cpp @@ -254,7 +254,7 @@ namespace SHADE } void SHAnimatorComponent::updateManualClipState(float dt) { - currPlaybackTime += dt; + currPlaybackTime += dt * currClip->GetPlaybackSpeedMultiplier(); const float CLIP_CURR_PLAYED_TIME = currPlaybackTime - currClip->GetStartTimeStamp(); if (CLIP_CURR_PLAYED_TIME > currClip->GetTotalDuration()) { diff --git a/SHADE_Engine/src/Assets/Asset Types/SHAnimClipContainerAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHAnimClipContainerAsset.h index 28d3b697..7a719685 100644 --- a/SHADE_Engine/src/Assets/Asset Types/SHAnimClipContainerAsset.h +++ b/SHADE_Engine/src/Assets/Asset Types/SHAnimClipContainerAsset.h @@ -25,6 +25,7 @@ namespace SHADE std::string name; uint32_t firstIndex; uint32_t lastIndex; + float playbackMultiplier = 1.0f; AssetID animRawDataAssetId; // Not serialised, only populated during runtime from parent asset }; diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHBinaryLoader.cpp b/SHADE_Engine/src/Assets/Libraries/Loaders/SHBinaryLoader.cpp index 119bd9aa..a8663dde 100644 --- a/SHADE_Engine/src/Assets/Libraries/Loaders/SHBinaryLoader.cpp +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHBinaryLoader.cpp @@ -79,7 +79,7 @@ namespace SHADE file.write( reinterpret_cast(&clip->firstIndex), - sizeof(uint32_t) * 2 + sizeof(uint32_t) * 3 ); } } @@ -118,7 +118,7 @@ namespace SHADE file.read( reinterpret_cast(&clip->firstIndex), - sizeof(uint32_t) * 2 + sizeof(uint32_t) * 3 ); clip->animRawDataAssetId = data->animRawDataAssetId; diff --git a/SHADE_Engine/src/Assets/SHAssetManager.cpp b/SHADE_Engine/src/Assets/SHAssetManager.cpp index 8cddaf2c..dc9d9587 100644 --- a/SHADE_Engine/src/Assets/SHAssetManager.cpp +++ b/SHADE_Engine/src/Assets/SHAssetManager.cpp @@ -313,7 +313,7 @@ namespace SHADE .isSubAsset = true, .parent = parent }; - auto& newClip {animContainer->clips.emplace_back()}; + auto& newClip {animContainer->clips.emplace_back(new SHAnimClipAsset())}; newClip->name = name; assetCollection.emplace(id, asset); assetCollection[parent].subAssets.push_back(&assetCollection[id]); diff --git a/SHADE_Engine/src/Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.cpp index 332bf6e9..e85efaf4 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.cpp @@ -54,6 +54,7 @@ namespace SHADE newAssetName.clear(); firstIndex = 0; lastIndex = rawAnimation->GetTotalFrames(); + playbackMultiplier = 1.0f; } // Assign callback @@ -72,6 +73,9 @@ namespace SHADE SHEditorUI::PushID(1); SHEditorUI::InputUnsignedInt("Last Frame Index", lastIndex); SHEditorUI::PopID(); + SHEditorUI::PushID(2); + SHEditorUI::InputFloat("Playback Multiplier", playbackMultiplier); + SHEditorUI::PopID(); // Invalid values const bool INVALID_CONFIG = newAssetName.empty() || firstIndex > lastIndex; @@ -88,6 +92,7 @@ namespace SHADE animClip->firstIndex = firstIndex; animClip->lastIndex = lastIndex; animClip->animRawDataAssetId = SHResourceManager::GetAssetID(rawAnimation).value_or(0); + animClip->playbackMultiplier = playbackMultiplier; SHAssetManager::SaveAsset(containerAsset->id); // Close @@ -168,6 +173,7 @@ namespace SHADE int firstIndex = animClip->GetStartFrameIndex(); int endIndex = animClip->GetEndFrameIndex(); + float playbackMp = animClip->GetPlaybackSpeedMultiplier(); ImGui::Separator(); ImGui::Text(animClipName.has_value() ? animClipName.value().c_str() : ""); @@ -183,12 +189,18 @@ namespace SHADE [&]() { return endIndex; }, [&](int i) { endIndex = i; } ); + changed |= SHEditorWidgets::DragFloat + ( + "Playback Multiplier", + [&]() { return playbackMp; }, + [&](float f) { playbackMp = f; } + ); // If there's a change we need to commit changes if (changed && firstIndex < endIndex) { // Update runtime asset - *animClip = SHAnimationClip(currRawAnim, firstIndex, endIndex); + *animClip = SHAnimationClip(currRawAnim, firstIndex, endIndex, playbackMp); // Update serialized asset auto assetId = SHResourceManager::GetAssetID(animClip); @@ -197,6 +209,7 @@ namespace SHADE auto const animAsset = SHAssetManager::GetData(assetId.value()); animAsset->firstIndex = firstIndex; animAsset->lastIndex = endIndex; + animAsset->playbackMultiplier = playbackMp; SHAssetManager::SaveAsset(containerAsset->id); } } diff --git a/SHADE_Engine/src/Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.h b/SHADE_Engine/src/Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.h index 6790cded..550bd158 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.h +++ b/SHADE_Engine/src/Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.h @@ -62,6 +62,7 @@ namespace SHADE std::string newAssetName; uint32_t firstIndex = 0; uint32_t lastIndex = 0; + float playbackMultiplier = 1.0f; Handle rawAnimation; SHAsset* containerAsset{nullptr}; SHAnimClipContainerAsset* container{nullptr}; diff --git a/SHADE_Engine/src/Resource/SHResourceManager.hpp b/SHADE_Engine/src/Resource/SHResourceManager.hpp index 6474b478..d2bc9241 100644 --- a/SHADE_Engine/src/Resource/SHResourceManager.hpp +++ b/SHADE_Engine/src/Resource/SHResourceManager.hpp @@ -372,7 +372,8 @@ namespace SHADE ( LoadOrGet(assetData.animRawDataAssetId), assetData.firstIndex, - assetData.lastIndex + assetData.lastIndex, + assetData.playbackMultiplier ); } else if constexpr (std::is_same_v)