SP3-2 Cleaned Up Physics System #85

Merged
direnbharwani merged 11 commits from SP3-2-Physics into main 2022-10-13 18:32:25 +08:00
185 changed files with 8960 additions and 1977 deletions
Showing only changes of commit 5b4838c5b9 - Show all commits

BIN
Assets/Audio/Master.bank Normal file

Binary file not shown.

Binary file not shown.

BIN
Assets/Audio/footsteps.bank Normal file

Binary file not shown.

BIN
Assets/Cube.003.shmesh Normal file

Binary file not shown.

BIN
Assets/Cube.012.shmesh Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -19,10 +19,11 @@ echo "L - yamlcpp"
echo "M - SDL"
echo "N - dotnet"
echo "O - tinyddsloader"
echo "P - fmod"
echo ---------------------------------------------------
echo.
choice /C ABCDEFGHIJKLMNO /T 10 /D A
choice /C ABCDEFGHIJKLMNOP /T 10 /D A
set _e=%ERRORLEVEL%
if %_e%==1 goto VMA
@ -40,6 +41,7 @@ if %_e%==12 goto yamlcpp
if %_e%==13 goto SDL
if %_e%==14 goto dotnet
if %_e%==15 goto tinyddsloader
if %_e%==16 goto fmod
:VMA
echo -----------------------VMA----------------------------
@ -145,6 +147,12 @@ if %_e%==14 (goto :done) else (goto :tinyddsloader)
echo --------------------tinyddsloader-------------------------
rmdir "Dependencies/tinyddsloader" /S /Q
git clone https://github.com/SHADE-DP/tinyddsloader.git "Dependencies/tinyddsloader"
if %_e%==15 (goto :done) else (goto :fmod)
:fmod
echo --------------------fmod-------------------------
rmdir "Dependencies/fmod" /S /Q
git clone https://github.com/SHADE-DP/FMOD.git "Dependencies/fmod"
:done
echo DONE!

View File

@ -15,3 +15,4 @@ IncludeDir["SDL"] = "%{wks.location}\\Dependencies\\SDL"
IncludeDir["VULKAN"] = "$(VULKAN_SDK)"
IncludeDir["dotnet"] = "%{wks.location}\\Dependencies\\dotnet"
IncludeDir["tinyddsloader"] = "%{wks.location}\\Dependencies\\tinyddsloader"
IncludeDir["fmod"] = "%{wks.location}\\Dependencies\\fmod"

View File

@ -30,12 +30,14 @@ project "SHADE_Application"
externalincludedirs
{
"%{IncludeDir.spdlog}/include",
"%{IncludeDir.VULKAN}/include",
"%{IncludeDir.VMA}/include",
"%{IncludeDir.VULKAN}/Source/SPIRV-Reflect",
"%{IncludeDir.RTTR}/include",
"%{IncludeDir.tinyddsloader}"
"%{IncludeDir.RTTR}\\include",
"%{IncludeDir.fmod}/include",
"%{IncludeDir.VULKAN}/Source/SPIRV-Reflect",
"%{IncludeDir.VMA}/include",
"%{IncludeDir.VULKAN}/include",
"%{IncludeDir.spdlog}/include",
"%{IncludeDir.tinyddsloader}",
"%{IncludeDir.reactphysics3d}\\include"
}
externalwarnings "Off"
@ -56,7 +58,7 @@ project "SHADE_Application"
libdirs
{
"%{IncludeDir.spdlog}/lib",
"%{IncludeDir.SDL}/lib",
"%{IncludeDir.SDL}/lib"
}
defines
@ -66,9 +68,16 @@ project "SHADE_Application"
disablewarnings
{
"4251"
"4251",
"26812",
"26439",
"26451",
"26437",
"4275"
}
linkoptions { "-IGNORE:4006" }
warnings 'Extra'
filter "configurations:Debug"
@ -81,4 +90,4 @@ project "SHADE_Application"
filter "configurations:Publish"
optimize "On"
defines{"_RELEASE"}
defines{"_RELEASE", "_PUBLISH"}

View File

@ -14,22 +14,34 @@
#include <chrono>
#include <ratio>
#include <ctime>
#define SDL_HINT_VIDEO_FOREIGN_WINDOW_VULKAN 1
#include <SDL.h>
#include "Scripting/SHScriptEngine.h"
#include "Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Scene/SHSceneManager.h"
#include "Math/Transform/SHTransformSystem.h"
#include "Input/SHInputManagerSystem.h"
#include "Scenes/SBTestScene.h"
#include "Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h"
// Managers
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Scene/SHSceneManager.h"
// Systems
#include "Scripting/SHScriptEngine.h"
#include "Physics/SHPhysicsSystem.h"
#include "Math/Transform/SHTransformSystem.h"
#include "Input/SHInputManager.h"
#include "FRC/SHFramerateController.h"
#include "AudioSystem/SHAudioSystem.h"
// Components
#include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Scenes/SBTestScene.h"
#include "Assets/SHAssetManager.h"
#include "Tools/SHLogger.h"
using namespace SHADE;
namespace Sandbox
@ -51,10 +63,10 @@ namespace Sandbox
// Create Systems
SHADE::SHSystemManager::CreateSystem<SHADE::SHGraphicsSystem>();
SHADE::SHSystemManager::CreateSystem<SHADE::SHScriptEngine>();
// TODO(Diren): Create Physics System here
SHADE::SHSystemManager::CreateSystem<SHADE::SHPhysicsSystem>();
SHADE::SHSystemManager::CreateSystem<SHADE::SHTransformSystem>();
SHADE::SHGraphicsSystem* graphicsSystem = static_cast<SHADE::SHGraphicsSystem*>(SHADE::SHSystemManager::GetSystem<SHADE::SHGraphicsSystem>());
SHADE::SHSystemManager::CreateSystem<SHADE::SHInputManagerSystem>();
SHADE::SHSystemManager::CreateSystem<SHADE::SHAudioSystem>();
// Create Routines
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHScriptEngine, SHADE::SHScriptEngine::FrameSetUpRoutine>();
@ -62,27 +74,37 @@ namespace Sandbox
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHScriptEngine, SHADE::SHScriptEngine::LateUpdateRoutine>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHScriptEngine, SHADE::SHScriptEngine::FrameCleanUpRoutine>();
// TODO(Diren): Register Physics System & Routines here
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHPhysicsSystem, SHADE::SHPhysicsSystem::PhysicsPreUpdate>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHPhysicsSystem, SHADE::SHPhysicsSystem::PhysicsFixedUpdate>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHPhysicsSystem, SHADE::SHPhysicsSystem::PhysicsPostUpdate>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHTransformSystem, SHADE::SHTransformSystem::TransformUpdateRoutine>();
SHADE::SHComponentManager::CreateComponentSparseSet<SHADE::SHTransformComponent>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHGraphicsSystem, SHADE::SHGraphicsSystem::BatcherDispatcherRoutine>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHGraphicsSystem, SHADE::SHGraphicsSystem::BeginRoutine>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHGraphicsSystem, SHADE::SHGraphicsSystem::RenderRoutine>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHGraphicsSystem, SHADE::SHGraphicsSystem::EndRoutine>();
SHADE::SHComponentManager::CreateComponentSparseSet<SHADE::SHRenderable>();
SHADE::SHComponentManager::CreateComponentSparseSet<SHADE::SHRigidBodyComponent>();
SHADE::SHComponentManager::CreateComponentSparseSet<SHADE::SHColliderComponent>();
SHADE::SHComponentManager::CreateComponentSparseSet<SHADE::SHTransformComponent>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHInputManagerSystem, SHADE::SHInputManagerSystem::InputManagerRoutine>();
SHADE::SHComponentManager::CreateComponentSparseSet<SHADE::SHRenderable>();
//TODO: REMOVE AFTER PRESENTATION
SHADE::SHAssetManager::LoadDataTemp("../../Assets/racoon.gltf");
SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonBag_Color_Ver4.dds");
SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.dds");
//SHADE::SHAssetManager::LoadDataTemp("../../Assets/racoon.gltf");
SHADE::SHAssetManager::LoadDataTemp("../../Assets/Cube.012.shmesh");
//SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonBag_Color_Ver4.dds");
//SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.dds");
SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.shtex");
//TODO: REMOVE AFTER PRESENTATION
auto id = SHFamilyID<SHSystem>::GetID<SHGraphicsSystem>();
auto id2 = SHFamilyID<SHSystem>::GetID<SHGraphicsSystem>();
auto id3 = SHFamilyID<SHSystem>::GetID<SHGraphicsSystem>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHAudioSystem, SHADE::SHAudioSystem::AudioRoutine>();
// Set up graphics system and windows
graphicsSystem->SetWindow(&window);
@ -94,7 +116,10 @@ namespace Sandbox
#else
#endif
SHSceneManager::InitSceneManager<SBTestScene>("TestScene");
SHFrameRateController::UpdateFRC();
}
void SBApplication::Update(void)
@ -103,6 +128,8 @@ namespace Sandbox
//TODO: Change true to window is open
while (!window.WindowShouldClose())
{
SHFrameRateController::UpdateFRC();
SHInputManager::UpdateInput(SHFrameRateController::GetRawDeltaTime());
SHSceneManager::UpdateSceneManager();
SHSceneManager::SceneUpdate(1/60.0f);
//#ifdef SHEDITOR
@ -118,6 +145,9 @@ namespace Sandbox
SHADE::SHSystemManager::RunRoutines(false, 0.016f);
}
// Finish all graphics jobs first
graphicsSystem->AwaitGraphicsExecution();
}

View File

@ -9,6 +9,9 @@
#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h"
#include "Scripting/SHScriptEngine.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Physics/Components/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h"
#include "Assets/SHAssetManager.h"
@ -17,9 +20,9 @@ using namespace SHADE;
namespace Sandbox
{
void SBTestScene::WindowFocusFunc([[maybe_unused]]void* window, int focused)
void SBTestScene::WindowFocusFunc([[maybe_unused]] void* window, int focused)
{
if(focused)
if (focused)
{
}
else
@ -35,99 +38,156 @@ namespace Sandbox
SHADE::SHGraphicsSystem* graphicsSystem = static_cast<SHADE::SHGraphicsSystem*>(SHADE::SHSystemManager::GetSystem<SHADE::SHGraphicsSystem>());
// Create temp meshes
const auto CUBE_MESH = SHADE::SHPrimitiveGenerator::Cube(*graphicsSystem);
//graphicsSystem->BuildMeshBuffers();
//Test Racoon mesh
auto meshes = SHADE::SHAssetManager::GetAllMeshes();
std::vector<Handle<SHMesh>> handles;
for (auto const& mesh : meshes)
{
if (mesh.meshName == "Cube.012")
if (mesh.header.meshName == "Cube.012")
{
handles.push_back(graphicsSystem->AddMesh(
mesh.header.vertexCount,
mesh.vertexPosition.data(),
mesh.texCoords.data(),
mesh.vertexTangent.data(),
mesh.vertexNormal.data(),
mesh.header.indexCount,
mesh.indices.data()
));
handles.push_back(graphicsSystem->AddMesh(
mesh.header.vertexCount,
mesh.vertexPosition.data(),
mesh.texCoords.data(),
mesh.vertexTangent.data(),
mesh.vertexNormal.data(),
mesh.header.indexCount,
mesh.indices.data()
));
}
}
graphicsSystem->BuildMeshBuffers();
//Test Textures
auto textures{ SHADE::SHAssetManager::GetAllTextures() };
// Load Textures
auto textures = SHADE::SHAssetManager::GetAllTextures();
std::vector<Handle<SHTexture>> texHandles;
for (const auto& tex : textures)
{
auto texture = graphicsSystem->Add(tex);
texHandles.push_back(texture);
}
graphicsSystem->BuildTextures();
// Create Materials
auto matInst = graphicsSystem->AddOrGetBaseMaterialInstance();
auto customMat = graphicsSystem->AddMaterialInstanceCopy(matInst);
customMat->SetProperty("data.color", SHVec4(0.0f, 1.0f, 1.0f, 1.0f));
customMat->SetProperty("data.textureIndex", 0);
customMat->SetProperty("data.alpha", 0.1f);
// Create Stress Test Objects
static const SHVec3 TEST_OBJ_SCALE = { 0.2f, 0.2f, 0.2f };
constexpr int NUM_ROWS = 1;
constexpr int NUM_COLS = 1;
static const SHVec3 TEST_OBJ_SPACING = { 1.0f, 1.0f, 1.0f };
static const SHVec3 TEST_OBJ_START_POS = { - (NUM_COLS / 2 * TEST_OBJ_SPACING.x ), 0.0f, 0.0f };
//for (int z = 0; z < NUM_ROWS; ++z)
//for (int x = 0; x < NUM_COLS; ++x)
//{
// auto entity = SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>();
// auto& renderable = *SHComponentManager::GetComponent_s<SHRenderable>(entity);
// auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(entity);
static const SHVec3 TEST_OBJ_SCALE = SHVec3::One * 0.5f;
constexpr int NUM_ROWS = 10;
constexpr int NUM_COLS = 10;
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 };
// renderable.Mesh = handles.front();
// renderable.SetMaterial(matInst);
// // Set initial positions
// transform.SetWorldPosition(TEST_OBJ_START_POS + SHVec3{ x * TEST_OBJ_SPACING.x, 0.0f, z * TEST_OBJ_SPACING.z });
// //transform.SetLocalScale(TEST_OBJ_SCALE);
// stressTestObjects.emplace_back(entity);
//}
auto entity = SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>();
for (int y = 0; y < NUM_ROWS; ++y)
for (int x = 0; x < NUM_COLS; ++x)
{
auto entity = SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent, SHRigidBodyComponent, SHColliderComponent>();
auto& renderable = *SHComponentManager::GetComponent_s<SHRenderable>(entity);
auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(entity);
auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(entity);
auto& collider = *SHComponentManager::GetComponent_s<SHColliderComponent>(entity);
renderable.Mesh = handles.front();
renderable.SetMaterial(matInst);
//renderable.Mesh = handles.front();
renderable.Mesh = CUBE_MESH;
renderable.SetMaterial(customMat);
//transform.SetLocalScale(TEST_OBJ_SCALE);
if (y == 50)
renderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(1.0f, 0.0f, 0.0f, 1.0f));
//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({-1.0f, -1.0f, -1.0f});
transform.SetWorldRotation(SHMath::GenerateRandomNumber(), SHMath::GenerateRandomNumber(), SHMath::GenerateRandomNumber());
transform.SetWorldScale(TEST_OBJ_SCALE);
auto* box = collider.AddBoundingBox();
box->SetHalfExtents(transform.GetWorldScale() * 0.5f);
stressTestObjects.emplace_back(entity);
}
auto raccoonSpin = SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>();
auto& renderable = *SHComponentManager::GetComponent_s<SHRenderable>(raccoonSpin);
auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(raccoonSpin);
renderable.Mesh = handles.front();
renderable.SetMaterial(customMat);
renderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f));
renderable.GetModifiableMaterial()->SetProperty("data.alpha", 1.0f);
renderable.GetModifiableMaterial()->SetProperty("data.textureIndex", 0);
transform.SetWorldPosition({ -3.0f, -1.0f, -1.0f });
transform.SetLocalScale({ 5.0f, 5.0f, 5.0f });
auto floor = SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent, SHRigidBodyComponent, SHColliderComponent>();
auto& floorRenderable = *SHComponentManager::GetComponent_s<SHRenderable>(floor);
auto& floorTransform = *SHComponentManager::GetComponent_s<SHTransformComponent>(floor);
auto& floorRigidBody = *SHComponentManager::GetComponent_s<SHRigidBodyComponent>(floor);
auto& floorCollider = *SHComponentManager::GetComponent_s<SHColliderComponent>(floor);
floorRenderable.Mesh = CUBE_MESH;
floorRenderable.SetMaterial(customMat);
floorRenderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(1.0f, 1.0f, 1.0f, 1.0f));
floorTransform.SetWorldScale({7.5f, 0.5f, 7.5});
floorTransform.SetWorldPosition({0.0f, -3.0f, -5.0f});
floorRigidBody.SetType(SHRigidBodyComponent::Type::STATIC);
auto* floorBox = floorCollider.AddBoundingBox();
floorBox->SetHalfExtents(floorTransform.GetWorldScale() * 0.5f);
// Create blank entity with a script
testObj = SHADE::SHEntityManager::CreateEntity();
//testObj = SHADE::SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>();
//auto& testObjRenderable = *SHComponentManager::GetComponent<SHRenderable>(testObj);
//testObjRenderable.Mesh = CUBE_MESH;
//testObjRenderable.SetMaterial(matInst);
SHADE::SHScriptEngine* scriptEngine = static_cast<SHADE::SHScriptEngine*>(SHADE::SHSystemManager::GetSystem<SHADE::SHScriptEngine>());
scriptEngine->AddScript(testObj, "TestScript");
scriptEngine->AddScript(raccoonSpin, "RaccoonSpin");
auto raccoonShowcase = SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>();
auto& renderableShowcase = *SHComponentManager::GetComponent_s<SHRenderable>(raccoonShowcase);
auto& transformShowcase = *SHComponentManager::GetComponent_s<SHTransformComponent>(raccoonShowcase);
renderableShowcase.Mesh = handles.front();
renderableShowcase.SetMaterial(customMat);
renderableShowcase.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f));
renderableShowcase.GetModifiableMaterial()->SetProperty("data.alpha", 1.0f);
renderableShowcase.GetModifiableMaterial()->SetProperty("data.textureIndex", 0);
transformShowcase.SetWorldPosition({ 3.0f, -1.0f, -1.0f });
transformShowcase.SetLocalScale({ 5.0f, 5.0f, 5.0f });
scriptEngine->AddScript(raccoonShowcase, "RaccoonShowcase");
}
void SBTestScene::Update(float dt)
{
/*static float rotation = 0.0f;
static float rotation = 0.0f;
auto& transform = *SHADE::SHComponentManager::GetComponent_s<SHADE::SHTransformComponent>(testObj);
//auto& transform = *SHADE::SHComponentManager::GetComponent_s<SHADE::SHTransformComponent>(testObj);
transform.SetLocalRotation(rotation, 0.0f, 0.0f);
rotation += dt * 10.0f;*/
/*static float rotation = 0.0f;
auto& transform = *SHADE::SHComponentManager::GetComponent_s<SHADE::SHTransformComponent>(stressTestObjects[0]);
transform.SetWorldPosition({rotation, 0.0f, 0.0f});
rotation += dt * 10.0f;*/
//transform.SetWorldPosition({1.0f, 1.0f, -1.0f});
//transform.SetWorldRotation(0.0f, 0.0f + rotation, 0.0f);
//rotation += dt * 0.2f;
// Destroy entity if space is pressed
if (GetKeyState(VK_SPACE) & 0x8000)
{
SHADE::SHScriptEngine* scriptEngine = static_cast<SHADE::SHScriptEngine*>(SHADE::SHSystemManager::GetSystem<SHADE::SHScriptEngine>());
scriptEngine->RemoveAllScripts(testObj);
rotation = 0.0f;
SHADE::SHScriptEngine* scriptEngine = static_cast<SHADE::SHScriptEngine*>(SHADE::SHSystemManager::GetSystem<SHADE::SHScriptEngine>());
scriptEngine->RemoveAllScripts(testObj);
}
}
void SBTestScene::Render()
{
}
void SBTestScene::Unload()
@ -138,8 +198,4 @@ namespace Sandbox
{
//SHSerialization::SerializeScene("resources/scenes/Scene01.SHADE");
}
}

View File

@ -42,7 +42,8 @@ project "SHADE_Engine"
"%{IncludeDir.VULKAN}\\include",
"%{IncludeDir.VULKAN}\\Source\\SPIRV-Reflect",
"%{IncludeDir.dotnet}\\include",
"%{IncludeDir.tinyddsloader}"
"%{IncludeDir.tinyddsloader}",
"%{IncludeDir.fmod}\\include"
}
externalwarnings "Off"
@ -55,7 +56,8 @@ project "SHADE_Engine"
"%{IncludeDir.assimp}/lib/Release",
"%{IncludeDir.RTTR}/lib",
"%{IncludeDir.SDL}/lib",
"%{IncludeDir.spdlog}/lib"
"%{IncludeDir.spdlog}/lib",
"%{IncludeDir.fmod}/lib"
}
links
@ -74,9 +76,16 @@ project "SHADE_Engine"
disablewarnings
{
"4251"
"4251",
"26812",
"26439",
"26451",
"26437",
"4275"
}
linkoptions { "-IGNORE:4006" }
defines
{
"_LIB",
@ -108,9 +117,30 @@ project "SHADE_Engine"
}
filter "configurations:Debug"
postbuildcommands {"xcopy /r /y /q \"%{IncludeDir.assimp}\\bin\\Debug\\assimp-vc142-mtd.dll\" \"$(OutDir)\""}
postbuildcommands
{
"xcopy /r /y /q \"%{IncludeDir.assimp}\\bin\\Debug\\assimp-vc142-mtd.dll\" \"$(OutDir)\"",
"xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmodL.dll\" \"$(OutDir)\"",
"xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmodstudioL.dll\" \"$(OutDir)\""
}
filter "configurations:Release"
postbuildcommands
{
"xcopy /r /y /q \"%{IncludeDir.assimp}\\bin\\Release\\assimp-vc142-mt.dll\" \"$(OutDir)\"",
"xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmod.dll\" \"$(OutDir)\"",
"xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmodstudio.dll\" \"$(OutDir)\""
}
filter "configurations:Publish"
postbuildcommands
{
"xcopy /r /y /q \"%{IncludeDir.assimp}\\bin\\Release\\assimp-vc142-mt.dll\" \"$(OutDir)\"",
"xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmod.dll\" \"$(OutDir)\"",
"xcopy /r /y /q \"%{IncludeDir.fmod}\\lib\\fmodstudio.dll\" \"$(OutDir)\""
}
filter "configurations:Publish"
postbuildcommands {"xcopy /r /y /q \"%{IncludeDir.assimp}\\bin\\Release\\assimp-vc142-mt.dll\" \"$(OutDir)\""}
warnings 'Extra'
@ -119,22 +149,22 @@ project "SHADE_Engine"
symbols "On"
defines {"_DEBUG", "SHEDITOR"}
links{"assimp-vc142-mtd.lib", "librttr_core_d.lib", "spdlogd.lib"}
--links{"fmodstudioL_vc.lib", "fmodL_vc.lib"}
links{"fmodstudioL_vc.lib", "fmodL_vc.lib"}
filter "configurations:Release"
optimize "On"
defines{"_RELEASE", "SHEDITOR"}
links{"assimp-vc142-mt.lib", "librttr_core.lib", "spdlog.lib"}
--links{"fmodstudio_vc.lib", "fmod_vc.lib"}
links{"fmodstudio_vc.lib", "fmod_vc.lib"}
filter "configurations:Publish"
optimize "On"
defines{"_RELEASE"}
defines{"_RELEASE", "_PUBLISH"}
links{"assimp-vc142-mt.lib", "librttr_core.lib", "spdlog.lib"}
excludes
{
"%{prj.location}/src/Editor/**.cpp",
"%{prj.location}/src/Editor/**.h",
"%{prj.location}/src/Editor/**.hpp",
-- "%{prj.location}/src/Editor/**.cpp",
-- "%{prj.location}/src/Editor/**.h",
-- "%{prj.location}/src/Editor/**.hpp",
}
--links{"fmodstudio_vc.lib", "fmod_vc.lib"}
links{"fmodstudio_vc.lib", "fmod_vc.lib"}

View File

@ -1,25 +1,37 @@
/*************************************************************************//**
* \file SHMeshAsset.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Struct to contain ready data for loading into GPU. Also used for
* compilation into binary files
*
*
* 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 "Math/SHMath.h"
#include "SH_API.h"
namespace SHADE
{
struct SHMeshAssetHeader
struct SH_API SHMeshAssetHeader
{
uint32_t vertexCount;
uint32_t indexCount;
std::string meshName;
};
struct SHMeshAsset
struct SH_API SHMeshAsset
{
bool compiled;
bool changed;
SHMeshAssetHeader header;
std::string meshName;
std::vector<SHVec3> vertexPosition;
std::vector<SHVec3> vertexTangent;
std::vector<SHVec3> vertexNormal;

View File

@ -1,15 +1,14 @@
#pragma once
#include "tinyddsloader.h"
#include "Graphics/MiddleEnd/Textures/SHTextureLibrary.h"
#include <memory>
namespace SHADE
{
struct SHTextureAsset
{
bool compiled;
uint32_t numBytes;
uint32_t width;
uint32_t height;
@ -18,7 +17,8 @@ namespace SHADE
SHTexture::PixelChannel const * pixelData;
SHTextureAsset()
: numBytes{ 0 },
: compiled{ false },
numBytes{ 0 },
width{ 0 },
height{ 0 },
format{ SHTexture::TextureFormat::eUndefined },
@ -26,7 +26,8 @@ namespace SHADE
{}
SHTextureAsset(SHTextureAsset const& rhs)
: numBytes{ rhs.numBytes },
: compiled{ false },
numBytes{ rhs.numBytes },
width{ rhs.width },
height{ rhs.height },
format{ rhs.format },

View File

@ -0,0 +1,70 @@
/*************************************************************************//**
* \file SHMeshCompiler.cpp
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to write data in SHMeshAsset into binary file for faster
* loading in the future
*
*
* 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 "SHMeshCompiler.h"
#include "Graphics/MiddleEnd/Meshes/SHMeshData.h"
#include <fstream>
void SHADE::SHMeshCompiler::CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept
{
std::string newPath{ path.string() };
newPath = newPath.substr(0, newPath.find_last_of('/') + 1);
newPath += asset.header.meshName + MESH_EXTENSION;
std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open file for writing mesh file: {}", path.string());
}
file.write(
reinterpret_cast<char const*>(&(asset.header.vertexCount)),
sizeof(uint32_t)
);
file.write(
reinterpret_cast<const char*>(&(asset.header.indexCount)),
sizeof(uint32_t)
);
auto const vertexVec3Byte {sizeof(SHVec3) * asset.header.vertexCount};
auto const vertexVec2Byte {sizeof(SHVec2) * asset.header.vertexCount};
file.write(
reinterpret_cast<char const*>(asset.vertexPosition.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexTangent.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexNormal.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.texCoords.data()),
vertexVec2Byte
);
file.write(
reinterpret_cast<char const*>(asset.indices.data()),
sizeof(uint32_t) * asset.header.indexCount
);
file.close();
}

View File

@ -0,0 +1,26 @@
/*************************************************************************//**
* \file SHMeshCompiler.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to write data in SHMeshAsset into binary file for faster
* loading in the future
*
*
* 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 "../Asset Types/SHMeshAsset.h"
#include "../SHAssetMacros.h"
namespace SHADE
{
class SHMeshCompiler
{
private:
public:
static void CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept;
};
}

View File

@ -1,12 +1,25 @@
/*************************************************************************//**
* \file SHMeshLoader.cpp
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Implementation for Mesh loader. Accounts for custom binary format
* as well as GLTF file format.
*
*
* 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 "SHMeshLoader.h"
#include <assimp/postprocess.h>
#include <fstream>
namespace SHADE
{
Assimp::Importer SHMeshLoader::aiImporter;
void SHMeshLoader::ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes)
void SHMeshLoader::ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes) noexcept
{
for (size_t i {0}; i < node.mNumMeshes; ++i)
{
@ -20,15 +33,14 @@ namespace SHADE
}
}
SHMeshAsset SHMeshLoader::ProcessMesh(aiMesh const& mesh, aiScene const& scene)
SHMeshAsset SHMeshLoader::ProcessMesh(aiMesh const& mesh, aiScene const& scene) noexcept
{
(void)scene;
SHMeshAsset result
{
.compiled { false},
.changed { false },
.meshName { mesh.mName.C_Str() }
.changed { false }
};
for (size_t i{0}; i < mesh.mNumVertices; ++i)
@ -79,36 +91,33 @@ namespace SHADE
}
}
result.header.vertexCount = result.vertexPosition.size();
result.header.indexCount = result.indices.size();
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;
}
bool SHMeshLoader::LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path)
{
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
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 false;
return;
}
//TODO MATERIALS FROM MESHES
//if (scene->HasMaterials())
//{
@ -116,14 +125,108 @@ namespace SHADE
// {
// if (scene->mMaterials[i]->mNumProperties > 0)
// {
// for (int j{0}; j < scene->mMaterials[i]->mProperties[j].)
// for (int j{0}; j < scene->mMaterials[i]->mProperties[j].)
// }
//std::cout << scene->mMaterials[i]->;
//std::cout << scene->mMaterials[i]->;
// }
//}
ProcessNode(*scene->mRootNode, *scene, meshes);
}
return true;
void SHMeshLoader::LoadSHMesh(SHMeshAsset& mesh, AssetPath path) noexcept
{
std::ifstream file{ path.string(), std::ios::in | std::ios::binary };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open SHMesh File: {}", path.string());
}
std::string name{ path.filename().string() };
name = name.substr(0, name.find_last_of('.'));
file.seekg(0);
uint32_t vertCount, indexCount;
std::vector<SHVec3> vertPos, vertTan, vertNorm;
std::vector<SHVec2> texCoord;
std::vector<uint32_t> indices;
file.read(reinterpret_cast<char*>(&vertCount), sizeof(uint32_t));
file.read(reinterpret_cast<char*>(&indexCount), sizeof(uint32_t));
auto const vertexVec3Byte{ sizeof(SHVec3) * vertCount };
auto const vertexVec2Byte{ sizeof(SHVec2) * vertCount };
vertPos.resize(vertCount);
vertTan.resize(vertCount);
vertNorm.resize(vertCount);
texCoord.resize(vertCount);
indices.resize(indexCount);
file.read(reinterpret_cast<char *>(vertPos.data()), vertexVec3Byte);
file.read(reinterpret_cast<char *>(vertTan.data()), vertexVec3Byte);
file.read(reinterpret_cast<char *>(vertNorm.data()), vertexVec3Byte);
file.read(reinterpret_cast<char *>(texCoord.data()), vertexVec2Byte);
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.changed = false;
mesh.header.indexCount = indexCount;
mesh.header.vertexCount = vertCount;
mesh.header.meshName = name;
mesh.vertexPosition = std::move(vertPos);
mesh.vertexTangent = std::move(vertTan);
mesh.vertexNormal = std::move(vertNorm);
mesh.texCoords = std::move(texCoord);
mesh.indices = std::move(indices);
file.close();
}
void SHMeshLoader::LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept
{
if (path.extension().string() == GLTF_EXTENSION)
{
LoadExternal(meshes, path);
return;
}
meshes.emplace_back();
LoadSHMesh(meshes.back(), path);
}
}

View File

@ -1,3 +1,14 @@
/*************************************************************************//**
* \file SHMeshLoader.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to load gltf mesh files and custom binary format
*
*
* 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>
@ -12,10 +23,14 @@ namespace SHADE
private:
static Assimp::Importer aiImporter;
static void ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes);
static void ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes) noexcept;
static SHMeshAsset ProcessMesh(aiMesh const& mesh, aiScene const& scene);
static SHMeshAsset ProcessMesh(aiMesh const& mesh, aiScene const& scene) noexcept;
static void LoadExternal(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept;
static void LoadSHMesh(SHMeshAsset& meshes, AssetPath path) noexcept;
public:
static bool LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path);
static void LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept;
};
}

View File

@ -1,48 +0,0 @@
#include "SHpch.h"
#include "SHMeshWriter.h"
#include <fstream>
void SHADE::SHMeshWriter::WriteMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept
{
std::ofstream file{path, std::ios::out | std::ios::binary};
if (!file.is_open())
{
SHLOG_ERROR("Unable to open file for writing mesh file: {}", path.string());
}
file.write(
reinterpret_cast<char const*>(&(asset.header.vertexCount)),
sizeof(uint32_t)
);
file.write(
reinterpret_cast<const char*>(&(asset.header.indexCount)),
sizeof(uint32_t)
);
auto const vertexVec3Byte {sizeof(SHVec3) * asset.header.vertexCount};
auto const vertexVec2Byte {sizeof(SHVec2) * asset.header.vertexCount};
file.write(
reinterpret_cast<char const*>(asset.vertexPosition.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexTangent.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexNormal.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.texCoords.data()),
vertexVec2Byte
);
file.close();
}

View File

@ -1,14 +0,0 @@
#pragma once
#include "../Asset Types/SHMeshAsset.h"
#include "../SHAssetMacros.h"
namespace SHADE
{
class SHMeshWriter
{
private:
public:
static void WriteMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept;
};
}

View File

@ -0,0 +1,73 @@
/*************************************************************************//**
* \file SHTextureCompiler.cpp
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to write data in SHTextureAsset into binary file for
* faster loading in the future
*
*
* 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 "SHTextureCompiler.h"
#include <fstream>
namespace SHADE
{
void SHTextureCompiler::CompileTextureBinary(SHTextureAsset const& asset, AssetPath path)
{
std::string newPath{ path.string() };
newPath = newPath.substr(0, newPath.find_last_of('.'));
newPath += TEXTURE_EXTENSION;
std::ofstream file{ newPath, std::ios::out | std::ios::binary };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open file for writing texture file: {}", path.string());
}
auto const intBytes{sizeof(uint32_t)};
uint32_t mipOffsetCount{ static_cast<uint32_t>(asset.mipOffsets.size()) };
file.write(
reinterpret_cast<char const*>(&asset.numBytes),
intBytes
);
file.write(
reinterpret_cast<char const*>(&asset.width),
intBytes
);
file.write(
reinterpret_cast<char const*>(&asset.height),
intBytes
);
file.write(
reinterpret_cast<char const*>(&asset.format),
sizeof(SHTexture::TextureFormat)
);
file.write(
reinterpret_cast<char const*>(&mipOffsetCount),
intBytes
);
file.write(
reinterpret_cast<char const*>(asset.mipOffsets.data()),
intBytes * asset.mipOffsets.size()
);
file.write(
reinterpret_cast<char const*>(asset.pixelData),
asset.numBytes
);
file.close();
}
}

View File

@ -0,0 +1,24 @@
/*************************************************************************//**
* \file SHTextureCompiler.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to write data in SHTextureAsset into binary file for
* faster loading in the future
*
*
* 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/SHTextureAsset.h"
#include "Assets/SHAssetMacros.h"
namespace SHADE
{
struct SHTextureCompiler
{
static void CompileTextureBinary(SHTextureAsset const& asset, AssetPath path);
};
}

View File

@ -1,3 +1,14 @@
/*************************************************************************//**
* \file SHTextureLoader.cpp
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to load dds textures and custom binary format
*
*
* 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 "SHTextureLoader.h"
@ -58,7 +69,7 @@ namespace SHADE
}
}
void SHTextureLoader::LoadImageAsset(AssetPath path, SHTextureAsset& asset)
void SHTextureLoader::LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept
{
tinyddsloader::Result loadResult = tinyddsloader::Result::Success;
tinyddsloader::DDSFile file;
@ -72,21 +83,64 @@ namespace SHADE
std::vector<uint32_t> mipOff(file.GetMipCount());
for (auto i{0}; i < file.GetMipCount(); ++i)
for (size_t i{0}; i < file.GetMipCount(); ++i)
{
mipOff.push_back(totalBytes);
totalBytes += file.GetImageData(i, 0)->m_memSlicePitch;
mipOff[i] = static_cast<uint32_t>(totalBytes);
totalBytes += file.GetImageData(static_cast<uint32_t>(i), 0)->m_memSlicePitch;
}
SHTexture::PixelChannel* pixel = new SHTexture::PixelChannel[totalBytes];
std::memcpy(pixel, file.GetDDSData(), totalBytes);
std::memcpy(pixel, file.GetImageData()->m_mem, totalBytes);
//pixel = std::move(reinterpret_cast<SHTexture::PixelChannel const*>(file.GetDDSData()));
asset.numBytes = totalBytes;
asset.compiled = false;
asset.numBytes = static_cast<uint32_t>(totalBytes);
asset.width = file.GetWidth();
asset.height = file.GetHeight();
asset.format = ddsLoaderToVkFormat(file.GetFormat(), true);
asset.mipOffsets = std::move(mipOff);
asset.pixelData = std::move(pixel);
}
void SHTextureLoader::LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept
{
std::ifstream file{path.string(), std::ios::in | std::ios::binary};
if (!file.is_open())
{
SHLOG_ERROR("Error opening SHTexture file: {}", path.string());
}
auto const intBytes{ sizeof(uint32_t) };
uint32_t mipCount;
file.read(reinterpret_cast<char*>(&asset.numBytes), intBytes);
file.read(reinterpret_cast<char*>(&asset.width), intBytes);
file.read(reinterpret_cast<char*>(&asset.height), intBytes);
file.read(reinterpret_cast<char*>(&asset.format), sizeof(SHTexture::TextureFormat));
file.read(reinterpret_cast<char*>(&mipCount), intBytes);
std::vector<uint32_t> mips(mipCount);
file.read(reinterpret_cast<char*>(mips.data()), intBytes * mipCount);
auto pixel = new SHTexture::PixelChannel[asset.numBytes];
file.read(reinterpret_cast<char*>(pixel), asset.numBytes);
asset.mipOffsets = std::move(mips);
asset.pixelData = std::move( pixel );
asset.compiled = true;
file.close();
}
void SHTextureLoader::LoadImageAsset(AssetPath path, SHTextureAsset& asset)
{
if (path.extension().string() == DDS_EXTENSION)
{
LoadTinyDDS(path, asset);
}
else if (path.extension().string() == TEXTURE_EXTENSION)
{
LoadSHTexture(path, asset);
}
}
}

View File

@ -1,3 +1,14 @@
/*************************************************************************//**
* \file SHTextureLoader.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to load dds textures and custom binary format
*
*
* 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
#define TINYDDSLOADER_IMPLEMENTATION
@ -13,6 +24,9 @@ namespace SHADE
static std::string TinyDDSResultToString(tinyddsloader::Result value);
static vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear);
static void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept;
static void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept;
public:
static void LoadImageAsset(AssetPath paths, SHTextureAsset& image);
};

View File

@ -1,3 +1,14 @@
/*************************************************************************//**
* \file SHAsset.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Struct for asset identification and meta file writing
*
*
* 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 "Filesystem/SHFileSystem.h"

View File

@ -17,6 +17,9 @@
#include "Libraries/SHMeshLoader.h"
#include "Libraries/SHTextureLoader.h"
#include "Libraries/SHMeshCompiler.h"
#include "Libraries/SHTextureCompiler.h"
namespace SHADE
{
FMOD::System* SHAssetManager::audioSystem;
@ -69,12 +72,13 @@ namespace SHADE
AssetType type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string().c_str());
std::string folder;
switch (type)
{
default:
//TODO:ASSERT UNSUPPORTED FILE TYPE
return std::filesystem::path();
}
//TODO Implement asset type generation
//switch (type)
//{
//default:
// //TODO:ASSERT UNSUPPORTED FILE TYPE
// return std::filesystem::path();
//}
return std::filesystem::path(ASSET_ROOT + folder + path.filename().string());
}
@ -105,12 +109,13 @@ namespace SHADE
meta.type = type;
std::string folder;
switch (type)
{
default:
folder = "";
break;
}
//TODO implement folder choosing
//switch (type)
//{
//default:
// folder = "";
// break;
//}
AssetPath path{ ASSET_ROOT + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) };
SHAssetMetaHandler::WriteMetaData(meta);
@ -199,7 +204,9 @@ namespace SHADE
{
AssetPath path{ p };
if (path.extension().string() == GLTF_EXTENSION)
if (path.extension().string() == FBX_EXTENSION
|| path.extension().string() == GLTF_EXTENSION
|| path.extension().string() == MESH_EXTENSION)
{
LoadGLTF(
{
@ -211,7 +218,8 @@ namespace SHADE
}
);
}
else if (path.extension().string() == DDS_EXTENSION)
else if (path.extension().string() == DDS_EXTENSION
|| path.extension().string() == TEXTURE_EXTENSION)
{
LoadDDS(
{
@ -300,6 +308,11 @@ namespace SHADE
for (auto const& mesh : meshes)
{
meshCollection.emplace(GenerateAssetID(AssetType::MESH), mesh);
if (!mesh.compiled)
{
SHMeshCompiler::CompileMeshBinary(mesh, asset.path);
}
}
}
@ -310,6 +323,11 @@ namespace SHADE
SHTextureLoader::LoadImageAsset(asset.path, image);
textureCollection.emplace(GenerateAssetID(AssetType::DDS), image);
if (!image.compiled)
{
SHTextureCompiler::CompileTextureBinary(image, asset.path);
}
}
/****************************************************************************

View File

@ -99,6 +99,7 @@ namespace SHADE
****************************************************************************/
void SHAssetMetaHandler::WriteMetaData(SHAsset const& meta) noexcept
{
//TODO: Write into binary eventually
std::string path{ meta.path.string() };
path.append(META_EXTENSION);
@ -110,8 +111,20 @@ namespace SHADE
return;
}
metaFile << "Name: " << meta.name << "\n";
metaFile << "ID: " << meta.id << "\n";
metaFile << "Type: " << static_cast<int>(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();
}

View File

@ -0,0 +1,58 @@
/*********************************************************************
* \file SHAudioListenerComponent.cpp
* \author Glence Low
* \brief Definition of the SHAudioListenerComponent class.
*
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
or disclosure of this file or its contents without the prior written
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#include "SHpch.h"
#include "SHAudioListenerComponent.h"
#include "ECS_Base/Managers/SHSystemManager.h"
namespace SHADE
{
const SHVec3 SHAudioListenerComponent::GetPos() const
{
return pos;
}
const SHVec3 SHAudioListenerComponent::GetVel() const
{
return vel;
}
const SHVec3 SHAudioListenerComponent::GetForward() const
{
return forward;
}
const SHVec3 SHAudioListenerComponent::GetUp() const
{
return up;
}
void SHAudioListenerComponent::SetPos(const SHVec3 p)
{
pos = p;
}
void SHAudioListenerComponent::SetVel(const SHVec3 v)
{
vel = v;
}
void SHAudioListenerComponent::SetForward(const SHVec3 f)
{
forward = f;
}
void SHAudioListenerComponent::SetUp(const SHVec3 u)
{
up = u;
}
}

View File

@ -0,0 +1,41 @@
#pragma once
/*********************************************************************
* \file SHAudioListenerComponent.h
* \author Glence Low
* \brief Declaration of the SHAudioListenerComponent class.
*
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
or disclosure of this file or its contents without the prior written
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#pragma once
#include "ECS_Base/Components/SHComponent.h"
#include "Math/SHMath.h"
namespace SHADE
{
class SHAudioListenerComponent : public SHComponent
{
friend class SHAudioSystem;
public:
SHAudioListenerComponent() = default;
~SHAudioListenerComponent() = default;
const SHVec3 GetPos() const;
void SetPos(const SHVec3 p);
const SHVec3 GetVel() const;
const SHVec3 GetForward() const;
const SHVec3 GetUp() const;
void SetVel(const SHVec3 v);
void SetForward(const SHVec3 f);
void SetUp(const SHVec3 u);
private:
SHVec3 pos{}, vel{}, forward{}, up{ 0.f,1.f,0.f };
};
}//namespace SHADE

View File

@ -0,0 +1,53 @@
/*********************************************************************
* \file SHAudioSourceComponet.cpp
* \author Glence Low
* \brief Definition of the SHAudioSourceComponet class.
*
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
or disclosure of this file or its contents without the prior written
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#include "SHpch.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "AudioSystem/SHAudioSystem.h"
#include "SHAudioSourceComponent.h"
namespace SHADE
{
/**
* @brief play the sound
*
* @param index where the sound is in the index
*/
void SHAudioSourceComponent::PlaySoundSFX(EntityID id, bool loop, bool spatial, float min , float max )
{
SHSystemManager::GetSystem<SHAudioSystem>()->PlaySFX(id, GetEID(),loop,spatial, min, max);
}
void SHAudioSourceComponent::PlaySoundBGM(EntityID id, bool loop, bool spatial, float min, float max)
{
SHSystemManager::GetSystem<SHAudioSystem>()->PlayBGM(id, GetEID(), loop, spatial, min, max);
}
/**
* @brief Stop the sound
*
* @param index where the sound is in the index
*/
void SHAudioSourceComponent::StopSound(EntityID id)
{
SHSystemManager::GetSystem<SHAudioSystem>()->StopSound(id);
}
/**
* @brief Mute the sound
*
* @param index where the sound is in the index
*/
void SHAudioSourceComponent::SetMute(EntityID id, bool mute)
{
SHSystemManager::GetSystem<SHAudioSystem>()->SetMute(id, mute);
}
}

View File

@ -0,0 +1,60 @@
/*********************************************************************
* \file SHAudioSourceComponet.h
* \author Glence Low
* \brief Declaration of the SHAudioSourceComponet class.
*
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
or disclosure of this file or its contents without the prior written
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#pragma once
#include "ECS_Base/Components/SHComponent.h"
#include "ECS_Base/SHECSMacros.h"
namespace SHADE
{
class SHAudioSourceComponent : public SHComponent
{
public:
/**
* @brief default constructor for the component
*
*/
SHAudioSourceComponent() = default;
/**
* @brief default destructor for the component
*
*/
~SHAudioSourceComponent() = default;
/**
* @brief play the sound
*
* @param index where the sound is in the index
*/
void PlaySoundSFX(EntityID id, bool loop = false, bool spatial = false, float min = 5.0f, float max = 1000.f);
void PlaySoundBGM(EntityID id, bool loop = false, bool spatial = false, float min = 5.0f, float max = 1000.f);
/**
* @brief Stop the sound
*
* @param index where the sound is in the index
*/
void StopSound(EntityID id);
/**
* @brief Mute the sound
*
* @param index where the sound is in the index
*/
void SetMute(EntityID id, bool mute);
private:
};
}//namespace SHADE

View File

@ -0,0 +1,557 @@
#include "SHpch.h"
#include "SHAudioSystem.h"
#include "Scene/SHSceneManager.h"
#include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include <iostream>
#include "AudioSystem/SHAudioListenerComponent.h"
#include "AudioSystem/SHAudioSourceComponent.h"
#include "Math/Transform/SHTransformComponent.h"
#pragma warning(push)
#pragma warning(disable:26812) //disable warning about preference of enum class over enum as ImGuizmo uses enums
#include <FMOD/fmod_errors.h>
#include <FMOD/fmod.hpp>
#include <FMOD/fmod_studio.hpp>
#include <SDL_keyboard.h>
namespace SHADE
{
SHAudioSystem::SHAudioSystem()
: fmodStudioSystem(nullptr)
, extraDriverData(nullptr)
, soundList()
, bgmChannelGroup(nullptr)
, sfxChannelGroup(nullptr)
, masterGroup(nullptr)
, audioChannels()
, result(FMOD_RESULT_FORCEINT)
, bgmVolume(1.F)
, sfxVolume(1.F)
, masterVolume(1.0F)
, version(0)
, speakerMode(FMOD_SPEAKERMODE_5POINT1)
, paused(false)
{
result = FMOD::Studio::System::create(&fmodStudioSystem);
ErrorCheck();
}
SHAudioSystem::~SHAudioSystem()
{
}
void SHADE::SHAudioSystem::Init()
{
SHADE::SHComponentManager::CreateComponentSparseSet<SHADE::SHAudioSourceComponent>();
SHADE::SHComponentManager::CreateComponentSparseSet<SHADE::SHAudioListenerComponent>();
denseListener = &SHComponentManager::GetDense<SHAudioListenerComponent>();
fmodStudioSystem->getCoreSystem(&fmodSystem);
result = fmodStudioSystem->initialize(AUDIO_SYS_MAX_CHANNELS, AUDIO_SYS_MAX_CHANNELS, FMOD_STUDIO_INIT_NORMAL, extraDriverData);
ErrorCheck();
fmodSystem->setSoftwareFormat(0, speakerMode, 0);
result = fmodSystem->createChannelGroup("SFX", &sfxChannelGroup);
ErrorCheck();
result = fmodSystem->createChannelGroup("BGM", &bgmChannelGroup);
ErrorCheck();
result = fmodSystem->getMasterChannelGroup(&masterGroup);
ErrorCheck();
result = masterGroup->addGroup(bgmChannelGroup);
ErrorCheck();
result = masterGroup->addGroup(sfxChannelGroup);
ErrorCheck();
bgmChannelGroup->setVolume(bgmVolume);
sfxChannelGroup->setVolume(sfxVolume);
masterGroup->setVolume(masterVolume);
//SHResourceManager::LoadAllAudio(system, soundList);
LoadBank("../../Assets/Audio/Master.bank");
LoadBank("../../Assets/Audio/Master.strings.bank");
//LoadBank("../../Assets/Audio/Music.bank");
LoadBank("../../Assets/Audio/footsteps.bank");
//auto clip = CreateAudioClip("event:/Characters/sfx_footsteps_human");
//clip->Play();
//PlayEventOnce("event:/Characters/sfx_footsteps_raccoon");
//PlayEventOnce("event:/SFX/Dawn/Dawn_Attack");
}
void SHADE::SHAudioSystem::Run(double dt)
{
static_cast<void>(dt);
//if (GetKeyState(VK_SPACE) & 0x8000)
// PlayEventOnce("event:/Characters/sfx_footsteps_raccoon");
fmodStudioSystem->update();
if (!denseListener->empty())
{
SHAudioListenerComponent& listener = denseListener->at(0);
SHTransformComponent* listenerTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(listener.GetEID());
if (listenerTransform)
{
listener.SetPos(listenerTransform->GetLocalPosition());
listener.SetForward({ (listenerTransform->GetLocalScale()[0] > 0.f) ? 1.f : -1.f, 0.f, 0.f });
FMOD_VECTOR pos = { listener.pos[0] ,listener.pos[1] ,0.f };
FMOD_VECTOR forward = { listener.forward[0] ,listener.forward[1] ,listener.forward[2] };
FMOD_VECTOR up = { listener.up[0] ,listener.up[1] ,listener.up[2] };
fmodSystem->set3DListenerAttributes(0, &pos, nullptr, &forward, &up);
}
}
}
SHAudioSystem::AudioRoutine::AudioRoutine()
: SHSystemRoutine("Audio Routine", false) {}
void SHAudioSystem::AudioRoutine::Execute(double dt) noexcept
{
reinterpret_cast<SHAudioSystem*>(system)->Run(dt);
}
void SHADE::SHAudioSystem::Exit()
{
for (auto& event : eventMap)
{
result = event.second->releaseAllInstances();
ErrorCheck();
}
for (auto& bank : bankMap)
{
result = bank.second->unload();
ErrorCheck();
}
for (auto& sound : soundList)
{
result = sound.second->release();
ErrorCheck();
}
if (bgmChannelGroup)
{
result = bgmChannelGroup->release();
ErrorCheck();
}
if (sfxChannelGroup)
{
result = sfxChannelGroup->release();
ErrorCheck();
}
if (fmodStudioSystem)
{
result = fmodStudioSystem->release();
ErrorCheck();
}
}
void SHAudioSystem::ErrorCheck() const
{
if (result != FMOD_OK)
std::cerr << "Audio system error: " << FMOD_ErrorString(result) << std::endl;
}
void SHAudioSystem::PlayEventOnce(const char* path, bool isSFX, EntityID eid, bool spatial)
{
if (paused)
return;
auto it = eventMap.find(path);
if (it != eventMap.end())
{
FMOD::Studio::EventInstance* event = nullptr;
it->second->createInstance(&event);
if (event)
{
event->setVolume(masterVolume * (isSFX ? sfxVolume : bgmVolume));
if (spatial)
{
if (SHTransformComponent* audioTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(eid))
{
FMOD_3D_ATTRIBUTES attributes{ {} };
attributes.forward.z = 1.0f;
attributes.up.y = 1.0f;
SHAudioListenerComponent& listener = denseListener->at(0);
SHTransformComponent* listenerTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(listener.GetEID());
if (listenerTransform)
{
attributes.position.z = listenerTransform->GetLocalPosition()[2];
}
attributes.position.x = audioTransform->GetLocalPosition()[0];
attributes.position.y = audioTransform->GetLocalPosition()[1];
event->set3DAttributes(&attributes);
}
}
event->start();
event->release();
}
}
}
void SHAudioSystem::PlaySFX(EntityID id, EntityID eid, const bool& loop, const bool& spatial, float min, float max)
{
SHSound sound = soundList[id];
int index = GetAvailableChannelIndex();
if (index >= 0)
{
unsigned int mode{};
mode |= (loop ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
mode |= (spatial ? FMOD_3D : FMOD_2D);
sound->setMode(mode);
result = fmodSystem->playSound(sound, sfxChannelGroup, false, &audioChannels[index]);
if (spatial && SHComponentManager::HasComponent<SHTransformComponent>(eid))
{
SHTransformComponent* audioTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
FMOD_VECTOR fpos{ audioTransform->GetLocalPosition()[0],audioTransform->GetLocalPosition()[1] ,0.f};
audioChannels[index]->set3DAttributes(&fpos, nullptr);
audioChannels[index]->setMode(mode);
audioChannels[index]->set3DMinMaxDistance(min, max);
}
ErrorCheck();
}
}
void SHAudioSystem::PlayBGM(EntityID id, EntityID eid, const bool& loop, const bool& spatial, float min, float max)
{
SHSound sound = soundList[id];
int index = GetAvailableChannelIndex();
if (index >= 0)
{
unsigned int mode{};
mode |= (loop ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
mode |= (spatial ? FMOD_3D : FMOD_2D);
sound->setMode(mode);
result = fmodSystem->playSound(sound, bgmChannelGroup, false, &audioChannels[index]);
if (spatial && SHComponentManager::HasComponent<SHTransformComponent>(eid))
{
SHTransformComponent* audioTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
FMOD_VECTOR fpos{ audioTransform->GetLocalPosition()[0],audioTransform->GetLocalPosition()[1] ,0.f };
audioChannels[index]->set3DAttributes(&fpos, nullptr);
audioChannels[index]->setMode(mode);
audioChannels[index]->set3DMinMaxDistance(min, max);
}
ErrorCheck();
}
}
void SHAudioSystem::SetMute(EntityID id, bool mute)
{
SHSound sound;
for (auto& channel : audioChannels)
{
channel->getCurrentSound(&sound);
if (soundList.find(id)->second == sound) // tbc
{
channel->setMute(mute);
}
}
}
void SHAudioSystem::StopSound(EntityID id)
{
SHSound sound;
for (auto& channel : audioChannels)
{
channel->getCurrentSound(&sound);
if (soundList.find(id)->second == sound) // tbc
{
channel->stop();
}
}
}
void SHAudioSystem::StopAllSounds()
{
for (auto& channel : audioChannels)
{
bool isPlaying{ false };
if (channel->isPlaying(&isPlaying) == FMOD_OK && isPlaying)
channel->stop();
}
}
std::optional<FMOD_GUID> SHAudioSystem::GetEventGUID(const char* path)
{
FMOD_GUID guid;
FMOD::Studio::EventDescription* event;
result = fmodStudioSystem->getEvent(path, &event);
ErrorCheck();
if (result == FMOD_OK)
{
result = event->getID(&guid);
ErrorCheck();
if (result == FMOD_OK)
{
return guid;
}
}
return std::nullopt;
}
AudioClip* SHAudioSystem::CreateAudioClip(const char* path)
{
AudioClipID newID{};
AudioClip* clip = nullptr;
auto it = eventMap.find(path);
if (it != eventMap.end())
{
FMOD::Studio::EventInstance* event = nullptr;
it->second->createInstance(&event);
if (event)
{
//event->start();
newID = clipID;
clipID++;
eventInstances.emplace(newID, AudioClip(newID, event));
clip = &eventInstances[newID];
}
}
return clip;
}
//std::vector<const char*> SHAudioSystem::GetAllEvents()
//{
// int count{};
// stringsBank->getEventCount(&count);
// std::vector<FMOD::Studio::EventDescription*> events(count);
// auto eventData = events.data();
// int finalCount{};
// stringsBank->getEventList(eventData, count, &finalCount);
// std::vector<const char*> eventNames;
// std::transform(events.begin(), events.end(), std::back_inserter(eventNames), [](FMOD::Studio::EventDescription* event)
// {
// char path[256];
// event->getPath(path, 256, nullptr);
// return path;
// });
// return eventNames;
//}
//void SHAudioSystem::PlayEventInstance(FMOD::Studio::EventInstance* instance, bool isSFX, EntityID eid, bool spatial)
//{
// instance->setVolume(masterVolume * (isSFX ? sfxVolume : bgmVolume));
// FMOD::ChannelGroup* channelGroup;
// if (spatial)
// {
// if (SHTransformComponent* audioTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(eid))
// {
// FMOD_3D_ATTRIBUTES attributes{ {} };
// attributes.forward.z = 1.0f;
// attributes.up.y = 1.0f;
// SHAudioListenerComponent& listener = denseListener->at(0);
// SHTransformComponent* listenerTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(listener.GetEID());
// if (listenerTransform)
// {
// attributes.position.z = listenerTransform->GetTranslation()[2];
// }
// attributes.position.x = audioTransform->GetTranslation()[0];
// attributes.position.y = audioTransform->GetTranslation()[1];
// instance->set3DAttributes(&attributes);
// }
// }
// instance->start();
//}
int SHAudioSystem::GetAvailableChannelIndex()
{
bool isPlaying = false;
for (int i = 0; i < AUDIO_SYS_MAX_CHANNELS; ++i)
{
audioChannels[i]->isPlaying(&isPlaying);
if (!isPlaying)
return i;
}
return -1;
}
float SHAudioSystem::GetBgmVolume()
{
return bgmVolume;
}
float SHAudioSystem::GetSfxVolume()
{
return sfxVolume;
}
float SHAudioSystem::GetMasterVolume()
{
return masterVolume;
}
void SHAudioSystem::SetBgmVolume(float const bgmvol)
{
bgmChannelGroup->setVolume(bgmvol);
}
void SHAudioSystem::SetSfxVolume(float const sfxvol)
{
sfxChannelGroup->setVolume(sfxvol);
}
void SHAudioSystem::SetMasterVolume(float const mastervol)
{
masterGroup->setVolume(mastervol);
}
void SHAudioSystem::SetPaused(bool pause)
{
paused = pause;
for (auto const& channel : audioChannels)
{
channel->setPaused(paused);
}
for (auto const& event : eventMap)
{
int instanceCount = 0;
event.second->getInstanceCount(&instanceCount);
std::vector<FMOD::Studio::EventInstance*> instances(instanceCount);
event.second->getInstanceList(instances.data(), static_cast<int>(instances.size()), &instanceCount);
for (auto const& instance : instances)
{
instance->setPaused(pause);
}
}
}
bool SHAudioSystem::GetPaused() const
{
return paused;
}
SHVec3 SHAudioSystem::GetListenerPosition()
{
auto &listener = denseListener->at(0);
SHTransformComponent* listenerTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(listener.GetEID());
if (listenerTransform)
{
return listenerTransform->GetLocalPosition();
}
return {};
}
void SHAudioSystem::LoadBank(const char* path)
{
FMOD::Studio::Bank* bank = nullptr;
result = fmodStudioSystem->loadBankFile(path, FMOD_STUDIO_LOAD_BANK_NORMAL, &bank);
ErrorCheck();
if (result != FMOD_OK)
return;
bankMap.emplace(path, bank);
bank->loadSampleData();
int numOfEvents;
bank->getEventCount(&numOfEvents);
if (numOfEvents > 0)
{
std::vector<FMOD::Studio::EventDescription*> events(numOfEvents);
bank->getEventList(events.data(), numOfEvents, &numOfEvents);
char eventName[512];
for (int i{}; i < numOfEvents; ++i)
{
FMOD::Studio::EventDescription* event = events[i];
event->getPath(eventName, 512, nullptr);
eventMap.emplace(eventName, event);
}
}
}
AudioClip::AudioClip(AudioClipID clipID, FMOD::Studio::EventInstance* inst)
:instance(inst), id(clipID)
{
}
AudioClip::~AudioClip()
{
}
void AudioClip::Play(bool isSfx)
{
if (!instance)
return;
instance->start();
auto audioSystem = SHSystemManager::GetSystem<SHADE::SHAudioSystem>();
instance->setVolume(audioSystem->GetMasterVolume() * (isSfx ? audioSystem->GetSfxVolume() : audioSystem->GetBgmVolume()));
}
void AudioClip::Play(SHVec3 position, bool isSfx)
{
if (!instance)
return;
instance->start();
FMOD_3D_ATTRIBUTES attributes{ {} };
attributes.forward.z = 1.0f;
attributes.up.y = 1.0f;
auto audioSystem = SHSystemManager::GetSystem<SHADE::SHAudioSystem>();
SHVec3 listenerPos = audioSystem->GetListenerPosition();
attributes.position.x = position[0];
attributes.position.y = position[1];
attributes.position.z = listenerPos[2];
instance->set3DAttributes(&attributes);
instance->setVolume(audioSystem->GetMasterVolume() * (isSfx ? audioSystem->GetSfxVolume() : audioSystem->GetBgmVolume()));
}
void AudioClip::Stop(bool fadeOut)
{
if (!instance)
return;
instance->stop(fadeOut ? FMOD_STUDIO_STOP_ALLOWFADEOUT : FMOD_STUDIO_STOP_IMMEDIATE);
}
void AudioClip::SetPause(bool pause)
{
if (!instance)
return;
instance->setPaused(pause);
}
bool AudioClip::IsPaused()
{
if (!instance)
return true;
bool paused{};
instance->getPaused(&paused);
return paused;
}
void AudioClip::SetParameter(const char* paramName, float value)
{
if (!instance)
return;
instance->setParameterByName(paramName, value);
}
void AudioClip::SetParameterLabel(const char* paramName, const char* label)
{
if (!instance)
return;
instance->setParameterByNameWithLabel(paramName, label);
}
float AudioClip::GetParameterValue(const char* paramName)
{
if (!instance)
return {};
float value{};
instance->getParameterByName(paramName, &value);
return value;
}
}
#pragma warning(pop)

View File

@ -0,0 +1,110 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
#include <set>
#include <unordered_map>
#include "ECS_Base/System/SHSystem.h"
#include "ECS_Base/System/SHSystemRoutine.h"
#include "ECS_Base/SHECSMacros.h"
#include "Math/SHMath.h"
#include <optional>
#include <FMOD/fmod_studio.hpp>
#include "SH_API.h"
#define AUDIO_SYS_MAX_CHANNELS 1024
namespace SHADE
{
typedef FMOD::Sound* SHSound;
typedef FMOD::Studio::Bank* SHBank;
class SHAudioListenerComponent;
typedef uint64_t AudioClipID;
class AudioClip
{
public:
AudioClip() = default;
AudioClip(AudioClipID clipID, FMOD::Studio::EventInstance* inst);
~AudioClip();
void Play(bool isSfx = true);
void Play(SHVec3 position, bool isSfx = true);
void Stop(bool fadeOut = true);
void SetPause(bool pause);
bool IsPaused();
void SetParameter(const char* paramName, float value);
void SetParameterLabel(const char* paramName, const char* label);
float GetParameterValue(const char* paramName);
friend class SHAudioSystem;
private:
FMOD::Studio::EventInstance* instance;
AudioClipID id;
};
class SH_API SHAudioSystem : public SHSystem
{
public:
SHAudioSystem();
~SHAudioSystem();
void Init();
void Run(double dt);
class SH_API AudioRoutine final : public SHSystemRoutine
{
public:
AudioRoutine();
void Execute(double dt) noexcept override final;
};
void Exit();
int GetAvailableChannelIndex();
/*std::vector<SHSound>::size_type CreateSound(const char* filepath, bool loop = false);*/
void PlaySFX(EntityID id, EntityID eid, const bool& loop, const bool& spatial, float min = 5.0f, float max = 1000.0f);
void PlayBGM(EntityID id, EntityID eid, const bool& loop, const bool& spatial, float min = 5.0f, float max = 1000.0f);
void PlayEventOnce(const char* path, bool isSFX = true, EntityID eid = MAX_EID, bool spatial = false);
void SetMute(EntityID id, bool);
void StopSound(EntityID id);
void StopAllSounds();
std::optional<FMOD_GUID> GetEventGUID(const char* path);
AudioClip* CreateAudioClip(const char* path);
//std::vector<const char*> GetAllEvents();
float GetBgmVolume();
float GetSfxVolume();
float GetMasterVolume();
void SetBgmVolume(float const bgmvol);
void SetSfxVolume(float const sfxvol);
void SetMasterVolume(float const mastervol);
void SetPaused(bool pause);
bool GetPaused() const;
SHVec3 GetListenerPosition();
void LoadBank(const char* path);
private:
FMOD::Studio::System* fmodStudioSystem;
FMOD::System* fmodSystem;
bool paused;
void ErrorCheck() const;
void* extraDriverData;
std::unordered_map<EntityID, SHSound> soundList;
//std::unordered_map<ResourceID, SHBank> bankMap;
std::unordered_map<std::string, SHBank> bankMap;
std::unordered_map<std::string, FMOD::Studio::EventDescription*> eventMap;
std::unordered_map<AudioClipID, AudioClip> eventInstances;
FMOD::ChannelGroup* bgmChannelGroup, * sfxChannelGroup, * masterGroup;
FMOD::Channel* audioChannels[AUDIO_SYS_MAX_CHANNELS];
FMOD_RESULT result;
float bgmVolume, sfxVolume, masterVolume;
unsigned int version;
FMOD_SPEAKERMODE speakerMode;
SHBank masterBank, stringsBank, musicBank, sfxBank; //To do: change to map of banks loaded by resource manager
std::vector<SHAudioListenerComponent>* denseListener;
AudioClipID clipID = 0;
};
}

View File

@ -14,6 +14,7 @@
#include "SHpch.h"
#include "../SHECSMacros.h"
#include "SH_API.h"
#include "ECS_Base/General/SHFamily.h"
namespace SHADE
{
@ -117,4 +118,7 @@ namespace SHADE
};
template class SH_API SHFamilyID<SHComponent>;
}

View File

@ -0,0 +1,12 @@
#pragma once
#include "ECS_Base/Components/SHComponent.h"
namespace SHADE
{
struct SHComponentAddedEvent
{
EntityID eid;
ComponentTypeID addedComponentType;
};
}

View File

@ -0,0 +1,12 @@
#pragma once
#include "ECS_Base/Components/SHComponent.h"
namespace SHADE
{
struct SHComponentRemovedEvent
{
EntityID eid;
ComponentTypeID removedComponentType;
};
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "SHFamily.h"
#include "SHpch.h"
namespace SHADE
{
//initialize currentID as 0
}

View File

@ -14,16 +14,17 @@
#pragma once
#include "../SHECSMacros.h"
#include "SH_API.h"
namespace SHADE
{
template<typename BaseClass>
class SHFamilyID
class SH_API SHFamilyID
{
private:
//this is used to keep track of the new current ID to be assign to a new Derived class type.
static ComponentTypeID currentID;
/*!*************************************************************************
* \brief Construct a new SHFamilyID object
@ -46,6 +47,9 @@ namespace SHADE
}
public:
//this is used to keep track of the new current ID to be assign to a new Derived class type.
static inline ComponentTypeID currentID = 0;
/*!*************************************************************************
* \brief
* Checks if this identifier is cuurrently in use / valid.
@ -59,7 +63,6 @@ namespace SHADE
{
return(id < currentID);
}
/*!*************************************************************************
* \brief
* Get the ID of a derived class type.
@ -68,16 +71,27 @@ namespace SHADE
* @tparam DerivedClass
* The derived class type that we are trying to get the ID of.
***************************************************************************/
#ifdef SH_API_EXPORT
template<typename DerivedClass>
static ENABLE_IF_DERIVED(ComponentTypeID, BaseClass, DerivedClass) GetID() noexcept
static SH_API ENABLE_IF_DERIVED(ComponentTypeID, BaseClass, DerivedClass) GetID() noexcept
{
//The first time a new derived class type call this get id, it will initialize id using the currentID from familyID class.
static ComponentTypeID id = currentID++;
static ComponentTypeID id = SHFamilyID<BaseClass>::currentID++;
return id;
//return 0;
}
#else
template<typename DerivedClass>
static SH_API ENABLE_IF_DERIVED(ComponentTypeID, BaseClass, DerivedClass) GetID() noexcept;
#endif // SH_API_EXPORT
};
//initialize currentID as 0
template<typename BaseClass>
ComponentTypeID SHFamilyID<BaseClass>::currentID = 0;
}

View File

@ -17,8 +17,11 @@
#include "../General/SHSparseSetContainer.h"
#include "../Components/SHComponent.h"
#include "../Components/SHComponentGroup.h"
#include "../Events/SHComponentAddedEvent.h"
#include "../Events/SHComponentRemovedEvent.h"
//#include "Scene/SHSceneNode.h"
#include "SH_API.h"
#include "Events/SHEventManager.hpp"
#include <cassert>
@ -216,6 +219,11 @@ namespace SHADE
comp->OnCreate();
}
SHComponentAddedEvent eventData;
eventData.eid = entityID;
eventData.addedComponentType = ComponentFamily::GetID<T>();
SHEventManager::BroadcastEvent<SHComponentAddedEvent>(eventData, SH_COMPONENT_ADDED_EVENT);
}
/**************************************************************************
@ -247,6 +255,13 @@ namespace SHADE
{
comp->OnCreate();
}
SHComponentAddedEvent eventData;
eventData.eid = entityID;
eventData.addedComponentType = componentTypeID;
SHEventManager::BroadcastEvent<SHComponentAddedEvent>(eventData, SH_COMPONENT_ADDED_EVENT);
}
@ -313,6 +328,12 @@ namespace SHADE
componentSet.GetSparseSet<T>()->Remove(EntityHandleGenerator::GetIndex(entityID));
SHComponentRemovedEvent eventData;
eventData.eid = entityID;
eventData.removedComponentType = ComponentFamily::GetID<T>();
SHEventManager::BroadcastEvent<SHComponentRemovedEvent>(eventData, SH_COMPONENT_REMOVED_EVENT);
}
/*!*************************************************************************
@ -464,11 +485,6 @@ namespace SHADE
return componentGroups[index];
}
static void AddScriptComponent(EntityID eid, std::string const& scriptClassName) noexcept;
static void RemoveScriptComponent(EntityID eid, std::string const& scriptClassName) noexcept;
};// end SHComponentManager

View File

@ -68,6 +68,9 @@ namespace SHADE
id = ((SystemID)version << sizeof(SystemVersionID) * CHAR_BIT) + typeID;
}
systemContainer.emplace(id, std::make_unique<T>());
auto size = systemContainer.size();
systemContainer[id].get()->systemID = id;
return id;

View File

@ -26,4 +26,6 @@ const EntityIndex MAX_EID = 51000;
#define ENABLE_IF_UINT(_TYPE, _RETURN)\
typename std::enable_if<(std::is_integral<_TYPE>::value && !std::is_signed<_TYPE>::value),_RETURN>::type
#endif

View File

@ -8,23 +8,19 @@ namespace SHADE
{
class SHFixedSystemRoutine: public SHSystemRoutine
{
private:
double accumulatedTime;
double fixedTimeStep;
protected:
SHFixedSystemRoutine(double timeStep = DEFAULT_FIXED_STEP, std::string routineName = "Default Fixed Routine Name", bool editorPause = false)
double accumulatedTime;
double fixedTimeStep;
SHFixedSystemRoutine(double timeStep = DEFAULT_FIXED_STEP, std::string routineName = "Default Fixed Routine Name", bool editorPause = false)
:SHSystemRoutine(routineName, editorPause), accumulatedTime(0.0), fixedTimeStep(timeStep){}
public:
~SHFixedSystemRoutine() = default;
virtual void Execute(double dt) noexcept;
virtual void FixedExecute(double dt) noexcept {};
virtual void Execute(double dt) noexcept override;
virtual void FixedExecute(double dt) noexcept {}
};

View File

@ -12,6 +12,7 @@
#include "../SHECSMacros.h"
#include "SH_API.h"
#include "ECS_Base/General/SHFamily.h"
namespace SHADE
{
@ -69,5 +70,9 @@ namespace SHADE
};
template class SH_API SHFamilyID<SHSystem>;
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "../Components/SHComponent.h"
#include <rttr/registration>
namespace SHADE
{
@ -27,4 +28,50 @@ namespace SHADE
std::string value{};
};
class SHComponent_ENUM : public SHComponent
{
public:
enum class Option
{
OPT_A,
OPT_B,
OPT_C
};
bool boolTest{};
int intTest{};
float floatTest{};
double doubleTest{};
long longTest{};
uint8_t uint8Test{};
uint16_t uint16Test{};
uint32_t uint32Test{};
uint64_t uint64Test{};
Option option;
RTTR_ENABLE()
};
RTTR_REGISTRATION
{
using namespace rttr;
registration::enumeration<SHComponent_ENUM::Option>("Option")
(
value("Option A", SHComponent_ENUM::Option::OPT_A),
value("Option B", SHComponent_ENUM::Option::OPT_B),
value("Option C", SHComponent_ENUM::Option::OPT_C)
);
rttr::registration::class_<SHComponent_ENUM>("Enum Component")
.property("Option", &SHComponent_ENUM::option)
.property("boolTest", &SHComponent_ENUM::boolTest)
.property("intTest", &SHComponent_ENUM::intTest)( metadata("MIN", 0.0f), metadata("MAX", 1.f))
.property("floatTest", &SHComponent_ENUM::floatTest)(metadata("MIN", 0.0f), metadata("MAX", 1.f))
.property("doubleTest", &SHComponent_ENUM::doubleTest)(metadata("MIN", 0.0f), metadata("MAX", 1.f))
.property("uint8Test", &SHComponent_ENUM::uint8Test)(metadata("MIN", 0.0f), metadata("MAX", 1.f))
.property("uint16Test", &SHComponent_ENUM::uint16Test)(metadata("MIN", 0.0f), metadata("MAX", 1.f))
.property("uint32Test", &SHComponent_ENUM::uint32Test)(metadata("MIN", 0.0f), metadata("MAX", 1.f))
.property("uint64Test", &SHComponent_ENUM::uint64Test)(metadata("MIN", 0.0f), metadata("MAX", 1.f));
}
}

View File

@ -5,9 +5,13 @@
//#==============================================================#
#include <functional>
#include "SH_API.h"
#include "Scripting/SHScriptEngine.h"
#include "ECS_Base/Managers/SHSystemManager.h"
namespace SHADE
{
class SHBaseCommand
class SH_API SHBaseCommand
{
public:
virtual ~SHBaseCommand() = default;
@ -48,4 +52,20 @@ namespace SHADE
T newValue;
SetterFunction set;
};
class SH_API SHCLICommand : SHBaseCommand
{
public:
SHCLICommand() = default;
void Execute() override
{
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->RedoScriptInspectorChanges();
}
void Undo() override
{
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->UndoScriptInspectorChanges();
}
};
}//namespace SHADE

View File

@ -27,6 +27,11 @@ namespace SHADE
}
}
void SHCommandManager::RegisterCommand(CommandPtr commandPtr)
{
undoStack.push(commandPtr);
}
void SHCommandManager::UndoCommand()
{
if (undoStack.empty())

View File

@ -9,10 +9,11 @@
//|| SHADE Includes ||
//#==============================================================#
#include "SHCommand.hpp"
#include "SH_API.h"
namespace SHADE
{
class SHCommandManager
class SH_API SHCommandManager
{
public:
//#==============================================================#
@ -22,6 +23,7 @@ namespace SHADE
using CommandStack = std::stack<CommandPtr>;
static void PerformCommand(CommandPtr commandPtr, bool const& overrideValue = false);
static void RegisterCommand(CommandPtr commandPtr);
static void UndoCommand();
static void RedoCommand();
static std::size_t GetUndoStackSize();

View File

@ -114,7 +114,7 @@ namespace SHADE
auto* entity = SHEntityManager::GetEntityByID(currentNode->GetEntityID());
//Draw Node
bool isNodeOpen = ImGui::TreeNodeEx((void*)eid, nodeFlags, "%u: %s", EntityHandleGenerator::GetIndex(eid), entity->name.c_str());
bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast<void*>(entity), nodeFlags, "%u: %s", EntityHandleGenerator::GetIndex(eid), entity->name.c_str());
const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
//Check For Begin Drag

View File

@ -12,6 +12,7 @@
#include "Editor/IconsMaterialDesign.h"
#include "ECS_Base/Components/SHComponent.h"
#include "Editor/SHEditorWidgets.hpp"
#include "Reflection/SHReflectionMetadata.h"
namespace SHADE
{
template<typename T, std::enable_if_t<std::is_base_of<SHComponent, T>::value, bool> = true>
@ -45,7 +46,7 @@ namespace SHADE
if (!component)
return;
auto componentType = rttr::type::get(*component);
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; });
ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data()))
{
@ -55,14 +56,136 @@ namespace SHADE
{
auto const& type = property.get_type();
if (type == rttr::type::get<SHVec4>())
if(type.is_enumeration())
{
DragVec4(property.get_name().data(), { "X", "Y", "Z", "W" }, [component, property]() {return property.get_value(component).template convert<SHVec4>(); }, [component, property](SHVec4 vec) {return property.set_value(component, vec); });
auto enumAlign = type.get_enumeration();
auto names = enumAlign.get_names();
std::vector<const char*> list;
for(auto const& name : names)
list.push_back(name.data());
SHEditorWidgets::ComboBox(property.get_name().data(), list, [component, property]{return property.get_value(component).to_int();}, [component, property](int const& idx)
{
auto enumAlign = property.get_enumeration();
auto values = enumAlign.get_values();
auto it = std::next(values.begin(), idx);
property.set_value(component, *it);
});
}
else if(type.is_arithmetic())
{
if (type == rttr::type::get<bool>())
{
SHEditorWidgets::CheckBox(property.get_name().data(), [component, property]{return property.get_value(component).to_bool();}, [component, property](bool const& result){property.set_value(component, result);});
}
//else if (type == rttr::type::get<char>())
//{
//
//}
else if (type == rttr::type::get<int8_t>() || type == rttr::type::get<int16_t>() || type == rttr::type::get<int32_t>() || type == rttr::type::get<int64_t>())
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
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);});
}
else
{
SHEditorWidgets::DragInt(property.get_name().data(), [component, property]{return property.get_value(component).to_int();}, [component, property](int const& result){property.set_value(component, result);});
}
}
else if (type == rttr::type::get<uint8_t>())
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
if(metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<uint8_t>(property.get_name().data(), ImGuiDataType_U8, metaMin.template get_value<uint8_t>(), metaMax.template get_value<uint8_t>(), [component, property]{return property.get_value(component).to_uint8();}, [component, property](uint8_t const& result){property.set_value(component, result);},"%zu");
}
else
{
SHEditorWidgets::DragScalar<uint8_t>(property.get_name().data(), ImGuiDataType_U8, [component, property]{return property.get_value(component).to_uint8();}, [component, property](uint8_t const& result){property.set_value(component, result);},0.1f,0,0,"%zu");
}
}
else if (type == rttr::type::get<uint16_t>())
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
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");
}
else
{
SHEditorWidgets::DragScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, [component, property]{return property.get_value(component).to_uint16();}, [component, property](uint16_t const& result){property.set_value(component, result);},0.1f,0,0,"%zu");
}
}
else if (type == rttr::type::get<uint32_t>())
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
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");
}
else
{
SHEditorWidgets::DragScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, [component, property]{ return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result){property.set_value(component, result); },0.1f,0,0,"%zu");
}
}
else if (type == rttr::type::get<uint64_t>())
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
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");
}
else
{
SHEditorWidgets::DragScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, [component, property]{return property.get_value(component).to_uint64();}, [component, property](uint64_t const& result){property.set_value(component, result);},0.1f,0,0,"%zu");
}
}
else if (type == rttr::type::get<float>())
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
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);});
}
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);});
}
}
else if (type == rttr::type::get<double>())
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
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);});
}
else
{
SHEditorWidgets::DragScalar<double>(property.get_name().data(), ImGuiDataType_Double, [component, property]{return property.get_value(component).to_double();}, [component, property](double const& result){property.set_value(component, result);}, 0.1f);
}
}
}
else if (type == rttr::type::get<SHVec4>())
{
SHEditorWidgets::DragVec4(property.get_name().data(), { "X", "Y", "Z", "W" }, [component, property]() {return property.get_value(component).template convert<SHVec4>(); }, [component, property](SHVec4 vec) {return property.set_value(component, vec); });
}
else if (type == rttr::type::get<SHVec3>())
{
DragVec3(property.get_name().data(), { "X", "Y", "Z" }, [component, property]() {return property.get_value(component).template convert<SHVec3>(); }, [component, property](SHVec3 vec) {return property.set_value(component, vec); });
SHEditorWidgets::DragVec3(property.get_name().data(), { "X", "Y", "Z" }, [component, property]() {return property.get_value(component).template convert<SHVec3>(); }, [component, property](SHVec3 vec) {return property.set_value(component, vec); });
}
else if (type == rttr::type::get<SHVec2>())
{
SHEditorWidgets::DragVec2(property.get_name().data(), { "X", "Y"}, [component, property]() {return property.get_value(component).template convert<SHVec2>(); }, [component, property](SHVec2 vec) {return property.set_value(component, vec); });
}
}
}
else DrawContextMenu(component);

View File

@ -11,7 +11,15 @@
#include "Editor/SHImGuiHelpers.hpp"
#include "Editor/SHEditorWidgets.hpp"
#include "SHEditorComponentView.hpp"
#include "ECS_Base/UnitTesting/SHTestComponents.h"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Scripting/SHScriptEngine.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "AudioSystem/SHAudioSystem.h"
#include "Physics/Components/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h"
namespace SHADE
{
@ -39,13 +47,19 @@ namespace SHADE
SHEditorWindow::Update();
if (Begin())
{
if (ImGui::Button("AUDIO"))
{
auto audioSystem = SHSystemManager::GetSystem<SHADE::SHAudioSystem>();
audioSystem->PlayEventOnce("event:/Characters/sfx_footsteps_raccoon");
}
if (!SHEditor::selectedEntities.empty())
{
EntityID const& eid = SHEditor::selectedEntities[0];
SHEntity* entity = SHEntityManager::GetEntityByID(eid);
ImGui::TextColored(ImGuiColors::green, "EID: %zu", eid);
CheckBox("##IsActive", [entity]()->bool {return entity->GetActive(); }, [entity](bool const& active) {entity->SetActive(active); });
SHEditorWidgets::CheckBox("##IsActive", [entity]()->bool {return entity->GetActive(); }, [entity](bool const& active) {entity->SetActive(active); });
ImGui::SameLine();
ImGui::InputText("##EntityName", &entity->name);
@ -54,13 +68,32 @@ namespace SHADE
{
DrawComponent(transformComponent);
}
if(auto renderableComponent = SHComponentManager::GetComponent_s<SHRenderable>(eid))
{
DrawComponent(renderableComponent);
}
if(auto colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(eid))
{
DrawComponent(colliderComponent);
}
if(auto rigidbodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(eid))
{
DrawComponent(rigidbodyComponent);
}
ImGui::Separator();
// Render Scripts
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->RenderScriptsInInspector(eid);
ImGui::Separator();
if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data()))
{
DrawAddComponentButton<SHTransformComponent>(eid);
DrawAddComponentButton<SHRenderable>(eid);
DrawAddComponentButton<SHColliderComponent>(eid);
DrawAddComponentButton<SHRigidBodyComponent>(eid);
ImGui::EndMenu();
}
}
ImGui::End();
}

View File

@ -6,6 +6,9 @@
#include "SHEditorMenuBar.h"
#include "Editor/IconsMaterialDesign.h"
#include "Editor/Command/SHCommandManager.h"
#include "Scripting/SHScriptEngine.h"
#include "Editor/SHEditor.hpp"
#include "ECS_Base/Managers/SHSystemManager.h"
//#==============================================================#
//|| Library Includes ||
@ -14,9 +17,6 @@
#include <imgui_internal.h>
#include <rttr/type>
#include "Editor/SHEditor.hpp"
namespace SHADE
{
constexpr ImGuiWindowFlags editorMenuBarFlags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse |
@ -100,6 +100,25 @@ namespace SHADE
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Scripts"))
{
if (ImGui::Selectable("Generate Visual Studio Project"))
{
auto* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->GenerateScriptsCsProjFile();
}
if (ImGui::Selectable("Build Scripts - Debug"))
{
auto* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->BuildScriptAssembly(true, true);
}
if (ImGui::Selectable("Build Scripts - Release"))
{
auto* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->BuildScriptAssembly(false, true);
}
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}

View File

@ -0,0 +1,48 @@
#include "SHpch.h"
#include "SHEditorProfiler.h"
#include <imgui.h>
#include "ECS_Base/Managers/SHSystemManager.h"
#include "FRC/SHFramerateController.h"
namespace SHADE
{
SHEditorProfiler::SHEditorProfiler()
:SHEditorWindow("Profiler", ImGuiWindowFlags_None)
{
}
void SHEditorProfiler::Init()
{
SHEditorWindow::Init();
}
void SHEditorProfiler::Update()
{
SHEditorWindow::Update();
const float dt = static_cast<float>(SHFrameRateController::GetRawDeltaTime());
if(frames.size() > MaxFramesDisplayed)
{
for (size_t i = 1; i < frames.size(); i++)
{
frames[i-1] = frames[i];
}
frames[frames.size() - 1] = dt;
}
else
{
frames.push_back(dt);
}
if(Begin())
{
ImGui::PlotLines("DT", frames.data(), static_cast<int>(frames.size()), 0, nullptr, 0.0f, 16.0f);
ImGui::End();
}
}
void SHEditorProfiler::Exit()
{
SHEditorWindow::Exit();
}
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "Editor/EditorWindow/SHEditorWindow.h"
#include <vector>
constexpr uint32_t MaxFramesDisplayed = 100;
namespace SHADE
{
class SHEditorProfiler final : public SHEditorWindow
{
public:
SHEditorProfiler();
void Init() override;
void Update() override;
void Exit() override;
private:
std::vector<float> frames;
};
}

View File

@ -2,3 +2,4 @@
#include "MenuBar/SHEditorMenuBar.h" //Menu Bar
#include "HierarchyPanel/SHHierarchyPanel.h" //Hierarchy Panel
#include "Inspector/SHEditorInspector.h" //Inspector
#include "Profiling/SHEditorProfiler.h" //Profiler

View File

@ -843,7 +843,7 @@
#define ICON_MD_FLIP_TO_FRONT "\xee\xa2\x83" // U+e883
#define ICON_MD_FLOOD "\xee\xaf\xa6" // U+ebe6
#define ICON_MD_FLOURESCENT "\xee\xb0\xb1" // U+ec31
#define ICON_MD_FLOURESCENT "\xef\x80\x8d" // U+f00d
#define ICON_MD_FLOURESCENT2 "\xef\x80\x8d" // U+f00d
#define ICON_MD_FLUORESCENT "\xee\xb0\xb1" // U+ec31
#define ICON_MD_FLUTTER_DASH "\xee\x80\x8b" // U+e00b
#define ICON_MD_FMD_BAD "\xef\x80\x8e" // U+f00e

View File

@ -23,6 +23,8 @@
#include "SHEditor.hpp"
#include "SHEditorWidgets.hpp"
#include "Math/Transform/SHTransformSystem.h"
//#==============================================================#
//|| Editor Window Includes ||
//#==============================================================#
@ -87,6 +89,11 @@ namespace SHADE
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; //Enable docking
InitFonts();
auto id = SHFamilyID<SHSystem>::GetID<SHGraphicsSystem>();
auto id2 = SHFamilyID<SHSystem>::GetID<SHTransformSystem>();
auto id3 = SHFamilyID<SHSystem>::GetID<SHGraphicsSystem>();
InitBackend(sdlWindow);
SetStyle(Style::SHADE);
@ -95,6 +102,7 @@ namespace SHADE
CreateEditorWindow<SHEditorMenuBar>();
CreateEditorWindow<SHHierarchyPanel>();
CreateEditorWindow<SHEditorInspector>();
CreateEditorWindow<SHEditorProfiler>();
SHLOG_INFO("Successfully initialised SHADE Engine Editor")
}
@ -103,10 +111,10 @@ namespace SHADE
{
(void)dt;
NewFrame();
for (const auto& window : editorWindows | std::views::values)
{
window->Update();
if(window->isOpen)
window->Update();
}
if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z))
@ -292,6 +300,8 @@ namespace SHADE
imguiCommandBuffer->EndRecording();
gfxSystem->GetQueue()->SubmitCommandBuffer({ imguiCommandBuffer }, {}, {}, vk::PipelineStageFlagBits::eNone, {});
gfxSystem->GetDevice()->WaitIdle();
ImGui_ImplVulkan_DestroyFontUploadObjects();
renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle<SHVkCommandBuffer>& cmd) {

View File

@ -0,0 +1,259 @@
/************************************************************************************//*!
\file EditorUI.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 7, 2021
\brief Contains the implementation of the EditorUI class.
Copyright (C) 2021 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
// Precompiled Header
#include "SHpch.h"
// Primary Header
#include "SHEditorUI.h"
// External Dependencies
#include <imgui.h>
#include "SHEditorWidgets.hpp"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* ImGui Wrapper Functions - ID Stack */
/*-----------------------------------------------------------------------------------*/
void SHEditorUI::PushID(const std::string& id)
{
ImGui::PushID(id.c_str());
}
void SHEditorUI::PushID(int id)
{
ImGui::PushID(id);
}
void SHEditorUI::PopID()
{
ImGui::PopID();
}
/*-----------------------------------------------------------------------------------*/
/* ImGui Wrapper Functions - Indent */
/*-----------------------------------------------------------------------------------*/
void SHEditorUI::Indent()
{
ImGui::Indent();
}
void SHEditorUI::Unindent()
{
ImGui::Unindent();
}
/*-----------------------------------------------------------------------------------*/
/* ImGui Wrapper Functions - Organizers */
/*-----------------------------------------------------------------------------------*/
bool SHEditorUI::CollapsingHeader(const std::string& title)
{
return ImGui::CollapsingHeader(title.c_str());
}
void SHEditorUI::SameLine()
{
ImGui::SameLine();
}
void SHEditorUI::Separator()
{
ImGui::Separator();
}
bool SHEditorUI::BeginMenu(const std::string& label)
{
return ImGui::BeginMenu(label.data());
}
bool SHEditorUI::BeginMenu(const std::string& label, const char* icon)
{
return ImGui::BeginMenu(std::format("{} {}", icon, label.data()).data());
}
void SHEditorUI::EndMenu()
{
ImGui::EndMenu();
}
/*-----------------------------------------------------------------------------------*/
/* ImGui Wrapper Functions - Pop Ups */
/*-----------------------------------------------------------------------------------*/
bool SHEditorUI::BeginPopup(const std::string& label)
{
return ImGui::BeginPopup(label.c_str());
}
bool SHEditorUI::BeginPopupContextItem(const std::string& label)
{
return ImGui::BeginPopupContextItem(label.data());
}
void SHEditorUI::EndPopup()
{
ImGui::EndPopup();
}
void SHEditorUI::OpenPopup(const std::string& label)
{
ImGui::OpenPopup(label.c_str());
}
bool SHEditorUI::MenuItem(const std::string& label)
{
return ImGui::MenuItem(label.c_str());
}
/*-----------------------------------------------------------------------------------*/
/* ImGui Wrapper Functions - Widgets */
/*-----------------------------------------------------------------------------------*/
void SHEditorUI::Text(const std::string& title)
{
ImGui::Text(title.c_str());
}
bool SHEditorUI::SmallButton(const std::string& title)
{
return ImGui::SmallButton(title.c_str());
}
bool SHEditorUI::Button(const std::string& title)
{
return ImGui::Button(title.c_str());
}
bool SHEditorUI::Selectable(const std::string& label)
{
return ImGui::Selectable(label.data());
}
bool SHEditorUI::Selectable(const std::string& label, const char* icon)
{
return ImGui::Selectable(std::format("{} {}", icon, label).data());
}
bool SHEditorUI::InputCheckbox(const std::string& label, bool& value)
{
ImGui::Text(label.c_str());
ImGui::SameLine();
return ImGui::Checkbox("#", &value);
}
bool SHEditorUI::InputInt(const std::string& label, int& value)
{
ImGui::Text(label.c_str());
ImGui::SameLine();
return ImGui::InputInt("#", &value,
1, 10,
ImGuiInputTextFlags_EnterReturnsTrue);
}
bool SHEditorUI::InputUnsignedInt(const std::string& label, unsigned int& value)
{
int signedVal = static_cast<int>(value);
ImGui::Text(label.c_str());
ImGui::SameLine();
const bool CHANGED = InputInt("#", signedVal);
if (CHANGED)
{
signedVal = std::clamp(signedVal, 0, std::numeric_limits<int>::max());
value = static_cast<unsigned int>(signedVal);
}
return CHANGED;
}
bool SHEditorUI::InputFloat(const std::string& label, float& value)
{
ImGui::Text(label.c_str());
ImGui::SameLine();
return ImGui::InputFloat("#", &value,
0.1f, 1.0f, "%.3f",
ImGuiInputTextFlags_EnterReturnsTrue);
}
bool SHEditorUI::InputDouble(const std::string& label, double& value)
{
ImGui::Text(label.c_str());
ImGui::SameLine();
return ImGui::InputDouble("#", &value,
0.1, 1.0, "%.3f",
ImGuiInputTextFlags_EnterReturnsTrue);
}
bool SHEditorUI::InputAngle(const std::string& label, double& value)
{
ImGui::Text(label.c_str());
ImGui::SameLine();
return ImGui::InputDouble("#", &value,
1.0, 45.0, "%.3f",
ImGuiInputTextFlags_EnterReturnsTrue);
}
bool SHEditorUI::InputSlider(const std::string& label, double min, double max, double& value)
{
float val = static_cast<float>(value);
ImGui::Text(label.c_str());
ImGui::SameLine();
const bool CHANGED = ImGui::SliderFloat("#", &val,
static_cast<float>(min), static_cast<float>(max), "%.3f",
ImGuiInputTextFlags_EnterReturnsTrue);
if (CHANGED)
{
value = val;
}
return CHANGED;
}
bool SHEditorUI::InputVec2(const std::string& label, SHVec2& value)
{
static const std::vector<std::string> COMPONENT_LABELS = { "X", "Y" };
return SHEditorWidgets::DragN<float, 2>(label, COMPONENT_LABELS, { &value.x, &value.y });
}
bool SHEditorUI::InputVec3(const std::string& label, SHVec3& value, float speed)
{
static const std::vector<std::string> COMPONENT_LABELS = { "X", "Y", "Z"};
return SHEditorWidgets::DragN<float, 3>(label, COMPONENT_LABELS, { &value.x, &value.y, &value.z }, speed, "%.3f");
}
bool SHEditorUI::InputTextField(const std::string& label, std::string& value)
{
std::array<char, TEXT_FIELD_MAX_LENGTH> buffer = { '\0' };
strcpy_s(buffer.data(), TEXT_FIELD_MAX_LENGTH, value.c_str());
ImGui::Text(label.c_str());
ImGui::SameLine();
const bool CHANGED = ImGui::InputText("#", &buffer[0], TEXT_FIELD_MAX_LENGTH);
if (CHANGED)
{
value = std::string(buffer.data(), buffer.data() + TEXT_FIELD_MAX_LENGTH);
}
return CHANGED;
}
bool SHEditorUI::InputEnumCombo(const std::string& label, int& v, const std::vector<std::string>& enumNames)
{
// Clamp input value
const std::string& INITIAL_NAME = v >= static_cast<int>(enumNames.size()) ? "Unknown" : enumNames[v];
bool b = false;
ImGui::Text(label.c_str());
ImGui::SameLine();
if (ImGui::BeginCombo("#", INITIAL_NAME.c_str(), ImGuiComboFlags_None))
{
for (int i = 0; i < enumNames.size(); ++i)
{
const bool IS_SELECTED = v == i;
if (ImGui::Selectable(enumNames[i].c_str(), IS_SELECTED))
{
v = i;
b = true;
}
if (IS_SELECTED)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
return b;
}
}

View File

@ -0,0 +1,286 @@
/************************************************************************************//*!
\file SHEditorUI.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\par email: t.yanchongclarence\@digipen.edu
\date Sep 27, 2022
\brief Defines a class that contains wrapper functions for ImGui.
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
// Standard Library
#include <functional> // std::function
#include <string> // std::string
// Project Includes
#include "Math/Vector/SHVec2.h"
#include "Math/Vector/SHVec3.h"
#include "Math/Vector/SHVec4.h"
#include "Math/SHMatrix.h"
namespace SHADE
{
/// <summary>
/// Static class that contains useful functions for Editor UI using ImGui.
/// </summary>
class SH_API SHEditorUI final
{
public:
/*-----------------------------------------------------------------------------*/
/* Constants */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Maximum length of a string supported by InputTextField()
/// </summary>
static constexpr size_t TEXT_FIELD_MAX_LENGTH = 256;
/*-----------------------------------------------------------------------------*/
/* ImGui Wrapper Functions - ID Stack */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Marks the start of a stack of ImGui widgets with the specified id.
/// <br/>
/// Wraps up ImGui::PushID().
/// </summary>
/// <param name="id">String-based ID.</param>
static void PushID(const std::string& id);
/// <summary>
/// Marks the start of a stack of ImGui widgets with the specified id.
/// <br/>
/// Wraps up ImGui::PushID().
/// </summary>
/// <param name="id">Integer-based ID.</param>
static void PushID(int id);
/// <summary>
/// Marks the end of a stack of ImGui widgets from the last PushID() call.
/// <br/>
/// Wraps up ImGui::PopID().
/// </summary>
static void PopID();
/*-----------------------------------------------------------------------------*/
/* ImGui Wrapper Functions - Indent */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Indents the widgets rendered after this call.
/// <br/>
/// Wraps up ImGui::Indent().
/// </summary>
static void Indent();
/// <summary>
/// Unindents the widgets rendered after this call.
/// <br/>
/// Wraps up ImGui::Unindent().
/// </summary>
static void Unindent();
/*-----------------------------------------------------------------------------*/
/* ImGui Wrapper Functions - Organizers */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Creates a collapsing title header.
/// <br/>
/// Wraps up ImGui::CollapsingHeader().
/// </summary>
/// <param name="title">Label for the header.</param>
/// <returns>True if the header is open, false otherwise.</returns>
static bool CollapsingHeader(const std::string& title);
static void SameLine();
static void Separator();
/*-----------------------------------------------------------------------------*/
/* ImGui Wrapper Functions - Menu */
/*-----------------------------------------------------------------------------*/
static bool BeginMenu(const std::string& label);
static bool BeginMenu(const std::string& label, const char* icon);
static void EndMenu();
/*-----------------------------------------------------------------------------*/
/* ImGui Wrapper Functions - Pop Ups */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Marks the start of a definition of a mini pop up that can show options.
/// <br/>
/// Wraps up ImGui::BeginPopup().
/// </summary>
/// <param name="label">Label used to identify this widget.</param>
/// <returns>Whether or not the pop up is open.</returns>
static bool BeginPopup(const std::string& label);
static bool BeginPopupContextItem(const std::string& label);
/// <summary>
/// Marks the end of a definition of a mini pop up that can show options.
/// <br/>
/// Wraps up ImGui::EndPopup().
/// </summary>
static void EndPopup();
/// <summary>
/// Opens the popup that was defined with the specified label.
/// <br/>
/// Wraps up ImGui::OpenPopup().
/// </summary>
static void OpenPopup(const std::string& label);
/// <summary>
/// Creates a menu item in the list of items for a mini popup.
/// <br/>
/// Wraps up ImGui::MenuItem().
/// </summary>
/// <param name="label">Label used to identify this widget.</param>
/// <returns>Whether or not the menu item was selected.</returns>
static bool MenuItem(const std::string& label);
/*-----------------------------------------------------------------------------*/
/* ImGui Wrapper Functions - Widgets */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Creates a visual text widget.
/// <br/>
/// Wraps up ImGui::Text().
/// </summary>
/// <param name="title">Text to display.</param>
static void Text(const std::string& title);
/// <summary>
/// Creates a small inline button widget.
/// <br/>
/// Wraps up ImGui::SmallButton().
/// </summary>
/// <param name="title">Text to display.</param>
/// <returns>True if button was pressed.</returns>
static bool SmallButton(const std::string& title);
/// <summary>
/// Creates a inline button widget.
/// <br/>
/// Wraps up ImGui::Button().
/// </summary>
/// <param name="title">Text to display.</param>
/// <returns>True if button was pressed.</returns>
static bool Button(const std::string& title);
static bool Selectable(const std::string& label);
static bool Selectable(const std::string& label, const char* icon);
/// <summary>
/// Creates a checkbox widget for boolean input.
/// <br/>
/// Wraps up ImGui::Checkbox().
/// </summary>
/// <param name="label">Label used to identify this widget.</param>
/// <param name="value">Reference to the variable to store the result.</param>
/// <returns>True if the value was changed.</returns>
static bool InputCheckbox(const std::string& label, bool& value);
/// <summary>
/// Creates a integer field widget for integer input.
/// <br/>
/// Wraps up ImGui::InputInt().
/// </summary>
/// <param name="label">Label used to identify this widget.</param>
/// <param name="value">Reference to the variable to store the result.</param>
/// <returns>True if the value was changed.</returns>
static bool InputInt(const std::string& label, int& value);
/// <summary>
/// Creates a integer field widget for unsigned integer input.
/// <br/>
/// Wraps up ImGui::InputInt() with an additional clamping of values.
/// <br/>
/// Note: As a result, the range of this function limits it to the maximum
/// value of a 32-bit signed integer instead of a 32-bit unsigned integer.
/// </summary>
/// <param name="label">Label used to identify this widget.</param>
/// <param name="value">Reference to the variable to store the result.</param>
/// <returns>True if the value was changed.</returns>
static bool InputUnsignedInt(const std::string& label, unsigned int& value);
/// <summary>
/// Creates a decimal field widget for single precision float input.
/// <br/>
/// Wraps up ImGui::InputFloat().
/// </summary>
/// <param name="label">Label used to identify this widget.</param>
/// <param name="value">Reference to the variable to store the result.</param>
/// <returns>True if the value was changed.</returns>
static bool InputFloat(const std::string& label, float& value);
/// <summary>
/// Creates a decimal field widget for double precision float input.
/// <br/>
/// Wraps up ImGui::InputDouble().
/// </summary>
/// <param name="label">Label used to identify this widget.</param>
/// <param name="value">Reference to the variable to store the result.</param>
/// <returns>True if the value was changed.</returns>
static bool InputDouble(const std::string& label, double& value);
/// <summary>
/// Creates a decimal field widget for double input with increments of higher
/// steps meant for angle variables.
/// <br/>
/// Wraps up ImGui::InputDouble().
/// </summary>
/// <param name="label">Label used to identify this widget.</param>
/// <param name="value">Reference to the variable to store the result.</param>
/// <returns>True if the value was changed.</returns>
static bool InputAngle(const std::string& label, double& value);
/// <summary>
/// Creates a double slider field widget for double input.
/// <br/>
/// Wraps up ImGui::InputSliderFloat().
/// </summary>
/// <param name="label">Label used to identify this widget.</param>
/// <param name="min">Minimum value of the slider.</param>
/// <param name="max">Maximum value of the slider.</param>
/// <param name="value">Reference to the variable to store the result.</param>
/// <returns>True if the value was changed.</returns>
static bool InputSlider(const std::string& label, double min, double max, double& value);
/// <summary>
/// Creates a 2x double field widget for Vector2 input.
/// <br/>
/// Wraps up ImGui::InputFloat2().
/// </summary>
/// <param name="label">Label used to identify this widget.</param>
/// <param name="value">Reference to the variable to store the result.</param>
/// <returns>True if the value was changed.</returns>
static bool InputVec2(const std::string& label, SHVec2& value);
/// <summary>
/// Creates a 3x double field widget for Vector3 input.
/// <br/>
/// Wraps up ImGui::InputFloat3().
/// </summary>
/// <param name="label">Label used to identify this widget.</param>
/// <param name="value">Reference to the variable to store the result.</param>
/// <returns>True if the value was changed.</returns>
static bool InputVec3(const std::string& label, SHVec3& value, float speed = 0.1f);
/// <summary>
/// Creates a text field widget for string input.
/// <br/>
/// Wraps up ImGui::InputText().
/// </summary>
/// <param name="label">Label used to identify this widget.</param>
/// <param name="value">Reference to the variable to store the result.</param>
/// <returns>True if the value was changed.</returns>
static bool InputTextField(const std::string& label, std::string& value);
/// <summary>
/// Creates a combo box for enumeration input.
/// </summary>
/// <typeparam name="Enum">The type of enum to input.</typeparam>
/// <param name="label">The name of the input.</param>
/// <param name="v">The reference to the value to modify.</param>
/// <param name="maxVal">The maximum value of the enum.</param>
/// <param name="toStrFn">
/// Conversion function from the type of enum to C-style string.
/// </param>
/// <returns>Whether the value was modified.</returns>
template<typename Enum>
static bool InputEnumCombo(const std::string& label, Enum& v, int maxVal, std::function<const char*(Enum)> toStrFn);
/// <summary>
/// Creates a combo box for enumeration input using a specified list of names.
/// </summary>
/// <param name="label">The name of the input.</param>
/// <param name="v">The reference to the value to modify.</param>
/// <param name="enumNames">Vector of names for each enumeration value.</param>
/// <returns>Whether the value was modified.</returns>
static bool InputEnumCombo(const std::string& label, int& v, const std::vector<std::string>& enumNames);
private:
// Prevent instantiation of this static class
SHEditorUI() = delete;
};
}
#include "SHEditorUI.hpp"

View File

@ -0,0 +1,51 @@
/************************************************************************************//*!
\file SHEditorUI.hpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Sep 27, 2022
\brief Contains the implementation of editor inspector template functions.
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.
*//*************************************************************************************/
// Primary Header
#include "SHEditorUI.h"
// External Dependencies
#include <imgui.h>
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* ImGui Wrapper Functions - Widgets */
/*---------------------------------------------------------------------------------*/
template<typename Enum>
inline bool SHEditorUI::InputEnumCombo(const std::string& label, Enum& v, int maxVal, std::function<const char* (Enum)> toStrFn)
{
std::vector<Enum> values;
for (int i = 0; i <= maxVal; ++i)
{
values.emplace_back(static_cast<Enum>(i));
}
bool b = false;
if (ImGui::BeginCombo(label.c_str(), toStrFn(v), ImGuiComboFlags_None))
{
for (int i = 0; i <= maxVal; ++i)
{
const auto VALUE = values[i];
const bool IS_SELECTED = v == VALUE;
if (ImGui::Selectable(toStrFn(VALUE), IS_SELECTED))
{
v = VALUE;
b = true;
}
if (IS_SELECTED)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
return b;
}
}

View File

@ -12,6 +12,7 @@
#include "Math/SHMath.h"
#include "Command/SHCommandManager.h"
#include "SHImGuiHelpers.hpp"
#include "SH_API.h"
//#==============================================================#
//|| Library Includes ||
@ -23,165 +24,315 @@
namespace SHADE
{
//#==============================================================#
//|| Custom Widgets ||
//#==============================================================#
static bool Splitter(bool verticalSplit, float thickness, float* size1, float* size2, float minSize1, float minSize2, float splitterAxisSize = -1.0f)
class SH_API SHEditorWidgets
{
ImGuiWindow* window = ImGui::GetCurrentWindow();
const ImGuiID id = window->GetID("##Splitter");
ImRect bb;
bb.Min = window->DC.CursorPos + (verticalSplit ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1));
bb.Max = bb.Min + (verticalSplit ? ImVec2(thickness, splitterAxisSize) : ImVec2(splitterAxisSize, thickness));
return ImGui::SplitterBehavior(bb, id, verticalSplit ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, minSize1, minSize2, 0.0f);
}
public:
//#==============================================================#
//|| Constructor ||
//#==============================================================#
SHEditorWidgets() = delete;
template <typename T, std::size_t N>
static bool DragN(const std::string& fieldLabel, std::vector<std::string>const& componentLabels,
std::vector<T*> values, float speed = 0.1f, const char* displayFormat = "", T valueMin = T(), T valueMax = T(),
ImGuiSliderFlags flags = 0)
{
const ImGuiWindow* const window = ImGui::GetCurrentWindow();
if (window->SkipItems)
return false;
const ImGuiContext& g = *GImGui;
bool valueChanged = false;
ImGui::BeginGroup();
ImGui::PushID(fieldLabel.c_str());
PushMultiItemsWidthsAndLabels(componentLabels, 0.0f);
ImGui::BeginColumns("DragVecCol", 2, ImGuiOldColumnFlags_NoBorder | ImGuiOldColumnFlags_NoResize);
ImGui::SetColumnWidth(-1, 80.0f);
ImGui::Text(fieldLabel.c_str());
ImGui::NextColumn();
for (std::size_t i = 0; i < N; ++i)
//#==============================================================#
//|| Custom Widgets ||
//#==============================================================#
static bool Splitter(bool verticalSplit, float thickness, float* size1, float* size2, float minSize1, float minSize2, float splitterAxisSize = -1.0f)
{
ImGui::PushID(static_cast<int>(i));
ImGui::TextUnformatted(componentLabels[i].c_str(), ImGui::FindRenderedTextEnd(componentLabels[i].c_str())); ImGui::SameLine();
ImGui::SetNextItemWidth(80.0f);
valueChanged |= ImGui::DragFloat("##v", values[i], speed, valueMin, valueMax, displayFormat, flags);
const ImVec2 min = ImGui::GetItemRectMin();
const ImVec2 max = ImGui::GetItemRectMax();
const float spacing = g.Style.FrameRounding;
const float halfSpacing = spacing / 2;
window->DrawList->AddLine({ min.x + spacing, max.y - halfSpacing }, { max.x - spacing, max.y - halfSpacing },
ImGuiColors::colors[i], 4);
ImGui::SameLine(0, g.Style.ItemInnerSpacing.x);
ImGui::PopID();
ImGui::PopItemWidth();
ImGuiWindow* window = ImGui::GetCurrentWindow();
const ImGuiID id = window->GetID("##Splitter");
ImRect bb;
bb.Min = window->DC.CursorPos + (verticalSplit ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1));
bb.Max = bb.Min + (verticalSplit ? ImVec2(thickness, splitterAxisSize) : ImVec2(splitterAxisSize, thickness));
return ImGui::SplitterBehavior(bb, id, verticalSplit ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, minSize1, minSize2, 0.0f);
}
ImGui::EndColumns();
ImGui::PopID();
ImGui::EndGroup();
return valueChanged;
}
template <typename T, std::size_t N>
static bool DragN(const std::string& fieldLabel, std::vector<std::string>const& componentLabels,
std::vector<T*> values, float speed = 0.1f, const char* displayFormat = "", T valueMin = T(), T valueMax = T(),
ImGuiSliderFlags flags = 0)
{
const ImGuiWindow* const window = ImGui::GetCurrentWindow();
if (window->SkipItems)
return false;
const ImGuiContext& g = *GImGui;
bool valueChanged = false;
ImGui::BeginGroup();
ImGui::PushID(fieldLabel.c_str());
PushMultiItemsWidthsAndLabels(componentLabels, 0.0f);
ImGui::BeginColumns("DragVecCol", 2, ImGuiOldColumnFlags_NoBorder | ImGuiOldColumnFlags_NoResize);
ImGui::SetColumnWidth(-1, 80.0f);
ImGui::Text(fieldLabel.c_str());
ImGui::NextColumn();
for (std::size_t i = 0; i < N; ++i)
{
ImGui::PushID(static_cast<int>(i));
ImGui::TextUnformatted(componentLabels[i].c_str(), ImGui::FindRenderedTextEnd(componentLabels[i].c_str())); ImGui::SameLine();
ImGui::SetNextItemWidth(80.0f);
valueChanged |= ImGui::DragFloat("##v", values[i], speed, valueMin, valueMax, displayFormat, flags);
const ImVec2 min = ImGui::GetItemRectMin();
const ImVec2 max = ImGui::GetItemRectMax();
const float spacing = g.Style.FrameRounding;
const float halfSpacing = spacing / 2;
window->DrawList->AddLine({ min.x + spacing, max.y - halfSpacing }, { max.x - spacing, max.y - halfSpacing },
ImGuiColors::colors[i], 4);
ImGui::SameLine(0, g.Style.ItemInnerSpacing.x);
ImGui::PopID();
ImGui::PopItemWidth();
}
ImGui::EndColumns();
ImGui::PopID();
ImGui::EndGroup();
return valueChanged;
}
static bool DragVec2(const std::string& fieldLabel, 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,
ImGuiSliderFlags flags = 0)
{
SHVec2 values = get();
bool changed = false;
if (DragN<float, 2>(fieldLabel, componentLabels, {&values.x, &values.y}, speed, displayFormat, valueMin, valueMax, flags))
std::function<void(SHVec2)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
ImGuiSliderFlags flags = 0)
{
changed = true;
SHVec2 values = get();
bool changed = false;
if (DragN<float, 2>(fieldLabel, componentLabels, { &values.x, &values.y }, speed, displayFormat, valueMin, valueMax, flags))
{
changed = true;
}
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)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false);
}
return changed;
}
if (changed)
static bool DragVec3(const std::string& fieldLabel, 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,
ImGuiSliderFlags flags = 0)
{
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false);
else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), true);
else if(ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false);
SHVec3 values = get();
bool changed = false;
if (DragN<float, 3>(fieldLabel, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags))
{
changed = true;
}
if (changed)
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false);
}
return changed;
}
return changed;
}
static bool DragVec3(const std::string& fieldLabel, 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,
ImGuiSliderFlags flags = 0)
{
SHVec3 values = get();
bool changed = false;
if (DragN<float, 3>(fieldLabel, componentLabels, {&values.x, &values.y, &values.z}, speed, displayFormat, valueMin, valueMax, flags))
static bool DragVec4(const std::string& fieldLabel, 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,
ImGuiSliderFlags flags = 0)
{
changed = true;
SHVec4 values = get();
bool changed = false;
if (DragN<float, 4>(fieldLabel, componentLabels, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags))
{
changed = true;
}
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)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), false);
}
return changed;
}
if (changed)
//#==============================================================#
//|| Widget Extensions ||
//#==============================================================#
static bool CheckBox(std::string const& label, std::function<bool(void)> get, std::function<void(bool const&)> set)
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false);
else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), true);
else if(ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false);
bool value = get();
if (ImGui::Checkbox(label.c_str(), &value))
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<bool>>(get(), value, set)), false);
return true;
}
return false;
}
return changed;
}
static bool DragVec4(const std::string& fieldLabel, 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,
ImGuiSliderFlags flags = 0)
{
SHVec4 values = get();
bool changed = false;
if (DragN<float, 4>(fieldLabel, componentLabels, {&values.x, &values.y, &values.z, &values.w}, speed, displayFormat, valueMin, valueMax, flags))
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)
{
changed = true;
}
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)), false);
else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), true);
else if(ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), false);
}
return changed;
}
//#==============================================================#
//|| Widget Extensions ||
//#==============================================================#
static bool CheckBox(std::string const& label, std::function<bool(void)> get, std::function<void(bool const&)> set)
{
bool value = get();
if (ImGui::Checkbox(label.c_str(), &value))
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<bool>>(get(), value, set)), false);
T type = get();
for (size_t i = 0; i < listTypes.size(); i++)
{
if (ImGui::RadioButton(listLabels[i].c_str(), type == listTypes[i]))
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), listTypes[i], set)), false);
}
ImGui::SameLine();
}
return true;
}
return false;
}
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)
{
T type = get();
for (size_t i = 0; i < listTypes.size(); i++)
static bool InputText(const std::string& label, const std::function<std::string(void)> get,
const std::function<void(std::string)> set, ImGuiInputTextFlags flag = 0,
ImGuiInputTextCallback callback = (ImGuiInputTextCallback)0, void* userData = (void*)0)
{
if (ImGui::RadioButton(listLabels[i].c_str(), type == listTypes[i]))
std::string text = get();
if (ImGui::InputText(label.c_str(), &text, flag, callback, userData))
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), listTypes[i], set)), false);
if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<std::string>>(get(), text, set)), false);
return true;
}
ImGui::SameLine();
return false;
}
return true;
}
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))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
return true;
}
return false;
}
static bool DragFloat(const std::string& fieldLabel, std::function<float(void)> get, std::function<void(float const&)> set,
float speed = 0.1f, float p_min = float(), float p_max = float(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{
float value = get();
//bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags);
if (ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags))
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
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;
}
return false;
}
static bool DragInt(const std::string& fieldLabel, std::function<int(void)> get, std::function<void(int const&)> set,
float speed = 1.0f, int p_min = int(), int p_max = int(), const char* displayFormat = "%d", ImGuiSliderFlags flags = 0)
{
int value = get();
//bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags);
if (ImGui::DragInt(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags))
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
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);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
return true;
}
return false;
}
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,
const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{
T value = get();
if (ImGui::SliderScalar(fieldLabel.c_str(), data_type, &value, &min, &max, displayFormat, flags))
{
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)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), true);
return true;
}
return false;
}
static bool SliderFloat(const std::string& fieldLabel, float min, float max, std::function<float(void)> get, std::function<void(float const&)> set,
const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{
float value = get();
if (ImGui::SliderFloat(fieldLabel.c_str(), &value, min, max, displayFormat, flags))
{
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)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), true);
return true;
}
return false;
}
static bool SliderInt(const std::string& fieldLabel, int min, int max, std::function<int(void)> get, std::function<void(int const&)> set,
const char* displayFormat = "%d", ImGuiSliderFlags flags = 0)
{
int value = get();
if (ImGui::SliderInt(fieldLabel.c_str(), &value, min, max, displayFormat, flags))
{
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;
}
return false;
}
static bool ComboBox(const std::string& fieldLabel, std::vector<const char*> list, std::function<int(void)> get, std::function<void(int const&)> set)
{
bool edited = false;
int selected = get();
ImGui::PushID(fieldLabel.c_str());
ImGui::Text(fieldLabel.c_str()); ImGui::SameLine();
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);
}
ImGui::PopID();
return edited;
}
};
}//namespace SHADE

View File

@ -8,3 +8,5 @@ typedef uint32_t SHEventHandle;
constexpr SHEventIdentifier SH_EXAMPLE_EVENT{0};
constexpr SHEventIdentifier SH_ENTITY_DESTROYED_EVENT{ 1 };
constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT{ 2 };
constexpr SHEventIdentifier SH_COMPONENT_ADDED_EVENT{ 3 };
constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT{ 4 };

View File

@ -9,12 +9,31 @@
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
//TODO Legacy code. Delete soon
#include <chrono>
#include <cassert>
#include <SHpch.h>
#include "SHFramerateController.h"
#include "../Tools/SHLogger.h"
namespace SHADE
{
double SHFrameRateController::rawDeltaTime = 0.0;
std::chrono::steady_clock::time_point SHFrameRateController::prevFrameTime = std::chrono::high_resolution_clock::now();
void SHFrameRateController::UpdateFRC() noexcept
{
std::chrono::duration<double> deltaTime;
deltaTime = std::chrono::high_resolution_clock::now() - prevFrameTime;
prevFrameTime = std::chrono::high_resolution_clock::now();
rawDeltaTime = deltaTime.count();
}
}
//TODO Legacy code. Delete soon
#if 0
namespace SHADE
{
//Init statics
@ -132,3 +151,4 @@ namespace SHADE
}
}
}
#endif

View File

@ -13,6 +13,38 @@
#define SH_FRAMERATECONTROLLER_H
#pragma once
#include <chrono>
#include "Tools/SHLogger.h"
#include "SH_API.h"
namespace SHADE
{
class SH_API SHFrameRateController
{
private:
//Varying delta time. The actual time it took for every frame
static double rawDeltaTime;
static std::chrono::steady_clock::time_point prevFrameTime;
public:
//Gets the raw delta time
static inline double GetRawDeltaTime() noexcept
{
return rawDeltaTime;
}
//Updates the raw delta time accordingly
static void UpdateFRC() noexcept;
};
}
//TODO Legacy code. Delete soon
#if 0
#include "../Scene/SHScene.h"
namespace SHADE
@ -56,7 +88,19 @@ namespace SHADE
//halt execution of the current scene and prepare
//execution of the next
static inline void SetNextScene(SHScene* const next) { nextScene = next; }
};
}
#endif
#endif

View File

@ -2,7 +2,6 @@
#include "SHFileSystem.h"
#include "fileapi.h"
#include <filesystem>
#include <cassert>
#include <queue>
namespace SHADE
@ -28,7 +27,10 @@ namespace SHADE
auto const count = static_cast<FolderCounter>(folders[here]->subFolders.size());
assert(count < FOLDER_MAX_COUNT, "Max subfolders reached\n");
if (count >= FOLDER_MAX_COUNT)
{
SHLOG_ERROR("Max subfolder reached: {}\n", name);
}
auto const location = static_cast<FolderLocation>(count);
@ -37,7 +39,10 @@ namespace SHADE
return location;
}
assert(folders.contains(here), "Folder creation location does not exist/invalid\n");
if (!folders.contains(here))
{
SHLOG_ERROR("Folder creation location does not exist/invalid: {}\n", here);
}
auto const count = static_cast<FolderCounter>(folders[here]->subFolders.size());
@ -45,7 +50,11 @@ namespace SHADE
location <<= FOLDER_BIT_ALLOCATE;
location |= count;
assert(count < FOLDER_MAX_COUNT, "Max subfolders reached\n");
if (count >= FOLDER_MAX_COUNT)
{
SHLOG_ERROR("Max subfolder reached: {}\n", name);
}
CreateFolder(folders[0]->path, here, location, name);
return location;
@ -53,7 +62,10 @@ namespace SHADE
bool SHFileSystem::DeleteFolder(FolderPointer location) noexcept
{
assert(folders.contains(location->id), "Delete target does not exist/invalid.\n");
if (!folders.contains(location->id))
{
SHLOG_ERROR("Delete target does not exist/invalid: {}\n", location->name);
}
for (auto const& subFolder : folders[location->id]->subFolders)
{
@ -116,10 +128,11 @@ namespace SHADE
FolderPointer SHFileSystem::CreateFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept
{
assert(
CreateDirectoryA(path.c_str(), nullptr),
"Failed to create folder\n"
);
if (!CreateDirectoryA(path.c_str(), nullptr))
{
SHLOG_ERROR("Failed to create folder: {}\n", path);
}
folders[location] = std::make_unique<SHFolder>(location, name);
folders[location]->path = path;

View File

@ -24,7 +24,7 @@ namespace SHADE
/***************************************************************************/
SHVkCommandBuffer::~SHVkCommandBuffer(void) noexcept
{
if (vkCommandBuffer)
if (vkCommandBuffer && parentPool)
parentPool->GetLogicalDevice()->GetVkLogicalDevice().freeCommandBuffers(parentPool->GetVkCommandPool(), commandBufferCount, &vkCommandBuffer);
}

View File

@ -102,8 +102,6 @@ namespace SHADE
logicalDeviceHdl = rhs.logicalDeviceHdl;
transient = rhs.transient;
static_cast<ISelfHandle<SHVkCommandPool>&>(*this) = static_cast<ISelfHandle<SHVkCommandPool>&>(rhs);
rhs.vkCommandPool = VK_NULL_HANDLE;
return *this;

View File

@ -39,8 +39,10 @@ namespace SHADE
std::vector<vk::DescriptorPoolSize> Limits =
{
{ vk::DescriptorType::eCombinedImageSampler, 100 },
{ vk::DescriptorType::eUniformBuffer, 100 },
{ vk::DescriptorType::eUniformBufferDynamic, 100 }
{ vk::DescriptorType::eUniformBuffer, 100 },
{ vk::DescriptorType::eUniformBufferDynamic, 100 },
{ vk::DescriptorType::eStorageImage, 100},
{ vk::DescriptorType::eStorageBufferDynamic, 100 }
};
/// <summary>
/// Maximum number of descriptor sets allowed

View File

@ -155,7 +155,7 @@ namespace SHADE
*/
/***************************************************************************/
void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<std::pair<Handle<SHVkImageView>, Handle<SHVkSampler>>> const& imageViewsAndSamplers) noexcept
void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept
{
// Find the target writeDescSet
BindingAndSetHash writeHash = binding;
@ -170,9 +170,10 @@ namespace SHADE
for (uint32_t i = 0; i < imageViewsAndSamplers.size(); ++i)
{
// write sampler and image view
auto& ivs = imageViewsAndSamplers[i];
writeInfo.descImageInfos[i].imageView = ivs.first->GetImageView();
writeInfo.descImageInfos[i].sampler = ivs.second->GetVkSampler();
auto& [view, sampler, layout] = imageViewsAndSamplers[i];
writeInfo.descImageInfos[i].imageView = view->GetImageView();
writeInfo.descImageInfos[i].sampler = sampler->GetVkSampler();
writeInfo.descImageInfos[i].imageLayout = layout;
}
}
@ -207,7 +208,7 @@ namespace SHADE
BindingAndSetHash bsHash = SHVkUtil::GenBindingSetHash(set, binding);
// to index a set
uint32_t setIndex = setIndexing[bsHash];
uint32_t setIndex = setIndexing[set];
// to index a write for a binding
uint32_t writeInfoIndex = updater.writeHashMap[bsHash];
@ -232,7 +233,7 @@ namespace SHADE
BindingAndSetHash bsHash = SHVkUtil::GenBindingSetHash(set, binding);
// to index a set
uint32_t setIndex = setIndexing[bsHash];
uint32_t setIndex = setIndexing[set];
// to index a write for a binding
uint32_t writeInfoIndex = updater.writeHashMap[bsHash];

View File

@ -1,5 +1,7 @@
#pragma once
#include <tuple>
// Project Includes
#include "Graphics/SHVulkanIncludes.h"
#include "Resource/Handle.h"
@ -63,7 +65,7 @@ namespace SHADE
void UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept;
void UpdateDescriptorSetBuffer(uint32_t set, uint32_t binding) noexcept;
void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<std::pair<Handle<SHVkImageView>, Handle<SHVkSampler>>> const& imageViewsAndSamplers) noexcept;
void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept;
void ModifyWriteDescBuffer (uint32_t set, uint32_t binding, std::span<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept;

View File

@ -16,6 +16,7 @@
#include "Graphics/Framebuffer/SHVkFramebuffer.h"
#include "Graphics/Images/SHVkImageView.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/Images/SHVkSampler.h"
namespace SHADE
{
@ -85,6 +86,17 @@ namespace SHADE
}
uint32_t SHVkLogicalDevice::ComputeAlignedBufferSize(uint32_t originalSize, size_t alignmentSize) const noexcept
{
uint32_t alignedSize = originalSize;
//uint32_t minBuffer
if (alignmentSize > 0)
{
alignedSize = (alignedSize + static_cast<uint32_t>(alignmentSize) - 1) & ~(alignmentSize - 1);
}
return alignedSize;
}
/***************************************************************************/
/*!
@ -176,12 +188,15 @@ namespace SHADE
// point and lines fill mode
features.fillModeNonSolid = true;
features.samplerAnisotropy = VK_TRUE;
features.multiDrawIndirect = true;
// for wide lines
features.wideLines = true;
vk::PhysicalDeviceDescriptorIndexingFeatures descIndexingFeature{};
descIndexingFeature.descriptorBindingVariableDescriptorCount = true;
descIndexingFeature.shaderSampledImageArrayNonUniformIndexing = true;
descIndexingFeature.runtimeDescriptorArray = true;
// Prepare to create the device
vk::DeviceCreateInfo deviceCreateInfo
@ -236,6 +251,22 @@ namespace SHADE
vkLogicalDevice.destroy(nullptr);
}
SHVkLogicalDevice& SHVkLogicalDevice::operator=(SHVkLogicalDevice&& rhs) noexcept
{
if (this == &rhs)
return *this;
vkLogicalDevice = std::move (rhs.vkLogicalDevice);
queueFamilyIndices = std::move (rhs.queueFamilyIndices);
vmaAllocator = rhs.vmaAllocator;
nonDedicatedBestIndex = 0;
parentPhysicalDeviceHdl = rhs.parentPhysicalDeviceHdl;
rhs.vkLogicalDevice = VK_NULL_HANDLE;
return *this;
}
/***************************************************************************/
/*!
@ -288,13 +319,12 @@ namespace SHADE
uint32_t SHVkLogicalDevice::PadUBOSize(uint32_t originalSize) const noexcept
{
uint32_t alignedSize = originalSize;
//uint32_t minBuffer
if (uboBufferMemoryAlignment > 0)
{
alignedSize = (alignedSize + uboBufferMemoryAlignment - 1) & ~(uboBufferMemoryAlignment - 1);
}
return alignedSize;
return ComputeAlignedBufferSize(originalSize, uboBufferMemoryAlignment);
}
uint32_t SHVkLogicalDevice::PadSSBOSize(uint32_t originalSize) const noexcept
{
return ComputeAlignedBufferSize(originalSize, ssboBufferMemoryAlignment);
}
/***************************************************************************/
@ -499,6 +529,11 @@ namespace SHADE
}
Handle<SHVkSampler> SHVkLogicalDevice::CreateSampler(const SHVkSamplerParams& params) noexcept
{
return SHVkInstance::GetResourceManager().Create <SHVkSampler>(GetHandle(), params);
}
Handle<SHVkRenderpass> SHVkLogicalDevice::CreateRenderpass(std::span<vk::AttachmentDescription> const vkDescriptions, std::vector<SHVkSubpassParams> const& subpasses) noexcept
{
return SHVkInstance::GetResourceManager().Create <SHVkRenderpass>(GetHandle(), vkDescriptions, subpasses);

View File

@ -21,7 +21,6 @@
#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
#include "Graphics/Images/SHVkImage.h"
namespace SHADE
{
/*-----------------------------------------------------------------------*/
@ -41,6 +40,8 @@ namespace SHADE
class SHShaderBlockInterface;
class SHVkDescriptorSetGroup;
class SHSubpass;
class SHVkSampler;
struct SHVkSamplerParams;
/***************************************************************************/
/*!
@ -102,6 +103,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
void InitializeVMA (void) noexcept;
void InitializeQueues (std::initializer_list<SHQueueParams> queueCreateParams) noexcept;
uint32_t ComputeAlignedBufferSize(uint32_t originalSize, size_t typeSize) const noexcept;
public:
/*-----------------------------------------------------------------------*/
@ -113,7 +115,7 @@ namespace SHADE
~SHVkLogicalDevice (void) noexcept;
SHVkLogicalDevice& operator= (SHVkLogicalDevice const& rhs) noexcept = default;
SHVkLogicalDevice& operator= (SHVkLogicalDevice&& rhs) noexcept = default;
SHVkLogicalDevice& operator= (SHVkLogicalDevice&& rhs) noexcept;
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER VARIABLES */
@ -121,7 +123,8 @@ namespace SHADE
// Miscellaneous functions
void WaitIdle (void) noexcept;
uint32_t FindMemoryType (uint32_t typeFilter, vk::MemoryPropertyFlags properties);
uint32_t PadUBOSize (uint32_t originalSize) const noexcept;
uint32_t PadUBOSize(uint32_t originalSize) const noexcept;
uint32_t PadSSBOSize(uint32_t originalSize) const noexcept;
// creation functions
Handle<SHVkSurface> CreateSurface (HWND const& windowHandle) const noexcept;
@ -178,6 +181,7 @@ namespace SHADE
Handle<SHVkRenderpass> const& renderpassHdl,
Handle<SHSubpass> subpass
) 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::span<vk::SubpassDescription> const spDescs, std::span<vk::SubpassDependency> const spDeps) noexcept;

View File

@ -98,6 +98,51 @@ namespace SHADE
return *this;
}
void SHVkFramebuffer::HandleResize(Handle<SHVkRenderpass> const& renderpassHdl, std::vector<Handle<SHVkImageView>> const& attachments, uint32_t inWidth, uint32_t inHeight) noexcept
{
width = inWidth;
height = inHeight;
for (auto& attachment : attachments)
{
// Not sure if its an error to pass in diff dimension images.
if (attachment->GetParentImage()->GetWidth() != (*attachments.begin())->GetParentImage()->GetWidth() || attachment->GetParentImage()->GetHeight() != (*attachments.begin())->GetParentImage()->GetHeight())
{
SHLOG_ERROR("Dimensions of images not same as each other. Cannot create framebuffer.");
return;
}
}
std::vector<vk::ImageView> vkAttachments(attachments.size());
uint32_t i = 0;
for(auto const& attachment : attachments)
{
vkAttachments[i] = attachment->GetImageView();
++i;
}
vk::FramebufferCreateInfo createInfo
{
.renderPass = renderpassHdl->GetVkRenderpass(),
.attachmentCount = static_cast<uint32_t>(vkAttachments.size()),
.pAttachments = vkAttachments.data(),
.width = width,
.height = height,
.layers = 1 // TODO: Find out why this is 1
};
if (auto result = logicalDeviceHdl->GetVkLogicalDevice().createFramebuffer(&createInfo, nullptr, &vkFramebuffer); result != vk::Result::eSuccess)
{
SHVulkanDebugUtil::ReportVkError(result, "Failed to create framebuffer. ");
return;
}
else
{
SHVulkanDebugUtil::ReportVkSuccess("Successfully created framebuffer. ");
}
}
/***************************************************************************/
/*!

View File

@ -37,6 +37,8 @@ namespace SHADE
SHVkFramebuffer(SHVkFramebuffer&& rhs) noexcept;
SHVkFramebuffer& operator=(SHVkFramebuffer&& rhs) noexcept;
void HandleResize (Handle<SHVkRenderpass> const& renderpassHdl, std::vector<Handle<SHVkImageView>> const& attachments, uint32_t inWidth, uint32_t inHeight) noexcept;
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/

View File

@ -26,7 +26,7 @@ namespace SHADE
*/
/***************************************************************************/
void SHVkImage::PrepStagingBuffer(void* data, uint32_t srcSize) noexcept
void SHVkImage::PrepStagingBuffer(const void* data, uint32_t srcSize) noexcept
{
// For creation of buffer
vk::BufferCreateInfo bufferInfo{};
@ -70,7 +70,7 @@ namespace SHADE
vmaMapMemory(*vmaAllocator, stagingAlloc, &stagingBufferMappedPtr);
if (stagingBufferMappedPtr)
std::memcpy(static_cast<uint8_t*>(stagingBufferMappedPtr), static_cast<uint8_t*>(data), srcSize);
std::memcpy(static_cast<uint8_t*>(stagingBufferMappedPtr), static_cast<const uint8_t*>(data), srcSize);
const VkDeviceSize offsets = 0;
const VkDeviceSize sizes = srcSize;
@ -79,10 +79,45 @@ namespace SHADE
vmaUnmapMemory(*vmaAllocator, stagingAlloc);
}
void SHVkImage::CreateFramebufferImage(void) noexcept
{
vk::ImageCreateInfo imageCreateInfo{};
imageCreateInfo.imageType = vk::ImageType::e2D;
imageCreateInfo.extent.width = width;
imageCreateInfo.extent.height = height;
imageCreateInfo.extent.depth = depth;
imageCreateInfo.mipLevels = mipLevelCount;
imageCreateInfo.arrayLayers = layerCount;
imageCreateInfo.format = imageFormat;
imageCreateInfo.tiling = vk::ImageTiling::eOptimal;
imageCreateInfo.initialLayout = vk::ImageLayout::eUndefined;
imageCreateInfo.usage = usageFlags;
imageCreateInfo.sharingMode = vk::SharingMode::eExclusive;
imageCreateInfo.samples = vk::SampleCountFlagBits::e1;
imageCreateInfo.flags = createFlags;
// Prepare allocation parameters for call to create images later
VmaAllocationCreateInfo allocCreateInfo{};
allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
allocCreateInfo.flags = {}; // TODO: Make sure the vk::MemoryPropertyFlags returned from vmaGetAllocationMemoryProperties has the device local bit set
VmaAllocationInfo allocInfo{};
VkImage tempImage;
auto result = vmaCreateImage(*vmaAllocator, &imageCreateInfo.operator VkImageCreateInfo & (), &allocCreateInfo, &tempImage, &alloc, &allocInfo);
vkImage = tempImage;
if (result != VK_SUCCESS)
SHVulkanDebugUtil::ReportVkError(vk::Result(result), "Failed to create vulkan image. ");
else
SHVulkanDebugUtil::ReportVkSuccess("Successfully created image. ");
}
SHVkImage::SHVkImage(
VmaAllocator const* allocator,
SHImageCreateParams const& imageDetails,
unsigned char* data,
const unsigned char* data,
uint32_t dataSize,
std::span<uint32_t> inMipOffsets,
VmaMemoryUsage memUsage,
@ -196,37 +231,7 @@ namespace SHADE
, createFlags {create}
, vmaAllocator {allocator}
{
vk::ImageCreateInfo imageCreateInfo{};
imageCreateInfo.imageType = vk::ImageType::e2D;
imageCreateInfo.extent.width = width;
imageCreateInfo.extent.height = height;
imageCreateInfo.extent.depth = depth;
imageCreateInfo.mipLevels = mipLevelCount;
imageCreateInfo.arrayLayers = layerCount;
imageCreateInfo.format = imageFormat;
imageCreateInfo.tiling = vk::ImageTiling::eOptimal;
imageCreateInfo.initialLayout = vk::ImageLayout::eUndefined;
imageCreateInfo.usage = usageFlags;
imageCreateInfo.sharingMode = vk::SharingMode::eExclusive;
imageCreateInfo.samples = vk::SampleCountFlagBits::e1;
imageCreateInfo.flags = createFlags;
// Prepare allocation parameters for call to create images later
VmaAllocationCreateInfo allocCreateInfo{};
allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
allocCreateInfo.flags = {}; // TODO: Make sure the vk::MemoryPropertyFlags returned from vmaGetAllocationMemoryProperties has the device local bit set
VmaAllocationInfo allocInfo{};
VkImage tempImage;
auto result = vmaCreateImage(*vmaAllocator, &imageCreateInfo.operator VkImageCreateInfo & (), &allocCreateInfo, &tempImage, &alloc, &allocInfo);
vkImage = tempImage;
if (result != VK_SUCCESS)
SHVulkanDebugUtil::ReportVkError(vk::Result(result), "Failed to create vulkan image. ");
else
SHVulkanDebugUtil::ReportVkSuccess("Successfully created image. ");
CreateFramebufferImage();
}
Handle<SHVkImageView> SHVkImage::CreateImageView(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, Handle<SHVkImage> const& parent, SHImageViewDetails const& createParams) const noexcept
@ -288,6 +293,16 @@ namespace SHADE
barrier.subresourceRange.layerCount = layerCount;
}
void SHVkImage::HandleResizeFramebufferImage(uint32_t newWidth, uint32_t newHeight) noexcept
{
vmaDestroyImage(*vmaAllocator, vkImage, alloc);
width = newWidth;
height = newHeight;
CreateFramebufferImage();
}
void SHVkImage::LinkWithExteriorImage(vk::Image inVkImage, vk::ImageType type, uint32_t inWidth, uint32_t inHeight, uint32_t inDepth, uint32_t layers, uint8_t levels, vk::Format format, vk::ImageUsageFlags flags) noexcept
{
vkImage = inVkImage;

View File

@ -107,8 +107,8 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void PrepStagingBuffer(void* data, uint32_t srcSize) noexcept;
void PrepStagingBuffer(const void* data, uint32_t srcSize) noexcept;
void CreateFramebufferImage (void) noexcept;
public:
/*-----------------------------------------------------------------------*/
@ -119,7 +119,7 @@ namespace SHADE
SHVkImage(
VmaAllocator const* allocator,
SHImageCreateParams const& imageDetails,
unsigned char* data,
const unsigned char* data,
uint32_t dataSize,
std::span<uint32_t> inMipOffsets,
VmaMemoryUsage memUsage,
@ -137,6 +137,7 @@ namespace SHADE
Handle<SHVkImageView> CreateImageView (Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, Handle<SHVkImage> const& parent, SHImageViewDetails const& createParams) const noexcept;
void TransferToDeviceResource (Handle<SHVkCommandBuffer> cmdBufferHdl) noexcept;
void PrepareImageTransitionInfo (vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::ImageMemoryBarrier& barrier) noexcept;
void HandleResizeFramebufferImage(uint32_t newWidth, uint32_t newHeight) noexcept;
/*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */

View File

@ -6,27 +6,13 @@
namespace SHADE
{
/***************************************************************************/
/*!
\brief
Non-default ctor. Initializes image view with image that it is a view of.
\param parent
Parent image the view is a view of.
*/
/***************************************************************************/
SHVkImageView::SHVkImageView(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, Handle<SHVkImage> const& parent, SHImageViewDetails const& createParams) noexcept
: parentImage{ }
, vkImageView{}
, imageViewDetails{}
, logicalDeviceHdl {inLogicalDeviceHdl}
void SHVkImageView::Create(void) noexcept
{
auto parentImageCreateFlags = parent->GetImageeCreateFlags();
auto parentImageCreateFlags = parentImage->GetImageeCreateFlags();
// 2D array image type means parent image must be 2D array compatible
if (createParams.viewType == vk::ImageViewType::e2DArray)
if (imageViewDetails.viewType == vk::ImageViewType::e2DArray)
{
if (!(parentImageCreateFlags & vk::ImageCreateFlagBits::e2DArrayCompatible))
{
@ -36,7 +22,7 @@ namespace SHADE
}
// Check if its possible for the image view to have different format than parent image
if (createParams.format != parent->GetImageFormat())
if (imageViewDetails.format != parentImage->GetImageFormat())
{
if (!(parentImageCreateFlags & vk::ImageCreateFlagBits::eMutableFormat))
{
@ -49,9 +35,9 @@ namespace SHADE
vk::ImageViewCreateInfo viewCreateInfo
{
.pNext = nullptr, // Can be used to override with a VkImageViewUsageCreateInfo to override usage. See Vulkan spec page 877 for more information
.image = parent->GetVkImage(),
.viewType = createParams.viewType,
.format = createParams.format,
.image = parentImage->GetVkImage(),
.viewType = imageViewDetails.viewType,
.format = imageViewDetails.format,
.components
{
.r = vk::ComponentSwizzle::eR,
@ -61,15 +47,15 @@ namespace SHADE
},
.subresourceRange
{
.aspectMask = createParams.imageAspectFlags,
.baseMipLevel = createParams.baseMipLevel,
.levelCount = createParams.mipLevelCount,
.baseArrayLayer = createParams.baseArrayLayer,
.layerCount = createParams.layerCount,
.aspectMask = imageViewDetails.imageAspectFlags,
.baseMipLevel = imageViewDetails.baseMipLevel,
.levelCount = imageViewDetails.mipLevelCount,
.baseArrayLayer = imageViewDetails.baseArrayLayer,
.layerCount = imageViewDetails.layerCount,
},
};
if (auto result = inLogicalDeviceHdl->GetVkLogicalDevice().createImageView(&viewCreateInfo, nullptr, &vkImageView); result != vk::Result::eSuccess)
if (auto result = logicalDeviceHdl->GetVkLogicalDevice().createImageView(&viewCreateInfo, nullptr, &vkImageView); result != vk::Result::eSuccess)
{
SHVulkanDebugUtil::ReportVkError(result, "Failed to create image view! ");
return;
@ -79,9 +65,26 @@ namespace SHADE
SHVulkanDebugUtil::ReportVkSuccess("Successfully created image view. ");
}
// After success, THEN assign variables
parentImage = parent;
imageViewDetails = createParams;
}
/***************************************************************************/
/*!
\brief
Non-default ctor. Initializes image view with image that it is a view of.
\param parent
Parent image the view is a view of.
*/
/***************************************************************************/
SHVkImageView::SHVkImageView(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, Handle<SHVkImage> const& parent, SHImageViewDetails const& createParams) noexcept
: parentImage{ parent }
, vkImageView{}
, imageViewDetails{createParams}
, logicalDeviceHdl {inLogicalDeviceHdl}
{
Create();
}
SHVkImageView::SHVkImageView(SHVkImageView&& rhs) noexcept
@ -94,6 +97,17 @@ namespace SHADE
}
void SHVkImageView::ViewNewImage(Handle<SHVkImage> const& parent, SHImageViewDetails const& createParams) noexcept
{
imageViewDetails = createParams;
parentImage = parent;
if (vkImageView)
logicalDeviceHdl->GetVkLogicalDevice().destroyImageView(vkImageView, nullptr);
Create();
}
Handle<SHVkImage> const& SHVkImageView::GetParentImage(void) const noexcept
{
return parentImage;

View File

@ -25,12 +25,17 @@ namespace SHADE
//! Logical Device needed for creation and destruction
Handle<SHVkLogicalDevice> logicalDeviceHdl;
//! Create new image view
void Create (void) noexcept;
public:
SHVkImageView(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, Handle<SHVkImage> const& parent, SHImageViewDetails const& createParams) noexcept;
~SHVkImageView(void) noexcept;
SHVkImageView(SHVkImageView&& rhs) noexcept;
SHVkImageView& operator=(SHVkImageView&& rhs) noexcept;
void ViewNewImage (Handle<SHVkImage> const& parent, SHImageViewDetails const& createParams) noexcept;
/*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */
/*-----------------------------------------------------------------------*/

View File

@ -1,12 +1,62 @@
/************************************************************************************//*!
\file SHVkSampler.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Sep 26, 2022
\brief Contains definitions for all of the functions of the SHVkSampler class.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#include "SHpch.h"
#include "SHVkSampler.h"
#include "Graphics/Devices/SHVkLogicalDevice.h"
namespace SHADE
{
vk::Sampler SHVkSampler::GetVkSampler(void) const noexcept
/*-----------------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------------*/
SHVkSampler::SHVkSampler(Handle<SHVkLogicalDevice> logicalDevice, const SHVkSamplerParams& params) noexcept
: device { logicalDevice }
{
return vkSampler;
const vk::SamplerCreateInfo SAMPLER_CREATE_INFO
{
.magFilter = params.magFilter,
.minFilter = params.minFilter,
.mipmapMode = params.mipmapMode,
.addressModeU = params.addressMode,
.addressModeV = params.addressMode,
.addressModeW = params.addressMode,
.minLod = params.minLod,
.maxLod = params.maxLod
};
// Create the sampler
vkSampler = device->GetVkLogicalDevice().createSampler(SAMPLER_CREATE_INFO);
}
SHVkSampler::SHVkSampler(SHVkSampler&& rhs) noexcept
: vkSampler { rhs.vkSampler }
{
rhs.vkSampler = nullptr;
}
SHVkSampler::~SHVkSampler() noexcept
{
if (vkSampler)
device->GetVkLogicalDevice().destroySampler();
}
/*-----------------------------------------------------------------------------------*/
/* Overloaded Operators */
/*-----------------------------------------------------------------------------------*/
SHADE::SHVkSampler& SHVkSampler::operator=(SHVkSampler&& rhs) noexcept
{
vkSampler = rhs.vkSampler;
rhs.vkSampler = nullptr;
return *this;
}
}

View File

@ -1,28 +1,80 @@
/************************************************************************************//*!
\file SHVkSampler.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Sep 26, 2022
\brief Contains definitions of the SHVkSampler class.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
// STL Includes
#include <vector>
// Project Includes
#include "Graphics/SHVulkanIncludes.h"
#include "Resource/Handle.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHVkLogicalDevice;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/*************************************************************************************/
/*!
\brief
Holds parameters for constructing the SHVkSampler.
*/
/*************************************************************************************/
struct SHVkSamplerParams
{
vk::Filter minFilter;
vk::Filter maxFilter;
//vk::Filter maxFilter;
vk::Filter minFilter = vk::Filter::eLinear;
vk::Filter magFilter = vk::Filter::eLinear;
vk::SamplerAddressMode addressMode = vk::SamplerAddressMode::eClampToEdge;
vk::SamplerMipmapMode mipmapMode = vk::SamplerMipmapMode::eLinear;
float minLod = 0;
float maxLod = 0;
};
/*************************************************************************************/
/*!
\brief
Wrapper for a VkSampler.
*/
/*************************************************************************************/
class SHVkSampler
{
private:
//! The vulkan sampler handler
vk::Sampler vkSampler;
public:
/*---------------------------------------------------------------------------------*/
/* Constructors */
/*---------------------------------------------------------------------------------*/
SHVkSampler(Handle<SHVkLogicalDevice> logicalDevice, const SHVkSamplerParams& params = {}) noexcept;
SHVkSampler(SHVkSampler&& rhs) noexcept;
~SHVkSampler() noexcept;
public:
SHVkSampler () noexcept;
SHVkSampler (SHVkSampler&& rhs) noexcept;
SHVkSampler&& operator=(SHVkSampler&& rhs) noexcept;
/*---------------------------------------------------------------------------------*/
/* Overloaded Operators */
/*---------------------------------------------------------------------------------*/
SHVkSampler& operator=(SHVkSampler&& rhs) noexcept;
vk::Sampler GetVkSampler (void) const noexcept;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
vk::Sampler GetVkSampler(void) const noexcept { return vkSampler; }
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
vk::Sampler vkSampler; //! The Vulkan sampler handler
Handle<SHVkLogicalDevice> device; //! Stored device for deallocating the object
};
}

View File

@ -22,8 +22,11 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/Pipeline/SHVkPipeline.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "ECS_Base/Managers/SHComponentManager.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h"
#include "Graphics/Descriptors/SHVkDescriptorPool.h"
namespace SHADE
{
@ -120,7 +123,7 @@ namespace SHADE
}
}
void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex)
void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
@ -154,21 +157,17 @@ namespace SHADE
if (!matBufferDirty[frameIndex])
return;
// Build CPI Buffer
// Build CPU Buffer
char* propsCurrPtr = matPropsData.get();
for (auto& subBatch : subBatches)
for (const SHRenderable* renderable : subBatch.Renderables)
{
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
propsCurrPtr += singleMatPropSize;
propsCurrPtr += singleMatPropAlignedSize;
}
// Transfer to GPU
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
vk::BufferUsageFlagBits::eStorageBuffer
);
rebuildMaterialBuffers(frameIndex, descPool);
// This frame is updated
matBufferDirty[frameIndex] = false;
@ -207,7 +206,7 @@ namespace SHADE
transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix)), 0, 0);
}
void SHBatch::Build(Handle<SHVkLogicalDevice> _device, uint32_t frameIndex)
void SHBatch::Build(Handle<SHVkLogicalDevice> _device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
@ -215,6 +214,9 @@ namespace SHADE
return;
}
// Save logical device
device = _device;
// No need to build as there are no changes
if (!isDirty[frameIndex])
return;
@ -247,7 +249,8 @@ namespace SHADE
if (!EMPTY_MAT_PROPS)
{
singleMatPropSize = SHADER_INFO->GetBytesRequired();
matPropTotalBytes = drawData.size() * singleMatPropSize;
singleMatPropAlignedSize = device->PadSSBOSize(static_cast<uint32_t>(singleMatPropSize));
matPropTotalBytes = numTotalElements * singleMatPropAlignedSize;
if (matPropsDataSize < matPropTotalBytes)
{
matPropsData.reset(new char[matPropTotalBytes]);
@ -267,7 +270,7 @@ namespace SHADE
.instanceCount = static_cast<uint32_t>(subBatch.Renderables.size()),
.firstIndex = subBatch.Mesh->FirstIndex,
.vertexOffset = subBatch.Mesh->FirstVertex,
.firstInstance = nextInstanceIndex
.firstInstance = nextInstanceIndex++
});
// Fill in buffers (CPU)
@ -289,7 +292,7 @@ namespace SHADE
if (!EMPTY_MAT_PROPS)
{
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
propsCurrPtr += singleMatPropSize;
propsCurrPtr += singleMatPropAlignedSize;
}
}
}
@ -304,30 +307,21 @@ namespace SHADE
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,
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,
device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
BuffUsage::eVertexBuffer
);
// - Material Properties Buffer
if (matPropsData)
{
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
_device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
BuffUsage::eStorageBuffer
);
}
rebuildMaterialBuffers(frameIndex, descPool);
// Mark this frame as no longer dirty
isDirty[frameIndex] = false;
// Save logical device
this->device = _device;
}
/*---------------------------------------------------------------------------------*/
@ -341,8 +335,20 @@ namespace SHADE
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);
if (matPropsDescSet[frameIndex])
{
cmdBuffer->BindDescriptorSet
(
matPropsDescSet[frameIndex],
vk::PipelineBindPoint::eGraphics,
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
dynamicOffset
);
}
cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
}
@ -355,4 +361,39 @@ namespace SHADE
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

@ -35,6 +35,8 @@ namespace SHADE
class SHRenderable;
class SHVkLogicalDevice;
class SHMaterialInstance;
class SHVkDescriptorSetGroup;
class SHVkDescriptorPool;
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
@ -74,9 +76,9 @@ namespace SHADE
void Add(const SHRenderable* renderable);
void Remove(const SHRenderable* renderable);
void Clear();
void UpdateMaterialBuffer(uint32_t frameIndex);
void UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
void UpdateTransformBuffer(uint32_t frameIndex);
void Build(Handle<SHVkLogicalDevice> device, uint32_t frameIndex);
void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) ;
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex);
/*-----------------------------------------------------------------------------*/
@ -84,34 +86,44 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
Handle<SHVkPipeline> GetPipeline() const noexcept { return pipeline; };
private:
private:
/*-----------------------------------------------------------------------------*/
/* Type Definition */
/*-----------------------------------------------------------------------------*/
using TripleBool = std::array<bool, SHGraphicsConstants::NUM_FRAME_BUFFERS>;
using TripleBuffer = std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS>;
using TripleDescSet = std::array<Handle<SHVkDescriptorSetGroup>, SHGraphicsConstants::NUM_FRAME_BUFFERS>;
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
// Resources
Handle<SHVkLogicalDevice> device;
Handle<SHVkLogicalDevice> device;
// Batch Properties
Handle<SHVkPipeline> pipeline;
Handle<SHVkPipeline> pipeline;
std::unordered_set<Handle<SHMaterialInstance>> referencedMatInstances;
std::array<bool, SHGraphicsConstants::NUM_FRAME_BUFFERS> matBufferDirty;
TripleBool matBufferDirty;
// Batch Tree
std::vector<SHSubBatch> subBatches;
std::array<bool, SHGraphicsConstants::NUM_FRAME_BUFFERS> isDirty;
std::vector<SHSubBatch> subBatches;
TripleBool isDirty;
// CPU Buffers
std::vector<vk::DrawIndexedIndirectCommand> drawData;
std::vector<SHMatrix> transformData;
std::unique_ptr<char> matPropsData;
Byte matPropsDataSize = 0;
Byte singleMatPropSize = 0;
bool isCPUBuffersDirty = true;
std::vector<vk::DrawIndexedIndirectCommand> drawData;
std::vector<SHMatrix> transformData;
std::unique_ptr<char> matPropsData;
Byte matPropsDataSize = 0;
Byte singleMatPropAlignedSize = 0;
Byte singleMatPropSize = 0;
bool isCPUBuffersDirty = true;
// GPU Buffers
std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS> drawDataBuffer;
std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS> transformDataBuffer;
std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS> matPropsBuffer;
TripleBuffer drawDataBuffer;
TripleBuffer transformDataBuffer;
TripleBuffer matPropsBuffer;
TripleDescSet matPropsDescSet;
/*-----------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
void setAllDirtyFlags();
void rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
};
}

View File

@ -91,12 +91,12 @@ namespace SHADE
(*superBatch)->Remove(renderable);
}
void SHBatcher::FinaliseBatches(Handle<SHVkLogicalDevice> device, uint32_t frameIndex)
void SHBatcher::FinaliseBatches(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex)
{
// Build SuperBatches
for (auto& batch : superBatches)
{
batch->Build(device, frameIndex);
batch->Build(device, descPool, frameIndex);
}
}
@ -109,11 +109,11 @@ namespace SHADE
superBatches.clear();
}
void SHBatcher::UpdateBuffers(uint32_t frameIndex)
void SHBatcher::UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
for (auto& batch : superBatches)
{
batch->UpdateBuffers(frameIndex);
batch->UpdateBuffers(frameIndex, descPool);
}
}

View File

@ -27,6 +27,7 @@ namespace SHADE
class SHSuperBatch;
class SHVkLogicalDevice;
class SHVkCommandBuffer;
class SHVkDescriptorPool;
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
@ -51,9 +52,9 @@ namespace SHADE
void PrepareBatches();
void AddToBatch(SHRenderable const* renderable);
void RemoveFromBatch(SHRenderable const* renderable);
void FinaliseBatches(Handle<SHVkLogicalDevice> device, uint32_t frameIndex);
void FinaliseBatches(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex);
void ClearBatches();
void UpdateBuffers(uint32_t frameIndex);
void UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
void RegisterSuperBatch(Handle<SHSuperBatch> superBatch);
void DeregisterSuperBatch(Handle<SHSuperBatch> superBatch);

View File

@ -16,6 +16,7 @@ of DigiPen Institute of Technology is prohibited.
#include "SHBatch.h"
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Graphics/Descriptors/SHVkDescriptorPool.h"
namespace SHADE
{
@ -78,21 +79,21 @@ namespace SHADE
batches.clear();
}
void SHSuperBatch::UpdateBuffers(uint32_t frameIndex)
void SHSuperBatch::UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
for (auto& batch : batches)
{
batch.UpdateMaterialBuffer(frameIndex);
batch.UpdateMaterialBuffer(frameIndex, descPool);
batch.UpdateTransformBuffer(frameIndex);
}
}
void SHSuperBatch::Build(Handle<SHVkLogicalDevice> device, uint32_t frameIndex) noexcept
void SHSuperBatch::Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
{
// Build all batches
for (auto& batch : batches)
{
batch.Build(device, frameIndex);
batch.Build(device, descPool, frameIndex);
}
}

View File

@ -55,8 +55,8 @@ namespace SHADE
void Add(const SHRenderable* renderable) noexcept;
void Remove(const SHRenderable* renderable) noexcept;
void Clear() noexcept;
void UpdateBuffers(uint32_t frameIndex);
void Build(Handle<SHVkLogicalDevice> device, uint32_t frameIndex) noexcept;
void UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
/*-----------------------------------------------------------------------------*/

View File

@ -7,7 +7,22 @@
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Static Definitions */
/*-----------------------------------------------------------------------------------*/
std::vector<Handle<SHVkDescriptorSetLayout>> SHGraphicsGlobalData::globalDescSetLayouts;
Handle<SHVkDescriptorSetGroup> SHGraphicsGlobalData::globalDescSets;
SHVertexInputState SHGraphicsGlobalData::defaultVertexInputState;
Handle<SHVkPipelineLayout> SHGraphicsGlobalData::dummyPipelineLayout;
void SHGraphicsGlobalData::InitHighFrequencyGlobalData(void) noexcept
{
}
/*-----------------------------------------------------------------------------------*/
/* Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHGraphicsGlobalData::InitDescSetLayouts(Handle<SHVkLogicalDevice> logicalDevice) noexcept
{
SHVkDescriptorSetLayout::Binding genericDataBinding
@ -87,18 +102,18 @@ namespace SHADE
InitDefaultVertexInputState();
}
std::vector<Handle<SHVkDescriptorSetLayout>> const& SHGraphicsGlobalData::GetDescSetLayouts(void) const noexcept
std::vector<Handle<SHVkDescriptorSetLayout>> const& SHGraphicsGlobalData::GetDescSetLayouts(void) noexcept
{
return globalDescSetLayouts;
}
SHVertexInputState const& SHGraphicsGlobalData::GetDefaultViState(void) const noexcept
SHVertexInputState const& SHGraphicsGlobalData::GetDefaultViState(void) noexcept
{
return defaultVertexInputState;
}
Handle<SHVkPipelineLayout> SHGraphicsGlobalData::GetDummyPipelineLayout(void) const noexcept
Handle<SHVkPipelineLayout> SHGraphicsGlobalData::GetDummyPipelineLayout(void) noexcept
{
return dummyPipelineLayout;
}

View File

@ -15,31 +15,38 @@ namespace SHADE
{
private:
//! Global descriptor set layouts. Used to allocate descriptor sets
std::vector<Handle<SHVkDescriptorSetLayout>> globalDescSetLayouts;
static std::vector<Handle<SHVkDescriptorSetLayout>> globalDescSetLayouts;
//! Global Descriptor sets
Handle<SHVkDescriptorSetGroup> globalDescSets;
static Handle<SHVkDescriptorSetGroup> globalDescSets;
//! Default vertex input state (used by everything).
SHVertexInputState defaultVertexInputState;
static SHVertexInputState defaultVertexInputState;
//! Since we want to bind global data but can't do so without a pipeline layout,
//! we create a dummy pipeline layout to use it for binding.
Handle<SHVkPipelineLayout> dummyPipelineLayout;
static Handle<SHVkPipelineLayout> dummyPipelineLayout;
static void InitHighFrequencyGlobalData (void) noexcept;
static void InitDescSetLayouts (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
static void InitDefaultVertexInputState (void) noexcept;
void InitDescSetLayouts (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
void InitDefaultVertexInputState(void) noexcept;
public:
/*-----------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------*/
SHGraphicsGlobalData() = delete;
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void Init (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
static void Init (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
std::vector<Handle<SHVkDescriptorSetLayout>> const& GetDescSetLayouts (void) const noexcept;
SHVertexInputState const& GetDefaultViState (void) const noexcept;
Handle<SHVkPipelineLayout> GetDummyPipelineLayout (void) const noexcept;
static std::vector<Handle<SHVkDescriptorSetLayout>> const& GetDescSetLayouts (void) noexcept;
static SHVertexInputState const& GetDefaultViState (void) noexcept;
static Handle<SHVkPipelineLayout> GetDummyPipelineLayout (void) noexcept;
};
}

View File

@ -23,21 +23,39 @@ namespace SHADE
{
SHVec3 view = target - pos; view = SHVec3::Normalise(view);
SHVec3 right = SHVec3::Cross(view, up); right = SHVec3::Normalise(right);
const SHVec3 UP = SHVec3::Cross(right, view);
const SHVec3 UP = SHVec3::Cross(view, right);
//viewMatrix = SHMatrix::Identity;
//viewMatrix(0, 0) = UP[0];
//viewMatrix(1, 0) = UP[1];
//viewMatrix(2, 0) = UP[2];
//viewMatrix(0, 1) = right[0];
//viewMatrix(1, 1) = right[1];
//viewMatrix(2, 1) = right[2];
//viewMatrix(0, 2) = view[0];
//viewMatrix(1, 2) = view[1];
//viewMatrix(2, 2) = view[2];
//viewMatrix(3, 0) = -UP.Dot(pos);
//viewMatrix(3, 1) = -right.Dot(pos);
//viewMatrix(3, 2) = -view.Dot(pos);
viewMatrix = SHMatrix::Identity;
viewMatrix(0, 0) = UP[0];
viewMatrix(1, 0) = UP[1];
viewMatrix(2, 0) = UP[2];
viewMatrix(0, 1) = right[0];
viewMatrix(1, 1) = right[1];
viewMatrix(2, 1) = right[2];
viewMatrix(0, 2) = view[0];
viewMatrix(1, 2) = view[1];
viewMatrix(2, 2) = view[2];
viewMatrix(3, 0) = -UP.Dot(pos);
viewMatrix(3, 1) = -right.Dot(pos);
viewMatrix(3, 2) = -view.Dot(pos);
viewMatrix(0, 0) = right[0];
viewMatrix(0, 1) = right[1];
viewMatrix(0, 2) = right[2];
viewMatrix(1, 0) = UP[0];
viewMatrix(1, 1) = UP[1];
viewMatrix(1, 2) = UP[2];
viewMatrix(2, 0) = view[0];
viewMatrix(2, 1) = view[1];
viewMatrix(2, 2) = view[2];
viewMatrix(0, 3) = -right.Dot(pos);
viewMatrix(1, 3) = -UP.Dot(pos);
viewMatrix(2, 3) = -view.Dot(pos);
isDirty = true;
}

View File

@ -69,7 +69,7 @@ namespace SHADE
SHMatrix inverseViewMatrix;
SHMatrix inverseProjMatrix;
SHMatrix inverseVpMatrix;
bool isDirty;
bool isDirty = true;
/*-----------------------------------------------------------------------------*/
/* Helper Functions */

View File

@ -30,6 +30,8 @@ of DigiPen Institute of Technology is prohibited.
#include "SHGraphicsConstants.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h"
#include "Graphics/Buffers/SHVkBuffer.h"
#include "Graphics/Images/SHVkSampler.h"
#include "Assets/Asset Types/SHTextureAsset.h"
namespace SHADE
{
@ -65,9 +67,17 @@ namespace SHADE
// Register callback to notify render context upon a window resize
window->RegisterWindowSizeCallback([&]([[maybe_unused]] uint32_t width, [[maybe_unused]] uint32_t height)
{
if (width == 0 || height == 0)
return;
renderContext.SetIsResized(true);
});
window->RegisterWindowCloseCallback([&](void)
{
renderContext.SetWindowIsDead(true);
}
);
// Create graphics queue
graphicsQueue = device->GetQueue(SH_Q_FAM::GRAPHICS, 0);
transferQueue = device->GetQueue(SH_Q_FAM::TRANSFER, 0);
@ -91,8 +101,10 @@ namespace SHADE
descPool = device->CreateDescriptorPools();
// Create generic command buffer
transferCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::TRANSFER, SH_CMD_POOL_RESET::POOL_BASED, true);
transferCmdBuffer = transferCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
//transferCmdPool = 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);
graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
@ -106,23 +118,22 @@ namespace SHADE
- Global data
/*-----------------------------------------------------------------------*/
globalData = resourceManager.Create<SHGraphicsGlobalData>();
globalData->Init(device);
SHGraphicsGlobalData::Init(device);
// Set Up Cameras
screenCamera = resourceManager.Create<SHCamera>();
screenCamera->SetLookAt(SHVec3(0.0f, 0.0f, -1.0f), SHVec3(0.0f, 0.0f, 1.0f), SHVec3(0.0f, 1.0f, 0.0f));
screenCamera->SetOrthographic(static_cast<float>(windowDims.first), static_cast<float>(windowDims.second), 0.01f, 100.0f);
worldCamera = resourceManager.Create<SHCamera>();
//worldCamera->SetLookAt(SHVec3(1.0f, 0.0f, -1.0f), SHVec3(0.0f, 0.0f, 2.0f), SHVec3(0.0f, 1.0f, 0.0f));
worldCamera->SetLookAt(SHVec3(0.0f, 5.0f, -1.0f), SHVec3(0.0f, 0.0f, 2.0f), SHVec3(0.0f, 1.0f, 0.0f));
worldCamera->SetLookAt(SHVec3(0.0f, 0.0f, 0.0f), SHVec3(0.0f, 0.0f, -2.0f), SHVec3(0.0f, 1.0f, 0.0f));
worldCamera->SetPerspective(90.0f, static_cast<float>(windowDims.first), static_cast<float>(windowDims.second), 0.0f, 100.0f);
// Create Default Viewport
defaultViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast<float>(window->GetWindowSize().first), static_cast<float>(window->GetWindowSize().second), 0.0f, 1.0f));
// Get render graph from default viewport world renderer
auto worldRenderGraph = resourceManager.Create<SHRenderGraph>();
worldRenderGraph = resourceManager.Create<SHRenderGraph>();
std::vector<Handle<SHVkCommandPool>> renderContextCmdPools{swapchain->GetNumImages()};
for (uint32_t i = 0; i < renderContextCmdPools.size(); ++i)
@ -131,18 +142,20 @@ namespace SHADE
}
// Initialize world render graph
worldRenderGraph->Init(device, swapchain, globalData);
worldRenderGraph->Init(device, swapchain);
worldRenderGraph->AddResource("Depth Buffer", SH_ATT_DESC_TYPE::DEPTH_STENCIL, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint);
//worldRenderGraph->AddResource("Position", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat);
//worldRenderGraph->AddResource("Normals", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat);
//worldRenderGraph->AddResource("Composite", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat);
worldRenderGraph->AddResource("Scene", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eB8G8R8A8Unorm);
//worldRenderGraph->AddResource("Scene", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eB8G8R8A8Unorm);
worldRenderGraph->AddResource("Present", SH_ATT_DESC_TYPE::COLOR_PRESENT, windowDims.first, windowDims.second);
auto node = worldRenderGraph->AddNode("G-Buffer", { /*"Composite", "Position", */"Present" }, {}); // no predecessors
auto node = worldRenderGraph->AddNode("G-Buffer", { /*"Composite", "Position", */"Depth Buffer", "Present" }, {}); // no predecessors
//First subpass to write to G-Buffer
auto gBufferWriteSubpass = node->AddSubpass("G-Buffer Write");
//gBufferWriteSubpass->AddColorOutput("Scene");
gBufferWriteSubpass->AddColorOutput("Present");
gBufferWriteSubpass->AddDepthOutput ("Depth Buffer", SH_ATT_DESC_TYPE::DEPTH_STENCIL);
//writeSubpass->AddColorOutput("Normals");
// //Second subpass to read from G-Buffer
@ -171,7 +184,7 @@ namespace SHADE
debugWorldRenderer->SetCamera(worldCamera);*/
// Add world renderer to default viewport
worldRenderer = defaultViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, globalData->GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph);
worldRenderer = defaultViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph);
worldRenderer->SetCamera(worldCamera);
@ -184,8 +197,8 @@ namespace SHADE
shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary);
auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl");
auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl");
//triVS->Reflect();
//triFS->Reflect();
cubeVS->Reflect();
cubeFS->Reflect();
defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferWriteSubpass);
}
@ -205,6 +218,15 @@ namespace SHADE
/***************************************************************************/
void SHGraphicsSystem::Run(double) noexcept
{
if (window->IsMinimized() || renderContext.GetWindowIsDead())
return;
if (renderContext.GetResized())
{
return;
}
// Frame data for the current frame
auto const& frameData = renderContext.GetCurrentFrameData();
uint32_t frameIndex = renderContext.GetCurrentFrame();
@ -224,6 +246,9 @@ namespace SHADE
renderContext.ResetFence();
// Bind textures
// For every viewport
for (int vpIndex = 0; vpIndex < static_cast<int>(viewports.size()); ++vpIndex)
{
@ -241,7 +266,11 @@ namespace SHADE
// Begin recording the command buffer
currentCmdBuffer->BeginRecording();
currentCmdBuffer->ForceSetPipelineLayout(globalData->GetDummyPipelineLayout());
uint32_t w = static_cast<uint32_t>(viewports[vpIndex]->GetWidth());
uint32_t h = static_cast<uint32_t>(viewports[vpIndex]->GetHeight());
currentCmdBuffer->SetViewportScissor (static_cast<float>(w), static_cast<float>(h), w, h);
currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout());
// Bind all the buffers required for meshes
for (auto& [buffer, bindingPoint] : MESH_DATA)
@ -252,11 +281,26 @@ namespace SHADE
currentCmdBuffer->BindIndexBuffer(buffer, 0);
}
// Bind textures
auto textureDescSet = texLibrary.GetTextureDescriptorSetGroup();
if (textureDescSet)
{
std::array<uint32_t, 1> texDynamicOffset {0};
currentCmdBuffer->BindDescriptorSet
(
textureDescSet,
vk::PipelineBindPoint::eGraphics,
0,
texDynamicOffset
);
}
// bind camera data
renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
// Draw first
renderers[renIndex]->Draw(frameIndex);
renderers[renIndex]->Draw(frameIndex, descPool);
// End the command buffer recording
currentCmdBuffer->EndRecording();
@ -281,13 +325,6 @@ namespace SHADE
void SHGraphicsSystem::Exit(void)
{
renderContext.Destroy();
graphicsQueue.Free();
swapchain.Free();
surface.Free();
device.Free();
SHVkInstance::Destroy();
}
/*---------------------------------------------------------------------------------*/
@ -305,11 +342,14 @@ namespace SHADE
/***************************************************************************/
void SHGraphicsSystem::BeginRender()
{
if (window->IsMinimized() || renderContext.GetWindowIsDead())
return;
// Finalise all batches
for (auto vp : viewports)
for (auto renderer : vp->GetRenderers())
{
renderer->GetRenderGraph()->FinaliseBatch(renderContext.GetCurrentFrame());
renderer->GetRenderGraph()->FinaliseBatch(renderContext.GetCurrentFrame(), descPool);
}
// Resize
@ -318,10 +358,7 @@ namespace SHADE
{
device->WaitIdle();
// Resize the swapchain
swapchain->Resize(surface, windowDims.first, windowDims.second);
renderContext.HandleResize();
HandleResize();
}
const uint32_t CURR_FRAME_IDX = renderContext.GetCurrentFrame();
@ -354,6 +391,16 @@ namespace SHADE
/***************************************************************************/
void SHGraphicsSystem::EndRender()
{
if (window->IsMinimized() || renderContext.GetWindowIsDead())
return;
if (renderContext.GetResized())
{
return;
}
const uint32_t CURR_FRAME_IDX = renderContext.GetCurrentFrame();
auto& currFrameData = renderContext.GetCurrentFrameData();
@ -364,10 +411,8 @@ namespace SHADE
// If swapchain is incompatible/outdated
if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR)
{
auto windowDims = window->GetWindowSize();
swapchain->Resize(surface, windowDims.first, windowDims.second);
renderContext.HandleResize();
HandleResize();
}
}
@ -455,7 +500,60 @@ namespace SHADE
transferCmdBuffer->BeginRecording();
meshLibrary.BuildBuffers(device, transferCmdBuffer);
transferCmdBuffer->EndRecording();
transferQueue->SubmitCommandBuffer({ transferCmdBuffer });
graphicsQueue->SubmitCommandBuffer({ transferCmdBuffer });
}
/*---------------------------------------------------------------------------------*/
/* Texture Registration Functions */
/*---------------------------------------------------------------------------------*/
Handle<SHTexture> SHGraphicsSystem::Add(const SHTextureAsset& texAsset)
{
auto sampler = samplerCache.GetSampler(device, SHVkSamplerParams { .maxLod = static_cast<float>(texAsset.mipOffsets.size()) });
return texLibrary.Add(texAsset, sampler);
}
SHADE::Handle<SHADE::SHTexture> SHGraphicsSystem::Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector<uint32_t> mipOffsets)
{
auto sampler = samplerCache.GetSampler(device, SHVkSamplerParams{ .maxLod = static_cast<float>(mipOffsets.size()) });
return texLibrary.Add(pixelCount, pixelData, width, height, format, mipOffsets, sampler);
}
void SHGraphicsSystem::Remove(Handle<SHTexture> tex)
{
texLibrary.Remove(tex);
}
void SHGraphicsSystem::BuildTextures()
{
texLibrary.BuildTextures
(
device, graphicsTexCmdBuffer, graphicsQueue, descPool
);
}
void SHGraphicsSystem::HandleResize(void) noexcept
{
if (window->IsMinimized() || renderContext.GetWindowIsDead())
return;
auto windowDims = window->GetWindowSize();
// Resize the swapchain
swapchain->Resize(surface, windowDims.first, windowDims.second);
renderContext.HandleResize();
worldRenderGraph->HandleResize(windowDims.first, windowDims.second);
defaultViewport->SetWidth(static_cast<float>(windowDims.first));
defaultViewport->SetHeight(static_cast<float>(windowDims.second));
worldCamera->SetPerspective(90.0f, static_cast<float>(windowDims.first), static_cast<float>(windowDims.second), 0.0f, 100.0f);
}
void SHGraphicsSystem::AwaitGraphicsExecution()
{
device->WaitIdle();
}
void SHGraphicsSystem::SetWindow(SHWindow* wind) noexcept
@ -463,20 +561,49 @@ namespace SHADE
window = wind;
}
/*-----------------------------------------------------------------------------------*/
/* System Routine Functions - BeginRoutine */
/*-----------------------------------------------------------------------------------*/
SHGraphicsSystem::BeginRoutine::BeginRoutine()
: SHSystemRoutine("Graphics System Frame Set Up", false)
{}
void SHGraphicsSystem::BeginRoutine::Execute(double) noexcept
{
reinterpret_cast<SHGraphicsSystem*>(system)->BeginRender();
}
/*-----------------------------------------------------------------------------------*/
/* System Routine Functions - RenderRoutine */
/*-----------------------------------------------------------------------------------*/
SHGraphicsSystem::RenderRoutine::RenderRoutine()
: SHSystemRoutine("Graphics System Render", false)
{}
void SHGraphicsSystem::RenderRoutine::Execute(double dt) noexcept
{
reinterpret_cast<SHGraphicsSystem*>(system)->Run(dt);
}
/*-----------------------------------------------------------------------------------*/
/* System Routine Functions - EndRoutine */
/*-----------------------------------------------------------------------------------*/
SHGraphicsSystem::EndRoutine::EndRoutine()
: SHSystemRoutine("Graphics System Frame Clean Up", false)
{}
void SHGraphicsSystem::EndRoutine::Execute(double) noexcept
{
reinterpret_cast<SHGraphicsSystem*>(system)->EndRender();
}
/*-----------------------------------------------------------------------------------*/
/* System Routine Functions - BatcherDispatcherRoutine */
/*-----------------------------------------------------------------------------------*/
SHGraphicsSystem::BatcherDispatcherRoutine::BatcherDispatcherRoutine()
: SHSystemRoutine("Graphics System Batcher Dispatcher", false)
{}
void SHGraphicsSystem::BatcherDispatcherRoutine::Execute(double) noexcept
{
auto& renderables = SHComponentManager::GetDense<SHRenderable>();
@ -493,9 +620,13 @@ namespace SHADE
oldSuperBatch->Remove(&renderable);
}
// Add to new SuperBatch
Handle<SHSuperBatch> newSuperBatch = renderable.GetMaterial()->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
newSuperBatch->Add(&renderable);
// Add to new SuperBatch if there is a material
Handle<SHMaterialInstance> newMatInstance = renderable.GetMaterial();
if (newMatInstance)
{
Handle<SHSuperBatch> newSuperBatch = newMatInstance->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
newSuperBatch->Add(&renderable);
}
// Unset change flag
renderable.ResetChangedFlag();

View File

@ -29,6 +29,8 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.h"
#include "SHMeshLibrary.h"
#include "Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.h"
#include "../Textures/SHTextureLibrary.h"
#include "../Textures/SHVkSamplerCache.h"
namespace SHADE
{
@ -67,21 +69,25 @@ namespace SHADE
class SH_API BeginRoutine final : public SHSystemRoutine
{
public:
BeginRoutine();
virtual void Execute(double dt) noexcept override final;
};
class SH_API RenderRoutine final : public SHSystemRoutine
{
public:
RenderRoutine();
virtual void Execute(double dt) noexcept override final;
};
class SH_API EndRoutine final : public SHSystemRoutine
{
public:
EndRoutine();
virtual void Execute(double dt) noexcept override final;
};
class SH_API BatcherDispatcherRoutine final : public SHSystemRoutine
{
public:
BatcherDispatcherRoutine();
virtual void Execute(double dt) noexcept override final;
};
@ -188,6 +194,65 @@ namespace SHADE
/***************************************************************************/
void BuildMeshBuffers();
/*-----------------------------------------------------------------------------*/
/* Texture Registration Functions */
/*-----------------------------------------------------------------------------*/
/*******************************************************************************/
/*!
\brief
Adds a texture to the Texture Library. But this does not mean that the
textures have been added yet. A call to "BuildTextures()" is required to
transfer all textures into the GPU.
\param pixelCount
Number of pixels in this Mesh.
\param positions
Pointer to the first in a contiguous array of SHMathVec3s that define vertex
positions.
\param format
Format of the texture loaded in.
\return
Handle to the created Texture. This is not valid to be used until a call to
BuildImages().
*/
/*******************************************************************************/
Handle<SHTexture> Add(const SHTextureAsset& texAsset);
Handle<SHTexture> Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector<uint32_t> mipOffsets);
/*******************************************************************************/
/*!
\brief
Removes a mesh from the Texture Library. But this does not mean that the
textures have been removed yet. A call to "BuildTextures()" is required to
finalise all changes.
\param mesh
Handle to the Texture to remove.
*/
/*******************************************************************************/
void Remove(Handle<SHTexture> tex);
/***************************************************************************/
/*!
\brief
Finalises all changes to the Texture Library into the GPU buffers.
\param cmdBuffer
Command buffer used to set up transfers of data in the GPU memory. This
call must be preceded by calls to cmdBuffer's BeginRecording() and ended
with EndRecording(). Do recall to also submit the cmdBuffer to a transfer
queue.
*/
/***************************************************************************/
void BuildTextures();
void HandleResize(void) noexcept;
void AwaitGraphicsExecution();
/*-----------------------------------------------------------------------------*/
/* Setters */
/*-----------------------------------------------------------------------------*/
@ -220,19 +285,19 @@ namespace SHADE
Handle<SHVkQueue> graphicsQueue;
Handle<SHVkQueue> transferQueue;
Handle<SHVkDescriptorPool> descPool;
Handle<SHVkCommandPool> transferCmdPool;
Handle<SHVkCommandPool> graphicsCmdPool;
Handle<SHVkCommandBuffer> transferCmdBuffer;
Handle<SHVkCommandBuffer> graphicsTexCmdBuffer;
SHRenderContext renderContext;
std::array<Handle<SHVkSemaphore>, 2> graphSemaphores;
// Not Owned Resources
SHWindow* window = nullptr;
// global data (descriptor sets as well)
Handle<SHGraphicsGlobalData> globalData;
// Middle End Resources
ResourceManager resourceManager;
SHMeshLibrary meshLibrary;
SHTextureLibrary texLibrary;
SHSamplerCache samplerCache;
SHMaterialInstanceCache materialInstanceCache;
// Viewports
Handle<SHViewport> defaultViewport; // Whole screen
@ -255,5 +320,7 @@ namespace SHADE
// Temp Materials
Handle<SHMaterial> defaultMaterial;
Handle<SHRenderGraph> worldRenderGraph;
};
}

View File

@ -63,7 +63,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
Handle<SHVkPipeline> pipeline;
std::unique_ptr<char> propMemory;
Byte propMemorySize;
Byte propMemorySize = 0;
/*-----------------------------------------------------------------------------*/
/* Helper Functions */

View File

@ -40,8 +40,6 @@ namespace SHADE
void SHMaterialInstance::ExportProperties(void* dest)
{
assert(dataStore != nullptr);
if (!baseMaterial)
throw std::runtime_error("[SHMaterialInstance] Attempted to set export a Material Instance with no base Material!");

View File

@ -15,6 +15,7 @@ of DigiPen Institute of Technology is prohibited.
// Project Includes
#include "Resource/Handle.h"
#include "Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h"
#include "SH_API.h"
namespace SHADE
{
@ -34,7 +35,7 @@ namespace SHADE
a SHRenderable.
*/
/***********************************************************************************/
class SHMaterialInstance
class SH_API SHMaterialInstance
{
public:
/*-----------------------------------------------------------------------------*/

View File

@ -48,7 +48,7 @@ namespace SHADE
}
// Get offset and modify the memory directly
T* dataPtr = dataStore.get() + od.StoredDataOffset;
T* dataPtr = reinterpret_cast<T*>(dataStore.get() + od.StoredDataOffset);
*dataPtr = value;
// Save the override data information

View File

@ -81,7 +81,7 @@ namespace SHADE
if (!material)
{
SHGraphicsSystem* gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
material = gfxSystem->AddOrGetBaseMaterialInstance(sharedMaterial->GetBaseMaterial());
material = gfxSystem->AddMaterialInstanceCopy(sharedMaterial);
}
return material;

View File

@ -49,6 +49,14 @@ namespace SHADE
cameraDescriptorSet->UpdateDescriptorSetBuffer(SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, SHGraphicsConstants::DescriptorSetBindings::CAMERA_DATA);
}
SHRenderer::~SHRenderer(void)
{
//for (auto& cmdBuffer : commandBuffers)
//{
// cmdBuffer.Free();
//}
}
/*-----------------------------------------------------------------------------------*/
/* Camera Registration */
/*-----------------------------------------------------------------------------------*/
@ -60,9 +68,9 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/
/* Drawing Functions */
/*-----------------------------------------------------------------------------------*/
void SHRenderer::Draw(uint32_t frameIndex) noexcept
void SHRenderer::Draw(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept
{
renderGraph->Execute(frameIndex, commandBuffers[frameIndex]);
renderGraph->Execute(frameIndex, commandBuffers[frameIndex], descPool);
}
void SHRenderer::UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept

View File

@ -65,6 +65,7 @@ namespace SHADE
/* Constructor/Destructors */
/*-----------------------------------------------------------------------------*/
SHRenderer(Handle<SHVkLogicalDevice> logicalDevice, uint32_t numFrames, std::vector<Handle<SHVkCommandPool>>& cmdPools, Handle<SHVkDescriptorPool> descriptorPool, Handle<SHVkDescriptorSetLayout> cameraDescLayout, Handle<SHViewport> viewport, Handle<SHRenderGraph> renderGraph);
~SHRenderer(void);
/*-----------------------------------------------------------------------------*/
/* Camera Registration */
@ -74,7 +75,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
/* Drawing Functions */
/*-----------------------------------------------------------------------------*/
void Draw(uint32_t frameIndex) noexcept;
void Draw(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept;
void UpdateDataAndBind (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void UpdateCameraDataToBuffer (void) noexcept;

View File

@ -73,4 +73,16 @@ namespace SHADE
iter->Free();
renderers.erase(iter);
}
void SHViewport::SetWidth(float w) noexcept
{
viewport.width = w;
}
void SHViewport::SetHeight(float h) noexcept
{
viewport.height = h;
}
}

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