Merge branch 'main' into SP3-141-Camera-System

This commit is contained in:
maverickdgg 2022-10-27 08:55:06 +08:00
commit d8086edbe2
141 changed files with 5382 additions and 2393 deletions

5
.editorconfig Normal file
View File

@ -0,0 +1,5 @@
root = true
[*.{c,cpp,h,hpp}]
indent_style = space
indent_size = 2

View File

@ -1,3 +1,3 @@
Name: Cube.003 Name: Cube.003
ID: 110152941 ID: 110152941
Type:  Type: 6

View File

@ -1,3 +1,3 @@
Name: Cube.012 Name: Cube.012
ID: 107348815 ID: 107348815
Type:  Type: 6

View File

@ -4,13 +4,13 @@ Size=1920,20
Collapsed=0 Collapsed=0
[Window][SHEditorMenuBar] [Window][SHEditorMenuBar]
Pos=0,24 Pos=0,48
Size=1920,1036 Size=1920,1012
Collapsed=0 Collapsed=0
[Window][Hierarchy Panel] [Window][Hierarchy Panel]
Pos=0,120 Pos=0,197
Size=225,940 Size=308,863
Collapsed=0 Collapsed=0
DockId=0x00000004,0 DockId=0x00000004,0
@ -20,29 +20,96 @@ Size=400,400
Collapsed=0 Collapsed=0
[Window][Inspector] [Window][Inspector]
Pos=1686,24 Pos=1528,48
Size=234,1036 Size=392,1012
Collapsed=0 Collapsed=0
DockId=0x00000006,0 DockId=0x00000006,0
[Window][Profiler] [Window][Profiler]
Pos=0,24 Pos=0,48
Size=225,94 Size=308,147
Collapsed=0 Collapsed=0
DockId=0x00000003,0 DockId=0x00000003,0
[Window][Viewport] [Window][Viewport]
Pos=227,24 Pos=227,48
Size=1457,1036 Size=1457,1012
Collapsed=0 Collapsed=0
DockId=0x00000002,0 DockId=0x0000000B,0
[Window][ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌð‡Žoû]
Pos=60,60
Size=32,64
Collapsed=0
[Window][ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ]
Pos=60,60
Size=999,581
Collapsed=0
[Window][ð‡]
Pos=60,60
Size=32,64
Collapsed=0
[Window][ÌÌÌÌ]
Pos=60,60
Size=553,422
Collapsed=0
[Window][]
Pos=60,60
Size=770,394
Collapsed=0
[Window][ Viewport]
Pos=227,48
Size=1457,1012
Collapsed=0
DockId=0x0000000B,0
[Window][ Viewport]
Pos=227,48
Size=1457,1012
Collapsed=0
DockId=0x0000000B,0
[Window][î<> Viewport]
Pos=310,48
Size=1216,715
Collapsed=0
DockId=0x0000000B,0
[Window][V]
Pos=310,722
Size=1501,338
Collapsed=0
DockId=0x00000008,0
[Window][p£€Ê]
Pos=310,750
Size=1501,310
Collapsed=0
DockId=0x0000000A,0
[Window][ Asset Browser]
Pos=310,765
Size=1216,295
Collapsed=0
DockId=0x0000000C,0
[Docking][Data] [Docking][Data]
DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,55 Size=1920,1036 Split=X DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,79 Size=1920,1012 Split=X
DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1684,1036 Split=X DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1526,1036 Split=X
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=225,1036 Split=Y Selected=0x1E6EB881 DockNode ID=0x00000001 Parent=0x00000005 SizeRef=308,1036 Split=Y Selected=0x1E6EB881
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881 DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,147 Selected=0x1E6EB881
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Selected=0xE096E5AE DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,863 Selected=0xE096E5AE
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1293,1036 CentralNode=1 Selected=0x13926F0B DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1216,1036 Split=Y Selected=0xB41284E7
DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=234,1036 Selected=0xE7039252 DockNode ID=0x00000007 Parent=0x00000002 SizeRef=1501,672 Split=Y Selected=0xB41284E7
DockNode ID=0x00000009 Parent=0x00000007 SizeRef=1501,700 Split=Y Selected=0xB41284E7
DockNode ID=0x0000000B Parent=0x00000009 SizeRef=1501,715 CentralNode=1 Selected=0xB41284E7
DockNode ID=0x0000000C Parent=0x00000009 SizeRef=1501,295 Selected=0xB128252A
DockNode ID=0x0000000A Parent=0x00000007 SizeRef=1501,310 Selected=0xD446F7B6
DockNode ID=0x00000008 Parent=0x00000002 SizeRef=1501,338 Selected=0xD9F31532
DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=392,1036 Selected=0xE7039252

View File

@ -1,3 +1,3 @@
Name: RaccoonPreTexturedVer1_Base9 Name: RaccoonPreTexturedVer1_Base9
ID: 91918845 ID: 91918845
Type:  Type: 4

View File

@ -56,8 +56,8 @@ namespace Sandbox
_In_ INT nCmdShow _In_ INT nCmdShow
) )
{ {
// Set working directory // Set working directory
SHFileUtilities::SetWorkDirToExecDir(); SHFileUtilities::SetWorkDirToExecDir();
window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow); window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
@ -83,16 +83,19 @@ namespace Sandbox
SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::LateUpdateRoutine>(); SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::LateUpdateRoutine>();
SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::FrameCleanUpRoutine>(); SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::FrameCleanUpRoutine>();
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostLogicUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>();
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformUpdateRoutine>(); SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>();
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BatcherDispatcherRoutine>(); SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BatcherDispatcherRoutine>();
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BeginRoutine>(); SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BeginRoutine>();
SHSystemManager::RegisterRoutine<SHCameraSystem, SHCameraSystem::EditorCameraUpdate>(); SHSystemManager::RegisterRoutine<SHCameraSystem, SHCameraSystem::EditorCameraUpdate>();
SHSystemManager::RegisterRoutine<SHCameraSystem, SHCameraSystem::CameraSystemUpdate>();
#ifdef SHEDITOR #ifdef SHEDITOR
SHSystemManager::RegisterRoutine<SHEditor, SHEditor::EditorRoutine>(); SHSystemManager::RegisterRoutine<SHEditor, SHEditor::EditorRoutine>();
@ -149,16 +152,16 @@ namespace Sandbox
SHSceneManager::SceneUpdate(0.016f); SHSceneManager::SceneUpdate(0.016f);
#endif #endif
SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, 0.016f); SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, 0.016f);
//editor->PollPicking(); editor->PollPicking();
} }
// Finish all graphics jobs first // Finish all graphics jobs first
graphicsSystem->AwaitGraphicsExecution(); graphicsSystem->AwaitGraphicsExecution();
} }
void SBApplication::Exit(void) void SBApplication::Exit(void)
{ {
#ifdef SHEDITOR #ifdef SHEDITOR
SDL_DestroyWindow(sdlWindow); SDL_DestroyWindow(sdlWindow);
SDL_Quit(); SDL_Quit();
#endif #endif

View File

@ -12,8 +12,10 @@
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Physics/Components/SHRigidBodyComponent.h" #include "Physics/Components/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Components/SHColliderComponent.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Assets/SHAssetManager.h" #include "Assets/SHAssetManager.h"
#include "Camera/SHCameraComponent.h"
#include "Resource/SHResourceManager.h" #include "Resource/SHResourceManager.h"
using namespace SHADE; using namespace SHADE;
@ -51,7 +53,7 @@ namespace Sandbox
if (asset.name == "Cube.012") if (asset.name == "Cube.012")
handles.emplace_back(SHResourceManager::LoadOrGet<SHMesh>(asset.id)); handles.emplace_back(SHResourceManager::LoadOrGet<SHMesh>(asset.id));
break; break;
case AssetType::TEXTURE: case AssetType::IMAGE:
texHandles.emplace_back(SHResourceManager::LoadOrGet<SHTexture>(asset.id)); texHandles.emplace_back(SHResourceManager::LoadOrGet<SHTexture>(asset.id));
break; break;
} }
@ -66,9 +68,9 @@ namespace Sandbox
customMat->SetProperty("data.alpha", 0.1f); customMat->SetProperty("data.alpha", 0.1f);
// Create Stress Test Objects // Create Stress Test Objects
static const SHVec3 TEST_OBJ_SCALE = SHVec3::One * 0.5f; static const SHVec3 TEST_OBJ_SCALE = SHVec3::One;
constexpr int NUM_ROWS = 0; constexpr int NUM_ROWS = 3;
constexpr int NUM_COLS = 0; constexpr int NUM_COLS = 1;
static const SHVec3 TEST_OBJ_SPACING = { 0.1f, 0.1f, 0.1f }; static const SHVec3 TEST_OBJ_SPACING = { 0.1f, 0.1f, 0.1f };
static const SHVec3 TEST_OBJ_START_POS = { -(NUM_COLS / 2 * TEST_OBJ_SPACING.x) + 1.0f, -2.0f, -1.0f }; static const SHVec3 TEST_OBJ_START_POS = { -(NUM_COLS / 2 * TEST_OBJ_SPACING.x) + 1.0f, -2.0f, -1.0f };
@ -90,13 +92,13 @@ namespace Sandbox
//Set initial positions //Set initial positions
transform.SetWorldPosition(TEST_OBJ_START_POS + SHVec3{ x * TEST_OBJ_SPACING.x, y * TEST_OBJ_SPACING.y, SHMath::GenerateRandomNumber(-3.5f, -5.0f) }); transform.SetWorldPosition(TEST_OBJ_START_POS + SHVec3{ x * TEST_OBJ_SPACING.x, y * TEST_OBJ_SPACING.y, SHMath::GenerateRandomNumber(-3.5f, -5.0f) });
//transform.SetWorldPosition({-1.0f, -1.0f, -1.0f}); //transform.SetWorldPosition({-1.0f, -1.0f, -1.0f});
transform.SetWorldRotation(SHMath::GenerateRandomNumber(), SHMath::GenerateRandomNumber(), SHMath::GenerateRandomNumber()); transform.SetWorldRotation(SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f));
transform.SetWorldScale(TEST_OBJ_SCALE); transform.SetWorldScale(TEST_OBJ_SCALE);
if (const bool IS_EVEN = (y * NUM_ROWS + x) % 2; IS_EVEN) //if (const bool IS_EVEN = (y * NUM_ROWS + x) % 2; IS_EVEN)
collider.AddBoundingBox(SHVec3::One * 0.5f, SHVec3::Zero); collider.AddBoundingBox(SHVec3::One * 0.5f, SHVec3::Zero);
else //else
collider.AddBoundingSphere(0.5f, SHVec3::Zero); // collider.AddBoundingSphere(0.5f, SHVec3::Zero);
stressTestObjects.emplace_back(entity); stressTestObjects.emplace_back(entity);
} }
@ -155,6 +157,11 @@ namespace Sandbox
transformShowcase.SetWorldPosition({ 3.0f, -1.0f, -1.0f }); transformShowcase.SetWorldPosition({ 3.0f, -1.0f, -1.0f });
transformShowcase.SetLocalScale({ 5.0f, 5.0f, 5.0f }); transformShowcase.SetLocalScale({ 5.0f, 5.0f, 5.0f });
scriptEngine->AddScript(raccoonShowcase, "RaccoonShowcase"); scriptEngine->AddScript(raccoonShowcase, "RaccoonShowcase");
SHComponentManager::AddComponent<SHCameraComponent>(0);
SHComponentManager::AddComponent<SHLightComponent>(0);
SHComponentManager::RemoveComponent <SHRigidBodyComponent>(0);
SHComponentManager::RemoveComponent <SHColliderComponent>(0);
} }
void SBTestScene::Update(float dt) void SBTestScene::Update(float dt)

View File

@ -0,0 +1,30 @@
/*************************************************************************//**
* \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 "SH_API.power h"
namespace SHADE
{
struct SH_API SHAnimationAsset
{
std::string name;
std::vector<aiNodeAnim*> nodeChannels;
std::vector<aiMeshAnim*> meshChannels;
std::vector<aiMeshMorphAnim*> morphMeshChannels;
double duration;
double ticksPerSecond;
};
}

View File

@ -0,0 +1,30 @@
/*************************************************************************//**
* \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

@ -0,0 +1,19 @@
/*************************************************************************//**
* \file SHAssetDataBase.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
namespace SHADE
{
struct SHAssetData
{
virtual ~SHAssetData(){}
};
}

View File

@ -0,0 +1,4 @@
#pragma once
#include "SHMeshAsset.h"
#include "SHTextureAsset.h"

View File

@ -0,0 +1,21 @@
/*************************************************************************//**
* \file SHInternalAsset.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 "SHAsset.h"
namespace SHADE
{
struct SHInternalAsset : SHAsset
{
};
}

View File

@ -14,7 +14,7 @@
#include <vector> #include <vector>
#include "Math/SHMath.h" #include "Math/SHMath.h"
#include "SH_API.h" #include "SHAssetData.h"
namespace SHADE namespace SHADE
{ {
@ -22,10 +22,10 @@ namespace SHADE
{ {
uint32_t vertexCount; uint32_t vertexCount;
uint32_t indexCount; uint32_t indexCount;
std::string meshName; std::string name;
}; };
struct SH_API SHMeshAsset struct SH_API SHMeshAsset : SHAssetData
{ {
bool compiled; bool compiled;
bool changed; bool changed;

View File

@ -2,10 +2,11 @@
#include "tinyddsloader.h" #include "tinyddsloader.h"
#include "Graphics/MiddleEnd/Textures/SHTextureLibrary.h" #include "Graphics/MiddleEnd/Textures/SHTextureLibrary.h"
#include "SHAssetData.h"
namespace SHADE namespace SHADE
{ {
struct SHTextureAsset struct SHTextureAsset : SHAssetData
{ {
bool compiled; bool compiled;

View File

@ -0,0 +1,21 @@
/*************************************************************************//**
* \file SHAssetLoader.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 "Assets/Asset Types/SHAssetData.h"
namespace SHADE
{
struct SHAssetLoader
{
virtual SHAssetData* Load(AssetPath path) = 0;
};
}

View File

@ -0,0 +1,141 @@
/*************************************************************************//**
* \file SHAssimpLibrary.cpp
* \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.
*****************************************************************************/
#include "SHpch.h"
#include "SHAssimpLibrary.h"
#include <assimp/postprocess.h>
namespace SHADE
{
Assimp::Importer SHAssimpLibrary::aiImporter;
void SHAssimpLibrary::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept
{
for (size_t i {0}; i < node.mNumMeshes; ++i)
{
aiMesh* mesh = scene.mMeshes[node.mMeshes[i]];
meshes.push_back(ProcessMesh(*mesh));
}
for (size_t i{ 0 }; i < node.mNumChildren; ++i)
{
ProcessNode(*node.mChildren[i], scene, meshes);
}
}
void SHAssimpLibrary::ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept
{
if (scene.HasAnimations())
{
std::vector<SHAnimationAsset> anims(scene.mNumAnimations);
for (auto i{0}; i < scene.mNumAnimations; ++i)
{
auto const& anim {*scene.mAnimations[i]};
anims[i].name = anim.mName.C_Str();
anims[i].duration = anim.mDuration;
anims[i].ticksPerSecond = anim.mTicksPerSecond;
std::copy_n(anim.mChannels, anim.mNumChannels, anims[i].nodeChannels.data());
std::copy_n(anim.mMeshChannels, anim.mNumMeshChannels, anims[i].meshChannels.data());
std::copy_n(anim.mMorphMeshChannels, anim.mNumMorphMeshChannels, anims[i].morphMeshChannels.data());
}
}
}
SHMeshAsset* SHAssimpLibrary::ProcessMesh(aiMesh const& mesh) noexcept
{
SHMeshAsset* result = new SHMeshAsset();
result->compiled = false;
result->changed = false;
for (size_t i{0}; i < mesh.mNumVertices; ++i)
{
// Vertex position
SHVec3 vertex;
vertex.x = mesh.mVertices[i].x;
vertex.y = mesh.mVertices[i].y;
vertex.z = mesh.mVertices[i].z;
result->vertexPosition.push_back(vertex);
// Tex coords
SHVec2 texCoord{0.f, 0.f};
if (mesh.mTextureCoords[0])
{
texCoord.x = mesh.mTextureCoords[0][i].x;
texCoord.y = mesh.mTextureCoords[0][i].y;
}
result->texCoords.push_back(texCoord);
// Normals
SHVec3 normal{0.f, 0.f, 0.f};
if (mesh.mNormals)
{
normal.x = mesh.mNormals[i].x;
normal.y = mesh.mNormals[i].y;
normal.z = mesh.mNormals[i].z;
}
result->vertexNormal.push_back(normal);
// Tangent
SHVec3 tangent{0.f, 0.f, 0.f};
if (mesh.mTangents)
{
tangent.x = mesh.mTangents[i].x;
tangent.y = mesh.mTangents[i].y;
tangent.z = mesh.mTangents[i].z;
}
result->vertexTangent.push_back(tangent);
}
for (size_t i {0}; i < mesh.mNumFaces; ++i)
{
aiFace face = mesh.mFaces[i];
for (size_t j{0}; j < face.mNumIndices; ++j)
{
result->indices.push_back(face.mIndices[j]);
}
}
result->header.vertexCount = static_cast<uint32_t>(result->vertexPosition.size());
result->header.indexCount = static_cast<uint32_t>(result->indices.size());
result->header.name = mesh.mName.C_Str();
return result;
}
void SHAssimpLibrary::LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept
{
const aiScene* scene = aiImporter.ReadFile(path.string().c_str(),
aiProcess_Triangulate // Make sure we get triangles rather than nvert polygons
| aiProcess_GenUVCoords // Convert any type of mapping to uv mapping
| aiProcess_TransformUVCoords // preprocess UV transformations (scaling, translation ...)
| aiProcess_FindInstances // search for instanced meshes and remove them by references to one master
| aiProcess_CalcTangentSpace // calculate tangents and bitangents if possible
| aiProcess_JoinIdenticalVertices // join identical vertices/ optimize indexing
| aiProcess_RemoveRedundantMaterials // remove redundant materials
| aiProcess_FindInvalidData // detect invalid model data, such as invalid normal vectors
| aiProcess_FlipUVs // flip the V to match the Vulkans way of doing UVs
);
if (!scene || !scene->HasMeshes())
{
SHLOG_ERROR("ERROR in GLTF::ASSIMP: {}\nFile: {}", aiImporter.GetErrorString(), path.string());
return;
}
ExtractAnimations(*scene, anims);
ProcessNode(*scene->mRootNode, *scene, meshes);
aiImporter.FreeScene();
}
}

View File

@ -0,0 +1,36 @@
/*************************************************************************//**
* \file SHAssimpLibrary.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 <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <vector>
#include "../SHAssetMacros.h"
#include "../Asset Types/SHMeshAsset.h"
#include "../Asset Types/SHAnimationAsset.h"
namespace SHADE
{
class SHAssimpLibrary
{
private:
using MeshVectorRef = std::vector<SHMeshAsset*>&;
using AnimVectorRef = std::vector<SHAnimationAsset*>&;
static Assimp::Importer aiImporter;
static void ProcessNode(aiNode const& node, aiScene const& scene,MeshVectorRef meshes) noexcept;
static void ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept;
static SHMeshAsset* ProcessMesh(aiMesh const& mesh) noexcept;
public:
static void LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept;
};
}

View File

@ -20,7 +20,7 @@ std::string SHADE::SHMeshCompiler::CompileMeshBinary(SHMeshAsset const& asset, A
{ {
std::string newPath{ path.string() }; std::string newPath{ path.string() };
newPath = newPath.substr(0, newPath.find_last_of('/') + 1); newPath = newPath.substr(0, newPath.find_last_of('/') + 1);
newPath += asset.header.meshName + MESH_EXTENSION; newPath += asset.header.name + MESH_EXTENSION.data();
std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc }; std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc };
if (!file.is_open()) if (!file.is_open())

View File

@ -12,129 +12,11 @@
*****************************************************************************/ *****************************************************************************/
#include "SHpch.h" #include "SHpch.h"
#include "SHMeshLoader.h" #include "SHMeshLoader.h"
#include <assimp/postprocess.h>
#include <fstream> #include <fstream>
namespace SHADE namespace SHADE
{ {
Assimp::Importer SHMeshLoader::aiImporter; void SHMeshLoader::LoadSHMesh(AssetPath path, SHMeshAsset& mesh) noexcept
void SHMeshLoader::ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes) noexcept
{
for (size_t i {0}; i < node.mNumMeshes; ++i)
{
aiMesh* mesh = scene.mMeshes[node.mMeshes[i]];
meshes.push_back(ProcessMesh(*mesh, scene));
}
for (size_t i{ 0 }; i < node.mNumChildren; ++i)
{
ProcessNode(*node.mChildren[i], scene, meshes);
}
}
SHMeshAsset SHMeshLoader::ProcessMesh(aiMesh const& mesh, aiScene const& scene) noexcept
{
(void)scene;
SHMeshAsset result
{
.compiled { false},
.changed { false }
};
for (size_t i{0}; i < mesh.mNumVertices; ++i)
{
// Vertex position
SHVec3 vertex;
vertex.x = mesh.mVertices[i].x;
vertex.y = mesh.mVertices[i].y;
vertex.z = mesh.mVertices[i].z;
result.vertexPosition.push_back(vertex);
// Tex coords
SHVec2 texCoord{0.f, 0.f};
if (mesh.mTextureCoords[0])
{
texCoord.x = mesh.mTextureCoords[0][i].x;
texCoord.y = mesh.mTextureCoords[0][i].y;
}
result.texCoords.push_back(texCoord);
// Normals
SHVec3 normal{0.f, 0.f, 0.f};
if (mesh.mNormals)
{
normal.x = mesh.mNormals[i].x;
normal.y = mesh.mNormals[i].y;
normal.z = mesh.mNormals[i].z;
}
result.vertexNormal.push_back(normal);
// Tangent
SHVec3 tangent{0.f, 0.f, 0.f};
if (mesh.mTangents)
{
tangent.x = mesh.mTangents[i].x;
tangent.y = mesh.mTangents[i].y;
tangent.z = mesh.mTangents[i].z;
}
result.vertexTangent.push_back(tangent);
}
for (size_t i {0}; i < mesh.mNumFaces; ++i)
{
aiFace face = mesh.mFaces[i];
for (size_t j{0}; j < face.mNumIndices; ++j)
{
result.indices.push_back(face.mIndices[j]);
}
}
result.header.vertexCount = static_cast<uint32_t>(result.vertexPosition.size());
result.header.indexCount = static_cast<uint32_t>(result.indices.size());
result.header.meshName = mesh.mName.C_Str();
return result;
}
void SHMeshLoader::LoadExternal(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept
{
const aiScene* scene = aiImporter.ReadFile(path.string().c_str(),
aiProcess_Triangulate // Make sure we get triangles rather than nvert polygons
| aiProcess_GenUVCoords // Convert any type of mapping to uv mapping
| aiProcess_TransformUVCoords // preprocess UV transformations (scaling, translation ...)
| aiProcess_FindInstances // search for instanced meshes and remove them by references to one master
| aiProcess_CalcTangentSpace // calculate tangents and bitangents if possible
| aiProcess_JoinIdenticalVertices // join identical vertices/ optimize indexing
| aiProcess_RemoveRedundantMaterials // remove redundant materials
| aiProcess_FindInvalidData // detect invalid model data, such as invalid normal vectors
| aiProcess_FlipUVs // flip the V to match the Vulkans way of doing UVs
);
if (!scene || !scene->HasMeshes())
{
SHLOG_ERROR("ERROR in GLTF::ASSIMP: {}\nFile: {}", aiImporter.GetErrorString(), path.string());
return;
}
//TODO MATERIALS FROM MESHES
//if (scene->HasMaterials())
//{
// for (int i{0}; i < scene->mNumMaterials; ++i)
// {
// if (scene->mMaterials[i]->mNumProperties > 0)
// {
// for (int j{0}; j < scene->mMaterials[i]->mProperties[j].)
// }
//std::cout << scene->mMaterials[i]->;
// }
//}
ProcessNode(*scene->mRootNode, *scene, meshes);
}
void SHMeshLoader::LoadSHMesh(SHMeshAsset& mesh, AssetPath path) noexcept
{ {
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())
@ -168,45 +50,13 @@ namespace SHADE
file.read(reinterpret_cast<char *>(vertNorm.data()), vertexVec3Byte); file.read(reinterpret_cast<char *>(vertNorm.data()), vertexVec3Byte);
file.read(reinterpret_cast<char *>(texCoord.data()), vertexVec2Byte); file.read(reinterpret_cast<char *>(texCoord.data()), vertexVec2Byte);
file.read(reinterpret_cast<char *>(indices.data()), sizeof(uint32_t) * indexCount); file.read(reinterpret_cast<char *>(indices.data()), sizeof(uint32_t) * indexCount);
//for (auto i{ 0 }; i < vertCount; ++i)
//{
// file >> vertPos[i].x;
// file >> vertPos[i].y;
// file >> vertPos[i].z;
//}
//
//for (auto i{ 0 }; i < vertCount; ++i)
//{
// file >> vertTan[i].x;
// file >> vertTan[i].y;
// file >> vertTan[i].z;
//}
//for (auto i{ 0 }; i < vertCount; ++i)
//{
// file >> vertNorm[i].x;
// file >> vertNorm[i].y;
// file >> vertNorm[i].z;
//}
//for (auto i{ 0 }; i < vertCount; ++i)
//{
// file >> texCoord[i].x;
// file >> texCoord[i].y;
//}
//for (auto i{ 0 }; i < indexCount; ++i)
//{
// file >> indices[i];
//}
mesh.compiled = true; mesh.compiled = true;
mesh.changed = false; mesh.changed = false;
mesh.header.indexCount = indexCount; mesh.header.indexCount = indexCount;
mesh.header.vertexCount = vertCount; mesh.header.vertexCount = vertCount;
mesh.header.meshName = name; mesh.header.name = name;
mesh.vertexPosition = std::move(vertPos); mesh.vertexPosition = std::move(vertPos);
mesh.vertexTangent = std::move(vertTan); mesh.vertexTangent = std::move(vertTan);
@ -217,15 +67,12 @@ namespace SHADE
file.close(); file.close();
} }
void SHMeshLoader::LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept SHAssetData* SHMeshLoader::Load(AssetPath path)
{ {
if (path.extension().string() == GLTF_EXTENSION) auto result = new SHMeshAsset();
{
LoadExternal(meshes, path);
return;
}
meshes.emplace_back(); LoadSHMesh(path, *result);
LoadSHMesh(meshes.back(), path);
return result;
} }
} }

View File

@ -10,27 +10,15 @@
* of DigiPen Institute of Technology is prohibited. * of DigiPen Institute of Technology is prohibited.
*****************************************************************************/ *****************************************************************************/
#pragma once #pragma once
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include "../SHAssetMacros.h" #include "../SHAssetMacros.h"
#include "../Asset Types/SHMeshAsset.h" #include "../Asset Types/SHMeshAsset.h"
#include <vector> #include "SHAssetLoader.h"
namespace SHADE namespace SHADE
{ {
class SHMeshLoader struct SHMeshLoader : public SHAssetLoader
{ {
private: void LoadSHMesh(AssetPath path, SHMeshAsset& meshes) noexcept;
static Assimp::Importer aiImporter; SHAssetData* Load(AssetPath path) override;
static void ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes) noexcept;
static SHMeshAsset ProcessMesh(aiMesh const& mesh, aiScene const& scene) noexcept;
static void LoadExternal(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept;
public:
static void LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept;
static void LoadSHMesh(SHMeshAsset& meshes, AssetPath path) noexcept;
}; };
} }

View File

@ -133,6 +133,15 @@ namespace SHADE
file.close(); file.close();
} }
SHAssetData* SHTextureLoader::Load(AssetPath path)
{
auto result = new SHTextureAsset();
LoadImageAsset(path, *result);
return result;
}
void SHTextureLoader::LoadImageAsset(AssetPath path, SHTextureAsset& asset) void SHTextureLoader::LoadImageAsset(AssetPath path, SHTextureAsset& asset)
{ {
if (path.extension().string() == DDS_EXTENSION) if (path.extension().string() == DDS_EXTENSION)

View File

@ -15,19 +15,20 @@
#include "../SHAssetMacros.h" #include "../SHAssetMacros.h"
#include "../Asset Types/SHTextureAsset.h" #include "../Asset Types/SHTextureAsset.h"
#include "tinyddsloader.h" #include "tinyddsloader.h"
#include "SHAssetLoader.h"
namespace SHADE namespace SHADE
{ {
class SHTextureLoader class SHTextureLoader : public SHAssetLoader
{ {
private: private:
static std::string TinyDDSResultToString(tinyddsloader::Result value); std::string TinyDDSResultToString(tinyddsloader::Result value);
static vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear); vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear);
void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept;
static void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept;
public: public:
static void LoadImageAsset(AssetPath paths, SHTextureAsset& image); void LoadImageAsset(AssetPath paths, SHTextureAsset& image);
static void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept; void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept;
SHAssetData* Load(AssetPath path) override;
}; };
} }

View File

@ -12,11 +12,12 @@
#pragma once #pragma once
#include "Filesystem/SHFileSystem.h" #include "Filesystem/SHFileSystem.h"
#include "SHAssetMacros.h" #include "Assets/SHAssetMacros.h"
#include "SH_API.h"
namespace SHADE namespace SHADE
{ {
struct SHAsset struct SH_API SHAsset
{ {
AssetName name; AssetName name;
AssetID id; AssetID id;

View File

@ -32,12 +32,12 @@ typedef std::filesystem::path AssetPath;
typedef unsigned char* AssetData; typedef unsigned char* AssetData;
typedef std::string AssetMetaVersion; typedef std::string AssetMetaVersion;
typedef std::string AssetExtension; typedef std::string AssetExtension;
typedef unsigned char AssetTypeMeta; typedef size_t AssetTypeMeta;
typedef FMOD::Sound* SHSound; typedef FMOD::Sound* SHSound;
// Asset Meta Version // Asset Meta Version
#define ASSET_META_VER "1.0" constexpr std::string_view ASSET_META_VER { "1.0" };
// Asset type enum // Asset type enum
enum class AssetType : AssetTypeMeta enum class AssetType : AssetTypeMeta
@ -53,34 +53,35 @@ enum class AssetType : AssetTypeMeta
SCENE, SCENE,
PREFAB, PREFAB,
AUDIO_WAV, AUDIO_WAV,
DDS DDS,
MAX_COUNT
}; };
//Directory //Directory
#ifdef _PUBLISH #ifdef _PUBLISH
#define ASSET_ROOT "Assets" constexpr std::string_view ASSET_ROOT {"Assets"};
#else #else
#define ASSET_ROOT "../../Assets" constexpr std::string_view ASSET_ROOT {"../../Assets"};
#endif #endif
// ASSET EXTENSIONS // ASSET EXTENSIONS
#define META_EXTENSION ".shmeta" constexpr std::string_view META_EXTENSION {".shmeta"};
#define IMAGE_EXTENSION ".png" constexpr std::string_view IMAGE_EXTENSION {".png"};
#define AUDIO_EXTENSION ".ogg" constexpr std::string_view AUDIO_EXTENSION {".ogg"};
#define AUDIO_WAV_EXTENSION ".wav" constexpr std::string_view AUDIO_WAV_EXTENSION {".wav"};
#define SHADER_EXTENSION ".glsl" constexpr std::string_view SHADER_EXTENSION {".glsl"};
#define SCRIPT_EXTENSION ".cs" constexpr std::string_view SCRIPT_EXTENSION {".cs"};
#define SCENE_EXTENSION ".SHADE" constexpr std::string_view SCENE_EXTENSION {".SHADE"};
#define PREFAB_EXTENSION ".SHPrefab" constexpr std::string_view PREFAB_EXTENSION {".SHPrefab"};
#define MATERIAL_EXTENSION ".SHMat" constexpr std::string_view MATERIAL_EXTENSION {".SHMat"};
#define TEXTURE_EXTENSION ".shtex" constexpr std::string_view TEXTURE_EXTENSION {".shtex"};
#define DDS_EXTENSION ".dds" constexpr std::string_view DDS_EXTENSION {".dds"};
#define FBX_EXTENSION ".fbx" constexpr std::string_view FBX_EXTENSION {".fbx"};
#define GLTF_EXTENSION ".gltf" constexpr std::string_view GLTF_EXTENSION {".gltf"};
#define MESH_EXTENSION ".shmesh" constexpr std::string_view MESH_EXTENSION {".shmesh"};
std::string const EXTENSIONS[] = { constexpr std::string_view EXTENSIONS[] = {
AUDIO_EXTENSION, AUDIO_EXTENSION,
SHADER_EXTENSION, SHADER_EXTENSION,
MATERIAL_EXTENSION, MATERIAL_EXTENSION,
@ -96,10 +97,12 @@ std::string const EXTENSIONS[] = {
GLTF_EXTENSION GLTF_EXTENSION
}; };
constexpr size_t TYPE_COUNT {static_cast<size_t>(AssetType::MAX_COUNT) };
// Error flags // Error flags
#define FILE_NOT_FOUND_ERR "FILE NOT FOUND" constexpr std::string_view FILE_NOT_FOUND_ERR {"FILE NOT FOUND"};
#define META_NOT_FOUND_ERR "META NOT FOUND" constexpr std::string_view META_NOT_FOUND_ERR {"META NOT FOUND"};
#define ASSET_NOT_FOUND_ERR "ASSET NOT FOUND" constexpr std::string_view ASSET_NOT_FOUND_ERR {"ASSET NOT FOUND"};
#define EXT_DOES_NOT_EXIST "TYPE DOES NOT HAVE EXTENSION DEFINED" constexpr std::string_view EXT_DOES_NOT_EXIST {"TYPE DOES NOT HAVE EXTENSION DEFINED"};
#endif // !SH_ASSET_MACROS_H #endif // !SH_ASSET_MACROS_H

View File

@ -14,6 +14,7 @@
#include "SHAssetMetaHandler.h" #include "SHAssetMetaHandler.h"
#include "Filesystem/SHFileSystem.h" #include "Filesystem/SHFileSystem.h"
#include "Libraries/SHAssimpLibrary.h"
#include "Libraries/SHMeshLoader.h" #include "Libraries/SHMeshLoader.h"
#include "Libraries/SHTextureLoader.h" #include "Libraries/SHTextureLoader.h"
@ -25,11 +26,10 @@ namespace SHADE
FMOD::System* SHAssetManager::audioSystem; FMOD::System* SHAssetManager::audioSystem;
std::unordered_map<AssetID, SHSound >* SHAssetManager::audioSoundList; std::unordered_map<AssetID, SHSound >* SHAssetManager::audioSoundList;
std::vector<SHAsset> SHAssetManager::assetCollection; std::vector<SHAssetLoader*> SHAssetManager::loaders(TYPE_COUNT);
std::unordered_map<AssetID, SHAsset> SHAssetManager::assetRegistry;
std::unordered_map<AssetID, SHMeshAsset> SHAssetManager::meshCollection; std::vector<SHAsset> SHAssetManager::assetCollection;
std::unordered_map<AssetID, SHTextureAsset> SHAssetManager::textureCollection; std::unordered_map<AssetID, SHAssetData * const> SHAssetManager::assetData;
/**************************************************************************** /****************************************************************************
* \brief Static function to generate asset ID. * \brief Static function to generate asset ID.
@ -56,18 +56,15 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
void SHAssetManager::Unload() noexcept void SHAssetManager::Unload() noexcept
{ {
for (auto const& asset : assetCollection)
{
SHAssetMetaHandler::WriteMetaData(asset);
}
} }
void SHAssetManager::Unload(AssetID assetId) noexcept void SHAssetManager::Unload(AssetID assetId) noexcept
{ {
// TODO // TODO
} }
AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept
{ {
if (!IsRecognised(path.extension().string().c_str())) if (!IsRecognised(path.extension().string().c_str()))
{ {
@ -85,7 +82,37 @@ namespace SHADE
// return std::filesystem::path(); // return std::filesystem::path();
//} //}
return std::filesystem::path(ASSET_ROOT + folder + path.filename().string()); return std::filesystem::path(std::string(ASSET_ROOT) + folder + path.filename().string());
}
AssetPath SHAssetManager::GenerateNewPath(AssetName name, AssetType type)
{
std::string folder;
switch(type)
{
case AssetType::SCENE:
folder = "scenes/";
break;
case AssetType::PREFAB:
folder = "prefabs/";
break;
case AssetType::MATERIAL:
folder = "materials/";
break;
default:
folder = "/";
}
return std::filesystem::path{
std::string(ASSET_ROOT) +
folder +
name +
std::string(EXTENSIONS[static_cast<size_t>(type)])
};
} }
/**************************************************************************** /****************************************************************************
@ -121,7 +148,7 @@ namespace SHADE
// folder = ""; // folder = "";
// break; // break;
//} //}
AssetPath path{ ASSET_ROOT + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) }; AssetPath path{ std::string{ASSET_ROOT} + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) };
SHAssetMetaHandler::WriteMetaData(meta); SHAssetMetaHandler::WriteMetaData(meta);
@ -130,6 +157,19 @@ namespace SHADE
return id; return id;
} }
AssetID SHAssetManager::CreateAsset(AssetName name, AssetType type) noexcept
{
AssetID id = GenerateAssetID(type);
assetCollection.emplace_back(
name,
id,
type,
GenerateNewPath(name, type),
0
);
return id;
}
/**************************************************************************** /****************************************************************************
* \brief Import new asset from outside editor window. * \brief Import new asset from outside editor window.
* *
@ -138,7 +178,10 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
AssetID SHAssetManager::ImportNewAsset(char const* p) noexcept AssetID SHAssetManager::ImportNewAsset(char const* p) noexcept
{ {
std::filesystem::path const path{ p }; std::filesystem::path const path{ p };
auto const type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string());
auto const id = GenerateAssetID(type);
std::filesystem::path const newPath{ GenerateLocalPath(path) }; std::filesystem::path const newPath{ GenerateLocalPath(path) };
if (newPath.empty()) if (newPath.empty())
@ -149,11 +192,7 @@ namespace SHADE
std::filesystem::copy(path, newPath); std::filesystem::copy(path, newPath);
AssetID id{ RetrieveAsset(newPath.string().c_str()) }; assetCollection.push_back(CreateAssetFromPath(newPath));
if (id != 0)
{
LoadData(id);
}
return id; return id;
} }
@ -164,158 +203,14 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
void SHAssetManager::RefreshAllAssets() noexcept void SHAssetManager::RefreshAllAssets() noexcept
{ {
std::vector<AssetPath> metaFiles;
std::vector<AssetPath> AssetFiles;
//SHFileSystem::LoadAllFiles(metaFiles, AssetFiles);
//std::vector<AssetPath> AssetFilesVerified;
std::vector<AssetPath> AssetFilesNew;
for (auto const& asset : AssetFiles)
{
bool found = false;
for (auto it {metaFiles.begin()}; it != metaFiles.end(); ++it)
{
std::string fileExtCheck{ asset.filename().string() };
fileExtCheck += META_EXTENSION;
if (it->filename().string() == fileExtCheck)
{
metaFiles.erase(it);
found = true;
break;
}
}
if (!found && IsRecognised(asset.extension().string().c_str()))
{
AssetFilesNew.push_back(asset);
}
}
std::vector<SHAsset> newLoad;
newLoad.reserve(AssetFilesNew.size());
//TODO: Handle if meta does not match all assets (if meta exist and asset doesnt, vice versa)
for (auto const& file : AssetFilesNew)
{
newLoad.push_back(RegisterAssetNew(file));
}
//UpdateAllSpriteSets();
}
void SHAssetManager::LoadDataTemp(std::string p) noexcept
{
AssetPath path{ p };
if (path.extension().string() == FBX_EXTENSION
|| path.extension().string() == GLTF_EXTENSION
|| path.extension().string() == MESH_EXTENSION)
{
LoadGLTF(
{
.name {path.filename().string()},
.id {0},
.type {AssetType::MESH},
.path {path},
.location {0}
}
);
}
else if (path.extension().string() == DDS_EXTENSION
|| path.extension().string() == TEXTURE_EXTENSION)
{
LoadDDS(
{
.name {path.filename().string()},
.id {0},
.type {AssetType::DDS},
.path {path},
.location {0}
}
);
}
}
std::vector<SHMeshAsset> SHAssetManager::GetAllMeshes() noexcept
{
std::vector<SHMeshAsset> result;
for (auto const& mesh : meshCollection)
{
result.push_back(mesh.second);
}
return result;
}
std::vector<SHTextureAsset> SHAssetManager::GetAllTextures() noexcept
{
std::vector<SHTextureAsset> result;
for (auto const& dds : textureCollection)
{
result.push_back(dds.second);
}
return result;
}
SHMeshAsset const* SHAssetManager::GetMesh(AssetID id) noexcept
{
if (meshCollection.find(id) == meshCollection.end())
{
return nullptr;
}
return &meshCollection[id];
}
SHTextureAsset const* SHAssetManager::GetTexture(AssetID id) noexcept
{
if (textureCollection.find(id) == textureCollection.end())
{
return nullptr;
}
return &textureCollection[id];
}
/****************************************************************************
* \param Path for meta data file
* \param Path for asset file
* \brief Links meta data to asset in registries. Meta data should
* already exist
****************************************************************************/
void SHAssetManager::RegisterAsset(AssetPath const& metaPath, AssetPath const& path) noexcept
{
SHAsset const meta = SHAssetMetaHandler::RetrieveMetaData(metaPath);
assetCollection.push_back(meta);
}
/****************************************************************************
* \param Path for asset file
* \brief Creates new meta data for new asset.
****************************************************************************/
SHAsset SHAssetManager::RegisterAssetNew(AssetPath const& asset) noexcept
{
SHAsset meta;
meta.type = SHAssetMetaHandler::GetTypeFromExtension(asset.extension().string());
meta.id = GenerateAssetID(meta.type);
assetCollection.push_back(meta);
SHAssetMetaHandler::WriteMetaData(meta);
return assetCollection.back();
} }
bool SHAssetManager::IsRecognised(char const* ext) noexcept bool SHAssetManager::IsRecognised(char const* ext) noexcept
{ {
for (auto const& e : EXTENSIONS) for (auto const& e : EXTENSIONS)
{ {
if (strcmp(ext, e.c_str()) == 0) if (strcmp(ext, e.data()) == 0)
{ {
return true; return true;
} }
@ -324,54 +219,31 @@ namespace SHADE
return false; return false;
} }
void SHAssetManager::LoadGLTF(SHAsset asset) noexcept SHAsset SHAssetManager::CreateAssetFromPath(AssetPath path) noexcept
{ {
std::vector<SHMeshAsset> meshes; SHAsset result;
SHMeshLoader::LoadMesh(meshes, asset.path); result.name = path.stem().string();
result.type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string());
result.id = GenerateAssetID(result.type);
result.path = path;
for (auto const& mesh : meshes) return result;
{
auto id{ GenerateAssetID(AssetType::MESH) };
meshCollection.emplace(id, mesh);
AssetPath path;
if (!mesh.compiled)
{
path = SHMeshCompiler::CompileMeshBinary(mesh, asset.path);
}
assetCollection.emplace_back(
mesh.header.meshName,
id,
AssetType::MESH,
path,
0
);
}
} }
void SHAssetManager::LoadDDS(SHAsset asset) noexcept void SHAssetManager::InitLoaders() noexcept
{ {
SHTextureAsset image; loaders[static_cast<size_t>(AssetType::AUDIO)] = nullptr;
loaders[static_cast<size_t>(AssetType::SHADER)] = nullptr;
SHTextureLoader::LoadImageAsset(asset.path, image); loaders[static_cast<size_t>(AssetType::MATERIAL)] = nullptr;
loaders[static_cast<size_t>(AssetType::IMAGE)] = dynamic_cast<SHAssetLoader*>(new SHTextureLoader());
if (!image.compiled) loaders[static_cast<size_t>(AssetType::TEXTURE)] = nullptr;
{ loaders[static_cast<size_t>(AssetType::MESH)] = dynamic_cast<SHAssetLoader*>(new SHMeshLoader());
auto id{ GenerateAssetID(AssetType::TEXTURE) }; loaders[static_cast<size_t>(AssetType::SCRIPT)] = nullptr;
textureCollection.emplace(id, image); loaders[static_cast<size_t>(AssetType::SCENE)] = nullptr;
loaders[static_cast<size_t>(AssetType::PREFAB)] = nullptr;
auto path{ SHTextureCompiler::CompileTextureBinary(image, asset.path) }; loaders[static_cast<size_t>(AssetType::AUDIO_WAV)] = nullptr;
loaders[static_cast<size_t>(AssetType::DDS)] = nullptr;
assetCollection.emplace_back(
image.name,
id,
AssetType::TEXTURE,
path,
0
);
}
} }
/**************************************************************************** /****************************************************************************
@ -379,8 +251,9 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
void SHAssetManager::Load() noexcept void SHAssetManager::Load() noexcept
{ {
RetrieveAssets(); InitLoaders();
LoadAllData(); BuildAssetCollection();
//LoadAllData();
} }
/**************************************************************************** /****************************************************************************
@ -388,143 +261,40 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
void SHAssetManager::LoadAllData() noexcept void SHAssetManager::LoadAllData() noexcept
{ {
//TODO Remove when on demand loading is done
for (auto const& asset : assetCollection) for (auto const& asset : assetCollection)
{ {
switch (asset.type) SHAssetData* data = loaders[static_cast<size_t>(asset.type)]->Load(asset.path);
{ assetData.emplace(asset.id, data);
case AssetType::MESH:
meshCollection.emplace(asset.id, SHMeshAsset());
SHMeshLoader::LoadSHMesh(meshCollection[asset.id], asset.path);
break;
case AssetType::TEXTURE:
textureCollection.emplace(asset.id, SHTextureAsset());
SHTextureLoader::LoadSHTexture(asset.path, textureCollection[asset.id]);
break;
default:
void;
}
} }
} }
void SHAssetManager::LoadData(AssetID id) noexcept SHAssetData* SHAssetManager::LoadData(SHAsset const& asset) noexcept
{ {
(void)id; SHAssetData* data = loaders[static_cast<size_t>(asset.type)]->Load(asset.path);
}
/**************************************************************************** if (data == nullptr)
* \brief Retrieve all asset files and meta files from filesystem
****************************************************************************/
void SHAssetManager::RetrieveAssets() noexcept
{
std::vector<AssetPath> metaFiles;
std::vector<AssetPath> AssetFiles;
for (auto const dir : std::filesystem::recursive_directory_iterator(ASSET_ROOT))
{ {
if (dir.path().extension().string() == META_EXTENSION) SHLOG_ERROR("Unable to load asset into memory: {}\n", asset.path.string());
{
auto meta{ SHAssetMetaHandler::RetrieveMetaData(dir.path()) };
assetCollection.push_back(meta);
assetRegistry.emplace(meta.id, meta);
}
}
//TODO: Write new function for file manager to loop through all files
//SHFileSystem::StartupFillDirectories(ASSET_ROOT);
//FolderPointer rootFolder = SHFileSystem::GetRoot();
//for (auto const& meta : metaFiles)
//{
// for (std::vector<AssetPath>::const_iterator it{ AssetFiles.cbegin() };
// it != AssetFiles.cend();
// ++it)
// {
// // Asset exists for meta file
// std::string fileExtCheck{ it->filename().string() };
// fileExtCheck += META_EXTENSION;
// if (meta.filename().string() == fileExtCheck)
// {
// RegisterAsset(meta, *it);
// AssetFiles.erase(it);
// break;
// }
// }
//}
//TODO: Handle if meta does not match all assets (if meta exist and asset doesnt, vice versa)
//for (auto const& file : AssetFiles)
//{
// if (IsRecognised(file.extension().string().c_str()))
// {
// SHAssetMetaHandler::WriteMetaData(RegisterAssetNew(file));
// }
// else
// {
// std::cout << "Unsupported File Format: " << file.filename() << "\n";
// }
//}
}
AssetID SHAssetManager::RetrieveAsset(char const* path) noexcept
{
std::filesystem::path p{ path };
if (IsRecognised(p.extension().string().c_str()))
{
SHAsset const& meta{ RegisterAssetNew(p) };
SHAssetMetaHandler::WriteMetaData(meta);
return meta.id;
} }
else else
{ {
std::cout << "Unsupported File Format: " << p.filename() << "\n"; assetData.emplace(asset.id, data);
} }
// Assert that file imported is not recognised return data;
return 0;
} }
/**************************************************************************** void SHAssetManager::BuildAssetCollection() noexcept
* \param Full path of file
* \brief Extracts file name from path. Formats file name into readable
* with spaces and capitalises first letter of every word
****************************************************************************/
AssetName SHAssetManager::GetNameFromPath(AssetPath filepath) noexcept
{ {
std::string name{ filepath.filename().string() }; for (auto const& dir : std::filesystem::recursive_directory_iterator{ASSET_ROOT})
name = name.substr(0, name.find_last_of('.')); {
if (dir.is_regular_file())
//if (name[0] <= 122 && name[0] >= 97) {
//{ if (dir.path().extension().string() == META_EXTENSION.data())
// name[0] -= 32; {
//} assetCollection.push_back(SHAssetMetaHandler::RetrieveMetaData(dir.path()));
}
//for (size_t i{ 1 }; i < name.length(); ++i) }
//{ }
// // Replace all underscores with spaces
// if (name[i] == '_')
// {
// name[i] = ' ';
// continue;
// }
// if (name[i + 1] <= 'Z' && name[i + 1] >= 'A'
// && name[i] <= 'z' && name[i] >= 'a')
// {
// name.insert(i + 1, 1, ' ');
// continue;
// }
// if (name[i - 1] == ' ' && name[i] <= 'z' && name[i] >= 'a')
// {
// name[i] -= 32;
// }
//}
return name;
} }
} }

View File

@ -11,9 +11,10 @@
#pragma once #pragma once
#include "tinyddsloader.h" #include "tinyddsloader.h"
#include "SHAsset.h" #include "SHAsset.h"
#include "Asset Types/SHAssetData.h"
#include "Libraries/SHAssetLoader.h"
#include <memory>
#include "Asset Types/SHMeshAsset.h"
#include "Asset Types/SHTextureAsset.h"
#include "SH_API.h" #include "SH_API.h"
namespace SHADE namespace SHADE
@ -28,6 +29,8 @@ namespace SHADE
static AssetPath GenerateLocalPath(AssetPath path) noexcept; static AssetPath GenerateLocalPath(AssetPath path) noexcept;
static AssetPath GenerateNewPath(AssetName name, AssetType type);
/**************************************************************************** /****************************************************************************
* \brief Deallocate all memory used by resource data * \brief Deallocate all memory used by resource data
****************************************************************************/ ****************************************************************************/
@ -55,6 +58,7 @@ namespace SHADE
* \return resource id generated for new asset * \return resource id generated for new asset
****************************************************************************/ ****************************************************************************/
static AssetID CreateNewAsset(AssetType, AssetName) noexcept; static AssetID CreateNewAsset(AssetType, AssetName) noexcept;
static AssetID CreateAsset(AssetName name, AssetType type) noexcept;
/**************************************************************************** /****************************************************************************
* \brief Import new resource from outside editor window. * \brief Import new resource from outside editor window.
@ -71,66 +75,33 @@ namespace SHADE
static void RefreshAllAssets() noexcept; static void RefreshAllAssets() noexcept;
// -------------------------------------------------------------------------/ // -------------------------------------------------------------------------/
//TODO: TEMPORARY FOR TESTING GLTF & DDS template<typename T>
static void LoadDataTemp(std::string path) noexcept; static std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> GetData(AssetID id) noexcept;
static std::vector<SHMeshAsset> GetAllMeshes() noexcept;
static std::vector<SHTextureAsset> GetAllTextures() noexcept;
static SHMeshAsset const* GetMesh(AssetID id) noexcept;
static SHTextureAsset const* GetTexture(AssetID id) noexcept;
private: private:
/**************************************************************************** /****************************************************************************
* \brief Load resource data into memory * \brief Load resource data into memory
****************************************************************************/ ****************************************************************************/
static void LoadAllData() noexcept; static void LoadAllData() noexcept;
static void LoadData(AssetID id) noexcept; static SHAssetData* LoadData(SHAsset const& asset) noexcept;
/**************************************************************************** inline static void BuildAssetCollection() noexcept;
* \brief Retrieve all resource files and meta files from filesystem
****************************************************************************/
static void RetrieveAssets() noexcept;
static AssetID RetrieveAsset(char const* path) noexcept;
/****************************************************************************
* \param Full path of file
* \brief Extracts file name from path. Formats file name into readable
* with spaces and capitalises first letter of every word
****************************************************************************/
static AssetName GetNameFromPath(AssetPath) noexcept;
/****************************************************************************
* \param Path for meta data file
* \param Path for resource file
* \brief Links meta data to resource in registries. Meta data should
* already exist
****************************************************************************/
static void RegisterAsset(AssetPath const&, AssetPath const&) noexcept;
/****************************************************************************
* \param Path for resource file
* \brief Creates new meta data for new resource.
****************************************************************************/
static SHAsset RegisterAssetNew(AssetPath const&) noexcept;
static bool IsRecognised(char const*) noexcept; static bool IsRecognised(char const*) noexcept;
static SHAsset CreateAssetFromPath(AssetPath path) noexcept;
// Specialised load calls static void InitLoaders() noexcept;
static void LoadGLTF(SHAsset asset) noexcept;
static void LoadDDS(SHAsset asset) noexcept;
static FMOD::System* audioSystem; static FMOD::System* audioSystem;
static std::unordered_map<AssetID,SHSound>* audioSoundList; static std::unordered_map<AssetID,SHSound>* audioSoundList;
static std::vector<SHAssetLoader*> loaders;
// For all resources // For all resources
static std::vector<SHAsset> assetCollection; static std::vector<SHAsset> assetCollection;
static std::unordered_map<AssetID, SHAsset> assetRegistry; static std::unordered_map<AssetID, SHAssetData * const> assetData;
static std::unordered_map<AssetID, SHMeshAsset> meshCollection;
static std::unordered_map<AssetID, SHTextureAsset> textureCollection;
}; };
} }
#include "SHAssetManager.hpp"

View File

@ -0,0 +1,26 @@
#include "SHAssetManager.h"
namespace SHADE
{
template<typename T>
std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> SHAssetManager::GetData(AssetID id) noexcept
{
if (!assetData.contains(id))
{
for (auto const& asset : assetCollection)
{
if (asset.id == id)
{
assetData.emplace(id, LoadData(asset));
return dynamic_cast<T const* const>(assetData[id]);
}
}
SHLOG_ERROR("Asset ID provided does not exist: {}", id);
return nullptr;
}
return dynamic_cast<T const* const>(assetData[id]);
}
}

View File

@ -37,7 +37,7 @@ namespace SHADE
{ {
for (int i{0}; i < EXTENSIONS->size(); ++i) for (int i{0}; i < EXTENSIONS->size(); ++i)
{ {
if (ext == EXTENSIONS[i]) if (strcmp(ext.c_str(), EXTENSIONS[i].data()) == 0)
{ {
return static_cast<AssetType>(i); return static_cast<AssetType>(i);
} }
@ -53,7 +53,7 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
AssetExtension SHAssetMetaHandler::GetExtensionFromType(AssetType type) noexcept AssetExtension SHAssetMetaHandler::GetExtensionFromType(AssetType type) noexcept
{ {
return EXTENSIONS[static_cast<size_t>(type)]; return AssetExtension(EXTENSIONS[static_cast<size_t>(type)]);
} }
/**************************************************************************** /****************************************************************************
@ -124,16 +124,6 @@ namespace SHADE
metaFile << "ID: " << meta.id << "\n"; metaFile << "ID: " << meta.id << "\n";
metaFile << "Type: " << static_cast<AssetTypeMeta>(meta.type) << std::endl; metaFile << "Type: " << static_cast<AssetTypeMeta>(meta.type) << std::endl;
////TODO Add in information that is specific to types like mesh
//switch(meta.type)
//{
//case AssetType::MESH:
// break;
//default:
// break;
//}
metaFile.close(); metaFile.close();
} }

View File

@ -140,10 +140,11 @@ namespace SHADE
{ {
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(camera.GetEID()); auto transform = SHComponentManager::GetComponent<SHTransformComponent>(camera.GetEID());
SHVec3 rotation = transform->GetWorldRotation(); SHVec3 rotation = transform->GetWorldRotation();
camera.pitch = rotation.x; camera.pitch = SHMath::RadiansToDegrees(rotation.x);
camera.yaw = rotation.y; camera.yaw = SHMath::RadiansToDegrees(rotation.y);
camera.roll = rotation.z; camera.roll = SHMath::RadiansToDegrees(rotation.z);
camera.position = transform->GetWorldPosition(); camera.position = transform->GetWorldPosition();
camera.dirtyView = true;
} }

View File

@ -0,0 +1,84 @@
#include "SHpch.h"
#include "SHAssetBrowser.h"
#include "Editor/IconsMaterialDesign.h"
#include "Editor/SHImGuiHelpers.hpp"
#include <imgui.h>
#include "Assets/SHAssetManager.h"
#include "Editor/DragDrop/SHDragDrop.hpp"
namespace SHADE
{
SHAssetBrowser::SHAssetBrowser()
:SHEditorWindow("\xee\x8b\x87 Asset Browser", ImGuiWindowFlags_MenuBar)
{
}
void SHAssetBrowser::Init()
{
SHEditorWindow::Init();
}
void SHAssetBrowser::Update()
{
SHEditorWindow::Update();
if(Begin())
{
DrawMenuBar();
auto const& assets = SHAssetManager::GetAllAssets();
if(ImGui::BeginTable("AssetBrowserTable", 3))
{
ImGui::TableNextColumn();
ImGui::TableHeader("Asset ID");
ImGui::TableNextColumn();
ImGui::TableHeader("Name");
ImGui::TableNextColumn();
ImGui::TableHeader("Type");
for(SHAsset const& asset : assets)
{
DrawAsset(asset);
}
ImGui::EndTable();
}
}
ImGui::End();
}
void SHAssetBrowser::DrawMenuBar()
{
if(ImGui::BeginMenuBar())
{
ImGui::EndMenuBar();
}
}
void SHAssetBrowser::DrawAsset(SHAsset const& asset)
{
ImGui::PushID(asset.id);
ImGui::BeginGroup();
ImGui::TableNextColumn();
ImGui::Selectable(std::format("{}", asset.id).data(), false, ImGuiSelectableFlags_SpanAllColumns);
if(SHDragDrop::BeginSource())
{
auto id = asset.id;
ImGui::Text("Moving Asset: %zu", id);
SHDragDrop::SetPayload<AssetID>(DRAG_RESOURCE, &id);
SHDragDrop::EndSource();
}
ImGui::TableNextColumn();
ImGui::Text("%s", asset.name.c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", "Type");
ImGui::EndGroup();
ImGui::PopID();
}
}

View File

@ -0,0 +1,24 @@
#pragma once
#include "Assets/SHAsset.h"
#include "Editor/EditorWindow/SHEditorWindow.h"
namespace SHADE
{
class SHAssetBrowser final : public SHEditorWindow
{
public:
SHAssetBrowser();
void Init();
void Update();
void Refresh();
private:
void DrawMenuBar();
void DrawAsset(SHAsset const& asset);
float idColumnWidth, nameColumnWidth, typeColumnWidth;
};
}

View File

@ -93,8 +93,7 @@ namespace SHADE
{ {
if (ImGui::BeginMenuBar()) if (ImGui::BeginMenuBar())
{ {
ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x * 0.75f);
ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x - 35.0f);
if(ImGui::SmallButton(ICON_MD_DESELECT)) if(ImGui::SmallButton(ICON_MD_DESELECT))
{ {
auto editor = SHSystemManager::GetSystem<SHEditor>(); auto editor = SHSystemManager::GetSystem<SHEditor>();

View File

@ -39,6 +39,10 @@ namespace SHADE
{ {
SHComponentManager::RemoveComponent<T>(component->GetEID()); SHComponentManager::RemoveComponent<T>(component->GetEID());
} }
if (ImGui::Selectable(std::format("{} Reset {}", ICON_MD_RESTART_ALT, componentName.data()).data()))
{
*component = T();
}
ImGui::EndPopup(); ImGui::EndPopup();
} }
} }
@ -48,7 +52,7 @@ namespace SHADE
if (!component) if (!component)
return; return;
const auto componentType = rttr::type::get(*component); const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data())) if (ImGui::CollapsingHeader(componentType.get_name().data()))
{ {
@ -89,7 +93,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
if (metaMin && metaMax) if (metaMin && metaMax)
{ {
SHEditorWidgets::SliderInt(property.get_name().data(), metaMin.template get_value<int>(), metaMin.template get_value<int>(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); }); SHEditorWidgets::SliderInt(property.get_name().data(), metaMin.template get_value<int>(), metaMax.template get_value<int>(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); });
} }
else else
{ {
@ -115,7 +119,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid()) if (metaMin.is_valid() && metaMax.is_valid())
{ {
SHEditorWidgets::SliderScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value<uint16_t>(), metaMin.template get_value<uint16_t>(), [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, "%zu"); SHEditorWidgets::SliderScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value<uint16_t>(), metaMax.template get_value<uint16_t>(), [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, "%zu");
} }
else else
{ {
@ -128,7 +132,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid()) if (metaMin.is_valid() && metaMax.is_valid())
{ {
SHEditorWidgets::SliderScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value<uint32_t>(), metaMin.template get_value<uint32_t>(), [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, "%zu"); SHEditorWidgets::SliderScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value<uint32_t>(), metaMax.template get_value<uint32_t>(), [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, "%zu");
} }
else else
{ {
@ -141,7 +145,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid()) if (metaMin.is_valid() && metaMax.is_valid())
{ {
SHEditorWidgets::SliderScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value<uint64_t>(), metaMin.template get_value<uint64_t>(), [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, "%zu"); SHEditorWidgets::SliderScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value<uint64_t>(), metaMax.template get_value<uint64_t>(), [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, "%zu");
} }
else else
{ {
@ -152,13 +156,18 @@ namespace SHADE
{ {
auto metaMin = property.get_metadata(META::min); auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
float min{}, max{};
if(metaMin.is_valid())
min = std::max(metaMin.template get_value<float>(), -FLT_MAX * 0.5f);
if(metaMax.is_valid())
max = std::min(metaMax.template get_value<float>(), FLT_MAX * 0.5f);
if (metaMin.is_valid() && metaMax.is_valid()) if (metaMin.is_valid() && metaMax.is_valid())
{ {
SHEditorWidgets::SliderFloat(property.get_name().data(), metaMin.template get_value<float>(), metaMin.template get_value<float>(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); }); SHEditorWidgets::SliderFloat(property.get_name().data(), min, max, [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); });
} }
else else
{ {
SHEditorWidgets::DragFloat(property.get_name().data(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); }); SHEditorWidgets::DragFloat(property.get_name().data(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); }, "Test");
} }
} }
else if (type == rttr::type::get<double>()) else if (type == rttr::type::get<double>())
@ -167,7 +176,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid()) if (metaMin.is_valid() && metaMax.is_valid())
{ {
SHEditorWidgets::SliderScalar<double>(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value<double>(), metaMin.template get_value<double>(), [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); }); SHEditorWidgets::SliderScalar<double>(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value<double>(), metaMax.template get_value<double>(), [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); });
} }
else else
{ {

View File

@ -35,6 +35,23 @@ 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>
bool DrawAddComponentWithEnforcedComponentButton(EntityID const& eid)
{
bool selected = false;
if (!SHComponentManager::HasComponent<ComponentType>(eid))
{
if(selected = ImGui::Selectable(std::format("Add {}", rttr::type::get<ComponentType>().get_name().data()).data()); selected)
{
if(SHComponentManager::GetComponent_s<EnforcedComponent>(eid) == nullptr)
SHComponentManager::AddComponent<EnforcedComponent>(eid);
SHComponentManager::AddComponent<ComponentType>(eid);
}
}
return selected;
}
SHEditorInspector::SHEditorInspector() SHEditorInspector::SHEditorInspector()
:SHEditorWindow("Inspector", ImGuiWindowFlags_MenuBar) :SHEditorWindow("Inspector", ImGuiWindowFlags_MenuBar)
{ {
@ -84,21 +101,19 @@ namespace SHADE
} }
ImGui::Separator(); ImGui::Separator();
// Render Scripts // Render Scripts
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>()); SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->RenderScriptsInInspector(eid); scriptEngine->RenderScriptsInInspector(eid);
ImGui::Separator(); ImGui::Separator();
if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data())) if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data()))
{ {
DrawAddComponentButton<SHTransformComponent>(eid); DrawAddComponentButton<SHTransformComponent>(eid);
DrawAddComponentButton<SHRenderable>(eid);
DrawAddComponentButton<SHColliderComponent>(eid); // Components that require Transforms
if(DrawAddComponentButton<SHRigidBodyComponent>(eid))
{ DrawAddComponentWithEnforcedComponentButton<SHRenderable, SHTransformComponent>(eid);
if(SHComponentManager::GetComponent_s<SHTransformComponent>(eid) == nullptr) DrawAddComponentWithEnforcedComponentButton<SHRigidBodyComponent, SHTransformComponent>(eid);
{ DrawAddComponentWithEnforcedComponentButton<SHColliderComponent, SHTransformComponent>(eid);
SHComponentManager::AddComponent<SHTransformComponent>(eid);
}
}
ImGui::EndMenu(); ImGui::EndMenu();
} }

View File

@ -3,4 +3,5 @@
#include "HierarchyPanel/SHHierarchyPanel.h" //Hierarchy Panel #include "HierarchyPanel/SHHierarchyPanel.h" //Hierarchy Panel
#include "Inspector/SHEditorInspector.h" //Inspector #include "Inspector/SHEditorInspector.h" //Inspector
#include "Profiling/SHEditorProfiler.h" //Profiler #include "Profiling/SHEditorProfiler.h" //Profiler
#include "ViewportWindow/SHEditorViewport.h" //Editor Viewport #include "ViewportWindow/SHEditorViewport.h" //Editor Viewport
#include "AssetBrowser/SHAssetBrowser.h" //Asset Browser

View File

@ -24,12 +24,13 @@ namespace SHADE
void SHEditorViewport::Init() void SHEditorViewport::Init()
{ {
SHEditorWindow::Init(); SHEditorWindow::Init();
transformGizmo.Init();
} }
void SHEditorViewport::Update() void SHEditorViewport::Update()
{ {
SHEditorWindow::Update(); SHEditorWindow::Update();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f,0.0f));
if(Begin()) if(Begin())
{ {
ImGuizmo::SetDrawlist(); ImGuizmo::SetDrawlist();
@ -55,7 +56,7 @@ namespace SHADE
ImGuizmo::SetRect(beginCursorPos.x , beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y); ImGuizmo::SetRect(beginCursorPos.x , beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y);
transformGizmo.Draw(); transformGizmo.Draw();
ImGui::End(); ImGui::End();
ImGui::PopStyleVar();
} }
void SHEditorViewport::Exit() void SHEditorViewport::Exit()

View File

@ -13,6 +13,12 @@
#include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h" #include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h"
namespace SHADE namespace SHADE
{ {
void SHTransformGizmo::Init()
{
auto& style = ImGuizmo::GetStyle();
style.RotationLineThickness = 2.5f;
}
void SHTransformGizmo::Draw() void SHTransformGizmo::Draw()
{ {
bool justChangedTfm = false; bool justChangedTfm = false;
@ -26,9 +32,12 @@ namespace SHADE
SHMatrix view = SHMatrix::Transpose(editorCamera->GetViewMatrix()); SHMatrix view = SHMatrix::Transpose(editorCamera->GetViewMatrix());
SHMatrix proj = SHMatrix::Transpose(editorCamera->GetProjMatrix()); SHMatrix proj = SHMatrix::Transpose(editorCamera->GetProjMatrix());
//Invert projection y-axis
proj(1, 1) *= -1; proj(1, 1) *= -1;
static SHMatrix gridMat = SHMatrix::Translate(0, -0.5f, 0.f) * SHMatrix::Identity; static SHMatrix gridMat = SHMatrix::Translate(0, -0.5f, 0.f) * SHMatrix::Identity;
//ImGuizmo::DrawGrid(&view._11, &proj._11, &gridMat._11, 100.f);
if (selectedEntityTransformComponent == nullptr) if (selectedEntityTransformComponent == nullptr)
{ {
SHEditor* editor = SHSystemManager::GetSystem<SHEditor>(); SHEditor* editor = SHSystemManager::GetSystem<SHEditor>();
@ -55,31 +64,37 @@ namespace SHADE
return; return;
SHMatrix mat = selectedEntityTransformComponent->GetTRS(); SHMatrix mat = selectedEntityTransformComponent->GetTRS();
isManipulating = ImGuizmo::Manipulate(&view._11, &proj._11, static_cast<ImGuizmo::OPERATION>(operation), ImGuizmo::MODE::WORLD, &mat._11); useSnap = ImGui::IsKeyDown(ImGuiKey_LeftCtrl);
if (!justChangedTfm) if(useSnap)
{ {
if (ImGui::IsItemClicked()) switch (operation)
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = std::move(selectedEntityTransformComponent)](SHMatrix const& mtx) {
{ case Operation::TRANSLATE: snap = &translationSnap.x; break;
if (!tfm) case Operation::ROTATE: snap = &rotationSnap; break;
return; case Operation::SCALE: snap = &scaleSnap; break;
SHVec3 translate{}, rotate{}, scale{}; default: snap = &translationSnap.x;
mtx.Decompose(translate, rotate, scale); }
tfm->SetWorldPosition(translate);
tfm->SetWorldRotation(rotate);
tfm->SetWorldScale(scale);
})));
else if (ImGui::IsItemHovered(ImGuiMouseButton_Left) && ImGui::IsMouseDown(ImGuiMouseButton_Left) && isManipulating)
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = std::move(selectedEntityTransformComponent)](SHMatrix const& mtx)
{
if (!tfm)
return;
SHVec3 translate{}, rotate{}, scale{};
mtx.Decompose(translate, rotate, scale);
tfm->SetWorldPosition(translate);
tfm->SetWorldRotation(rotate);
tfm->SetWorldScale(scale);
})), true);
} }
ImGuizmo::Manipulate(&view._11, &proj._11, static_cast<ImGuizmo::OPERATION>(operation), ImGuizmo::MODE::WORLD, &mat._11, nullptr, useSnap ? snap : nullptr);
static bool startRecording = false;
if (!justChangedTfm && ImGuizmo::IsUsing())
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = (selectedEntityTransformComponent)](SHMatrix const& mtx)
{
if (!tfm)
return;
SHVec3 translate{}, rotate{}, scale{};
mtx.Decompose(translate, rotate, scale);
tfm->SetWorldPosition(translate);
tfm->SetWorldRotation(rotate);
tfm->SetWorldScale(scale);
})), startRecording);
if(!startRecording)
startRecording = true;
}
isManipulating = ImGuizmo::IsUsing() || startRecording;
if(startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
startRecording = false;
} }
} }

View File

@ -37,11 +37,17 @@ namespace SHADE
UNIVERSAL = TRANSLATE | ROTATE | SCALEU UNIVERSAL = TRANSLATE | ROTATE | SCALEU
}; };
void Init();
void Draw(); void Draw();
bool isManipulating = false; bool isManipulating = false;
bool useSnap = false;
Mode mode = Mode::WORLD; Mode mode = Mode::WORLD;
Operation operation = Operation::TRANSLATE; Operation operation = Operation::TRANSLATE;
private: private:
float scaleSnap = 0.25f;
float rotationSnap = 1.0f;
SHVec3 translationSnap = SHVec3(0.25f, 0.25f, 0.25f);
float* snap = nullptr;
SHTransformComponent* selectedEntityTransformComponent{nullptr}; SHTransformComponent* selectedEntityTransformComponent{nullptr};
SHCameraComponent* editorCamera{nullptr}; SHCameraComponent* editorCamera{nullptr};
}; };

View File

@ -92,6 +92,7 @@ namespace SHADE
SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>(); SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>();
SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>(); SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>();
SHEditorWindowManager::CreateEditorWindow<SHEditorProfiler>(); SHEditorWindowManager::CreateEditorWindow<SHEditorProfiler>();
SHEditorWindowManager::CreateEditorWindow<SHAssetBrowser>();
SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>(); SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>();
io = &ImGui::GetIO(); io = &ImGui::GetIO();
@ -134,7 +135,7 @@ namespace SHADE
} }
} }
PollPicking(); //PollPicking();
if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z)) if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z))
{ {

View File

@ -40,7 +40,6 @@ namespace SHADE
{ {
ImGui::BeginGroup(); ImGui::BeginGroup();
auto cursorPos = ImGui::GetCursorScreenPos();
auto itemSpacing = ImGui::GetStyle().ItemSpacing; auto itemSpacing = ImGui::GetStyle().ItemSpacing;
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
@ -158,7 +157,7 @@ namespace SHADE
} }
template <typename T, std::size_t N> template <typename T, std::size_t N>
static bool DragN(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, static bool DragN(const std::string& label, std::vector<std::string>const& componentLabels,
std::vector<T*> values, float speed = 0.1f, const char* displayFormat = "", T valueMin = T(), T valueMax = T(), std::vector<T*> values, float speed = 0.1f, const char* displayFormat = "", T valueMin = T(), T valueMax = T(),
ImGuiSliderFlags flags = 0, bool* isHovered = nullptr) ImGuiSliderFlags flags = 0, bool* isHovered = nullptr)
{ {
@ -169,13 +168,13 @@ namespace SHADE
const ImGuiContext& g = *GImGui; const ImGuiContext& g = *GImGui;
bool valueChanged = false; bool valueChanged = false;
ImGui::BeginGroup(); ImGui::BeginGroup();
ImGui::PushID(fieldLabel.c_str()); ImGui::PushID(label.c_str());
PushMultiItemsWidthsAndLabels(componentLabels, 0.0f); PushMultiItemsWidthsAndLabels(componentLabels, 0.0f);
ImGui::BeginColumns("DragVecCol", 2, ImGuiOldColumnFlags_NoBorder | ImGuiOldColumnFlags_NoResize); ImGui::BeginColumns("DragVecCol", 2, ImGuiOldColumnFlags_NoBorder | ImGuiOldColumnFlags_NoResize);
ImGui::SetColumnWidth(-1, 80.0f); ImGui::SetColumnWidth(-1, 80.0f);
ImGui::Text(fieldLabel.c_str()); ImGui::Text(label.c_str());
if (isHovered) if (isHovered)
*isHovered = ImGui::IsItemHovered(); *isHovered = ImGui::IsItemHovered();
ImGui::NextColumn(); ImGui::NextColumn();
for (std::size_t i = 0; i < N; ++i) for (std::size_t i = 0; i < N; ++i)
{ {
@ -203,75 +202,91 @@ namespace SHADE
return valueChanged; return valueChanged;
} }
static bool DragVec2(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec2(void)> get, static bool DragVec2(const std::string& label, std::vector<std::string>const& componentLabels, std::function<SHVec2(void)> get,
std::function<void(SHVec2)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f, std::function<void(SHVec2)> set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f,
ImGuiSliderFlags flags = 0) ImGuiSliderFlags flags = 0)
{ {
SHVec2 values = get(); SHVec2 values = get();
bool changed = false; bool const changed = DragN<float, 2>(label, componentLabels, { &values.x, &values.y }, speed, displayFormat, valueMin, valueMax, flags);
if (DragN<float, 2>(fieldLabel, componentLabels, { &values.x, &values.y }, speed, displayFormat, valueMin, valueMax, flags)) static bool startRecording = false;
{
changed = true;
}
if (changed) if (changed)
{ {
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left)) SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), startRecording);
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false); if (!startRecording)
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) startRecording = true;
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), true); }
else if (ImGui::IsItemDeactivatedAfterEdit()) if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false); startRecording = false;
if(!tooltip.empty())
{
if(ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
} }
return changed; return changed;
} }
static bool DragVec3(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec3(void)> get, static bool DragVec3(const std::string& label, std::vector<std::string>const& componentLabels, std::function<SHVec3(void)> get,
std::function<void(SHVec3)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f, std::function<void(SHVec3)> set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f,
ImGuiSliderFlags flags = 0) ImGuiSliderFlags flags = 0)
{ {
SHVec3 values = get(); SHVec3 values = get();
bool changed = false; bool const changed = DragN<float, 3>(label, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags);
if (DragN<float, 3>(fieldLabel, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags))
{
changed = true;
}
static bool startRecording = false;
if (changed) if (changed)
{ {
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) SHVec3 old = get();
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false); SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(old, values, set)), startRecording);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) if (!startRecording)
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), true); startRecording = true;
else if (ImGui::IsItemDeactivatedAfterEdit()) }
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false); if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
startRecording = false;
}
if(!tooltip.empty())
{
if(ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
} }
return changed; return changed;
} }
static bool DragVec4(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec4(void)> get, static bool DragVec4(const std::string& label, std::vector<std::string>const& componentLabels, std::function<SHVec4(void)> get,
std::function<void(SHVec4)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f, std::function<void(SHVec4)> set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f,
ImGuiSliderFlags flags = 0) ImGuiSliderFlags flags = 0)
{ {
SHVec4 values = get(); SHVec4 values = get();
bool changed = false; bool const changed = DragN<float, 4>(label, componentLabels, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags);
if (DragN<float, 4>(fieldLabel, componentLabels, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags)) static bool startRecording = false;
{
changed = true;
}
if (changed) if (changed)
{ {
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), startRecording);
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), false); if (!startRecording)
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) startRecording = true;
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), true); }
else if (ImGui::IsItemDeactivatedAfterEdit()) if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), false); {
startRecording = false;
}
if(!tooltip.empty())
{
if(ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
} }
return changed; return changed;
} }
@ -279,173 +294,325 @@ namespace SHADE
//|| Widget Extensions || //|| Widget Extensions ||
//#==============================================================# //#==============================================================#
static bool CheckBox(std::string const& label, std::function<bool(void)> get, std::function<void(bool const&)> set) static void TextLabel(std::string_view const& text, bool sameLine = true)
{
const ImVec2 textSize = ImGui::CalcTextSize(text.data(), NULL, true);
if(textSize.x > 0.0f)
{
ImGui::Text(text.data());
ImGui::SameLine();
}
}
static bool CheckBox(std::string_view const& label, std::function<bool(void)> get, std::function<void(bool const&)> set, std::string_view const& tooltip = {})
{ {
bool value = get(); bool value = get();
if (ImGui::Checkbox(label.c_str(), &value)) ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
if (ImGui::Checkbox("##", &value))
{ {
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<bool>>(get(), value, set)), false); SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<bool>>(get(), value, set)), false);
return true; return true;
} }
ImGui::PopID();
ImGui::EndGroup();
if(!tooltip.empty())
{
if(ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return false; return false;
} }
template<typename T> template<typename T>
static bool RadioButton(std::vector<std::string> const& listLabels, std::vector<T> const& listTypes, std::function<T(void)> get, std::function<void(T const&)> set) static bool RadioButton(std::vector<std::string> const& label, std::vector<T> const& listTypes, std::function<T(void)> get, std::function<void(T const&)> set ,std::string_view const& tooltip = {})
{ {
T type = get(); T type = get();
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
for (size_t i = 0; i < listTypes.size(); i++) for (size_t i = 0; i < listTypes.size(); i++)
{ {
if (ImGui::RadioButton(listLabels[i].c_str(), type == listTypes[i])) if (ImGui::RadioButton(label[i].c_str(), type == listTypes[i]))
{ {
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), listTypes[i], set)), false); SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), listTypes[i], set)), false);
} }
ImGui::SameLine(); ImGui::SameLine();
} }
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return true; return true;
} }
static bool InputText(const std::string& label, const std::function<std::string(void)> get, static bool InputText(const std::string& label, const std::function<std::string(void)> get,
const std::function<void(std::string)> set, ImGuiInputTextFlags flag = 0, const std::function<void(std::string)> set, std::string_view const& tooltip = {},
ImGuiInputTextCallback callback = (ImGuiInputTextCallback)0, void* userData = (void*)0) ImGuiInputTextFlags flag = 0, ImGuiInputTextCallback callback = (ImGuiInputTextCallback)0, void* userData = (void*)0)
{ {
std::string text = get(); std::string text = get();
if (ImGui::InputText(label.c_str(), &text, flag, callback, userData)) ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
if (ImGui::InputText("##", &text, flag, callback, userData))
{ {
if (ImGui::IsItemDeactivatedAfterEdit()) if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<std::string>>(get(), text, set)), false); SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<std::string>>(get(), text, set)), false);
return true; return true;
} }
return false; ImGui::PopID();
} ImGui::EndGroup();
if (!tooltip.empty())
template <typename T>
static bool DragScalar(const std::string& fieldLabel, ImGuiDataType data_type, std::function<T(void)> get, std::function<void(T const&)> set,
float speed = 1.0f, T p_min = T(), T p_max = T(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{
T value = get();
std::cout << value << " \n";
//bool hasChange = ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags);
if (ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags))
{ {
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left)) if (ImGui::IsItemHovered())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false); {
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) ImGui::BeginTooltip();
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), true); ImGui::Text(tooltip.data());
else if (ImGui::IsItemDeactivatedAfterEdit()) ImGui::EndTooltip();
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false); }
return true;
} }
return false; return false;
} }
static bool DragFloat(const std::string& fieldLabel, std::function<float(void)> get, std::function<void(float const&)> set, template <typename T>
static bool DragScalar(const std::string& label, ImGuiDataType data_type, std::function<T(void)> get, std::function<void(T const&)> set,
float speed = 1.0f, T p_min = T(), T p_max = T(), const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, ImGuiSliderFlags flags = 0)
{
T value = get();
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
const bool hasChange = ImGui::DragScalar("##", data_type, &value, speed, &p_min, &p_max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), startRecording);
if (!startRecording)
startRecording = true;
}
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
startRecording = false;
}
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return hasChange;
}
static bool DragFloat(const std::string_view& label, std::function<float(void)> get, std::function<void(float const&)> set, std::string_view const& tooltip = {},
float speed = 0.1f, float p_min = float(), float p_max = float(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0) float speed = 0.1f, float p_min = float(), float p_max = float(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{ {
float value = get(); float value = get();
//bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags); ImGui::BeginGroup();
if (ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags)) ImGui::PushID(label.data());
TextLabel(label);
const bool hasChange = ImGui::DragFloat("##", &value, speed, p_min, p_max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{ {
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left)) SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), startRecording);
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false); if (!startRecording)
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) startRecording = true;
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
return true;
} }
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
return false; {
startRecording = false;
}
ImGui::PopID();
ImGui::EndGroup();
if(!tooltip.empty())
{
if(ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return hasChange;
} }
static bool DragInt(const std::string& fieldLabel, std::function<int(void)> get, std::function<void(int const&)> set, static bool DragInt(const std::string& label, std::function<int(void)> get, std::function<void(int const&)> set, std::string_view const& tooltip = {},
float speed = 1.0f, int p_min = int(), int p_max = int(), const char* displayFormat = "%d", ImGuiSliderFlags flags = 0) float speed = 1.0f, int p_min = int(), int p_max = int(), const char* displayFormat = "%d", ImGuiSliderFlags flags = 0)
{ {
int value = get(); int value = get();
//bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags); ImGui::BeginGroup();
if (ImGui::DragInt(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags)) ImGui::PushID(label.data());
TextLabel(label);
const bool hasChange = ImGui::DragInt("##", &value, speed, p_min, p_max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{ {
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left)) SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), startRecording);
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false); if (!startRecording)
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) startRecording = true;
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
return true;
} }
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
return false; {
startRecording = false;
}
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return hasChange;
} }
template <typename T> template <typename T>
static bool SliderScalar(const std::string& fieldLabel, ImGuiDataType data_type, T min, T max, std::function<T(void)> get, std::function<void(T const&)> set, static bool SliderScalar(const std::string& label, ImGuiDataType data_type, T min, T max, std::function<T(void)> get, std::function<void(T const&)> set, std::string_view const& tooltip = {},
const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0) const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{ {
T value = get(); T value = get();
if (ImGui::SliderScalar(fieldLabel.c_str(), data_type, &value, &min, &max, displayFormat, flags)) ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
bool const hasChange = ImGui::SliderScalar("##", data_type, &value, &min, &max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{ {
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), startRecording);
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false); if (!startRecording)
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) startRecording = true;
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), true);
return true;
} }
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
return false; {
startRecording = false;
}
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return hasChange;
} }
static bool SliderFloat(const std::string& fieldLabel, float min, float max, std::function<float(void)> get, std::function<void(float const&)> set, static bool SliderFloat(const std::string& label, float const& min, float const& max, std::function<float(void)> get, std::function<void(float const&)> set, std::string_view const& tooltip = {},
const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0) const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{ {
float value = get(); float value = get();
if (ImGui::SliderFloat(fieldLabel.c_str(), &value, min, max, displayFormat, flags)) ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
bool const hasChange = ImGui::SliderFloat("##", &value, min, max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{ {
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), startRecording);
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false); if (!startRecording)
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) startRecording = true;
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), true);
return true;
} }
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
return false; {
startRecording = false;
}
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return hasChange;
} }
static bool SliderInt(const std::string& fieldLabel, int min, int max, std::function<int(void)> get, std::function<void(int const&)> set, static bool SliderInt(const std::string& label, int min, int max, std::function<int(void)> get, std::function<void(int const&)> set, std::string_view const& tooltip = {},
const char* displayFormat = "%d", ImGuiSliderFlags flags = 0) const char* displayFormat = "%d", ImGuiSliderFlags flags = 0)
{ {
int value = get(); int value = get();
if (ImGui::SliderInt(fieldLabel.c_str(), &value, min, max, displayFormat, flags)) ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
bool const hasChange = ImGui::SliderInt("##", &value, min, max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{ {
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), true);
return true; SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), startRecording);
if (!startRecording)
startRecording = true;
} }
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
return false; {
startRecording = false;
}
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return hasChange;
} }
static bool ComboBox(const std::string& fieldLabel, std::vector<const char*> list, std::function<int(void)> get, std::function<void(int const&)> set) static bool ComboBox(const std::string& label, std::vector<const char*> list, std::function<int(void)> get, std::function<void(int const&)> set, std::string_view const& tooltip = {})
{ {
bool edited = false; bool edited = false;
int selected = get(); int selected = get();
ImGui::PushID(fieldLabel.c_str()); ImGui::BeginGroup();
ImGui::Text(fieldLabel.c_str()); ImGui::SameLine(); ImGui::PushID(label.c_str());
TextLabel(label);
ImGui::SameLine();
if (edited = ImGui::Combo("##Combo", &selected, list.data(), static_cast<int>(list.size()))) if (edited = ImGui::Combo("##Combo", &selected, list.data(), static_cast<int>(list.size())))
{ {
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), selected, set)), false); SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), selected, set)), false);
} }
ImGui::PopID(); ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return edited; return edited;
} }
}; };

View File

@ -5,8 +5,12 @@ typedef uint32_t SHEventIdentifier;
typedef uint32_t SHEventHandle; typedef uint32_t SHEventHandle;
//Add your event identifiers here: //Add your event identifiers here:
constexpr SHEventIdentifier SH_EXAMPLE_EVENT{0}; constexpr SHEventIdentifier SH_EXAMPLE_EVENT { 0 };
constexpr SHEventIdentifier SH_ENTITY_DESTROYED_EVENT{ 1 }; constexpr SHEventIdentifier SH_ENTITY_DESTROYED_EVENT { 1 };
constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT{ 2 }; constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT { 2 };
constexpr SHEventIdentifier SH_COMPONENT_ADDED_EVENT{ 3 }; constexpr SHEventIdentifier SH_COMPONENT_ADDED_EVENT { 3 };
constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT{ 4 }; constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT { 4 };
constexpr SHEventIdentifier SH_SCENEGRAPH_CHANGE_PARENT_EVENT { 5 };
constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_ADDED_EVENT { 6 };
constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_REMOVED_EVENT { 7 };

View File

@ -12,6 +12,7 @@
#include "SHpch.h" #include "SHpch.h"
#include "SHEvent.h" #include "SHEvent.h"
#include "SHEventReceiver.h" #include "SHEventReceiver.h"
#include "SH_API.h"
/****************************************************************************** /******************************************************************************
INSTRUCTIONS FOR USE: INSTRUCTIONS FOR USE:
@ -67,7 +68,7 @@ namespace SHADE
using EventManagerListener = std::function<void(SHEvent)>; using EventManagerListener = std::function<void(SHEvent)>;
class SHEventManager class SH_API SHEventManager
{ {
private: private:

View File

@ -10,6 +10,7 @@
#include "Graphics/Buffers/SHVkBuffer.h" #include "Graphics/Buffers/SHVkBuffer.h"
#include "Graphics/Images/SHVkImage.h" #include "Graphics/Images/SHVkImage.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" #include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/SHVkUtil.h"
namespace SHADE namespace SHADE
@ -299,7 +300,7 @@ namespace SHADE
SHLOG_ERROR("Command buffer must have started recording before a pipeline can be bound. "); SHLOG_ERROR("Command buffer must have started recording before a pipeline can be bound. ");
return; return;
} }
boundPipelineLayoutHdl = pipelineHdl->GetPipelineLayout(); bindPointData[static_cast<uint32_t>(pipelineHdl->GetPipelineType())].boundPipelineLayoutHdl = pipelineHdl->GetPipelineLayout();
vkCommandBuffer.bindPipeline(pipelineHdl->GetPipelineBindPoint(), pipelineHdl->GetVkPipeline()); vkCommandBuffer.bindPipeline(pipelineHdl->GetPipelineBindPoint(), pipelineHdl->GetVkPipeline());
} }
@ -358,9 +359,10 @@ namespace SHADE
} }
} }
void SHVkCommandBuffer::BindDescriptorSet(Handle<SHVkDescriptorSetGroup> descSetGroup, vk::PipelineBindPoint bindPoint, uint32_t firstSet, std::span<uint32_t> dynamicOffsets) void SHVkCommandBuffer::BindDescriptorSet(Handle<SHVkDescriptorSetGroup> descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span<uint32_t> dynamicOffsets)
{ {
vkCommandBuffer.bindDescriptorSets(bindPoint, boundPipelineLayoutHdl->GetVkPipelineLayout(), firstSet, descSetGroup->GetVkHandle(), dynamicOffsets); uint32_t bindPointIndex = static_cast<uint32_t>(bindPoint);
vkCommandBuffer.bindDescriptorSets(SHVkUtil::GetPipelineBindPointFromType(bindPoint), bindPointData[bindPointIndex].boundPipelineLayoutHdl->GetVkPipelineLayout(), firstSet, descSetGroup->GetVkHandle(), dynamicOffsets);
} }
/***************************************************************************/ /***************************************************************************/
@ -452,6 +454,11 @@ namespace SHADE
vkCommandBuffer.drawIndexedIndirect(indirectDrawData->GetVkBuffer(), 0, drawCount, sizeof(vk::DrawIndexedIndirectCommand)); vkCommandBuffer.drawIndexedIndirect(indirectDrawData->GetVkBuffer(), 0, drawCount, sizeof(vk::DrawIndexedIndirectCommand));
} }
void SHVkCommandBuffer::ComputeDispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept
{
vkCommandBuffer.dispatch (groupCountX, groupCountY, groupCountZ);
}
void SHVkCommandBuffer::CopyBufferToImage(const vk::Buffer& src, const vk::Image& dst, const std::vector<vk::BufferImageCopy>& copyInfo) void SHVkCommandBuffer::CopyBufferToImage(const vk::Buffer& src, const vk::Image& dst, const std::vector<vk::BufferImageCopy>& copyInfo)
{ {
vkCommandBuffer.copyBufferToImage vkCommandBuffer.copyBufferToImage
@ -500,9 +507,9 @@ namespace SHADE
// //vkCommandBuffer.pipelineBarrier() // //vkCommandBuffer.pipelineBarrier()
//} //}
void SHVkCommandBuffer::ForceSetPipelineLayout(Handle<SHVkPipelineLayout> pipelineLayout) noexcept void SHVkCommandBuffer::ForceSetPipelineLayout(Handle<SHVkPipelineLayout> pipelineLayout, SH_PIPELINE_TYPE pipelineType) noexcept
{ {
boundPipelineLayoutHdl = pipelineLayout; bindPointData[static_cast<uint32_t>(pipelineType)].boundPipelineLayoutHdl = pipelineLayout;
} }
/***************************************************************************/ /***************************************************************************/
@ -513,12 +520,13 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
void SHVkCommandBuffer::SubmitPushConstants(void) const noexcept void SHVkCommandBuffer::SubmitPushConstants(SH_PIPELINE_TYPE bindPoint) const noexcept
{ {
vkCommandBuffer.pushConstants(boundPipelineLayoutHdl->GetVkPipelineLayout(), auto layoutHdl = bindPointData[static_cast<uint32_t>(bindPoint)].boundPipelineLayoutHdl;
boundPipelineLayoutHdl->GetPushConstantInterface().GetShaderStageFlags(), vkCommandBuffer.pushConstants(layoutHdl->GetVkPipelineLayout(),
layoutHdl->GetPushConstantInterface().GetShaderStageFlags(),
0, 0,
boundPipelineLayoutHdl->GetPushConstantInterface().GetSize(), pushConstantData); layoutHdl->GetPushConstantInterface().GetSize(), pushConstantData);
} }
/***************************************************************************/ /***************************************************************************/
@ -695,7 +703,7 @@ namespace SHADE
, usageFlags{ rhs.usageFlags } , usageFlags{ rhs.usageFlags }
, commandBufferCount{ rhs.commandBufferCount } , commandBufferCount{ rhs.commandBufferCount }
, parentPool{ rhs.parentPool } , parentPool{ rhs.parentPool }
, boundPipelineLayoutHdl{ rhs.boundPipelineLayoutHdl } , bindPointData{ std::move (rhs.bindPointData)}
{ {
memcpy(pushConstantData, rhs.pushConstantData, PUSH_CONSTANT_SIZE); memcpy(pushConstantData, rhs.pushConstantData, PUSH_CONSTANT_SIZE);
@ -728,7 +736,7 @@ namespace SHADE
usageFlags = rhs.usageFlags; usageFlags = rhs.usageFlags;
commandBufferCount = rhs.commandBufferCount; commandBufferCount = rhs.commandBufferCount;
parentPool = rhs.parentPool; parentPool = rhs.parentPool;
boundPipelineLayoutHdl = rhs.boundPipelineLayoutHdl; bindPointData = std::move(rhs.bindPointData);
memcpy(pushConstantData, rhs.pushConstantData, PUSH_CONSTANT_SIZE); memcpy(pushConstantData, rhs.pushConstantData, PUSH_CONSTANT_SIZE);
rhs.vkCommandBuffer = VK_NULL_HANDLE; rhs.vkCommandBuffer = VK_NULL_HANDLE;

View File

@ -6,6 +6,7 @@
#include "SHCommandPoolResetMode.h" #include "SHCommandPoolResetMode.h"
#include "Resource/SHResourceLibrary.h" #include "Resource/SHResourceLibrary.h"
#include "Graphics/Pipeline/SHVkPipelineLayout.h" #include "Graphics/Pipeline/SHVkPipelineLayout.h"
#include "Graphics/Pipeline/SHPipelineType.h"
namespace SHADE namespace SHADE
{ {
@ -39,7 +40,14 @@ namespace SHADE
friend class SHResourceLibrary<SHVkCommandBuffer>; friend class SHResourceLibrary<SHVkCommandBuffer>;
static constexpr uint16_t PUSH_CONSTANT_SIZE = 512; static constexpr uint16_t PUSH_CONSTANT_SIZE = 512;
private: private:
struct PipelineBindPointData
{
//! The currently bound pipeline
Handle<SHVkPipelineLayout> boundPipelineLayoutHdl;
};
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */ /* PRIVATE MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -66,8 +74,8 @@ namespace SHADE
//! The command pool that this command buffer belongs to //! The command pool that this command buffer belongs to
Handle<SHVkCommandPool> parentPool; Handle<SHVkCommandPool> parentPool;
//! The currently bound pipeline //! Every command buffer will have a set of pipeline bind point specific data
Handle<SHVkPipelineLayout> boundPipelineLayoutHdl; std::array<PipelineBindPointData, static_cast<uint32_t>(SH_PIPELINE_TYPE::NUM_TYPES)> bindPointData;
//! The push constant data for the command buffer //! The push constant data for the command buffer
uint8_t pushConstantData[PUSH_CONSTANT_SIZE]; uint8_t pushConstantData[PUSH_CONSTANT_SIZE];
@ -112,13 +120,16 @@ namespace SHADE
void BindPipeline (Handle<SHVkPipeline> const& pipelineHdl) noexcept; void BindPipeline (Handle<SHVkPipeline> const& pipelineHdl) noexcept;
void BindVertexBuffer (uint32_t bindingPoint, Handle<SHVkBuffer> const& buffer, vk::DeviceSize offset) noexcept; void BindVertexBuffer (uint32_t bindingPoint, Handle<SHVkBuffer> const& buffer, vk::DeviceSize offset) noexcept;
void BindIndexBuffer (Handle<SHVkBuffer> const& buffer, uint32_t startingIndex) const noexcept; void BindIndexBuffer (Handle<SHVkBuffer> const& buffer, uint32_t startingIndex) const noexcept;
void BindDescriptorSet (Handle<SHVkDescriptorSetGroup> descSetGroup, vk::PipelineBindPoint bindPoint, uint32_t firstSet, std::span<uint32_t> dynamicOffsets); void BindDescriptorSet (Handle<SHVkDescriptorSetGroup> descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span<uint32_t> dynamicOffsets);
// Draw Commands // Draw Commands
void DrawArrays (uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept; void DrawArrays (uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept;
void DrawIndexed (uint32_t indexCount, uint32_t firstIndex, uint32_t vertexOffset) const noexcept; void DrawIndexed (uint32_t indexCount, uint32_t firstIndex, uint32_t vertexOffset) const noexcept;
void DrawMultiIndirect (Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount); void DrawMultiIndirect (Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount);
// Compute Commands
void ComputeDispatch (uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept;
// Buffer Copy // Buffer Copy
void CopyBufferToImage (const vk::Buffer& src, const vk::Image& dst, const std::vector<vk::BufferImageCopy>& copyInfo); void CopyBufferToImage (const vk::Buffer& src, const vk::Image& dst, const std::vector<vk::BufferImageCopy>& copyInfo);
void CopyImageToBuffer (const vk::Image& src, const vk::Buffer& dst, const std::vector<vk::BufferImageCopy>& copyInfo); void CopyImageToBuffer (const vk::Image& src, const vk::Buffer& dst, const std::vector<vk::BufferImageCopy>& copyInfo);
@ -138,13 +149,13 @@ namespace SHADE
// Push Constant variable setting // Push Constant variable setting
template <typename T> template <typename T>
void SetPushConstantVariable(std::string variableName, T const& data) noexcept void SetPushConstantVariable(std::string variableName, T const& data, SH_PIPELINE_TYPE bindPoint) noexcept
{ {
memcpy (static_cast<uint8_t*>(pushConstantData) + boundPipelineLayoutHdl->GetPushConstantInterface().GetOffset(variableName), &data, sizeof (T)); memcpy (static_cast<uint8_t*>(pushConstantData) + bindPointData[static_cast<uint32_t>(bindPoint)].boundPipelineLayoutHdl->GetPushConstantInterface().GetOffset(variableName), &data, sizeof (T));
}; };
void ForceSetPipelineLayout (Handle<SHVkPipelineLayout> pipelineLayout) noexcept; void ForceSetPipelineLayout (Handle<SHVkPipelineLayout> pipelineLayout, SH_PIPELINE_TYPE pipelineType) noexcept;
void SubmitPushConstants (void) const noexcept; void SubmitPushConstants (SH_PIPELINE_TYPE bindPoint) const noexcept;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */ /* GETTERS AND SETTERS */

View File

@ -25,7 +25,8 @@ namespace SHADE
} }
SHVkDescriptorPool::SHVkDescriptorPool(SHVkDescriptorPool&& rhs) noexcept SHVkDescriptorPool::SHVkDescriptorPool(SHVkDescriptorPool&& rhs) noexcept
: device{ rhs.device } : ISelfHandle (rhs)
, device{ rhs.device }
, pool{ rhs.pool } , pool{ rhs.pool }
{ {
rhs.pool = VK_NULL_HANDLE; rhs.pool = VK_NULL_HANDLE;

View File

@ -91,7 +91,7 @@ namespace SHADE
// new write for the binding // new write for the binding
updater.writeInfos.emplace_back(); updater.writeInfos.emplace_back();
updater.writeHashMap.try_emplace(writeHash, updater.writeInfos.size() - 1); updater.writeHashMap.try_emplace(writeHash, static_cast<uint32_t>(updater.writeInfos.size()) - 1u);
auto& writeInfo = updater.writeInfos.back(); auto& writeInfo = updater.writeInfos.back();
// Descriptor count for the write descriptor set. Usually this is set to 1, but if binding is variable sized, set to info passed in // Descriptor count for the write descriptor set. Usually this is set to 1, but if binding is variable sized, set to info passed in
@ -102,10 +102,10 @@ namespace SHADE
//case vk::DescriptorType::eSampler: //case vk::DescriptorType::eSampler:
//case vk::DescriptorType::eSampledImage: //case vk::DescriptorType::eSampledImage:
case vk::DescriptorType::eCombinedImageSampler: case vk::DescriptorType::eCombinedImageSampler:
case vk::DescriptorType::eStorageImage:
case vk::DescriptorType::eInputAttachment:
writeInfo.descImageInfos.resize(descriptorCount); writeInfo.descImageInfos.resize(descriptorCount);
break; break;
//case vk::DescriptorType::eStorageImage:
// break;
case vk::DescriptorType::eUniformTexelBuffer: case vk::DescriptorType::eUniformTexelBuffer:
case vk::DescriptorType::eStorageTexelBuffer: case vk::DescriptorType::eStorageTexelBuffer:
case vk::DescriptorType::eUniformBuffer: case vk::DescriptorType::eUniformBuffer:
@ -165,6 +165,7 @@ namespace SHADE
if (imageViewsAndSamplers.size() > writeInfo.descImageInfos.size()) if (imageViewsAndSamplers.size() > writeInfo.descImageInfos.size())
{ {
SHLOG_ERROR("Attempting write too many descriptors into descriptor set. Failed to write to vk::WriteDescriptorSet. "); SHLOG_ERROR("Attempting write too many descriptors into descriptor set. Failed to write to vk::WriteDescriptorSet. ");
return;
} }
for (uint32_t i = 0; i < imageViewsAndSamplers.size(); ++i) for (uint32_t i = 0; i < imageViewsAndSamplers.size(); ++i)

View File

@ -31,6 +31,8 @@ namespace SHADE
class SHVkDescriptorSetGroup class SHVkDescriptorSetGroup
{ {
public: public:
using viewSamplerLayout = std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout>;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Constructor/Destructors */ /* Constructor/Destructors */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/

View File

@ -233,6 +233,8 @@ namespace SHADE
, vmaAllocator{rhs.vmaAllocator} , vmaAllocator{rhs.vmaAllocator}
, nonDedicatedBestIndex {0} , nonDedicatedBestIndex {0}
, parentPhysicalDeviceHdl {rhs.parentPhysicalDeviceHdl} , parentPhysicalDeviceHdl {rhs.parentPhysicalDeviceHdl}
, uboBufferMemoryAlignment{ 0 }
, ssboBufferMemoryAlignment{ 0 }
{ {
rhs.vkLogicalDevice = VK_NULL_HANDLE; rhs.vkLogicalDevice = VK_NULL_HANDLE;
} }
@ -261,6 +263,8 @@ namespace SHADE
vmaAllocator = rhs.vmaAllocator; vmaAllocator = rhs.vmaAllocator;
nonDedicatedBestIndex = 0; nonDedicatedBestIndex = 0;
parentPhysicalDeviceHdl = rhs.parentPhysicalDeviceHdl; parentPhysicalDeviceHdl = rhs.parentPhysicalDeviceHdl;
uboBufferMemoryAlignment = rhs.uboBufferMemoryAlignment;
ssboBufferMemoryAlignment = rhs.ssboBufferMemoryAlignment;
rhs.vkLogicalDevice = VK_NULL_HANDLE; rhs.vkLogicalDevice = VK_NULL_HANDLE;
@ -529,6 +533,11 @@ namespace SHADE
} }
Handle<SHVkPipeline> SHVkLogicalDevice::CreateComputePipeline(Handle<SHVkPipelineLayout> const& pipelineLayoutHdl) noexcept
{
return SHVkInstance::GetResourceManager().Create <SHVkPipeline>(GetHandle(), pipelineLayoutHdl);
}
Handle<SHVkSampler> SHVkLogicalDevice::CreateSampler(const SHVkSamplerParams& params) noexcept Handle<SHVkSampler> SHVkLogicalDevice::CreateSampler(const SHVkSamplerParams& params) noexcept
{ {
return SHVkInstance::GetResourceManager().Create <SHVkSampler>(GetHandle(), params); return SHVkInstance::GetResourceManager().Create <SHVkSampler>(GetHandle(), params);

View File

@ -175,12 +175,17 @@ namespace SHADE
std::string const& shaderName std::string const& shaderName
) noexcept; ) noexcept;
Handle<SHVkPipeline> CreateGraphicsPipeline ( Handle<SHVkPipeline> CreateGraphicsPipeline (
Handle<SHVkPipelineLayout> const& pipelineLayoutHdl, Handle<SHVkPipelineLayout> const& pipelineLayoutHdl,
SHVkPipelineState const* const state, SHVkPipelineState const* const state,
Handle<SHVkRenderpass> const& renderpassHdl, Handle<SHVkRenderpass> const& renderpassHdl,
Handle<SHSubpass> subpass Handle<SHSubpass> subpass
) noexcept; ) noexcept;
Handle<SHVkPipeline> CreateComputePipeline (
Handle<SHVkPipelineLayout> const& pipelineLayoutHdl
) noexcept;
Handle<SHVkSampler> CreateSampler (const SHVkSamplerParams& params) noexcept; Handle<SHVkSampler> CreateSampler (const SHVkSamplerParams& params) noexcept;
Handle<SHVkRenderpass> CreateRenderpass (std::span<vk::AttachmentDescription> const vkDescriptions, std::vector<SHVkSubpassParams> const& subpasses) noexcept; Handle<SHVkRenderpass> CreateRenderpass (std::span<vk::AttachmentDescription> const vkDescriptions, std::vector<SHVkSubpassParams> const& subpasses) noexcept;

View File

@ -49,7 +49,7 @@ namespace SHADE
SHVkSampler::~SHVkSampler() noexcept SHVkSampler::~SHVkSampler() noexcept
{ {
if (vkSampler) if (vkSampler)
device->GetVkLogicalDevice().destroySampler(); device->GetVkLogicalDevice().destroySampler(vkSampler);
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/

View File

@ -155,7 +155,7 @@ namespace SHADE
SHVkDebugMessenger::GenMessengerType(SH_DEBUG_MSG_TYPE::T_GENERAL, SH_DEBUG_MSG_TYPE::T_VALIDATION, SH_DEBUG_MSG_TYPE::T_PERFORMANCE)); SHVkDebugMessenger::GenMessengerType(SH_DEBUG_MSG_TYPE::T_GENERAL, SH_DEBUG_MSG_TYPE::T_VALIDATION, SH_DEBUG_MSG_TYPE::T_PERFORMANCE));
instanceDbgInfo.pfnUserCallback = SHVulkanDebugUtil::GenericDebugCallback; instanceDbgInfo.pfnUserCallback = SHVulkanDebugUtil::GenericDebugCallback;
instanceInfo.pNext = static_cast<vk::DebugUtilsMessengerCreateInfoEXT*>(&instanceDbgInfo); //instanceInfo.pNext = static_cast<vk::DebugUtilsMessengerCreateInfoEXT*>(&instanceDbgInfo);
} }
// Finally create the instance // Finally create the instance

View File

@ -30,185 +30,200 @@ of DigiPen Institute of Technology is prohibited.
namespace SHADE namespace SHADE
{ {
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* SHBatch - Usage Functions */ /* SHBatch - Usage Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
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!");
// Mark all as dirty // Mark all as dirty
setAllDirtyFlags(); setAllDirtyFlags();
}
void SHBatch::Add(const SHRenderable* renderable)
{
// Check if we have a SubBatch with the same mesh yet
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
{
return batch.Mesh == renderable->Mesh;
});
// Create one if not found
if (subBatch == subBatches.end())
{
subBatches.emplace_back(renderable->Mesh);
subBatch = subBatches.end() - 1;
} }
void SHBatch::Add(const SHRenderable* renderable) // Add renderable in
{ subBatch->Renderables.insert(renderable->GetEID());
// Check if we have a SubBatch with the same mesh yet
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
{
return batch.Mesh == renderable->Mesh;
});
// Create one if not found // Also add material instance in
if (subBatch == subBatches.end()) referencedMatInstances.insert(renderable->GetMaterial());
// Mark all as dirty
setAllDirtyFlags();
}
void SHBatch::Remove(const SHRenderable* renderable)
{
// Check if we have a SubBatch with the same mesh yet
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
{
return batch.Mesh == renderable->Mesh;
});
// Attempt to remove if it exists
if (subBatch == subBatches.end())
return;
subBatch->Renderables.erase(renderable->GetEID());
// Check if other renderables in subBatches contain the same material instance
bool matUnused = true;
for (const auto& sb : subBatches)
for (const auto& rendId : sb.Renderables)
{
auto rend = SHComponentManager::GetComponent<SHRenderable>(rendId);
if (rend)
{ {
subBatches.emplace_back(renderable->Mesh); if (rend->GetMaterial() == renderable->GetMaterial())
subBatch = subBatches.end() - 1; {
matUnused = false;
break;
}
} }
else
{
SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
}
}
// Add renderable in // Material is no longer in this library, so we remove it
subBatch->Renderables.insert(renderable); if (matUnused)
referencedMatInstances.erase(renderable->WasMaterialChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial());
// Also add material instance in // Mark all as dirty
referencedMatInstances.insert(renderable->GetMaterial()); setAllDirtyFlags();
}
// Mark all as dirty void SHBatch::Clear()
setAllDirtyFlags(); {
subBatches.clear();
// Clear CPU buffers
drawData.clear();
transformData.clear();
instancedIntegerData.clear();
matPropsData.reset();
matPropsDataSize = 0;
// Clear GPU buffers
for (int i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{
drawDataBuffer[i].Free();
transformDataBuffer[i].Free();
instancedIntegerBuffer[i].Free();
matPropsBuffer[i].Free();
}
}
void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
return;
} }
void SHBatch::Remove(const SHRenderable* renderable) // Check if there are even material properties to update
if (!matPropsData)
return;
// Check if any materials have changed
bool hasChanged = false;
for (const auto& material : referencedMatInstances)
{ {
// Check if we have a SubBatch with the same mesh yet if (material->HasChanged())
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch) {
{ hasChanged = true;
return batch.Mesh == renderable->Mesh; break;
}); }
// Attempt to remove if it exists
if (subBatch == subBatches.end())
return;
subBatch->Renderables.erase(renderable);
// Check if other renderables in subBatches contain the same material instance
bool matUnused = true;
for (const auto& sb : subBatches)
for (const auto& rend : sb.Renderables)
{
if (rend->GetMaterial() == renderable->GetMaterial())
{
matUnused = false;
break;
}
}
// Material is no longer in this library, so we remove it
if (matUnused)
referencedMatInstances.erase(renderable->GetMaterial());
// Mark all as dirty
for (bool& dirt : isDirty)
dirt = true;
} }
void SHBatch::Clear() // We need to update all the material buffers if the materials have changed
if (hasChanged)
{ {
subBatches.clear(); for (auto& dirt : matBufferDirty)
dirt = true;
// Clear CPU buffers
drawData.clear();
transformData.clear();
eidData.clear();
matPropsData.reset();
matPropsDataSize = 0;
// Clear GPU buffers
for (int i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{
drawDataBuffer[i].Free();
transformDataBuffer[i].Free();
eidBuffer[i].Free();
matPropsBuffer[i].Free();
}
} }
void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) // Check if this frame's buffer is dirty
{ if (!matBufferDirty[frameIndex])
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) return;
{
SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
return;
}
// Check if there are even material properties to update // Build CPU Buffer
if (!matPropsData) char* propsCurrPtr = matPropsData.get();
return; for (auto& subBatch : subBatches)
for (auto rendId : subBatch.Renderables)
// Check if any materials have changed {
bool hasChanged = false; const SHRenderable* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
for (const auto& material : referencedMatInstances) if (renderable)
{ {
if (material->HasChanged()) renderable->GetMaterial()->ExportProperties(propsCurrPtr);
{
hasChanged = true;
break;
}
} }
else
// We need to update all the material buffers if the materials have changed
if (hasChanged)
{ {
for (auto& dirt : matBufferDirty) SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
dirt = true;
} }
propsCurrPtr += singleMatPropAlignedSize;
}
// Check if this frame's buffer is dirty // Transfer to GPU
if (!matBufferDirty[frameIndex]) rebuildMaterialBuffers(frameIndex, descPool);
return;
// Build CPU Buffer // This frame is updated
char* propsCurrPtr = matPropsData.get(); matBufferDirty[frameIndex] = false;
for (auto& subBatch : subBatches) }
for (const SHRenderable* renderable : subBatch.Renderables)
{
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
propsCurrPtr += singleMatPropAlignedSize;
}
// Transfer to GPU
rebuildMaterialBuffers(frameIndex, descPool);
// This frame is updated void SHBatch::UpdateTransformBuffer(uint32_t frameIndex)
matBufferDirty[frameIndex] = false; {
} if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
void SHBatch::UpdateTransformBuffer(uint32_t frameIndex)
{ {
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
{ return;
SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
return;
}
// Reset Transform Data
transformData.clear();
// Populate on the CPU
for (auto& subBatch : subBatches)
for (const SHRenderable* renderable : subBatch.Renderables)
{
// Transform
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(renderable->GetEID());
if (!transform)
{
SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
transformData.emplace_back();
}
else
{
transformData.emplace_back(transform->GetTRS());
}
}
// Transfer to GPU
if (transformDataBuffer[frameIndex])
transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix)), 0, 0);
} }
void SHBatch::UpdateEIDBuffer(uint32_t frameIndex) // Reset Transform Data
transformData.clear();
// Populate on the CPU
for (auto& subBatch : subBatches)
for (auto rendId : subBatch.Renderables)
{
// Transform
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(rendId);
if (transform)
{
transformData.emplace_back(transform->GetTRS());
}
else
{
SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
transformData.emplace_back();
}
}
// Transfer to GPU
if (transformDataBuffer[frameIndex])
transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix)), 0, 0);
}
void SHBatch::UpdateInstancedIntegerBuffer(uint32_t frameIndex)
{ {
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{ {
@ -217,224 +232,244 @@ namespace SHADE
} }
// Reset Transform Data // Reset Transform Data
eidData.clear(); instancedIntegerData.clear();
// Populate on the CPU // Populate on the CPU
for (auto& subBatch : subBatches) for (auto& subBatch : subBatches)
for (const SHRenderable* renderable : subBatch.Renderables) for (auto rendId : subBatch.Renderables)
{ {
eidData.emplace_back(renderable->GetEID()); auto* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
instancedIntegerData.emplace_back(SHInstancedIntegerData
{
rendId,
renderable->GetLightLayer()
}
);
} }
// Transfer to GPU // Transfer to GPU
if (eidBuffer[frameIndex]) if (instancedIntegerBuffer[frameIndex])
eidBuffer[frameIndex]->WriteToMemory(eidData.data(), static_cast<EntityID>(eidData.size() * sizeof(EntityID)), 0, 0); instancedIntegerBuffer[frameIndex]->WriteToMemory(instancedIntegerData.data(), static_cast<uint32_t>(instancedIntegerData.size() * sizeof(SHInstancedIntegerData)), 0, 0);
} }
void SHBatch::Build(Handle<SHVkLogicalDevice> _device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) void SHBatch::Build(Handle<SHVkLogicalDevice> _device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{ {
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) SHLOG_WARNING("[SHBatch] Attempted to update build batch buffers with an invalid frame index.");
{ return;
SHLOG_WARNING("[SHBatch] Attempted to update build batch buffers with an invalid frame index.");
return;
}
// Save logical device
device = _device;
// No need to build as there are no changes
if (!isDirty[frameIndex])
return;
// Count number of elements
size_t numTotalElements = 0;
for (const auto& subBatch : subBatches)
{
numTotalElements += subBatch.Renderables.size();
}
// Generate CPU buffers if there are changes
if (isCPUBuffersDirty)
{
// - Draw data
drawData.reserve(subBatches.size());
drawData.clear();
// - Transform data
transformData.reserve(numTotalElements);
transformData.clear();
// - EID data
eidData.reserve(numTotalElements);
eidData.clear();
// - Material Properties Data
const Handle<SHShaderBlockInterface> SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
vk::ShaderStageFlagBits::eFragment
);
const bool EMPTY_MAT_PROPS = !SHADER_INFO;
Byte matPropTotalBytes = 0;
if (!EMPTY_MAT_PROPS)
{
singleMatPropSize = SHADER_INFO->GetBytesRequired();
singleMatPropAlignedSize = device->PadSSBOSize(static_cast<uint32_t>(singleMatPropSize));
matPropTotalBytes = numTotalElements * singleMatPropAlignedSize;
if (matPropsDataSize < matPropTotalBytes)
{
matPropsData.reset(new char[matPropTotalBytes]);
matPropsDataSize = matPropTotalBytes;
}
}
// Build Sub Batches
uint32_t nextInstanceIndex = 0;
char* propsCurrPtr = matPropsData.get();
for (auto& subBatch : subBatches)
{
// Create command
drawData.emplace_back(vk::DrawIndexedIndirectCommand
{
.indexCount = subBatch.Mesh->IndexCount,
.instanceCount = static_cast<uint32_t>(subBatch.Renderables.size()),
.firstIndex = subBatch.Mesh->FirstIndex,
.vertexOffset = subBatch.Mesh->FirstVertex,
.firstInstance = nextInstanceIndex++
});
// Fill in buffers (CPU)
for (const SHRenderable* renderable : subBatch.Renderables)
{
// Transform
EntityID eid = renderable->GetEID();
auto transform = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
if (!transform)
{
SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
transformData.emplace_back();
}
else
{
transformData.emplace_back(transform->GetTRS());
}
eidData.emplace_back(eid);
// Material Properties
if (!EMPTY_MAT_PROPS)
{
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
propsCurrPtr += singleMatPropAlignedSize;
}
}
}
// Successfully update CPU buffers
isCPUBuffersDirty = false;
}
// Send all buffered data to the GPU buffers
using BuffUsage = vk::BufferUsageFlagBits;
// - Draw Data
const uint32_t DRAW_DATA_BYTES = static_cast<uint32_t>(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES,
BuffUsage::eIndirectBuffer
);
// - Transform Buffer
const uint32_t TF_DATA_BYTES = static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
BuffUsage::eVertexBuffer
);
const uint32_t EID_DATA_BYTES = static_cast<uint32_t>(eidData.size() * sizeof(EntityID));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, eidBuffer[frameIndex], eidData.data(), EID_DATA_BYTES,
BuffUsage::eVertexBuffer
);
// - Material Properties Buffer
rebuildMaterialBuffers(frameIndex, descPool);
// Mark this frame as no longer dirty
isDirty[frameIndex] = false;
} }
/*---------------------------------------------------------------------------------*/ // Save logical device
/* SHBatch - Usage Functions */ device = _device;
/*---------------------------------------------------------------------------------*/
void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to draw a batch with an invalid frame index.");
return;
}
// Bind all required objects before drawing // No need to build as there are no changes
static std::array<uint32_t, 1> dynamicOffset { 0 }; if (!isDirty[frameIndex])
cmdBuffer->BindPipeline(pipeline); return;
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::EID, eidBuffer[frameIndex], 0); // Count number of elements
if (matPropsDescSet[frameIndex]) size_t numTotalElements = 0;
for (const auto& subBatch : subBatches)
{
numTotalElements += subBatch.Renderables.size();
}
// Generate CPU buffers if there are changes
if (isCPUBuffersDirty)
{
// - Draw data
drawData.reserve(subBatches.size());
drawData.clear();
// - Transform data
transformData.reserve(numTotalElements);
transformData.clear();
// - EID data
instancedIntegerData.reserve(numTotalElements);
instancedIntegerData.clear();
// - Material Properties Data
const Handle<SHShaderBlockInterface> SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
vk::ShaderStageFlagBits::eFragment
);
const bool EMPTY_MAT_PROPS = !SHADER_INFO;
Byte matPropTotalBytes = 0;
if (!EMPTY_MAT_PROPS)
{
singleMatPropSize = SHADER_INFO->GetBytesRequired();
singleMatPropAlignedSize = device->PadSSBOSize(static_cast<uint32_t>(singleMatPropSize));
matPropTotalBytes = numTotalElements * singleMatPropAlignedSize;
if (matPropsDataSize < matPropTotalBytes)
{ {
cmdBuffer->BindDescriptorSet matPropsData.reset(new char[matPropTotalBytes]);
( matPropsDataSize = matPropTotalBytes;
matPropsDescSet[frameIndex], }
vk::PipelineBindPoint::eGraphics, }
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
dynamicOffset // Build Sub Batches
uint32_t nextInstanceIndex = 0;
char* propsCurrPtr = matPropsData.get();
for (auto& subBatch : subBatches)
{
// Create command
const uint32_t CURR_INSTANCES = static_cast<uint32_t>(subBatch.Renderables.size());
drawData.emplace_back(vk::DrawIndexedIndirectCommand
{
.indexCount = subBatch.Mesh->IndexCount,
.instanceCount = CURR_INSTANCES,
.firstIndex = subBatch.Mesh->FirstIndex,
.vertexOffset = subBatch.Mesh->FirstVertex,
.firstInstance = nextInstanceIndex
});
nextInstanceIndex += CURR_INSTANCES;
// Fill in buffers (CPU)
for (auto rendId : subBatch.Renderables)
{
// Transform
auto transform = SHComponentManager::GetComponent_s<SHTransformComponent>(rendId);
if (!transform)
{
SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
transformData.emplace_back();
}
else
{
transformData.emplace_back(transform->GetTRS());
}
const SHRenderable* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
instancedIntegerData.emplace_back(SHInstancedIntegerData
{
rendId,
renderable->GetLightLayer()
}
); );
}
cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
}
/*---------------------------------------------------------------------------------*/ // Material Properties
/* SHBatch - Helper Functions */ if (!EMPTY_MAT_PROPS)
/*---------------------------------------------------------------------------------*/ {
void SHBatch::setAllDirtyFlags() if (renderable)
{
for (bool& dirt : isDirty)
dirt = true;
isCPUBuffersDirty = true;
}
void SHBatch::rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
if (matPropsData)
{
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
vk::BufferUsageFlagBits::eStorageBuffer
);
if (!matPropsDescSet[frameIndex])
{ {
matPropsDescSet[frameIndex] = descPool->Allocate renderable->GetMaterial()->ExportProperties(propsCurrPtr);
(
{ SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE] },
{ 0 }
);
} }
std::array<Handle<SHVkBuffer>, 1> bufferList = { matPropsBuffer[frameIndex] }; else
matPropsDescSet[frameIndex]->ModifyWriteDescBuffer {
( SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, }
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA, propsCurrPtr += singleMatPropAlignedSize;
bufferList, }
0, static_cast<uint32_t>(matPropsDataSize)
);
matPropsDescSet[frameIndex]->UpdateDescriptorSetBuffer
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA
);
} }
}
// Successfully update CPU buffers
isCPUBuffersDirty = false;
} }
// Send all buffered data to the GPU buffers
using BuffUsage = vk::BufferUsageFlagBits;
// - Draw Data
const uint32_t DRAW_DATA_BYTES = static_cast<uint32_t>(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES,
BuffUsage::eIndirectBuffer
);
// - Transform Buffer
const uint32_t TF_DATA_BYTES = static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
BuffUsage::eVertexBuffer
);
const uint32_t EID_DATA_BYTES = static_cast<uint32_t>(instancedIntegerData.size() * sizeof(SHInstancedIntegerData));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, instancedIntegerBuffer[frameIndex], instancedIntegerData.data(), EID_DATA_BYTES,
BuffUsage::eVertexBuffer
);
// - Material Properties Buffer
rebuildMaterialBuffers(frameIndex, descPool);
// Mark this frame as no longer dirty
isDirty[frameIndex] = false;
}
/*---------------------------------------------------------------------------------*/
/* SHBatch - Usage Functions */
/*---------------------------------------------------------------------------------*/
void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to draw a batch with an invalid frame index.");
return;
}
// Bind all required objects before drawing
static std::array<uint32_t, 1> dynamicOffset{ 0 };
cmdBuffer->BindPipeline(pipeline);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0);
if (matPropsDescSet[frameIndex])
{
cmdBuffer->BindDescriptorSet
(
matPropsDescSet[frameIndex],
SH_PIPELINE_TYPE::GRAPHICS,
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
dynamicOffset
);
}
cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
}
/*---------------------------------------------------------------------------------*/
/* SHBatch - Helper Functions */
/*---------------------------------------------------------------------------------*/
void SHBatch::setAllDirtyFlags()
{
for (bool& dirt : isDirty)
dirt = true;
isCPUBuffersDirty = true;
}
void SHBatch::rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
if (matPropsData)
{
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
vk::BufferUsageFlagBits::eStorageBuffer
);
if (!matPropsDescSet[frameIndex])
{
matPropsDescSet[frameIndex] = descPool->Allocate
(
{ SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE] },
{ 0 }
);
}
std::array<Handle<SHVkBuffer>, 1> bufferList = { matPropsBuffer[frameIndex] };
matPropsDescSet[frameIndex]->ModifyWriteDescBuffer
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
bufferList,
0, static_cast<uint32_t>(matPropsDataSize)
);
matPropsDescSet[frameIndex]->UpdateDescriptorSetBuffer
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA
);
}
}
} }

View File

@ -23,6 +23,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Math/SHMatrix.h" #include "Math/SHMatrix.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "ECS_Base/SHECSMacros.h" #include "ECS_Base/SHECSMacros.h"
#include "Graphics/MiddleEnd/Interface/SHInstancedIntegerData.h"
namespace SHADE namespace SHADE
{ {
@ -55,7 +56,7 @@ namespace SHADE
/* Data Members */ /* Data Members */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
Handle<SHMesh> Mesh; Handle<SHMesh> Mesh;
std::unordered_set<const SHRenderable*> Renderables; std::unordered_set<EntityID> Renderables;
}; };
/***********************************************************************************/ /***********************************************************************************/
/*! /*!
@ -79,7 +80,7 @@ namespace SHADE
void Clear(); void Clear();
void UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool); void UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
void UpdateTransformBuffer(uint32_t frameIndex); void UpdateTransformBuffer(uint32_t frameIndex);
void UpdateEIDBuffer(uint32_t frameIndex); void UpdateInstancedIntegerBuffer(uint32_t frameIndex);
void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) ; void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) ;
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex); void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex);
@ -111,7 +112,7 @@ namespace SHADE
// CPU Buffers // CPU Buffers
std::vector<vk::DrawIndexedIndirectCommand> drawData; std::vector<vk::DrawIndexedIndirectCommand> drawData;
std::vector<SHMatrix> transformData; std::vector<SHMatrix> transformData;
std::vector<EntityID> eidData; std::vector<SHInstancedIntegerData> instancedIntegerData;
std::unique_ptr<char> matPropsData; std::unique_ptr<char> matPropsData;
Byte matPropsDataSize = 0; Byte matPropsDataSize = 0;
Byte singleMatPropAlignedSize = 0; Byte singleMatPropAlignedSize = 0;
@ -120,7 +121,7 @@ namespace SHADE
// GPU Buffers // GPU Buffers
TripleBuffer drawDataBuffer; TripleBuffer drawDataBuffer;
TripleBuffer transformDataBuffer; TripleBuffer transformDataBuffer;
TripleBuffer eidBuffer; TripleBuffer instancedIntegerBuffer;
TripleBuffer matPropsBuffer; TripleBuffer matPropsBuffer;
TripleDescSet matPropsDescSet; TripleDescSet matPropsDescSet;

View File

@ -20,91 +20,91 @@ of DigiPen Institute of Technology is prohibited.
namespace SHADE namespace SHADE
{ {
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Constructor/Destructors */ /* Constructor/Destructors */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHSuperBatch::SHSuperBatch(Handle<SHSubpass> sp) SHSuperBatch::SHSuperBatch(Handle<SHSubpass> sp)
: subpass { sp } : subpass{ sp }
{} {}
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Usage Functions */ /* Usage Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SHSuperBatch::Add(const SHRenderable* renderable) noexcept void SHSuperBatch::Add(const SHRenderable* renderable) noexcept
{
const Handle<SHVkPipeline> PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline();
// Check if we have a batch with the same pipeline first
auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch)
{
return batch.GetPipeline() == PIPELINE;
});
// Create one if not found
if (batch == batches.end())
{ {
const Handle<SHVkPipeline> PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline(); batches.emplace_back(PIPELINE);
batch = batches.end() - 1;
// Check if we have a batch with the same pipeline first
auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch)
{
return batch.GetPipeline() == PIPELINE;
});
// Create one if not found
if (batch == batches.end())
{
batches.emplace_back(PIPELINE);
batch = batches.end() - 1;
}
// Add renderable in
batch->Add(renderable);
} }
void SHSuperBatch::Remove(const SHRenderable* renderable) noexcept // Add renderable in
batch->Add(renderable);
}
void SHSuperBatch::Remove(const SHRenderable* renderable) noexcept
{
const Handle<SHVkPipeline> PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline();
// Check if we have a Batch with the same pipeline yet
auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch)
{
return batch.GetPipeline() == PIPELINE;
});
// Attempt to remove if it exists
if (batch == batches.end())
return;
batch->Remove(renderable);
}
void SHSuperBatch::Clear() noexcept
{
for (auto& batch : batches)
{ {
const Handle<SHVkPipeline> PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline(); batch.Clear();
// Check if we have a Batch with the same pipeline yet
auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch)
{
return batch.GetPipeline() == PIPELINE;
});
// Attempt to remove if it exists
if (batch == batches.end())
return;
batch->Remove(renderable);
} }
batches.clear();
}
void SHSuperBatch::Clear() noexcept void SHSuperBatch::UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
for (auto& batch : batches)
{ {
for (auto& batch : batches) batch.UpdateMaterialBuffer(frameIndex, descPool);
{ batch.UpdateTransformBuffer(frameIndex);
batch.Clear(); batch.UpdateInstancedIntegerBuffer(frameIndex);
}
batches.clear();
} }
}
void SHSuperBatch::UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) void SHSuperBatch::Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
{
// Build all batches
for (auto& batch : batches)
{ {
for (auto& batch : batches) batch.Build(device, descPool, frameIndex);
{
batch.UpdateMaterialBuffer(frameIndex, descPool);
batch.UpdateTransformBuffer(frameIndex);
batch.UpdateEIDBuffer(frameIndex);
}
} }
}
void SHSuperBatch::Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept void SHSuperBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{
// Build all batches
for (auto& batch : batches)
{ {
// Build all batches batch.Draw(cmdBuffer, frameIndex);
for (auto& batch : batches)
{
batch.Build(device, descPool, frameIndex);
}
}
void SHSuperBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{
// Build all batches
for (auto& batch : batches)
{
batch.Draw(cmdBuffer, frameIndex);
}
} }
}
} }

View File

@ -4,6 +4,8 @@
#include "Graphics/Pipeline/SHPipelineState.h" #include "Graphics/Pipeline/SHPipelineState.h"
#include "Graphics/Pipeline/SHVkPipelineLayout.h" #include "Graphics/Pipeline/SHVkPipelineLayout.h"
#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h" #include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
#include "Graphics/MiddleEnd/Lights/SHLightData.h"
#include "Tools/SHUtilities.h"
namespace SHADE namespace SHADE
{ {
@ -45,16 +47,35 @@ namespace SHADE
// For global data (generic data and textures) // For global data (generic data and textures)
Handle<SHVkDescriptorSetLayout> staticGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS,{ genericDataBinding, texturesBinding }); Handle<SHVkDescriptorSetLayout> staticGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS,{ genericDataBinding, texturesBinding });
SHVkDescriptorSetLayout::Binding lightBinding std::vector<SHVkDescriptorSetLayout::Binding> lightBindings{};
for (uint32_t i = 0; i < SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); ++i)
{ {
.Type = vk::DescriptorType::eStorageBufferDynamic, lightBindings.push_back (SHVkDescriptorSetLayout::Binding
.Stage = vk::ShaderStageFlagBits::eFragment, {
.BindPoint = SHGraphicsConstants::DescriptorSetBindings::LIGHTS_DATA, .Type = vk::DescriptorType::eStorageBufferDynamic,
.DescriptorCount = 1, .Stage = vk::ShaderStageFlagBits::eFragment,
}; .BindPoint = i,
.DescriptorCount = 1,
});
}
//SHVkDescriptorSetLayout::Binding pointLightBinding
//{
// .Type = vk::DescriptorType::eStorageBufferDynamic,
// .Stage = vk::ShaderStageFlagBits::eFragment,
// .BindPoint = SHGraphicsConstants::DescriptorSetBindings::POINT_LIGHT_DATA,
// .DescriptorCount = 1,
//};
//SHVkDescriptorSetLayout::Binding spotLightBinding
//{
// .Type = vk::DescriptorType::eStorageBufferDynamic,
// .Stage = vk::ShaderStageFlagBits::eFragment,
// .BindPoint = SHGraphicsConstants::DescriptorSetBindings::SPOT_LIGHT_DATA,
// .DescriptorCount = 1,
//};
// For Dynamic global data (lights) // For Dynamic global data (lights)
Handle<SHVkDescriptorSetLayout> dynamicGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, { lightBinding }); Handle<SHVkDescriptorSetLayout> dynamicGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, lightBindings);
SHVkDescriptorSetLayout::Binding cameraDataBinding SHVkDescriptorSetLayout::Binding cameraDataBinding
{ {
@ -94,7 +115,7 @@ namespace SHADE
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Normals at binding 2 defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Normals at binding 2
defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Tangents at binding 3 defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // 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) }); // Transform at binding 4 - 7 (4 slots)
defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::UINT32_1D) }); // EID at binding 8 defaultVertexInputState.AddBinding(true, true, { SHVertexAttribute(SHAttribFormat::UINT32_2D) }); // Instanced integer data at index 8
} }
void SHGraphicsGlobalData::Init(Handle<SHVkLogicalDevice> logicalDevice) noexcept void SHGraphicsGlobalData::Init(Handle<SHVkLogicalDevice> logicalDevice) noexcept

View File

@ -63,6 +63,14 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
static constexpr uint32_t PER_INSTANCE = 3; static constexpr uint32_t PER_INSTANCE = 3;
/***************************************************************************/
/*!
\brief
DescriptorSet Index for render graph resources.
*/
/***************************************************************************/
static constexpr uint32_t RENDERGRAPH_RESOURCE = 4;
}; };
@ -86,14 +94,32 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
static constexpr uint32_t IMAGE_AND_SAMPLERS_DATA = 1; static constexpr uint32_t IMAGE_AND_SAMPLERS_DATA = 1;
/***************************************************************************/ ///***************************************************************************/
/*! ///*!
\brief // \brief
DescriptorSet binding for lights. // DescriptorSet binding for directional lights.
*/ //*/
/***************************************************************************/ ///***************************************************************************/
static constexpr uint32_t LIGHTS_DATA = 0; //static constexpr uint32_t DIRECTIONAL_LIGHT_DATA = 0;
///***************************************************************************/
///*!
// \brief
// DescriptorSet binding for directional lights.
//*/
///***************************************************************************/
//static constexpr uint32_t POINT_LIGHT_DATA = 1;
///***************************************************************************/
///*!
// \brief
// DescriptorSet binding for directional lights.
//*/
///***************************************************************************/
//static constexpr uint32_t SPOT_LIGHT_DATA = 2;
/***************************************************************************/ /***************************************************************************/
/*! /*!
@ -156,7 +182,7 @@ namespace SHADE
Vertex buffer bindings for the eid buffer. Vertex buffer bindings for the eid buffer.
*/ */
/***************************************************************************/ /***************************************************************************/
static constexpr uint32_t EID = 5; static constexpr uint32_t INTEGER_DATA = 5;
}; };

View File

@ -36,6 +36,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/Images/SHVkSampler.h" #include "Graphics/Images/SHVkSampler.h"
#include "Assets/Asset Types/SHTextureAsset.h" #include "Assets/Asset Types/SHTextureAsset.h"
#include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h" #include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h"
#include "Graphics/MiddleEnd/Lights/SHLightingSubSystem.h"
namespace SHADE namespace SHADE
{ {
@ -115,6 +116,26 @@ namespace SHADE
graphicsCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true); graphicsCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true);
transferCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); transferCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
// TODO: This is VERY temporarily here until a more solid resource management system is implemented
shaderSourceLibrary.Init("../../TempShaderFolder/");
shaderSourceLibrary.LoadShader(0, "TestCubeVs.glsl", SH_SHADER_TYPE::VERTEX, true);
shaderSourceLibrary.LoadShader(1, "TestCubeFs.glsl", SH_SHADER_TYPE::FRAGMENT, true);
shaderSourceLibrary.LoadShader(2, "KirschCs.glsl", SH_SHADER_TYPE::COMPUTE, true);
shaderSourceLibrary.LoadShader(3, "PureCopyCs.glsl", SH_SHADER_TYPE::COMPUTE, true);
shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary);
auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl");
auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl");
auto greyscale = shaderModuleLibrary.GetShaderModule("KirschCs.glsl");
auto pureCopy = shaderModuleLibrary.GetShaderModule("PureCopyCs.glsl");
cubeVS->Reflect();
cubeFS->Reflect();
greyscale->Reflect();
pureCopy->Reflect();
} }
void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept
@ -130,6 +151,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
auto windowDims = window->GetWindowSize(); auto windowDims = window->GetWindowSize();
auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
// Set Up Cameras // Set Up Cameras
screenCamera = resourceManager.Create<SHCamera>(); screenCamera = resourceManager.Create<SHCamera>();
@ -154,21 +176,32 @@ namespace SHADE
// Initialize world render graph // Initialize world render graph
worldRenderGraph->Init(device, swapchain); worldRenderGraph->Init(device, swapchain);
worldRenderGraph->AddResource("Scene", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT }, windowDims.first, windowDims.second); worldRenderGraph->AddResource("Scene Pre-Process", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
worldRenderGraph->AddResource("Depth Buffer", { SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); worldRenderGraph->AddResource("Scene", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
worldRenderGraph->AddResource("Entity ID", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); worldRenderGraph->AddResource("Depth Buffer", { SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint);
worldRenderGraph->AddResource("Entity ID", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
worldRenderGraph->AddResource("Light Layer Indices", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
auto node = worldRenderGraph->AddNode("G-Buffer", { "Entity ID", "Depth Buffer", "Scene"}, {}); // no predecessors auto gBufferNode = worldRenderGraph->AddNode("G-Buffer", { "Light Layer Indices", "Entity ID", "Depth Buffer", "Scene", "Scene Pre-Process"}, {}); // no predecessors
auto gBufferSubpass = gBufferNode->AddSubpass("G-Buffer Write");
gBufferSubpass->AddColorOutput("Scene Pre-Process");
gBufferSubpass->AddColorOutput("Entity ID");
gBufferSubpass->AddColorOutput("Light Layer Indices");
gBufferSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL);
//First subpass to write to G-Buffer //// kirsch
auto gBufferWriteSubpass = node->AddSubpass("G-Buffer Write"); //auto kirschShader = shaderModuleLibrary.GetShaderModule("KirschCs.glsl");
gBufferWriteSubpass->AddColorOutput("Scene"); //gBufferNode->AddNodeCompute(kirschShader, { "Scene Pre-Process", "Scene" });
gBufferWriteSubpass->AddColorOutput("Entity ID");
gBufferWriteSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL); // copy
auto pureCopyShader = shaderModuleLibrary.GetShaderModule("PureCopyCs.glsl");
gBufferNode->AddNodeCompute(pureCopyShader, { "Scene Pre-Process", "Scene" });
auto dummyNode = worldRenderGraph->AddNode("Dummy Pass", { "Scene" }, {"G-Buffer"}); // no predecessors
auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass");
dummySubpass->AddInput("Scene");
// We do this to just transition our scene layout to shader read
auto sceneLayoutTransitionSubpass = node->AddSubpass("Scene Layout Transition");
sceneLayoutTransitionSubpass->AddInput("Scene");
// Generate world render graph // Generate world render graph
worldRenderGraph->Generate(); worldRenderGraph->Generate();
@ -177,20 +210,13 @@ namespace SHADE
worldRenderer = worldViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph); worldRenderer = worldViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph);
worldRenderer->SetCamera(worldCamera); worldRenderer->SetCamera(worldCamera);
worldRenderer->SetCameraDirector(cameraSystem->CreateDirector());
// TODO: This is VERY temporarily here until a more solid resource management system is implemented
shaderSourceLibrary.Init("../../TempShaderFolder/");
shaderSourceLibrary.LoadShader(0, "TestCubeVs.glsl", SH_SHADER_TYPE::VERTEX, true);
shaderSourceLibrary.LoadShader(1, "TestCubeFs.glsl", SH_SHADER_TYPE::FRAGMENT, true);
shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary);
auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl"); auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl");
auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl"); auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl");
cubeVS->Reflect();
cubeFS->Reflect();
defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferWriteSubpass); defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferSubpass);
} }
void SHGraphicsSystem::InitMiddleEnd(void) noexcept void SHGraphicsSystem::InitMiddleEnd(void) noexcept
@ -220,11 +246,15 @@ namespace SHADE
for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i) for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i)
cmdPools.push_back(renderContext.GetFrameData(i).cmdPoolHdls[0]); cmdPools.push_back(renderContext.GetFrameData(i).cmdPoolHdls[0]);
// Mouse picking system for the editor (Will still run with editor disabled)
mousePickSystem->Init(device, cmdPools, worldRenderGraph->GetRenderGraphResource("Entity ID")); mousePickSystem->Init(device, cmdPools, worldRenderGraph->GetRenderGraphResource("Entity ID"));
// Register the post offscreen render to the system // Register the post offscreen render to the system
postOffscreenRender = resourceManager.Create<SHPostOffscreenRenderSystem>(); postOffscreenRender = resourceManager.Create<SHPostOffscreenRenderSystem>();
postOffscreenRender->Init(device, worldRenderGraph->GetRenderGraphResource("Scene"), descPool); postOffscreenRender->Init(device, worldRenderGraph->GetRenderGraphResource("Scene"), descPool);
lightingSubSystem = resourceManager.Create<SHLightingSubSystem>();
lightingSubSystem->Init(device, descPool);
} }
#ifdef SHEDITOR #ifdef SHEDITOR
@ -323,21 +353,7 @@ namespace SHADE
auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>(); auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
#ifdef SHEDITOR
auto editorSystem = SHSystemManager::GetSystem<SHEditor>();
if (editorSystem->editorState != SHEditor::State::PLAY)
{
worldRenderer->SetViewProjectionMatrix(SHMatrix::Transpose(cameraSystem->GetEditorCamera()->GetProjMatrix() * cameraSystem->GetEditorCamera()->GetViewMatrix()));
}
else
{
// main camera
}
#else
// main camera
#endif
// For every viewport // For every viewport
for (int vpIndex = 0; vpIndex < static_cast<int>(viewports.size()); ++vpIndex) for (int vpIndex = 0; vpIndex < static_cast<int>(viewports.size()); ++vpIndex)
@ -356,11 +372,13 @@ namespace SHADE
// Begin recording the command buffer // Begin recording the command buffer
currentCmdBuffer->BeginRecording(); currentCmdBuffer->BeginRecording();
// set viewport and scissor
uint32_t w = static_cast<uint32_t>(viewports[vpIndex]->GetWidth()); uint32_t w = static_cast<uint32_t>(viewports[vpIndex]->GetWidth());
uint32_t h = static_cast<uint32_t>(viewports[vpIndex]->GetHeight()); uint32_t h = static_cast<uint32_t>(viewports[vpIndex]->GetHeight());
currentCmdBuffer->SetViewportScissor (static_cast<float>(w), static_cast<float>(h), w, h); currentCmdBuffer->SetViewportScissor (static_cast<float>(w), static_cast<float>(h), w, h);
currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout()); // Force set the pipeline layout
currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout(), SH_PIPELINE_TYPE::GRAPHICS);
// Bind all the buffers required for meshes // Bind all the buffers required for meshes
for (auto& [buffer, bindingPoint] : MESH_DATA) for (auto& [buffer, bindingPoint] : MESH_DATA)
@ -371,6 +389,8 @@ namespace SHADE
currentCmdBuffer->BindIndexBuffer(buffer, 0); currentCmdBuffer->BindIndexBuffer(buffer, 0);
} }
// Bind the descriptor set for lights
lightingSubSystem->Run(currentCmdBuffer, frameIndex);
// Bind textures // Bind textures
auto textureDescSet = texLibrary.GetTextureDescriptorSetGroup(); auto textureDescSet = texLibrary.GetTextureDescriptorSetGroup();
@ -380,16 +400,31 @@ namespace SHADE
currentCmdBuffer->BindDescriptorSet currentCmdBuffer->BindDescriptorSet
( (
textureDescSet, textureDescSet,
vk::PipelineBindPoint::eGraphics, SH_PIPELINE_TYPE::GRAPHICS,
0, 0,
texDynamicOffset texDynamicOffset
); );
} }
// bind camera data // bind camera data
renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex); //renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
// Draw first #ifdef SHEDITOR
if (renderers[renIndex] == worldRenderer)
{
auto editorSystem = SHSystemManager::GetSystem<SHEditor>();
if (editorSystem->editorState != SHEditor::State::PLAY)
worldRenderer->UpdateDataAndBind(currentCmdBuffer, frameIndex, SHMatrix::Transpose(cameraSystem->GetEditorCamera()->GetProjMatrix() * cameraSystem->GetEditorCamera()->GetViewMatrix()));
else
renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
}
else
renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
#else
renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
#endif
// Draw the scene
renderers[renIndex]->Draw(frameIndex, descPool); renderers[renIndex]->Draw(frameIndex, descPool);
// End the command buffer recording // End the command buffer recording
@ -665,10 +700,10 @@ namespace SHADE
continue; continue;
// Remove from old material's SuperBatch // Remove from old material's SuperBatch
Handle<SHMaterial> prevMaterial = renderable.GetPrevMaterial(); Handle<SHMaterialInstance> prevMaterial = renderable.GetPrevMaterial();
if (prevMaterial) if (prevMaterial)
{ {
Handle<SHSuperBatch> oldSuperBatch = prevMaterial->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch(); Handle<SHSuperBatch> oldSuperBatch = prevMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
oldSuperBatch->Remove(&renderable); oldSuperBatch->Remove(&renderable);
} }
@ -726,8 +761,8 @@ namespace SHADE
auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>(); auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
#ifdef SHEDITOR #ifdef SHEDITOR
cameraSystem->GetEditorCamera()->SetWidth(resizeWidth); cameraSystem->GetEditorCamera()->SetWidth(static_cast<float>(resizeWidth));
cameraSystem->GetEditorCamera()->SetHeight(resizeHeight); cameraSystem->GetEditorCamera()->SetHeight(static_cast<float>(resizeHeight));
#else #else
#endif #endif

View File

@ -32,6 +32,7 @@ of DigiPen Institute of Technology is prohibited.
#include "../Textures/SHTextureLibrary.h" #include "../Textures/SHTextureLibrary.h"
#include "../Textures/SHVkSamplerCache.h" #include "../Textures/SHVkSamplerCache.h"
#include "Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.h" #include "Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.h"
#include "Graphics/MiddleEnd/Lights/SHLightingSubSystem.h"
namespace SHADE namespace SHADE
{ {
@ -351,6 +352,7 @@ namespace SHADE
// Sub systems // Sub systems
Handle<SHMousePickSystem> mousePickSystem; Handle<SHMousePickSystem> mousePickSystem;
Handle<SHPostOffscreenRenderSystem> postOffscreenRender; Handle<SHPostOffscreenRenderSystem> postOffscreenRender;
Handle<SHLightingSubSystem> lightingSubSystem;
uint32_t resizeWidth; uint32_t resizeWidth;
uint32_t resizeHeight; uint32_t resizeHeight;

View File

@ -0,0 +1,12 @@
#pragma once
#include "ECS_Base/SHECSMacros.h"
namespace SHADE
{
struct SHInstancedIntegerData
{
EntityID eid;
uint32_t lightLayer;
};
}

View File

@ -7,6 +7,7 @@
#include "Graphics/Buffers/SHVkBuffer.h" #include "Graphics/Buffers/SHVkBuffer.h"
#include "Graphics/SHVkUtil.h" #include "Graphics/SHVkUtil.h"
#include "Graphics/MiddleEnd/Interface/SHViewport.h" #include "Graphics/MiddleEnd/Interface/SHViewport.h"
//#include "Graphics/MiddleEnd/Interface/SHInstancedIntegerData.h"
namespace SHADE namespace SHADE
{ {
@ -53,7 +54,7 @@ namespace SHADE
// wait for the copy to be done // wait for the copy to be done
afterCopyFence->Wait(true, std::numeric_limits<uint64_t>::max()); afterCopyFence->Wait(true, std::numeric_limits<uint64_t>::max());
pickedEID = imageDataDstBuffer->GetDataFromMappedPointer<uint32_t>(static_cast<uint32_t>(viewportMousePos.y) * entityIDAttachment->GetWidth() + static_cast<uint32_t>(viewportMousePos.x)); pickedEID = imageDataDstBuffer->GetDataFromMappedPointer<EntityID>(static_cast<uint32_t>(viewportMousePos.y) * entityIDAttachment->GetWidth() + static_cast<uint32_t>(viewportMousePos.x));
} }
} }

View File

@ -27,19 +27,22 @@ namespace SHADE
sharedMaterial = {}; sharedMaterial = {};
material = {}; material = {};
oldMaterial = {}; oldMaterial = {};
lightLayer = 0;
} }
void SHRenderable::OnDestroy() void SHRenderable::OnDestroy()
{ {
// Remove from SuperBatch
Handle<SHSuperBatch> superBatch = sharedMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
superBatch->Remove(this);
// Free resources
if (material) if (material)
{ {
material.Free(); material.Free();
material = {}; material = {};
} }
// Remove from SuperBatch
Handle<SHSuperBatch> superBatch = sharedMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
superBatch->Remove(this);
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -51,20 +54,23 @@ namespace SHADE
if (!material && sharedMaterial == materialInstance) if (!material && sharedMaterial == materialInstance)
return; return;
// Flag that material was changed
materialChanged = true;
// Free copies of materials if any // Free copies of materials if any
if (material) if (material)
{ {
oldMaterial = material;
material.Free(); material.Free();
material = {}; material = {};
} }
else if (sharedMaterial)
// Flag that material was changed {
materialChanged = true; oldMaterial = sharedMaterial;
if (sharedMaterial) }
oldMaterial = sharedMaterial->GetBaseMaterial();
// Update the material // Update the material
sharedMaterial = materialInstance; sharedMaterial = materialInstance;
} }
Handle<SHMaterialInstance> SHRenderable::GetMaterial() const Handle<SHMaterialInstance> SHRenderable::GetMaterial() const
@ -87,6 +93,11 @@ namespace SHADE
return material; return material;
} }
uint8_t SHRenderable::GetLightLayer(void) const noexcept
{
return lightLayer;
}
void SHRenderable::ResetChangedFlag() void SHRenderable::ResetChangedFlag()
{ {
materialChanged = false; materialChanged = false;

View File

@ -55,7 +55,8 @@ namespace SHADE
/* Getter Functions */ /* Getter Functions */
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
bool WasMaterialChanged() const noexcept { return materialChanged; } bool WasMaterialChanged() const noexcept { return materialChanged; }
Handle<SHMaterial> GetPrevMaterial() const noexcept { return oldMaterial; } Handle<SHMaterialInstance> GetPrevMaterial() const noexcept { return oldMaterial; }
uint8_t GetLightLayer (void) const noexcept;
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
/* Batcher Dispatcher Functions */ /* Batcher Dispatcher Functions */
@ -74,7 +75,8 @@ namespace SHADE
Handle<SHMaterialInstance> sharedMaterial; Handle<SHMaterialInstance> sharedMaterial;
Handle<SHMaterialInstance> material; Handle<SHMaterialInstance> material;
bool materialChanged = true; bool materialChanged = true;
Handle<SHMaterial> oldMaterial; Handle<SHMaterialInstance> oldMaterial;
uint8_t lightLayer;
}; };
} }

View File

@ -21,6 +21,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" #include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/Buffers/SHVkBuffer.h" #include "Graphics/Buffers/SHVkBuffer.h"
#include "Camera/SHCameraDirector.h"
namespace SHADE namespace SHADE
{ {
@ -65,6 +66,11 @@ namespace SHADE
camera = _camera; camera = _camera;
} }
void SHRenderer::SetCameraDirector(Handle<SHCameraDirector> director) noexcept
{
cameraDirector = director;
}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Drawing Functions */ /* Drawing Functions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -75,17 +81,24 @@ namespace SHADE
void SHRenderer::UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept void SHRenderer::UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{ {
if (camera) if (camera && cameraDirector)
{ {
//cpuCameraData.viewProjectionMatrix = camera->GetViewProjectionMatrix(); UpdateDataAndBind(cmdBuffer, frameIndex, SHMatrix::Transpose(cameraDirector->GetVPMatrix()));
cameraBuffer->WriteToMemory(&cpuCameraData, sizeof(SHShaderCameraData), 0, cameraDataAlignedSize * frameIndex);
std::array<uint32_t, 1> dynamicOffsets{ frameIndex * cameraDataAlignedSize };
cmdBuffer->BindDescriptorSet(cameraDescriptorSet, vk::PipelineBindPoint::eGraphics, SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, std::span{ dynamicOffsets.data(), 1 });
} }
} }
void SHRenderer::UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, SHMatrix exteriorMatrix) noexcept
{
SetViewProjectionMatrix(exteriorMatrix);
//cpuCameraData.viewProjectionMatrix = camera->GetViewProjectionMatrix();
cameraBuffer->WriteToMemory(&cpuCameraData, sizeof(SHShaderCameraData), 0, cameraDataAlignedSize * frameIndex);
std::array<uint32_t, 1> dynamicOffsets{ frameIndex * cameraDataAlignedSize };
cmdBuffer->BindDescriptorSet(cameraDescriptorSet, SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, std::span{ dynamicOffsets.data(), 1 });
}
void SHRenderer::UpdateCameraDataToBuffer(void) noexcept void SHRenderer::UpdateCameraDataToBuffer(void) noexcept
{ {
} }

View File

@ -40,6 +40,7 @@ namespace SHADE
class SHGraphicsGlobalData; class SHGraphicsGlobalData;
class SHVkDescriptorPool; class SHVkDescriptorPool;
class SHVkBuffer; class SHVkBuffer;
class SHCameraDirector;
struct SHShaderCameraData struct SHShaderCameraData
{ {
@ -71,12 +72,14 @@ namespace SHADE
/* Camera Registration */ /* Camera Registration */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
void SetCamera(Handle<SHCamera> _camera); void SetCamera(Handle<SHCamera> _camera);
void SetCameraDirector (Handle<SHCameraDirector> director) noexcept;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Drawing Functions */ /* Drawing Functions */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
void Draw(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept; void Draw(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept;
void UpdateDataAndBind (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept; void UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, SHMatrix exteriorMatrix) noexcept;
void UpdateCameraDataToBuffer (void) noexcept; void UpdateCameraDataToBuffer (void) noexcept;
void SetViewProjectionMatrix (SHMatrix const& vpMatrix) noexcept; void SetViewProjectionMatrix (SHMatrix const& vpMatrix) noexcept;
@ -99,6 +102,8 @@ namespace SHADE
Handle<SHVkDescriptorSetGroup> cameraDescriptorSet; Handle<SHVkDescriptorSetGroup> cameraDescriptorSet;
Handle<SHVkBuffer> cameraBuffer; Handle<SHVkBuffer> cameraBuffer;
Handle<SHCameraDirector> cameraDirector;
// we really only need 1 copy even though we need %swapchainImages copies for // we really only need 1 copy even though we need %swapchainImages copies for
// GPU. // GPU.
SHShaderCameraData cpuCameraData; SHShaderCameraData cpuCameraData;

View File

@ -0,0 +1,123 @@
#include "SHpch.h"
#include "SHLightComponent.h"
namespace SHADE
{
void SHLightComponent::OnCreate(void)
{
lightData.Reset();
SetType(SH_LIGHT_TYPE::DIRECTIONAL);
indexInBuffer = std::numeric_limits<uint32_t>::max();
active = true;
Unbind();
}
void SHLightComponent::OnDestroy(void)
{
}
void SHLightComponent::SetPosition(SHVec3 position) noexcept
{
lightData.position = position;
MakeDirty();
}
void SHLightComponent::SetType(SH_LIGHT_TYPE type) noexcept
{
lightData.type = type;
MakeDirty();
}
void SHLightComponent::SetDirection(SHVec3 direction) noexcept
{
lightData.direction = direction;
MakeDirty();
}
void SHLightComponent::SetDiffuseColor(SHVec4 diffuseColor) noexcept
{
lightData.diffuseColor = diffuseColor;
MakeDirty();
}
void SHLightComponent::ModifyLayer(uint8_t layerIndex, bool value) noexcept
{
if (value)
lightData.cullingMask |= (1u << layerIndex);
else
lightData.cullingMask &= ~(1u << layerIndex);
MakeDirty();
}
void SHLightComponent::SetAllLayers(void) noexcept
{
lightData.cullingMask = std::numeric_limits<uint32_t>::max();
MakeDirty();
}
void SHLightComponent::ClearAllLayers(void) noexcept
{
lightData.cullingMask = 0;
MakeDirty();
}
void SHLightComponent::MakeDirty(void) noexcept
{
dirty = true;
}
void SHLightComponent::ClearDirtyFlag(void) noexcept
{
dirty = false;
}
void SHLightComponent::Unbind(void) noexcept
{
bound = false;
MakeDirty();
}
void SHLightComponent::SetBound(uint32_t inIndexInBuffer) noexcept
{
bound = true;
indexInBuffer = inIndexInBuffer;
}
void SHLightComponent::SetActive(bool flag) noexcept
{
MakeDirty();
active = flag;
}
SHLightData const& SHLightComponent::GetLightData(void) const noexcept
{
return lightData;
}
bool SHLightComponent::IsDirty(void) const noexcept
{
return dirty;
}
bool SHLightComponent::GetBound(void) const noexcept
{
return bound;
}
uint32_t SHLightComponent::GetIndexInBuffer(void) const noexcept
{
return indexInBuffer;
}
}

View File

@ -0,0 +1,60 @@
#pragma once
#include "ECS_Base/Components/SHComponent.h"
#include "SHLightData.h"
namespace SHADE
{
class SH_API SHLightComponent final : public SHComponent
{
private:
//! General data for the light. This will purely be CPU bound. Whatever gets sent to the
//! GPU depends on the type of the light.
SHLightData lightData;
//! Since the lighting system is gonna be self contained and light weight, we store this
//! so that we only write this to the CPU buffer when this light component change, we don't
//! rewrite everything. However we still write to the GPU buffer when everything changes.
uint32_t indexInBuffer;
//! If the light component changed some value we mark this true.
bool dirty;
//! If the light's data is already in the buffers, this will be set to true.
bool bound;
//! If the light is active, this is true.
bool active;
public:
/*-----------------------------------------------------------------------*/
/* LIFECYCLE FUNCTIONS */
/*-----------------------------------------------------------------------*/
void OnCreate (void) override final;
void OnDestroy (void) override final;
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
void SetPosition (SHVec3 position) noexcept;
void SetType (SH_LIGHT_TYPE type) noexcept;
void SetDirection (SHVec3 direction) noexcept;
void SetDiffuseColor (SHVec4 diffuseColor) noexcept;
void ModifyLayer (uint8_t layerIndex, bool value) noexcept;
void SetAllLayers (void) noexcept;
void ClearAllLayers (void) noexcept;
void MakeDirty (void) noexcept;
void ClearDirtyFlag (void) noexcept;
void Unbind (void) noexcept;
void SetBound (uint32_t inIndexInBuffer) noexcept;
void SetActive (bool flag) noexcept;
SHLightData const& GetLightData (void) const noexcept;
bool IsDirty (void) const noexcept;
bool GetBound (void) const noexcept;
uint32_t GetIndexInBuffer (void) const noexcept;
};
}

View File

@ -0,0 +1,21 @@
#include "SHpch.h"
#include "SHLightData.h"
namespace SHADE
{
void SHLightData::Reset(void) noexcept
{
// no culling is done.
cullingMask = std::numeric_limits<uint32_t>::max();
// reset position to 0
position = SHVec3::Zero;
// direction just point in positive z axis
direction = SHVec3::Forward;
// Diffuse color set to 1
diffuseColor = SHVec4::One;
}
}

View File

@ -0,0 +1,55 @@
#pragma once
#include "Math/Vector/SHVec3.h"
#include "Math/Vector/SHVec4.h"
namespace SHADE
{
enum class SH_LIGHT_TYPE : uint32_t
{
DIRECTIONAL = 0,
POINT,
SPOT,
NUM_TYPES
};
/***************************************************************************/
/*!
\class
Every light will essentially be using this struct. However, when passing
light data over to the GPU, the light data will be split according to
type for more optimal cache access.
*/
/***************************************************************************/
struct SHLightData
{
//! position of the light
SHVec3 position;
//! Type of the light
SH_LIGHT_TYPE type;
//! direction of the light
SHVec3 direction;
//! Each bit in this 32 bit field will represent a layer. If the bit is set,
//! when a fragment is being evaluated, the shader will use the fragment's
//! layer value to AND with the light's. If result is 1, do lighting calculations.
uint32_t cullingMask;
//! Diffuse color emitted by the light
SHVec4 diffuseColor;
void Reset (void) noexcept;
//! TODO:
//! - Add cut off. (inner and outer).
//! - Add constant, linear and quadratic for attenuation
//! - Specular color if needed. see below.
//! Specular color
//SHVec4 specularColor;
};
}

View File

@ -0,0 +1,431 @@
#include "SHpch.h"
#include "SHLightingSubSystem.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h"
#include "Tools/SHUtilities.h"
#include "Graphics/Devices/SHVkLogicalDevice.h"
#include "Graphics/Buffers/SHVkBuffer.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "SHLightComponent.h"
#include "ECS_Base/Managers/SHComponentManager.h"
#include "SHLightComponent.h"
namespace SHADE
{
/***************************************************************************/
/*!
\brief
This function takes an address in the CPU container and writes light
component data to it. What gets written depends on the light type.
\param address
The address to write to.
\param lightComp
The light component with the data to write from.
\param lightType
The type of the light
\return
*/
/***************************************************************************/
void SHLightingSubSystem::PerTypeData::WriteLightToAddress(void* address, SHLightComponent* lightComp) noexcept
{
auto const& lightData = lightComp->GetLightData();
switch (lightData.type)
{
case SH_LIGHT_TYPE::DIRECTIONAL:
{
SHDirectionalLightData* lightPtr = reinterpret_cast<SHDirectionalLightData*>(address);
lightPtr->cullingMask = lightData.cullingMask;
lightPtr->direction = lightData.direction;
lightPtr->diffuseColor = lightData.diffuseColor;
break;
}
case SH_LIGHT_TYPE::POINT:
break;
case SH_LIGHT_TYPE::SPOT:
break;
case SH_LIGHT_TYPE::NUM_TYPES:
break;
default:
break;
}
}
/***************************************************************************/
/*!
\brief
Initializes type, intermediate data and buffer. dirty will be true.
\param lightType
type of the light.
*/
/***************************************************************************/
void SHLightingSubSystem::PerTypeData::InitializeData(Handle<SHVkLogicalDevice> logicalDevice, SH_LIGHT_TYPE type) noexcept
{
// initialize the type
lightType = type;
// boilerplate
intermediateData = nullptr;
// initialize alignment
lightDataAlignmentSize = logicalDevice->PadSSBOSize(GetLightTypeSize(type));
// So create some data!
Expand(logicalDevice);
}
/***************************************************************************/
/*!
\brief
Expands both the CPU container and the GPU buffer when the number of
lights have exceeded the capacity.
*/
/***************************************************************************/
void SHLightingSubSystem::PerTypeData::Expand(Handle<SHVkLogicalDevice> logicalDevice) noexcept
{
if (lightDataAlignmentSize == 0)
{
SHLOG_ERROR ("One of the types of lights have not been accounted for. Make sure lightDataAlignmentSize is not nullptr.");
return;
}
// we want to wait for the command buffers to finish using the buffers first
logicalDevice->WaitIdle();
// First time we are initializing lights
if (intermediateData == nullptr)
{
// max lights should start of at STARTING_NUM_LIGHTS lights
maxLights = STARTING_NUM_LIGHTS;
numLights = 0;
// Initialize the data for lights
intermediateData = std::make_unique<uint8_t[]>(lightDataAlignmentSize * maxLights);
// We want to initialize 3 times the amount of data required.
dataBuffer = logicalDevice->CreateBuffer(maxLights * lightDataAlignmentSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, nullptr, maxLights * lightDataAlignmentSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT);
}
else
{
// save old number of lights
uint32_t const OLD_MAX_LIGHTS = maxLights;
// before we increase the number of lights, create space to store old data.
std::unique_ptr<uint8_t[]> oldData = std::make_unique<uint8_t[]>(lightDataAlignmentSize * OLD_MAX_LIGHTS);
// copy data over.
std::memcpy (oldData.get(), intermediateData.get(), lightDataAlignmentSize * OLD_MAX_LIGHTS);
// now we start to expand....
// double space for lights
maxLights *= 2;
// destroy old data and initialize container for double the amount of data.
intermediateData = std::make_unique<uint8_t[]>(lightDataAlignmentSize * maxLights);
// copy old data to new container
std::memcpy(intermediateData.get(), oldData.get(), lightDataAlignmentSize * OLD_MAX_LIGHTS);
// Resize the GPU buffer. TODO: Replace with Resize no copy here
dataBuffer->ResizeReplace(maxLights * lightDataAlignmentSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, oldData.get(), lightDataAlignmentSize * OLD_MAX_LIGHTS);
}
}
/***************************************************************************/
/*!
\brief
Gets the size required to store data for a light type.
\param type
Type of a light.
\return
Size required to store a light based on type.
*/
/***************************************************************************/
uint32_t SHLightingSubSystem::PerTypeData::GetLightTypeSize(SH_LIGHT_TYPE type) noexcept
{
switch (type)
{
case SH_LIGHT_TYPE::DIRECTIONAL:
// TOOD: Change after creating point light struct
return sizeof(SHDirectionalLightData);
case SH_LIGHT_TYPE::POINT:
return 4;
case SH_LIGHT_TYPE::SPOT:
// TOOD: Change after creating spot light struct
return 4;
case SH_LIGHT_TYPE::NUM_TYPES:
default:
return 4;
}
}
Handle<SHVkBuffer> SHLightingSubSystem::PerTypeData::GetDataBuffer(void) const noexcept
{
return dataBuffer;
}
uint32_t SHLightingSubSystem::PerTypeData::GetAlignmentSize(void) const noexcept
{
return lightDataAlignmentSize;
}
uint32_t SHLightingSubSystem::PerTypeData::GetNumLights(void) const noexcept
{
return numLights;
}
uint32_t SHLightingSubSystem::PerTypeData::GetMaxLights(void) const noexcept
{
return maxLights;
}
/***************************************************************************/
/*!
\brief
This function takes in a light comp in the event that its data has not
been placed in the buffer yet. It also checks if the size of the buffer
is big enough to hold the new light. If the buffer is too small, expand
it.
\param lightComp
The light component to add.
*/
/***************************************************************************/
void SHLightingSubSystem::PerTypeData::AddLight(Handle<SHVkLogicalDevice> logicalDevice, SHLightComponent* unboundLight, bool expanded) noexcept
{
if (unboundLight)
{
// capacity is full
if (numLights == maxLights)
{
// expand first
Expand(logicalDevice);
expanded = true;
}
// Now that the container is big enough, bind the new light
// Get address of write location
void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignmentSize * numLights);
// Write the light data to address
WriteLightToAddress(writeLocation, unboundLight);
// Set the light component to be bound to that location
unboundLight->SetBound(numLights);
// Increase light count
++numLights;
}
}
/***************************************************************************/
/*!
\brief
Modify the data at a specific light address.
\param lightComp
The light component to write.
*/
/***************************************************************************/
void SHLightingSubSystem::PerTypeData::ModifyLight(SHLightComponent* lightComp) noexcept
{
void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignmentSize * lightComp->GetIndexInBuffer());
WriteLightToAddress(writeLocation, lightComp);
}
void SHLightingSubSystem::PerTypeData::WriteToGPU(uint32_t frameIndex) noexcept
{
if (intermediateData)
{
// we want to write to the offset of the current frame
dataBuffer->WriteToMemory(intermediateData.get(), lightDataAlignmentSize * numLights, 0, lightDataAlignmentSize * maxLights * frameIndex);
}
}
/***************************************************************************/
/*!
\brief
Update descriptor sets. We want to call this every time we expand buffers.
\param binding
The binding in the set we want to update.
*/
/***************************************************************************/
void SHLightingSubSystem::UpdateDescSet(uint32_t binding) noexcept
{
auto buffer = perTypeData[binding].GetDataBuffer();
// We bind the buffer with the correct desc set binding
lightingDataDescSet->ModifyWriteDescBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS,
binding,
{ &buffer, 1 },
0,
perTypeData[binding].GetAlignmentSize() * perTypeData[binding].GetMaxLights());
lightingDataDescSet->UpdateDescriptorSetBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, binding);
}
/***************************************************************************/
/*!
\brief
Computes dynamic offsets.
*/
/***************************************************************************/
void SHLightingSubSystem::ComputeDynamicOffsets(void) noexcept
{
for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{
for (uint32_t j = 0; j < dynamicOffsets.size(); ++j)
{
auto const& typeData = perTypeData[j];
{
dynamicOffsets[i][j] = j * typeData.GetAlignmentSize() * typeData.GetMaxLights();
}
}
}
}
/***************************************************************************/
/*!
\brief
Initializes per light type data. This includes buffers and descriptor
sets.
*/
/***************************************************************************/
void SHLightingSubSystem::Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool) noexcept
{
SHComponentManager::CreateComponentSparseSet<SHLightComponent>();
logicalDevice = device;
uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES);
std::vector<uint32_t> variableSizes{ NUM_LIGHT_TYPES };
std::fill (variableSizes.begin(), variableSizes.end(), 1);
// Create the descriptor set
lightingDataDescSet = descPool->Allocate({SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS]}, variableSizes);
for (uint32_t i = 0; i < NUM_LIGHT_TYPES; ++i)
{
// initialize all the data first. We add more lights here as we add more types.
perTypeData[i].InitializeData(logicalDevice, static_cast<SH_LIGHT_TYPE>(i));
UpdateDescSet(i);
}
for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{
dynamicOffsets[i].resize(NUM_LIGHT_TYPES);
}
}
/***************************************************************************/
/*!
\brief
Loops through every single light component and checks for dirty light
data. If light data is dirty, rewrite to the CPU container. We also want
to bind the descriptor set for the light data.
*/
/***************************************************************************/
void SHLightingSubSystem::Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{
auto& lightComps = SHComponentManager::GetDense<SHLightComponent>();
bool expanded = false;
for (auto& light : lightComps)
{
auto enumValue = SHUtilities::ToUnderlying(light.GetLightData().type);
// First we want to make sure the light is already bound to the system. if it
// isn't, we write it to the correct buffer.
if (!light.GetBound())
{
perTypeData[enumValue].AddLight(logicalDevice, &light, expanded);
}
// if there was modification to the light data
if (light.IsDirty())
{
// Write the data to the CPU
perTypeData[enumValue].ModifyLight(&light);
// Light is now updated in the container
light.ClearDirtyFlag();
}
}
// Write data to GPU
for (auto& data : perTypeData)
{
data.WriteToGPU(frameIndex);
}
// If any of the buffers got expanded, the descriptor set is invalid because the expanded buffer
// is a new buffer. If some expansion was detected, update descriptor sets.
if (expanded)
{
uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES);
for (uint32_t i = 0; i < NUM_LIGHT_TYPES; ++i)
{
UpdateDescSet(i);
}
}
// compute dynamic offsets. We don't actually have to compute every frame but its pretty lightweight,
// so we do it anyway. #NoteToSelf: if at any point it affects performance, do a check before computing.
ComputeDynamicOffsets();
// Bind descriptor set (We bind at an offset because the buffer holds NUM_FRAME_BUFFERS sets of data).
cmdBuffer->BindDescriptorSet(lightingDataDescSet, SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, {dynamicOffsets[frameIndex]});
}
/***************************************************************************/
/*!
\brief
Does nothing for now.
*/
/***************************************************************************/
void SHLightingSubSystem::Exit(void) noexcept
{
}
}

View File

@ -0,0 +1,124 @@
#pragma once
#include "Resource/SHHandle.h"
#include "Math/Vector/SHVec3.h"
#include "Math/Vector/SHVec4.h"
#include "SHLightData.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
namespace SHADE
{
class SHVkLogicalDevice;
class SHVkDescriptorPool;
class SHVkDescriptorSetGroup;
class SHVkDescriptorSetLayout;
class SHVkBuffer;
class SHLightComponent;
class SHVkCommandBuffer;
// Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU.
struct SHDirectionalLightData
{
//! Direction of the light
SHVec3 direction;
//! Represents if the light is active or not
uint32_t active;
//! Each bit in this 32 bit field will represent a layer. If the bit is set,
//! when a fragment is being evaluated, the shader will use the fragment's
//! layer value to AND with the light's. If result is 1, do lighting calculations.
uint32_t cullingMask;
//! Diffuse color emitted by the light
SHVec4 diffuseColor;
};
class SH_API SHLightingSubSystem
{
private:
class PerTypeData
{
private:
/*-----------------------------------------------------------------------*/
/* STATIC MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
static constexpr uint32_t STARTING_NUM_LIGHTS = 20;
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
//! Capacity of the container.
uint32_t maxLights;
//! SSBOs need to be aligned. This is to pad lighting structs
uint32_t lightDataAlignmentSize;
//! type of the light. Will be used later when we want to expand
SH_LIGHT_TYPE lightType;
//! number of lights currently alive.
uint32_t numLights;
//! GPU buffer required to store GPU data
Handle<SHVkBuffer> dataBuffer;
//! Before data gets copied to the GPU, it goes into here first. Data here is aligned to whatever struct is
//! used to represent data in this container. Note this will store only 1 copy of all the lights, compared
//! to the GPU that stores NUM_FRAME_BUFFERS copies.
std::unique_ptr<uint8_t[]> intermediateData;
void WriteLightToAddress (void* address, SHLightComponent* lightComp) noexcept;
public:
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void InitializeData (Handle<SHVkLogicalDevice> logicalDevice, SH_LIGHT_TYPE type) noexcept;
void Expand (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
void AddLight (Handle<SHVkLogicalDevice> logicalDevice, SHLightComponent* unboundLight, bool expanded) noexcept;
void ModifyLight (SHLightComponent* lightComp) noexcept;
void WriteToGPU (uint32_t frameIndex) noexcept;
/*-----------------------------------------------------------------------*/
/* GETTERS */
/*-----------------------------------------------------------------------*/
static uint32_t GetLightTypeSize (SH_LIGHT_TYPE type) noexcept;
Handle<SHVkBuffer> GetDataBuffer (void) const noexcept;
uint32_t GetAlignmentSize (void) const noexcept;
uint32_t GetNumLights (void) const noexcept;
uint32_t GetMaxLights (void) const noexcept;
};
private:
//! logical device used for creation
Handle<SHVkLogicalDevice> logicalDevice;
//! The descriptor set that will hold the lighting data. Each binding will hold a buffer, NUM_FRAMES times the size required.
Handle<SHVkDescriptorSetGroup> lightingDataDescSet;
//! Each type will have some data associated with it for processing
std::array<PerTypeData, static_cast<uint32_t>(SH_LIGHT_TYPE::NUM_TYPES)> perTypeData;
//! Container to store dynamic offsets for binding descriptor sets
std::array<std::vector<uint32_t>, static_cast<uint32_t>(SHGraphicsConstants::NUM_FRAME_BUFFERS)> dynamicOffsets;
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void UpdateDescSet (uint32_t binding) noexcept;
void ComputeDynamicOffsets (void) noexcept;
public:
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void Init (Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool) noexcept;
void Run (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void Exit (void) noexcept;
};
}

View File

@ -8,7 +8,7 @@
namespace SHADE namespace SHADE
{ {
Handle<SHVkPipeline> SHPipelineLibrary::CreateDrawPipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHVkRenderpass> renderpass, Handle<SHSubpass> subpass) noexcept Handle<SHVkPipeline> SHPipelineLibrary::CreateGraphicsPipelines(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHVkRenderpass> renderpass, Handle<SHSubpass> subpass) noexcept
{ {
SHPipelineLayoutParams params SHPipelineLayoutParams params
{ {
@ -52,7 +52,7 @@ namespace SHADE
newPipeline->ConstructPipeline(); newPipeline->ConstructPipeline();
// Emplace the new pipeline // Emplace the new pipeline
pipelines.emplace (vsFsPair, newPipeline); graphicsPipelines.emplace (vsFsPair, newPipeline);
return newPipeline; return newPipeline;
} }
@ -62,19 +62,19 @@ namespace SHADE
logicalDevice = device; logicalDevice = device;
} }
Handle<SHVkPipeline> SHPipelineLibrary::GetDrawPipline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept Handle<SHVkPipeline> SHPipelineLibrary::GetGraphicsPipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept
{ {
// return the pipeline requested for // return the pipeline requested for
if (pipelines.contains(vsFsPair)) if (graphicsPipelines.contains(vsFsPair))
return pipelines.at(vsFsPair); return graphicsPipelines.at(vsFsPair);
else else
return {}; return {};
} }
bool SHPipelineLibrary::CheckDrawPipelineExistence(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept bool SHPipelineLibrary::CheckGraphicsPipelineExistence(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept
{ {
// Returns if a pipeline exists or not // Returns if a pipeline exists or not
return pipelines.contains(vsFsPair); return graphicsPipelines.contains(vsFsPair);
} }
} }

View File

@ -23,19 +23,19 @@ namespace SHADE
Handle<SHVkLogicalDevice> logicalDevice; Handle<SHVkLogicalDevice> logicalDevice;
//! a map of pipelines that are hashed using a pair of shader module handles //! a map of pipelines that are hashed using a pair of shader module handles
std::unordered_map<std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>>, Handle<SHVkPipeline>> pipelines; std::unordered_map<std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>>, Handle<SHVkPipeline>> graphicsPipelines;
public: public:
void Init (Handle<SHVkLogicalDevice> device) noexcept; void Init (Handle<SHVkLogicalDevice> device) noexcept;
// Draw pipeline functions. used only when creating pipelines for drawing using a vertex and fragment shader // Draw pipeline functions. used only when creating pipelines for drawing using a vertex and fragment shader
Handle<SHVkPipeline> CreateDrawPipeline ( Handle<SHVkPipeline> CreateGraphicsPipelines (
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
) noexcept; ) noexcept;
Handle<SHVkPipeline> GetDrawPipline (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept; Handle<SHVkPipeline> GetGraphicsPipeline (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept;
bool CheckDrawPipelineExistence (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept; bool CheckGraphicsPipelineExistence (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept;
}; };
} }

View File

@ -142,6 +142,12 @@ namespace SHADE
case SHAttribFormat::UINT32_1D: case SHAttribFormat::UINT32_1D:
return std::make_tuple(1, 4, vk::Format::eR32Uint); return std::make_tuple(1, 4, vk::Format::eR32Uint);
case SHAttribFormat::UINT32_2D:
return std::make_tuple(1, 8, vk::Format::eR32G32Uint);
case SHAttribFormat::UINT32_3D:
return std::make_tuple(1, 12, vk::Format::eR32G32B32Uint);
case SHAttribFormat::UINT32_4D:
return std::make_tuple(1, 16, vk::Format::eR32G32B32A32Uint);
} }
return std::make_tuple(0, 0, vk::Format::eR32Sfloat); return std::make_tuple(0, 0, vk::Format::eR32Sfloat);
} }

View File

@ -5,9 +5,13 @@ namespace SHADE
{ {
enum class SH_PIPELINE_TYPE enum class SH_PIPELINE_TYPE
{ {
GRAPHICS, GRAPHICS = 0,
COMPUTE, COMPUTE,
RAY_TRACING,
NUM_TYPES,
}; };
} }
#endif #endif

View File

@ -4,6 +4,7 @@
#include "Graphics/Shaders/SHVkShaderModule.h" #include "Graphics/Shaders/SHVkShaderModule.h"
#include "Graphics/Debugging/SHVulkanDebugUtil.h" #include "Graphics/Debugging/SHVulkanDebugUtil.h"
#include "Graphics/RenderGraph/SHRenderGraph.h" #include "Graphics/RenderGraph/SHRenderGraph.h"
#include "Graphics/SHVkUtil.h"
namespace SHADE namespace SHADE
{ {
@ -171,6 +172,29 @@ namespace SHADE
void SHVkPipeline::CreateComputePipeline(void) noexcept void SHVkPipeline::CreateComputePipeline(void) noexcept
{ {
auto shaderModule = pipelineLayout->GetShaderModules()[0];
vk::PipelineShaderStageCreateInfo shaderStageCreateInfo
{
.stage = vk::ShaderStageFlagBits::eCompute,
.module = shaderModule->GetVkShaderModule(),
.pName = shaderModule->GetEntryPoint().c_str(),
};
vk::ComputePipelineCreateInfo cpCreateInfo
{
.flags = {},
.stage = shaderStageCreateInfo,
.layout = pipelineLayout->GetVkPipelineLayout(),
};
if (auto result = logicalDeviceHdl->GetVkLogicalDevice().createComputePipelines({}, 1, &cpCreateInfo, nullptr, &vkPipeline); result != vk::Result::eSuccess)
SHVulkanDebugUtil::ReportVkError(result, "Failed to create Compute Pipeline. ");
else
{
SHVulkanDebugUtil::ReportVkSuccess("Successfully created a Compute Pipeline. ");
created = true;
}
} }
@ -245,7 +269,7 @@ namespace SHADE
, logicalDeviceHdl{ rhs.logicalDeviceHdl } , logicalDeviceHdl{ rhs.logicalDeviceHdl }
, pipelineLayout { rhs.pipelineLayout } , pipelineLayout { rhs.pipelineLayout }
{ {
vkPipeline = VK_NULL_HANDLE; rhs.vkPipeline = VK_NULL_HANDLE;
} }
/***************************************************************************/ /***************************************************************************/
@ -285,7 +309,8 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
SHVkPipeline::~SHVkPipeline(void) noexcept SHVkPipeline::~SHVkPipeline(void) noexcept
{ {
logicalDeviceHdl->GetVkLogicalDevice().destroyPipeline(vkPipeline, nullptr); if (vkPipeline)
logicalDeviceHdl->GetVkLogicalDevice().destroyPipeline(vkPipeline, nullptr);
} }
/***************************************************************************/ /***************************************************************************/
@ -313,7 +338,7 @@ namespace SHADE
created = rhs.created; created = rhs.created;
logicalDeviceHdl = rhs.logicalDeviceHdl; logicalDeviceHdl = rhs.logicalDeviceHdl;
vkPipeline = VK_NULL_HANDLE; rhs.vkPipeline = VK_NULL_HANDLE;
return *this; return *this;
} }
@ -399,18 +424,7 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
vk::PipelineBindPoint SHVkPipeline::GetPipelineBindPoint(void) const noexcept vk::PipelineBindPoint SHVkPipeline::GetPipelineBindPoint(void) const noexcept
{ {
switch (pipelineType) return SHVkUtil::GetPipelineBindPointFromType(pipelineType);
{
case SH_PIPELINE_TYPE::GRAPHICS:
return vk::PipelineBindPoint::eGraphics;
case SH_PIPELINE_TYPE::COMPUTE:
return vk::PipelineBindPoint::eCompute;
break;
default:
return vk::PipelineBindPoint::eGraphics;
break;
}
} }
/***************************************************************************/ /***************************************************************************/
@ -450,4 +464,9 @@ namespace SHADE
return pipelineLayout; return pipelineLayout;
} }
SH_PIPELINE_TYPE SHVkPipeline::GetPipelineType(void) const noexcept
{
return pipelineType;
}
} }

View File

@ -77,6 +77,7 @@ namespace SHADE
vk::Pipeline GetVkPipeline (void) const noexcept; vk::Pipeline GetVkPipeline (void) const noexcept;
bool GetIsCreated (void) const noexcept; bool GetIsCreated (void) const noexcept;
Handle<SHVkPipelineLayout> GetPipelineLayout (void) const noexcept; Handle<SHVkPipelineLayout> GetPipelineLayout (void) const noexcept;
SH_PIPELINE_TYPE GetPipelineType (void) const noexcept;
}; };
} }

View File

@ -216,9 +216,18 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
void SHVkPipelineLayout::PrepareVkDescriptorSetLayouts(void) noexcept void SHVkPipelineLayout::PrepareVkDescriptorSetLayouts(void) noexcept
{ {
// pipeline layouts contain global layouts first, then layouts for allocation
descriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size()); descriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size());
vkDescriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size());
// Settle allocate layouts first // First we insert the global layouts
for (auto const& layout : descriptorSetLayoutsGlobal)
{
descriptorSetLayoutsPipeline.emplace_back(layout);
//vkDescriptorSetLayoutsPipeline.emplace_back(layout->GetVkHandle());
}
// Then the allocate layouts
vkDescriptorSetLayoutsAllocate.reserve(descriptorSetLayoutsAllocate.size()); vkDescriptorSetLayoutsAllocate.reserve(descriptorSetLayoutsAllocate.size());
for (auto const& layout : descriptorSetLayoutsAllocate) for (auto const& layout : descriptorSetLayoutsAllocate)
{ {
@ -226,18 +235,13 @@ namespace SHADE
vkDescriptorSetLayoutsAllocate.emplace_back(layout->GetVkHandle()); vkDescriptorSetLayoutsAllocate.emplace_back(layout->GetVkHandle());
} }
// pipeline layouts contain global layouts first, then layouts for allocation for (auto const& layout : descriptorSetLayoutsPipeline)
vkDescriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size());
// First we insert the global layouts
for (auto const& layout : descriptorSetLayoutsGlobal)
{ {
descriptorSetLayoutsPipeline.emplace_back(layout);
vkDescriptorSetLayoutsPipeline.emplace_back(layout->GetVkHandle()); vkDescriptorSetLayoutsPipeline.emplace_back(layout->GetVkHandle());
} }
// Then we append layouts for allocation at the back of the vector // Then we append layouts for allocation at the back of the vector
std::copy(vkDescriptorSetLayoutsAllocate.begin(), vkDescriptorSetLayoutsAllocate.end(), std::back_inserter(vkDescriptorSetLayoutsPipeline)); //std::copy(vkDescriptorSetLayoutsAllocate.begin(), vkDescriptorSetLayoutsAllocate.end(), std::back_inserter(vkDescriptorSetLayoutsPipeline));
} }
/***************************************************************************/ /***************************************************************************/
@ -294,6 +298,7 @@ namespace SHADE
, descriptorSetLayoutsGlobal{pipelineLayoutParams.globalDescSetLayouts } // do a copy, some other pipeline layout might need this , descriptorSetLayoutsGlobal{pipelineLayoutParams.globalDescSetLayouts } // do a copy, some other pipeline layout might need this
, descriptorSetLayoutsAllocate{} , descriptorSetLayoutsAllocate{}
, vkDescriptorSetLayoutsAllocate{} , vkDescriptorSetLayoutsAllocate{}
, descriptorSetLayoutsPipeline{}
, vkDescriptorSetLayoutsPipeline{} , vkDescriptorSetLayoutsPipeline{}
{ {
for (auto& mod : shaderModules) for (auto& mod : shaderModules)
@ -318,6 +323,7 @@ namespace SHADE
, descriptorSetLayoutsGlobal{} , descriptorSetLayoutsGlobal{}
, descriptorSetLayoutsAllocate{} , descriptorSetLayoutsAllocate{}
, vkDescriptorSetLayoutsAllocate{} , vkDescriptorSetLayoutsAllocate{}
, descriptorSetLayoutsPipeline{}
, vkDescriptorSetLayoutsPipeline{} , vkDescriptorSetLayoutsPipeline{}
{ {
@ -368,7 +374,8 @@ namespace SHADE
, descriptorSetLayoutsGlobal {std::move (rhs.descriptorSetLayoutsGlobal)} , descriptorSetLayoutsGlobal {std::move (rhs.descriptorSetLayoutsGlobal)}
, descriptorSetLayoutsAllocate {std::move (rhs.descriptorSetLayoutsAllocate)} , descriptorSetLayoutsAllocate {std::move (rhs.descriptorSetLayoutsAllocate)}
, vkDescriptorSetLayoutsAllocate{std::move (rhs.vkDescriptorSetLayoutsAllocate)} , vkDescriptorSetLayoutsAllocate{std::move (rhs.vkDescriptorSetLayoutsAllocate)}
, vkDescriptorSetLayoutsPipeline{std::move (rhs.vkDescriptorSetLayoutsAllocate)} , descriptorSetLayoutsPipeline { std::move(rhs.descriptorSetLayoutsPipeline) }
, vkDescriptorSetLayoutsPipeline{ std::move(rhs.vkDescriptorSetLayoutsPipeline) }
{ {
rhs.vkPipelineLayout = VK_NULL_HANDLE; rhs.vkPipelineLayout = VK_NULL_HANDLE;
} }
@ -441,12 +448,12 @@ namespace SHADE
return {}; return {};
} }
std::vector<Handle<SHVkDescriptorSetLayout>> SHVkPipelineLayout::GetDescriptorSetLayoutsPipeline(void) const noexcept std::vector<Handle<SHVkDescriptorSetLayout>> const& SHVkPipelineLayout::GetDescriptorSetLayoutsPipeline(void) const noexcept
{ {
return descriptorSetLayoutsPipeline; return descriptorSetLayoutsPipeline;
} }
std::vector<Handle<SHVkDescriptorSetLayout>> SHVkPipelineLayout::GetDescriptorSetLayoutsAllocate(void) const noexcept std::vector<Handle<SHVkDescriptorSetLayout>> const& SHVkPipelineLayout::GetDescriptorSetLayoutsAllocate(void) const noexcept
{ {
return descriptorSetLayoutsAllocate; return descriptorSetLayoutsAllocate;
} }
@ -464,7 +471,8 @@ namespace SHADE
descriptorSetLayoutsGlobal = std::move(rhs.descriptorSetLayoutsGlobal); descriptorSetLayoutsGlobal = std::move(rhs.descriptorSetLayoutsGlobal);
descriptorSetLayoutsAllocate = std::move(rhs.descriptorSetLayoutsAllocate); descriptorSetLayoutsAllocate = std::move(rhs.descriptorSetLayoutsAllocate);
vkDescriptorSetLayoutsAllocate = std::move(rhs.vkDescriptorSetLayoutsAllocate); vkDescriptorSetLayoutsAllocate = std::move(rhs.vkDescriptorSetLayoutsAllocate);
vkDescriptorSetLayoutsPipeline = std::move(rhs.vkDescriptorSetLayoutsAllocate); descriptorSetLayoutsPipeline = std::move(rhs.descriptorSetLayoutsPipeline);
vkDescriptorSetLayoutsPipeline = std::move(rhs.vkDescriptorSetLayoutsPipeline);
rhs.vkPipelineLayout = VK_NULL_HANDLE; rhs.vkPipelineLayout = VK_NULL_HANDLE;

View File

@ -74,12 +74,12 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */ /* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
std::vector<Handle<SHVkShaderModule>> const& GetShaderModules (void) const noexcept; std::vector<Handle<SHVkShaderModule>> const& GetShaderModules (void) const noexcept;
vk::PipelineLayout GetVkPipelineLayout (void) const noexcept; vk::PipelineLayout GetVkPipelineLayout (void) const noexcept;
SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept; SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept;
Handle<SHShaderBlockInterface> GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept; Handle<SHShaderBlockInterface> GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept;
std::vector<Handle<SHVkDescriptorSetLayout>> GetDescriptorSetLayoutsPipeline(void) const noexcept; std::vector<Handle<SHVkDescriptorSetLayout>> const& GetDescriptorSetLayoutsPipeline(void) const noexcept;
std::vector<Handle<SHVkDescriptorSetLayout>> GetDescriptorSetLayoutsAllocate(void) const noexcept; std::vector<Handle<SHVkDescriptorSetLayout>> const& GetDescriptorSetLayoutsAllocate(void) const noexcept;
}; };
} }

View File

@ -10,6 +10,8 @@ namespace SHADE
DEPTH = 0x04, DEPTH = 0x04,
STENCIL = 0x08, STENCIL = 0x08,
DEPTH_STENCIL = 0x10, DEPTH_STENCIL = 0x10,
INPUT = 0x20 INPUT = 0x20,
STORAGE = 0x40
}; };
} }

View File

@ -9,6 +9,8 @@
#include "Graphics/Buffers/SHVkBuffer.h" #include "Graphics/Buffers/SHVkBuffer.h"
#include "Tools/SHLogger.h" #include "Tools/SHLogger.h"
#include "SHAttachmentDescInitParams.h" #include "SHAttachmentDescInitParams.h"
#include "SHRenderGraphStorage.h"
#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h"
namespace SHADE namespace SHADE
{ {
@ -52,12 +54,12 @@ namespace SHADE
// If we set to // If we set to
if (w == static_cast<uint32_t>(-1) && h == static_cast<uint32_t>(-1)) if (w == static_cast<uint32_t>(-1) && h == static_cast<uint32_t>(-1))
{ {
w = swapchainHdl->GetSwapchainImage(0)->GetWidth(); w = renderGraphStorage->swapchain->GetSwapchainImage(0)->GetWidth();
h = swapchainHdl->GetSwapchainImage(0)->GetHeight(); h = renderGraphStorage->swapchain->GetSwapchainImage(0)->GetHeight();
format = swapchainHdl->GetSurfaceFormatKHR().format; format = renderGraphStorage->swapchain->GetSurfaceFormatKHR().format;
} }
graphResources.try_emplace(resourceName, resourceManager->Create<SHRenderGraphResource>(logicalDeviceHdl, swapchainHdl, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags)); renderGraphStorage->graphResources->try_emplace(resourceName, resourceManager->Create<SHRenderGraphResource>(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags));
} }
/***************************************************************************/ /***************************************************************************/
@ -77,36 +79,38 @@ namespace SHADE
for (uint32_t i = 0; auto& node : nodes) for (uint32_t i = 0; auto& node : nodes)
{ {
// key is handle ID, value is pair (first is initial layout, second is final layout). // key is handle ID, value is final layout.
std::unordered_map<uint32_t, vk::ImageLayout> resourceAttLayouts; std::unordered_map<uint32_t, vk::ImageLayout> resourceAttFinalLayouts;
if (node->subpasses.empty()) if (node->subpasses.empty())
{ {
SHLOG_ERROR("Node does not contain a subpass. Cannot configure attachment descriptions as a result. "); SHLOG_ERROR("Node does not contain a subpass. Cannot configure attachment descriptions as a result. ");
return; return;
} }
// attempt to get all final layouts for all resources
for (auto& subpass : node->subpasses) for (auto& subpass : node->subpasses)
{ {
for (auto& color : subpass->colorReferences) for (auto& color : subpass->colorReferences)
{ {
// If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass
if (i == nodes.size() - 1 && (node->attResources[color.attachment]->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT))) if (i == nodes.size() - 1 && (node->attResources[color.attachment]->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)))
resourceAttLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR;
else else
resourceAttLayouts[color.attachment] = color.layout; resourceAttFinalLayouts[color.attachment] = color.layout;
} }
for (auto& depth : subpass->depthReferences) for (auto& depth : subpass->depthReferences)
resourceAttLayouts[depth.attachment] = depth.layout; resourceAttFinalLayouts[depth.attachment] = depth.layout;
for (auto& input : subpass->inputReferences) for (auto& input : subpass->inputReferences)
resourceAttLayouts[input.attachment] = input.layout; resourceAttFinalLayouts[input.attachment] = input.layout;
} }
for (uint32_t j = 0; j < node->attachmentDescriptions.size(); ++j) for (uint32_t j = 0; j < node->attachmentDescriptions.size(); ++j)
{ {
auto& att = node->attachmentDescriptions[j]; auto& att = node->attachmentDescriptions[j];
att.initialLayout = vk::ImageLayout::eUndefined; att.initialLayout = vk::ImageLayout::eUndefined;
att.finalLayout = resourceAttLayouts[j]; att.finalLayout = resourceAttFinalLayouts[j];
} }
++i; ++i;
} }
@ -138,6 +142,9 @@ namespace SHADE
attDesc.loadOp = vk::AttachmentLoadOp::eLoad; attDesc.loadOp = vk::AttachmentLoadOp::eLoad;
predAttDesc.storeOp = vk::AttachmentStoreOp::eStore; predAttDesc.storeOp = vk::AttachmentStoreOp::eStore;
attDesc.stencilLoadOp = vk::AttachmentLoadOp::eLoad;
attDesc.stencilStoreOp = vk::AttachmentStoreOp::eStore;
// TODO: Stencil load and store // TODO: Stencil load and store
// When an image is done being used in a renderpass, the image layout will end up being the finalLayout // When an image is done being used in a renderpass, the image layout will end up being the finalLayout
@ -292,6 +299,9 @@ namespace SHADE
dep.dstAccessMask = dstAccess; dep.dstAccessMask = dstAccess;
dep.srcStageMask = srcStage; dep.srcStageMask = srcStage;
// initialize input descriptors
node->subpasses[i]->CreateInputDescriptors();
} }
} }
} }
@ -343,10 +353,18 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
void SHRenderGraph::Init(Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain) noexcept void SHRenderGraph::Init(Handle<SHVkLogicalDevice> logicalDevice, Handle<SHVkSwapchain> swapchain) noexcept
{ {
logicalDeviceHdl = logicalDevice; resourceManager = std::make_shared<SHResourceHub>();
swapchainHdl = swapchain;
renderGraphStorage = resourceManager->Create<SHRenderGraphStorage>();
renderGraphStorage->graphResources = resourceManager->Create<std::unordered_map<std::string, Handle<SHRenderGraphResource>>>();
renderGraphStorage->logicalDevice = logicalDevice;
renderGraphStorage->swapchain = swapchain;
renderGraphStorage->resourceManager = resourceManager;
renderGraphStorage->descriptorPool = logicalDevice->CreateDescriptorPools();
} }
/***************************************************************************/ /***************************************************************************/
@ -361,24 +379,19 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
SHRenderGraph::SHRenderGraph(void) noexcept SHRenderGraph::SHRenderGraph(void) noexcept
: logicalDeviceHdl{ } : renderGraphStorage{}
, swapchainHdl{ }
, nodes{} , nodes{}
, graphResources{}
, resourceManager{nullptr} , resourceManager{nullptr}
{ {
resourceManager = std::make_shared<SHResourceHub>();
} }
SHRenderGraph::SHRenderGraph(SHRenderGraph&& rhs) noexcept SHRenderGraph::SHRenderGraph(SHRenderGraph&& rhs) noexcept
: logicalDeviceHdl{ rhs.logicalDeviceHdl } : renderGraphStorage{ rhs.renderGraphStorage }
, swapchainHdl{ rhs.swapchainHdl }
, nodeIndexing{ std::move(rhs.nodeIndexing) } , nodeIndexing{ std::move(rhs.nodeIndexing) }
, nodes{ std::move(rhs.nodes) } , nodes{ std::move(rhs.nodes) }
, graphResources{ std::move(rhs.graphResources) }
, resourceManager{ std::move(rhs.resourceManager) } , resourceManager{ std::move(rhs.resourceManager) }
{ {
} }
SHRenderGraph& SHRenderGraph::operator=(SHRenderGraph&& rhs) noexcept SHRenderGraph& SHRenderGraph::operator=(SHRenderGraph&& rhs) noexcept
@ -386,11 +399,9 @@ namespace SHADE
if (&rhs == this) if (&rhs == this)
return *this; return *this;
logicalDeviceHdl = rhs.logicalDeviceHdl; renderGraphStorage = rhs.renderGraphStorage;
swapchainHdl = rhs.swapchainHdl;
nodeIndexing = std::move(rhs.nodeIndexing); nodeIndexing = std::move(rhs.nodeIndexing);
nodes = std::move(rhs.nodes); nodes = std::move(rhs.nodes);
graphResources = std::move(rhs.graphResources);
resourceManager = std::move(rhs.resourceManager); resourceManager = std::move(rhs.resourceManager);
return *this; return *this;
@ -426,12 +437,12 @@ namespace SHADE
for (auto const& instruction : resourceInstruction) for (auto const& instruction : resourceInstruction)
{ {
// If the resource that the new node is requesting for exists, allow the graph to reference it // If the resource that the new node is requesting for exists, allow the graph to reference it
if (graphResources.contains(instruction.resourceName)) if (renderGraphStorage->graphResources->contains(instruction.resourceName))
{ {
descInitParams.push_back( descInitParams.push_back(
{ {
.resourceHdl = graphResources.at(instruction.resourceName), .resourceHdl = renderGraphStorage->graphResources->at(instruction.resourceName),
.dontClearOnLoad = false, .dontClearOnLoad = instruction.dontClearOnLoad,
} }
); );
} }
@ -456,7 +467,7 @@ namespace SHADE
} }
} }
nodes.emplace_back(resourceManager->Create<SHRenderGraphNode>(resourceManager, logicalDeviceHdl, swapchainHdl, std::move(descInitParams), std::move(predecessors), &graphResources)); nodes.emplace_back(resourceManager->Create<SHRenderGraphNode>(renderGraphStorage, std::move(descInitParams), std::move(predecessors)));
nodeIndexing.emplace(nodeName, static_cast<uint32_t>(nodes.size()) - 1u); nodeIndexing.emplace(nodeName, static_cast<uint32_t>(nodes.size()) - 1u);
return nodes.at(nodeIndexing[nodeName]); return nodes.at(nodeIndexing[nodeName]);
} }
@ -476,12 +487,31 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
void SHRenderGraph::Generate(void) noexcept void SHRenderGraph::Generate(void) noexcept
{ {
CheckForNodeComputes();
ConfigureAttachmentDescriptions(); ConfigureAttachmentDescriptions();
ConfigureSubpasses(); ConfigureSubpasses();
ConfigureRenderpasses(); ConfigureRenderpasses();
ConfigureFramebuffers(); ConfigureFramebuffers();
} }
/***************************************************************************/
/*!
\brief
This function goes through all renderpasses and checks for existence of
node computes. If they exist, adds dummy subpasses to transition resources
into general.
*/
/***************************************************************************/
void SHRenderGraph::CheckForNodeComputes(void) noexcept
{
for (auto& node : nodes)
{
node->AddDummySubpassIfNeeded();
}
}
// TODO: The graph scope buffers were meant to bind vertex buffers and index buffers for meshes. Find a // TODO: The graph scope buffers were meant to bind vertex buffers and index buffers for meshes. Find a
// better way to manage these // better way to manage these
void SHRenderGraph::Execute(uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkDescriptorPool> descPool) noexcept void SHRenderGraph::Execute(uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkDescriptorPool> descPool) noexcept
@ -501,7 +531,7 @@ namespace SHADE
void SHRenderGraph::HandleResize(uint32_t newWidth, uint32_t newHeight) noexcept void SHRenderGraph::HandleResize(uint32_t newWidth, uint32_t newHeight) noexcept
{ {
// resize resources // resize resources
for (auto& [name, resource]: graphResources) for (auto& [name, resource] : *renderGraphStorage->graphResources)
resource->HandleResize(newWidth, newHeight); resource->HandleResize(newWidth, newHeight);
for (auto& node : nodes) for (auto& node : nodes)
@ -521,9 +551,9 @@ namespace SHADE
Handle<SHRenderGraphResource> SHRenderGraph::GetRenderGraphResource(std::string const& resourceName) const noexcept Handle<SHRenderGraphResource> SHRenderGraph::GetRenderGraphResource(std::string const& resourceName) const noexcept
{ {
if (graphResources.contains(resourceName)) if (renderGraphStorage->graphResources->contains(resourceName))
{ {
return graphResources.at(resourceName); return renderGraphStorage->graphResources->at(resourceName);
} }
return {}; return {};
} }

View File

@ -30,7 +30,8 @@ namespace SHADE
class SHVkCommandBuffer; class SHVkCommandBuffer;
class SHRenderGraphNode; class SHRenderGraphNode;
class SHGraphicsGlobalData; class SHGraphicsGlobalData;
class SHVkDescriptorPool;
class SHRenderGraphStorage;
class SH_API SHRenderGraph class SH_API SHRenderGraph
{ {
@ -56,10 +57,8 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */ /* PRIVATE MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
Handle<SHVkLogicalDevice> logicalDeviceHdl;
//! swapchain used for querying image count Handle<SHRenderGraphStorage> renderGraphStorage;
Handle<SHVkSwapchain> swapchainHdl;
//! For indexing render graph node container //! For indexing render graph node container
std::map<std::string, uint32_t> nodeIndexing; std::map<std::string, uint32_t> nodeIndexing;
@ -67,9 +66,6 @@ namespace SHADE
//! Render graph nodes //! Render graph nodes
std::vector<Handle<SHRenderGraphNode>> nodes; std::vector<Handle<SHRenderGraphNode>> nodes;
//! Resources that exist for the entire render graph
std::unordered_map<std::string, Handle<SHRenderGraphResource>> graphResources;
//! Resource library for graph handles //! Resource library for graph handles
std::shared_ptr<SHResourceHub> resourceManager; std::shared_ptr<SHResourceHub> resourceManager;
@ -85,14 +81,15 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */ /* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void Init (Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain) noexcept; void Init (Handle<SHVkLogicalDevice> logicalDevice, Handle<SHVkSwapchain> swapchain) noexcept;
void AddResource(std::string resourceName, std::initializer_list<SH_ATT_DESC_TYPE_FLAGS> typeFlags, uint32_t w = static_cast<uint32_t>(-1), uint32_t h = static_cast<uint32_t>(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, uint8_t levels = 1, vk::ImageUsageFlagBits usageFlags = {}, vk::ImageCreateFlagBits createFlags = {}); void AddResource(std::string resourceName, std::initializer_list<SH_ATT_DESC_TYPE_FLAGS> typeFlags, uint32_t w = static_cast<uint32_t>(-1), uint32_t h = static_cast<uint32_t>(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, uint8_t levels = 1, vk::ImageUsageFlagBits usageFlags = {}, vk::ImageCreateFlagBits createFlags = {});
Handle<SHRenderGraphNode> AddNode (std::string nodeName, std::initializer_list<ResourceInstruction> resourceInstruction, std::initializer_list<std::string> predecessorNodes) noexcept; Handle<SHRenderGraphNode> AddNode (std::string nodeName, std::initializer_list<ResourceInstruction> resourceInstruction, std::initializer_list<std::string> predecessorNodes) noexcept;
void Generate (void) noexcept; void Generate (void) noexcept;
void Execute (uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkDescriptorPool> descPool) noexcept; void CheckForNodeComputes (void) noexcept;
void FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool); void Execute (uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkDescriptorPool> descPool) noexcept;
void HandleResize (uint32_t newWidth, uint32_t newHeight) noexcept; void FinaliseBatch (uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
void HandleResize (uint32_t newWidth, uint32_t newHeight) noexcept;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */ /* SETTERS AND GETTERS */

View File

@ -6,6 +6,9 @@
#include "Graphics/Framebuffer/SHVkFramebuffer.h" #include "Graphics/Framebuffer/SHVkFramebuffer.h"
#include "SHRenderGraphResource.h" #include "SHRenderGraphResource.h"
#include "SHSubpass.h" #include "SHSubpass.h"
#include "SHRenderGraphStorage.h"
#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h"
#include "Graphics/SHVkUtil.h"
namespace SHADE namespace SHADE
{ {
@ -21,7 +24,7 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
void SHRenderGraphNode::CreateRenderpass(void) noexcept void SHRenderGraphNode::CreateRenderpass(void) noexcept
{ {
renderpass = logicalDeviceHdl->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps);
} }
/***************************************************************************/ /***************************************************************************/
@ -53,7 +56,7 @@ namespace SHADE
} }
framebuffers[i] = logicalDeviceHdl->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); framebuffers[i] = graphStorage->logicalDevice->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight);
} }
} }
@ -79,9 +82,18 @@ namespace SHADE
fbHeight = attResources[j]->height; fbHeight = attResources[j]->height;
} }
framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight); framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight);
} }
for (auto& subpass : subpasses)
{
subpass->HandleResize();
}
for (auto& nodeCompute : nodeComputes)
{
nodeCompute->HandleResize();
}
} }
/***************************************************************************/ /***************************************************************************/
@ -104,8 +116,8 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
SHRenderGraphNode::SHRenderGraphNode(std::shared_ptr<SHResourceHub> rm, Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::vector<SHAttachmentDescInitParams> attDescInitParams, std::vector<Handle<SHRenderGraphNode>> predecessors, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources) noexcept SHRenderGraphNode::SHRenderGraphNode(Handle<SHRenderGraphStorage> renderGraphStorage, std::vector<SHAttachmentDescInitParams> attDescInitParams, std::vector<Handle<SHRenderGraphNode>> predecessors) noexcept
: logicalDeviceHdl{ logicalDevice } : graphStorage{ renderGraphStorage}
, renderpass{} , renderpass{}
, framebuffers{} , framebuffers{}
, prereqNodes{ std::move(predecessors) } , prereqNodes{ std::move(predecessors) }
@ -115,11 +127,10 @@ namespace SHADE
, subpasses{} , subpasses{}
, executed{ false } , executed{ false }
, configured{ false } , configured{ false }
, resourceManager{ rm } , nodeComputes{}
, ptrToResources{ resources }
{ {
// pipeline library initialization // pipeline library initialization
pipelineLibrary.Init(logicalDeviceHdl); pipelineLibrary.Init(graphStorage->logicalDevice);
// Store all the handles to resources // Store all the handles to resources
attResources.reserve (attDescInitParams.size()); attResources.reserve (attDescInitParams.size());
@ -155,15 +166,14 @@ namespace SHADE
if (!containsSwapchainImage) if (!containsSwapchainImage)
framebuffers.resize(1); framebuffers.resize(1);
else else
framebuffers.resize(swapchain->GetNumImages()); framebuffers.resize(graphStorage->swapchain->GetNumImages());
// At this point, we could configure framebuffers if we had the renderpass object but we don't so their creation has to be // At this point, we could configure framebuffers if we had the renderpass object but we don't so their creation has to be
// deferred to when renderpasses are also created. // deferred to when renderpasses are also created.
} }
SHRenderGraphNode::SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept SHRenderGraphNode::SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept
: resourceManager{ std::move (rhs.resourceManager) } : graphStorage{ rhs.graphStorage}
, logicalDeviceHdl{ rhs.logicalDeviceHdl }
, renderpass{ rhs.renderpass } , renderpass{ rhs.renderpass }
, framebuffers{ std::move(rhs.framebuffers) } , framebuffers{ std::move(rhs.framebuffers) }
, prereqNodes{ std::move(rhs.prereqNodes) } , prereqNodes{ std::move(rhs.prereqNodes) }
@ -174,11 +184,11 @@ namespace SHADE
, subpassIndexing{ std::move(rhs.subpassIndexing) } , subpassIndexing{ std::move(rhs.subpassIndexing) }
, configured{ rhs.configured } , configured{ rhs.configured }
, executed{ rhs.executed } , executed{ rhs.executed }
, ptrToResources{ rhs.ptrToResources }
, pipelineLibrary{ std::move(rhs.pipelineLibrary) } , pipelineLibrary{ std::move(rhs.pipelineLibrary) }
, batcher{ std::move(rhs.batcher) } , batcher{ std::move(rhs.batcher) }
, spDescs{ std::move(rhs.spDescs) } , spDescs{ std::move(rhs.spDescs) }
, spDeps{ std::move(rhs.spDeps) } , spDeps{ std::move(rhs.spDeps) }
, nodeComputes{ std::move(rhs.nodeComputes) }
{ {
rhs.renderpass = {}; rhs.renderpass = {};
@ -189,8 +199,7 @@ namespace SHADE
if (&rhs == this) if (&rhs == this)
return *this; return *this;
resourceManager = std::move(rhs.resourceManager); graphStorage = rhs.graphStorage;
logicalDeviceHdl = rhs.logicalDeviceHdl;
renderpass = rhs.renderpass; renderpass = rhs.renderpass;
framebuffers = std::move(rhs.framebuffers); framebuffers = std::move(rhs.framebuffers);
prereqNodes = std::move(rhs.prereqNodes); prereqNodes = std::move(rhs.prereqNodes);
@ -199,11 +208,11 @@ namespace SHADE
subpasses = std::move(rhs.subpasses); subpasses = std::move(rhs.subpasses);
resourceAttachmentMapping = std::move(rhs.resourceAttachmentMapping); resourceAttachmentMapping = std::move(rhs.resourceAttachmentMapping);
subpassIndexing = std::move(rhs.subpassIndexing); subpassIndexing = std::move(rhs.subpassIndexing);
ptrToResources = std::move(rhs.ptrToResources);
pipelineLibrary = std::move(rhs.pipelineLibrary); pipelineLibrary = std::move(rhs.pipelineLibrary);
batcher = std::move(rhs.batcher); batcher = std::move(rhs.batcher);
spDescs = std::move(rhs.spDescs); spDescs = std::move(rhs.spDescs);
spDeps = std::move(rhs.spDeps); spDeps = std::move(rhs.spDeps);
nodeComputes = std::move(rhs.nodeComputes);
rhs.renderpass = {}; rhs.renderpass = {};
@ -235,10 +244,10 @@ namespace SHADE
} }
// Add subpass to container and create mapping for it // Add subpass to container and create mapping for it
subpasses.emplace_back(resourceManager->Create<SHSubpass>(GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources)); subpasses.emplace_back(graphStorage->resourceManager->Create<SHSubpass>(graphStorage, GetHandle(), static_cast<uint32_t>(subpasses.size()), &resourceAttachmentMapping));
subpassIndexing.try_emplace(subpassName, static_cast<uint32_t>(subpasses.size()) - 1u); subpassIndexing.try_emplace(subpassName, static_cast<uint32_t>(subpasses.size()) - 1u);
Handle<SHSubpass> subpass = subpasses.back(); Handle<SHSubpass> subpass = subpasses.back();
subpass->Init(*resourceManager); subpass->Init(*graphStorage->resourceManager);
// Register the SuperBatch // Register the SuperBatch
batcher.RegisterSuperBatch(subpass->GetSuperBatch()); batcher.RegisterSuperBatch(subpass->GetSuperBatch());
@ -246,21 +255,84 @@ namespace SHADE
return subpass; return subpass;
} }
Handle<SHRenderGraphNodeCompute> SHRenderGraphNode::AddNodeCompute(Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, float numWorkGroupScale/* = 1.0f*/) noexcept
{
// Look for the required resources in the graph
std::vector<Handle<SHRenderGraphResource>> nodeComputeResources{};
nodeComputeResources.reserve(resources.size());
for (auto& resourceName : resources)
{
auto resource = graphStorage->graphResources->at(resourceName);
nodeComputeResources.push_back(resource);
}
// Create the subpass compute with the resources
auto nodeCompute = graphStorage->resourceManager->Create<SHRenderGraphNodeCompute>(graphStorage, computeShaderModule, std::move(nodeComputeResources));
nodeComputes.push_back(nodeCompute);
return nodeCompute;
}
/***************************************************************************/
/*!
\brief
This function checks all node computes and adds a subpass to transition
all needed resources to general.
*/
/***************************************************************************/
void SHRenderGraphNode::AddDummySubpassIfNeeded(void) noexcept
{
if (!nodeComputes.empty())
{
// we save the resource names involved
std::unordered_set<std::string> resourcesInvolved;
for (auto& compute : nodeComputes)
{
for (auto& resource : compute->resources)
{
resourcesInvolved.emplace(resource->GetName());
}
}
// insert them all for a subpass to transition them. This subpass is the last subpass
auto dummySubpass = AddSubpass("dummy");
for (auto& resource : resourcesInvolved)
{
dummySubpass->AddGeneralInput(resource);
if (SHVkUtil::IsDepthStencilAttachment(graphStorage->graphResources->at(resource)->GetResourceFormat()))
dummySubpass->AddGeneralDepthOutput(resource);
else
dummySubpass->AddGeneralColorOutput(resource);
}
}
}
void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
{ {
frameIndex = (framebuffers.size() > 1) ? frameIndex : 0; uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0;
commandBuffer->BeginRenderpass(renderpass, framebuffers[frameIndex]); commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]);
for (uint32_t i = 0; i < subpasses.size(); ++i) for (uint32_t i = 0; i < subpasses.size(); ++i)
{ {
subpasses[i]->Execute(commandBuffer, descPool, frameIndex); subpasses[i]->Execute(commandBuffer, descPool, frameIndex);
// Go to next subpass if not last subpass // Go to next subpass if not last subpass
if (i != subpasses.size() - 1) if (i != static_cast<uint32_t>(subpasses.size()) - 1u)
commandBuffer->NextSubpass(); commandBuffer->NextSubpass();
} }
commandBuffer->EndRenderpass(); commandBuffer->EndRenderpass();
// Execute all subpass computes
for (auto& sbCompute : nodeComputes)
{
sbCompute->Execute(commandBuffer, frameIndex);
}
} }
Handle<SHVkPipeline> SHRenderGraphNode::GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept Handle<SHVkPipeline> SHRenderGraphNode::GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept
@ -273,10 +345,10 @@ namespace SHADE
} }
Handle<SHVkPipeline> pipeline = pipelineLibrary.GetDrawPipline(vsFsPair); Handle<SHVkPipeline> pipeline = pipelineLibrary.GetGraphicsPipeline(vsFsPair);
if (!pipeline) if (!pipeline)
{ {
pipeline = pipelineLibrary.CreateDrawPipeline pipeline = pipelineLibrary.CreateGraphicsPipelines
( (
vsFsPair, vsFsPair,
renderpass, renderpass,
@ -289,7 +361,7 @@ namespace SHADE
void SHRenderGraphNode::FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) void SHRenderGraphNode::FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{ {
batcher.FinaliseBatches(logicalDeviceHdl, descPool, frameIndex); batcher.FinaliseBatches(graphStorage->logicalDevice, descPool, frameIndex);
} }
/***************************************************************************/ /***************************************************************************/

View File

@ -19,6 +19,9 @@ namespace SHADE
class SHVkLogicalDevice; class SHVkLogicalDevice;
class SHVkRenderpass; class SHVkRenderpass;
class SHVkDescriptorPool; class SHVkDescriptorPool;
class SHGraphicsGlobalData;
class SHRenderGraphStorage;
class SHRenderGraphNodeCompute;
class SH_API SHRenderGraphNode : public ISelfHandle<SHRenderGraphNode> class SH_API SHRenderGraphNode : public ISelfHandle<SHRenderGraphNode>
{ {
@ -26,10 +29,9 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */ /* PRIVATE MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
std::shared_ptr<SHResourceHub> resourceManager;
//! For Vulkan object creation //! For Vulkan object creation
Handle<SHVkLogicalDevice> logicalDeviceHdl; //Handle<SHVkLogicalDevice> logicalDeviceHdl;
Handle<SHRenderGraphStorage> graphStorage;
//! Each node will have a renderpass and each renderpass will have its own subpasses. //! Each node will have a renderpass and each renderpass will have its own subpasses.
//! These subpasses will execute sequentially. //! These subpasses will execute sequentially.
@ -63,12 +65,13 @@ namespace SHADE
//! For indexing subpasses //! For indexing subpasses
std::map<std::string, uint32_t> subpassIndexing; std::map<std::string, uint32_t> subpassIndexing;
//! Pointer to resources in the render graph (for getting handle IDs)
std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources;
//! Every renderpass will require a pipeline library that will contain pipelines compatible with this renderpass //! Every renderpass will require a pipeline library that will contain pipelines compatible with this renderpass
SHPipelineLibrary pipelineLibrary; SHPipelineLibrary pipelineLibrary;
//! Sometimes we want the subpass to do something to the images instead
//! of drawing objects on the image (i.e. compute).
std::vector<Handle<SHRenderGraphNodeCompute>> nodeComputes;
//! Whether or not the node has finished execution //! Whether or not the node has finished execution
bool executed; bool executed;
@ -77,6 +80,7 @@ namespace SHADE
SHBatcher batcher; SHBatcher batcher;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */ /* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -88,7 +92,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */ /* CTORS AND DTORS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
SHRenderGraphNode(std::shared_ptr<SHResourceHub> rm, Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::vector<SHAttachmentDescInitParams> attDescInitParams, std::vector<Handle<SHRenderGraphNode>> predecessors, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources) noexcept; SHRenderGraphNode(Handle<SHRenderGraphStorage> renderGraphStorage, std::vector<SHAttachmentDescInitParams> attDescInitParams, std::vector<Handle<SHRenderGraphNode>> predecessors) noexcept;
SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept; SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept;
SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept; SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept;
@ -96,6 +100,9 @@ namespace SHADE
/* PUBLIC MEMBER FUNCTIONS */ /* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
Handle<SHSubpass> AddSubpass(std::string subpassName) noexcept; Handle<SHSubpass> AddSubpass(std::string subpassName) noexcept;
Handle<SHRenderGraphNodeCompute> AddNodeCompute(Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, float numWorkGroupScale = 1.0f) noexcept;
void AddDummySubpassIfNeeded (void) noexcept;
// TODO: RemoveSubpass() // TODO: RemoveSubpass()
void Execute(Handle<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept; void Execute(Handle<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
Handle<SHVkPipeline> GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept; Handle<SHVkPipeline> GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept;

View File

@ -0,0 +1,109 @@
#include "SHpch.h"
#include "SHRenderGraphNodeCompute.h"
#include "Graphics/Pipeline/SHVkPipeline.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/Descriptors/SHVkDescriptorPool.h"
#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
#include "Graphics/Devices/SHVkLogicalDevice.h"
#include "Graphics/Pipeline/SHVkPipelineLayout.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h"
#include "SHRenderGraphStorage.h"
#include "SHRenderGraphResource.h"
#include "Graphics/Commands/SHVkCommandBuffer.h"
namespace SHADE
{
SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, float inNumWorkGroupScale/* = 1.0f*/) noexcept
: computePipeline{}
, pipelineLayout{}
, resources{}
, groupSizeX{0}
, groupSizeY{0}
, numWorkGroupScale {std::clamp(inNumWorkGroupScale, 0.0f, 1.0f)}
{
SHPipelineLayoutParams pipelineLayoutParams
{
.shaderModules = {computeShaderModule},
.globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts()
};
// Create pipeline layout from parameters
pipelineLayout = graphStorage->logicalDevice->CreatePipelineLayout (pipelineLayoutParams);
// Create the compute pipeline
computePipeline = graphStorage->logicalDevice->CreateComputePipeline(pipelineLayout);
// and construct it
computePipeline->ConstructPipeline();
// save the resources
resources = std::move (subpassComputeResources);
//Get the descriptor set layouts required to allocate. We only want the ones for allocate because
//global descriptors are already bound in the main system.
auto const& layouts = computePipeline->GetPipelineLayout()->GetDescriptorSetLayoutsAllocate();
//Variable counts for the descriptor sets (all should be 1).
std::vector<uint32_t> variableCounts{ static_cast<uint32_t>(layouts.size()) };
std::fill(variableCounts.begin(), variableCounts.end(), 0);
// Allocate descriptor sets to hold the images for reading (STORAGE_IMAGE)
for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{
descSetGroups[i] = graphStorage->descriptorPool->Allocate(layouts, variableCounts);
}
HandleResize();
}
void SHRenderGraphNodeCompute::Execute(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{
// bind the compute pipeline
cmdBuffer->BindPipeline(computePipeline);
// bind descriptor sets
cmdBuffer->BindDescriptorSet(descSetGroups[frameIndex], SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, {});
// dispatch compute
cmdBuffer->ComputeDispatch(groupSizeX, groupSizeY, 1);
// TODO: barrier
}
void SHRenderGraphNodeCompute::HandleResize(void) noexcept
{
// Get the layout for the render graph resource. We can index it this way because the container returned is a container of layouts that includes the global ones
auto pipelineDescSetLayouts = computePipeline->GetPipelineLayout()->GetDescriptorSetLayoutsPipeline()[SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE];
// everything below here needs resizing
for (uint32_t frameIndex = 0; frameIndex < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++frameIndex)
{
uint32_t i = 0;
// loop through bindings and write descriptor sets
for (auto& binding : pipelineDescSetLayouts->GetBindings())
{
uint32_t imageIndex = (resources[i]->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? frameIndex : 0;
SHVkDescriptorSetGroup::viewSamplerLayout vsl = std::make_tuple(resources[i]->GetImageView(imageIndex), Handle<SHVkSampler>{}, vk::ImageLayout::eGeneral);
descSetGroups[frameIndex]->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint, { &vsl, 1 });
descSetGroups[frameIndex]->UpdateDescriptorSetImages(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint);
++i;
}
}
// Get the group size from the max width and height
uint32_t maxWidth = 0, maxHeight = 0;
for (auto& resource : resources)
{
maxWidth = std::max(resource->GetWidth(), maxWidth);
maxHeight = std::max(resource->GetHeight(), maxHeight);
}
groupSizeX = maxWidth / workGroupSizeX;
groupSizeY = maxHeight / workGroupSizeY;
}
}

View File

@ -0,0 +1,57 @@
#pragma once
#include "Resource/SHHandle.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include <initializer_list>
#include <string>
#include <unordered_set>
namespace SHADE
{
class SHVkPipeline;
class SHVkDescriptorSetGroup;
class SHVkDescriptorPool;
class SHVkLogicalDevice;
class SHVkPipelineLayout;
class SHRenderGraphStorage;
class SHRenderGraphResource;
class SHVkShaderModule;
class SHVkCommandBuffer;
class SHRenderGraphNodeCompute
{
private:
static constexpr uint32_t workGroupSizeX = 16;
static constexpr uint32_t workGroupSizeY = 16;
//! To run the dispatch command
Handle<SHVkPipeline> computePipeline;
//! Pipeline layout for the pipeline creation
Handle<SHVkPipelineLayout> pipelineLayout;
//! Descriptor set group to hold the images for reading (STORAGE_IMAGE)
std::array<Handle<SHVkDescriptorSetGroup>, SHGraphicsConstants::NUM_FRAME_BUFFERS> descSetGroups;
//! vector of resources needed by the subpass compute
std::vector<Handle<SHRenderGraphResource>> resources;
//! X dimension work group size. Should scale with resource size.
uint32_t groupSizeX;
//! Y dimension work group size
uint32_t groupSizeY;
float numWorkGroupScale;
public:
SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, float inNumWorkGroupScale = 1.0f) noexcept;
void Execute (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void HandleResize (void) noexcept;
friend class SHRenderGraph;
friend class SHRenderGraphNode;
};
}

View File

@ -5,6 +5,7 @@
#include "Graphics/Images/SHVkImageView.h" #include "Graphics/Images/SHVkImageView.h"
#include "Graphics/Buffers/SHVkBuffer.h" #include "Graphics/Buffers/SHVkBuffer.h"
#include "Graphics/SHVkUtil.h" #include "Graphics/SHVkUtil.h"
#include "SHRenderGraphStorage.h"
namespace SHADE namespace SHADE
{ {
@ -45,9 +46,8 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
SHRenderGraphResource::SHRenderGraphResource(Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::string const& name, std::initializer_list<SH_ATT_DESC_TYPE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept SHRenderGraphResource::SHRenderGraphResource(Handle<SHRenderGraphStorage> renderGraphStorage, std::string const& name, std::initializer_list<SH_ATT_DESC_TYPE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept
: logicalDevice {logicalDevice} : graphStorage{renderGraphStorage}
, swapchain{ swapchain }
, resourceTypeFlags{ } , resourceTypeFlags{ }
, resourceFormat{ format } , resourceFormat{ format }
, images{} , images{}
@ -66,7 +66,7 @@ namespace SHADE
SHImageViewDetails viewDetails SHImageViewDetails viewDetails
{ {
.viewType = vk::ImageViewType::e2D, .viewType = vk::ImageViewType::e2D,
.format = swapchain->GetSurfaceFormatKHR().format, .format = graphStorage->swapchain->GetSurfaceFormatKHR().format,
.imageAspectFlags = vk::ImageAspectFlagBits::eColor, .imageAspectFlags = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0, .baseMipLevel = 0,
.mipLevelCount = 1, .mipLevelCount = 1,
@ -75,13 +75,13 @@ namespace SHADE
}; };
// We want an image handle for every swapchain image // We want an image handle for every swapchain image
images.resize(swapchain->GetNumImages()); images.resize(graphStorage->swapchain->GetNumImages());
imageViews.resize(swapchain->GetNumImages()); imageViews.resize(graphStorage->swapchain->GetNumImages());
for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i) for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i)
{ {
images[i] = swapchain->GetSwapchainImage(i); images[i] = graphStorage->swapchain->GetSwapchainImage(i);
imageViews[i] = images[i]->CreateImageView(logicalDevice, images[i], viewDetails); imageViews[i] = images[i]->CreateImageView(graphStorage->logicalDevice, images[i], viewDetails);
} }
} }
else // if swapchain image resource else // if swapchain image resource
@ -117,6 +117,9 @@ namespace SHADE
usage |= vk::ImageUsageFlagBits::eInputAttachment; usage |= vk::ImageUsageFlagBits::eInputAttachment;
usage |= vk::ImageUsageFlagBits::eSampled; usage |= vk::ImageUsageFlagBits::eSampled;
break; break;
case SH_ATT_DESC_TYPE_FLAGS::STORAGE:
usage |= vk::ImageUsageFlagBits::eStorage;
break;
case SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT: case SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT:
{ {
SHLOG_ERROR ("COLOR_PRESENT cannot be with other resource type flags. "); SHLOG_ERROR ("COLOR_PRESENT cannot be with other resource type flags. ");
@ -126,7 +129,7 @@ namespace SHADE
} }
// The resource is not a swapchain image, just use the first slot of the vector // The resource is not a swapchain image, just use the first slot of the vector
images.push_back(logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags)); images.push_back(graphStorage->logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags));
// prepare image view details // prepare image view details
SHImageViewDetails viewDetails SHImageViewDetails viewDetails
@ -141,7 +144,7 @@ namespace SHADE
}; };
// just 1 image view created // just 1 image view created
imageViews.push_back(images[0]->CreateImageView(logicalDevice, images[0], viewDetails)); imageViews.push_back(images[0]->CreateImageView(graphStorage->logicalDevice, images[0], viewDetails));
} }
} }
@ -166,7 +169,7 @@ namespace SHADE
, height{ rhs.height } , height{ rhs.height }
, mipLevels{ rhs.mipLevels } , mipLevels{ rhs.mipLevels }
, imageAspectFlags{ rhs.imageAspectFlags } , imageAspectFlags{ rhs.imageAspectFlags }
, swapchain {rhs.swapchain} , graphStorage{rhs.graphStorage}
{ {
} }
@ -198,7 +201,7 @@ namespace SHADE
height = rhs.height; height = rhs.height;
mipLevels = rhs.mipLevels; mipLevels = rhs.mipLevels;
imageAspectFlags = rhs.imageAspectFlags; imageAspectFlags = rhs.imageAspectFlags;
swapchain = rhs.swapchain; graphStorage = rhs.graphStorage;
return *this; return *this;
} }
@ -247,7 +250,7 @@ namespace SHADE
SHImageViewDetails viewDetails SHImageViewDetails viewDetails
{ {
.viewType = vk::ImageViewType::e2D, .viewType = vk::ImageViewType::e2D,
.format = swapchain->GetSurfaceFormatKHR().format, .format = graphStorage->swapchain->GetSurfaceFormatKHR().format,
.imageAspectFlags = vk::ImageAspectFlagBits::eColor, .imageAspectFlags = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0, .baseMipLevel = 0,
.mipLevelCount = 1, .mipLevelCount = 1,
@ -255,9 +258,9 @@ namespace SHADE
.layerCount = 1, .layerCount = 1,
}; };
for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i) for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i)
{ {
images[i] = swapchain->GetSwapchainImage(i); images[i] = graphStorage->swapchain->GetSwapchainImage(i);
imageViews[i]->ViewNewImage(images[i], viewDetails); imageViews[i]->ViewNewImage(images[i], viewDetails);
} }
} }
@ -308,6 +311,7 @@ namespace SHADE
return resourceFormat; return resourceFormat;
} }
uint32_t SHRenderGraphResource::GetWidth(void) const noexcept uint32_t SHRenderGraphResource::GetWidth(void) const noexcept
{ {
return width; return width;
@ -323,4 +327,19 @@ namespace SHADE
return imageViews [index]; return imageViews [index];
} }
Handle<SHVkImage> SHRenderGraphResource::GetImage(uint32_t index /*= NON_SWAPCHAIN_RESOURCE_INDEX*/) const noexcept
{
return images[index];
}
uint8_t SHRenderGraphResource::GetMipLevels(void) const noexcept
{
return mipLevels;
}
std::string SHRenderGraphResource::GetName(void) const noexcept
{
return resourceName;
}
} }

View File

@ -15,6 +15,7 @@ namespace SHADE
class SHVkSwapchain; class SHVkSwapchain;
class SHVkCommandBuffer; class SHVkCommandBuffer;
class SHVkBuffer; class SHVkBuffer;
class SHRenderGraphStorage;
static constexpr uint32_t NON_SWAPCHAIN_RESOURCE_INDEX = 0; static constexpr uint32_t NON_SWAPCHAIN_RESOURCE_INDEX = 0;
@ -24,11 +25,8 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */ /* PRIVATE MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
// for creation/recreation //! Storage from the render graph
Handle<SHVkLogicalDevice> logicalDevice; Handle<SHRenderGraphStorage> graphStorage;
// for creation/recreation
Handle<SHVkSwapchain> swapchain;
//! Name of the resource //! Name of the resource
std::string resourceName; std::string resourceName;
@ -69,7 +67,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */ /* CTORS AND DTORS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
SHRenderGraphResource(Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::string const& name, std::initializer_list<SH_ATT_DESC_TYPE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept; SHRenderGraphResource(Handle<SHRenderGraphStorage> renderGraphStorage, std::string const& name, std::initializer_list<SH_ATT_DESC_TYPE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept;
SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept; SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept;
SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept; SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept;
~SHRenderGraphResource(void) noexcept; ~SHRenderGraphResource(void) noexcept;
@ -84,12 +82,17 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */ /* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
vk::Format GetResourceFormat (void) const noexcept; vk::Format GetResourceFormat (void) const noexcept;
uint32_t GetWidth (void) const noexcept; uint32_t GetWidth (void) const noexcept;
uint32_t GetHeight (void) const noexcept; uint32_t GetHeight (void) const noexcept;
Handle<SHVkImageView> GetImageView (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept; Handle<SHVkImageView> GetImageView (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept;
Handle<SHVkImage> GetImage (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept;
uint8_t GetMipLevels (void) const noexcept;
std::string GetName (void) const noexcept;
friend class SHRenderGraphNode; friend class SHRenderGraphNode;
friend class SHRenderGraph; friend class SHRenderGraph;
friend class SHSubpass;
friend class SHRenderGraphNodeCompute;
}; };
} }

View File

@ -0,0 +1,43 @@
#pragma once
#include "Resource/SHHandle.h"
#include <memory>
namespace SHADE
{
class SHVkLogicalDevice;
class SHVkSwapchain;
class SHGraphicsGlobalData;
class SHVkDescriptorPool;
class SHRenderGraphResource;
class SHRenderGraphStorage
{
//! Logical device for creation of vulkan objects
Handle<SHVkLogicalDevice> logicalDevice;
//! swapchain handle
Handle<SHVkSwapchain> swapchain;
//! Resource manager for creation of objects
std::shared_ptr<SHResourceHub> resourceManager;
//! Descriptor pool for the descriptor sets to be created in the subpasses
Handle<SHVkDescriptorPool> descriptorPool;
//! For accessing resources anywhere in the graph
Handle<std::unordered_map<std::string, Handle<SHRenderGraphResource>>> graphResources;
//SHRenderGraphStorage(void) noexcept;
//SHRenderGraphStorage(SHRenderGraphStorage&& rhs) noexcept;
//SHRenderGraphStorage& operator=(SHRenderGraphStorage&& rhs) noexcept;
friend class SHRenderGraph;
friend class SHRenderGraphNode;
friend class SHSubpass;
friend class SHRenderGraphResource;
friend class SHRenderGraphNodeCompute;
};
}

View File

@ -4,6 +4,13 @@
#include "Graphics/Devices/SHVkLogicalDevice.h" #include "Graphics/Devices/SHVkLogicalDevice.h"
#include "SHRenderGraphNode.h" #include "SHRenderGraphNode.h"
#include "SHRenderGraphResource.h" #include "SHRenderGraphResource.h"
#include "Graphics/Shaders/SHVkShaderModule.h"
#include "SHRenderGraphNode.h"
#include "SHRenderGraphStorage.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/Swapchain/SHVkSwapchain.h"
#include "Graphics/Images/SHVkSampler.h"
#include "SHRenderGraphResource.h"
namespace SHADE namespace SHADE
{ {
@ -23,15 +30,16 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
SHSubpass::SHSubpass(Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources) noexcept SHSubpass::SHSubpass(Handle<SHRenderGraphStorage> renderGraphStorage, Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping) noexcept
: resourceAttachmentMapping{ mapping } : resourceAttachmentMapping{ mapping }
, ptrToResources{ resources }
, parentNode{ parent } , parentNode{ parent }
, subpassIndex{ index } , subpassIndex{ index }
, superBatch{} , superBatch{}
, colorReferences{} , colorReferences{}
, depthReferences{} , depthReferences{}
, inputReferences{} , inputReferences{}
, graphStorage{ renderGraphStorage }
, inputImageDescriptors {SHGraphicsConstants::NUM_FRAME_BUFFERS}
{ {
} }
@ -54,9 +62,14 @@ namespace SHADE
, depthReferences{ std::move(rhs.depthReferences) } , depthReferences{ std::move(rhs.depthReferences) }
, inputReferences{ std::move(rhs.inputReferences) } , inputReferences{ std::move(rhs.inputReferences) }
, resourceAttachmentMapping{ rhs.resourceAttachmentMapping } , resourceAttachmentMapping{ rhs.resourceAttachmentMapping }
, ptrToResources{ rhs.ptrToResources }
, descriptorSetLayout{ rhs.descriptorSetLayout } , descriptorSetLayout{ rhs.descriptorSetLayout }
, exteriorDrawCalls{ std::move (rhs.exteriorDrawCalls) } , exteriorDrawCalls{ std::move(rhs.exteriorDrawCalls) }
, graphStorage{ rhs.graphStorage }
, inputNames{ std::move(rhs.inputNames) }
, inputImageDescriptors{ std::move(rhs.inputImageDescriptors) }
, inputDescriptorLayout{ rhs.inputDescriptorLayout }
, inputSamplers{ rhs.inputSamplers }
{ {
} }
@ -84,9 +97,13 @@ namespace SHADE
depthReferences = std::move(rhs.depthReferences); depthReferences = std::move(rhs.depthReferences);
inputReferences = std::move(rhs.inputReferences); inputReferences = std::move(rhs.inputReferences);
resourceAttachmentMapping = rhs.resourceAttachmentMapping; resourceAttachmentMapping = rhs.resourceAttachmentMapping;
ptrToResources = rhs.ptrToResources;
descriptorSetLayout = rhs.descriptorSetLayout; descriptorSetLayout = rhs.descriptorSetLayout;
exteriorDrawCalls = std::move(rhs.exteriorDrawCalls); exteriorDrawCalls = std::move(rhs.exteriorDrawCalls);
graphStorage = rhs.graphStorage;
inputNames = std::move(rhs.inputNames);
inputImageDescriptors = std::move(rhs.inputImageDescriptors);
inputDescriptorLayout = rhs.inputDescriptorLayout;
inputSamplers = rhs.inputSamplers;
return *this; return *this;
} }
@ -105,7 +122,12 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
void SHSubpass::AddColorOutput(std::string resourceToReference) noexcept void SHSubpass::AddColorOutput(std::string resourceToReference) noexcept
{ {
colorReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal }); colorReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal });
}
void SHSubpass::AddGeneralColorOutput(std::string resourceToReference) noexcept
{
colorReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eGeneral });
} }
/***************************************************************************/ /***************************************************************************/
@ -142,7 +164,13 @@ namespace SHADE
//Invalid //Invalid
return; return;
} }
depthReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), imageLayout }); depthReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), imageLayout });
}
void SHSubpass::AddGeneralDepthOutput(std::string resourceToReference) noexcept
{
depthReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eGeneral });
} }
/***************************************************************************/ /***************************************************************************/
@ -159,7 +187,14 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
void SHSubpass::AddInput(std::string resourceToReference) noexcept void SHSubpass::AddInput(std::string resourceToReference) noexcept
{ {
inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal }); inputReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal });
inputNames.push_back(resourceToReference);
}
void SHSubpass::AddGeneralInput(std::string resourceToReference) noexcept
{
inputReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eGeneral });
} }
void SHSubpass::Execute(Handle<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept void SHSubpass::Execute(Handle<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
@ -175,6 +210,12 @@ namespace SHADE
{ {
drawCall(commandBuffer); drawCall(commandBuffer);
} }
}
void SHSubpass::HandleResize(void) noexcept
{
UpdateWriteDescriptors();
} }
void SHSubpass::AddExteriorDrawCalls(std::function<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept void SHSubpass::AddExteriorDrawCalls(std::function<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept
@ -188,6 +229,152 @@ namespace SHADE
} }
void SHSubpass::CreateInputDescriptors(void) noexcept
{
if (inputNames.empty())
return;
std::vector<SHVkDescriptorSetLayout::Binding> bindings{};
for (auto& input : inputReferences)
{
SHVkDescriptorSetLayout::Binding newBinding
{
.Type = (input.layout == vk::ImageLayout::eShaderReadOnlyOptimal) ? vk::DescriptorType::eInputAttachment : vk::DescriptorType::eStorageImage,
.Stage = vk::ShaderStageFlagBits::eFragment,
.BindPoint = static_cast<uint32_t>(bindings.size()),
.DescriptorCount = 1,
.flags = {},
};
bindings.push_back(newBinding);
}
// We build a new descriptor set layout to store our images
inputDescriptorLayout = graphStorage->logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, bindings);
// we store a sampler if its an input attachment. if it is storage image, no need sampler, store an empty handle.
for (uint32_t i = 0; i < bindings.size(); ++i)
{
if (bindings[i].Type == vk::DescriptorType::eInputAttachment)
{
auto newSampler = graphStorage->logicalDevice->CreateSampler(SHVkSamplerParams
{
.minFilter = vk::Filter::eLinear,
.magFilter = vk::Filter::eLinear,
.addressMode = vk::SamplerAddressMode::eRepeat,
.mipmapMode = vk::SamplerMipmapMode::eLinear,
.minLod = -1000,
.maxLod = 1000
}
);
inputSamplers.push_back(newSampler);
}
else
{
inputSamplers.push_back({});
}
}
//// maybe do this in handle resize?
//UpdateWriteDescriptors();
}
void SHSubpass::UpdateWriteDescriptors(void) noexcept
{
if (inputNames.empty())
return;
auto const& bindings = inputDescriptorLayout->GetBindings();
std::vector<uint32_t> variableCounts{ static_cast<uint32_t>(bindings.size()) };
std::fill (variableCounts.begin(), variableCounts.end(), 0u);
// For every frame's descriptor set
for (auto& group : inputImageDescriptors)
{
if (group)
group.Free();
group = graphStorage->descriptorPool->Allocate({ inputDescriptorLayout }, variableCounts);
uint32_t i = 0;
for (auto& binding : bindings)
{
// get the resource
auto resource = graphStorage->graphResources->at(inputNames[binding.BindPoint]);
// If resource is swapchain image, get the correct image, if not just get 0.
uint32_t viewIndex = (resource->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? i : 0;
// layout is GENERAL if image is meant to be used as storage image, if not use SHADER_READ_ONLY_OPTINAL
vk::ImageLayout descriptorLayout = (binding.Type == vk::DescriptorType::eStorageImage) ? vk::ImageLayout::eGeneral : vk::ImageLayout::eShaderReadOnlyOptimal;
// Update descriptor sets
auto args = std::make_tuple(resource->GetImageView(viewIndex), inputSamplers[i], descriptorLayout);
group->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint, std::span{&args, 1});
group->UpdateDescriptorSetImages(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint);
}
++i;
}
}
//void SHSubpass::InitComputeBarriers(void) noexcept
//{
// std::unordered_set <uint64_t> handleBarriers{};
// // we will have swapchainNumImages vectors of vector of barriers
// subpassComputeBarriers.resize(graphStorage->swapchain->GetNumImages());
// for (auto sbCompute : subpassComputes)
// {
// // for every resource the subpass compute is using
// for (auto resource : sbCompute->resources)
// {
// // Get the resource handle
// uint64_t resourceRaw = resource.GetId().Raw;
// // if the barrier is not registered
// if (!handleBarriers.contains(resourceRaw))
// {
// // If the resource is a swapchain image
// bool isSwapchainImage = (resource->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT));
// for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i)
// {
// // if swapchain image, we want the index of the swapchain image, if not take base image
// uint32_t imageIndex = isSwapchainImage ? i : 0;
// // Prepare image barrier
// vk::ImageMemoryBarrier imageBarrier
// {
// .oldLayout = colorReferences[resourceAttachmentMapping->at(resource.GetId().Raw)].layout,
// .newLayout = vk::ImageLayout::eGeneral,
// .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
// .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
// .image = resource->GetImage(imageIndex)->GetVkImage(),
// .subresourceRange =
// {
// .aspectMask = resource->imageAspectFlags,
// .levelCount = resource->GetMipLevels(),
// .baseArrayLayer = 0,
// .layerCount = 1
// }
// };
// // push the barrier
// subpassComputeBarriers[i].push_back(imageBarrier);
// }
// // Image transition registered
// handleBarriers.emplace(resourceRaw);
// }
// }
// }
//}
/***************************************************************************/ /***************************************************************************/
/*! /*!

View File

@ -14,7 +14,11 @@ namespace SHADE
class SHRenderGraphResource; class SHRenderGraphResource;
class SHVkCommandBuffer; class SHVkCommandBuffer;
class SHVkDescriptorSetLayout; class SHVkDescriptorSetLayout;
class SHVkDescriptorSetGroup;
class SHVkDescriptorPool; class SHVkDescriptorPool;
class SHRenderGraphStorage;
class SHVkShaderModule;
class SHVkSampler;
class SH_API SHSubpass : public ISelfHandle<SHSubpass> class SH_API SHSubpass : public ISelfHandle<SHSubpass>
{ {
@ -22,32 +26,49 @@ namespace SHADE
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */ /* PRIVATE MEMBER VARIABLES */
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
Handle<SHRenderGraphStorage> graphStorage;
//! The index of the subpass in the render graph //! The index of the subpass in the render graph
uint32_t subpassIndex; uint32_t subpassIndex;
//! The parent renderpass that this subpass belongs to //! The parent renderpass that this subpass belongs to
Handle<SHRenderGraphNode> parentNode; Handle<SHRenderGraphNode> parentNode;
//! //!
Handle<SHSuperBatch> superBatch; Handle<SHSuperBatch> superBatch;
//! Descriptor set layout to hold attachments //! Descriptor set layout to hold attachments
Handle<SHVkDescriptorSetLayout> descriptorSetLayout; Handle<SHVkDescriptorSetLayout> descriptorSetLayout;
//! Color attachments //! Color attachments
std::vector<vk::AttachmentReference> colorReferences; std::vector<vk::AttachmentReference> colorReferences;
//! Depth attachments //! Depth attachments
std::vector<vk::AttachmentReference> depthReferences; std::vector<vk::AttachmentReference> depthReferences;
//! Input attachments //! Input attachments
std::vector<vk::AttachmentReference> inputReferences; std::vector<vk::AttachmentReference> inputReferences;
//! This is mainly for when we want to retrieve resources using names.
std::vector<std::string> inputNames;
//! For getting attachment reference indices using handles //! For getting attachment reference indices using handles
std::unordered_map<uint64_t, uint32_t> const* resourceAttachmentMapping; std::unordered_map<uint64_t, uint32_t> const* resourceAttachmentMapping;
//! Pointer to resources in the render graph (for getting handle IDs) //! Descriptor set group to hold the images for input
std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources; std::vector<Handle<SHVkDescriptorSetGroup>> inputImageDescriptors;
//! Descriptor set layout for allocating descriptor set for inputs
Handle<SHVkDescriptorSetLayout> inputDescriptorLayout;
std::vector<Handle<SHVkSampler>> inputSamplers;
////! subpass compute image barriers. We do this because every frame has a different
////! swapchain image. If the resource we want to transition is not a swapchain image,
////! we duplicate the barrier anyway, not much memory wasted. ;)
//std::vector<std::vector<vk::ImageMemoryBarrier>> subpassComputeBarriers{};
//! Sometimes there exists entities that we want to render onto a render target //! Sometimes there exists entities that we want to render onto a render target
//! but don't want it to come from the batching system. An example would be ImGUI. //! but don't want it to come from the batching system. An example would be ImGUI.
@ -62,7 +83,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */ /* CTORS AND DTORS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
SHSubpass(Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources) noexcept; SHSubpass(Handle<SHRenderGraphStorage> renderGraphStorage, Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping) noexcept;
SHSubpass(SHSubpass&& rhs) noexcept; SHSubpass(SHSubpass&& rhs) noexcept;
SHSubpass& operator=(SHSubpass&& rhs) noexcept; SHSubpass& operator=(SHSubpass&& rhs) noexcept;
@ -71,14 +92,22 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
// Preparation functions // Preparation functions
void AddColorOutput(std::string resourceToReference) noexcept; void AddColorOutput(std::string resourceToReference) noexcept;
void AddGeneralColorOutput(std::string resourceToReference) noexcept;
void AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE_FLAGS attachmentDescriptionType = SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL) noexcept; void AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE_FLAGS attachmentDescriptionType = SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL) noexcept;
void AddGeneralDepthOutput(std::string resourceToReference) noexcept;
void AddInput(std::string resourceToReference) noexcept; void AddInput(std::string resourceToReference) noexcept;
void AddGeneralInput (std::string resourceToReference) noexcept;
void AddExteriorDrawCalls(std::function<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept;
// Runtime functions // Runtime functions
void Execute(Handle<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept; void Execute(Handle<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
void AddExteriorDrawCalls(std::function<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept; void HandleResize (void) noexcept;
void Init(SHResourceHub& resourceManager) noexcept; void Init(SHResourceHub& resourceManager) noexcept;
//void InitComputeBarriers (void) noexcept;
void CreateInputDescriptors (void) noexcept;
void UpdateWriteDescriptors (void) noexcept;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */ /* GETTERS AND SETTERS */
@ -91,5 +120,6 @@ namespace SHADE
friend class SHRenderGraphNode; friend class SHRenderGraphNode;
friend class SHRenderGraph; friend class SHRenderGraph;
friend class SHSubpass;
}; };
} }

View File

@ -1,23 +0,0 @@
#include "SHpch.h"
#include "SHSubpassCompute.h"
#include "Graphics/Pipeline/SHVkPipeline.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/Descriptors/SHVkDescriptorPool.h"
namespace SHADE
{
SHSubpassCompute::SHSubpassCompute(Handle<SHVkPipeline> inPipeline, Handle<SHVkDescriptorPool> descPool) noexcept
: pipeline {inPipeline}
{
// Get the descriptor set layouts required to allocate. we will bind a different pipeline layout, one that includes the layout for global.
auto const& layouts = pipeline->GetPipelineLayout()->GetDescriptorSetLayoutsAllocate();
// Variable counts for the descriptor sets (all should be 1).
std::vector<uint32_t> variableCounts{static_cast<uint32_t>(layouts.size())};
std::fill (variableCounts.begin(), variableCounts.end(), 0);
// Allocate descriptor sets to hold the images for reading (STORAGE_IMAGE)
descPool->Allocate(layouts, variableCounts);
}
}

View File

@ -1,25 +0,0 @@
#pragma once
#include <Resource/SHHandle.h>
namespace SHADE
{
class SHVkPipeline;
class SHVkDescriptorSetGroup;
class SHVkDescriptorPool;
class SHSubpassCompute
{
private:
//! To run the dispatch command
Handle<SHVkPipeline> pipeline;
//! Descriptor set group
Handle<SHVkDescriptorSetGroup> descSetGroup;
public:
SHSubpassCompute (Handle<SHVkPipeline> inPipeline, Handle<SHVkDescriptorPool> descPool) noexcept;
};
}

View File

@ -51,10 +51,37 @@ namespace SHADE
case vk::Format::eR32Uint: case vk::Format::eR32Uint:
case vk::Format::eR32Sfloat: case vk::Format::eR32Sfloat:
return 4; return 4;
case vk::Format::eR32G32Sint:
case vk::Format::eR32G32Uint:
case vk::Format::eR32G32Sfloat:
return 8;
case vk::Format::eR32G32B32Sint:
case vk::Format::eR32G32B32Uint:
case vk::Format::eR32G32B32Sfloat:
return 12;
case vk::Format::eR32G32B32A32Sint:
case vk::Format::eR32G32B32A32Uint:
case vk::Format::eR32G32B32A32Sfloat:
return 16;
} }
return 0; return 0;
} }
vk::PipelineBindPoint SHVkUtil::GetPipelineBindPointFromType(SH_PIPELINE_TYPE pipelineType) noexcept
{
switch (pipelineType)
{
case SH_PIPELINE_TYPE::GRAPHICS:
return vk::PipelineBindPoint::eGraphics;
case SH_PIPELINE_TYPE::COMPUTE:
return vk::PipelineBindPoint::eCompute;
case SH_PIPELINE_TYPE::RAY_TRACING:
return vk::PipelineBindPoint::eRayTracingKHR;
default:
return vk::PipelineBindPoint::eGraphics;
}
}
void SHVkUtil::EnsureBufferAndCopyData(Handle<SHVkLogicalDevice> device, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkBuffer>& bufferHandle, void* src, uint32_t size, vk::BufferUsageFlagBits usage) void SHVkUtil::EnsureBufferAndCopyData(Handle<SHVkLogicalDevice> device, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkBuffer>& bufferHandle, void* src, uint32_t size, vk::BufferUsageFlagBits usage)
{ {
if (bufferHandle) if (bufferHandle)

View File

@ -4,6 +4,7 @@
#include "SHVulkanIncludes.h" #include "SHVulkanIncludes.h"
#include "Resource/SHHandle.h" #include "Resource/SHHandle.h"
#include "Graphics/Pipeline/SHPipelineType.h"
namespace SHADE namespace SHADE
{ {
@ -20,11 +21,12 @@ namespace SHADE
class SHVkUtil class SHVkUtil
{ {
public: public:
static bool IsDepthOnlyFormat (vk::Format format) noexcept; static bool IsDepthOnlyFormat (vk::Format format) noexcept;
static bool IsDepthStencilAttachment (vk::Format format) noexcept; static bool IsDepthStencilAttachment (vk::Format format) noexcept;
static bool IsBlendCompatible (vk::Format format) noexcept; static bool IsBlendCompatible (vk::Format format) noexcept;
static uint32_t GetBytesPerPixelFromFormat (vk::Format format) noexcept; static uint32_t GetBytesPerPixelFromFormat (vk::Format format) noexcept;
static vk::PipelineBindPoint GetPipelineBindPointFromType (SH_PIPELINE_TYPE pipelineType) noexcept;
/***********************************************************************************/ /***********************************************************************************/
/*! /*!

View File

@ -177,6 +177,9 @@ namespace SHADE
return vk::DescriptorType::eStorageBufferDynamic; return vk::DescriptorType::eStorageBufferDynamic;
case SpvReflectDescriptorType::SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: case SpvReflectDescriptorType::SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
return vk::DescriptorType::eInputAttachment; return vk::DescriptorType::eInputAttachment;
case SpvReflectDescriptorType::SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE:
return vk::DescriptorType::eStorageImage;
break;
default: default:
return vk::DescriptorType::eCombinedImageSampler; return vk::DescriptorType::eCombinedImageSampler;
break; break;

View File

@ -22,6 +22,9 @@ namespace SHADE
// integer formats // integer formats
UINT32_1D, UINT32_1D,
UINT32_2D,
UINT32_3D,
UINT32_4D,
}; };
struct SHVertexAttribute struct SHVertexAttribute

View File

@ -295,32 +295,33 @@ namespace SHADE
) != 0; ) != 0;
} }
SHMatrix::operator XMMATRIX() const noexcept
{
return XMLoadFloat4x4(this);
}
SHMatrix operator*(float lhs, const SHMatrix& rhs) noexcept SHMatrix operator*(float lhs, const SHMatrix& rhs) noexcept
{ {
return rhs * lhs; return rhs * lhs;
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Function Member Definitions */ /* Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHMatrix::Transpose() noexcept void SHMatrix::Transpose() noexcept
{ {
const XMMATRIX M = XMLoadFloat4x4(this); XMStoreFloat4x4(this, XMMatrixTranspose(*this));
XMStoreFloat4x4(this, XMMatrixTranspose(M));
} }
void SHMatrix::Invert() noexcept void SHMatrix::Invert() noexcept
{ {
const XMMATRIX M = XMLoadFloat4x4(this); XMStoreFloat4x4(this, XMMatrixInverse(nullptr, *this));
XMStoreFloat4x4(this, XMMatrixInverse(nullptr, M));
} }
float SHMatrix::Determinant() const noexcept float SHMatrix::Determinant() const noexcept
{ {
const XMMATRIX M = XMLoadFloat4x4(this); return XMVectorGetX(XMMatrixDeterminant(*this));
return XMVectorGetX(XMMatrixDeterminant(M));
} }
std::string SHMatrix::ToString() const noexcept std::string SHMatrix::ToString() const noexcept
@ -337,9 +338,8 @@ namespace SHADE
bool SHMatrix::Decompose(SHVec3& translation, SHVec3& rotation, SHVec3& scale) const noexcept bool SHMatrix::Decompose(SHVec3& translation, SHVec3& rotation, SHVec3& scale) const noexcept
{ {
XMVECTOR s, r, t; XMVECTOR s, r, t;
const XMMATRIX M = XMLoadFloat4x4(this);
if (!XMMatrixDecompose(&s, &r, &t, M)) if (!XMMatrixDecompose(&s, &r, &t, *this))
return false; return false;
SHQuaternion orientation; SHQuaternion orientation;
@ -356,9 +356,8 @@ namespace SHADE
bool SHMatrix::Decompose(SHVec3& translation, SHQuaternion& orientation, SHVec3& scale) const noexcept bool SHMatrix::Decompose(SHVec3& translation, SHQuaternion& orientation, SHVec3& scale) const noexcept
{ {
XMVECTOR s, r, t; XMVECTOR s, r, t;
const XMMATRIX M = XMLoadFloat4x4(this);
if (!XMMatrixDecompose(&s, &r, &t, M)) if (!XMMatrixDecompose(&s, &r, &t, *this))
return false; return false;
XMStoreFloat3(&scale, s); XMStoreFloat3(&scale, s);
@ -376,8 +375,7 @@ namespace SHADE
{ {
SHMatrix result; SHMatrix result;
const XMMATRIX M = XMLoadFloat4x4(&matrix); XMStoreFloat4x4(&result, XMMatrixTranspose(matrix));
XMStoreFloat4x4(&result, XMMatrixTranspose(M));
return result; return result;
} }
@ -385,8 +383,7 @@ namespace SHADE
{ {
SHMatrix result; SHMatrix result;
const XMMATRIX M = XMLoadFloat4x4(&matrix); XMStoreFloat4x4(&result, XMMatrixInverse(nullptr, matrix));
XMStoreFloat4x4(&result, XMMatrixInverse(nullptr, M));
return result; return result;
} }
@ -401,8 +398,8 @@ namespace SHADE
SHMatrix SHMatrix::Translate(const SHVec3& pos) noexcept SHMatrix SHMatrix::Translate(const SHVec3& pos) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixTranslation(pos.x, pos.y, pos.z));
XMStoreFloat4x4(&result, XMMatrixTranslation(pos.x, pos.y, pos.z));
return result; return result;
} }
@ -410,25 +407,23 @@ namespace SHADE
{ {
SHMatrix result; SHMatrix result;
const XMVECTOR A = XMLoadFloat3(&axis); XMStoreFloat4x4(&result, XMMatrixRotationAxis(axis, angleInRad));
XMStoreFloat4x4(&result, XMMatrixRotationAxis(A, angleInRad));
return result; return result;
} }
SHMatrix SHMatrix::Rotate(float yaw, float pitch, float roll) noexcept SHMatrix SHMatrix::Rotate(float yaw, float pitch, float roll) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(pitch, yaw, roll));
XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(pitch, yaw, roll));
return result; return result;
} }
SHMatrix SHMatrix::Rotate(const SHVec3& eulerAngles) noexcept SHMatrix SHMatrix::Rotate(const SHVec3& eulerAngles) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(eulerAngles.x, eulerAngles.y, eulerAngles.z));
XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYawFromVector(eulerAngles));
return result; return result;
} }
@ -436,57 +431,55 @@ namespace SHADE
{ {
SHMatrix result; SHMatrix result;
const XMVECTOR Q = XMLoadFloat4(&q); XMStoreFloat4x4(&result, XMMatrixRotationQuaternion(q));
XMStoreFloat4x4(&result, XMMatrixRotationQuaternion(Q));
return result; return result;
} }
SHMatrix SHMatrix::RotateX(float angleInRad) noexcept SHMatrix SHMatrix::RotateX(float angleInRad) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixRotationX(angleInRad));
XMStoreFloat4x4(&result, XMMatrixRotationX(angleInRad));
return result; return result;
} }
SHMatrix SHMatrix::RotateY(float angleInRad) noexcept SHMatrix SHMatrix::RotateY(float angleInRad) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixRotationY(angleInRad));
XMStoreFloat4x4(&result, XMMatrixRotationY(angleInRad));
return result; return result;
} }
SHMatrix SHMatrix::RotateZ(float angleInRad) noexcept SHMatrix SHMatrix::RotateZ(float angleInRad) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixRotationZ(angleInRad));
XMStoreFloat4x4(&result, XMMatrixRotationZ(angleInRad));
return result; return result;
} }
SHMatrix SHMatrix::Scale(float uniformScaleFactor) noexcept SHMatrix SHMatrix::Scale(float uniformScaleFactor) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixScaling(uniformScaleFactor, uniformScaleFactor, uniformScaleFactor));
XMStoreFloat4x4(&result, XMMatrixScaling(uniformScaleFactor, uniformScaleFactor, uniformScaleFactor));
return result; return result;
} }
SHMatrix SHMatrix::Scale(float x, float y, float z) noexcept SHMatrix SHMatrix::Scale(float x, float y, float z) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixScaling(x, y, z));
XMStoreFloat4x4(&result, XMMatrixScaling(x, y, z));
return result; return result;
} }
SHMatrix SHMatrix::Scale(const SHVec3& scale) noexcept SHMatrix SHMatrix::Scale(const SHVec3& scale) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixScaling(scale.x, scale.y, scale.z));
XMStoreFloat4x4(&result, XMMatrixScalingFromVector(scale));
return result; return result;
} }
@ -494,12 +487,7 @@ namespace SHADE
{ {
SHMatrix result; SHMatrix result;
const XMVECTOR EYE = XMLoadFloat3(&eye); XMStoreFloat4x4(&result, XMMatrixLookAtRH(eye, target, up));
const XMVECTOR TGT = XMLoadFloat3(&target);
const XMVECTOR UP = XMLoadFloat3(&up);
XMStoreFloat4x4(&result, XMMatrixLookAtRH(EYE, TGT, UP));
return result; return result;
} }
@ -507,12 +495,7 @@ namespace SHADE
{ {
SHMatrix result; SHMatrix result;
const XMVECTOR EYE = XMLoadFloat3(&eye); XMStoreFloat4x4(&result, XMMatrixLookAtLH(eye, target, up));
const XMVECTOR TGT = XMLoadFloat3(&target);
const XMVECTOR UP = XMLoadFloat3(&up);
XMStoreFloat4x4(&result, XMMatrixLookAtLH(EYE, TGT, UP));
return result; return result;
} }
@ -522,8 +505,8 @@ namespace SHADE
const SHVec3 FWD_HAT = SHVec3::Normalise(-forward); const SHVec3 FWD_HAT = SHVec3::Normalise(-forward);
const XMVECTOR Z_HAT = XMVector3Normalize(XMLoadFloat3(&FWD_HAT)); const XMVECTOR Z_HAT = XMVector3Normalize(FWD_HAT);
const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(XMLoadFloat3(&up), Z_HAT)); const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(up, Z_HAT));
const XMVECTOR Y_HAT = XMVector3Cross(Z_HAT, X_HAT); const XMVECTOR Y_HAT = XMVector3Cross(Z_HAT, X_HAT);
XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&result._11), X_HAT); XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&result._11), X_HAT);
@ -543,8 +526,8 @@ namespace SHADE
const SHVec3 FWD_HAT = SHVec3::Normalise(forward); const SHVec3 FWD_HAT = SHVec3::Normalise(forward);
const XMVECTOR Z_HAT = XMVector3Normalize(XMLoadFloat3(&FWD_HAT)); const XMVECTOR Z_HAT = XMVector3Normalize(FWD_HAT);
const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(XMLoadFloat3(&up), Z_HAT)); const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(up, Z_HAT));
const XMVECTOR Y_HAT = XMVector3Cross(Z_HAT, X_HAT); const XMVECTOR Y_HAT = XMVector3Cross(Z_HAT, X_HAT);
XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&result._11), X_HAT); XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&result._11), X_HAT);
@ -563,7 +546,6 @@ namespace SHADE
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixPerspectiveFovRH(fov, aspectRatio, nearPlane, farPlane)); XMStoreFloat4x4(&result, XMMatrixPerspectiveFovRH(fov, aspectRatio, nearPlane, farPlane));
return result; return result;
} }
@ -572,7 +554,6 @@ namespace SHADE
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixPerspectiveFovLH(fov, aspectRatio, nearPlane, farPlane)); XMStoreFloat4x4(&result, XMMatrixPerspectiveFovLH(fov, aspectRatio, nearPlane, farPlane));
return result; return result;
} }
@ -581,7 +562,6 @@ namespace SHADE
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixPerspectiveRH(width, height, nearPlane, farPlane)); XMStoreFloat4x4(&result, XMMatrixPerspectiveRH(width, height, nearPlane, farPlane));
return result; return result;
} }
@ -590,7 +570,6 @@ namespace SHADE
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixPerspectiveLH(width, height, nearPlane, farPlane)); XMStoreFloat4x4(&result, XMMatrixPerspectiveLH(width, height, nearPlane, farPlane));
return result; return result;
} }
@ -599,7 +578,6 @@ namespace SHADE
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixOrthographicRH(width, height, nearPlane, farPlane)); XMStoreFloat4x4(&result, XMMatrixOrthographicRH(width, height, nearPlane, farPlane));
return result; return result;
} }
@ -608,7 +586,6 @@ namespace SHADE
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixOrthographicLH(width, height, nearPlane, farPlane)); XMStoreFloat4x4(&result, XMMatrixOrthographicLH(width, height, nearPlane, farPlane));
return result; return result;
} }

View File

@ -77,6 +77,8 @@ namespace SHADE
SHMatrix& operator= (const SHMatrix& rhs) = default; SHMatrix& operator= (const SHMatrix& rhs) = default;
SHMatrix& operator= (SHMatrix&& rhs) = default; SHMatrix& operator= (SHMatrix&& rhs) = default;
operator DirectX::XMMATRIX () const noexcept;
SHMatrix& operator+= (const SHMatrix& rhs) noexcept; SHMatrix& operator+= (const SHMatrix& rhs) noexcept;
SHMatrix& operator-= (const SHMatrix& rhs) noexcept; SHMatrix& operator-= (const SHMatrix& rhs) noexcept;
SHMatrix& operator*= (const SHMatrix& rhs) noexcept; SHMatrix& operator*= (const SHMatrix& rhs) noexcept;

View File

@ -36,44 +36,18 @@ namespace SHADE
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
{} {}
SHQuaternion::SHQuaternion(const SHVec4& vec4) noexcept
: XMFLOAT4( vec4.x, vec4.y, vec4.z, vec4.w )
{}
SHQuaternion::SHQuaternion(float _x, float _y, float _z, float _w) noexcept SHQuaternion::SHQuaternion(float _x, float _y, float _z, float _w) noexcept
: XMFLOAT4( _x, _y, _z, _w ) : XMFLOAT4( _x, _y, _z, _w )
{} {}
SHQuaternion::SHQuaternion(float yaw, float pitch, float roll) noexcept
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
{
XMStoreFloat4(this, XMQuaternionRotationRollPitchYaw(pitch, yaw, roll));
}
SHQuaternion::SHQuaternion(const SHVec3& eulerAngles) noexcept
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
{
const XMVECTOR V = XMLoadFloat3(&eulerAngles);
XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(V));
}
SHQuaternion::SHQuaternion(const SHVec3& axis, float angleInRad) noexcept
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
{
const XMVECTOR AXIS = XMLoadFloat3(&axis);
XMStoreFloat4(this, XMQuaternionRotationAxis(AXIS, angleInRad));
}
SHQuaternion::SHQuaternion(const SHMatrix& rotationMatrix) noexcept
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
{
const XMMATRIX M = XMLoadFloat4x4(&rotationMatrix);
XMStoreFloat4(this, XMQuaternionRotationMatrix(M));
}
SHQuaternion::SHQuaternion(const reactphysics3d::Vector3& rp3dEuler) noexcept SHQuaternion::SHQuaternion(const reactphysics3d::Vector3& rp3dEuler) noexcept
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
{ {
const SHVec3& SHADE_VEC{ rp3dEuler }; XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(SHVec3 { rp3dEuler }));
const XMVECTOR V = XMLoadFloat3(&SHADE_VEC);
XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(V));
} }
SHQuaternion::SHQuaternion(const reactphysics3d::Quaternion& rp3dQuat) noexcept SHQuaternion::SHQuaternion(const reactphysics3d::Quaternion& rp3dQuat) noexcept
@ -113,10 +87,7 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q1 = XMLoadFloat4(this); XMStoreFloat4(&result, XMVectorAdd(*this, rhs));
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
XMStoreFloat4(&result, XMVectorAdd(Q1, Q2));
return result; return result;
} }
@ -124,10 +95,7 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q1 = XMLoadFloat4(this); XMStoreFloat4(&result, XMVectorSubtract(*this, rhs));
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
XMStoreFloat4(&result, XMVectorSubtract(Q1, Q2));
return result; return result;
} }
@ -135,9 +103,7 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q = XMLoadFloat4(this); XMStoreFloat4(&result, XMVectorNegate(*this));
XMStoreFloat4(&result, XMVectorNegate(Q));
return result; return result;
} }
@ -145,10 +111,7 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q1 = XMLoadFloat4(this); XMStoreFloat4(&result, XMQuaternionMultiply(*this, rhs));
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q2));
return result; return result;
} }
@ -156,9 +119,7 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q = XMLoadFloat4(this); XMStoreFloat4(&result, XMVectorScale(*this, rhs));
XMStoreFloat4(&result, XMVectorScale(Q, rhs));
return result; return result;
} }
@ -166,27 +127,18 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q1 = XMLoadFloat4(this); XMStoreFloat4(&result, XMQuaternionMultiply(*this, XMQuaternionInverse(rhs)));
const XMVECTOR Q2 = XMQuaternionInverse(XMLoadFloat4(&rhs));
XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q2));
return result; return result;
} }
bool SHQuaternion::operator==(const SHQuaternion& rhs) const noexcept bool SHQuaternion::operator==(const SHQuaternion& rhs) const noexcept
{ {
const XMVECTOR Q1 = XMLoadFloat4(this); return XMQuaternionEqual(*this, rhs);
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
return XMQuaternionEqual(Q1, Q2);
} }
bool SHQuaternion::operator!=(const SHQuaternion& rhs) const noexcept bool SHQuaternion::operator!=(const SHQuaternion& rhs) const noexcept
{ {
const XMVECTOR Q1 = XMLoadFloat4(this); return XMQuaternionNotEqual(*this, rhs);
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
return XMQuaternionNotEqual(Q1, Q2);
} }
SHQuaternion::operator reactphysics3d::Quaternion() const noexcept SHQuaternion::operator reactphysics3d::Quaternion() const noexcept
@ -199,6 +151,11 @@ namespace SHADE
return reactphysics3d::Vector3{ ToEuler() }; return reactphysics3d::Vector3{ ToEuler() };
} }
SHQuaternion::operator XMVECTOR() const noexcept
{
return XMLoadFloat4(this);
}
SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept
{ {
return rhs * lhs; return rhs * lhs;
@ -213,8 +170,7 @@ namespace SHADE
XMVECTOR axis; XMVECTOR axis;
float angle; float angle;
const XMVECTOR Q = XMLoadFloat4(this); XMQuaternionToAxisAngle(&axis, &angle, *this);
XMQuaternionToAxisAngle(&axis, &angle, Q);
return angle; return angle;
} }
@ -223,8 +179,7 @@ namespace SHADE
XMVECTOR axis; XMVECTOR axis;
float angle; float angle;
const XMVECTOR Q = XMLoadFloat4(this); XMQuaternionToAxisAngle(&axis, &angle, *this);
XMQuaternionToAxisAngle(&axis, &angle, Q);
return SHVec4{XMVectorGetX(axis), XMVectorGetY(axis), XMVectorGetZ(axis), angle}; return SHVec4{XMVectorGetX(axis), XMVectorGetY(axis), XMVectorGetZ(axis), angle};
@ -238,64 +193,49 @@ namespace SHADE
void SHQuaternion::Invert() noexcept void SHQuaternion::Invert() noexcept
{ {
const XMVECTOR Q = XMLoadFloat4(this); XMStoreFloat4(this, XMQuaternionInverse(*this));
XMStoreFloat4(this, XMQuaternionInverse(Q));
} }
float SHQuaternion::Length() const noexcept float SHQuaternion::Length() const noexcept
{ {
const XMVECTOR Q = XMLoadFloat4(this); return XMVectorGetX(XMQuaternionLength(*this));
return XMVectorGetX(XMQuaternionLength(Q));
} }
float SHQuaternion::LengthSquared() const noexcept float SHQuaternion::LengthSquared() const noexcept
{ {
const XMVECTOR Q = XMLoadFloat4(this); return XMVectorGetX(XMQuaternionLengthSq(*this));
return XMVectorGetX(XMQuaternionLengthSq(Q));
} }
float SHQuaternion::Dot(const SHQuaternion& rhs) const noexcept float SHQuaternion::Dot(const SHQuaternion& rhs) const noexcept
{ {
const XMVECTOR Q1 = XMLoadFloat4(this); return XMVectorGetX(XMQuaternionDot(*this, rhs));
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
return XMVectorGetX(XMQuaternionDot(Q1, Q2));
}
SHQuaternion SHQuaternion::RotateTowards(const SHQuaternion&, float) const noexcept
{
SHQuaternion result;
// TODO (Diren)
return result;
} }
SHVec3 SHQuaternion::ToEuler() const noexcept SHVec3 SHQuaternion::ToEuler() const noexcept
{ {
const float xx = x * x; const float XX = x * x;
const float yy = y * y; const float YY = y * y;
const float zz = z * z; const float ZZ = z * z;
const float m31 = 2.f * x * z + 2.f * y * w; const float M_31 = 2.f * x * z + 2.f * y * w;
const float m32 = 2.f * y * z - 2.f * x * w; const float M_32 = 2.f * y * z - 2.f * x * w;
const float m33 = 1.f - 2.f * xx - 2.f * yy; const float M_33 = 1.f - 2.f * XX - 2.f * YY;
const float cy = sqrtf(m33 * m33 + m31 * m31); const float CY = sqrtf(M_33 * M_33 + M_31 * M_31);
const float cx = atan2f(-m32, cy); const float CX = atan2f(-M_32, CY);
if (cy > 16.0f * SHMath::EPSILON) if (CY > 16.0f * SHMath::EPSILON)
{ {
const float m12 = 2.f * x * y + 2.f * z * w; const float M_12 = 2.f * x * y + 2.f * z * w;
const float m22 = 1.f - 2.f * xx - 2.f * zz; const float M_22 = 1.f - 2.f * XX - 2.f * ZZ;
return SHVec3(cx, atan2f(m31, m33), atan2f(m12, m22)); return SHVec3(CX, atan2f(M_31, M_33), atan2f(M_12, M_22));
} }
else else
{ {
const float m11 = 1.f - 2.f * yy - 2.f * zz; const float m11 = 1.f - 2.f * YY - 2.f * ZZ;
const float m21 = 2.f * x * y - 2.f * z * w; const float m21 = 2.f * x * y - 2.f * z * w;
return SHVec3(cx, 0.f, atan2f(-m21, m11)); return SHVec3(CX, 0.f, atan2f(-m21, m11));
} }
} }
@ -311,13 +251,43 @@ namespace SHADE
/* Static Function Member Definitions */ /* Static Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHQuaternion SHQuaternion::FromEuler(const SHVec3& eulerAngles) noexcept
{
SHQuaternion result;
XMStoreFloat4(&result, XMQuaternionRotationRollPitchYawFromVector(eulerAngles));
return result;
}
SHQuaternion SHQuaternion::FromPitchYawRoll(float pitch, float yaw, float roll) noexcept
{
SHQuaternion result;
XMStoreFloat4(&result, XMQuaternionRotationRollPitchYaw(pitch, yaw, roll));
return result;
}
SHQuaternion SHQuaternion::FromAxisAngle(const SHVec3& axis, float angle) noexcept
{
SHQuaternion result;
XMStoreFloat4(&result, XMQuaternionRotationAxis(axis, angle));
return result;
}
SHQuaternion SHQuaternion::FromRotationMatrix(const SHMatrix& rotationMatrix) noexcept
{
SHQuaternion result;
XMStoreFloat4(&result, XMQuaternionRotationMatrix(rotationMatrix));
return result;
}
SHQuaternion SHQuaternion::Normalise(const SHQuaternion& q) noexcept SHQuaternion SHQuaternion::Normalise(const SHQuaternion& q) noexcept
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q = XMLoadFloat4(&q); XMStoreFloat4(&result, XMQuaternionNormalize(q));
XMStoreFloat4(&result, XMQuaternionNormalize(Q));
return result; return result;
} }
@ -325,9 +295,7 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q = XMLoadFloat4(&q); XMStoreFloat4(&result, XMQuaternionConjugate(q));
XMStoreFloat4(&result, XMQuaternionConjugate(Q));
return result; return result;
} }
@ -335,26 +303,37 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q = XMLoadFloat4(&q); XMStoreFloat4(&result, XMQuaternionInverse(q));
XMStoreFloat4(&result, XMQuaternionInverse(Q));
return result; return result;
} }
float SHQuaternion::Angle(const SHQuaternion&, const SHQuaternion&) noexcept float SHQuaternion::Angle(const SHQuaternion& q1, const SHQuaternion& q2) noexcept
{ {
// TODO (Diren) XMVECTOR R = XMQuaternionMultiply(XMQuaternionConjugate(q1), q2);
return 0.0f; const float RS = XMVectorGetW(R);
R = XMVector3Length(R);
return 2.0f * atan2f(XMVectorGetX(R), RS);
} }
SHQuaternion SHQuaternion::Lerp(const SHQuaternion&, const SHQuaternion&, float) noexcept SHQuaternion SHQuaternion::Lerp(const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept
{ {
SHQuaternion result; SHQuaternion result;
// TODO (Diren) XMVECTOR R = XMVectorZero();
if (XMVector4GreaterOrEqual(XMVector4Dot(q1, q2), R))
{
R = XMVectorLerp(q1, q2, t);
}
else
{
const XMVECTOR X0 = XMVectorMultiply(q1, XMVectorReplicate(1.f - t));
const XMVECTOR X1 = XMVectorMultiply(q2, XMVectorReplicate(t));
R = XMVectorSubtract(X0, X1);
}
XMStoreFloat4(&result, XMQuaternionNormalize(R));
return result; return result;
} }
@ -362,19 +341,105 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q1 = XMLoadFloat4(&q1); XMStoreFloat4(&result, XMQuaternionSlerp(q1, q2, t));
const XMVECTOR Q2 = XMLoadFloat4(&q2);
XMStoreFloat4(&result, XMQuaternionSlerp(Q1, Q2, t));
return result; return result;
} }
SHQuaternion SHQuaternion::Rotate(const SHVec3& , const SHVec3&) noexcept SHQuaternion SHQuaternion::ClampedLerp(const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin, float tMax) noexcept
{
return Lerp(q1, q2, std::clamp(t, tMin, tMax));
}
SHQuaternion SHQuaternion::ClampedSlerp(const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin, float tMax) noexcept
{
return Slerp(q1, q2, std::clamp(t, tMin, tMax));
}
SHQuaternion SHQuaternion::FromToRotation(const SHVec3& from, const SHVec3& to) noexcept
{
// Melax, "The Shortest Arc Quaternion", Game Programming Gems
SHQuaternion result;
const XMVECTOR F = XMVector3Normalize(from);
const XMVECTOR T = XMVector3Normalize(to);
const float dot = XMVectorGetX(XMVector3Dot(F, T));
if (dot >= 1.f)
{
result = Identity;
}
else if (dot <= -1.f)
{
XMVECTOR axis = XMVector3Cross(F, SHVec3::Right);
if (XMVector3NearEqual(XMVector3LengthSq(axis), g_XMZero, g_XMEpsilon))
{
axis = XMVector3Cross(F, SHVec3::Up);
}
const XMVECTOR Q = XMQuaternionRotationAxis(axis, XM_PI);
XMStoreFloat4(&result, Q);
}
else
{
const XMVECTOR C = XMVector3Cross(F, T);
XMStoreFloat4(&result, C);
const float s = sqrtf((1.f + dot) * 2.f);
result.x /= s;
result.y /= s;
result.z /= s;
result.w = s * 0.5f;
}
return result;
}
SHQuaternion SHQuaternion::LookRotation(const SHVec3& forward, const SHVec3& up) noexcept
{ {
SHQuaternion result; SHQuaternion result;
// TODO (Diren) const SHQuaternion Q1 = FromToRotation(SHVec3::Forward, forward);
const XMVECTOR C = XMVector3Cross(forward, up);
if (XMVector3NearEqual(XMVector3LengthSq(C), g_XMZero, g_XMEpsilon))
{
// forward and up are co-linear
return Q1;
}
SHVec3 qU;
XMStoreFloat3(&qU, XMQuaternionMultiply(Q1, SHVec3::Up));
const SHQuaternion Q2 = FromToRotation(qU, up);
XMStoreFloat4(&result, XMQuaternionMultiply(Q2, Q1));
return result;
}
SHQuaternion SHQuaternion::RotateTowards(const SHQuaternion& from, const SHQuaternion& to, float maxAngleInRad) noexcept
{
SHQuaternion result;
// We can use the conjugate here instead of inverse assuming q1 & q2 are normalized.
const XMVECTOR R = XMQuaternionMultiply(XMQuaternionConjugate(from), to);
const float RS = XMVectorGetW(R);
const XMVECTOR L = XMVector3Length(R);
const float angle = 2.f * atan2f(XMVectorGetX(L), RS);
if (angle > maxAngleInRad)
{
const XMVECTOR delta = XMQuaternionRotationAxis(R, maxAngleInRad);
const XMVECTOR Q = XMQuaternionMultiply(delta, from);
XMStoreFloat4(&result, Q);
}
else
{
// Don't overshoot.
result = to;
}
return result; return result;
} }

View File

@ -49,11 +49,8 @@ namespace SHADE
SHQuaternion (SHQuaternion&& rhs) = default; SHQuaternion (SHQuaternion&& rhs) = default;
SHQuaternion () noexcept; SHQuaternion () noexcept;
SHQuaternion (const SHVec4& vec4) noexcept;
SHQuaternion (float x, float y, float z, float w) noexcept; SHQuaternion (float x, float y, float z, float w) noexcept;
SHQuaternion (float yaw, float pitch, float roll) noexcept;
SHQuaternion (const SHVec3& eulerAngles) noexcept;
SHQuaternion (const SHVec3& axis, float angleInRad) noexcept;
SHQuaternion (const SHMatrix& rotationMatrix) noexcept;
// Conversion from other math types // Conversion from other math types
@ -87,6 +84,7 @@ namespace SHADE
operator reactphysics3d::Quaternion () const noexcept; operator reactphysics3d::Quaternion () const noexcept;
operator reactphysics3d::Vector3 () const noexcept; operator reactphysics3d::Vector3 () const noexcept;
operator DirectX::XMVECTOR () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */
@ -99,29 +97,37 @@ namespace SHADE
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void Invert () noexcept; void Invert () noexcept;
[[nodiscard]] float Length () const noexcept; [[nodiscard]] float Length () const noexcept;
[[nodiscard]] float LengthSquared () const noexcept; [[nodiscard]] float LengthSquared () const noexcept;
[[nodiscard]] float Dot (const SHQuaternion& rhs) const noexcept; [[nodiscard]] float Dot (const SHQuaternion& rhs) const noexcept;
[[nodiscard]] SHQuaternion RotateTowards (const SHQuaternion& target, float maxAngleInRad) const noexcept;
[[nodiscard]] SHVec3 ToEuler () const noexcept; [[nodiscard]] SHVec3 ToEuler () const noexcept;
[[nodiscard]] std::string ToString () const noexcept; [[nodiscard]] std::string ToString () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Static Function Members */ /* Static Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] static SHQuaternion Normalise (const SHQuaternion& q) noexcept; [[nodiscard]] static SHQuaternion FromEuler (const SHVec3& eulerAngles) noexcept;
[[nodiscard]] static SHQuaternion Conjugate (const SHQuaternion& q) noexcept; [[nodiscard]] static SHQuaternion FromPitchYawRoll (float pitch, float yaw, float roll) noexcept;
[[nodiscard]] static SHQuaternion Inverse (const SHQuaternion& q) noexcept; [[nodiscard]] static SHQuaternion FromAxisAngle (const SHVec3& axis, float angle) noexcept;
[[nodiscard]] static float Angle (const SHQuaternion& q1, const SHQuaternion& q2) noexcept; [[nodiscard]] static SHQuaternion FromRotationMatrix(const SHMatrix& rotationMatrix) noexcept;
[[nodiscard]] static SHQuaternion Lerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept; [[nodiscard]] static SHQuaternion Normalise (const SHQuaternion& q) noexcept;
[[nodiscard]] static SHQuaternion Slerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept; [[nodiscard]] static SHQuaternion Conjugate (const SHQuaternion& q) noexcept;
[[nodiscard]] static SHQuaternion Inverse (const SHQuaternion& q) noexcept;
[[nodiscard]] static float Angle (const SHQuaternion& q1, const SHQuaternion& q2) noexcept;
[[nodiscard]] static SHQuaternion Rotate (const SHVec3& from, const SHVec3& to) noexcept; [[nodiscard]] static SHQuaternion Lerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept;
[[nodiscard]] static SHQuaternion Slerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept;
[[nodiscard]] static SHQuaternion ClampedLerp (const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept;
[[nodiscard]] static SHQuaternion ClampedSlerp (const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept;
[[nodiscard]] static SHQuaternion FromToRotation (const SHVec3& from, const SHVec3& to) noexcept;
[[nodiscard]] static SHQuaternion LookRotation (const SHVec3& forward, const SHVec3& up) noexcept;
[[nodiscard]] static SHQuaternion RotateTowards (const SHQuaternion& from, const SHQuaternion& to, float maxAngleInRad) noexcept;
}; };
SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept; SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept;

Some files were not shown because too many files have changed in this diff Show More