Implemented Animation Clip asset and animation controller #410

Merged
XiaoQiDigipen merged 66 commits from SP3-22-AnimationController into main 2023-03-09 16:19:40 +08:00
12 changed files with 374 additions and 187 deletions
Showing only changes of commit e97f5747cb - Show all commits

View File

@ -13,6 +13,7 @@ of DigiPen Institute of Technology is prohibited.
#include "SHpch.h"
// Primary Header
#include "SHAnimationClip.h"
#include "SHRawAnimation.h"
namespace SHADE
{
@ -23,5 +24,12 @@ namespace SHADE
: rawAnim { rawAnimHandle }
, startFrameIndex { firstFrame }
, endFrameIndex { lastFrame }
{}
, duration { 0.0f }
{
if (!rawAnim)
return;
const int ONE_PAST_LAST_FRAME = lastFrame + 1;
duration = (ONE_PAST_LAST_FRAME - firstFrame) / rawAnim->GetTicksPerSecond();
}
}

View File

@ -50,6 +50,7 @@ namespace SHADE
inline Handle<SHRawAnimation> 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; }
private:
/*---------------------------------------------------------------------------------*/
@ -58,5 +59,6 @@ namespace SHADE
Handle<SHRawAnimation> rawAnim;
int startFrameIndex; // First Frame
int endFrameIndex; // Last Frame (inclusive)
float duration; // Total playback time
};
}

View File

@ -20,21 +20,27 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*-----------------------------------------------------------------------------------*/
void SHAnimationController::Update()
void SHAnimationController::Update(InstanceData& instData, float dt)
{
// Is there a valid node
if (!currentNode)
if (!instData.CurrentNode)
return;
// Update
for (const auto& transition : currentNode->Transitions)
{
// Update the current playback
instData.ClipPlaybackTime += dt;
}
}
void SHAnimationController::Reset()
// Check if we finished playing
if (instData.ClipPlaybackTime > instData.CurrentNode->Clip->GetTotalDuration())
{
currentNode = startNode;
// Clamp
instData.ClipPlaybackTime = instData.CurrentNode->Clip->GetTotalDuration();
// Go to next state
for (const auto& transition : instData.CurrentNode->Transitions)
{
// TODO
}
}
}
/*-----------------------------------------------------------------------------------*/
@ -75,4 +81,24 @@ namespace SHADE
// Clear node
node.Free();
}
/*-----------------------------------------------------------------------------------*/
/* AnimParam Functions */
/*-----------------------------------------------------------------------------------*/
SHAnimationController::AnimParam::AnimParam(Type type)
: ParamType { type }
{
switch (ParamType)
{
case Type::Bool:
Value = false;
break;
case Type::Float:
Value = 0.0f;
break;
case Type::Int:
Value = 0;
break;
}
}
}

View File

@ -27,6 +27,7 @@ namespace SHADE
/// <summary>
/// Object that controls the animation that is played by an animator through the use
/// of an internal state machine.
/// This should never be modified once it has been attached to a SHAnimatorComponent!
/// </summary>
class SH_API SHAnimationController
{
@ -58,12 +59,23 @@ namespace SHADE
Float,
Int
};
using ValueType = std::variant<bool, float, int>;
/*-------------------------------------------------------------------------------*/
/* Constructor */
/*-------------------------------------------------------------------------------*/
/// <summary>
/// Constructs an AnimParam with the default value set for the Value field based
/// on the specified type.
/// </summary>
/// <param name="type">Type of AnimParam.</param>
explicit AnimParam(Type type);
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
Type ParamType;
std::variant<bool, float, int> Value;
ValueType Value;
};
/// <summary>
@ -92,6 +104,7 @@ namespace SHADE
/* Data Members */
/*-------------------------------------------------------------------------------*/
ConditionType Condition;
AnimParam::ValueType Threshold;
Handle<Node> Target;
};
@ -104,17 +117,23 @@ namespace SHADE
std::vector<Transition> Transitions;
};
/// <summary>
/// Describes a node in the animation controller.
/// </summary>
struct InstanceData
{
Handle<Node> CurrentNode;
std::unordered_map<std::string, AnimParam> Params;
float ClipPlaybackTime;
};
/*---------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Runs a single update for the animation controller.
/// </summary>
void Update();
/// <summary>
/// Resets the animation controller to its starting node.
/// </summary>
void Reset();
void Update(InstanceData& instData, float dt);
/*---------------------------------------------------------------------------------*/
/* Usage Functions */
@ -130,20 +149,23 @@ namespace SHADE
/// </summary>
/// <param name="node">Node to destroy.</param>
void DestroyNode(Handle<Node> node);
void AddTransition(Handle<Node> source, const Transition& transition);
void AddParameter(const std::string& name, AnimParam::Type type);
/*---------------------------------------------------------------------------------*/
/* Getters */
/*---------------------------------------------------------------------------------*/
Handle<Node> GetCurrentNode() const noexcept { return currentNode; }
Handle<Node> GetStartingNode() const noexcept { return startNode; }
const std::unordered_map<std::string, AnimParam::Type>& GetParams() const noexcept { return parameters; }
const std::vector<Handle<Node>>& GetNodes() const noexcept { return nodes; }
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
// State machine
Handle<Node> currentNode;
Handle<Node> startNode;
std::vector<Handle<Node>> nodes;
std::unordered_map<std::string, AnimParam> parameters;
std::unordered_map<std::string, AnimParam::Type> parameters;
};
}

View File

@ -39,9 +39,42 @@ namespace SHADE
void SHAnimatorComponent::Play(Handle<SHAnimationClip> clip)
{
// Ignore if nothing is specified
if (!clip)
{
SHLOG_WARNING("[SHAnimatorComponent] Attempted to play an null SHAnimationClip. Use Stop() if stopping animation instead.");
return;
}
// Remove animation controller as we switch to manual play mode
animController = {};
animInstanceData.CurrentNode = {};
animInstanceData.Params.clear();
animInstanceData.ClipPlaybackTime = 0.0f;
// Set accordingly
currClip = clip;
currPlaybackTime = 0.0f;
channelMaps.clear();
auto RAW_ANIM = clip->GetRawAnimation();
// Set up if valid
if (currClip && RAW_ANIM)
{
// Create channel maps
channelMaps.emplace(RAW_ANIM, createChannelMap(RAW_ANIM));
// Calculate secs for the clip
secsPerTick = 1.0f / RAW_ANIM->GetTicksPerSecond();
// Start playback
Play();
// Set to initial pose
if (rig && rig->GetRootNode())
{
updateCurrentAnimatorState(currClip, 0.0f);
}
}
}
void SHAnimatorComponent::PlayOneShot(Handle<SHAnimationClip> clip)
@ -67,6 +100,37 @@ namespace SHADE
currPlaybackTime = 0.0f;
}
/*-----------------------------------------------------------------------------------*/
/* Update Functions */
/*-----------------------------------------------------------------------------------*/
void SHAnimatorComponent::Update(float dt)
{
// Reset matrices
std::fill(boneMatrices.begin(), boneMatrices.end(), SHMatrix::Identity);
// Do not do anything if is not playing or there's nothing to animate
if (!isPlaying || !rig || !rig->GetRootNode())
return;
// Update the animation controller if any, this will set the currClip
if (animController)
{
updateAnimController(dt);
// Only update the animation state if there is a clip
if (animInstanceData.CurrentNode && animInstanceData.CurrentNode->Clip)
{
updateCurrentAnimatorState(animInstanceData.CurrentNode->Clip, animInstanceData.ClipPlaybackTime);
}
}
// Otherwise, a single clip was provided, then we'll use it
else if (currClip)
{
updateManualClipState(dt);
updateCurrentAnimatorState(currClip, currPlaybackTime);
}
}
/*-----------------------------------------------------------------------------------*/
/* Setter Functions */
/*-----------------------------------------------------------------------------------*/
@ -86,95 +150,133 @@ namespace SHADE
}
}
void SHAnimatorComponent::SetClip(Handle<SHAnimationClip> newClip)
void SHAnimatorComponent::SetAnimationController(Handle<SHAnimationController> ac)
{
// No change
if (currClip == newClip)
if (animController == ac)
return;
// Get animation data
auto animData = currClip->GetRawAnimation();
if (!animData)
return;
// Set the controller
animController = ac;
// Set parameters
currClip = newClip;
secsPerTick = 1.0f / animData->GetTicksPerSecond();
// Calculate total time for the clip
if (currClip)
// If valid, we want to initialize it
if (animController)
{
const int ONE_PAST_LAST_FRAME = currClip->GetEndFrameIndex() + 1;
currClipTotalTime = (ONE_PAST_LAST_FRAME - currClip->GetStartFrameIndex()) / animData->GetTicksPerSecond();
// Parameters
animInstanceData.Params.clear();
for (auto param : animController->GetParams())
{
animInstanceData.Params.emplace(param.first, SHAnimationController::AnimParam(param.second));
}
// First Node
animInstanceData.CurrentNode = animController->GetStartingNode();
// Playback Time
animInstanceData.ClipPlaybackTime = 0.0f;
// Get set of unique SHRawAnimation used by the animController
std::unordered_set<Handle<SHRawAnimation>> rawAnims;
for (auto node : animController->GetNodes())
{
// Ensure no null handles
if (!node)
continue;
const Handle<SHAnimationClip> CLIP = node->Clip;
if (!CLIP)
continue;
const Handle<SHRawAnimation> RAW_ANIM = CLIP->GetRawAnimation();
if (!RAW_ANIM)
continue;
// Store
rawAnims.emplace(RAW_ANIM);
}
// Build channel map and clip-specific data
channelMap.clear();
if (animData)
// Load channel maps
for (auto anim : rawAnims)
{
for (const auto& channel : animData->GetChannels())
channelMaps.emplace(anim, createChannelMap(anim));
}
}
}
/*-----------------------------------------------------------------------------------*/
/* Helper Functions - Loading */
/*-----------------------------------------------------------------------------------*/
SHAnimatorComponent::ChannelMap SHAnimatorComponent::createChannelMap(Handle<SHRawAnimation> rawAnimData)
{
ChannelMap channelMap;
for (const auto& channel : rawAnimData->GetChannels())
{
channelMap.emplace(channel.Name, &channel);
}
}
if (rig && rig->GetRootNode() && currClip)
{
updatePoseWithClip(0.0f);
}
return channelMap;
}
/*-----------------------------------------------------------------------------------*/
/* Update Functions */
/* Helper Functions - Update */
/*-----------------------------------------------------------------------------------*/
void SHAnimatorComponent::Update(float dt)
void SHAnimatorComponent::updateAnimController(float dt)
{
// Reset matrices
std::fill(boneMatrices.begin(), boneMatrices.end(), SHMatrix::Identity);
// Nothing to animate
if (!currClip || !isPlaying || !rig || !rig->GetRootNode())
// No animation controller
if (!animInstanceData.CurrentNode)
return;
// Get animation data
auto animData = currClip->GetRawAnimation();
if (!animData)
return;
// Update the animation controller
animController->Update(animInstanceData, dt);
// Update time on the playback
// Get current clip
currClip = animInstanceData.CurrentNode->Clip;
if (currClip && currClip->GetRawAnimation())
{
secsPerTick = 1.0f / currClip->GetRawAnimation();
}
}
void SHAnimatorComponent::updateManualClipState(float dt)
{
currPlaybackTime += dt;
if (currPlaybackTime > currClipTotalTime)
if (currPlaybackTime > currClip->GetTotalDuration())
{
if (playOnce)
{
playOnce = false;
isPlaying = false;
currPlaybackTime = currClip->GetTotalDuration();
}
else
{
currPlaybackTime = currPlaybackTime - currClipTotalTime;
currPlaybackTime = currPlaybackTime - currClip->GetTotalDuration();
}
}
}
void SHAnimatorComponent::updateCurrentAnimatorState(Handle<SHAnimationClip> clip, float playbackTime)
{
// Nothing to animate
if (!clip || !isPlaying || !rig || !rig->GetRootNode())
return;
// Check that we have animation data
if (!clip->GetRawAnimation())
return;
// Play the clip
updatePoseWithClip(currPlaybackTime);
updatePoseWithClip(clip, currPlaybackTime);
}
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/
void SHAnimatorComponent::updatePoseWithClip(float poseTime)
void SHAnimatorComponent::updatePoseWithClip(Handle<SHAnimationClip> clip, float poseTime)
{
// Get closest frame index
const int CLOSEST_FRAME_IDX = currClip->GetStartFrameIndex() + static_cast<int>(std::floorf(poseTime * currClip->GetRawAnimation()->GetTicksPerSecond()));
updatePoseWithClip(CLOSEST_FRAME_IDX, poseTime, rig->GetRootNode(), SHMatrix::Identity);
const int CLOSEST_FRAME_IDX = clip->GetStartFrameIndex() + static_cast<int>(std::floorf(poseTime / secsPerTick));
updatePoseWithClip(CLOSEST_FRAME_IDX, poseTime, clip->GetRawAnimation(), rig->GetRootNode(), SHMatrix::Identity);
}
void SHAnimatorComponent::updatePoseWithClip(int closestFrameIndex, float poseTime, Handle<SHRigNode> node, const SHMatrix& parentMatrix)
void SHAnimatorComponent::updatePoseWithClip(int closestFrameIndex, float poseTime, Handle<SHRawAnimation> rawAnimData, Handle<SHRigNode> node, const SHMatrix& parentMatrix)
{
// Check if there is a channel for this node
const std::string& BONE_NAME = rig->GetName(node);
SHMatrix transformMatrix = node->TransformMatrix;
if (channelMaps.contains(rawAnimData))
{
auto channelMap = channelMaps[rawAnimData];
if (channelMap.contains(BONE_NAME))
{
const auto CHANNEL = channelMap[BONE_NAME];
@ -185,6 +287,7 @@ namespace SHADE
getInterpolatedValue(CHANNEL->ScaleKeyFrames, closestFrameIndex, poseTime)
);
}
}
// Apply parent's transformation
transformMatrix = transformMatrix * parentMatrix;
@ -200,7 +303,7 @@ namespace SHADE
// Apply pose to children
for (auto& child : node->Children)
{
updatePoseWithClip(closestFrameIndex, poseTime, child, transformMatrix);
updatePoseWithClip(closestFrameIndex, poseTime, rawAnimData, child, transformMatrix);
}
}
}

View File

@ -23,6 +23,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Math/Vector/SHVec3.h"
#include "Math/SHQuaternion.h"
#include "SHRawAnimation.h"
#include "SHAnimationController.h"
namespace SHADE
{
@ -52,12 +53,14 @@ namespace SHADE
/// </summary>
void Play();
/// <summary>
/// Plays the specified animation clip from the start.
/// Plays the specified animation clip from the start. This will unset any
/// SHAnimationControllers that have been set.
/// </summary>
/// <param name="clip">Animation clip to play.</param>
void Play(Handle<SHAnimationClip> clip);
/// <summary>
/// Plays the specified animation clip from the start one time only.
/// Plays the specified animation clip from the start one time only. This will unset
/// any SHAnimationControllers that have been set.
/// </summary>
/// <param name="clip">Animation clip to play.</param>
void PlayOneShot(Handle<SHAnimationClip> clip);
@ -74,6 +77,16 @@ namespace SHADE
/// </summary>
void Stop();
/*---------------------------------------------------------------------------------*/
/* Update Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Updates the current state of the animation if one is specified based on the
/// current animation clip and frames. This will update the bone matrices.
/// </summary>
/// <param name="dt">Time passed since the last frame.</param>
void Update(float dt);
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
@ -82,13 +95,7 @@ namespace SHADE
/// </summary>
/// <param name="newRig">Rig to use.</param>
void SetRig(Handle<SHRig> newRig);
/// <summary>
/// Sets the animation clip of this animator without playing it.
/// This will set the pose of the model to it's initial pose.
/// If the clip is the same as the current clip, nothing happens.
/// </summary>
/// <param name="newClip">Clip to use.</param>
void SetClip(Handle<SHAnimationClip> newClip);
void SetAnimationController(Handle<SHAnimationController> ac);
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
@ -104,51 +111,55 @@ namespace SHADE
/// <returns>Handle to the currently set rig.</returns>
Handle<SHRig> GetRig() const noexcept { return rig; }
/// <summary>
/// <summary>
/// Retrieve the currently set animation clip.
/// </summary>
/// <returns>Handle to the currently set animation clip.</returns>
Handle<SHAnimationClip> GetCurrentClip() const noexcept { return currClip; }
/// <summary>
/// Checks if an animation is currently playing.
/// </summary>
/// <returns>True if an animation clip is currently playing.</returns>
bool IsPlaying() const { return isPlaying; }
/*---------------------------------------------------------------------------------*/
/* Update Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Updates the current state of the animation if one is specified based on the
/// current animation clip and frames. This will update the bone matrices.
/// Retrieves the current node for the Animation Controller. This returns a null
/// if there is no Animation Controller currently set.
/// </summary>
/// <param name="dt">Time passed since the last frame.</param>
void Update(float dt);
/// <returns>Handle to the current Animation Controller node.</returns>
Handle<SHAnimationController::Node> GetCurrentNode() const noexcept { return animInstanceData.CurrentNode; }
Handle<SHAnimationController> GetAnimationController() const noexcept { return animController; }
private:
/*---------------------------------------------------------------------------------*/
/* Type Definition */
/*---------------------------------------------------------------------------------*/
using ChannelMap = std::unordered_map<std::string, const SHRawAnimation::Channel*>;
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
// Resources
Handle<SHRig> rig;
// Playback Tracking for Animation Controller Mode
Handle<SHAnimationController> animController;
SHAnimationController::InstanceData animInstanceData;
// Playback Tracking for Manual Mode
Handle<SHAnimationClip> currClip;
// Playback Tracking
float currPlaybackTime = 0.0f;
bool isPlaying = true;
bool playOnce = false;
float currClipTotalTime = 0.0f;
// Useful Cached Data
// Shared Tracking
bool isPlaying = true;
float secsPerTick = 0.0f;
// Buffer
std::vector<SHMatrix> boneMatrices;
// Caches
std::unordered_map<std::string, const SHRawAnimation::Channel*> channelMap;
std::unordered_map<Handle<SHRawAnimation>, ChannelMap> channelMaps;
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
void updatePoseWithClip(float poseTime);
void updatePoseWithClip(int closestFrameIndex, float poseTime, Handle<SHRigNode> node, const SHMatrix& parentMatrix);
// Loading
ChannelMap createChannelMap(Handle<SHRawAnimation> rawAnimData);
// Update
void updateAnimController(float dt);
void updateManualClipState(float dt);
void updateCurrentAnimatorState(Handle<SHAnimationClip> clip, float playbackTime);
void updatePoseWithClip(Handle<SHAnimationClip> clip, float poseTime);
void updatePoseWithClip(int closestFrameIndex, float poseTime, Handle<SHRawAnimation> rawAnimData, Handle<SHRigNode> node, const SHMatrix& parentMatrix);
template<typename T>
T getInterpolatedValue(const std::vector<SHAnimationKeyFrame<T>>& keyframes, int closestFrameIndex, float poseTime);

View File

@ -0,0 +1,27 @@
/************************************************************************************//*!
\file SHAnimControllerAsset.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 1, 2023
\brief Contains the definition of the SHAnimControllerAsset struct and related
types.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
#include <string>
#include "SH_API.h"
#include "SHAssetData.h"
namespace SHADE
{
struct SH_API SHAnimControllerAsset : SHAssetData
{
std::string name;
// TODO
};
}

View File

@ -646,31 +646,6 @@ namespace SHADE
SHEditorWindowManager::GetEditorWindow<SHAssetBrowser>()->SetScrollTo(assetID);
}
}
Handle<SHRawAnimation> const clip = (component->GetCurrentClip() ? component->GetCurrentClip()->GetRawAnimation() : Handle<SHRawAnimation>{});
const auto CLIP_NAME = clip ? SHResourceManager::GetAssetName<SHRawAnimation>(clip).value_or("") : "";
SHEditorWidgets::DragDropReadOnlyField<AssetID>("Clip", CLIP_NAME,
[component]()
{
Handle<SHRawAnimation> const clip = (component->GetCurrentClip() ? component->GetCurrentClip()->GetRawAnimation() : Handle<SHRawAnimation>{});
return SHResourceManager::GetAssetID<SHRawAnimation>(clip).value_or(0);
},
[component](AssetID const& id)
{
if (SHAssetManager::GetType(id) != AssetType::MODEL)
{
SHLOG_WARNING("Attempted to assign non mesh asset to Renderable Mesh property!")
return;
}
component->SetClip(SHResourceManager::LoadOrGet<SHAnimationClip>(id));
}, SHDragDrop::DRAG_RESOURCE);
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
{
if (Handle<SHRawAnimation> const clip = component->GetCurrentClip()->GetRawAnimation())
{
AssetID assetID = SHResourceManager::GetAssetID<SHRawAnimation>(clip).value_or(0);
SHEditorWindowManager::GetEditorWindow<SHAssetBrowser>()->SetScrollTo(assetID);
}
}
}
else
{

View File

@ -22,6 +22,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Assets/Asset Types/SHTextureAsset.h"
#include "Assets/Asset Types/SHShaderAsset.h"
#include "Assets/Asset Types/SHAnimClipAsset.h"
#include "Assets/Asset Types/SHAnimControllerAsset.h"
#include "Graphics/Shaders/SHVkShaderModule.h"
#include "Graphics/MiddleEnd/Textures/SHTextureLibrary.h"
#include "Graphics/MiddleEnd/Interface/SHMeshLibrary.h"
@ -40,6 +41,7 @@ namespace SHADE
class SHMaterial;
struct SHRigNode;
class SHAnimationClip;
class SHAnimationController;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
@ -58,6 +60,7 @@ namespace SHADE
template<> struct SHResourceLoader<SHRawAnimation> { using AssetType = SHModelAsset; };
template<> struct SHResourceLoader<SHRig> { using AssetType = SHModelAsset; };
template<> struct SHResourceLoader<SHAnimationClip> { using AssetType = SHAnimClipAsset; };
template<> struct SHResourceLoader<SHAnimationController> { using AssetType = SHAnimControllerAsset; };
/// <summary>
/// Static class responsible for loading and caching runtime resources from their

View File

@ -43,7 +43,9 @@ namespace SHADE
!std::is_same_v<ResourceType, SHFont> &&
!std::is_same_v<ResourceType, SHMaterial> &&
!std::is_same_v<ResourceType, SHRawAnimation> &&
!std::is_same_v<ResourceType, SHRig>
!std::is_same_v<ResourceType, SHRig> &&
!std::is_same_v<ResourceType, SHAnimationClip> &&
!std::is_same_v<ResourceType, SHAnimationController>
)
{
static_assert(true, "Unsupported Resource Type specified for SHResourceManager.");
@ -361,7 +363,7 @@ namespace SHADE
loadedAssetData.emplace_back(assetId);
return resourceHub.Create<ResourceType>(*assetData.anims[0]);
}
else if constexpr (std::is_same_v<ResourceType, SHAnimClipAsset>)
else if constexpr (std::is_same_v<ResourceType, SHAnimationClip>)
{
loadedAssetData.emplace_back(assetId);
return resourceHub.Create<ResourceType>
@ -371,5 +373,13 @@ namespace SHADE
assetData->lastIndex
);
}
else if constexpr (std::is_same_v<ResourceType, SHAnimationController>)
{
loadedAssetData.emplace_back(assetId);
return resourceHub.Create<ResourceType>
(
// TODO
);
}
}
}

View File

@ -394,13 +394,13 @@ namespace YAML
struct convert<SHAnimatorComponent>
{
static constexpr std::string_view RIG_YAML_TAG = "Rig";
static constexpr std::string_view CLIP_YAML_TAG = "Clip";
static constexpr std::string_view AC_YAML_TAG = "AnimationController";
static YAML::Node encode(SHAnimatorComponent const& rhs)
{
YAML::Node node;
node[RIG_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHRig>(rhs.GetRig()).value_or(0);
node[CLIP_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHAnimationClip>(rhs.GetCurrentClip()).value_or(0);
node[AC_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHAnimationController>(rhs.GetAnimationController()).value_or(0);
return node;
}
static bool decode(YAML::Node const& node, SHAnimatorComponent& rhs)
@ -409,9 +409,9 @@ namespace YAML
{
rhs.SetRig(SHResourceManager::LoadOrGet<SHRig>(node[RIG_YAML_TAG.data()].as<AssetID>()));
}
if (node[CLIP_YAML_TAG.data()].IsDefined())
if (node[AC_YAML_TAG.data()].IsDefined())
{
rhs.SetClip(SHResourceManager::LoadOrGet<SHAnimationClip>(node[CLIP_YAML_TAG.data()].as<AssetID>()));
rhs.SetAnimationController(SHResourceManager::LoadOrGet<SHAnimationController>(node[AC_YAML_TAG.data()].as<AssetID>()));
}
return true;
}