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
{
@ -20,8 +21,15 @@ namespace SHADE
/* Constructors */
/*-----------------------------------------------------------------------------------*/
SHAnimationClip::SHAnimationClip(Handle<SHRawAnimation> rawAnimHandle, int firstFrame, int lastFrame)
: rawAnim { rawAnimHandle }
: 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,22 +20,28 @@ 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;
// Check if we finished playing
if (instData.ClipPlaybackTime > instData.CurrentNode->Clip->GetTotalDuration())
{
// Clamp
instData.ClipPlaybackTime = instData.CurrentNode->Clip->GetTotalDuration();
// Go to next state
for (const auto& transition : instData.CurrentNode->Transitions)
{
// TODO
}
}
}
void SHAnimationController::Reset()
{
currentNode = startNode;
}
/*-----------------------------------------------------------------------------------*/
/* Usage Functions */
@ -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;
Type ParamType;
ValueType Value;
};
/// <summary>
@ -91,10 +103,11 @@ namespace SHADE
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
ConditionType Condition;
Handle<Node> Target;
ConditionType Condition;
AnimParam::ValueType Threshold;
Handle<Node> Target;
};
/// <summary>
/// Describes a node in the animation controller.
/// </summary>
@ -103,6 +116,16 @@ namespace SHADE
Handle<SHAnimationClip> Clip;
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 */
@ -110,11 +133,7 @@ namespace SHADE
/// <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;
Play();
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,104 +150,143 @@ 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();
}
// Build channel map and clip-specific data
channelMap.clear();
if (animData)
{
for (const auto& channel : animData->GetChannels())
// Parameters
animInstanceData.Params.clear();
for (auto param : animController->GetParams())
{
channelMap.emplace(channel.Name, &channel);
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);
}
// Load channel maps
for (auto anim : rawAnims)
{
channelMaps.emplace(anim, createChannelMap(anim));
}
}
if (rig && rig->GetRootNode() && currClip)
}
/*-----------------------------------------------------------------------------------*/
/* Helper Functions - Loading */
/*-----------------------------------------------------------------------------------*/
SHAnimatorComponent::ChannelMap SHAnimatorComponent::createChannelMap(Handle<SHRawAnimation> rawAnimData)
{
ChannelMap channelMap;
for (const auto& channel : rawAnimData->GetChannels())
{
updatePoseWithClip(0.0f);
channelMap.emplace(channel.Name, &channel);
}
return channelMap;
}
/*-----------------------------------------------------------------------------------*/
/* Helper Functions - Update */
/*-----------------------------------------------------------------------------------*/
void SHAnimatorComponent::updateAnimController(float dt)
{
// No animation controller
if (!animInstanceData.CurrentNode)
return;
// Update the animation controller
animController->Update(animInstanceData, dt);
// Get current clip
currClip = animInstanceData.CurrentNode->Clip;
if (currClip && currClip->GetRawAnimation())
{
secsPerTick = 1.0f / currClip->GetRawAnimation();
}
}
/*-----------------------------------------------------------------------------------*/
/* Update Functions */
/*-----------------------------------------------------------------------------------*/
void SHAnimatorComponent::Update(float dt)
void SHAnimatorComponent::updateManualClipState(float dt)
{
// Reset matrices
std::fill(boneMatrices.begin(), boneMatrices.end(), SHMatrix::Identity);
// Nothing to animate
if (!currClip || !isPlaying || !rig || !rig->GetRootNode())
return;
// Get animation data
auto animData = currClip->GetRawAnimation();
if (!animData)
return;
// Update time on the playback
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 (channelMap.contains(BONE_NAME))
if (channelMaps.contains(rawAnimData))
{
const auto CHANNEL = channelMap[BONE_NAME];
transformMatrix = SHMatrix::Transform
(
getInterpolatedValue(CHANNEL->PositionKeyFrames, closestFrameIndex, poseTime),
getInterpolatedValue(CHANNEL->RotationKeyFrames, closestFrameIndex, poseTime),
getInterpolatedValue(CHANNEL->ScaleKeyFrames, closestFrameIndex, poseTime)
);
auto channelMap = channelMaps[rawAnimData];
if (channelMap.contains(BONE_NAME))
{
const auto CHANNEL = channelMap[BONE_NAME];
transformMatrix = SHMatrix::Transform
(
getInterpolatedValue(CHANNEL->PositionKeyFrames, closestFrameIndex, poseTime),
getInterpolatedValue(CHANNEL->RotationKeyFrames, closestFrameIndex, poseTime),
getInterpolatedValue(CHANNEL->ScaleKeyFrames, closestFrameIndex, poseTime)
);
}
}
// Apply parent's transformation
@ -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

@ -18,10 +18,10 @@
// FMOD Fwd Declare
namespace FMOD
{
class Sound;
class System;
class ChannelGroup;
class Channel;
class Sound;
class System;
class ChannelGroup;
class Channel;
}
enum FMOD_RESULT : int;
enum FMOD_SPEAKERMODE : int;
@ -45,9 +45,9 @@ constexpr AssetID INVALID_ASSET_ID {0};
// Asset type enum
enum class AssetType : AssetTypeMeta
{
INVALID,
SHADER,
SHADER_BUILT_IN,
INVALID,
SHADER,
SHADER_BUILT_IN,
TEXTURE,
MODEL,
SCENE,
@ -56,7 +56,7 @@ enum class AssetType : AssetTypeMeta
MESH,
SCRIPT,
FONT,
MAX_COUNT
MAX_COUNT
};
constexpr size_t TYPE_COUNT{ static_cast<size_t>(AssetType::MAX_COUNT) };
@ -94,18 +94,18 @@ constexpr std::string_view TEXTURE_EXTENSION {".shtex"};
constexpr std::string_view MODEL_EXTENSION{ ".shmodel" };
constexpr std::string_view EXTENSIONS[] = {
AUDIO_EXTENSION,
SHADER_EXTENSION,
SHADER_BUILT_IN_EXTENSION,
AUDIO_EXTENSION,
SHADER_EXTENSION,
SHADER_BUILT_IN_EXTENSION,
TEXTURE_EXTENSION,
MODEL_EXTENSION,
SCENE_EXTENSION,
PREFAB_EXTENSION,
PREFAB_EXTENSION,
MATERIAL_EXTENSION,
"dummy",
SCRIPT_EXTENSION,
FONT_EXTENSION,
AUDIO_WAV_EXTENSION,
AUDIO_WAV_EXTENSION,
};
constexpr size_t EXTENSIONS_COUNT{ 11 };
@ -118,10 +118,10 @@ constexpr std::string_view GLTF_EXTENSION{ ".gltf" };
constexpr std::string_view TTF_EXTENSION{ ".ttf" };
constexpr std::string_view EXTERNALS[] = {
GLSL_EXTENSION,
DDS_EXTENSION,
FBX_EXTENSION,
GLTF_EXTENSION,
GLSL_EXTENSION,
DDS_EXTENSION,
FBX_EXTENSION,
GLTF_EXTENSION,
TTF_EXTENSION
};
@ -131,9 +131,9 @@ constexpr std::string_view FRAGMENT_SHADER{ "_FS" };
constexpr std::string_view COMPUTER_SHADER{ "_CS" };
constexpr std::pair<std::string_view, SHADE::SH_SHADER_TYPE> SHADER_IDENTIFIERS[] = {
std::make_pair(VERTEX_SHADER, SHADE::SH_SHADER_TYPE::VERTEX),
std::make_pair(FRAGMENT_SHADER, SHADE::SH_SHADER_TYPE::FRAGMENT),
std::make_pair(COMPUTER_SHADER, SHADE::SH_SHADER_TYPE::COMPUTE)
std::make_pair(VERTEX_SHADER, SHADE::SH_SHADER_TYPE::VERTEX),
std::make_pair(FRAGMENT_SHADER, SHADE::SH_SHADER_TYPE::FRAGMENT),
std::make_pair(COMPUTER_SHADER, SHADE::SH_SHADER_TYPE::COMPUTE)
};
constexpr size_t SHADER_TYPE_MAX_COUNT{ 3 };

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 */
@ -48,16 +50,17 @@ namespace SHADE
/// Template structs that maps a resource to their loaded asset representation type.
/// </summary>
template<typename T = void>
struct SHResourceLoader { using AssetType = void; };
template<> struct SHResourceLoader<SHMesh> { using AssetType = SHMeshAsset; };
template<> struct SHResourceLoader<SHTexture> { using AssetType = SHTextureAsset; };
template<> struct SHResourceLoader<SHVkShaderModule> { using AssetType = SHShaderAsset; };
template<> struct SHResourceLoader<SHMaterialSpec> { using AssetType = SHMaterialAsset; };
template<> struct SHResourceLoader<SHMaterial> { using AssetType = SHMaterialSpec; };
template<> struct SHResourceLoader<SHFont> { using AssetType = SHFontAsset; };
template<> struct SHResourceLoader<SHRawAnimation> { using AssetType = SHModelAsset; };
template<> struct SHResourceLoader<SHRig> { using AssetType = SHModelAsset; };
template<> struct SHResourceLoader<SHAnimationClip> { using AssetType = SHAnimClipAsset; };
struct SHResourceLoader { using AssetType = void; };
template<> struct SHResourceLoader<SHMesh> { using AssetType = SHMeshAsset; };
template<> struct SHResourceLoader<SHTexture> { using AssetType = SHTextureAsset; };
template<> struct SHResourceLoader<SHVkShaderModule> { using AssetType = SHShaderAsset; };
template<> struct SHResourceLoader<SHMaterialSpec> { using AssetType = SHMaterialAsset; };
template<> struct SHResourceLoader<SHMaterial> { using AssetType = SHMaterialSpec; };
template<> struct SHResourceLoader<SHFont> { using AssetType = SHFontAsset; };
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

@ -36,14 +36,16 @@ namespace SHADE
Handle<ResourceType> SHResourceManager::LoadOrGet(AssetID assetId)
{
// Check if it is an unsupported type
if (!std::is_same_v<ResourceType, SHMesh> &&
!std::is_same_v<ResourceType, SHTexture> &&
!std::is_same_v<ResourceType, SHVkShaderModule> &&
!std::is_same_v<ResourceType, SHMaterialSpec> &&
!std::is_same_v<ResourceType, SHFont> &&
!std::is_same_v<ResourceType, SHMaterial> &&
!std::is_same_v<ResourceType, SHRawAnimation> &&
!std::is_same_v<ResourceType, SHRig>
if (!std::is_same_v<ResourceType, SHMesh> &&
!std::is_same_v<ResourceType, SHTexture> &&
!std::is_same_v<ResourceType, SHVkShaderModule> &&
!std::is_same_v<ResourceType, SHMaterialSpec> &&
!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, 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;
}