Added UI Element and other QoL fixes for scripting #329

Merged
Pycorax merged 7 commits from SP3-6-c-scripting into main 2023-02-02 10:57:20 +08:00
90 changed files with 4834 additions and 3771 deletions
Showing only changes of commit a5b7672102 - Show all commits

View File

@ -1,4 +0,0 @@
Start Maximized: true
Working Scene ID: 97161771
Window Size: {x: 1920, y: 1080}
Style: 0

View File

@ -0,0 +1,8 @@
- VertexShader: 47911992
FragmentShader: 46377769
SubPass: G-Buffer Write
Properties:
data.color: {x: 1, y: 1, z: 1, w: 1}
data.textureIndex: 58303057
data.alpha: 0
data.beta: {x: 1, y: 1, z: 1}

View File

@ -0,0 +1,3 @@
Name: AnimatedBag
ID: 117923942
Type: 7

View File

@ -0,0 +1,8 @@
- VertexShader: 47911992
FragmentShader: 46377769
SubPass: G-Buffer Write
Properties:
data.color: {x: 1, y: 1, z: 1, w: 1}
data.textureIndex: 64651793
data.alpha: 0
data.beta: {x: 1, y: 1, z: 1}

View File

@ -0,0 +1,3 @@
Name: AnimatedRaccoon
ID: 128805346
Type: 7

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -0,0 +1,7 @@
Name: BoneIKTest4
ID: 81814706
Type: 4
Sub Assets:
Name: Cube
ID: 137599708
Type: 8

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -4,6 +4,7 @@ using System;
public class SoundsBoard : Script public class SoundsBoard : Script
{ {
AudioClipHandler test;
protected override void awake() protected override void awake()
{ {
/* /*
@ -31,13 +32,21 @@ event:/Homeowner/homeowner_humming
event:/Homeowner/homeowner_footsteps event:/Homeowner/homeowner_footsteps
event:/Homeowner/homeowner_detect_raccoon event:/Homeowner/homeowner_detect_raccoon
*/ */
test = Audio.CreateAudioClip("event:/Music/player_undetected");
Audio.AddAudioClipToSFXChannelGroup(test);
}
protected override void start()
{
test.Play();
} }
protected override void update() protected override void update()
{ {
if (Input.GetKeyDown(Input.KeyCode.Q)) if (Input.GetKeyDown(Input.KeyCode.Q))
Audio.PlayBGMOnce2D("event:/UI/mouse_down_element"); test.Play();
if (Input.GetKeyDown(Input.KeyCode.W)) if (Input.GetKeyDown(Input.KeyCode.W))
Audio.PlayBGMOnce2D("event:/UI/mouse_down_empty"); test.Stop(true);
if (Input.GetKeyDown(Input.KeyCode.E)) if (Input.GetKeyDown(Input.KeyCode.E))
Audio.PlayBGMOnce2D("event:/UI/mouse_enter_element"); Audio.PlayBGMOnce2D("event:/UI/mouse_enter_element");
if (Input.GetKeyDown(Input.KeyCode.R)) if (Input.GetKeyDown(Input.KeyCode.R))

View File

@ -0,0 +1,78 @@
#version 450
#extension GL_KHR_vulkan_glsl : enable
//#include "ShaderDescriptorDefinitions.glsl"
layout(location = 0) in vec3 aVertexPos;
layout(location = 1) in vec2 aUV;
layout(location = 2) in vec3 aNormal;
layout(location = 3) in vec3 aTangent;
layout(location = 4) in mat4 worldTransform;
layout(location = 8) in uvec2 integerData;
layout(location = 9) in uvec4 aBoneIndices;
layout(location = 10) in vec4 aBoneWeights;
layout(location = 11) in uint firstBoneIndex;
layout(location = 0) out struct
{
vec4 vertPos; // location 0
vec2 uv; // location = 1
vec4 normal; // location = 2
vec4 worldPos; // location = 3
} Out;
// material stuff
layout(location = 4) out struct
{
int materialIndex;
uint eid;
uint lightLayerIndex;
} Out2;
layout(set = 1, binding = 0) uniform CameraData
{
vec4 position;
mat4 vpMat;
mat4 viewMat;
mat4 projMat;
} cameraData;
layout (std430, set = 2, binding = 1) buffer AnimBoneMatrices
{
mat4 data[];
} BoneMatrices;
void main()
{
Out2.materialIndex = gl_InstanceIndex;
Out2.eid = integerData[0];
Out2.lightLayerIndex = integerData[1];
// for transforming gBuffer position and normal data
mat4 modelViewMat = cameraData.viewMat * worldTransform;
// gBuffer position will be in view space
Out.vertPos = modelViewMat * vec4(aVertexPos, 1.0f);
Out.worldPos = worldTransform * vec4 (aVertexPos, 1.0f);
// uvs for texturing in fragment shader
Out.uv = aUV;
mat3 transposeInv = mat3 (transpose(inverse(modelViewMat)));
// normals are also in view space
Out.normal.rgb = transposeInv * aNormal.rgb;
Out.normal.rgb = normalize (Out.normal.rgb);
// Compute bone matrix
mat4 boneMatrix = BoneMatrices.data[firstBoneIndex + aBoneIndices[0]] * aBoneWeights[0];
boneMatrix += BoneMatrices.data[firstBoneIndex + aBoneIndices[1]] * aBoneWeights[1];
boneMatrix += BoneMatrices.data[firstBoneIndex + aBoneIndices[2]] * aBoneWeights[2];
boneMatrix += BoneMatrices.data[firstBoneIndex + aBoneIndices[3]] * aBoneWeights[3];
// clip space for rendering
gl_Position = cameraData.vpMat * worldTransform * boneMatrix * vec4 (aVertexPos, 1.0f);
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: Anim_VS
ID: 47911992
Type: 2

View File

@ -17,7 +17,6 @@ layout(location = 0) in struct
vec2 uv; // location = 1 vec2 uv; // location = 1
vec4 normal; // location = 2 vec4 normal; // location = 2
vec4 worldPos; // location = 3 vec4 worldPos; // location = 3
} In; } In;
// material stuff // material stuff

View File

@ -10,7 +10,9 @@ layout(location = 2) in vec3 aNormal;
layout(location = 3) in vec3 aTangent; layout(location = 3) in vec3 aTangent;
layout(location = 4) in mat4 worldTransform; layout(location = 4) in mat4 worldTransform;
layout(location = 8) in uvec2 integerData; layout(location = 8) in uvec2 integerData;
layout(location = 9) in uvec4 aBoneIndices;
layout(location = 10) in vec4 aBoneWeights;
layout(location = 11) in uint firstBoneIndex;
layout(location = 0) out struct layout(location = 0) out struct
{ {

Binary file not shown.

View File

@ -34,6 +34,7 @@
#include "Physics/System/SHPhysicsDebugDrawSystem.h" #include "Physics/System/SHPhysicsDebugDrawSystem.h"
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
#include "UI/SHUISystem.h" #include "UI/SHUISystem.h"
#include "Animation/SHAnimationSystem.h"
// Components // Components
#include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h"
@ -47,6 +48,7 @@
#include "Tools/Logger/SHLogger.h" #include "Tools/Logger/SHLogger.h"
#include "Tools/SHDebugDraw.h" #include "Tools/SHDebugDraw.h"
#include "Resource/SHResourceManager.h"
using namespace SHADE; using namespace SHADE;
@ -95,6 +97,7 @@ namespace Sandbox
// Link up SHDebugDraw // Link up SHDebugDraw
SHSystemManager::CreateSystem<SHDebugDrawSystem>(); SHSystemManager::CreateSystem<SHDebugDrawSystem>();
SHDebugDraw::Init(SHSystemManager::GetSystem<SHDebugDrawSystem>()); SHDebugDraw::Init(SHSystemManager::GetSystem<SHDebugDrawSystem>());
SHSystemManager::CreateSystem<SHAnimationSystem>();
#ifdef SHEDITOR #ifdef SHEDITOR
SDL_Init(SDL_INIT_VIDEO); SDL_Init(SDL_INIT_VIDEO);
@ -141,7 +144,7 @@ namespace Sandbox
#ifdef SHEDITOR #ifdef SHEDITOR
SHSystemManager::RegisterRoutine<SHEditor, SHEditor::EditorRoutine>(); SHSystemManager::RegisterRoutine<SHEditor, SHEditor::EditorRoutine>();
#endif #endif
SHSystemManager::RegisterRoutine<SHAnimationSystem, SHAnimationSystem::UpdateRoutine>();
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::RenderRoutine>(); SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::RenderRoutine>();
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::EndRoutine>(); SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::EndRoutine>();
@ -149,6 +152,7 @@ namespace Sandbox
SHComponentManager::CreateComponentSparseSet<SHColliderComponent>(); SHComponentManager::CreateComponentSparseSet<SHColliderComponent>();
SHComponentManager::CreateComponentSparseSet<SHTransformComponent>(); SHComponentManager::CreateComponentSparseSet<SHTransformComponent>();
SHComponentManager::CreateComponentSparseSet<SHRenderable>(); SHComponentManager::CreateComponentSparseSet<SHRenderable>();
SHComponentManager::CreateComponentSparseSet<SHAnimatorComponent>();
//SHComponentManager::CreateComponentSparseSet<SHCameraComponent>(); //SHComponentManager::CreateComponentSparseSet<SHCameraComponent>();
SHAssetManager::Load(); SHAssetManager::Load();
@ -170,6 +174,10 @@ namespace Sandbox
// Link up SHDebugDraw // Link up SHDebugDraw
SHDebugDraw::Init(SHSystemManager::GetSystem<SHDebugDrawSystem>()); SHDebugDraw::Init(SHSystemManager::GetSystem<SHDebugDrawSystem>());
auto clip = SHResourceManager::LoadOrGet<SHAnimationClip>(77816045);
auto rig = SHResourceManager::LoadOrGet<SHRig>(77816045);
int i = 0;
} }
void SBApplication::Update(void) void SBApplication::Update(void)
@ -232,7 +240,13 @@ namespace Sandbox
SDL_Quit(); SDL_Quit();
#endif #endif
// Unload scenes
SHSceneManager::Exit(); SHSceneManager::Exit();
// Free all remaining resources
SHResourceManager::UnloadAll();
// Shut down engine
SHSystemManager::Exit(); SHSystemManager::Exit();
SHAssetManager::Exit(); SHAssetManager::Exit();
} }

View File

@ -0,0 +1,65 @@
/************************************************************************************//*!
\file SHAnimationClip.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 20, 2022
\brief Contains the function definitions of the SHAnimationClip class.
Copyright (C) 2022 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.
*//*************************************************************************************/
// Pre-compiled Header
#include "SHpch.h"
// Primary Header
#include "SHAnimationClip.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------------*/
SHAnimationClip::SHAnimationClip(const SHAnimAsset& asset)
: ticksPerSecond { static_cast<int>(asset.ticksPerSecond) }
, totalTime { static_cast<float>(asset.duration) / static_cast<int>(asset.ticksPerSecond) }
{
// Populate keyframes
for (const auto& channel : asset.nodeChannels)
{
// Create a channel
Channel newChannel;
newChannel.Name = std::string(channel.name);
newChannel.PositionKeyFrames.reserve(channel.positionKeys.size());
newChannel.RotationKeyFrames.reserve(channel.rotationKeys.size());
newChannel.ScaleKeyFrames.reserve(channel.scaleKeys.size());
// Populate Keyframes
for (const auto& posKey : channel.positionKeys)
{
newChannel.PositionKeyFrames.emplace_back(SHAnimationKeyFrame<SHVec3>{ static_cast<int>(posKey.time), posKey.value});
}
for (const auto& rotKey : channel.rotationKeys)
{
newChannel.RotationKeyFrames.emplace_back(SHAnimationKeyFrame<SHQuaternion>{ static_cast<int>(rotKey.time), rotKey.value});
}
for (const auto& scaleKey : channel.scaleKeys)
{
newChannel.ScaleKeyFrames.emplace_back(SHAnimationKeyFrame<SHVec3>{ static_cast<int>(scaleKey.time), scaleKey.value});
}
newChannel.MaxFrames = std::max({ newChannel.PositionKeyFrames.size(), newChannel.RotationKeyFrames.size(), newChannel.ScaleKeyFrames.size() });
// Insert the channel
channels.emplace_back(std::move(newChannel));
}
}
/*-----------------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/
}

View File

@ -0,0 +1,85 @@
/************************************************************************************//*!
\file SHAnimationClip.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Dec 12, 2022
\brief Contains the definition of the SHAnimationClip struct and related types.
Copyright (C) 2022 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
// Project Includes
#include "SH_API.h"
#include "Math/SHMatrix.h"
#include "Assets/Asset Types/Models/SHAnimationAsset.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/// <summary>
/// Defines a single key frame in an animation for a specific type of data.
/// </summary>
template<typename T>
struct SHAnimationKeyFrame
{
int FrameIndex;
T Data;
};
/// <summary>
/// Represents a animation clip of a 3D animation that is made for a specific model
/// rig.
/// </summary>
class SH_API SHAnimationClip
{
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Defines the animations of a single bone in a rig.
/// </summary>
struct Channel
{
std::string Name;
std::vector<SHAnimationKeyFrame<SHVec3>> PositionKeyFrames;
std::vector<SHAnimationKeyFrame<SHQuaternion>> RotationKeyFrames;
std::vector<SHAnimationKeyFrame<SHVec3>> ScaleKeyFrames;
int MaxFrames;
};
/*---------------------------------------------------------------------------------*/
/* Constructors */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Constructs an SHAnimation Clip from a specified SHAnimAsset.
/// </summary>
/// <param name="asset">Animation asset to load.</param>
explicit SHAnimationClip(const SHAnimAsset& asset);
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
const std::vector<Channel>& GetChannels() const noexcept { return channels; }
int GetTicksPerSecond() const noexcept { return ticksPerSecond; }
float GetTotalTime() const noexcept { return totalTime; }
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
std::vector<Channel> channels;
int ticksPerSecond;
float totalTime;
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
};
}

View File

@ -0,0 +1,54 @@
/************************************************************************************//*!
\file SHAnimationSystem.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 20, 2022
\brief Contains the function definitions of the SHAnimationSystem class.
Copyright (C) 2022 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.
*//*************************************************************************************/
// Precompiled Header
#include "SHpch.h"
// Primary Include
#include "SHAnimationSystem.h"
// Project Includes
#include "ECS_Base/Managers/SHComponentManager.h"
#include "SHAnimatorComponent.h"
#include "ECS_Base/General/SHFamily.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* System Routine Functions - UpdateRoutine */
/*-----------------------------------------------------------------------------------*/
SHAnimationSystem::UpdateRoutine::UpdateRoutine()
: SHSystemRoutine("Animation System Update", true)
{
SHFamilyID<SHSystem>::GetID<SHAnimationSystem>();
}
void SHAnimationSystem::UpdateRoutine::Execute(double dt) noexcept
{
auto& animators = SHComponentManager::GetDense<SHAnimatorComponent>();
for (auto& animator : animators)
{
animator.Update(dt);
}
}
/*---------------------------------------------------------------------------------*/
/* SHSystem Overrides */
/*---------------------------------------------------------------------------------*/
void SHAnimationSystem::Init(void)
{
}
void SHAnimationSystem::Exit(void)
{
}
}

View File

@ -0,0 +1,55 @@
/************************************************************************************//*!
\file SHAnimationSystem.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 20, 2022
\brief Contains the definition of the SHAnimationSystem class and related types.
Copyright (C) 2022 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
// Project Includes
#include "SH_API.h"
#include "ECS_Base/System/SHSystem.h"
#include "ECS_Base/System/SHSystemRoutine.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/// <summary>
/// System that is responsible for updating all animations.
/// </summary>
class SH_API SHAnimationSystem : public SHSystem
{
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Responsible for updating the playback of all animator components and computing
/// the required bone matrices.
/// </summary>
class SH_API UpdateRoutine final : public SHSystemRoutine
{
public:
UpdateRoutine();
void Execute(double dt) noexcept override final;
};
/*---------------------------------------------------------------------------------*/
/* Constructors */
/*---------------------------------------------------------------------------------*/
SHAnimationSystem() = default;
/*---------------------------------------------------------------------------------*/
/* SHSystem Overrides */
/*---------------------------------------------------------------------------------*/
virtual void Init(void) override final;
virtual void Exit(void) override final;
};
}

View File

@ -0,0 +1,187 @@
/************************************************************************************//*!
\file SHAnimatorComponent.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 20, 2022
\brief Contains the definition of functions of the SHAnimatorComponent Component
class.
Copyright (C) 2022 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.
*//*************************************************************************************/
// Precompiled Header
#include "SHpch.h"
// Primary Include
#include "SHAnimatorComponent.h"
// STL Includes
#include <queue>
// Project Includes
#include "SHRig.h"
#include "Math/SHMatrix.h"
#include "SHAnimationClip.h"
#include "Graphics/SHVkUtil.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Tools/SHDebugDraw.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------------*/
void SHAnimatorComponent::Play()
{
isPlaying = false;
}
void SHAnimatorComponent::Play(Handle<SHAnimationClip> clip)
{
currClip = clip;
currPlaybackTime = 0.0f;
Play();
}
void SHAnimatorComponent::PlayFromStart()
{
isPlaying = true;
currPlaybackTime = 0.0f;
}
void SHAnimatorComponent::Pause()
{
isPlaying = false;
}
void SHAnimatorComponent::Stop()
{
isPlaying = false;
currPlaybackTime = 0.0f;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Functions */
/*-----------------------------------------------------------------------------------*/
void SHAnimatorComponent::SetRig(Handle<SHRig> newRig)
{
// Same rig, don't bother
if (rig == newRig)
return;
rig = newRig;
// Populate bone matrices based on new rig's default pose
boneMatrices.clear();
if (rig)
{
std::fill_n(std::back_inserter(boneMatrices), rig->GetNodeCount(), SHMatrix::Identity);
}
}
void SHAnimatorComponent::SetClip(Handle<SHAnimationClip> newClip)
{
// No change
if (currClip == newClip)
return;
// Set parameters
currClip = newClip;
secsPerTick = 1.0f / currClip->GetTicksPerSecond();
// Build channel map
channelMap.clear();
if (currClip)
{
for (const auto& channel : currClip->GetChannels())
{
channelMap.emplace(channel.Name, &channel);
}
}
if (rig && currClip)
{
updatePoseWithClip(0.0f);
}
}
/*-----------------------------------------------------------------------------------*/
/* Update Functions */
/*-----------------------------------------------------------------------------------*/
void SHAnimatorComponent::Update(float dt)
{
// Nothing to animate
if (!currClip || !isPlaying || !rig)
return;
// Update time on the playback
currPlaybackTime += dt;
if (currPlaybackTime > currClip->GetTotalTime())
{
currPlaybackTime = currPlaybackTime - currClip->GetTotalTime();
}
// Reset all matrices
for (auto& mat : boneMatrices)
{
mat = SHMatrix::Identity;
}
// Play the clip
updatePoseWithClip(currPlaybackTime);
}
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/
void SHAnimatorComponent::updatePoseWithClip(float poseTime)
{
// Get closest frame index
const int CLOSEST_FRAME_IDX = static_cast<int>(std::floorf(poseTime * currClip->GetTicksPerSecond()));
updatePoseWithClip(CLOSEST_FRAME_IDX, poseTime, rig->GetRootNode(), SHMatrix::Identity);
}
void SHAnimatorComponent::updatePoseWithClip(int closestFrameIndex, float poseTime, 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))
{
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
transformMatrix = transformMatrix * parentMatrix;
// Apply transformations to this node
const int BONE_MTX_IDX = rig->GetNodeIndex(node);
std::optional<SHVec3> position;
if (BONE_MTX_IDX >= 0)
{
boneMatrices[BONE_MTX_IDX] = node->OffsetMatrix * transformMatrix;
}
// Apply pose to children
for (auto& child : node->Children)
{
updatePoseWithClip(closestFrameIndex, poseTime, child, transformMatrix);
}
}
}
/*-------------------------------------------------------------------------------------*/
/* RTTR Registration */
/*-------------------------------------------------------------------------------------*/
RTTR_REGISTRATION
{
using namespace SHADE;
using namespace rttr;
registration::class_<SHAnimatorComponent>("Animator Component");
}

View File

@ -0,0 +1,155 @@
/************************************************************************************//*!
\file SHAnimatorComponent.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 20, 2022
\brief Contains the definition of the SHAnimatorComponent class and related
types.
Copyright (C) 2022 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
// STL Includes
#include <vector>
// External Dependencies
#include <rttr/registration>
// Project Includes
#include "ECS_Base/Components/SHComponent.h"
#include "Resource/SHHandle.h"
#include "Math/SHMatrix.h"
#include "Math/Vector/SHVec3.h"
#include "Math/SHQuaternion.h"
#include "SHAnimationClip.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHRig;
struct SHRigNode;
class SHAnimationClip;
class SHVkBuffer;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/// <summary>
/// Component that holds and controls the animation related properties of a skinned
/// mesh.
/// </summary>
class SH_API SHAnimatorComponent final : public SHComponent
{
public:
/*---------------------------------------------------------------------------------*/
/* Usage Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Plays the currently loaded animation from the last time.
/// </summary>
void Play();
/// <summary>
/// Plays the specified animation clip from the start.
/// </summary>
/// <param name="clip"></param>
void Play(Handle<SHAnimationClip> clip);
/// <summary>
/// Plays the currently loaded animation clip from the start.
/// </summary>
void PlayFromStart();
/// <summary>
/// Pauses the animation at the current time.
/// </summary>
void Pause();
/// <summary>
/// Stops the animation and resets the play time back to 0.
/// </summary>
void Stop();
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Sets the animation rig for this animator.
/// </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);
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Retrieves all the bone matrices of this animator.
/// </summary>
/// <returns>Reference to a vector of the bone matrices.</returns>
const std::vector<SHMatrix>& GetBoneMatrices() const noexcept { return boneMatrices; }
/// <summary>
/// Retrieve the currently set model rig.
/// </summary>
/// <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.
/// </summary>
/// <param name="dt">Time passed since the last frame.</param>
void Update(float dt);
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
// Resources
Handle<SHRig> rig;
Handle<SHAnimationClip> currClip;
// Playback Tracking
float currPlaybackTime = 0.0f;
bool isPlaying = true;
// Useful Cached Data
float secsPerTick = 0.0f;
// Buffer
std::vector<SHMatrix> boneMatrices;
// Caches
std::unordered_map<std::string, const SHAnimationClip::Channel*> channelMap;
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
void updatePoseWithClip(float poseTime);
void updatePoseWithClip(int closestFrameIndex, float poseTime, Handle<SHRigNode> node, const SHMatrix& parentMatrix);
template<typename T>
T getInterpolatedValue(const std::vector<SHAnimationKeyFrame<T>>& keyframes, int closestFrameIndex, float poseTime);
/*---------------------------------------------------------------------------------*/
/* RTTR */
/*---------------------------------------------------------------------------------*/
RTTR_ENABLE()
};
}
#include "SHAnimatorComponent.hpp"

View File

@ -0,0 +1,82 @@
/************************************************************************************//*!
\file SHAnimatorComponent.hpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Jan 10, 2023
\brief Contains the definition of function templates of the SHAnimatorComponent
Component class.
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.
*//*************************************************************************************/
// Primary Include
#include "SHAnimatorComponent.h"
// Project Includes
#include "SHRig.h"
#include "Math/SHMatrix.h"
#include "SHAnimationClip.h"
#include "Graphics/SHVkUtil.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h"
#include "ECS_Base/Managers/SHSystemManager.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/
template<typename T>
T SHAnimatorComponent::getInterpolatedValue(const std::vector<SHAnimationKeyFrame<T>>& keyframes, int closestFrameIndex, float poseTime)
{
// Only allow SHVec3 and SHQuaternion
static_assert(std::is_same_v<T, SHVec3> || std::is_same_v<T, SHQuaternion>, "Only interpolation for SHVec3 and SHQuaternion is allowed.");
// Find the key frames that surround the current frame index
auto firstKeyFrame = keyframes.end();
auto nextKeyFrame = keyframes.end();
for (auto iter = keyframes.begin(); iter != keyframes.end(); ++iter)
{
const auto& KEYFRAME = *iter;
if (KEYFRAME.FrameIndex <= closestFrameIndex)
{
firstKeyFrame = iter;
}
else // KEYFRAME.FrameIndex > closestFrameIndex
{
nextKeyFrame = iter;
break;
}
}
// Edge Cases
if (firstKeyFrame == keyframes.end())
{
// No keyframes at all, means no changes
if (nextKeyFrame == keyframes.end())
return T();
// Out of range, clamp to the back
else
return nextKeyFrame->Data;
}
// At the back, so no keyframes will follow
else if (nextKeyFrame == keyframes.end())
{
return firstKeyFrame->Data;
}
// Get interpolated vector
const float PREV_FRAME_TIME = firstKeyFrame->FrameIndex * secsPerTick;
const float NEXT_FRAME_TIME = nextKeyFrame->FrameIndex * secsPerTick;
const float NORMALISED_TIME = (poseTime - PREV_FRAME_TIME) / (NEXT_FRAME_TIME - PREV_FRAME_TIME);
if constexpr (std::is_same_v<T, SHQuaternion>)
{
return SHQuaternion::Slerp(firstKeyFrame->Data, nextKeyFrame->Data, NORMALISED_TIME);
}
else if constexpr (std::is_same_v<T, SHVec3>)
{
return SHVec3::Lerp(firstKeyFrame->Data, nextKeyFrame->Data, NORMALISED_TIME);
}
}
}

View File

@ -0,0 +1,149 @@
/************************************************************************************//*!
\file SHRig.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 20, 2022
\brief Contains the function definitions of the SHRig class.
Copyright (C) 2022 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.
*//*************************************************************************************/
// Pre-compiled Header
#include "SHpch.h"
// Primary Header
#include "SHRig.h"
// STL Includes
#include <stack>
// Project Headers
#include "Assets/Asset Types/Models/SHRigAsset.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------------*/
SHRig::SHRig(const SHRigAsset& asset, SHResourceLibrary<SHRigNode>& nodeStore)
{
// Don't bother if empty
if (asset.root == nullptr)
{
SHLOG_ERROR("[SHRig] Attempted to load an invalid rig with no root.");
return;
}
// Do a recursive depth first traversal to populate the rig
rootNode = recurseCreateNode(asset, asset.root, nodeStore);
if (rootNode)
{
globalInverseMatrix = SHMatrix::Inverse(rootNode->TransformMatrix);
}
}
SHRig::SHRig(SHRig&& rhs)
: rootNode { rhs.rootNode }
, nodeNames { std::move(rhs.nodeNames) }
, nodesByName { std::move(rhs.nodesByName) }
, nodes { std::move(rhs.nodes) }
, nodeIndexMap { std::move(rhs.nodeIndexMap) }
, globalInverseMatrix { std::move(rhs.globalInverseMatrix) }
{
rhs.rootNode = {};
}
SHRig::~SHRig()
{
// Unload all nodes
for (auto node : nodes)
{
if (node)
node.Free();
}
nodes.clear();
}
SHRig& SHRig::operator=(SHRig&& rhs)
{
rootNode = rhs.rootNode;
nodeNames = std::move(rhs.nodeNames);
nodesByName = std::move(rhs.nodesByName);
nodes = std::move(rhs.nodes);
nodeIndexMap = std::move(rhs.nodeIndexMap);
globalInverseMatrix = std::move(rhs.globalInverseMatrix);
rhs.rootNode = {};
return *this;
}
/*-----------------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------------*/
const std::string& SHRig::GetName(Handle<SHRigNode> node) const noexcept
{
static const std::string EMPTY_STRING = "";
if (nodeNames.contains(node))
return nodeNames.at(node);
return EMPTY_STRING;
}
Handle<SHRigNode> SHRig::GetNode(const std::string& name) const noexcept
{
if (nodesByName.contains(name))
return nodesByName.at(name);
return {};
}
int SHRig::GetNodeCount() const noexcept
{
return static_cast<int>(nodes.size());
}
int SHRig::GetNodeIndex(Handle<SHRigNode> node) const noexcept
{
if (nodeIndexMap.contains(node))
{
return nodeIndexMap.at(node);
}
return -1;
}
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/
Handle<SHRigNode> SHRig::recurseCreateNode(const SHRigAsset& asset, const SHRigNodeAsset* sourceNode, SHResourceLibrary<SHRigNode>& nodeStore)
{
// Construct the node
auto newNode = nodeStore.Create();
// Fill the node with data
const auto& NODE_DATA = asset.nodeDataCollection.at(sourceNode->idRef);
newNode->OffsetMatrix = SHMatrix::Transpose(NODE_DATA.offset);
newNode->TransformMatrix = SHMatrix::Transpose(NODE_DATA.transform);
// Populate maps
if (!NODE_DATA.name.empty())
{
nodeNames.emplace(newNode, NODE_DATA.name);
nodesByName.emplace(NODE_DATA.name, newNode);
}
nodeIndexMap.emplace(newNode, sourceNode->idRef);
nodes.emplace_back(newNode);
// Fill child nodes
for (const auto& child : sourceNode->children)
{
// Ignore nulls
if (child == nullptr)
continue;
// Recursively create children
auto childNode = recurseCreateNode(asset, child, nodeStore); // Not sure why this works but it is required for
newNode->Children.emplace_back(childNode); // the emplace_back operation to not crash
}
return newNode;
}
}

View File

@ -0,0 +1,147 @@
/************************************************************************************//*!
\file SHRig.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 20, 2022
\brief Contains the definition of the SHRig struct and related types.
Copyright (C) 2022 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
// STL Includes
#include <string>
#include <vector>
#include <unordered_map>
// Project Includes
#include "SH_API.h"
#include "Math/SHMatrix.h"
#include "Resource/SHHandle.h"
#include "Resource/SHResourceLibrary.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
struct SHRigAsset;
struct SHRigNodeAsset;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/// <summary>
///
/// </summary>
struct SHRigNode
{
/// <summary>
/// Matrix that performs a transformation from local space to bone (node) space.
/// </summary>
SHMatrix OffsetMatrix;
/// <summary>
/// Matrix that performs a transformation from bone (node) space to local space.
/// </summary>
SHMatrix TransformMatrix;
/// <summary>
/// Child nodes of this node.
/// </summary>
std::vector<Handle<SHRigNode>> Children;
};
/// <summary>
/// Represents an animation skeletal rig for a model.
/// </summary>
class SH_API SHRig
{
public:
/*---------------------------------------------------------------------------------*/
/* Constructors/Destructors */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Constructs a rig from a SHRigAsset.
/// </summary>
/// <param name="asset">
/// SHRigAsset to load.
/// </param>
/// <param name="nodeStore">
/// Reference to a ResourceLibrary to use to create the rig's nodes.
/// </param>
explicit SHRig(const SHRigAsset& asset, SHResourceLibrary<SHRigNode>& nodeStore);
/// <summary>
/// Move Constructor
/// </summary>
/// <param name="rhs>SHRig to move from.</param>
SHRig(SHRig&& rhs);
/// <summary>
/// Default destructor.
/// </summary>
~SHRig();
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Move assignment operator.
/// </summary>
/// <param name="rhs>SHRig to move from.</param>
/// <returns>Reference to this object.</returns>
SHRig& operator=(SHRig&& rhs);
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Retrieves the name of a node.
/// </summary>
/// <param name="node">Node to get the name of.</param>
/// <returns>
/// Name of the node. If it does not have a name or is invalid, an empty string will
/// be provided.
/// </returns>
const std::string& GetName(Handle<SHRigNode> node) const noexcept;
/// <summary>
/// Retrieves the root node of the rig.
/// </summary>
/// <returns>Handle to the root node of the rig.</returns>
Handle<SHRigNode> GetRootNode() const noexcept { return rootNode; }
const SHMatrix& GetGlobalInverseMatrix() const noexcept { return globalInverseMatrix; }
/// <summary>
/// Retrieves a node via name.
/// </summary>
/// <param name="name">Name of the node to retrieve.</param>
/// <returns>
/// Node with the specified name. If it does not have a name or is invalid, an empty
/// handle will be provided.
/// </returns>
Handle<SHRigNode> GetNode(const std::string& name) const noexcept;
/// <summary>
/// Returns the number of nodes in the rig. This matches the number of bone matrices
/// needed.
/// </summary>
int GetNodeCount() const noexcept;
/// <summary>
/// Retrieves the index in the node storage.
/// </summary>
int GetNodeIndex(Handle<SHRigNode> node) const noexcept;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
Handle<SHRigNode> rootNode;
std::unordered_map<Handle<SHRigNode>, std::string> nodeNames;
std::unordered_map<std::string, Handle<SHRigNode>> nodesByName;
std::vector<Handle<SHRigNode>> nodes;
std::unordered_map<Handle<SHRigNode>, int> nodeIndexMap;
SHMatrix globalInverseMatrix;
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
Handle<SHRigNode> recurseCreateNode(const SHRigAsset& asset, const SHRigNodeAsset* sourceNode, SHResourceLibrary<SHRigNode>& nodeStore);
};
}

View File

@ -0,0 +1,88 @@
/*************************************************************************//**
* \file SHAnimationAsset.h
* \author Loh Xiao Qi
* \date October 2022
* \brief
*
* Copyright (C) 2022 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 "Math/SHMath.h"
#include "Assets/Asset Types/SHAssetData.h"
#include <vector>
namespace SHADE
{
enum class SHAnimationBehaviour : uint8_t
{
DEFAULT = 0x0,
CONSTANT = 0x1,
LINEAR = 0x2,
REPEAT = 0x3
};
// Smallest data containers
struct PositionKey
{
float time;
SHVec3 value;
};
struct RotationKey
{
float time;
SHVec4 value;
};
struct ScaleKey
{
float time;
SHVec3 value;
};
// Headers for read/write
struct SHAnimNodeInfo
{
uint32_t charCount;
uint32_t posKeyCount;
uint32_t rotKeyCount;
uint32_t scaKeyCount;
};
struct SHAnimDataHeader
{
uint32_t charCount;
uint32_t animNodeCount;
std::vector<SHAnimNodeInfo> nodeHeaders;
};
// Main data containers
struct SHAnimData
{
std::string name;
SHAnimationBehaviour pre;
SHAnimationBehaviour post;
std::vector<PositionKey> positionKeys;
std::vector<RotationKey> rotationKeys;
std::vector<ScaleKey> scaleKeys;
};
struct SH_API SHAnimAsset : SHAssetData
{
std::string name;
double duration;
double ticksPerSecond;
std::vector<SHAnimData> nodeChannels;
//std::vector<aiMeshAnim*> meshChannels;
//std::vector<aiMeshMorphAnim*> morphMeshChannels;
};
}

View File

@ -0,0 +1,63 @@
/******************************************************************************
* \file SHMeshAsset.h
* \author Loh Xiao Qi
* \date 19 November 2022
* \brief
*
* \copyright Copyright (c) 2021 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 "Math/SHMath.h"
#include "Assets/Asset Types/SHAssetData.h"
#include "Math/Vector/SHVec4U.h"
#include <vector>
#include <string>
namespace SHADE
{
constexpr int BONE_INDEX_ALIGHTMENT = 4;
struct SHMeshDataHeader
{
uint32_t vertexCount;
uint32_t indexCount;
uint32_t charCount;
uint32_t boneCount;
};
struct MeshBoneInfo
{
uint32_t charCount;
uint32_t weightCount; // Size should be same as boneCount
};
struct BoneWeight
{
uint32_t index;
float weight;
};
struct MeshBone
{
std::string name;
SHMatrix offset;
std::vector<BoneWeight> weights;
};
struct SH_API SHMeshAsset : SHAssetData
{
std::string name;
std::vector<SHVec3> VertexPositions;
std::vector<SHVec3> VertexTangents;
std::vector<SHVec3> VertexNormals;
std::vector<SHVec2> VertexTexCoords;
std::vector<uint32_t> Indices;
std::vector<SHVec4U> VertexBoneIndices;
std::vector<SHVec4> VertexBoneWeights;
uint32_t BoneCount;
};
}

View File

@ -13,36 +13,28 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include "Math/SHMath.h"
#include "SHAssetData.h" #include "Assets/Asset Types/Models/SHAnimationAsset.h"
#include "Assets/Asset Types/Models/SHMeshAsset.h"
#include "Assets/Asset Types/Models/SHRigAsset.h"
namespace SHADE namespace SHADE
{ {
struct SHMeshAssetHeader
{
uint32_t vertexCount;
uint32_t indexCount;
std::string name;
};
struct SHModelAssetHeader struct SHModelAssetHeader
{ {
size_t meshCount; size_t meshCount;
}; size_t animCount;
struct SH_API SHMeshData : SHAssetData
{
SHMeshAssetHeader header;
std::vector<SHVec3> VertexPositions;
std::vector<SHVec3> VertexTangents;
std::vector<SHVec3> VertexNormals;
std::vector<SHVec2> VertexTexCoords;
std::vector<uint32_t> Indices;
}; };
struct SH_API SHModelAsset : SHAssetData struct SH_API SHModelAsset : SHAssetData
{ {
SHModelAssetHeader header; SHModelAssetHeader header;
std::vector<SHMeshData*> subMeshes; SHRigAsset rig;
std::vector<SHMeshDataHeader> meshHeaders;
std::vector<SHAnimDataHeader> animHeaders;
std::vector<SHMeshAsset*> meshes;
std::vector<SHAnimAsset*> anims;
}; };
} }

View File

@ -0,0 +1,13 @@
#include "SHpch.h"
#include "SHRigAsset.h"
#include <queue>
namespace SHADE
{
SHRigAsset::~SHRigAsset()
{
if (root != nullptr)
delete[] root;
}
}

View File

@ -0,0 +1,47 @@
/******************************************************************************
* \file SHRigAsset.h
* \author Loh Xiao Qi
* \date 19 November 2022
* \brief
*
* \copyright Copyright (c) 2021 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 "Math/SHMath.h"
#include "Assets/Asset Types/SHAssetData.h"
#include <map>
namespace SHADE
{
struct SHRigDataHeader
{
uint32_t nodeCount;
std::vector<uint32_t> charCounts;
};
struct SHRigNodeData
{
std::string name;
SHMatrix transform;
SHMatrix offset;
};
struct SHRigNodeAsset
{
uint32_t idRef;
std::vector<SHRigNodeAsset*> children;
};
struct SH_API SHRigAsset : SHAssetData
{
~SHRigAsset();
SHRigDataHeader header;
std::vector<SHRigNodeData> nodeDataCollection;
SHRigNodeAsset* root;
};
}

View File

@ -1,30 +0,0 @@
/*************************************************************************//**
* \file SHAnimationAsset.h
* \author Loh Xiao Qi
* \date October 2022
* \brief
*
* Copyright (C) 2022 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 <vector>
#include <assimp/anim.h>
#include "SHAssetData.h"
namespace SHADE
{
struct SH_API SHAnimationAsset : SHAssetData
{
std::string name;
std::vector<aiNodeAnim*> nodeChannels;
std::vector<aiMeshAnim*> meshChannels;
std::vector<aiMeshMorphAnim*> morphMeshChannels;
double duration;
double ticksPerSecond;
};
}

View File

@ -1,4 +1,4 @@
#pragma once #pragma once
#include "SHModelAsset.h" #include "Models/SHModelAsset.h"
#include "SHTextureAsset.h" #include "SHTextureAsset.h"

View File

@ -13,73 +13,321 @@
#include "SHpch.h" #include "SHpch.h"
#include "SHModelLoader.h" #include "SHModelLoader.h"
#include <fstream> #include <fstream>
#include <queue>
namespace SHADE namespace SHADE
{ {
void SHModelLoader::ReadHeader(std::ifstream& file, SHMeshLoaderHeader& header) noexcept void SHModelLoader::ReadHeaders(FileReference file, SHModelAsset& asset)
{ {
file.read( file.read(
reinterpret_cast<char*>(&header), reinterpret_cast<char*>(&asset.header),
sizeof(SHMeshLoaderHeader) sizeof(asset.header)
);
if (asset.header.meshCount > 0)
{
asset.meshHeaders.resize(asset.header.meshCount);
file.read(
reinterpret_cast<char*>(asset.meshHeaders.data()),
asset.header.meshCount * sizeof(SHMeshDataHeader)
);
}
if (asset.header.animCount > 0)
{
asset.animHeaders.resize(asset.header.animCount);
for (auto i {0}; i < asset.header.animCount; ++i)
{
auto& animHeader = asset.animHeaders[i];
file.read(
reinterpret_cast<char*>(&animHeader.charCount),
sizeof(uint32_t)
);
file.read(
reinterpret_cast<char*>(&animHeader.animNodeCount),
sizeof(uint32_t)
);
animHeader.nodeHeaders.resize(animHeader.animNodeCount);
for (auto j {0}; j < animHeader.animNodeCount; ++j)
{
auto& nodeHeader = animHeader.nodeHeaders[j];
file.read(
reinterpret_cast<char*>(&nodeHeader),
sizeof(SHAnimNodeInfo)
);
}
}
}
}
void SHModelLoader::ReadData(FileReference file, SHModelAsset& asset)
{
ReadMeshData(file, asset.meshHeaders, asset.meshes);
ReadAnimData(file, asset.animHeaders, asset.anims);
// Not eof yet, animation exists
if (file.peek() != EOF)
{
ReadRigHeader(file, asset.rig.header);
ReadRigData(file, asset.rig.header, asset.rig.nodeDataCollection);
ReadRigTree(file, asset.rig.header, asset.rig.root);
}
}
void SHModelLoader::ReadAnimNode(FileReference file, SHAnimNodeInfo const& info, SHAnimData& data)
{
data.name.resize(info.charCount);
file.read(
data.name.data(),
info.charCount
);
file.read(
reinterpret_cast<char*>(&data.pre),
sizeof(SHAnimationBehaviour)
);
file.read(
reinterpret_cast<char*>(&data.post),
sizeof(SHAnimationBehaviour)
);
uint32_t keySize {0};
file.read(
reinterpret_cast<char*>(&keySize),
sizeof(uint32_t)
);
data.positionKeys.resize(keySize);
data.rotationKeys.resize(keySize);
data.scaleKeys.resize(keySize);
file.read(
reinterpret_cast<char*>(data.positionKeys.data()),
sizeof(PositionKey) * keySize
);
file.read(
reinterpret_cast<char*>(data.rotationKeys.data()),
sizeof(RotationKey) * keySize
);
file.read(
reinterpret_cast<char*>(data.scaleKeys.data()),
sizeof(ScaleKey) * keySize
); );
} }
void SHModelLoader::ReadData(std::ifstream& file, SHMeshLoaderHeader const& header, SHMeshData& data) noexcept void SHModelLoader::ReadRigHeader(FileReference file, SHRigDataHeader& header)
{ {
auto const vertexVec3Byte{ sizeof(SHVec3) * header.vertexCount }; file.read(
auto const vertexVec2Byte{ sizeof(SHVec2) * header.vertexCount }; reinterpret_cast<char*>(&header.nodeCount),
sizeof(uint32_t)
);
data.VertexPositions.resize(header.vertexCount); header.charCounts.resize(header.nodeCount);
data.VertexTangents.resize(header.vertexCount); file.read(
data.VertexNormals.resize(header.vertexCount); reinterpret_cast<char*>(header.charCounts.data()),
data.VertexTexCoords.resize(header.vertexCount); sizeof(uint32_t) * header.nodeCount
data.Indices.resize(header.indexCount); );
data.header.name.resize(header.charCount);
file.read(data.header.name.data(), header.charCount);
file.read(reinterpret_cast<char*>(data.VertexPositions.data()), vertexVec3Byte);
file.read(reinterpret_cast<char*>(data.VertexTangents.data()), vertexVec3Byte);
file.read(reinterpret_cast<char*>(data.VertexNormals.data()), vertexVec3Byte);
file.read(reinterpret_cast<char*>(data.VertexTexCoords.data()), vertexVec2Byte);
file.read(reinterpret_cast<char*>(data.Indices.data()), sizeof(uint32_t) * header.indexCount);
data.header.vertexCount = header.vertexCount;
data.header.indexCount = header.indexCount;
} }
void SHModelLoader::LoadSHMesh(AssetPath path, SHModelAsset& model) noexcept void SHModelLoader::ReadRigData(FileReference file, SHRigDataHeader const& header, std::vector<SHRigNodeData>& data)
{ {
data.resize(header.nodeCount);
for (auto i {0}; i < header.nodeCount; ++i)
{
data[i].name.resize(header.charCounts[i]);
file.read(
data[i].name.data(),
header.charCounts[i]
);
file.read(
reinterpret_cast<char*>(&data[i].transform),
sizeof(SHMatrix)
);
file.read(
reinterpret_cast<char*>(&data[i].offset),
sizeof(SHMatrix)
);
}
}
void SHModelLoader::ReadRigTree(FileReference file, SHRigDataHeader const& header, SHRigNodeAsset*& root)
{
// Read All nodes into one contiguous data block
struct NodeTemp
{
uint32_t id, numChild;
};
NodeTemp* dst = new NodeTemp[header.nodeCount];
file.read(
reinterpret_cast<char*>(dst),
sizeof(NodeTemp) * header.nodeCount
);
// Build and populate tree
SHRigNodeAsset* nodePool = new SHRigNodeAsset[header.nodeCount];
root = nodePool;
std::queue<std::pair<SHRigNodeAsset*, NodeTemp*>> nodeQueue;
nodeQueue.emplace(std::make_pair(nodePool, dst));
SHRigNodeAsset* depthPtr = nodePool + 1;
NodeTemp* depthTempPtr = dst + 1;
while(!nodeQueue.empty())
{
auto currPair = nodeQueue.front();
nodeQueue.pop();
auto currNode = currPair.first;
auto currTemp = currPair.second;
currNode->idRef = currTemp->id;
for (auto i{0}; i < currTemp->numChild; ++i)
{
currNode->children.push_back(depthPtr);
nodeQueue.emplace(depthPtr++, depthTempPtr++);
}
}
delete[] dst;
}
void SHModelLoader::ReadMeshData(FileReference file, std::vector<SHMeshDataHeader> const& headers,
std::vector<SHMeshAsset*>& meshes)
{
meshes.resize(headers.size());
for (auto i {0}; i < headers.size(); ++i)
{
auto const& header = headers[i];
auto& data = *new SHMeshAsset;
auto const vertexVec3Byte{ sizeof(SHVec3) * header.vertexCount };
auto const vertexVec2Byte{ sizeof(SHVec2) * header.vertexCount };
data.name.resize(header.charCount);
data.VertexPositions.resize(header.vertexCount);
data.VertexTangents.resize(header.vertexCount);
data.VertexNormals.resize(header.vertexCount);
data.VertexTexCoords.resize(header.vertexCount);
data.Indices.resize(header.indexCount);
data.BoneCount = header.boneCount;
file.read(data.name.data(), header.charCount);
file.read(reinterpret_cast<char*>(data.VertexPositions.data()), vertexVec3Byte);
file.read(reinterpret_cast<char*>(data.VertexTangents.data()), vertexVec3Byte);
file.read(reinterpret_cast<char*>(data.VertexNormals.data()), vertexVec3Byte);
file.read(reinterpret_cast<char*>(data.VertexTexCoords.data()), vertexVec2Byte);
file.read(reinterpret_cast<char*>(data.Indices.data()), sizeof(uint32_t) * header.indexCount);
if (header.boneCount)
{
std::vector<MeshBoneInfo> boneInfos(header.boneCount);
std::vector<MeshBone> bones(header.boneCount);
file.read(reinterpret_cast<char*>(boneInfos.data()), sizeof(MeshBoneInfo) * header.boneCount);
for (auto i{ 0 }; i < header.boneCount; ++i)
{
auto& bone = bones[i];
auto const& info = boneInfos[i];
bone.name.resize(info.charCount);
file.read(bone.name.data(), info.charCount);
file.read(reinterpret_cast<char*>(&bone.offset), sizeof(SHMatrix));
bone.weights.resize(info.weightCount);
file.read(reinterpret_cast<char*>(bone.weights.data()), sizeof(BoneWeight) * info.weightCount);
}
data.VertexBoneIndices.resize(header.vertexCount);
data.VertexBoneWeights.resize(header.vertexCount);
for (uint32_t boneIndex{0}; boneIndex < bones.size(); ++boneIndex)
{
auto const& bone = bones[boneIndex];
for (auto const& weight : bone.weights)
{
auto& boneIndices = data.VertexBoneIndices[weight.index];
auto& boneWeight = data.VertexBoneWeights[weight.index];
for (auto j{0}; j < BONE_INDEX_ALIGHTMENT; ++j)
{
if (boneWeight[j] == 0.f)
{
boneIndices[j] = boneIndex;
boneWeight[j] = weight.weight;
break;
}
}
}
}
}
meshes[i] = &data;
}
}
void SHModelLoader::ReadAnimData(FileReference file, std::vector<SHAnimDataHeader> const& headers,
std::vector<SHAnimAsset*>& anims)
{
anims.resize(headers.size());
for (auto i {0}; i < headers.size(); ++i)
{
auto const& header = headers[i];
auto& animAsset = *new SHAnimAsset;
animAsset.name.resize(header.charCount);
file.read(
animAsset.name.data(),
header.charCount
);
file.read(
reinterpret_cast<char*>(&animAsset.duration),
sizeof(double)
);
file.read(
reinterpret_cast<char*>(&animAsset.ticksPerSecond),
sizeof(double)
);
animAsset.nodeChannels.resize(header.animNodeCount);
for (auto i {0}; i < header.animNodeCount; ++i)
{
ReadAnimNode(file, header.nodeHeaders[i], animAsset.nodeChannels[i]);
}
anims[i] = &animAsset;
}
}
SHAssetData* SHModelLoader::Load(AssetPath path)
{
auto result = new SHModelAsset();
std::ifstream file{ path.string(), std::ios::in | std::ios::binary }; std::ifstream file{ path.string(), std::ios::in | std::ios::binary };
if (!file.is_open()) if (!file.is_open())
{ {
SHLOG_ERROR("[Model Loader] Unable to open SHModel File: {}", path.string()); SHLOG_ERROR("[Model Loader] Unable to open SHModel File: {}", path.string());
return; return nullptr;
} }
file.seekg(0); ReadHeaders(file, *result);
ReadData(file, *result);
file.read(
reinterpret_cast<char*>(&model.header),
sizeof(SHModelAssetHeader)
);
std::vector<SHMeshLoaderHeader> headers(model.header.meshCount);
model.subMeshes.resize(model.header.meshCount);
for (auto i{ 0 }; i < model.header.meshCount; ++i)
{
model.subMeshes[i] = new SHMeshData();
ReadHeader(file, headers[i]);
ReadData(file, headers[i], *model.subMeshes[i]);
}
file.close(); file.close();
}
SHAssetData* SHModelLoader::Load(AssetPath path)
{
auto result = new SHModelAsset();
LoadSHMesh(path, *result);
return result; return result;
} }

View File

@ -10,7 +10,7 @@
* of DigiPen Institute of Technology is prohibited. * of DigiPen Institute of Technology is prohibited.
*****************************************************************************/ *****************************************************************************/
#pragma once #pragma once
#include "Assets/Asset Types/SHModelAsset.h" #include "Assets/Asset Types/Models/SHModelAsset.h"
#include "SHAssetLoader.h" #include "SHAssetLoader.h"
#include <fstream> #include <fstream>
@ -18,19 +18,20 @@ namespace SHADE
{ {
class SHModelLoader : public SHAssetLoader class SHModelLoader : public SHAssetLoader
{ {
struct SHMeshLoaderHeader using FileReference = std::ifstream&;
{
uint32_t vertexCount; void ReadAnimNode(FileReference file, SHAnimNodeInfo const& info, SHAnimData& data);
uint32_t indexCount;
uint32_t charCount;
};
void ReadRigHeader(FileReference file, SHRigDataHeader& header);
void ReadRigData(FileReference file, SHRigDataHeader const& header, std::vector<SHRigNodeData>& data);
void ReadRigTree(FileReference file, SHRigDataHeader const& header, SHRigNodeAsset*& root);
void ReadMeshData(FileReference file, std::vector<SHMeshDataHeader> const& headers, std::vector<SHMeshAsset*>& meshes);
void ReadAnimData(FileReference file, std::vector<SHAnimDataHeader> const& headers, std::vector<SHAnimAsset*>& anims);
void ReadHeader(std::ifstream& file, SHMeshLoaderHeader& header) noexcept; void ReadHeaders(FileReference file, SHModelAsset& asset);
void ReadData(std::ifstream& file, SHMeshLoaderHeader const& header, SHMeshData& data) noexcept; void ReadData(FileReference file, SHModelAsset& asset);
public: public:
void LoadSHMesh(AssetPath path, SHModelAsset& model) noexcept;
SHAssetData* Load(AssetPath path) override; SHAssetData* Load(AssetPath path) override;
void Write(SHAssetData const* data, AssetPath path) override; void Write(SHAssetData const* data, AssetPath path) override;
}; };

View File

@ -492,8 +492,8 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
void SHAssetManager::Load() noexcept void SHAssetManager::Load() noexcept
{ {
BuildAssetCollection();
InitLoaders(); InitLoaders();
BuildAssetCollection();
//CompileAll(); //CompileAll();
//LoadAllData(); //LoadAllData();
} }
@ -549,7 +549,7 @@ namespace SHADE
{ {
assetData.emplace( assetData.emplace(
parent.subAssets[i]->id, parent.subAssets[i]->id,
parentModel->subMeshes[i] parentModel->meshes[i]
); );
} }
} }
@ -607,10 +607,10 @@ namespace SHADE
SHModelAsset* const data = reinterpret_cast<SHModelAsset*>(LoadData(newAsset)); SHModelAsset* const data = reinterpret_cast<SHModelAsset*>(LoadData(newAsset));
assetData.emplace(newAsset.id, data); assetData.emplace(newAsset.id, data);
for(auto const& subMesh : data->subMeshes) for(auto const& subMesh : data->meshes)
{ {
SHAsset subAsset{ SHAsset subAsset{
.name = subMesh->header.name, .name = subMesh->name,
.id = GenerateAssetID(AssetType::MESH), .id = GenerateAssetID(AssetType::MESH),
.type = AssetType::MESH, .type = AssetType::MESH,
.isSubAsset = true, .isSubAsset = true,

View File

@ -6,6 +6,11 @@ namespace SHADE
template<typename T> template<typename T>
std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T* const> SHAssetManager::GetData(AssetID id) noexcept std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T* const> SHAssetManager::GetData(AssetID id) noexcept
{ {
if (id == 0)
{
return nullptr;
}
if (!assetData.contains(id)) if (!assetData.contains(id))
{ {
for (auto const& asset : std::ranges::views::values(assetCollection)) for (auto const& asset : std::ranges::views::values(assetCollection))

View File

@ -125,14 +125,29 @@ namespace SHADE
SHTransformComponent* listenerTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(listener.GetEID()); SHTransformComponent* listenerTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(listener.GetEID());
if (listenerTransform) if (listenerTransform)
{ {
listener.SetPos(listenerTransform->GetLocalPosition()); listener.SetPos(listenerTransform->GetWorldPosition()); // TODO: Clean up listener
listener.SetForward({ (listenerTransform->GetLocalScale()[0] > 0.f) ? 1.f : -1.f, 0.f, 0.f }); listener.SetForward({ (listenerTransform->GetLocalScale()[0] > 0.f) ? 1.f : -1.f, 0.f, 0.f }); //TODO: USE CORRECT FORWARD
FMOD_VECTOR pos = { listener.pos[0] ,listener.pos[1] ,0.f }; FMOD_VECTOR pos = { listener.pos[0] ,listener.pos[1] ,0.f };
FMOD_VECTOR forward = { listener.forward[0] ,listener.forward[1] ,listener.forward[2] }; FMOD_VECTOR forward = { listener.forward[0] ,listener.forward[1] ,listener.forward[2] };
FMOD_VECTOR up = { listener.up[0] ,listener.up[1] ,listener.up[2] }; FMOD_VECTOR up = { listener.up[0] ,listener.up[1] ,listener.up[2] };
fmodSystem->set3DListenerAttributes(0, &pos, nullptr, &forward, &up); fmodSystem->set3DListenerAttributes(0, &pos, nullptr, &forward, &up);
} }
} }
auto [begin, end] = audioClipLibrary.GetDenseAccess();
for(auto it = begin; it != end; ++it)
{
if(it->instance && (it->transformRef != MAX_EID))
{
if(SHTransformComponent* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(it->transformRef))
{
FMOD_3D_ATTRIBUTES attribs{}; //TODO: Set other attribs
auto pos = transformComponent->GetWorldPosition();
attribs.position = {pos.x, pos.y, pos.z};
it->instance->set3DAttributes(&attribs);
}
}
}
} }
SHAudioSystem::AudioRoutine::AudioRoutine() SHAudioSystem::AudioRoutine::AudioRoutine()
@ -325,27 +340,83 @@ namespace SHADE
return std::nullopt; return std::nullopt;
} }
AudioClip* SHAudioSystem::CreateAudioClip(const char* path) Handle<AudioClip> SHAudioSystem::CreateAudioClip(const char* path)
{ {
AudioClipID newID{}; Handle<AudioClip> audioClipHandle{};
AudioClip* clip = nullptr;
auto it = eventMap.find(path); if(auto it = eventMap.find(path); it != eventMap.end())
if (it != eventMap.end())
{ {
FMOD::Studio::EventInstance* event = nullptr; audioClipHandle = audioClipLibrary.Create();
it->second->createInstance(&event); it->second->createInstance(&audioClipHandle->instance);
if (event)
{
//event->start();
newID = clipID;
clipID++;
eventInstances.emplace(newID, AudioClip(newID, event));
clip = &eventInstances[newID];
}
} }
return clip;
return audioClipHandle;
} }
void SHAudioSystem::AddAudioClipToBGMChannelGroup(Handle<AudioClip> handle)
{
if(!handle->instance)
return;
FMOD::ChannelGroup* channelGroup;
handle->instance->getChannelGroup(&channelGroup);
if(!channelGroup)
{
SHLOG_ERROR("Event instance has no channel group")
return;
}
bgmChannelGroup->addGroup(channelGroup);
}
void SHAudioSystem::AddAudioClipToSFXChannelGroup(Handle<AudioClip> handle)
{
if (!handle->instance)
return;
FMOD::ChannelGroup* channelGroup;
handle->instance->getChannelGroup(&channelGroup);
if (!channelGroup)
{
SHLOG_ERROR("Event instance has no channel group")
return;
}
sfxChannelGroup->addGroup(channelGroup);
}
void SHAudioSystem::AttachAudioClipToObject(Handle<AudioClip> handle, EntityID eid)
{
if (auto transform = SHComponentManager::GetComponent_s<SHTransformComponent>(eid))
{
handle->transformRef = eid;
}
}
void SHAudioSystem::DetachAudioClipFromObject(Handle<AudioClip> handle)
{
handle->transformRef = MAX_EID;
}
//AudioClip* SHAudioSystem::CreateAudioClip(const char* path)
//{
// AudioClipID newID{};
// AudioClip* clip = nullptr;
// auto it = eventMap.find(path);
// if (it != eventMap.end())
// {
// FMOD::Studio::EventInstance* event = nullptr;
// it->second->createInstance(&event);
// if (event)
// {
// //event->start();
// newID = clipID;
// clipID++;
// eventInstances.emplace(newID, AudioClip(newID, event));
// clip = &eventInstances[newID];
// }
// }
// return clip;
//}
//std::vector<const char*> SHAudioSystem::GetAllEvents() //std::vector<const char*> SHAudioSystem::GetAllEvents()
//{ //{
// int count{}; // int count{};
@ -489,41 +560,39 @@ namespace SHADE
} }
} }
AudioClip::AudioClip(AudioClipID clipID, FMOD::Studio::EventInstance* inst) void AudioClip::Play()
:instance(inst), id(clipID)
{ {
} if(!instance)
AudioClip::~AudioClip()
{
}
void AudioClip::Play(bool isSfx)
{
if (!instance)
return; return;
instance->start(); instance->start();
auto audioSystem = SHSystemManager::GetSystem<SHADE::SHAudioSystem>();
instance->setVolume(audioSystem->GetMasterVolume() * (isSfx ? audioSystem->GetSfxVolume() : audioSystem->GetBgmVolume()));
} }
void AudioClip::Play(SHVec3 position, bool isSfx) //void AudioClip::Play(bool isSfx)
{ //{
if (!instance) // if (!instance)
return; // return;
instance->start(); // instance->start();
FMOD_3D_ATTRIBUTES attributes{ {} }; // auto audioSystem = SHSystemManager::GetSystem<SHADE::SHAudioSystem>();
attributes.forward.z = 1.0f; // instance->setVolume(audioSystem->GetMasterVolume() * (isSfx ? audioSystem->GetSfxVolume() : audioSystem->GetBgmVolume()));
attributes.up.y = 1.0f; //}
auto audioSystem = SHSystemManager::GetSystem<SHADE::SHAudioSystem>(); //void AudioClip::Play(SHVec3 position, bool isSfx)
SHVec3 listenerPos = audioSystem->GetListenerPosition(); //{
attributes.position.x = position[0]; // if (!instance)
attributes.position.y = position[1]; // return;
attributes.position.z = listenerPos[2]; // instance->start();
instance->set3DAttributes(&attributes); // FMOD_3D_ATTRIBUTES attributes{ {} };
instance->setVolume(audioSystem->GetMasterVolume() * (isSfx ? audioSystem->GetSfxVolume() : audioSystem->GetBgmVolume())); // attributes.forward.z = 1.0f;
} // attributes.up.y = 1.0f;
// auto audioSystem = SHSystemManager::GetSystem<SHADE::SHAudioSystem>();
// SHVec3 listenerPos = audioSystem->GetListenerPosition();
// attributes.position.x = position[0];
// attributes.position.y = position[1];
// attributes.position.z = listenerPos[2];
// instance->set3DAttributes(&attributes);
// instance->setVolume(audioSystem->GetMasterVolume() * (isSfx ? audioSystem->GetSfxVolume() : audioSystem->GetBgmVolume()));
//}
void AudioClip::Stop(bool fadeOut) void AudioClip::Stop(bool fadeOut)
{ {
@ -557,12 +626,12 @@ namespace SHADE
instance->setParameterByName(paramName, value); instance->setParameterByName(paramName, value);
} }
void AudioClip::SetParameterLabel(const char* paramName, const char* label) //void AudioClip::SetParameterLabel(const char* paramName, const char* label)
{ //{
if (!instance) // if (!instance)
return; // return;
instance->setParameterByNameWithLabel(paramName, label); // instance->setParameterByNameWithLabel(paramName, label);
} //}
float AudioClip::GetParameterValue(const char* paramName) float AudioClip::GetParameterValue(const char* paramName)
{ {

View File

@ -13,6 +13,7 @@
#include "Events/SHEvent.h" #include "Events/SHEvent.h"
#include "SH_API.h" #include "SH_API.h"
#include <Resource/SHResourceLibrary.h>
#define AUDIO_SYS_MAX_CHANNELS 1024 #define AUDIO_SYS_MAX_CHANNELS 1024
namespace SHADE namespace SHADE
@ -22,27 +23,22 @@ namespace SHADE
class SHAudioListenerComponent; class SHAudioListenerComponent;
typedef uint64_t AudioClipID; class SH_API AudioClip
class AudioClip
{ {
public: public:
AudioClip() = default; void Play();
AudioClip(AudioClipID clipID, FMOD::Studio::EventInstance* inst); //void Play(SHVec3 position);
~AudioClip();
void Play(bool isSfx = true);
void Play(SHVec3 position, bool isSfx = true);
void Stop(bool fadeOut = true); void Stop(bool fadeOut = true);
void SetPause(bool pause); void SetPause(bool pause);
bool IsPaused(); bool IsPaused();
void SetParameter(const char* paramName, float value); void SetParameter(const char* paramName, float value);
void SetParameterLabel(const char* paramName, const char* label); //void SetParameterLabel(const char* paramName, const char* label);
float GetParameterValue(const char* paramName); float GetParameterValue(const char* paramName);
friend class SHAudioSystem; friend class SHAudioSystem;
private: private:
FMOD::Studio::EventInstance* instance; FMOD::Studio::EventInstance* instance = nullptr;
AudioClipID id; EntityID transformRef = MAX_EID;
}; };
class SH_API SHAudioSystem : public SHSystem class SH_API SHAudioSystem : public SHSystem
@ -62,7 +58,7 @@ namespace SHADE
void Exit(); void Exit();
int GetAvailableChannelIndex(); int GetAvailableChannelIndex();
/*std::vector<SHSound>::size_type CreateSound(const char* filepath, bool loop = false);*/
void PlaySFX(EntityID id, EntityID eid, const bool& loop, const bool& spatial, float min = 5.0f, float max = 1000.0f); void PlaySFX(EntityID id, EntityID eid, const bool& loop, const bool& spatial, float min = 5.0f, float max = 1000.0f);
void PlayBGM(EntityID id, EntityID eid, const bool& loop, const bool& spatial, float min = 5.0f, float max = 1000.0f); void PlayBGM(EntityID id, EntityID eid, const bool& loop, const bool& spatial, float min = 5.0f, float max = 1000.0f);
void PlayEventOnce(const char* path, bool isSFX = true, EntityID eid = MAX_EID, bool spatial = false); void PlayEventOnce(const char* path, bool isSFX = true, EntityID eid = MAX_EID, bool spatial = false);
@ -71,9 +67,15 @@ namespace SHADE
void StopAllSounds(); void StopAllSounds();
std::optional<FMOD_GUID> GetEventGUID(const char* path); std::optional<FMOD_GUID> GetEventGUID(const char* path);
AudioClip* CreateAudioClip(const char* path); //AudioClip* CreateAudioClip(const char* path);
//std::vector<const char*> GetAllEvents(); //AUDIO CLIP
Handle<AudioClip> CreateAudioClip(const char* path);
void AddAudioClipToBGMChannelGroup(Handle<AudioClip> handle);
void AddAudioClipToSFXChannelGroup(Handle<AudioClip> handle);
void AttachAudioClipToObject(Handle<AudioClip> handle, EntityID eid);
void DetachAudioClipFromObject(Handle<AudioClip> handle);
///
float GetBgmVolume(); float GetBgmVolume();
float GetSfxVolume(); float GetSfxVolume();
float GetMasterVolume(); float GetMasterVolume();
@ -84,6 +86,7 @@ namespace SHADE
bool GetPaused() const; bool GetPaused() const;
SHVec3 GetListenerPosition(); SHVec3 GetListenerPosition();
void LoadBank(const char* path); void LoadBank(const char* path);
private: private:
FMOD::Studio::System* fmodStudioSystem; FMOD::Studio::System* fmodStudioSystem;
FMOD::System* fmodSystem; FMOD::System* fmodSystem;
@ -95,7 +98,9 @@ namespace SHADE
//std::unordered_map<ResourceID, SHBank> bankMap; //std::unordered_map<ResourceID, SHBank> bankMap;
std::unordered_map<std::string, SHBank> bankMap; std::unordered_map<std::string, SHBank> bankMap;
std::unordered_map<std::string, FMOD::Studio::EventDescription*> eventMap; std::unordered_map<std::string, FMOD::Studio::EventDescription*> eventMap;
std::unordered_map<AudioClipID, AudioClip> eventInstances; //std::unordered_map<AudioClipID, AudioClip> eventInstances;
SHResourceLibrary<AudioClip> audioClipLibrary{};
FMOD::ChannelGroup* bgmChannelGroup, * sfxChannelGroup, * masterGroup; FMOD::ChannelGroup* bgmChannelGroup, * sfxChannelGroup, * masterGroup;
FMOD::Channel* audioChannels[AUDIO_SYS_MAX_CHANNELS]; FMOD::Channel* audioChannels[AUDIO_SYS_MAX_CHANNELS];
FMOD_RESULT result; FMOD_RESULT result;
@ -105,7 +110,6 @@ namespace SHADE
SHBank masterBank, stringsBank, musicBank, sfxBank; //To do: change to map of banks loaded by resource manager SHBank masterBank, stringsBank, musicBank, sfxBank; //To do: change to map of banks loaded by resource manager
std::vector<SHAudioListenerComponent>* denseListener; std::vector<SHAudioListenerComponent>* denseListener;
AudioClipID clipID = 0;
SHEventHandle onPlay(SHEventPtr onStopEvent); SHEventHandle onPlay(SHEventPtr onStopEvent);
SHEventHandle onStop(SHEventPtr onStopEvent); SHEventHandle onStop(SHEventPtr onStopEvent);

View File

@ -57,9 +57,13 @@ namespace SHADE
skipFrame = false; skipFrame = false;
return; return;
} }
DrawMenuBar();
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
DrawMenuBar();
if(wasFilterChanged && !filter.empty())
{
filterHighlightedEntities.clear();
filterOpenEntities.clear();
}
if (const auto root = sceneGraph.GetRoot()) if (const auto root = sceneGraph.GetRoot())
{ {
auto const& children = root->GetChildren(); auto const& children = root->GetChildren();
@ -67,7 +71,13 @@ namespace SHADE
for (const auto child : children) for (const auto child : children)
{ {
if (child) if (child)
{
if(wasFilterChanged && !filter.empty())
{
EntityFilterCheck(child);
}
RecursivelyDrawEntityNode(child); RecursivelyDrawEntityNode(child);
}
if (skipFrame) if (skipFrame)
{ {
ImGui::End(); ImGui::End();
@ -177,9 +187,10 @@ namespace SHADE
void SHHierarchyPanel::DrawHierarchyPanelFilter() noexcept void SHHierarchyPanel::DrawHierarchyPanelFilter() noexcept
{ {
wasFilterChanged = false;
if(ImGui::InputTextWithHint("##hierarchyPanelFilter", "Filter", &filter)) if(ImGui::InputTextWithHint("##hierarchyPanelFilter", "Filter", &filter))
{ {
wasFilterChanged = true;
} }
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::Button("x")) if(ImGui::Button("x"))
@ -199,29 +210,70 @@ namespace SHADE
bool result = false; bool result = false;
result |= SHStringUtilities::StringFindInsensitive(entity->name, filter) != std::string::npos; result |= SHStringUtilities::StringFindInsensitive(entity->name, filter) != std::string::npos;
if(SHStringUtilities::StringFindInsensitive(rttr::type::get<SHTransformComponent>().get_name().data(), filter) != std::string::npos) if(SHStringUtilities::StringFindInsensitive(rttr::type::get<SHTransformComponent>().get_name().data(), filter) != std::string::npos)
{ {
result |= SHComponentManager::HasComponent<SHTransformComponent>(eid); result |= SHComponentManager::HasComponent<SHTransformComponent>(eid);
} }
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHColliderComponent>().get_name().data(), filter) != std::string::npos; if(SHStringUtilities::StringFindInsensitive(rttr::type::get<SHColliderComponent>().get_name().data(), filter) != std::string::npos)
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHRigidBodyComponent>().get_name().data(), filter) != std::string::npos; {
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHCameraComponent>().get_name().data(), filter) != std::string::npos; result |= SHComponentManager::HasComponent<SHColliderComponent>(eid);
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHCameraArmComponent>().get_name().data(), filter) != std::string::npos; }
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHRenderable>().get_name().data(), filter) != std::string::npos; if(SHStringUtilities::StringFindInsensitive(rttr::type::get<SHRigidBodyComponent>().get_name().data(), filter) != std::string::npos)
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHLightComponent>().get_name().data(), filter) != std::string::npos; {
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHTextRenderableComponent>().get_name().data(), filter) != std::string::npos; result |= SHComponentManager::HasComponent<SHRigidBodyComponent>(eid);
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHUIComponent>().get_name().data(), filter) != std::string::npos; }
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHButtonComponent>().get_name().data(), filter) != std::string::npos; if(SHStringUtilities::StringFindInsensitive(rttr::type::get<SHCameraComponent>().get_name().data(), filter) != std::string::npos)
//result |= SHStringUtilities::StringFindInsensitive(rttr::type::get<SHCanvasComponent>().get_name().data(), filter) != std::string::npos; {
result |= SHComponentManager::HasComponent<SHCameraComponent>(eid);
}
if(SHStringUtilities::StringFindInsensitive(rttr::type::get<SHCameraArmComponent>().get_name().data(), filter) != std::string::npos)
{
result |= SHComponentManager::HasComponent<SHCameraArmComponent>(eid);
}
if(SHStringUtilities::StringFindInsensitive(rttr::type::get<SHRenderable>().get_name().data(), filter) != std::string::npos)
{
result |= SHComponentManager::HasComponent<SHRenderable>(eid);
}
if(SHStringUtilities::StringFindInsensitive(rttr::type::get<SHLightComponent>().get_name().data(), filter) != std::string::npos)
{
result |= SHComponentManager::HasComponent<SHLightComponent>(eid);
}
if(SHStringUtilities::StringFindInsensitive(rttr::type::get<SHTextRenderableComponent>().get_name().data(), filter) != std::string::npos)
{
result |= SHComponentManager::HasComponent<SHTextRenderableComponent>(eid);
}
if(SHStringUtilities::StringFindInsensitive(rttr::type::get<SHUIComponent>().get_name().data(), filter) != std::string::npos)
{
result |= SHComponentManager::HasComponent<SHUIComponent>(eid);
}
if(SHStringUtilities::StringFindInsensitive(rttr::type::get<SHButtonComponent>().get_name().data(), filter) != std::string::npos)
{
result |= SHComponentManager::HasComponent<SHButtonComponent>(eid);
}
if(SHStringUtilities::StringFindInsensitive(rttr::type::get<SHCanvasComponent>().get_name().data(), filter) != std::string::npos)
{
result |= SHComponentManager::HasComponent<SHCanvasComponent>(eid);
}
//std::vector<SHSceneNode*> const& children = entityNode->GetChildren(); if(result)
{
//for (auto const& child : children) filterHighlightedEntities.push_back(eid);
//{ }
// result |= EntityFilterCheck(child);
//}
std::vector<SHSceneNode*> const& children = entityNode->GetChildren();
bool open = false;
for (auto const& child : children)
{
open |= EntityFilterCheck(child);
}
result |= open;
if(open)
{
filterOpenEntities.push_back(eid);
}
return result; return result;
} }
@ -245,31 +297,27 @@ namespace SHADE
const bool isSelected = (std::ranges::find(editor->selectedEntities, eid) != editor->selectedEntities.end()); const bool isSelected = (std::ranges::find(editor->selectedEntities, eid) != editor->selectedEntities.end());
bool highlighted = false; bool highlighted = false, open = false;
//if(!filter.empty()) if(!filter.empty())
//{ {
// highlighted = EntityFilterCheck(currentNode); highlighted = (std::ranges::find(filterHighlightedEntities, eid) != filterHighlightedEntities.end());
// if (highlighted) if(open = std::ranges::find(filterOpenEntities, eid) != filterOpenEntities.end())
// { {
// ImGui::PushStyleColor(ImGuiCol_Text, highlightedColor); ImGui::SetNextItemOpen(true);
// }
// ImGui::SetNextItemOpen(true);
// if(!open && !highlighted)
// {
// } return ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
// else }
// { ImGui::PushStyleColor(ImGuiCol_Text, highlighted ? highlightedColor : ImVec4(0.5f, 0.5f, 0.5f, 1.f ));
// }
// }
//}
const ImGuiTreeNodeFlags nodeFlags = ((isSelected) ? ImGuiTreeNodeFlags_Selected : 0) | ((children.empty()) ? ImGuiTreeNodeFlags_Leaf : ImGuiTreeNodeFlags_OpenOnArrow); const ImGuiTreeNodeFlags nodeFlags = ((isSelected) ? ImGuiTreeNodeFlags_Selected : 0) | ((children.empty()) ? ImGuiTreeNodeFlags_Leaf : ImGuiTreeNodeFlags_OpenOnArrow);
//Draw Node //Draw Node
bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast<void*>(eid), nodeFlags, "%u: %s", SHEntityManager::GetEntityIndex(eid), entity->name.c_str()); bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast<void*>(eid), nodeFlags, "%u: %s", SHEntityManager::GetEntityIndex(eid), entity->name.c_str());
if (highlighted) if(!filter.empty())
{ {
ImGui::PopStyleColor(); ImGui::PopStyleColor();
} }

View File

@ -44,7 +44,8 @@ namespace SHADE
std::string filter; std::string filter;
bool isAnyNodeSelected = false; bool isAnyNodeSelected = false;
EntityID scrollTo = MAX_EID; EntityID scrollTo = MAX_EID;
std::vector<EntityID> draggingEntities; std::vector<EntityID> draggingEntities, filterOpenEntities, filterHighlightedEntities;
bool wasFilterChanged = false;
};//class SHHierarchyPanel };//class SHHierarchyPanel

View File

@ -22,6 +22,8 @@
#include "Serialization/SHSerializationHelper.hpp" #include "Serialization/SHSerializationHelper.hpp"
#include "Tools/Utilities/SHClipboardUtilities.h" #include "Tools/Utilities/SHClipboardUtilities.h"
#include "SHInspectorCommands.h" #include "SHInspectorCommands.h"
#include "Physics/Collision/SHCollisionTagMatrix.h"
#include "Animation/SHAnimatorComponent.h"
namespace SHADE namespace SHADE
{ {
template<typename T> template<typename T>
@ -574,4 +576,60 @@ namespace SHADE
} }
ImGui::PopID(); ImGui::PopID();
} }
template<>
static void DrawComponent(SHAnimatorComponent* component)
{
if (!component)
return;
ImGui::PushID(SHFamilyID<SHComponent>::GetID<SHAnimatorComponent>());
const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data()))
{
DrawContextMenu(component);
Handle<SHRig> const& rig = component->GetRig();
const auto RIG_NAME = rig ? SHResourceManager::GetAssetName<SHRig>(rig).value_or("") : "";
SHEditorWidgets::DragDropReadOnlyField<AssetID>("Rig", RIG_NAME, [component]()
{
Handle<SHRig> const& rig = component->GetRig();
return SHResourceManager::GetAssetID<SHRig>(rig).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->SetRig(SHResourceManager::LoadOrGet<SHRig>(id));
SHResourceManager::FinaliseChanges();
}, SHDragDrop::DRAG_RESOURCE);
Handle<SHAnimationClip> const& clip = component->GetCurrentClip();
const auto CLIP_NAME = clip ? SHResourceManager::GetAssetName<SHAnimationClip>(clip).value_or("") : "";
SHEditorWidgets::DragDropReadOnlyField<AssetID>("Clip", CLIP_NAME,
[component]()
{
Handle<SHAnimationClip> const& clip = component->GetCurrentClip();
return SHResourceManager::GetAssetID<SHAnimationClip>(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);
}
else
{
DrawContextMenu(component);
}
ImGui::PopID();
}
} }

View File

@ -28,6 +28,13 @@
namespace SHADE namespace SHADE
{ {
template<typename Component>
void EnsureComponent(EntityID eid)
{
if(SHComponentManager::GetComponent_s<Component>(eid) == nullptr)
SHComponentManager::AddComponent<Component>(eid);
}
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
bool DrawAddComponentButton(EntityID const& eid) bool DrawAddComponentButton(EntityID const& eid)
{ {
@ -49,9 +56,13 @@ namespace SHADE
return selected; return selected;
} }
template <typename ComponentType, typename EnforcedComponent, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true, std::enable_if_t<std::is_base_of_v<SHComponent, EnforcedComponent>, bool> = true> template <typename ComponentType, typename ... EnforcedComponents>
bool DrawAddComponentWithEnforcedComponentButton(EntityID const& eid) bool DrawAddComponentWithEnforcedComponentButton(EntityID const& eid)
{ {
// Only make sure components are passed here
static_assert(std::is_base_of_v<SHComponent, ComponentType>, "");
//(static_assert(std::is_base_of_v<SHComponent, EnforcedComponents>, ""), ...);
bool selected = false; bool selected = false;
if (!SHComponentManager::HasComponent<ComponentType>(eid)) if (!SHComponentManager::HasComponent<ComponentType>(eid))
{ {
@ -59,9 +70,8 @@ namespace SHADE
if(selected = ImGui::Selectable(std::format("Add {}", componentName).data()); selected) if(selected = ImGui::Selectable(std::format("Add {}", componentName).data()); selected)
{ {
if(SHComponentManager::GetComponent_s<EnforcedComponent>(eid) == nullptr) // Ensure that all required components are present
SHComponentManager::AddComponent<EnforcedComponent>(eid); (EnsureComponent<EnforcedComponents>(eid), ...);
SHComponentManager::AddComponent<ComponentType>(eid); SHComponentManager::AddComponent<ComponentType>(eid);
} }
if(ImGui::IsItemHovered()) if(ImGui::IsItemHovered())
@ -70,9 +80,8 @@ namespace SHADE
ImGui::Text("Adds", componentName); ImGui::SameLine(); ImGui::Text("Adds", componentName); ImGui::SameLine();
ImGui::TextColored(ImGuiColors::green, "%s", componentName); ImGui::SameLine(); ImGui::TextColored(ImGuiColors::green, "%s", componentName); ImGui::SameLine();
ImGui::Text("to this entity", componentName); ImGui::Text("to this entity", componentName);
ImGui::Text("Adds"); ImGui::SameLine(); ImGui::Text("Adds the following components if the entity does not already have it: ");
ImGui::TextColored(ImGuiColors::red, "%s", rttr::type::get<EnforcedComponent>().get_name().data()); ImGui::SameLine(); (ImGui::TextColored(ImGuiColors::red, "%s", rttr::type::get<EnforcedComponents>().get_name().data()), ...);
ImGui::Text("if the entity does not already have it");
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
} }
@ -118,6 +127,10 @@ namespace SHADE
{ {
DrawComponent(renderableComponent); DrawComponent(renderableComponent);
} }
if (auto animatorComponent = SHComponentManager::GetComponent_s<SHAnimatorComponent>(eid))
{
DrawComponent(animatorComponent);
}
if(auto colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(eid)) if(auto colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(eid))
{ {
DrawComponent(colliderComponent); DrawComponent(colliderComponent);
@ -179,6 +192,7 @@ namespace SHADE
DrawAddComponentWithEnforcedComponentButton<SHRigidBodyComponent, SHTransformComponent>(eid); DrawAddComponentWithEnforcedComponentButton<SHRigidBodyComponent, SHTransformComponent>(eid);
DrawAddComponentWithEnforcedComponentButton<SHColliderComponent, SHTransformComponent>(eid); DrawAddComponentWithEnforcedComponentButton<SHColliderComponent, SHTransformComponent>(eid);
DrawAddComponentWithEnforcedComponentButton<SHTextRenderableComponent, SHTransformComponent>(eid); DrawAddComponentWithEnforcedComponentButton<SHTextRenderableComponent, SHTransformComponent>(eid);
DrawAddComponentWithEnforcedComponentButton<SHAnimatorComponent, SHTransformComponent, SHRenderable>(eid);
ImGui::EndMenu(); ImGui::EndMenu();

View File

@ -201,8 +201,8 @@ namespace SHADE
// Get interface for the shader combination // Get interface for the shader combination
auto interface = fragShader->GetReflectedData().GetDescriptorBindingInfo().GetShaderBlockInterface auto interface = fragShader->GetReflectedData().GetDescriptorBindingInfo().GetShaderBlockInterface
( (
mappings.at(SHPredefinedDescriptorTypes::MATERIALS), mappings.at(SHPredefinedDescriptorTypes::PER_INSTANCE_BATCH),
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA SHGraphicsConstants::DescriptorSetBindings::PER_INST_MATERIAL_DATA
); );
if (!interface) if (!interface)
return; return;

View File

@ -106,8 +106,8 @@ namespace SHADE
SHEditorWindowManager::CreateEditorWindow<SHMaterialInspector>(); SHEditorWindowManager::CreateEditorWindow<SHMaterialInspector>();
SHEditorWindowManager::CreateEditorWindow<SHColliderTagPanel>(); SHEditorWindowManager::CreateEditorWindow<SHColliderTagPanel>();
SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>(); SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>();
SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>();
SHEditorWindowManager::CreateEditorWindow<SHInputBindingsPanel>(); SHEditorWindowManager::CreateEditorWindow<SHInputBindingsPanel>();
SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>();
SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>(); SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>();

View File

@ -105,6 +105,12 @@ namespace SHADE
std::vector<SHAsset> assets; std::vector<SHAsset> assets;
// Get all subfolders/files in this current folder // Get all subfolders/files in this current folder
if (!std::filesystem::exists(std::filesystem::path(folder->path)))
{
SHLOG_WARNING("[Asset Manager] Path to build directory does not exist!: {}", folder->path);
continue;
}
for (auto& dirEntry : std::filesystem::directory_iterator(folder->path)) for (auto& dirEntry : std::filesystem::directory_iterator(folder->path))
{ {
auto path = dirEntry.path(); auto path = dirEntry.path();

View File

@ -29,48 +29,59 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/Descriptors/SHVkDescriptorPool.h" #include "Graphics/Descriptors/SHVkDescriptorPool.h"
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
#include "UI/SHUIComponent.h" #include "UI/SHUIComponent.h"
#include "Animation/SHAnimatorComponent.h"
namespace SHADE namespace SHADE
{ {
/*---------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* SHBatch - Usage Functions */ /* SHBatch - Constructors/Destructors */
/*---------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHBatch::SHBatch(Handle<SHVkPipeline> pipeline) SHBatch::SHBatch(Handle<SHVkPipeline> pipeline)
: pipeline{ pipeline } : pipeline{ pipeline }
{ {
if (!pipeline) if (!pipeline)
throw std::invalid_argument("Attempted to create a SHBatch with an invalid SHPipeline!"); throw std::invalid_argument("Attempted to create a SHBatch with an invalid SHPipeline!");
// Check the pipeline and flag it depending on whether or not it is animated
isAnimated = checkIfIsAnimatedPipeline(pipeline);
// Mark all as dirty // Mark all as dirty
setAllDirtyFlags(); setAllDirtyFlags();
} }
SHBatch::SHBatch(SHBatch&& rhs) SHBatch::SHBatch(SHBatch&& rhs)
: device { rhs.device } : device { rhs.device }
, pipeline { rhs.pipeline } , isAnimated { rhs.isAnimated }
, referencedMatInstances { std::move(rhs.referencedMatInstances) } , pipeline { rhs.pipeline }
, matBufferDirty { std::move(rhs.matBufferDirty) } , referencedMatInstances { std::move(rhs.referencedMatInstances) }
, subBatches { std::move(rhs.subBatches) } , matBufferDirty { std::move(rhs.matBufferDirty) }
, isDirty { std::move(rhs.isDirty) } , subBatches { std::move(rhs.subBatches) }
, drawData { std::move(rhs.drawData) } , isDirty { std::move(rhs.isDirty) }
, transformData { std::move(rhs.transformData) } , drawData { std::move(rhs.drawData) }
, instancedIntegerData { std::move(rhs.instancedIntegerData) } , transformData { std::move(rhs.transformData) }
, matPropsData { std::move(rhs.matPropsData) } , instancedIntegerData { std::move(rhs.instancedIntegerData) }
, matPropsDataSize { rhs.matPropsDataSize } , matPropsData { std::move(rhs.matPropsData) }
, singleMatPropAlignedSize { rhs.singleMatPropAlignedSize } , matPropsDataSize { rhs.matPropsDataSize }
, singleMatPropSize { rhs.singleMatPropSize } , singleMatPropAlignedSize { rhs.singleMatPropAlignedSize }
, isCPUBuffersDirty { rhs.isCPUBuffersDirty } , singleMatPropSize { rhs.singleMatPropSize }
, drawDataBuffer { rhs.drawDataBuffer } , boneMatrixData { std::move(rhs.boneMatrixData) }
, transformDataBuffer { rhs.transformDataBuffer } , boneMatrixIndices { std::move(rhs.boneMatrixIndices) }
, instancedIntegerBuffer { rhs.instancedIntegerBuffer } , isCPUBuffersDirty { rhs.isCPUBuffersDirty }
, matPropsBuffer { rhs.matPropsBuffer } , drawDataBuffer { rhs.drawDataBuffer }
, matPropsDescSet { rhs.matPropsDescSet } , transformDataBuffer { rhs.transformDataBuffer }
, instancedIntegerBuffer { rhs.instancedIntegerBuffer }
, matPropsBuffer { rhs.matPropsBuffer }
, boneMatrixBuffer { rhs.boneMatrixBuffer }
, boneMatrixFirstIndexBuffer { rhs.boneMatrixFirstIndexBuffer }
, instanceDataDescSet { rhs.instanceDataDescSet }
{ {
rhs.drawDataBuffer = {}; rhs.drawDataBuffer = {};
rhs.transformDataBuffer = {}; rhs.transformDataBuffer = {};
rhs.instancedIntegerBuffer = {}; rhs.instancedIntegerBuffer = {};
rhs.matPropsBuffer = {}; rhs.matPropsBuffer = {};
rhs.matPropsDescSet = {}; rhs.boneMatrixBuffer = {};
rhs.boneMatrixFirstIndexBuffer = {};
rhs.instanceDataDescSet = {};
} }
SHBatch& SHBatch::operator=(SHBatch&& rhs) SHBatch& SHBatch::operator=(SHBatch&& rhs)
@ -78,32 +89,39 @@ namespace SHADE
if (this == &rhs) if (this == &rhs)
return *this; return *this;
device = rhs.device ; device = rhs.device ;
pipeline = rhs.pipeline ; isAnimated = rhs.isAnimated ;
referencedMatInstances = std::move(rhs.referencedMatInstances); pipeline = rhs.pipeline ;
matBufferDirty = std::move(rhs.matBufferDirty) ; referencedMatInstances = std::move(rhs.referencedMatInstances);
subBatches = std::move(rhs.subBatches) ; matBufferDirty = std::move(rhs.matBufferDirty) ;
isDirty = std::move(rhs.isDirty) ; subBatches = std::move(rhs.subBatches) ;
drawData = std::move(rhs.drawData) ; isDirty = std::move(rhs.isDirty) ;
transformData = std::move(rhs.transformData) ; drawData = std::move(rhs.drawData) ;
instancedIntegerData = std::move(rhs.instancedIntegerData) ; transformData = std::move(rhs.transformData) ;
matPropsData = std::move(rhs.matPropsData) ; instancedIntegerData = std::move(rhs.instancedIntegerData) ;
matPropsDataSize = rhs.matPropsDataSize ; matPropsData = std::move(rhs.matPropsData) ;
singleMatPropAlignedSize = rhs.singleMatPropAlignedSize ; matPropsDataSize = rhs.matPropsDataSize ;
singleMatPropSize = rhs.singleMatPropSize ; singleMatPropAlignedSize = rhs.singleMatPropAlignedSize ;
isCPUBuffersDirty = rhs.isCPUBuffersDirty ; singleMatPropSize = rhs.singleMatPropSize ;
drawDataBuffer = rhs.drawDataBuffer ; boneMatrixData = std::move(rhs.boneMatrixData) ;
transformDataBuffer = rhs.transformDataBuffer ; boneMatrixIndices = std::move(rhs.boneMatrixIndices) ;
instancedIntegerBuffer = rhs.instancedIntegerBuffer ; isCPUBuffersDirty = rhs.isCPUBuffersDirty ;
matPropsBuffer = rhs.matPropsBuffer ; drawDataBuffer = rhs.drawDataBuffer ;
matPropsDescSet = rhs.matPropsDescSet ; transformDataBuffer = rhs.transformDataBuffer ;
instancedIntegerBuffer = rhs.instancedIntegerBuffer ;
matPropsBuffer = rhs.matPropsBuffer ;
boneMatrixBuffer = rhs.boneMatrixBuffer ;
boneMatrixFirstIndexBuffer = rhs.boneMatrixFirstIndexBuffer ;
instanceDataDescSet = rhs.instanceDataDescSet ;
// Unset values // Unset values
rhs.drawDataBuffer = {}; rhs.drawDataBuffer = {};
rhs.transformDataBuffer = {}; rhs.transformDataBuffer = {};
rhs.instancedIntegerBuffer = {}; rhs.instancedIntegerBuffer = {};
rhs.matPropsBuffer = {}; rhs.matPropsBuffer = {};
rhs.matPropsDescSet = {}; rhs.boneMatrixBuffer = {};
rhs.boneMatrixFirstIndexBuffer = {};
rhs.instanceDataDescSet = {};
return *this; return *this;
} }
@ -121,11 +139,14 @@ namespace SHADE
instancedIntegerBuffer[i].Free(); instancedIntegerBuffer[i].Free();
if (matPropsBuffer[i]) if (matPropsBuffer[i])
matPropsBuffer[i].Free(); matPropsBuffer[i].Free();
if (matPropsDescSet[i]) if (instanceDataDescSet[i])
matPropsDescSet[i].Free(); instanceDataDescSet[i].Free();
} }
} }
/*-----------------------------------------------------------------------------------*/
/* SHBatch - Usage Functions */
/*-----------------------------------------------------------------------------------*/
void SHBatch::Add(const SHRenderable* renderable) void SHBatch::Add(const SHRenderable* renderable)
{ {
// Ignore if null // Ignore if null
@ -285,7 +306,7 @@ namespace SHADE
} }
// Transfer to GPU // Transfer to GPU
rebuildMaterialBuffers(frameIndex, descPool); rebuildDescriptorSetBuffers(frameIndex, descPool);
// This frame is updated // This frame is updated
matBufferDirty[frameIndex] = false; matBufferDirty[frameIndex] = false;
@ -359,21 +380,86 @@ namespace SHADE
// Populate on the CPU // Populate on the CPU
for (auto& subBatch : subBatches) for (auto& subBatch : subBatches)
for (auto rendId : subBatch.Renderables) for (auto rendId : subBatch.Renderables)
{
auto* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
instancedIntegerData.emplace_back(SHInstancedIntegerData
{ {
auto* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId); rendId,
instancedIntegerData.emplace_back(SHInstancedIntegerData renderable->GetLightLayer()
{ });
rendId, }
renderable->GetLightLayer()
}
);
}
// Transfer to GPU // Transfer to GPU
if (instancedIntegerBuffer[frameIndex] && !drawData.empty()) if (instancedIntegerBuffer[frameIndex] && !drawData.empty())
instancedIntegerBuffer[frameIndex]->WriteToMemory(instancedIntegerData.data(), static_cast<uint32_t>(instancedIntegerData.size() * sizeof(SHInstancedIntegerData)), 0, 0); instancedIntegerBuffer[frameIndex]->WriteToMemory(instancedIntegerData.data(), static_cast<uint32_t>(instancedIntegerData.size() * sizeof(SHInstancedIntegerData)), 0, 0);
}
void SHBatch::UpdateAnimationBuffer(uint32_t frameIndex)
{
// Ignore if not animated batch
if (!isAnimated)
return;
// Frame Index check
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to update animation buffers with an invalid frame index.");
return;
}
// Reset Animation Matrix Data
boneMatrixData.clear();
boneMatrixIndices.clear();
// Add the first identity matrix into the bone matrix data
boneMatrixData.emplace_back(SHMatrix::Identity); // This kills the GPU
// Populate on the CPU
for (auto& subBatch : subBatches)
for (auto rendId : subBatch.Renderables)
{
// Get resources
auto animator = SHComponentManager::GetComponent_s<SHAnimatorComponent>(rendId);
auto renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
auto mesh = renderable->GetMesh();
// Mark start
boneMatrixIndices.emplace_back(static_cast<uint32_t>(boneMatrixData.size()));
// Add matrices
const int BONE_COUNT = static_cast<int>(mesh->BoneCount);
int extraMatricesToAdd = BONE_COUNT;
if (animator)
{
// Add matrices
const auto& MATRICES = animator->GetBoneMatrices();
if (MATRICES.size() <= BONE_COUNT)
{
boneMatrixData.insert(boneMatrixData.end(), MATRICES.cbegin(), MATRICES.cend());
extraMatricesToAdd = std::max({0, BONE_COUNT - static_cast<int>(MATRICES.size())});
}
}
// If we need to patch up with more matrices, add it
if (extraMatricesToAdd > 0)
{
boneMatrixData.insert(boneMatrixData.end(), extraMatricesToAdd, SHMatrix::Identity);
}
}
// Update GPU Buffers
if (!boneMatrixIndices.empty())
{
const uint32_t BMI_DATA_BYTES = static_cast<uint32_t>(boneMatrixIndices.size() * sizeof(uint32_t));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, boneMatrixFirstIndexBuffer[frameIndex], boneMatrixIndices.data(), BMI_DATA_BYTES,
vk::BufferUsageFlagBits::eVertexBuffer,
"Batch Instance Bone Matrix First Index Buffer"
);
}
rebuildBoneMatrixDescSetBuffer(frameIndex);
} }
void SHBatch::Build(Handle<SHVkLogicalDevice> _device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) void SHBatch::Build(Handle<SHVkLogicalDevice> _device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex)
@ -410,14 +496,23 @@ namespace SHADE
// - EID data // - EID data
instancedIntegerData.reserve(numTotalElements); instancedIntegerData.reserve(numTotalElements);
instancedIntegerData.clear(); instancedIntegerData.clear();
// - Bone Data
if (isAnimated)
{
boneMatrixData.clear();
boneMatrixIndices.clear();
boneMatrixIndices.reserve(numTotalElements);
auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING); // Add the first identity matrix into the bone matrix data
boneMatrixData.emplace_back(SHMatrix::Identity);
}
// - Material Properties Data // - Material Properties Data
auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING);
const Handle<SHShaderBlockInterface> SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface const Handle<SHShaderBlockInterface> SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface
( (
descMappings.at(SHPredefinedDescriptorTypes::MATERIALS), descMappings.at(SHPredefinedDescriptorTypes::PER_INSTANCE_BATCH),
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA, SHGraphicsConstants::DescriptorSetBindings::PER_INST_MATERIAL_DATA,
vk::ShaderStageFlagBits::eFragment vk::ShaderStageFlagBits::eFragment
); );
const bool EMPTY_MAT_PROPS = !SHADER_INFO; const bool EMPTY_MAT_PROPS = !SHADER_INFO;
@ -444,13 +539,13 @@ namespace SHADE
if (CURR_INSTANCES > 0) if (CURR_INSTANCES > 0)
{ {
drawData.emplace_back(vk::DrawIndexedIndirectCommand drawData.emplace_back(vk::DrawIndexedIndirectCommand
{ {
.indexCount = subBatch.Mesh->IndexCount, .indexCount = subBatch.Mesh->IndexCount,
.instanceCount = CURR_INSTANCES, .instanceCount = CURR_INSTANCES,
.firstIndex = subBatch.Mesh->FirstIndex, .firstIndex = subBatch.Mesh->FirstIndex,
.vertexOffset = subBatch.Mesh->FirstVertex, .vertexOffset = subBatch.Mesh->FirstVertex,
.firstInstance = nextInstanceIndex .firstInstance = nextInstanceIndex
}); });
} }
nextInstanceIndex += CURR_INSTANCES; nextInstanceIndex += CURR_INSTANCES;
@ -503,9 +598,36 @@ namespace SHADE
{ {
SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!"); SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
} }
//propsCurrPtr += singleMatPropAlignedSize;
propsCurrPtr += singleMatPropSize; propsCurrPtr += singleMatPropSize;
} }
// Bone Data
if (isAnimated)
{
// Mark start
boneMatrixIndices.emplace_back(static_cast<uint32_t>(boneMatrixData.size()));
auto animator = SHComponentManager::GetComponent_s<SHAnimatorComponent>(rendId);
auto mesh = renderable->GetMesh();
const int BONE_COUNT = static_cast<int>(mesh->BoneCount);
int extraMatricesToAdd = BONE_COUNT;
if (animator)
{
// Add matrices
const auto& MATRICES = animator->GetBoneMatrices();
if (MATRICES.size() <= BONE_COUNT)
{
boneMatrixData.insert(boneMatrixData.end(), MATRICES.cbegin(), MATRICES.cend());
extraMatricesToAdd = std::max({0, BONE_COUNT - static_cast<int>(MATRICES.size())});
}
}
// If we need to patch up with more matrices, add it
if (extraMatricesToAdd > 0)
{
boneMatrixData.insert(boneMatrixData.end(), extraMatricesToAdd, SHMatrix::Identity);
}
}
} }
} }
@ -540,8 +662,19 @@ namespace SHADE
BuffUsage::eVertexBuffer, BuffUsage::eVertexBuffer,
"Batch Instance Data Buffer" "Batch Instance Data Buffer"
); );
// - Material Properties Buffer // - Bone Matrix Indices
rebuildMaterialBuffers(frameIndex, descPool); if (isAnimated && !boneMatrixIndices.empty())
{
const uint32_t BMI_DATA_BYTES = static_cast<uint32_t>(boneMatrixIndices.size() * sizeof(uint32_t));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, boneMatrixFirstIndexBuffer[frameIndex], boneMatrixIndices.data(), BMI_DATA_BYTES,
BuffUsage::eVertexBuffer,
"Batch Instance Bone Matrix First Index Buffer"
);
}
// - Material and bone buffers/descriptor sets
rebuildDescriptorSetBuffers(frameIndex, descPool);
} }
// Mark this frame as no longer dirty // Mark this frame as no longer dirty
@ -551,7 +684,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* SHBatch - Usage Functions */ /* SHBatch - Usage Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline/* = true*/) void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline)
{ {
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{ {
@ -564,7 +697,11 @@ namespace SHADE
return; return;
// Bind all required objects before drawing // Bind all required objects before drawing
static std::array<uint32_t, 1> dynamicOffset{ 0 }; std::vector<uint32_t> dynamicOffset{ 0 };
if (isAnimated && !boneMatrixData.empty())
{
dynamicOffset.emplace_back(0);
}
cmdBuffer->BeginLabeledSegment("SHBatch for Pipeline #" + std::to_string(pipeline.GetId().Data.Index)); cmdBuffer->BeginLabeledSegment("SHBatch for Pipeline #" + std::to_string(pipeline.GetId().Data.Index));
if (bindBatchPipeline) if (bindBatchPipeline)
@ -572,16 +709,24 @@ namespace SHADE
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0); cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0); cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0);
if (matPropsDescSet[frameIndex]) if (isAnimated && boneMatrixFirstIndexBuffer[frameIndex])
{ {
auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING); cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::BONE_MATRIX_FIRST_INDEX, boneMatrixFirstIndexBuffer[frameIndex], 0);
}
else
{
// HACK: Bind the transform buffer instead since we won't use it anyways, but we must bind something
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::BONE_MATRIX_FIRST_INDEX, transformDataBuffer[frameIndex], 0);
}
auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING);
if (instanceDataDescSet[frameIndex])
{
cmdBuffer->BindDescriptorSet cmdBuffer->BindDescriptorSet
( (
matPropsDescSet[frameIndex], instanceDataDescSet[frameIndex],
SH_PIPELINE_TYPE::GRAPHICS, SH_PIPELINE_TYPE::GRAPHICS,
//SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, descMappings.at(SHPredefinedDescriptorTypes::PER_INSTANCE_BATCH),
descMappings.at(SHPredefinedDescriptorTypes::MATERIALS),
dynamicOffset dynamicOffset
); );
} }
@ -624,49 +769,128 @@ namespace SHADE
isCPUBuffersDirty = true; isCPUBuffersDirty = true;
} }
void SHBatch::rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) void SHBatch::rebuildDescriptorSetBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{ {
if (matPropsData && !drawData.empty()) // Using Declarations and constants
{ using BuffUsage = vk::BufferUsageFlagBits;
SHVkUtil::EnsureBufferAndCopyHostVisibleData using PreDefDescLayoutType = SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes;
(
device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
vk::BufferUsageFlagBits::eStorageBuffer,
"Batch Material Data"
);
if (!matPropsDescSet[frameIndex]) /* Create Descriptor Sets if Needed */
PreDefDescLayoutType layoutTypes = {};
if (matPropsData)
{
layoutTypes = PreDefDescLayoutType::MATERIALS;
}
if (!boneMatrixData.empty())
{
layoutTypes = PreDefDescLayoutType::MATERIAL_AND_BONES;
}
const bool MUST_BUILD_BONE_DESC = isAnimated && !boneMatrixData.empty();
if (matPropsData || MUST_BUILD_BONE_DESC)
{
// Make sure that we have a descriptor set if we don't already have one
if (!instanceDataDescSet[frameIndex])
{ {
matPropsDescSet[frameIndex] = descPool->Allocate instanceDataDescSet[frameIndex] = descPool->Allocate
( (
SHGraphicsPredefinedData::GetPredefinedDescSetLayouts(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::MATERIALS), SHGraphicsPredefinedData::GetPredefinedDescSetLayouts(layoutTypes),
{ 0 } { 0 }
); );
#ifdef _DEBUG #ifdef _DEBUG
const auto& DESC_SETS = matPropsDescSet[frameIndex]->GetVkHandle(); const auto& DESC_SETS = instanceDataDescSet[frameIndex]->GetVkHandle();
for (auto descSet : DESC_SETS) for (auto descSet : DESC_SETS)
{ {
SET_VK_OBJ_NAME(device, vk::ObjectType::eDescriptorSet, descSet, "[Descriptor Set] Batch Material Data"); SET_VK_OBJ_NAME(device, vk::ObjectType::eDescriptorSet, descSet, "[Descriptor Set] Batch Material Data");
} }
#endif #endif
} }
}
static constexpr uint32_t MATERIAL_DESC_SET_INDEX = 0; /* Material Data */
if (matPropsData && !drawData.empty())
{
// Update GPU buffer
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
BuffUsage::eStorageBuffer,
"Batch Material Data"
);
// Update descriptor set buffer
std::array<Handle<SHVkBuffer>, 1> bufferList = { matPropsBuffer[frameIndex] }; std::array<Handle<SHVkBuffer>, 1> bufferList = { matPropsBuffer[frameIndex] };
matPropsDescSet[frameIndex]->ModifyWriteDescBuffer instanceDataDescSet[frameIndex]->ModifyWriteDescBuffer
( (
MATERIAL_DESC_SET_INDEX, MATERIAL_DESC_SET_INDEX,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA, SHGraphicsConstants::DescriptorSetBindings::PER_INST_MATERIAL_DATA,
bufferList, bufferList,
0, static_cast<uint32_t>(matPropsDataSize) 0, static_cast<uint32_t>(matPropsDataSize)
); );
matPropsDescSet[frameIndex]->UpdateDescriptorSetBuffer
// Update the descriptor set buffer
instanceDataDescSet[frameIndex]->UpdateDescriptorSetBuffer
( (
MATERIAL_DESC_SET_INDEX, MATERIAL_DESC_SET_INDEX,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA SHGraphicsConstants::DescriptorSetBindings::PER_INST_MATERIAL_DATA
); );
} }
/* Animation Bone Data */
if (MUST_BUILD_BONE_DESC)
{
rebuildBoneMatrixDescSetBuffer(frameIndex);
}
} }
void SHBatch::rebuildBoneMatrixDescSetBuffer(uint32_t frameIndex)
{
using BuffUsage = vk::BufferUsageFlagBits;
// Update GPU Buffers
const uint32_t BONE_MTX_DATA_BYTES = static_cast<uint32_t>(boneMatrixData.size() * sizeof(SHMatrix));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, boneMatrixBuffer[frameIndex], boneMatrixData.data(), BONE_MTX_DATA_BYTES,
BuffUsage::eStorageBuffer,
"Batch Bone Matrix Buffer"
);
// Update descriptor set buffer
std::array<Handle<SHVkBuffer>, 1> bufferList = { boneMatrixBuffer[frameIndex] };
instanceDataDescSet[frameIndex]->ModifyWriteDescBuffer
(
MATERIAL_DESC_SET_INDEX,
SHGraphicsConstants::DescriptorSetBindings::PER_INST_BONE_DATA,
bufferList,
0,
static_cast<uint32_t>(boneMatrixData.size() * sizeof(SHMatrix))
);
// Update the descriptor set buffer
instanceDataDescSet[frameIndex]->UpdateDescriptorSetBuffer
(
MATERIAL_DESC_SET_INDEX,
SHGraphicsConstants::DescriptorSetBindings::PER_INST_BONE_DATA
);
}
bool SHBatch::checkIfIsAnimatedPipeline(Handle<SHVkPipeline> pipeline)
{
if (!pipeline || !pipeline->GetPipelineLayout())
return false;
// Grab the pipeline descriptor set layouts
auto pipelineDescLayouts = pipeline->GetPipelineLayout()->GetDescriptorSetLayoutsPipeline();
// Check if they contain the material and bones layout, that indicates it is
using GfxPreDef = SHGraphicsPredefinedData;
using GfxPreDefType = GfxPreDef::PredefinedDescSetLayoutTypes;
const Handle<SHVkDescriptorSetLayout> BONE_DESC_SET_LAYOUT = GfxPreDef::GetPredefinedDescSetLayouts(GfxPreDefType::MATERIAL_AND_BONES)[0];
return std::find_if(pipelineDescLayouts.begin(), pipelineDescLayouts.end(), [BONE_DESC_SET_LAYOUT](Handle<SHVkDescriptorSetLayout> layout)
{
return BONE_DESC_SET_LAYOUT == layout;
}) != pipelineDescLayouts.end();
}
} }

View File

@ -27,116 +27,132 @@ of DigiPen Institute of Technology is prohibited.
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHVkBuffer;
class SHVkCommandBuffer;
class SHVkPipeline;
class SHMesh;
class SHRenderable;
class SHVkLogicalDevice;
class SHMaterialInstance;
class SHVkDescriptorSetGroup;
class SHVkDescriptorPool;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/*************************************************************************************/
/*!
\brief
Describes a segment of the sub batch operation.
*/
/*************************************************************************************/
struct SHSubBatch
{
public:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Forward Declarations */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
class SHVkBuffer; Handle<SHMesh> Mesh;
class SHVkCommandBuffer; std::unordered_set<EntityID> Renderables;
class SHVkPipeline; };
class SHMesh; /*************************************************************************************/
class SHRenderable; /*!
class SHVkLogicalDevice; \brief
class SHMaterialInstance; Describes a segment of the sub batch operation.
class SHVkDescriptorSetGroup; */
class SHVkDescriptorPool; /*************************************************************************************/
class SHBatch
{
public:
/*---------------------------------------------------------------------------------*/
/* Constructor/Destructors */
/*---------------------------------------------------------------------------------*/
SHBatch(Handle<SHVkPipeline> pipeline);
SHBatch(const SHBatch&) = delete;
SHBatch(SHBatch&& rhs);
SHBatch& operator=(const SHBatch&) = delete;
SHBatch& operator=(SHBatch&& rhs);
~SHBatch();
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Type Definitions */ /* Usage Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/***********************************************************************************/ void Add(const SHRenderable* renderable);
/*! void Remove(const SHRenderable* renderable);
\brief void Clear();
Describes a segment of the sub batch operation. void UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
*/ void UpdateTransformBuffer(uint32_t frameIndex);
/***********************************************************************************/ void UpdateInstancedIntegerBuffer(uint32_t frameIndex);
struct SHSubBatch void UpdateAnimationBuffer(uint32_t frameIndex);
{ void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex);
public: void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline);
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
Handle<SHMesh> Mesh;
std::unordered_set<EntityID> Renderables;
};
/***********************************************************************************/
/*!
\brief
Describes a segment of the sub batch operation.
*/
/***********************************************************************************/
class SHBatch
{
public:
/*-----------------------------------------------------------------------------*/
/* Constructor/Destructors */
/*-----------------------------------------------------------------------------*/
SHBatch(Handle<SHVkPipeline> pipeline);
SHBatch(const SHBatch&) = delete;
SHBatch(SHBatch&& rhs);
SHBatch& operator=(const SHBatch&) = delete;
SHBatch& operator=(SHBatch&& rhs);
~SHBatch();
/*-----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Usage Functions */ /* Getter Functions */
/*-----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void Add(const SHRenderable* renderable); Handle<SHVkPipeline> GetPipeline() const noexcept { return pipeline; };
void Remove(const SHRenderable* renderable); bool IsEmpty() const noexcept { return subBatches.empty(); }
void Clear(); Handle<SHVkBuffer> GetTransformBuffer(uint32_t frameIndex) const noexcept;
void UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool); Handle<SHVkBuffer> GetMDIBuffer(uint32_t frameIndex) const noexcept;
void UpdateTransformBuffer(uint32_t frameIndex); bool IsAnimated() const noexcept { return isAnimated; }
void UpdateInstancedIntegerBuffer(uint32_t frameIndex);
void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) ;
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, bool bindBatchPipeline = true);
/*-----------------------------------------------------------------------------*/ private:
/* Getter Functions */ /*---------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------*/ /* Type Definition */
Handle<SHVkPipeline> GetPipeline() const noexcept { return pipeline; }; /*---------------------------------------------------------------------------------*/
bool IsEmpty() const noexcept { return subBatches.empty(); } using TripleBool = std::array<bool, SHGraphicsConstants::NUM_FRAME_BUFFERS>;
Handle<SHVkBuffer> GetTransformBuffer(uint32_t frameIndex) const noexcept; using TripleBuffer = std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS>;
Handle<SHVkBuffer> GetMDIBuffer(uint32_t frameIndex) const noexcept; using TripleDescSet = std::array<Handle<SHVkDescriptorSetGroup>, SHGraphicsConstants::NUM_FRAME_BUFFERS>;
/*---------------------------------------------------------------------------------*/
/* Constants */
/*---------------------------------------------------------------------------------*/
static constexpr uint32_t MATERIAL_DESC_SET_INDEX = 0;
private: /*---------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------*/ /* Data Members */
/* Type Definition */ /*---------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------*/ // Resources
using TripleBool = std::array<bool, SHGraphicsConstants::NUM_FRAME_BUFFERS>; Handle<SHVkLogicalDevice> device;
using TripleBuffer = std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS>; // Config
using TripleDescSet = std::array<Handle<SHVkDescriptorSetGroup>, SHGraphicsConstants::NUM_FRAME_BUFFERS>; bool isAnimated; // Whether the material supports animation
// Batch Properties
Handle<SHVkPipeline> pipeline;
std::unordered_set<Handle<SHMaterialInstance>> referencedMatInstances;
TripleBool matBufferDirty;
// Batch Tree
std::vector<SHSubBatch> subBatches;
TripleBool isDirty;
// CPU Buffers
std::vector<vk::DrawIndexedIndirectCommand> drawData;
std::vector<SHMatrix> transformData;
std::vector<SHInstancedIntegerData> instancedIntegerData;
std::unique_ptr<char> matPropsData;
Byte matPropsDataSize = 0;
Byte singleMatPropAlignedSize = 0;
Byte singleMatPropSize = 0;
std::vector<SHMatrix> boneMatrixData; // 0th element is always an identity matrix
std::vector<uint32_t> boneMatrixIndices;
bool isCPUBuffersDirty = true;
// GPU Buffers
TripleBuffer drawDataBuffer;
TripleBuffer transformDataBuffer;
TripleBuffer instancedIntegerBuffer;
TripleBuffer matPropsBuffer;
TripleBuffer boneMatrixBuffer;
TripleBuffer boneMatrixFirstIndexBuffer; // Instanced buffer, indicates where the first bone matrix is
TripleDescSet instanceDataDescSet;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Data Members */ /* Helper Functions */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
// Resources void setAllDirtyFlags();
Handle<SHVkLogicalDevice> device; void rebuildDescriptorSetBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
// Batch Properties void rebuildBoneMatrixDescSetBuffer(uint32_t frameIndex);
Handle<SHVkPipeline> pipeline; static bool checkIfIsAnimatedPipeline(Handle<SHVkPipeline> pipeline);
std::unordered_set<Handle<SHMaterialInstance>> referencedMatInstances;
TripleBool matBufferDirty;
// Batch Tree
std::vector<SHSubBatch> subBatches;
TripleBool isDirty;
// CPU Buffers
std::vector<vk::DrawIndexedIndirectCommand> drawData;
std::vector<SHMatrix> transformData;
std::vector<SHInstancedIntegerData> instancedIntegerData;
std::unique_ptr<char> matPropsData;
Byte matPropsDataSize = 0;
Byte singleMatPropAlignedSize = 0;
Byte singleMatPropSize = 0;
bool isCPUBuffersDirty = true;
// GPU Buffers
TripleBuffer drawDataBuffer;
TripleBuffer transformDataBuffer;
TripleBuffer instancedIntegerBuffer;
TripleBuffer matPropsBuffer;
TripleDescSet matPropsDescSet;
/*-----------------------------------------------------------------------------*/ };
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
void setAllDirtyFlags();
void rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
};
} }

View File

@ -94,6 +94,7 @@ namespace SHADE
{ {
batch.UpdateMaterialBuffer(frameIndex, descPool); batch.UpdateMaterialBuffer(frameIndex, descPool);
batch.UpdateTransformBuffer(frameIndex); batch.UpdateTransformBuffer(frameIndex);
batch.UpdateAnimationBuffer(frameIndex);
batch.UpdateInstancedIntegerBuffer(frameIndex); batch.UpdateInstancedIntegerBuffer(frameIndex);
} }
} }

View File

@ -23,13 +23,19 @@ namespace SHADE
void SHGraphicsPredefinedData::InitDescMappings(void) noexcept void SHGraphicsPredefinedData::InitDescMappings(void) noexcept
{ {
perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING)].descMappings.AddMappings perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING)].descMappings.AddMappings
({ ({
{SHPredefinedDescriptorTypes::STATIC_DATA, 0}, {SHPredefinedDescriptorTypes::STATIC_DATA, 0},
{SHPredefinedDescriptorTypes::CAMERA, 1}, {SHPredefinedDescriptorTypes::CAMERA, 1},
{SHPredefinedDescriptorTypes::MATERIALS, 2}, {SHPredefinedDescriptorTypes::PER_INSTANCE_BATCH, 2},
}); });
perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING_ANIM)].descMappings.AddMappings
({
{SHPredefinedDescriptorTypes::STATIC_DATA, 0},
{SHPredefinedDescriptorTypes::CAMERA, 1},
{SHPredefinedDescriptorTypes::PER_INSTANCE_ANIM_BATCH, 2},
});
perSystemData[SHUtilities::ConvertEnum(SystemType::TEXT_RENDERING)].descMappings.AddMappings perSystemData[SHUtilities::ConvertEnum(SystemType::TEXT_RENDERING)].descMappings.AddMappings
({ ({
@ -50,9 +56,13 @@ namespace SHADE
void SHGraphicsPredefinedData::InitDummyPipelineLayouts(Handle<SHVkLogicalDevice> logicalDevice) noexcept void SHGraphicsPredefinedData::InitDummyPipelineLayouts(Handle<SHVkLogicalDevice> logicalDevice) noexcept
{ {
perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING)].dummyPipelineLayout = logicalDevice->CreatePipelineLayoutDummy(SHPipelineLayoutParamsDummy{ perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING)].descSetLayouts }); for (int i = 0; i < SYSTEM_TYPE_COUNT; ++i)
perSystemData[SHUtilities::ConvertEnum(SystemType::TEXT_RENDERING)].dummyPipelineLayout = logicalDevice->CreatePipelineLayoutDummy(SHPipelineLayoutParamsDummy{ perSystemData[SHUtilities::ConvertEnum(SystemType::TEXT_RENDERING)].descSetLayouts }); {
perSystemData[SHUtilities::ConvertEnum(SystemType::RENDER_GRAPH_NODE_COMPUTE)].dummyPipelineLayout = logicalDevice->CreatePipelineLayoutDummy(SHPipelineLayoutParamsDummy{ perSystemData[SHUtilities::ConvertEnum(SystemType::RENDER_GRAPH_NODE_COMPUTE)].descSetLayouts }); perSystemData[i].dummyPipelineLayout = logicalDevice->CreatePipelineLayoutDummy
(
SHPipelineLayoutParamsDummy { perSystemData[i].descSetLayouts }
);
}
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -124,8 +134,8 @@ namespace SHADE
SHVkDescriptorSetLayout::Binding materialDataBinding SHVkDescriptorSetLayout::Binding materialDataBinding
{ {
.Type = vk::DescriptorType::eStorageBufferDynamic, .Type = vk::DescriptorType::eStorageBufferDynamic,
.Stage = vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eVertex, .Stage = vk::ShaderStageFlagBits::eFragment,
.BindPoint = SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA, .BindPoint = SHGraphicsConstants::DescriptorSetBindings::PER_INST_MATERIAL_DATA,
.DescriptorCount = 1, .DescriptorCount = 1,
}; };
Handle<SHVkDescriptorSetLayout> materialDataPerInstanceLayout = logicalDevice->CreateDescriptorSetLayout({ materialDataBinding }); Handle<SHVkDescriptorSetLayout> materialDataPerInstanceLayout = logicalDevice->CreateDescriptorSetLayout({ materialDataBinding });
@ -165,6 +175,17 @@ namespace SHADE
// For global data (generic data and textures) // For global data (generic data and textures)
Handle<SHVkDescriptorSetLayout> shadowMapDescLayout = logicalDevice->CreateDescriptorSetLayout({ shadowMapBinding }); Handle<SHVkDescriptorSetLayout> shadowMapDescLayout = logicalDevice->CreateDescriptorSetLayout({ shadowMapBinding });
SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, shadowMapDescLayout->GetVkHandle(), "[Descriptor Set Layout] Shadow Maps"); SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, shadowMapDescLayout->GetVkHandle(), "[Descriptor Set Layout] Shadow Maps");
// For per instance data (transforms, materials, etc.)
SHVkDescriptorSetLayout::Binding boneDataBinding
{
.Type = vk::DescriptorType::eStorageBufferDynamic,
.Stage = vk::ShaderStageFlagBits::eVertex,
.BindPoint = SHGraphicsConstants::DescriptorSetBindings::PER_INST_BONE_DATA,
.DescriptorCount = 1,
};
Handle<SHVkDescriptorSetLayout> materialBoneDataPerInstanceLayout = logicalDevice->CreateDescriptorSetLayout({ materialDataBinding, boneDataBinding });
SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, materialBoneDataPerInstanceLayout->GetVkHandle(), "[Descriptor Set Layout] Material and Bone Globals");
predefinedLayouts.push_back(staticGlobalLayout); predefinedLayouts.push_back(staticGlobalLayout);
predefinedLayouts.push_back(lightDataDescSetLayout); predefinedLayouts.push_back(lightDataDescSetLayout);
@ -172,6 +193,7 @@ namespace SHADE
predefinedLayouts.push_back(materialDataPerInstanceLayout); predefinedLayouts.push_back(materialDataPerInstanceLayout);
predefinedLayouts.push_back(fontDataDescSetLayout); predefinedLayouts.push_back(fontDataDescSetLayout);
predefinedLayouts.push_back(shadowMapDescLayout); predefinedLayouts.push_back(shadowMapDescLayout);
predefinedLayouts.push_back(materialBoneDataPerInstanceLayout);
perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING)].descSetLayouts = GetPredefinedDescSetLayouts perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING)].descSetLayouts = GetPredefinedDescSetLayouts
( (
@ -180,6 +202,13 @@ namespace SHADE
SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::MATERIALS SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::MATERIALS
); );
perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING_ANIM)].descSetLayouts = GetPredefinedDescSetLayouts
(
SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::STATIC_DATA |
SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::CAMERA |
SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::MATERIAL_AND_BONES
);
perSystemData[SHUtilities::ConvertEnum(SystemType::TEXT_RENDERING)].descSetLayouts = GetPredefinedDescSetLayouts perSystemData[SHUtilities::ConvertEnum(SystemType::TEXT_RENDERING)].descSetLayouts = GetPredefinedDescSetLayouts
( (
SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::STATIC_DATA | SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::STATIC_DATA |
@ -197,12 +226,15 @@ namespace SHADE
void SHGraphicsPredefinedData::InitPredefinedVertexInputState(void) noexcept void SHGraphicsPredefinedData::InitPredefinedVertexInputState(void) noexcept
{ {
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // positions at binding 0 defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Attribute positions at binding 0
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_2D) }); // UVs at binding 1 defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_2D) }); // Attribute UVs at binding 1
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Normals at binding 2 defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Attribute Normals at binding 2
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Tangents at binding 3 defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Attribute Tangents at binding 3
defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }); // Transform at binding 4 - 7 (4 slots) defaultVertexInputState.AddBinding(true , true , { SHVertexAttribute(SHAttribFormat::MAT_4D) }); // Instanced Transform at binding 4 - 7 (4 slots)
defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::UINT32_2D) }); // Instanced integer data at index 8 defaultVertexInputState.AddBinding(true , true , { SHVertexAttribute(SHAttribFormat::UINT32_2D) }); // Instanced integer data at index 8
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::UINT32_4D) }); // Attribute bone indices at index 9
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_4D) }); // Attribute bone weights at index 10
defaultVertexInputState.AddBinding(true , true , { SHVertexAttribute(SHAttribFormat::UINT32_1D) }); // Instance bone matrix first index at index 11
shadowMapVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D)}); shadowMapVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D)});
shadowMapVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }, 4, 4); // Transform at binding 4 - 7 (4 slots) shadowMapVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::MAT_4D) }, 4, 4); // Transform at binding 4 - 7 (4 slots)
@ -256,12 +288,24 @@ namespace SHADE
return static_cast<SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes>(static_cast<uint64_t>(lhs) | static_cast<uint64_t>(rhs)); return static_cast<SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes>(static_cast<uint64_t>(lhs) | static_cast<uint64_t>(rhs));
} }
SHADE::SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes& operator|=(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes& lhs, SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes rhs) noexcept
{
lhs = lhs | rhs;
return lhs;
}
SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes operator&(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes lhs, SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes rhs) noexcept SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes operator&(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes lhs, SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes rhs) noexcept
{ {
return static_cast<SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes>(static_cast<uint64_t>(lhs) & static_cast<uint64_t>(rhs)); return static_cast<SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes>(static_cast<uint64_t>(lhs) & static_cast<uint64_t>(rhs));
} }
SHADE::SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes& operator&=(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes& lhs, SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes rhs) noexcept
{
lhs = lhs & rhs;
return lhs;
}
//SHGraphicsPredefinedData::PerSystem const& SHGraphicsPredefinedData::GetBatchingSystemData(void) noexcept //SHGraphicsPredefinedData::PerSystem const& SHGraphicsPredefinedData::GetBatchingSystemData(void) noexcept
//{ //{
// return batchingSystemData; // return batchingSystemData;

View File

@ -23,21 +23,24 @@ namespace SHADE
// This enum is mainly to initialize a bit field to retrieve bit fields from SHPRedefinedData // This enum is mainly to initialize a bit field to retrieve bit fields from SHPRedefinedData
enum class PredefinedDescSetLayoutTypes : uint64_t enum class PredefinedDescSetLayoutTypes : uint64_t
{ {
STATIC_DATA = 0x01, STATIC_DATA = 0b00000001,
LIGHTS = 0x02, LIGHTS = 0b00000010,
CAMERA = 0x04, CAMERA = 0b00000100,
MATERIALS = 0x08, MATERIALS = 0b00001000,
FONT = 0x10, FONT = 0b00010000,
SHADOW = 0x20, SHADOW = 0b00100000,
MATERIAL_AND_BONES = 0b01000000
}; };
enum class SystemType enum class SystemType
{ {
BATCHING = 0, BATCHING = 0,
BATCHING_ANIM,
TEXT_RENDERING, TEXT_RENDERING,
RENDER_GRAPH_NODE_COMPUTE, RENDER_GRAPH_NODE_COMPUTE,
NUM_TYPES NUM_TYPES
}; };
static constexpr int SYSTEM_TYPE_COUNT = static_cast<int>(SystemType::NUM_TYPES);
struct PerSystem struct PerSystem
{ {
@ -103,5 +106,7 @@ namespace SHADE
}; };
SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes operator| (SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes lhs, SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes rhs) noexcept; SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes operator| (SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes lhs, SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes rhs) noexcept;
SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes& operator|=(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes& lhs, SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes rhs) noexcept;
SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes operator& (SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes lhs, SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes rhs) noexcept; SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes operator& (SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes lhs, SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes rhs) noexcept;
SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes& operator&=(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes& lhs, SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes rhs) noexcept;
} }

View File

@ -11,7 +11,8 @@ namespace SHADE
STATIC_DATA, STATIC_DATA,
LIGHTS, LIGHTS,
CAMERA, CAMERA,
MATERIALS, PER_INSTANCE_BATCH,
PER_INSTANCE_ANIM_BATCH,
FONT, FONT,
RENDER_GRAPH_NODE_COMPUTE_RESOURCE, RENDER_GRAPH_NODE_COMPUTE_RESOURCE,
RENDER_GRAPH_RESOURCE, RENDER_GRAPH_RESOURCE,

View File

@ -14,7 +14,7 @@ of DigiPen Institute of Technology is prohibited.
// STL Includes // STL Includes
#include <algorithm> #include <algorithm>
// Project Includes // Project Includes
#include "Assets/Asset Types/SHModelAsset.h" #include "Assets/Asset Types/Models/SHModelAsset.h"
#include "../Meshes/SHPrimitiveGenerator.h" #include "../Meshes/SHPrimitiveGenerator.h"
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "SHGraphicsSystem.h" #include "SHGraphicsSystem.h"

View File

@ -161,7 +161,15 @@ namespace SHADE
DescriptorSet binding for per instance material values. DescriptorSet binding for per instance material values.
*/ */
/***************************************************************************/ /***************************************************************************/
static constexpr uint32_t BATCHED_PER_INST_DATA = 0; static constexpr uint32_t PER_INST_MATERIAL_DATA = 0;
/***************************************************************************/
/*!
\brief
DescriptorSet binding for per instance bone values.
*/
/***************************************************************************/
static constexpr uint32_t PER_INST_BONE_DATA = 1;
/***************************************************************************/ /***************************************************************************/
/*! /*!
@ -191,6 +199,14 @@ namespace SHADE
static constexpr uint32_t SHADOW_MAP_IMAGE_SAMPLER_DATA = 0; static constexpr uint32_t SHADOW_MAP_IMAGE_SAMPLER_DATA = 0;
/***************************************************************************/
/*!
\brief
Descriptor set binding for bone matrix data.
*/
/***************************************************************************/
static constexpr uint32_t BONE_MATRIX_DATA = 1;
}; };
struct VertexBufferBindings struct VertexBufferBindings
@ -237,6 +253,27 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
static constexpr uint32_t INTEGER_DATA = 5; static constexpr uint32_t INTEGER_DATA = 5;
/***************************************************************************/
/*!
\brief
Vertex buffer bindings for the bone indices buffer.
*/
/***************************************************************************/
static constexpr uint32_t BONE_INDICES = 6;
/***************************************************************************/
/*!
\brief
Vertex buffer bindings for the bone weights buffer.
*/
/***************************************************************************/
static constexpr uint32_t BONE_WEIGHTS = 7;
/***************************************************************************/
/*!
\brief
Vertex buffer bindings for the bone matrix first index buffer.
*/
/***************************************************************************/
static constexpr uint32_t BONE_MATRIX_FIRST_INDEX = 8;
static constexpr uint32_t CALCULATED_GLYPH_POSITION = 0; static constexpr uint32_t CALCULATED_GLYPH_POSITION = 0;
static constexpr uint32_t GLYPH_INDEX = 1; static constexpr uint32_t GLYPH_INDEX = 1;

View File

@ -127,15 +127,16 @@ namespace SHADE
SHFreetypeInstance::Init(); SHFreetypeInstance::Init();
SHAssetManager::CompileAsset("../../Assets/Shaders/DeferredComposite_CS.glsl", false); //SHAssetManager::CompileAsset("../../Assets/Shaders/DeferredComposite_CS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/SSAO_CS.glsl", false); //SHAssetManager::CompileAsset("../../Assets/Shaders/SSAO_CS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/SSAOBlur_CS.glsl", false); //SHAssetManager::CompileAsset("../../Assets/Shaders/SSAOBlur_CS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/PureCopy_CS.glsl", false); //SHAssetManager::CompileAsset("../../Assets/Shaders/PureCopy_CS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_VS.glsl", false); //SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_VS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_FS.glsl", false); //SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_FS.glsl", false);
// Load Built In Shaders // Load Built In Shaders
static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEFAULT); static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEFAULT);
static constexpr AssetID VS_ANIM = 47911992; animtVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_ANIM);
static constexpr AssetID FS_DEFAULT = 46377769; defaultFragShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(FS_DEFAULT); static constexpr AssetID FS_DEFAULT = 46377769; defaultFragShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(FS_DEFAULT);
static constexpr AssetID VS_DEBUG = 48002439; debugVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEBUG); static constexpr AssetID VS_DEBUG = 48002439; debugVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEBUG);
static constexpr AssetID FS_DEBUG = 36671027; debugFragShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(FS_DEBUG); static constexpr AssetID FS_DEBUG = 36671027; debugFragShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(FS_DEBUG);
@ -450,6 +451,12 @@ namespace SHADE
renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write") renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write")
); );
defaultMaterial->SetProperty("data.textureIndex", defaultTexture->TextureArrayIndex); defaultMaterial->SetProperty("data.textureIndex", defaultTexture->TextureArrayIndex);
defaultAnimMaterial = AddMaterial
(
animtVertShader, defaultFragShader,
renderGraph->GetNode("G-Buffer")->GetSubpass("G-Buffer Write")
);
defaultAnimMaterial->SetProperty("data.textureIndex", defaultTexture->TextureArrayIndex);
} }
@ -525,6 +532,8 @@ namespace SHADE
std::make_pair(meshLibrary.GetVertexTexCoordsBuffer(), SHGraphicsConstants::VertexBufferBindings::TEX_COORD), std::make_pair(meshLibrary.GetVertexTexCoordsBuffer(), SHGraphicsConstants::VertexBufferBindings::TEX_COORD),
std::make_pair(meshLibrary.GetVertexNormalsBuffer(), SHGraphicsConstants::VertexBufferBindings::NORMAL), std::make_pair(meshLibrary.GetVertexNormalsBuffer(), SHGraphicsConstants::VertexBufferBindings::NORMAL),
std::make_pair(meshLibrary.GetVertexTangentsBuffer(), SHGraphicsConstants::VertexBufferBindings::TANGENT), std::make_pair(meshLibrary.GetVertexTangentsBuffer(), SHGraphicsConstants::VertexBufferBindings::TANGENT),
std::make_pair(meshLibrary.GetVertexBoneIndicesBuffer(), SHGraphicsConstants::VertexBufferBindings::BONE_INDICES),
std::make_pair(meshLibrary.GetVertexBoneWeightsBuffer(), SHGraphicsConstants::VertexBufferBindings::BONE_WEIGHTS),
std::make_pair(meshLibrary.GetIndexBuffer(), 0), std::make_pair(meshLibrary.GetIndexBuffer(), 0),
}; };
@ -568,14 +577,14 @@ namespace SHADE
#endif #endif
} }
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::B)) //if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::B))
{ //{
auto& lightComps = SHComponentManager::GetDense<SHLightComponent>(); // auto& lightComps = SHComponentManager::GetDense<SHLightComponent>();
for (auto& comp : lightComps) // for (auto& comp : lightComps)
{ // {
comp.SetEnableShadow(true); // comp.SetEnableShadow(true);
} // }
} //}
renderGraph->Begin(frameIndex); renderGraph->Begin(frameIndex);
auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex); auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex);
@ -800,7 +809,12 @@ namespace SHADE
rasterState.cull_mode = vk::CullModeFlagBits::eBack; rasterState.cull_mode = vk::CullModeFlagBits::eBack;
tempLibrary.Init(device); tempLibrary.Init(device);
tempLibrary.CreateGraphicsPipelines({ shadowMapVS, {} }, shadowMapNode->GetRenderpass(), newSubpass, SHGraphicsPredefinedData::GetShadowMapViState(), rasterState); tempLibrary.CreateGraphicsPipelines
(
{ shadowMapVS, {} }, shadowMapNode->GetRenderpass(), newSubpass,
SHGraphicsPredefinedData::SystemType::BATCHING,
SHGraphicsPredefinedData::GetShadowMapViState(), rasterState
);
shadowMapPipeline = tempLibrary.GetGraphicsPipeline({ shadowMapVS, {} }); shadowMapPipeline = tempLibrary.GetGraphicsPipeline({ shadowMapVS, {} });
} }
newSubpass->SetCompanionSubpass(companionSubpass, shadowMapPipeline); // set companion subpass and pipeline newSubpass->SetCompanionSubpass(companionSubpass, shadowMapPipeline); // set companion subpass and pipeline
@ -865,9 +879,9 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Mesh Registration Functions */ /* Mesh Registration Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHADE::Handle<SHADE::SHMesh> SHGraphicsSystem::AddMesh(uint32_t vertexCount, const SHMesh::VertexPosition* const positions, const SHMesh::VertexTexCoord* const texCoords, const SHMesh::VertexTangent* const tangents, const SHMesh::VertexNormal* const normals, uint32_t indexCount, const SHMesh::Index* const indices) SHADE::Handle<SHADE::SHMesh> SHGraphicsSystem::AddMesh(uint32_t vertexCount, const SHMesh::VertexPosition* const positions, const SHMesh::VertexTexCoord* const texCoords, const SHMesh::VertexTangent* const tangents, const SHMesh::VertexNormal* const normals, uint32_t indexCount, const SHMesh::Index* const indices, const SHMesh::VertexBoneIndices* const boneIndices, const SHMesh::VertexWeights* const boneWeights, uint32_t boneCount)
{ {
return meshLibrary.AddMesh(vertexCount, positions, texCoords, tangents, normals, indexCount, indices); return meshLibrary.AddMesh(vertexCount, positions, texCoords, tangents, normals, boneIndices, boneWeights, indexCount, indices, boneCount);
} }
void SHGraphicsSystem::RemoveMesh(Handle<SHMesh> mesh) void SHGraphicsSystem::RemoveMesh(Handle<SHMesh> mesh)

View File

@ -230,7 +230,7 @@ namespace SHADE
*/ */
/*******************************************************************************/ /*******************************************************************************/
Handle<SHMesh> AddMesh(uint32_t vertexCount, const SHMesh::VertexPosition* const positions, const SHMesh::VertexTexCoord* const texCoords, const SHMesh::VertexTangent* const tangents, const SHMesh::VertexNormal* const normals, uint32_t indexCount, const SHMesh::Index* const indices); Handle<SHMesh> AddMesh(uint32_t vertexCount, const SHMesh::VertexPosition* const positions, const SHMesh::VertexTexCoord* const texCoords, const SHMesh::VertexTangent* const tangents, const SHMesh::VertexNormal* const normals, uint32_t indexCount, const SHMesh::Index* const indices, const SHMesh::VertexBoneIndices* const boneIndices = nullptr, const SHMesh::VertexWeights* const boneWeights = nullptr, uint32_t boneCount = 0);
/*******************************************************************************/ /*******************************************************************************/
/*! /*!
@ -455,6 +455,7 @@ namespace SHADE
// Built-In Shaders // Built-In Shaders
Handle<SHVkShaderModule> defaultVertShader; Handle<SHVkShaderModule> defaultVertShader;
Handle<SHVkShaderModule> animtVertShader;
Handle<SHVkShaderModule> defaultFragShader; Handle<SHVkShaderModule> defaultFragShader;
Handle<SHVkShaderModule> debugVertShader; Handle<SHVkShaderModule> debugVertShader;
Handle<SHVkShaderModule> debugFragShader; Handle<SHVkShaderModule> debugFragShader;
@ -473,6 +474,7 @@ namespace SHADE
// Built-In Materials // Built-In Materials
Handle<SHMaterial> defaultMaterial; Handle<SHMaterial> defaultMaterial;
Handle<SHMaterial> defaultAnimMaterial;
Handle<SHVkPipeline> debugDrawPipeline; Handle<SHVkPipeline> debugDrawPipeline;
Handle<SHVkPipeline> debugDrawDepthPipeline; Handle<SHVkPipeline> debugDrawDepthPipeline;
Handle<SHVkPipeline> debugDrawLineMeshPipeline; Handle<SHVkPipeline> debugDrawLineMeshPipeline;

View File

@ -100,9 +100,9 @@ namespace SHADE
auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING); auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING);
return pipeline->GetPipelineLayout()->GetShaderBlockInterface return pipeline->GetPipelineLayout()->GetShaderBlockInterface
( (
mappings.at (SHPredefinedDescriptorTypes::MATERIALS), mappings.at (SHPredefinedDescriptorTypes::PER_INSTANCE_BATCH),
//SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, //SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA, SHGraphicsConstants::DescriptorSetBindings::PER_INST_MATERIAL_DATA,
vk::ShaderStageFlagBits::eFragment vk::ShaderStageFlagBits::eFragment
); );
} }

View File

@ -81,9 +81,9 @@ namespace SHADE
{ {
return baseMaterial->GetPipeline()->GetPipelineLayout()->GetShaderBlockInterface return baseMaterial->GetPipeline()->GetPipelineLayout()->GetShaderBlockInterface
( (
SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING).at(SHPredefinedDescriptorTypes::MATERIALS), SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING).at(SHPredefinedDescriptorTypes::PER_INSTANCE_BATCH),
//SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, //SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA, SHGraphicsConstants::DescriptorSetBindings::PER_INST_MATERIAL_DATA,
vk::ShaderStageFlagBits::eFragment vk::ShaderStageFlagBits::eFragment
); );
} }

View File

@ -3,7 +3,7 @@
\author Tng Kah Wei, kahwei.tng, 390009620 \author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu \par email: kahwei.tng\@digipen.edu
\date Aug 30, 2022 \date Aug 30, 2022
\brief Contains definitions for all of the functions of the classes that deal \brief Contains definitions for all of the functions of the classes that deal
with storage and management of vertex and index buffers of meshes. with storage and management of vertex and index buffers of meshes.
Copyright (C) 2022 DigiPen Institute of Technology. Copyright (C) 2022 DigiPen Institute of Technology.
@ -20,187 +20,252 @@ of DigiPen Institute of Technology is prohibited.
namespace SHADE namespace SHADE
{ {
SHADE::Handle<SHADE::SHMesh> SHMeshLibrary::AddMesh(uint32_t vertexCount, const SHMesh::VertexPosition* const positions, const SHMesh::VertexTexCoord* const texCoords, const SHMesh::VertexTangent* const tangents, const SHMesh::VertexNormal* const normals, uint32_t indexCount, const SHMesh::Index* const indices) SHADE::Handle<SHADE::SHMesh> SHMeshLibrary::AddMesh
{ (
isDirty = true; uint32_t vertexCount, const SHMesh::VertexPosition* const positions,
const SHMesh::VertexTexCoord* const texCoords,
const SHMesh::VertexTangent* const tangents,
const SHMesh::VertexNormal* const normals,
const SHMesh::VertexBoneIndices* const boneIndices,
const SHMesh::VertexWeights* const boneWeights,
uint32_t indexCount, const SHMesh::Index* const indices,
uint32_t boneCount)
{
isDirty = true;
auto handle = meshes.Create(); auto handle = meshes.Create();
meshAddJobs.emplace_back( MeshAddJob meshAddJobs.emplace_back(MeshAddJob
{
vertexCount,
positions,
texCoords,
tangents,
normals,
indexCount,
indices,
handle
});
return handle;
}
void SHMeshLibrary::RemoveMesh(Handle<SHMesh> mesh)
{ {
if (!mesh) vertexCount,
throw std::invalid_argument("Attempted to remove a Mesh that did not belong to the Mesh Library!"); positions,
texCoords,
meshRemoveJobs.emplace_back(mesh); tangents,
isDirty = true; normals,
boneIndices,
boneWeights,
indexCount,
indices,
boneCount,
handle
});
return handle;
}
void SHMeshLibrary::RemoveMesh(Handle<SHMesh> mesh)
{
if (!mesh)
throw std::invalid_argument("Attempted to remove a Mesh that did not belong to the Mesh Library!");
meshRemoveJobs.emplace_back(mesh);
isDirty = true;
}
void SHMeshLibrary::BuildBuffers(Handle<SHVkLogicalDevice> device, Handle<SHVkCommandBuffer> cmdBuffer)
{
// No changes
if (!isDirty)
return;
// Remove
if (!meshRemoveJobs.empty())
{
// - Remove from order list
for (const auto& meshToRemove : meshRemoveJobs)
{
auto searchResult = std::find(meshOrder.begin(), meshOrder.end(), meshToRemove);
// Shouldn't happen, ignore
if (searchResult == meshOrder.end())
continue;
// Remove from mesh list
meshOrder.erase(searchResult);
}
meshRemoveJobs.clear();
// - Shift existing elements in to close up the gaps
int32_t nextVertInsertPoint = 0;
uint32_t nextIdxInsertPoint = 0;
for (auto& mesh : meshOrder)
{
// Check if already in the correct place
if (nextVertInsertPoint != mesh->FirstVertex)
{
/* There's a gap, we need to shift */
// Vertices
vertPosStorage.erase(vertPosStorage.begin() + nextVertInsertPoint, vertPosStorage.begin() + mesh->FirstVertex);
vertTexCoordStorage.erase(vertTexCoordStorage.begin() + nextVertInsertPoint, vertTexCoordStorage.begin() + mesh->FirstVertex);
vertTangentStorage.erase(vertTangentStorage.begin() + nextVertInsertPoint, vertTangentStorage.begin() + mesh->FirstVertex);
vertNormalStorage.erase(vertNormalStorage.begin() + nextVertInsertPoint, vertNormalStorage.begin() + mesh->FirstVertex);
vertBoneIdxStorage.erase(vertBoneIdxStorage.begin() + nextVertInsertPoint, vertBoneIdxStorage.begin() + mesh->FirstVertex);
vertBoneWeightStorage.erase(vertBoneWeightStorage.begin() + nextVertInsertPoint, vertBoneWeightStorage.begin() + mesh->FirstVertex);
// - Update mesh data
mesh->FirstVertex = nextVertInsertPoint;
// Indices
indexStorage.erase(indexStorage.begin() + nextIdxInsertPoint, indexStorage.begin() + mesh->FirstIndex);
// - Update mesh data
mesh->FirstIndex = nextIdxInsertPoint;
// Prepare for next
nextVertInsertPoint += mesh->VertexCount;
nextIdxInsertPoint += mesh->IndexCount;
}
}
} }
void SHMeshLibrary::BuildBuffers(Handle<SHVkLogicalDevice> device, Handle<SHVkCommandBuffer> cmdBuffer) // Add
if (!meshAddJobs.empty())
{ {
// No changes // - Compute updated size
if (!isDirty) size_t newVertElems = vertPosStorage.size();
return; size_t newIdxElems = indexStorage.size();
for (const auto& addJob : meshAddJobs)
// Remove {
if (!meshRemoveJobs.empty()) newVertElems += addJob.VertexCount;
newIdxElems += addJob.IndexCount;
}
// - Reserve new memory
vertPosStorage.reserve(newVertElems);
vertTexCoordStorage.reserve(newVertElems);
vertTangentStorage.reserve(newVertElems);
vertNormalStorage.reserve(newVertElems);
vertBoneIdxStorage.reserve(newVertElems);
vertBoneWeightStorage.reserve(newVertElems);
indexStorage.reserve(newIdxElems);
// - Append new data
for (auto& addJob : meshAddJobs)
{
// Update handle
SHMesh& meshData = *addJob.Handle;
meshData = SHMesh
{ {
// - Remove from order list .FirstVertex = static_cast<int32_t>(vertPosStorage.size()),
for (const auto& meshToRemove : meshRemoveJobs) .VertexCount = static_cast<uint32_t>(addJob.VertexCount),
{ .FirstIndex = static_cast<uint32_t>(indexStorage.size()),
auto searchResult = std::find(meshOrder.begin(), meshOrder.end(), meshToRemove); .IndexCount = static_cast<uint32_t>(addJob.IndexCount),
// Shouldn't happen, ignore .BoneCount = addJob.BoneCount
if (searchResult == meshOrder.end()) };
continue;
// Remove from mesh list // Copy into storage
meshOrder.erase(searchResult); vertPosStorage.insert
} (
meshRemoveJobs.clear(); vertPosStorage.end(),
// - Shift existing elements in to close up the gaps addJob.VertexPositions, addJob.VertexPositions + addJob.VertexCount
int32_t nextVertInsertPoint = 0; );
uint32_t nextIdxInsertPoint = 0; vertTexCoordStorage.insert
for (auto& mesh : meshOrder) (
{ vertTexCoordStorage.end(),
// Check if already in the correct place addJob.VertexTexCoords, addJob.VertexTexCoords + addJob.VertexCount
if (nextVertInsertPoint != mesh->FirstVertex) );
{ vertTangentStorage.insert
/* There's a gap, we need to shift */ (
// Vertices vertTangentStorage.end(),
vertPosStorage.erase(vertPosStorage.begin() + nextVertInsertPoint, vertPosStorage.begin() + mesh->FirstVertex); addJob.VertexTangents, addJob.VertexTangents + addJob.VertexCount
vertTexCoordStorage.erase(vertTexCoordStorage.begin() + nextVertInsertPoint, vertTexCoordStorage.begin() + mesh->FirstVertex); );
vertTangentStorage.erase(vertTangentStorage.begin() + nextVertInsertPoint, vertTangentStorage.begin() + mesh->FirstVertex); vertNormalStorage.insert
vertNormalStorage.erase(vertNormalStorage.begin() + nextVertInsertPoint, vertNormalStorage.begin() + mesh->FirstVertex); (
// - Update mesh data vertNormalStorage.end(),
mesh->FirstVertex = nextVertInsertPoint; addJob.VertexNormals, addJob.VertexNormals + addJob.VertexCount
);
// Indices if (addJob.VertexBoneIndices)
indexStorage.erase(indexStorage.begin() + nextIdxInsertPoint, indexStorage.begin() + mesh->FirstIndex);
// - Update mesh data
mesh->FirstIndex = nextIdxInsertPoint;
// Prepare for next
nextVertInsertPoint += mesh->VertexCount;
nextIdxInsertPoint += mesh->IndexCount;
}
}
}
// Add
if (!meshAddJobs.empty())
{ {
// - Compute updated size vertBoneIdxStorage.insert
size_t newVertElems = vertPosStorage.size(); (
size_t newIdxElems = indexStorage.size(); vertBoneIdxStorage.end(),
for (const auto& addJob : meshAddJobs) addJob.VertexBoneIndices, addJob.VertexBoneIndices + addJob.VertexCount
{ );
newVertElems += addJob.VertexCount;
newIdxElems += addJob.IndexCount;
}
// - Reserve new memory
vertPosStorage .reserve(newVertElems);
vertTexCoordStorage.reserve(newVertElems);
vertTangentStorage .reserve(newVertElems);
vertNormalStorage .reserve(newVertElems);
indexStorage .reserve(newIdxElems);
// - Append new data
for (auto& addJob : meshAddJobs)
{
// Update handle
SHMesh& meshData = *addJob.Handle;
meshData = SHMesh
{
.FirstVertex = static_cast<int32_t>(vertPosStorage.size()),
.VertexCount = static_cast<uint32_t>(addJob.VertexCount),
.FirstIndex = static_cast<uint32_t>(indexStorage.size()),
.IndexCount = static_cast<uint32_t>(addJob.IndexCount),
};
// Copy into storage
vertPosStorage.insert
(
vertPosStorage.end(),
addJob.VertexPositions, addJob.VertexPositions + addJob.VertexCount
);
vertTexCoordStorage.insert
(
vertTexCoordStorage.end(),
addJob.VertexTexCoords, addJob.VertexTexCoords + addJob.VertexCount
);
vertTangentStorage.insert
(
vertTangentStorage.end(),
addJob.VertexTangents, addJob.VertexTangents + addJob.VertexCount
);
vertNormalStorage.insert
(
vertNormalStorage.end(),
addJob.VertexNormals, addJob.VertexNormals + addJob.VertexCount
);
indexStorage.insert
(
indexStorage.end(),
addJob.Indices, addJob.Indices + addJob.IndexCount
);
}
meshAddJobs.clear();
} }
else
// Send to GPU {
using BuffUsage = vk::BufferUsageFlagBits; vertBoneIdxStorage.resize(vertBoneIdxStorage.size() + addJob.VertexCount);
SHVkUtil::EnsureBufferAndCopyData }
( if (addJob.VertexBoneWeights)
device, cmdBuffer, vertPosBuffer, {
vertPosStorage.data(), vertBoneWeightStorage.insert
static_cast<uint32_t>(vertPosStorage.size()) * sizeof(SHMesh::VertexPosition), (
BuffUsage::eVertexBuffer, vertBoneWeightStorage.end(),
"Mesh Library Vertex Positions" addJob.VertexBoneWeights, addJob.VertexBoneWeights + addJob.VertexCount
); );
SHVkUtil::EnsureBufferAndCopyData }
( else
device, cmdBuffer, vertTexCoordBuffer, {
vertTexCoordStorage.data(), const auto OG_SIZE = vertBoneWeightStorage.size();
static_cast<uint32_t>(vertTexCoordStorage.size()) * sizeof(SHMesh::VertexTexCoord), vertBoneWeightStorage.resize(vertBoneWeightStorage.size() + addJob.VertexCount);
BuffUsage::eVertexBuffer, std::fill_n(vertBoneWeightStorage.begin() + OG_SIZE, addJob.VertexCount, SHVec4(1.0f, 0.0f, 0.0f, 0.0f));
"Mesh Library Vertex TexCoords" }
); indexStorage.insert
SHVkUtil::EnsureBufferAndCopyData (
( indexStorage.end(),
device, cmdBuffer, vertTangentBuffer, addJob.Indices, addJob.Indices + addJob.IndexCount
vertTangentStorage.data(), );
static_cast<uint32_t>(vertTangentStorage.size()) * sizeof(SHMesh::VertexTangent), }
BuffUsage::eVertexBuffer, meshAddJobs.clear();
"Mesh Library Vertex Tangents"
);
SHVkUtil::EnsureBufferAndCopyData
(
device, cmdBuffer, vertNormalBuffer,
vertNormalStorage.data(),
static_cast<uint32_t>(vertNormalStorage.size()) * sizeof(SHMesh::VertexNormal),
BuffUsage::eVertexBuffer,
"Mesh Library Vertex Normals"
);
SHVkUtil::EnsureBufferAndCopyData
(
device, cmdBuffer, indexBuffer,
indexStorage.data(),
static_cast<uint32_t>(indexStorage.size()) * sizeof(SHMesh::Index),
BuffUsage::eIndexBuffer,
"Mesh Library Indices"
);
isDirty = false;
} }
// Send to GPU
using BuffUsage = vk::BufferUsageFlagBits;
SHVkUtil::EnsureBufferAndCopyData
(
device, cmdBuffer, vertPosBuffer,
vertPosStorage.data(),
static_cast<uint32_t>(vertPosStorage.size()) * sizeof(SHMesh::VertexPosition),
BuffUsage::eVertexBuffer,
"Mesh Library Vertex Positions"
);
SHVkUtil::EnsureBufferAndCopyData
(
device, cmdBuffer, vertTexCoordBuffer,
vertTexCoordStorage.data(),
static_cast<uint32_t>(vertTexCoordStorage.size()) * sizeof(SHMesh::VertexTexCoord),
BuffUsage::eVertexBuffer,
"Mesh Library Vertex TexCoords"
);
SHVkUtil::EnsureBufferAndCopyData
(
device, cmdBuffer, vertTangentBuffer,
vertTangentStorage.data(),
static_cast<uint32_t>(vertTangentStorage.size()) * sizeof(SHMesh::VertexTangent),
BuffUsage::eVertexBuffer,
"Mesh Library Vertex Tangents"
);
SHVkUtil::EnsureBufferAndCopyData
(
device, cmdBuffer, vertNormalBuffer,
vertNormalStorage.data(),
static_cast<uint32_t>(vertNormalStorage.size()) * sizeof(SHMesh::VertexNormal),
BuffUsage::eVertexBuffer,
"Mesh Library Vertex Normals"
);
if (!vertBoneIdxStorage.empty())
{
SHVkUtil::EnsureBufferAndCopyData
(
device, cmdBuffer, vertBoneIdxBuffer,
vertBoneIdxStorage.data(),
static_cast<uint32_t>(vertBoneIdxStorage.size()) * sizeof(SHMesh::VertexBoneIndices),
BuffUsage::eVertexBuffer,
"Mesh Library Vertex Bone Indices"
);
}
if (!vertBoneWeightStorage.empty())
{
SHVkUtil::EnsureBufferAndCopyData
(
device, cmdBuffer, vertBoneWeightBuffer,
vertBoneWeightStorage.data(),
static_cast<uint32_t>(vertBoneWeightStorage.size()) * sizeof(SHMesh::VertexWeights),
BuffUsage::eVertexBuffer,
"Mesh Library Vertex Bone Weights"
);
}
SHVkUtil::EnsureBufferAndCopyData
(
device, cmdBuffer, indexBuffer,
indexStorage.data(),
static_cast<uint32_t>(indexStorage.size()) * sizeof(SHMesh::Index),
BuffUsage::eIndexBuffer,
"Mesh Library Indices"
);
isDirty = false;
}
} }

View File

@ -19,170 +19,191 @@ of DigiPen Institute of Technology is prohibited.
#include "Resource/SHResourceLibrary.h" #include "Resource/SHResourceLibrary.h"
#include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec2.h"
#include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec3.h"
#include "Math/Vector/SHVec4.h"
#include "Math/Vector/SHVec4U.h"
namespace SHADE namespace SHADE
{ {
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Forward Declarations */ /* Forward Declarations */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
class SHVkBuffer; class SHVkBuffer;
class SHVkLogicalDevice; class SHVkLogicalDevice;
class SHVkCommandBuffer; class SHVkCommandBuffer;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/***********************************************************************************/ /***********************************************************************************/
/*!
\brief
Represents a single mesh that is stored in a SHMeshLibrary.
*/
/***********************************************************************************/
class SHMesh
{
public:
/*-----------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------*/
using Index = uint32_t;
using VertexPosition = SHVec3;
using VertexTexCoord = SHVec2;
using VertexTangent = SHVec3;
using VertexNormal = SHVec3;
using VertexBoneIndices = SHVec4U;
using VertexWeights = SHVec4;
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
int32_t FirstVertex;
uint32_t VertexCount;
uint32_t FirstIndex;
uint32_t IndexCount;
uint32_t BoneCount;
};
/***********************************************************************************/
/*!
\brief
Manages storage for all Meshes in the Graphics System as a single set of Vertex
and Index Buffers.
*/
/***********************************************************************************/
class SHMeshLibrary
{
public:
/*-----------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------*/
/*******************************************************************************/
/*! /*!
\brief
Represents a single mesh that is stored in a SHMeshLibrary.
*/
/***********************************************************************************/
class SHMesh
{
public:
/*-----------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------*/
using Index = uint32_t;
using VertexPosition = SHVec3;
using VertexTexCoord = SHVec2;
using VertexTangent = SHVec3;
using VertexNormal = SHVec3;
/*-----------------------------------------------------------------------------*/ \brief
/* Data Members */ Adds a mesh to the Mesh Library. But this does not mean that the meshes have
/*-----------------------------------------------------------------------------*/ been added yet. A call to "BuildBuffers()" is required to transfer all
int32_t FirstVertex; meshes into the GPU.
uint32_t VertexCount;
uint32_t FirstIndex; \param vertexCount
uint32_t IndexCount; Number of vertices in this Mesh.
}; \param positions
/***********************************************************************************/ Pointer to the first in a contiguous array of SHMathVec3s that define vertex
positions.
\param texCoords
Pointer to the first in a contiguous array of SHMathVec2s that define vertex
texture coordinates.
\param tangents
Pointer to the first in a contiguous array of SHMathVec3s that define vertex
tangents.
\param normals
Pointer to the first in a contiguous array of SHMathVec3s that define vertex
normals.
\param indexCount
Number of indices in this mesh.
\param indices
Pointer to the first in a contiguous array of uint32_ts that define mesh
indicies.
\return
Handle to the created Mesh. This is not valid to be used until a call to
BuildBuffers().
*/
/*******************************************************************************/
Handle<SHMesh> AddMesh(uint32_t vertexCount, const SHMesh::VertexPosition* const positions,
const SHMesh::VertexTexCoord* const texCoords,
const SHMesh::VertexTangent* const tangents,
const SHMesh::VertexNormal* const normals,
const SHMesh::VertexBoneIndices* const boneIndices,
const SHMesh::VertexWeights* const boneWeights,
uint32_t indexCount, const SHMesh::Index* const indices,
uint32_t boneCount);
/*******************************************************************************/
/*! /*!
\brief
Manages storage for all Meshes in the Graphics System as a single set of Vertex \brief
and Index Buffers. Removes a mesh from the MeshLibrary. But this does not mean that the meshes
have been removed yet. A call to "BuildBuffers()" is required to finalise all
changes.
\param mesh
Handle to the mesh to remove.
*/ */
/***********************************************************************************/ /*******************************************************************************/
class SHMeshLibrary void RemoveMesh(Handle<SHMesh> mesh);
/***************************************************************************/
/*!
\brief
Finalises all changes to the MeshLibrary into the GPU buffers.
\param device
Device used to create and update the buffers.
\param cmdBuffer
Command buffer used to set up transfers of data in the GPU memory. This
call must be preceded by calls to cmdBuffer's BeginRecording() and ended
with EndRecording(). Do recall to also submit the cmdBuffer to a transfer
queue.
*/
/***************************************************************************/
void BuildBuffers(Handle<SHVkLogicalDevice> device, Handle<SHVkCommandBuffer> cmdBuffer);
/*-----------------------------------------------------------------------------*/
/* Getter Functions */
/*-----------------------------------------------------------------------------*/
Handle<SHVkBuffer> GetVertexPositionsBuffer() const noexcept { return vertPosBuffer; }
Handle<SHVkBuffer> GetVertexTexCoordsBuffer() const noexcept { return vertTexCoordBuffer; }
Handle<SHVkBuffer> GetVertexTangentsBuffer() const noexcept { return vertTangentBuffer; }
Handle<SHVkBuffer> GetVertexNormalsBuffer() const noexcept { return vertNormalBuffer; }
Handle<SHVkBuffer> GetVertexBoneIndicesBuffer() const noexcept { return vertBoneIdxBuffer; }
Handle<SHVkBuffer> GetVertexBoneWeightsBuffer() const noexcept { return vertBoneWeightBuffer; }
Handle<SHVkBuffer> GetIndexBuffer() const noexcept { return indexBuffer; }
private:
/*-----------------------------------------------------------------------------*/
/* Type Definition */
/*-----------------------------------------------------------------------------*/
struct MeshAddJob
{ {
public: uint32_t VertexCount = 0;
/*-----------------------------------------------------------------------------*/ const SHMesh::VertexPosition* VertexPositions = nullptr;
/* Usage Functions */ const SHMesh::VertexTexCoord* VertexTexCoords = nullptr;
/*-----------------------------------------------------------------------------*/ const SHMesh::VertexTangent* VertexTangents = nullptr;
/*******************************************************************************/ const SHMesh::VertexNormal* VertexNormals = nullptr;
/*! const SHMesh::VertexBoneIndices* VertexBoneIndices = nullptr;
const SHMesh::VertexWeights* VertexBoneWeights = nullptr;
\brief uint32_t IndexCount = 0;
Adds a mesh to the Mesh Library. But this does not mean that the meshes have const SHMesh::Index* Indices = nullptr;
been added yet. A call to "BuildBuffers()" is required to transfer all uint32_t BoneCount = 0;
meshes into the GPU. Handle<SHMesh> Handle;
\param vertexCount
Number of vertices in this Mesh.
\param positions
Pointer to the first in a contiguous array of SHMathVec3s that define vertex
positions.
\param texCoords
Pointer to the first in a contiguous array of SHMathVec2s that define vertex
texture coordinates.
\param tangents
Pointer to the first in a contiguous array of SHMathVec3s that define vertex
tangents.
\param normals
Pointer to the first in a contiguous array of SHMathVec3s that define vertex
normals.
\param indexCount
Number of indices in this mesh.
\param indices
Pointer to the first in a contiguous array of uint32_ts that define mesh
indicies.
\return
Handle to the created Mesh. This is not valid to be used until a call to
BuildBuffers().
*/
/*******************************************************************************/
Handle<SHMesh> AddMesh(uint32_t vertexCount, const SHMesh::VertexPosition* const positions, const SHMesh::VertexTexCoord* const texCoords, const SHMesh::VertexTangent* const tangents, const SHMesh::VertexNormal* const normals, uint32_t indexCount, const SHMesh::Index* const indices);
/*******************************************************************************/
/*!
\brief
Removes a mesh from the MeshLibrary. But this does not mean that the meshes
have been removed yet. A call to "BuildBuffers()" is required to finalise all
changes.
\param mesh
Handle to the mesh to remove.
*/
/*******************************************************************************/
void RemoveMesh(Handle<SHMesh> mesh);
/***************************************************************************/
/*!
\brief
Finalises all changes to the MeshLibrary into the GPU buffers.
\param device
Device used to create and update the buffers.
\param cmdBuffer
Command buffer used to set up transfers of data in the GPU memory. This
call must be preceded by calls to cmdBuffer's BeginRecording() and ended
with EndRecording(). Do recall to also submit the cmdBuffer to a transfer
queue.
*/
/***************************************************************************/
void BuildBuffers(Handle<SHVkLogicalDevice> device, Handle<SHVkCommandBuffer> cmdBuffer);
/*-----------------------------------------------------------------------------*/
/* Getter Functions */
/*-----------------------------------------------------------------------------*/
Handle<SHVkBuffer> GetVertexPositionsBuffer() const noexcept { return vertPosBuffer; }
Handle<SHVkBuffer> GetVertexTexCoordsBuffer() const noexcept { return vertTexCoordBuffer; }
Handle<SHVkBuffer> GetVertexTangentsBuffer() const noexcept { return vertTangentBuffer; }
Handle<SHVkBuffer> GetVertexNormalsBuffer() const noexcept { return vertNormalBuffer; }
Handle<SHVkBuffer> GetIndexBuffer() const { return indexBuffer; }
private:
/*-----------------------------------------------------------------------------*/
/* Type Definition */
/*-----------------------------------------------------------------------------*/
struct MeshAddJob
{
uint32_t VertexCount = 0;
const SHMesh::VertexPosition* VertexPositions = nullptr;
const SHMesh::VertexTexCoord* VertexTexCoords = nullptr;
const SHMesh::VertexTangent * VertexTangents = nullptr;
const SHMesh::VertexNormal * VertexNormals = nullptr;
uint32_t IndexCount = 0;
const SHMesh::Index * Indices = nullptr;
Handle<SHMesh> Handle;
};
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
// Manipulation Queues
std::vector<MeshAddJob> meshAddJobs;
std::vector<Handle<SHMesh>> meshRemoveJobs;
// Tracking
SHResourceLibrary<SHMesh> meshes{};
std::vector<Handle<SHMesh>> meshOrder;
// CPU Storage
std::vector<SHMesh::VertexPosition> vertPosStorage;
std::vector<SHMesh::VertexTexCoord> vertTexCoordStorage;
std::vector<SHMesh::VertexTangent> vertTangentStorage;
std::vector<SHMesh::VertexNormal> vertNormalStorage;
std::vector<SHMesh::Index> indexStorage;
// GPU Storage
Handle<SHVkBuffer> vertPosBuffer{};
Handle<SHVkBuffer> vertTexCoordBuffer{};
Handle<SHVkBuffer> vertTangentBuffer{};
Handle<SHVkBuffer> vertNormalBuffer{};
Handle<SHVkBuffer> indexBuffer {};
// Flags
bool isDirty = true;
}; };
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
// Manipulation Queues
std::vector<MeshAddJob> meshAddJobs;
std::vector<Handle<SHMesh>> meshRemoveJobs;
// Tracking
SHResourceLibrary<SHMesh> meshes;
std::vector<Handle<SHMesh>> meshOrder;
// CPU Storage
std::vector<SHMesh::VertexPosition> vertPosStorage;
std::vector<SHMesh::VertexTexCoord> vertTexCoordStorage;
std::vector<SHMesh::VertexTangent> vertTangentStorage;
std::vector<SHMesh::VertexNormal> vertNormalStorage;
std::vector<SHMesh::VertexBoneIndices> vertBoneIdxStorage; // Must be in multiples of 4
std::vector<SHMesh::VertexWeights> vertBoneWeightStorage;
std::vector<SHMesh::Index> indexStorage;
// GPU Storage
Handle<SHVkBuffer> vertPosBuffer{};
Handle<SHVkBuffer> vertTexCoordBuffer{};
Handle<SHVkBuffer> vertTangentBuffer{};
Handle<SHVkBuffer> vertNormalBuffer{};
Handle<SHVkBuffer> vertBoneIdxBuffer{};
Handle<SHVkBuffer> vertBoneWeightBuffer{};
Handle<SHVkBuffer> indexBuffer{};
// Flags
bool isDirty = true;
};
} }

View File

@ -25,18 +25,18 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Static Member Definitions */ /* Static Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHMeshData SHPrimitiveGenerator::cubeMesh; SHMeshAsset SHPrimitiveGenerator::cubeMesh;
SHMeshData SHPrimitiveGenerator::sphereMesh; SHMeshAsset SHPrimitiveGenerator::sphereMesh;
SHMeshData SHPrimitiveGenerator::lineCubeMesh; SHMeshAsset SHPrimitiveGenerator::lineCubeMesh;
SHMeshData SHPrimitiveGenerator::lineCircleMesh; SHMeshAsset SHPrimitiveGenerator::lineCircleMesh;
SHMeshData SHPrimitiveGenerator::lineCapsuleCapMesh; SHMeshAsset SHPrimitiveGenerator::lineCapsuleCapMesh;
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Primitive Generation Functions */ /* Primitive Generation Functions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHMeshData SHPrimitiveGenerator::Cube() noexcept SHMeshAsset SHPrimitiveGenerator::Cube() noexcept
{ {
SHMeshData mesh; SHMeshAsset mesh;
mesh.VertexPositions = mesh.VertexPositions =
{ {
@ -221,9 +221,9 @@ namespace SHADE
return addMeshDataTo(cubeMesh, gfxSystem); return addMeshDataTo(cubeMesh, gfxSystem);
} }
SHMeshData SHPrimitiveGenerator::Sphere() noexcept SHMeshAsset SHPrimitiveGenerator::Sphere() noexcept
{ {
SHMeshData meshData; SHMeshAsset meshData;
const int LAT_SLICES = 12; const int LAT_SLICES = 12;
const int LONG_SLICES = 12; const int LONG_SLICES = 12;
@ -288,9 +288,9 @@ namespace SHADE
return addMeshDataTo(sphereMesh, gfxSystem); return addMeshDataTo(sphereMesh, gfxSystem);
} }
SHMeshData SHPrimitiveGenerator::LineCube() noexcept SHMeshAsset SHPrimitiveGenerator::LineCube() noexcept
{ {
SHMeshData mesh; SHMeshAsset mesh;
mesh.VertexPositions = mesh.VertexPositions =
{ {
@ -347,9 +347,9 @@ namespace SHADE
return addMeshDataTo(lineCubeMesh, gfxSystem); return addMeshDataTo(lineCubeMesh, gfxSystem);
} }
SHMeshData SHPrimitiveGenerator::LineCircle() noexcept SHMeshAsset SHPrimitiveGenerator::LineCircle() noexcept
{ {
SHMeshData mesh; SHMeshAsset mesh;
// Generate points of the circle // Generate points of the circle
static constexpr int SPLITS = 36; static constexpr int SPLITS = 36;
@ -393,9 +393,9 @@ namespace SHADE
return addMeshDataTo(lineCircleMesh, gfxSystem); return addMeshDataTo(lineCircleMesh, gfxSystem);
} }
SHADE::SHMeshData SHPrimitiveGenerator::LineCapsuleCap() noexcept SHMeshAsset SHPrimitiveGenerator::LineCapsuleCap() noexcept
{ {
SHMeshData mesh; SHMeshAsset mesh;
// Have multiple semi-circles for the cap // Have multiple semi-circles for the cap
static constexpr int SPLITS = 36; static constexpr int SPLITS = 36;
@ -454,7 +454,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Helper Functions */ /* Helper Functions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHADE::Handle<SHADE::SHMesh> SHPrimitiveGenerator::addMeshDataTo(const SHMeshData& meshData, SHMeshLibrary& meshLibrary) noexcept SHADE::Handle<SHADE::SHMesh> SHPrimitiveGenerator::addMeshDataTo(const SHMeshAsset& meshData, SHMeshLibrary& meshLibrary) noexcept
{ {
return meshLibrary.AddMesh return meshLibrary.AddMesh
( (
@ -463,12 +463,15 @@ namespace SHADE
meshData.VertexTexCoords.data(), meshData.VertexTexCoords.data(),
meshData.VertexTangents.data(), meshData.VertexTangents.data(),
meshData.VertexNormals.data(), meshData.VertexNormals.data(),
nullptr,
nullptr,
static_cast<uint32_t>(meshData.Indices.size()), static_cast<uint32_t>(meshData.Indices.size()),
meshData.Indices.data() meshData.Indices.data(),
0
); );
} }
SHADE::Handle<SHADE::SHMesh> SHPrimitiveGenerator::addMeshDataTo(const SHMeshData& meshData, SHGraphicsSystem& gfxSystem) noexcept SHADE::Handle<SHADE::SHMesh> SHPrimitiveGenerator::addMeshDataTo(const SHMeshAsset& meshData, SHGraphicsSystem& gfxSystem) noexcept
{ {
return gfxSystem.AddMesh return gfxSystem.AddMesh
( (

View File

@ -12,10 +12,11 @@ of DigiPen Institute of Technology is prohibited.
#pragma once #pragma once
// Project Includes // Project Includes
#include "Math/SHMath.h"
#include "Assets/Asset Types/SHModelAsset.h"
#include "Graphics/MiddleEnd/Interface/SHMeshLibrary.h"
#include "SH_API.h" #include "SH_API.h"
#include "Math/SHMath.h"
#include "Assets/Asset Types/Models/SHModelAsset.h"
#include "Assets/Asset Types/Models/SHMeshAsset.h"
#include "Graphics/MiddleEnd/Interface/SHMeshLibrary.h"
namespace SHADE namespace SHADE
{ {
@ -47,13 +48,13 @@ namespace SHADE
/***********************************************************************************/ /***********************************************************************************/
/*! /*!
\brief \brief
Produces a cube and stores the data in a SHMeshData object. Produces a cube and stores the data in a SHMeshAsset object.
\return \return
SHMeshData object containing vertex data for the cube. SHMeshAsset object containing vertex data for the cube.
*/ */
/***********************************************************************************/ /***********************************************************************************/
[[nodiscard]] static SHMeshData Cube() noexcept; [[nodiscard]] static SHMeshAsset Cube() noexcept;
/***********************************************************************************/ /***********************************************************************************/
/*! /*!
\brief \brief
@ -83,13 +84,13 @@ namespace SHADE
/***********************************************************************************/ /***********************************************************************************/
/*! /*!
\brief \brief
Produces a sphere and stores the data in a SHMeshData object. Produces a sphere and stores the data in a SHMeshAsset object.
\return \return
SHMeshData object containing vertex data for the sphere. SHMeshAsset object containing vertex data for the sphere.
*/ */
/***********************************************************************************/ /***********************************************************************************/
[[nodiscard]] static SHMeshData Sphere() noexcept; [[nodiscard]] static SHMeshAsset Sphere() noexcept;
/***********************************************************************************/ /***********************************************************************************/
/*! /*!
\brief \brief
@ -120,13 +121,13 @@ namespace SHADE
/*! /*!
\brief \brief
Produces a cube that is comprised only of lines with no diagonal lines and store Produces a cube that is comprised only of lines with no diagonal lines and store
the data in a SHMeshData object. the data in a SHMeshAsset object.
\return \return
SHMeshData object containing vertex data for the line cube. SHMeshAsset object containing vertex data for the line cube.
*/ */
/***********************************************************************************/ /***********************************************************************************/
[[nodiscard]] static SHMeshData LineCube() noexcept; [[nodiscard]] static SHMeshAsset LineCube() noexcept;
/***********************************************************************************/ /***********************************************************************************/
/*! /*!
\brief \brief
@ -158,13 +159,13 @@ namespace SHADE
/*! /*!
\brief \brief
Produces a circle that is comprised only of lines with no diagonal lines and Produces a circle that is comprised only of lines with no diagonal lines and
store the data in a SHMeshData object. store the data in a SHMeshAsset object.
\return \return
SHMeshData object containing vertex data for the line circle. SHMeshAsset object containing vertex data for the line circle.
*/ */
/***********************************************************************************/ /***********************************************************************************/
[[nodiscard]] static SHMeshData LineCircle() noexcept; [[nodiscard]] static SHMeshAsset LineCircle() noexcept;
/***********************************************************************************/ /***********************************************************************************/
/*! /*!
\brief \brief
@ -204,7 +205,7 @@ namespace SHADE
SHMeshData object containing vertex data for the line circle. SHMeshData object containing vertex data for the line circle.
*/ */
/***********************************************************************************/ /***********************************************************************************/
[[nodiscard]] static SHMeshData LineCapsuleCap() noexcept; [[nodiscard]] static SHMeshAsset LineCapsuleCap() noexcept;
/***********************************************************************************/ /***********************************************************************************/
/*! /*!
\brief \brief
@ -239,16 +240,16 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Helper Functions */ /* Helper Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
static Handle<SHMesh> addMeshDataTo(const SHMeshData& meshData, SHMeshLibrary& meshLibrary) noexcept; static Handle<SHMesh> addMeshDataTo(const SHMeshAsset& meshData, SHMeshLibrary& meshLibrary) noexcept;
static Handle<SHMesh> addMeshDataTo(const SHMeshData& meshData, SHGraphicsSystem& gfxSystem) noexcept; static Handle<SHMesh> addMeshDataTo(const SHMeshAsset& meshData, SHGraphicsSystem& gfxSystem) noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
static SHMeshData cubeMesh; static SHMeshAsset cubeMesh;
static SHMeshData sphereMesh; static SHMeshAsset sphereMesh;
static SHMeshData lineCubeMesh; static SHMeshAsset lineCubeMesh;
static SHMeshData lineCircleMesh; static SHMeshAsset lineCircleMesh;
static SHMeshData lineCapsuleCapMesh; static SHMeshAsset lineCapsuleCapMesh;
}; };
} }

View File

@ -7,7 +7,7 @@
namespace SHADE namespace SHADE
{ {
Handle<SHVkPipeline> SHPipelineLibrary::CreateGraphicsPipelines(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHVkRenderpass> renderpass, Handle<SHSubpass> subpass, SHVertexInputState const& viState/* = SHGraphicsPredefinedData::GetDefaultViState()*/, SHRasterizationState const& rasterState) noexcept Handle<SHVkPipeline> SHPipelineLibrary::CreateGraphicsPipelines(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHVkRenderpass> renderpass, Handle<SHSubpass> subpass, SHGraphicsPredefinedData::SystemType systemType, SHVertexInputState const& viState, SHRasterizationState const& rasterState) noexcept
{ {
std::vector<Handle<SHVkShaderModule>> modules{}; std::vector<Handle<SHVkShaderModule>> modules{};
if (vsFsPair.first) if (vsFsPair.first)
@ -17,8 +17,8 @@ namespace SHADE
SHPipelineLayoutParams params SHPipelineLayoutParams params
{ {
.shaderModules = std::move(modules), .shaderModules = {vsFsPair.first, vsFsPair.second},
.predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::BATCHING).descSetLayouts .predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(systemType).descSetLayouts
}; };
// Create the pipeline layout // Create the pipeline layout

View File

@ -34,6 +34,7 @@ namespace SHADE
std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair,
Handle<SHVkRenderpass> renderpass, Handle<SHVkRenderpass> renderpass,
Handle<SHSubpass> subpass, Handle<SHSubpass> subpass,
SHGraphicsPredefinedData::SystemType systemType,
SHVertexInputState const& viState = SHGraphicsPredefinedData::GetDefaultViState(), SHVertexInputState const& viState = SHGraphicsPredefinedData::GetDefaultViState(),
SHRasterizationState const& rasterState = SHRasterizationState{} SHRasterizationState const& rasterState = SHRasterizationState{}
) noexcept; ) noexcept;

View File

@ -689,11 +689,37 @@ namespace SHADE
Handle<SHVkPipeline> pipeline = pipelineLibrary.GetGraphicsPipeline(vsFsPair); Handle<SHVkPipeline> pipeline = pipelineLibrary.GetGraphicsPipeline(vsFsPair);
if (!pipeline) if (!pipeline)
{ {
// default to batching system type
SHGraphicsPredefinedData::SystemType systemType{ SHGraphicsPredefinedData::SystemType::BATCHING };
auto const& REFLECTED_SETS = vsFsPair.first->GetReflectedData().GetDescriptorBindingInfo().GetReflectedSets();
// look for animation set binding in the shader (set 2 binding 1)
for (auto const& set : REFLECTED_SETS)
{
auto const mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING_ANIM);
// Look for set 2
if (set->set == mappings.at(SHPredefinedDescriptorTypes::PER_INSTANCE_ANIM_BATCH))
{
for (int i = 0; i < set->binding_count; i++)
{
// look for binding 1. if found use BATCHING_ANIM system type
if (set->bindings[i]->binding == SHGraphicsConstants::DescriptorSetBindings::BONE_MATRIX_DATA)
{
systemType = SHGraphicsPredefinedData::SystemType::BATCHING_ANIM;
break;
}
}
break;
}
}
pipeline = pipelineLibrary.CreateGraphicsPipelines pipeline = pipelineLibrary.CreateGraphicsPipelines
( (
vsFsPair, vsFsPair,
renderpass, renderpass,
subpass subpass,
systemType
); );
} }

View File

@ -0,0 +1,23 @@
/************************************************************************************//*!
\file SHVec4U.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Jan 16, 2023
\brief Contains type alias for SHVec4U.
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
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/// <summary>
/// Simple type alias for a array of uint32_t of 4 uint32_ts.
/// </summary>
using SHVec4U = std::array<uint32_t, 4>;
}

View File

@ -176,12 +176,14 @@ namespace SHADE
/* Type Definition */ /* Type Definition */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
using LibraryDeleter = std::function<void()>; using LibraryDeleter = std::function<void()>;
using LibraryClearer = std::function<void()>;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
std::unordered_map<std::type_index, void*> resourceLibs; // TODO: Replace with compile time map std::unordered_map<std::type_index, void*> resourceLibs; // TODO: Replace with compile time map
std::vector<LibraryDeleter> deleters; std::vector<LibraryDeleter> deleters;
std::unordered_map<std::type_index, LibraryClearer> clearers;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Helper Functions */ /* Helper Functions */

View File

@ -20,9 +20,11 @@ namespace SHADE
/* Static Data Member Definitions */ /* Static Data Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHResourceHub SHResourceManager::resourceHub; SHResourceHub SHResourceManager::resourceHub;
SHResourceLibrary<SHRigNode> SHResourceManager::rigNodeStore;
std::unordered_map<std::type_index, std::unordered_map<AssetID, Handle<void>>> SHResourceManager::handlesMap; std::unordered_map<std::type_index, std::unordered_map<AssetID, Handle<void>>> SHResourceManager::handlesMap;
std::unordered_map<std::type_index, SHResourceManager::HandleAssetMap> SHResourceManager::assetIdMap; std::unordered_map<std::type_index, SHResourceManager::HandleAssetMap> SHResourceManager::assetIdMap;
std::unordered_map<std::type_index, std::function<void(AssetID)>> SHResourceManager::typedFreeFuncMap; std::unordered_map<std::type_index, SHResourceManager::AssetFreeFunc> SHResourceManager::typedFreeFuncMap;
std::unordered_map<std::type_index, SHResourceManager::LibraryClearer> SHResourceManager::typedFreeAllFuncMap;
std::vector<AssetID> SHResourceManager::loadedAssetData; std::vector<AssetID> SHResourceManager::loadedAssetData;
bool SHResourceManager::textureChanged = false; bool SHResourceManager::textureChanged = false;
bool SHResourceManager::meshChanged = false; bool SHResourceManager::meshChanged = false;
@ -91,6 +93,14 @@ namespace SHADE
loadedAssetData.clear(); loadedAssetData.clear();
} }
void SHResourceManager::UnloadAll()
{
for (auto func : typedFreeAllFuncMap)
{
func.second();
}
}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Query Functions */ /* Query Functions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/

View File

@ -13,11 +13,12 @@ of DigiPen Institute of Technology is prohibited.
// STL Includes // STL Includes
#include <unordered_map> #include <unordered_map>
// Project Includes // Project Includes
#include "SH_API.h" #include "SH_API.h"
#include "SHResourceLibrary.h" #include "SHResourceLibrary.h"
#include "Assets/SHAssetMacros.h" #include "Assets/SHAssetMacros.h"
#include "Assets/Asset Types/SHModelAsset.h" #include "Assets/Asset Types/Models/SHModelAsset.h"
#include "Assets/Asset Types/SHTextureAsset.h" #include "Assets/Asset Types/SHTextureAsset.h"
#include "Assets/Asset Types/SHShaderAsset.h" #include "Assets/Asset Types/SHShaderAsset.h"
#include "Graphics/Shaders/SHVkShaderModule.h" #include "Graphics/Shaders/SHVkShaderModule.h"
@ -27,6 +28,8 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h"
#include "Assets/Asset Types/SHMaterialAsset.h" #include "Assets/Asset Types/SHMaterialAsset.h"
#include "Graphics/MiddleEnd/TextRendering/SHFont.h" #include "Graphics/MiddleEnd/TextRendering/SHFont.h"
#include "Animation/SHAnimationClip.h"
#include "Animation/SHRig.h"
namespace SHADE namespace SHADE
{ {
@ -34,6 +37,7 @@ namespace SHADE
/* Forward Declarations */ /* Forward Declarations */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
class SHMaterial; class SHMaterial;
struct SHRigNode;
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
@ -43,12 +47,14 @@ namespace SHADE
/// </summary> /// </summary>
template<typename T = void> template<typename T = void>
struct SHResourceLoader { using AssetType = void; }; struct SHResourceLoader { using AssetType = void; };
template<> struct SHResourceLoader<SHMesh> { using AssetType = SHMeshData; }; template<> struct SHResourceLoader<SHMesh> { using AssetType = SHMeshAsset; };
template<> struct SHResourceLoader<SHTexture> { using AssetType = SHTextureAsset; }; template<> struct SHResourceLoader<SHTexture> { using AssetType = SHTextureAsset; };
template<> struct SHResourceLoader<SHVkShaderModule> { using AssetType = SHShaderAsset; }; template<> struct SHResourceLoader<SHVkShaderModule> { using AssetType = SHShaderAsset; };
template<> struct SHResourceLoader<SHMaterialSpec> { using AssetType = SHMaterialAsset; }; template<> struct SHResourceLoader<SHMaterialSpec> { using AssetType = SHMaterialAsset; };
template<> struct SHResourceLoader<SHMaterial> { using AssetType = SHMaterialSpec; }; template<> struct SHResourceLoader<SHMaterial> { using AssetType = SHMaterialSpec; };
template<> struct SHResourceLoader<SHFont> { using AssetType = SHFontAsset; }; template<> struct SHResourceLoader<SHFont> { using AssetType = SHFontAsset; };
template<> struct SHResourceLoader<SHAnimationClip> { using AssetType = SHModelAsset; };
template<> struct SHResourceLoader<SHRig> { using AssetType = SHModelAsset; };
/// <summary> /// <summary>
/// Static class responsible for loading and caching runtime resources from their /// Static class responsible for loading and caching runtime resources from their
@ -105,6 +111,10 @@ namespace SHADE
/// Needs to be called to finalise all changes to loads, unless at runtime. /// Needs to be called to finalise all changes to loads, unless at runtime.
/// </summary> /// </summary>
static void FinaliseChanges(); static void FinaliseChanges();
/// <summary>
/// Unloads all loaded resources.
/// </summary>
static void UnloadAll();
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Query Functions */ /* Query Functions */
@ -166,15 +176,19 @@ namespace SHADE
using HandleAssetMap = std::unordered_map<Handle<void>, AssetID>; using HandleAssetMap = std::unordered_map<Handle<void>, AssetID>;
using AssetHandleMapRef = std::reference_wrapper<AssetHandleMap>; using AssetHandleMapRef = std::reference_wrapper<AssetHandleMap>;
using HandleAssetMapRef = std::reference_wrapper<HandleAssetMap>; using HandleAssetMapRef = std::reference_wrapper<HandleAssetMap>;
using AssetFreeFunc = std::function<void(AssetID)>;
using LibraryClearer = std::function<void()>;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
// Handles // Handles
static SHResourceHub resourceHub; static SHResourceHub resourceHub;
static SHResourceLibrary<SHRigNode> rigNodeStore;
static std::unordered_map<std::type_index, AssetHandleMap> handlesMap; static std::unordered_map<std::type_index, AssetHandleMap> handlesMap;
static std::unordered_map<std::type_index, HandleAssetMap> assetIdMap; static std::unordered_map<std::type_index, HandleAssetMap> assetIdMap;
static std::unordered_map<std::type_index, std::function<void(AssetID)>> typedFreeFuncMap; static std::unordered_map<std::type_index, AssetFreeFunc> typedFreeFuncMap;
static std::unordered_map<std::type_index, LibraryClearer> typedFreeAllFuncMap;
// Pointers to temp CPU resources // Pointers to temp CPU resources
static std::vector<AssetID> loadedAssetData; static std::vector<AssetID> loadedAssetData;
// Dirty Flags // Dirty Flags

View File

@ -40,7 +40,9 @@ namespace SHADE
!std::is_same_v<ResourceType, SHVkShaderModule> && !std::is_same_v<ResourceType, SHVkShaderModule> &&
!std::is_same_v<ResourceType, SHMaterialSpec> && !std::is_same_v<ResourceType, SHMaterialSpec> &&
!std::is_same_v<ResourceType, SHFont> && !std::is_same_v<ResourceType, SHFont> &&
!std::is_same_v<ResourceType, SHMaterial> !std::is_same_v<ResourceType, SHMaterial> &&
!std::is_same_v<ResourceType, SHAnimationClip> &&
!std::is_same_v<ResourceType, SHRig>
) )
{ {
static_assert(true, "Unsupported Resource Type specified for SHResourceManager."); static_assert(true, "Unsupported Resource Type specified for SHResourceManager.");
@ -175,14 +177,19 @@ namespace SHADE
{ {
handlesMap.emplace(TYPE, AssetHandleMap{}); handlesMap.emplace(TYPE, AssetHandleMap{});
assetIdMap.emplace(TYPE, HandleAssetMap{}); assetIdMap.emplace(TYPE, HandleAssetMap{});
typedFreeFuncMap.emplace typedFreeFuncMap[TYPE] = [TYPE](AssetID assetId)
( {
TYPE, static_cast<Handle<ResourceType>>(SHResourceManager::handlesMap[TYPE][assetId]).Free();
[TYPE](AssetID assetId) };
typedFreeAllFuncMap[TYPE] = [TYPE]()
{
auto& handlesMap = SHResourceManager::handlesMap[TYPE];
for (auto handle : handlesMap)
{ {
static_cast<Handle<ResourceType>>(SHResourceManager::handlesMap[TYPE][assetId]).Free(); static_cast<Handle<ResourceType>>(handle.second).Free();
} }
); handlesMap.clear();
};
} }
return std::make_pair(std::ref(handlesMap[TYPE]), std::ref(assetIdMap[TYPE])); return std::make_pair(std::ref(handlesMap[TYPE]), std::ref(assetIdMap[TYPE]));
} }
@ -209,7 +216,10 @@ namespace SHADE
assetData.VertexTangents.data(), assetData.VertexTangents.data(),
assetData.VertexNormals.data(), assetData.VertexNormals.data(),
assetData.Indices.size(), assetData.Indices.size(),
assetData.Indices.data() assetData.Indices.data(),
assetData.VertexBoneIndices.empty() ? nullptr : assetData.VertexBoneIndices.data(),
assetData.VertexBoneWeights.empty() ? nullptr : assetData.VertexBoneWeights.data(),
assetData.BoneCount
); );
} }
// Textures // Textures
@ -345,5 +355,16 @@ namespace SHADE
return gfxSystem->AddFont(assetData); return gfxSystem->AddFont(assetData);
} }
// Animation Clip and Rig
else if constexpr (std::is_same_v<ResourceType, SHRig>)
{
loadedAssetData.emplace_back(assetId);
return resourceHub.Create<ResourceType>(assetData.rig, rigNodeStore);
}
else if constexpr (std::is_same_v<ResourceType, SHAnimationClip>)
{
loadedAssetData.emplace_back(assetId);
return resourceHub.Create<ResourceType>(*assetData.anims[0]);
}
} }
} }

View File

@ -204,6 +204,7 @@ namespace SHADE
AddComponentToComponentNode<SHToggleButtonComponent>(components, eid); AddComponentToComponentNode<SHToggleButtonComponent>(components, eid);
AddComponentToComponentNode<SHTextRenderableComponent>(components, eid); AddComponentToComponentNode<SHTextRenderableComponent>(components, eid);
AddComponentToComponentNode<SHAnimatorComponent>(components, eid);
node[ComponentsNode] = components; node[ComponentsNode] = components;
@ -261,6 +262,7 @@ namespace SHADE
AddComponentID<SHButtonComponent>(componentIDList, componentsNode); AddComponentID<SHButtonComponent>(componentIDList, componentsNode);
AddComponentID<SHToggleButtonComponent>(componentIDList, componentsNode); AddComponentID<SHToggleButtonComponent>(componentIDList, componentsNode);
AddComponentID<SHTextRenderableComponent>(componentIDList, componentsNode); AddComponentID<SHTextRenderableComponent>(componentIDList, componentsNode);
AddComponentID<SHAnimatorComponent>(componentIDList, componentsNode);
return componentIDList; return componentIDList;
} }
@ -344,5 +346,6 @@ namespace SHADE
SHSerializationHelper::InitializeComponentFromNode<SHToggleButtonComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHToggleButtonComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHTextRenderableComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHTextRenderableComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHLightComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHLightComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHAnimatorComponent>(componentsNode, eid);
} }
} }

View File

@ -325,7 +325,7 @@ namespace SHADE
{ {
auto fragShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(spec.fragShader); auto fragShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(spec.fragShader);
auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING); auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING);
auto interface = fragShader->GetReflectedData().GetDescriptorBindingInfo().GetShaderBlockInterface(mappings.at(SHPredefinedDescriptorTypes::MATERIALS), SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA); auto interface = fragShader->GetReflectedData().GetDescriptorBindingInfo().GetShaderBlockInterface(mappings.at(SHPredefinedDescriptorTypes::PER_INSTANCE_BATCH), SHGraphicsConstants::DescriptorSetBindings::PER_INST_MATERIAL_DATA);
int const varCount = static_cast<int>(interface->GetVariableCount()); int const varCount = static_cast<int>(interface->GetVariableCount());
for (int i = 0; i < varCount; ++i) for (int i = 0; i < varCount; ++i)

View File

@ -14,6 +14,7 @@
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "SHSerializationTools.h" #include "SHSerializationTools.h"
#include "Graphics/MiddleEnd/TextRendering/SHFont.h" #include "Graphics/MiddleEnd/TextRendering/SHFont.h"
#include "Animation/SHAnimatorComponent.h"
#include "Physics/Collision/SHCollisionTagMatrix.h" #include "Physics/Collision/SHCollisionTagMatrix.h"
namespace YAML namespace YAML
@ -29,6 +30,8 @@ namespace YAML
struct HasYAMLConv<SHRenderable> : std::true_type {}; struct HasYAMLConv<SHRenderable> : std::true_type {};
template<> template<>
struct HasYAMLConv<SHTextRenderableComponent> : std::true_type {}; struct HasYAMLConv<SHTextRenderableComponent> : std::true_type {};
template<>
struct HasYAMLConv<SHAnimatorComponent> : std::true_type {};
template<> template<>
struct convert<SHVec4> struct convert<SHVec4>
@ -386,4 +389,33 @@ namespace YAML
return true; return true;
} }
}; };
template<>
struct convert<SHAnimatorComponent>
{
static constexpr std::string_view RIG_YAML_TAG = "Rig";
static constexpr std::string_view CLIP_YAML_TAG = "Clip";
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);
return node;
}
static bool decode(YAML::Node const& node, SHAnimatorComponent& rhs)
{
if (node[RIG_YAML_TAG.data()].IsDefined())
{
rhs.SetRig(SHResourceManager::LoadOrGet<SHRig>(node[RIG_YAML_TAG.data()].as<AssetID>()));
}
if (node[CLIP_YAML_TAG.data()].IsDefined())
{
rhs.SetClip(SHResourceManager::LoadOrGet<SHAnimationClip>(node[CLIP_YAML_TAG.data()].as<AssetID>()));
}
return true;
}
};
} }

View File

@ -98,4 +98,35 @@ namespace SHADE
auto audioSys = SHSystemManager::GetSystem<SHAudioSystem>(); auto audioSys = SHSystemManager::GetSystem<SHAudioSystem>();
audioSys->StopAllSounds(); audioSys->StopAllSounds();
} }
AudioClipHandler Audio::CreateAudioClip(System::String^ path)
{
auto audioSys = SHSystemManager::GetSystem<SHAudioSystem>();
return AudioClipHandler(audioSys->CreateAudioClip(Convert::ToNative(path).data()));
}
void Audio::AddAudioClipToBGMChannelGroup(AudioClipHandler handle)
{
auto audioSys = SHSystemManager::GetSystem<SHAudioSystem>();
audioSys->AddAudioClipToBGMChannelGroup(handle.NativeObject);
}
void Audio::AddAudioClipToSFXChannelGroup(AudioClipHandler handle)
{
auto audioSys = SHSystemManager::GetSystem<SHAudioSystem>();
audioSys->AddAudioClipToSFXChannelGroup(handle.NativeObject);
}
void Audio::AttachAudioClipToObject(AudioClipHandler handle, EntityID eid)
{
auto audioSys = SHSystemManager::GetSystem<SHAudioSystem>();
audioSys->AttachAudioClipToObject(handle.NativeObject, eid);
}
void Audio::DetachAudioClipFromObject(AudioClipHandler handle)
{
auto audioSys = SHSystemManager::GetSystem<SHAudioSystem>();
audioSys->DetachAudioClipFromObject(handle.NativeObject);
}
} }

View File

@ -13,6 +13,7 @@ of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/ *//*************************************************************************************/
#pragma once #pragma once
#include "Engine/GameObject.hxx" #include "Engine/GameObject.hxx"
#include "Audio/AudioClip.hxx"
namespace SHADE namespace SHADE
{ {
@ -99,5 +100,13 @@ namespace SHADE
/// Stops playback of all sound effects and music. /// Stops playback of all sound effects and music.
/// </summary> /// </summary>
static void StopAllSounds(); static void StopAllSounds();
//to comment ltr
static AudioClipHandler CreateAudioClip(System::String^ path);
static void AddAudioClipToBGMChannelGroup(AudioClipHandler handle);
static void AddAudioClipToSFXChannelGroup(AudioClipHandler handle);
static void AttachAudioClipToObject(AudioClipHandler handle, EntityID eid);
static void DetachAudioClipFromObject(AudioClipHandler handle);
}; };
} }

View File

@ -0,0 +1,89 @@
/************************************************************************************//*!
\file AudioClip.cxx
\author Glence Low
\par email: glence.low\@digipen.edu
\date Jan 16, 2023
\brief Contains the implementation of the functions in managed AudioClip
Note: This file is written in C++17/CLI.
Copyright (C) 2022 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.
*//*************************************************************************************/
// Precompiled Headers
#include "SHpch.h"
// Primary Header
#include "AudioClip.hxx"
// Standard Library
#include <stdexcept>
// Project Includes
#include "Utility/Convert.hxx"
#include "Resource/SHResourceManagerInterface.h"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Properties */
/*---------------------------------------------------------------------------------*/
Handle<AudioClip> AudioClipHandler::NativeObject::get()
try
{
return Handle<AudioClip>(Convert::ToNative(audioClipInstHandle));
}
catch (const BadHandleCastException&)
{
return Handle<AudioClip>();
}
GenericHandle AudioClipHandler::NativeObjectHandle::get()
{
return audioClipInstHandle;
}
AssetID AudioClipHandler::NativeAssetID::get()
{
return SHResourceManagerInterface::GetAssetID(Convert::ToNative(audioClipInstHandle)).value_or(INVALID_ASSET_ID);
}
/*---------------------------------------------------------------------------------*/
/* Constructors/Destructor */
/*---------------------------------------------------------------------------------*/
AudioClipHandler::AudioClipHandler(Handle<AudioClip> audioClip)
: audioClipInstHandle{ Handle<void>(audioClip) }
{}
/*---------------------------------------------------------------------------------*/
/* AudioClip Properties Functions */
/*---------------------------------------------------------------------------------*/
void AudioClipHandler::Play()
{
NativeObject->Play();
}
void AudioClipHandler::Stop(bool fadeOut)
{
NativeObject->Stop(fadeOut);
}
void AudioClipHandler::SetPause(bool pause)
{
NativeObject->SetPause(pause);
}
bool AudioClipHandler::IsPaused()
{
return NativeObject->IsPaused();
}
void AudioClipHandler::SetParameter(System::String^ paramName, float value)
{
NativeObject->SetParameter(Convert::ToNative(paramName).data(), value);
}
float AudioClipHandler::GetParameterValue(System::String^ paramName)
{
return NativeObject->GetParameterValue(Convert::ToNative(paramName).data());
}
}

View File

@ -0,0 +1,83 @@
/************************************************************************************//*!
\file AudioClip.hxx
\author Glence Low
\par email: glence.low\@digipen.edu
\date Jan 16, 2023
\brief Contains the definition of the managed Audio Clip class.
Note: This file is written in C++17/CLI.
Copyright (C) 2022 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
// External Dependencies
#include "Resource/SHHandle.h"
#include "AudioSystem/SHAudioSystem.h"
#include "Assets/SHAssetMacros.h"
// Project Includes
#include "Engine/GenericHandle.hxx"
namespace SHADE
{
/// <summary>
/// Managed counterpart of the AudioSystem containing Audioclip
/// that can be fed to Audioscripting for creating clips.
/// </summary>
public value struct AudioClipHandler
{
internal:
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Copy of the Handle to the native object.
/// </summary>
property Handle<AudioClip> NativeObject
{
Handle<AudioClip> get();
}
/// <summary>
/// Generic handle for the native object
/// </summary>
property GenericHandle NativeObjectHandle
{
GenericHandle get();
}
/// <summary>
/// The raw asset ID of the asset.
/// </summary>
property AssetID NativeAssetID
{
AssetID get();
}
/*-----------------------------------------------------------------------------*/
/* Constructors/Destructor */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructor for the AudioClip
/// </summary>
/// <param name="AudioClip">Handle to the native material object.</param>
AudioClipHandler(Handle<AudioClip> audioclip);
public:
//to comment ltr
void Play();
void Stop(bool fadeOut);
void SetPause(bool pause);
bool IsPaused();
void SetParameter(System::String^ paramName, float value);
float GetParameterValue(System::String^ paramName);
protected:
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
GenericHandle audioClipInstHandle;
};
}