diff --git a/Assets/Audio/Master.bank b/Assets/Audio/Master.bank new file mode 100644 index 00000000..a1b4e563 Binary files /dev/null and b/Assets/Audio/Master.bank differ diff --git a/Assets/Audio/Master.strings.bank b/Assets/Audio/Master.strings.bank new file mode 100644 index 00000000..ecad89fe Binary files /dev/null and b/Assets/Audio/Master.strings.bank differ diff --git a/Assets/Audio/footsteps.bank b/Assets/Audio/footsteps.bank new file mode 100644 index 00000000..ce53111e Binary files /dev/null and b/Assets/Audio/footsteps.bank differ diff --git a/Assets/Cube.003.shmesh b/Assets/Cube.003.shmesh new file mode 100644 index 00000000..54cfb867 Binary files /dev/null and b/Assets/Cube.003.shmesh differ diff --git a/Assets/Cube.012.shmesh b/Assets/Cube.012.shmesh new file mode 100644 index 00000000..bc26a4e8 Binary files /dev/null and b/Assets/Cube.012.shmesh differ diff --git a/Assets/RaccoonPreTexturedVer1_Base9.shtex b/Assets/RaccoonPreTexturedVer1_Base9.shtex new file mode 100644 index 00000000..38e0cd0f Binary files /dev/null and b/Assets/RaccoonPreTexturedVer1_Base9.shtex differ diff --git a/Assets/TD_Checker_Base_Color.dds b/Assets/TD_Checker_Base_Color.dds new file mode 100644 index 00000000..9dcbfeee Binary files /dev/null and b/Assets/TD_Checker_Base_Color.dds differ diff --git a/Dependencies.bat b/Dependencies.bat index e16c4267..1d4a3473 100644 --- a/Dependencies.bat +++ b/Dependencies.bat @@ -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! diff --git a/Dependencies.lua b/Dependencies.lua index 9ae406f0..6dd7a711 100644 --- a/Dependencies.lua +++ b/Dependencies.lua @@ -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" \ No newline at end of file diff --git a/SHADE_Application/premake5.lua b/SHADE_Application/premake5.lua index b34b06fa..35ea2c10 100644 --- a/SHADE_Application/premake5.lua +++ b/SHADE_Application/premake5.lua @@ -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"} diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 20aa3b5a..c6da6f1f 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -14,22 +14,34 @@ #include #include #include -#define SDL_HINT_VIDEO_FOREIGN_WINDOW_VULKAN 1 #include -#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::SHSystemManager::CreateSystem(); - // TODO(Diren): Create Physics System here + SHADE::SHSystemManager::CreateSystem(); SHADE::SHSystemManager::CreateSystem(); SHADE::SHGraphicsSystem* graphicsSystem = static_cast(SHADE::SHSystemManager::GetSystem()); - SHADE::SHSystemManager::CreateSystem(); + SHADE::SHSystemManager::CreateSystem(); // Create Routines SHADE::SHSystemManager::RegisterRoutine(); @@ -62,27 +74,37 @@ namespace Sandbox SHADE::SHSystemManager::RegisterRoutine(); SHADE::SHSystemManager::RegisterRoutine(); - // TODO(Diren): Register Physics System & Routines here + SHADE::SHSystemManager::RegisterRoutine(); + SHADE::SHSystemManager::RegisterRoutine(); + SHADE::SHSystemManager::RegisterRoutine(); SHADE::SHSystemManager::RegisterRoutine(); - SHADE::SHComponentManager::CreateComponentSparseSet(); SHADE::SHSystemManager::RegisterRoutine(); SHADE::SHSystemManager::RegisterRoutine(); SHADE::SHSystemManager::RegisterRoutine(); SHADE::SHSystemManager::RegisterRoutine(); - SHADE::SHComponentManager::CreateComponentSparseSet(); + SHADE::SHComponentManager::CreateComponentSparseSet(); + SHADE::SHComponentManager::CreateComponentSparseSet(); SHADE::SHComponentManager::CreateComponentSparseSet(); - - SHADE::SHSystemManager::RegisterRoutine(); + SHADE::SHComponentManager::CreateComponentSparseSet(); //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::GetID(); + auto id2 = SHFamilyID::GetID(); + auto id3 = SHFamilyID::GetID(); + SHADE::SHSystemManager::RegisterRoutine(); + // Set up graphics system and windows graphicsSystem->SetWindow(&window); @@ -94,7 +116,10 @@ namespace Sandbox #else #endif + SHSceneManager::InitSceneManager("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(); } diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index 0f42b419..3b277e6c 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -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::SHSystemManager::GetSystem()); // Create temp meshes const auto CUBE_MESH = SHADE::SHPrimitiveGenerator::Cube(*graphicsSystem); - //graphicsSystem->BuildMeshBuffers(); //Test Racoon mesh auto meshes = SHADE::SHAssetManager::GetAllMeshes(); std::vector> 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> 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(); - // auto& renderable = *SHComponentManager::GetComponent_s(entity); - // auto& transform = *SHComponentManager::GetComponent_s(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(); + for (int y = 0; y < NUM_ROWS; ++y) + for (int x = 0; x < NUM_COLS; ++x) + { + auto entity = SHEntityManager::CreateEntity(); auto& renderable = *SHComponentManager::GetComponent_s(entity); - auto& transform = *SHComponentManager::GetComponent_s(entity); + auto& transform = *SHComponentManager::GetComponent_s(entity); + auto& collider = *SHComponentManager::GetComponent_s(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(); + auto& renderable = *SHComponentManager::GetComponent_s(raccoonSpin); + auto& transform = *SHComponentManager::GetComponent_s(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(); + auto& floorRenderable = *SHComponentManager::GetComponent_s(floor); + auto& floorTransform = *SHComponentManager::GetComponent_s(floor); + auto& floorRigidBody = *SHComponentManager::GetComponent_s(floor); + auto& floorCollider = *SHComponentManager::GetComponent_s(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(); + //auto& testObjRenderable = *SHComponentManager::GetComponent(testObj); + //testObjRenderable.Mesh = CUBE_MESH; + //testObjRenderable.SetMaterial(matInst); + + SHADE::SHScriptEngine* scriptEngine = static_cast(SHADE::SHSystemManager::GetSystem()); - scriptEngine->AddScript(testObj, "TestScript"); + scriptEngine->AddScript(raccoonSpin, "RaccoonSpin"); + + auto raccoonShowcase = SHEntityManager::CreateEntity(); + auto& renderableShowcase = *SHComponentManager::GetComponent_s(raccoonShowcase); + auto& transformShowcase = *SHComponentManager::GetComponent_s(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(testObj); + //auto& transform = *SHADE::SHComponentManager::GetComponent_s(testObj); - transform.SetLocalRotation(rotation, 0.0f, 0.0f); - rotation += dt * 10.0f;*/ - /*static float rotation = 0.0f; + //transform.SetWorldPosition({1.0f, 1.0f, -1.0f}); + //transform.SetWorldRotation(0.0f, 0.0f + rotation, 0.0f); + //rotation += dt * 0.2f; - auto& transform = *SHADE::SHComponentManager::GetComponent_s(stressTestObjects[0]); - - transform.SetWorldPosition({rotation, 0.0f, 0.0f}); - rotation += dt * 10.0f;*/ - // Destroy entity if space is pressed if (GetKeyState(VK_SPACE) & 0x8000) { - SHADE::SHScriptEngine* scriptEngine = static_cast(SHADE::SHSystemManager::GetSystem()); - scriptEngine->RemoveAllScripts(testObj); + rotation = 0.0f; + SHADE::SHScriptEngine* scriptEngine = static_cast(SHADE::SHSystemManager::GetSystem()); + scriptEngine->RemoveAllScripts(testObj); } } void SBTestScene::Render() { + } void SBTestScene::Unload() @@ -138,8 +198,4 @@ namespace Sandbox { //SHSerialization::SerializeScene("resources/scenes/Scene01.SHADE"); } - } - - - diff --git a/SHADE_Engine/premake5.lua b/SHADE_Engine/premake5.lua index 7de741b7..18920194 100644 --- a/SHADE_Engine/premake5.lua +++ b/SHADE_Engine/premake5.lua @@ -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,8 +76,15 @@ project "SHADE_Engine" disablewarnings { - "4251" + "4251", + "26812", + "26439", + "26451", + "26437", + "4275" } + + linkoptions { "-IGNORE:4006" } defines { @@ -104,13 +113,34 @@ project "SHADE_Engine" { "xcopy /s /r /y /q \"%{IncludeDir.spdlog}\\bin\" \"$(OutDir)\"", "xcopy /r /y /q \"%{IncludeDir.SDL}\\lib\\SDL2.dll\" \"$(OutDir)\"", - "xcopy /s /r /y /q \"%{IncludeDir.dotnet}\\bin\" \"$(OutDir)\"" + "xcopy /s /r /y /q \"%{IncludeDir.dotnet}\\bin\" \"$(OutDir)\"" } 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"} \ No newline at end of file + links{"fmodstudio_vc.lib", "fmod_vc.lib"} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h index b4632c2e..68c0d150 100644 --- a/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h +++ b/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h @@ -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 #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 vertexPosition; std::vector vertexTangent; std::vector vertexNormal; diff --git a/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h index d3b69e32..07cebea9 100644 --- a/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h +++ b/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h @@ -1,15 +1,14 @@ #pragma once #include "tinyddsloader.h" - #include "Graphics/MiddleEnd/Textures/SHTextureLibrary.h" -#include - 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 }, diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp b/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp new file mode 100644 index 00000000..12b2517e --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp @@ -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 + +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(&(asset.header.vertexCount)), + sizeof(uint32_t) + ); + + file.write( + reinterpret_cast(&(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(asset.vertexPosition.data()), + vertexVec3Byte + ); + + file.write( + reinterpret_cast(asset.vertexTangent.data()), + vertexVec3Byte + ); + + file.write( + reinterpret_cast(asset.vertexNormal.data()), + vertexVec3Byte + ); + + file.write( + reinterpret_cast(asset.texCoords.data()), + vertexVec2Byte + ); + + file.write( + reinterpret_cast(asset.indices.data()), + sizeof(uint32_t) * asset.header.indexCount + ); + + file.close(); +} diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.h b/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.h new file mode 100644 index 00000000..6da00525 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.h @@ -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; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp index 3ef454a0..3a5fb9ec 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp +++ b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp @@ -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 +#include namespace SHADE { Assimp::Importer SHMeshLoader::aiImporter; - void SHMeshLoader::ProcessNode(aiNode const& node, aiScene const& scene, std::vector& meshes) + void SHMeshLoader::ProcessNode(aiNode const& node, aiScene const& scene, std::vector& 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(result.vertexPosition.size()); + result.header.indexCount = static_cast(result.indices.size()); + result.header.meshName = mesh.mName.C_Str(); return result; } - bool SHMeshLoader::LoadMesh(std::vector& meshes, AssetPath path) - { + void SHMeshLoader::LoadExternal(std::vector& 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 vertPos, vertTan, vertNorm; + std::vector texCoord; + std::vector indices; + + file.read(reinterpret_cast(&vertCount), sizeof(uint32_t)); + file.read(reinterpret_cast(&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(vertPos.data()), vertexVec3Byte); + file.read(reinterpret_cast(vertTan.data()), vertexVec3Byte); + file.read(reinterpret_cast(vertNorm.data()), vertexVec3Byte); + file.read(reinterpret_cast(texCoord.data()), vertexVec2Byte); + file.read(reinterpret_cast(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& meshes, AssetPath path) noexcept + { + if (path.extension().string() == GLTF_EXTENSION) + { + LoadExternal(meshes, path); + return; + } + + meshes.emplace_back(); + LoadSHMesh(meshes.back(), path); } } diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h index fc8b548a..3e430aca 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h +++ b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h @@ -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 #include @@ -12,10 +23,14 @@ namespace SHADE private: static Assimp::Importer aiImporter; - static void ProcessNode(aiNode const& node, aiScene const& scene, std::vector& meshes); + static void ProcessNode(aiNode const& node, aiScene const& scene, std::vector& 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& meshes, AssetPath path) noexcept; + + static void LoadSHMesh(SHMeshAsset& meshes, AssetPath path) noexcept; public: - static bool LoadMesh(std::vector& meshes, AssetPath path); + static void LoadMesh(std::vector& meshes, AssetPath path) noexcept; }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshWriter.cpp b/SHADE_Engine/src/Assets/Libraries/SHMeshWriter.cpp deleted file mode 100644 index 965e7d68..00000000 --- a/SHADE_Engine/src/Assets/Libraries/SHMeshWriter.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "SHpch.h" -#include "SHMeshWriter.h" - -#include - -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(&(asset.header.vertexCount)), - sizeof(uint32_t) - ); - - file.write( - reinterpret_cast(&(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(asset.vertexPosition.data()), - vertexVec3Byte - ); - - file.write( - reinterpret_cast(asset.vertexTangent.data()), - vertexVec3Byte - ); - - file.write( - reinterpret_cast(asset.vertexNormal.data()), - vertexVec3Byte - ); - - file.write( - reinterpret_cast(asset.texCoords.data()), - vertexVec2Byte - ); - - file.close(); -} diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshWriter.h b/SHADE_Engine/src/Assets/Libraries/SHMeshWriter.h deleted file mode 100644 index 4a1a3e6b..00000000 --- a/SHADE_Engine/src/Assets/Libraries/SHMeshWriter.h +++ /dev/null @@ -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; - }; -} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.cpp b/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.cpp new file mode 100644 index 00000000..62af4da6 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.cpp @@ -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 + +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(asset.mipOffsets.size()) }; + + file.write( + reinterpret_cast(&asset.numBytes), + intBytes + ); + + file.write( + reinterpret_cast(&asset.width), + intBytes + ); + + file.write( + reinterpret_cast(&asset.height), + intBytes + ); + + file.write( + reinterpret_cast(&asset.format), + sizeof(SHTexture::TextureFormat) + ); + + file.write( + reinterpret_cast(&mipOffsetCount), + intBytes + ); + + file.write( + reinterpret_cast(asset.mipOffsets.data()), + intBytes * asset.mipOffsets.size() + ); + + file.write( + reinterpret_cast(asset.pixelData), + asset.numBytes + ); + + file.close(); + } +} diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.h b/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.h new file mode 100644 index 00000000..d8685795 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.h @@ -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); + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp index 33270bb6..47501d42 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp +++ b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp @@ -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 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(totalBytes); + totalBytes += file.GetImageData(static_cast(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(file.GetDDSData())); - asset.numBytes = totalBytes; + asset.compiled = false; + asset.numBytes = static_cast(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(&asset.numBytes), intBytes); + file.read(reinterpret_cast(&asset.width), intBytes); + file.read(reinterpret_cast(&asset.height), intBytes); + file.read(reinterpret_cast(&asset.format), sizeof(SHTexture::TextureFormat)); + + file.read(reinterpret_cast(&mipCount), intBytes); + std::vector mips(mipCount); + file.read(reinterpret_cast(mips.data()), intBytes * mipCount); + + auto pixel = new SHTexture::PixelChannel[asset.numBytes]; + file.read(reinterpret_cast(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); + } + } } diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h index 281a9a19..e84fe5cf 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h +++ b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h @@ -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); }; diff --git a/SHADE_Engine/src/Assets/SHAsset.h b/SHADE_Engine/src/Assets/SHAsset.h index 0ba2285f..8d7b55d1 100644 --- a/SHADE_Engine/src/Assets/SHAsset.h +++ b/SHADE_Engine/src/Assets/SHAsset.h @@ -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" diff --git a/SHADE_Engine/src/Assets/SHAssetManager.cpp b/SHADE_Engine/src/Assets/SHAssetManager.cpp index 60e35ab3..430b8c79 100644 --- a/SHADE_Engine/src/Assets/SHAssetManager.cpp +++ b/SHADE_Engine/src/Assets/SHAssetManager.cpp @@ -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); + } } /**************************************************************************** diff --git a/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp b/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp index aabb0dc0..6554a3e4 100644 --- a/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp +++ b/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp @@ -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); @@ -109,9 +110,21 @@ namespace SHADE SHLOG_ERROR("Asset write path is invalid: {}", path); return; } - + + metaFile << "Name: " << meta.name << "\n"; metaFile << "ID: " << meta.id << "\n"; metaFile << "Type: " << static_cast(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(); } diff --git a/SHADE_Engine/src/AudioSystem/SHAudioListenerComponent.cpp b/SHADE_Engine/src/AudioSystem/SHAudioListenerComponent.cpp new file mode 100644 index 00000000..988b2781 --- /dev/null +++ b/SHADE_Engine/src/AudioSystem/SHAudioListenerComponent.cpp @@ -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; + } + +} + diff --git a/SHADE_Engine/src/AudioSystem/SHAudioListenerComponent.h b/SHADE_Engine/src/AudioSystem/SHAudioListenerComponent.h new file mode 100644 index 00000000..e0fa8104 --- /dev/null +++ b/SHADE_Engine/src/AudioSystem/SHAudioListenerComponent.h @@ -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 + diff --git a/SHADE_Engine/src/AudioSystem/SHAudioSourceComponent.cpp b/SHADE_Engine/src/AudioSystem/SHAudioSourceComponent.cpp new file mode 100644 index 00000000..2d623ede --- /dev/null +++ b/SHADE_Engine/src/AudioSystem/SHAudioSourceComponent.cpp @@ -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()->PlaySFX(id, GetEID(),loop,spatial, min, max); + } + + void SHAudioSourceComponent::PlaySoundBGM(EntityID id, bool loop, bool spatial, float min, float max) + { + SHSystemManager::GetSystem()->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()->StopSound(id); + } + + /** + * @brief Mute the sound + * + * @param index where the sound is in the index + */ + void SHAudioSourceComponent::SetMute(EntityID id, bool mute) + { + SHSystemManager::GetSystem()->SetMute(id, mute); + } +} + diff --git a/SHADE_Engine/src/AudioSystem/SHAudioSourceComponent.h b/SHADE_Engine/src/AudioSystem/SHAudioSourceComponent.h new file mode 100644 index 00000000..987dc3d4 --- /dev/null +++ b/SHADE_Engine/src/AudioSystem/SHAudioSourceComponent.h @@ -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 + diff --git a/SHADE_Engine/src/AudioSystem/SHAudioSystem.cpp b/SHADE_Engine/src/AudioSystem/SHAudioSystem.cpp new file mode 100644 index 00000000..c3c7ef03 --- /dev/null +++ b/SHADE_Engine/src/AudioSystem/SHAudioSystem.cpp @@ -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 + +#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 +#include +#include +#include + +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::SHComponentManager::CreateComponentSparseSet(); + + denseListener = &SHComponentManager::GetDense(); + 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(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(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(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(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(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(eid)) + { + SHTransformComponent* audioTransform = SHComponentManager::GetComponent_s(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(eid)) + { + SHTransformComponent* audioTransform = SHComponentManager::GetComponent_s(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 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 SHAudioSystem::GetAllEvents() + //{ + // int count{}; + // stringsBank->getEventCount(&count); + + // std::vector events(count); + // auto eventData = events.data(); + // int finalCount{}; + // stringsBank->getEventList(eventData, count, &finalCount); + // std::vector 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(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(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 instances(instanceCount); + event.second->getInstanceList(instances.data(), static_cast(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(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 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(); + 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(); + 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) + + diff --git a/SHADE_Engine/src/AudioSystem/SHAudioSystem.h b/SHADE_Engine/src/AudioSystem/SHAudioSystem.h new file mode 100644 index 00000000..f19fcc3b --- /dev/null +++ b/SHADE_Engine/src/AudioSystem/SHAudioSystem.h @@ -0,0 +1,110 @@ +#pragma once +#include +#include +#include +#include +#include +#include "ECS_Base/System/SHSystem.h" +#include "ECS_Base/System/SHSystemRoutine.h" +#include "ECS_Base/SHECSMacros.h" +#include "Math/SHMath.h" +#include +#include +#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::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 GetEventGUID(const char* path); + AudioClip* CreateAudioClip(const char* path); + //std::vector 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 soundList; + //std::unordered_map bankMap; + std::unordered_map bankMap; + std::unordered_map eventMap; + std::unordered_map 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* denseListener; + AudioClipID clipID = 0; + }; + +} + diff --git a/SHADE_Engine/src/ECS_Base/Components/SHComponent.h b/SHADE_Engine/src/ECS_Base/Components/SHComponent.h index aba3ba51..cfcd724c 100644 --- a/SHADE_Engine/src/ECS_Base/Components/SHComponent.h +++ b/SHADE_Engine/src/ECS_Base/Components/SHComponent.h @@ -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; } diff --git a/SHADE_Engine/src/ECS_Base/Events/SHComponentAddedEvent.h b/SHADE_Engine/src/ECS_Base/Events/SHComponentAddedEvent.h new file mode 100644 index 00000000..1f2b62d5 --- /dev/null +++ b/SHADE_Engine/src/ECS_Base/Events/SHComponentAddedEvent.h @@ -0,0 +1,12 @@ +#pragma once + +#include "ECS_Base/Components/SHComponent.h" + +namespace SHADE +{ + struct SHComponentAddedEvent + { + EntityID eid; + ComponentTypeID addedComponentType; + }; +} diff --git a/SHADE_Engine/src/ECS_Base/Events/SHComponentRemovedEvent.h b/SHADE_Engine/src/ECS_Base/Events/SHComponentRemovedEvent.h new file mode 100644 index 00000000..34d6f9c8 --- /dev/null +++ b/SHADE_Engine/src/ECS_Base/Events/SHComponentRemovedEvent.h @@ -0,0 +1,12 @@ +#pragma once + +#include "ECS_Base/Components/SHComponent.h" + +namespace SHADE +{ + struct SHComponentRemovedEvent + { + EntityID eid; + ComponentTypeID removedComponentType; + }; +} diff --git a/SHADE_Engine/src/ECS_Base/General/SHFamily.cpp b/SHADE_Engine/src/ECS_Base/General/SHFamily.cpp new file mode 100644 index 00000000..bd5c0378 --- /dev/null +++ b/SHADE_Engine/src/ECS_Base/General/SHFamily.cpp @@ -0,0 +1,14 @@ +#pragma once +#include "SHFamily.h" +#include "SHpch.h" + +namespace SHADE +{ + //initialize currentID as 0 + + + + + + +} diff --git a/SHADE_Engine/src/ECS_Base/General/SHFamily.h b/SHADE_Engine/src/ECS_Base/General/SHFamily.h index 5815703f..51bd6a25 100644 --- a/SHADE_Engine/src/ECS_Base/General/SHFamily.h +++ b/SHADE_Engine/src/ECS_Base/General/SHFamily.h @@ -14,16 +14,17 @@ #pragma once #include "../SHECSMacros.h" +#include "SH_API.h" namespace SHADE { + template - 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 - 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::currentID++; return id; + //return 0; } +#else + template + static SH_API ENABLE_IF_DERIVED(ComponentTypeID, BaseClass, DerivedClass) GetID() noexcept; +#endif // SH_API_EXPORT + + + + + }; - //initialize currentID as 0 - template - ComponentTypeID SHFamilyID::currentID = 0; + + + } \ No newline at end of file diff --git a/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h b/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h index 60625d6a..8921fbce 100644 --- a/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h +++ b/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h @@ -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 @@ -216,6 +219,11 @@ namespace SHADE comp->OnCreate(); } + SHComponentAddedEvent eventData; + eventData.eid = entityID; + eventData.addedComponentType = ComponentFamily::GetID(); + + SHEventManager::BroadcastEvent(eventData, SH_COMPONENT_ADDED_EVENT); } /************************************************************************** @@ -247,6 +255,13 @@ namespace SHADE { comp->OnCreate(); } + + SHComponentAddedEvent eventData; + eventData.eid = entityID; + eventData.addedComponentType = componentTypeID; + + SHEventManager::BroadcastEvent(eventData, SH_COMPONENT_ADDED_EVENT); + } @@ -313,6 +328,12 @@ namespace SHADE componentSet.GetSparseSet()->Remove(EntityHandleGenerator::GetIndex(entityID)); + + SHComponentRemovedEvent eventData; + eventData.eid = entityID; + eventData.removedComponentType = ComponentFamily::GetID(); + + SHEventManager::BroadcastEvent(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 diff --git a/SHADE_Engine/src/ECS_Base/Managers/SHSystemManager.h b/SHADE_Engine/src/ECS_Base/Managers/SHSystemManager.h index f92f6635..995a1cf5 100644 --- a/SHADE_Engine/src/ECS_Base/Managers/SHSystemManager.h +++ b/SHADE_Engine/src/ECS_Base/Managers/SHSystemManager.h @@ -68,6 +68,9 @@ namespace SHADE id = ((SystemID)version << sizeof(SystemVersionID) * CHAR_BIT) + typeID; } systemContainer.emplace(id, std::make_unique()); + + auto size = systemContainer.size(); + systemContainer[id].get()->systemID = id; return id; diff --git a/SHADE_Engine/src/ECS_Base/SHECSMacros.h b/SHADE_Engine/src/ECS_Base/SHECSMacros.h index 02615ca4..4690099f 100644 --- a/SHADE_Engine/src/ECS_Base/SHECSMacros.h +++ b/SHADE_Engine/src/ECS_Base/SHECSMacros.h @@ -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 \ No newline at end of file diff --git a/SHADE_Engine/src/ECS_Base/System/SHFixedSystemRoutine.h b/SHADE_Engine/src/ECS_Base/System/SHFixedSystemRoutine.h index d9a2b510..d54d9441 100644 --- a/SHADE_Engine/src/ECS_Base/System/SHFixedSystemRoutine.h +++ b/SHADE_Engine/src/ECS_Base/System/SHFixedSystemRoutine.h @@ -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 {} }; diff --git a/SHADE_Engine/src/ECS_Base/System/SHSystem.h b/SHADE_Engine/src/ECS_Base/System/SHSystem.h index 93ea6a59..fe852b9a 100644 --- a/SHADE_Engine/src/ECS_Base/System/SHSystem.h +++ b/SHADE_Engine/src/ECS_Base/System/SHSystem.h @@ -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; + + + } \ No newline at end of file diff --git a/SHADE_Engine/src/ECS_Base/UnitTesting/SHTestComponents.h b/SHADE_Engine/src/ECS_Base/UnitTesting/SHTestComponents.h index e2e53d6b..b95a0233 100644 --- a/SHADE_Engine/src/ECS_Base/UnitTesting/SHTestComponents.h +++ b/SHADE_Engine/src/ECS_Base/UnitTesting/SHTestComponents.h @@ -1,6 +1,7 @@ #pragma once #include "../Components/SHComponent.h" +#include 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("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_("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)); + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/Command/SHCommand.hpp b/SHADE_Engine/src/Editor/Command/SHCommand.hpp index ae8834e9..7a526506 100644 --- a/SHADE_Engine/src/Editor/Command/SHCommand.hpp +++ b/SHADE_Engine/src/Editor/Command/SHCommand.hpp @@ -5,9 +5,13 @@ //#==============================================================# #include +#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(SHSystemManager::GetSystem()); + scriptEngine->RedoScriptInspectorChanges(); + } + void Undo() override + { + SHScriptEngine* scriptEngine = static_cast(SHSystemManager::GetSystem()); + scriptEngine->UndoScriptInspectorChanges(); + } + }; }//namespace SHADE diff --git a/SHADE_Engine/src/Editor/Command/SHCommandManager.cpp b/SHADE_Engine/src/Editor/Command/SHCommandManager.cpp index 67d6c2ee..ee2d316d 100644 --- a/SHADE_Engine/src/Editor/Command/SHCommandManager.cpp +++ b/SHADE_Engine/src/Editor/Command/SHCommandManager.cpp @@ -27,6 +27,11 @@ namespace SHADE } } + void SHCommandManager::RegisterCommand(CommandPtr commandPtr) + { + undoStack.push(commandPtr); + } + void SHCommandManager::UndoCommand() { if (undoStack.empty()) diff --git a/SHADE_Engine/src/Editor/Command/SHCommandManager.h b/SHADE_Engine/src/Editor/Command/SHCommandManager.h index 3ea42740..9152c3cb 100644 --- a/SHADE_Engine/src/Editor/Command/SHCommandManager.h +++ b/SHADE_Engine/src/Editor/Command/SHCommandManager.h @@ -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; 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(); diff --git a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp index f787d4db..25cd5a6a 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp @@ -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(entity), nodeFlags, "%u: %s", EntityHandleGenerator::GetIndex(eid), entity->name.c_str()); const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); //Check For Begin Drag diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 080cbf2c..a546504b 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -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::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()) + if(type.is_enumeration()) { - DragVec4(property.get_name().data(), { "X", "Y", "Z", "W" }, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec4 vec) {return property.set_value(component, vec); }); + auto enumAlign = type.get_enumeration(); + auto names = enumAlign.get_names(); + std::vector 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()) + { + 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()) + //{ + // + //} + else if (type == rttr::type::get() || type == rttr::type::get() || type == rttr::type::get() || type == rttr::type::get()) + { + 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(), metaMin.template get_value(), [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()) + { + auto metaMin = property.get_metadata(META::min); + auto metaMax = property.get_metadata(META::max); + if(metaMin.is_valid() && metaMax.is_valid()) + { + SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_U8, metaMin.template get_value(), metaMax.template get_value(), [component, property]{return property.get_value(component).to_uint8();}, [component, property](uint8_t const& result){property.set_value(component, result);},"%zu"); + } + else + { + SHEditorWidgets::DragScalar(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()) + { + auto metaMin = property.get_metadata(META::min); + auto metaMax = property.get_metadata(META::max); + if(metaMin.is_valid() && metaMax.is_valid()) + { + SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_uint16();}, [component, property](uint16_t const& result){property.set_value(component, result);},"%zu"); + } + else + { + SHEditorWidgets::DragScalar(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()) + { + auto metaMin = property.get_metadata(META::min); + auto metaMax = property.get_metadata(META::max); + if (metaMin.is_valid() && metaMax.is_valid()) + { + SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value(), metaMin.template get_value(), [component, property]{ return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result){property.set_value(component, result); },"%zu"); + } + else + { + SHEditorWidgets::DragScalar(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()) + { + auto metaMin = property.get_metadata(META::min); + auto metaMax = property.get_metadata(META::max); + if(metaMin.is_valid() && metaMax.is_valid()) + { + SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_uint64();}, [component, property](uint64_t const& result){property.set_value(component, result);},"%zu"); + } + else + { + SHEditorWidgets::DragScalar(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()) + { + 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(), metaMin.template get_value(), [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()) + { + auto metaMin = property.get_metadata(META::min); + auto metaMax = property.get_metadata(META::max); + if(metaMin.is_valid() && metaMax.is_valid()) + { + SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_double();}, [component, property](double const& result){property.set_value(component, result);}); + } + else + { + SHEditorWidgets::DragScalar(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()) + { + SHEditorWidgets::DragVec4(property.get_name().data(), { "X", "Y", "Z", "W" }, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec4 vec) {return property.set_value(component, vec); }); } else if (type == rttr::type::get()) { - DragVec3(property.get_name().data(), { "X", "Y", "Z" }, [component, property]() {return property.get_value(component).template convert(); }, [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(); }, [component, property](SHVec3 vec) {return property.set_value(component, vec); }); } + else if (type == rttr::type::get()) + { + SHEditorWidgets::DragVec2(property.get_name().data(), { "X", "Y"}, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec2 vec) {return property.set_value(component, vec); }); + } + } } else DrawContextMenu(component); diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index fba9512e..3d00ac4b 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -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(); + 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(eid)) + { + DrawComponent(renderableComponent); + } + if(auto colliderComponent = SHComponentManager::GetComponent_s(eid)) + { + DrawComponent(colliderComponent); + } + if(auto rigidbodyComponent = SHComponentManager::GetComponent_s(eid)) + { + DrawComponent(rigidbodyComponent); + } + ImGui::Separator(); + // Render Scripts + SHScriptEngine* scriptEngine = static_cast(SHSystemManager::GetSystem()); + scriptEngine->RenderScriptsInInspector(eid); ImGui::Separator(); if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data())) { DrawAddComponentButton(eid); DrawAddComponentButton(eid); + DrawAddComponentButton(eid); + DrawAddComponentButton(eid); ImGui::EndMenu(); } + } ImGui::End(); } diff --git a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp index 7e5f762c..8e26ae78 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp @@ -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 #include -#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(SHSystemManager::GetSystem()); + scriptEngine->GenerateScriptsCsProjFile(); + } + if (ImGui::Selectable("Build Scripts - Debug")) + { + auto* scriptEngine = static_cast(SHSystemManager::GetSystem()); + scriptEngine->BuildScriptAssembly(true, true); + } + if (ImGui::Selectable("Build Scripts - Release")) + { + auto* scriptEngine = static_cast(SHSystemManager::GetSystem()); + scriptEngine->BuildScriptAssembly(false, true); + } + ImGui::EndMenu(); + } ImGui::EndMainMenuBar(); } diff --git a/SHADE_Engine/src/Editor/EditorWindow/Profiling/SHEditorProfiler.cpp b/SHADE_Engine/src/Editor/EditorWindow/Profiling/SHEditorProfiler.cpp new file mode 100644 index 00000000..4b36fe5d --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/Profiling/SHEditorProfiler.cpp @@ -0,0 +1,48 @@ +#include "SHpch.h" +#include "SHEditorProfiler.h" +#include + +#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(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(frames.size()), 0, nullptr, 0.0f, 16.0f); + ImGui::End(); + } + } + + void SHEditorProfiler::Exit() + { + SHEditorWindow::Exit(); + } +} diff --git a/SHADE_Engine/src/Editor/EditorWindow/Profiling/SHEditorProfiler.h b/SHADE_Engine/src/Editor/EditorWindow/Profiling/SHEditorProfiler.h new file mode 100644 index 00000000..3f817a53 --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/Profiling/SHEditorProfiler.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Editor/EditorWindow/SHEditorWindow.h" +#include +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 frames; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h index 2ed34109..d1ebfbf4 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h +++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h @@ -1,4 +1,5 @@ #pragma once #include "MenuBar/SHEditorMenuBar.h" //Menu Bar #include "HierarchyPanel/SHHierarchyPanel.h" //Hierarchy Panel -#include "Inspector/SHEditorInspector.h" //Inspector \ No newline at end of file +#include "Inspector/SHEditorInspector.h" //Inspector +#include "Profiling/SHEditorProfiler.h" //Profiler \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/IconsMaterialDesign.h b/SHADE_Engine/src/Editor/IconsMaterialDesign.h index 68373237..3f15892b 100644 --- a/SHADE_Engine/src/Editor/IconsMaterialDesign.h +++ b/SHADE_Engine/src/Editor/IconsMaterialDesign.h @@ -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 diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index 34ebe6a6..e94f7398 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -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::GetID(); + auto id2 = SHFamilyID::GetID(); + auto id3 = SHFamilyID::GetID(); InitBackend(sdlWindow); SetStyle(Style::SHADE); @@ -95,6 +102,7 @@ namespace SHADE CreateEditorWindow(); CreateEditorWindow(); CreateEditorWindow(); + CreateEditorWindow(); 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& cmd) { diff --git a/SHADE_Engine/src/Editor/SHEditorUI.cpp b/SHADE_Engine/src/Editor/SHEditorUI.cpp new file mode 100644 index 00000000..65b65827 --- /dev/null +++ b/SHADE_Engine/src/Editor/SHEditorUI.cpp @@ -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 +#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(value); + ImGui::Text(label.c_str()); + ImGui::SameLine(); + const bool CHANGED = InputInt("#", signedVal); + if (CHANGED) + { + signedVal = std::clamp(signedVal, 0, std::numeric_limits::max()); + value = static_cast(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(value); + ImGui::Text(label.c_str()); + ImGui::SameLine(); + const bool CHANGED = ImGui::SliderFloat("#", &val, + static_cast(min), static_cast(max), "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + + if (CHANGED) + { + value = val; + } + + return CHANGED; + } + + bool SHEditorUI::InputVec2(const std::string& label, SHVec2& value) + { + static const std::vector COMPONENT_LABELS = { "X", "Y" }; + return SHEditorWidgets::DragN(label, COMPONENT_LABELS, { &value.x, &value.y }); + } + bool SHEditorUI::InputVec3(const std::string& label, SHVec3& value, float speed) + { + static const std::vector COMPONENT_LABELS = { "X", "Y", "Z"}; + return SHEditorWidgets::DragN(label, COMPONENT_LABELS, { &value.x, &value.y, &value.z }, speed, "%.3f"); + } + + bool SHEditorUI::InputTextField(const std::string& label, std::string& value) + { + std::array 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& enumNames) + { + // Clamp input value + const std::string& INITIAL_NAME = v >= static_cast(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; + } +} diff --git a/SHADE_Engine/src/Editor/SHEditorUI.h b/SHADE_Engine/src/Editor/SHEditorUI.h new file mode 100644 index 00000000..13468215 --- /dev/null +++ b/SHADE_Engine/src/Editor/SHEditorUI.h @@ -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 // std::function +#include // 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 +{ + /// + /// Static class that contains useful functions for Editor UI using ImGui. + /// + class SH_API SHEditorUI final + { + public: + /*-----------------------------------------------------------------------------*/ + /* Constants */ + /*-----------------------------------------------------------------------------*/ + /// + /// Maximum length of a string supported by InputTextField() + /// + static constexpr size_t TEXT_FIELD_MAX_LENGTH = 256; + + /*-----------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - ID Stack */ + /*-----------------------------------------------------------------------------*/ + /// + /// Marks the start of a stack of ImGui widgets with the specified id. + ///
+ /// Wraps up ImGui::PushID(). + ///
+ /// String-based ID. + static void PushID(const std::string& id); + /// + /// Marks the start of a stack of ImGui widgets with the specified id. + ///
+ /// Wraps up ImGui::PushID(). + ///
+ /// Integer-based ID. + static void PushID(int id); + /// + /// Marks the end of a stack of ImGui widgets from the last PushID() call. + ///
+ /// Wraps up ImGui::PopID(). + ///
+ static void PopID(); + + /*-----------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Indent */ + /*-----------------------------------------------------------------------------*/ + /// + /// Indents the widgets rendered after this call. + ///
+ /// Wraps up ImGui::Indent(). + ///
+ static void Indent(); + /// + /// Unindents the widgets rendered after this call. + ///
+ /// Wraps up ImGui::Unindent(). + ///
+ static void Unindent(); + + /*-----------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Organizers */ + /*-----------------------------------------------------------------------------*/ + /// + /// Creates a collapsing title header. + ///
+ /// Wraps up ImGui::CollapsingHeader(). + ///
+ /// Label for the header. + /// True if the header is open, false otherwise. + 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 */ + /*-----------------------------------------------------------------------------*/ + /// + /// Marks the start of a definition of a mini pop up that can show options. + ///
+ /// Wraps up ImGui::BeginPopup(). + ///
+ /// Label used to identify this widget. + /// Whether or not the pop up is open. + static bool BeginPopup(const std::string& label); + static bool BeginPopupContextItem(const std::string& label); + /// + /// Marks the end of a definition of a mini pop up that can show options. + ///
+ /// Wraps up ImGui::EndPopup(). + ///
+ static void EndPopup(); + /// + /// Opens the popup that was defined with the specified label. + ///
+ /// Wraps up ImGui::OpenPopup(). + ///
+ static void OpenPopup(const std::string& label); + /// + /// Creates a menu item in the list of items for a mini popup. + ///
+ /// Wraps up ImGui::MenuItem(). + ///
+ /// Label used to identify this widget. + /// Whether or not the menu item was selected. + static bool MenuItem(const std::string& label); + + /*-----------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Widgets */ + /*-----------------------------------------------------------------------------*/ + /// + /// Creates a visual text widget. + ///
+ /// Wraps up ImGui::Text(). + ///
+ /// Text to display. + static void Text(const std::string& title); + /// + /// Creates a small inline button widget. + ///
+ /// Wraps up ImGui::SmallButton(). + ///
+ /// Text to display. + /// True if button was pressed. + static bool SmallButton(const std::string& title); + /// + /// Creates a inline button widget. + ///
+ /// Wraps up ImGui::Button(). + ///
+ /// Text to display. + /// True if button was pressed. + static bool Button(const std::string& title); + static bool Selectable(const std::string& label); + static bool Selectable(const std::string& label, const char* icon); + /// + /// Creates a checkbox widget for boolean input. + ///
+ /// Wraps up ImGui::Checkbox(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputCheckbox(const std::string& label, bool& value); + /// + /// Creates a integer field widget for integer input. + ///
+ /// Wraps up ImGui::InputInt(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputInt(const std::string& label, int& value); + /// + /// Creates a integer field widget for unsigned integer input. + ///
+ /// Wraps up ImGui::InputInt() with an additional clamping of values. + ///
+ /// 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. + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputUnsignedInt(const std::string& label, unsigned int& value); + /// + /// Creates a decimal field widget for single precision float input. + ///
+ /// Wraps up ImGui::InputFloat(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputFloat(const std::string& label, float& value); + /// + /// Creates a decimal field widget for double precision float input. + ///
+ /// Wraps up ImGui::InputDouble(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputDouble(const std::string& label, double& value); + /// + /// Creates a decimal field widget for double input with increments of higher + /// steps meant for angle variables. + ///
+ /// Wraps up ImGui::InputDouble(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputAngle(const std::string& label, double& value); + /// + /// Creates a double slider field widget for double input. + ///
+ /// Wraps up ImGui::InputSliderFloat(). + ///
+ /// Label used to identify this widget. + /// Minimum value of the slider. + /// Maximum value of the slider. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputSlider(const std::string& label, double min, double max, double& value); + /// + /// Creates a 2x double field widget for Vector2 input. + ///
+ /// Wraps up ImGui::InputFloat2(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputVec2(const std::string& label, SHVec2& value); + /// + /// Creates a 3x double field widget for Vector3 input. + ///
+ /// Wraps up ImGui::InputFloat3(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputVec3(const std::string& label, SHVec3& value, float speed = 0.1f); + /// + /// Creates a text field widget for string input. + ///
+ /// Wraps up ImGui::InputText(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputTextField(const std::string& label, std::string& value); + /// + /// Creates a combo box for enumeration input. + /// + /// The type of enum to input. + /// The name of the input. + /// The reference to the value to modify. + /// The maximum value of the enum. + /// + /// Conversion function from the type of enum to C-style string. + /// + /// Whether the value was modified. + template + static bool InputEnumCombo(const std::string& label, Enum& v, int maxVal, std::function toStrFn); + /// + /// Creates a combo box for enumeration input using a specified list of names. + /// + /// The name of the input. + /// The reference to the value to modify. + /// Vector of names for each enumeration value. + /// Whether the value was modified. + static bool InputEnumCombo(const std::string& label, int& v, const std::vector& enumNames); + + + private: + // Prevent instantiation of this static class + SHEditorUI() = delete; + }; +} + +#include "SHEditorUI.hpp" \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/SHEditorUI.hpp b/SHADE_Engine/src/Editor/SHEditorUI.hpp new file mode 100644 index 00000000..f3af0412 --- /dev/null +++ b/SHADE_Engine/src/Editor/SHEditorUI.hpp @@ -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 + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Widgets */ + /*---------------------------------------------------------------------------------*/ + template + inline bool SHEditorUI::InputEnumCombo(const std::string& label, Enum& v, int maxVal, std::function toStrFn) + { + std::vector values; + for (int i = 0; i <= maxVal; ++i) + { + values.emplace_back(static_cast(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; + } +} diff --git a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp index 4a934e8c..8d2adcc6 100644 --- a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp +++ b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp @@ -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 - static bool DragN(const std::string& fieldLabel, std::vectorconst& componentLabels, - std::vector 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(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); + 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); + } + + template + static bool DragN(const std::string& fieldLabel, std::vectorconst& componentLabels, + std::vector 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(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::PopItemWidth(); + ImGui::EndGroup(); + + return valueChanged; } - ImGui::EndColumns(); - ImGui::PopID(); - ImGui::EndGroup(); - - return valueChanged; - } - + static bool DragVec2(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, - std::function 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(fieldLabel, componentLabels, {&values.x, &values.y}, speed, displayFormat, valueMin, valueMax, flags)) + std::function 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(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(std::make_shared>(get(), values, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), true); + else if (ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); + } + + return changed; } - - if (changed) + + static bool DragVec3(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, + std::function 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(std::make_shared>(get(), values, set)), false); - else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), true); - else if(ImGui::IsItemDeactivatedAfterEdit()) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); + SHVec3 values = get(); + bool changed = false; + if (DragN(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(std::make_shared>(get(), values, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), true); + else if (ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); + } + + return changed; } - - return changed; - } - - static bool DragVec3(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, - std::function 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(fieldLabel, componentLabels, {&values.x, &values.y, &values.z}, speed, displayFormat, valueMin, valueMax, flags)) + + static bool DragVec4(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, + std::function 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(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(std::make_shared>(get(), values, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), true); + else if (ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); + } + + return changed; } - - if (changed) + + //#==============================================================# + //|| Widget Extensions || + //#==============================================================# + + static bool CheckBox(std::string const& label, std::function get, std::function set) { - if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); - else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), true); - else if(ImGui::IsItemDeactivatedAfterEdit()) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); + bool value = get(); + if (ImGui::Checkbox(label.c_str(), &value)) + { + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + return true; + } + return false; } - - return changed; - } - - static bool DragVec4(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, - std::function 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(fieldLabel, componentLabels, {&values.x, &values.y, &values.z, &values.w}, speed, displayFormat, valueMin, valueMax, flags)) + + template + static bool RadioButton(std::vector const& listLabels, std::vector const& listTypes, std::function get, std::function set) { - changed = true; - } - - if (changed) - { - if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); - else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), true); - else if(ImGui::IsItemDeactivatedAfterEdit()) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); - } - - return changed; - } - - //#==============================================================# - //|| Widget Extensions || - //#==============================================================# - - static bool CheckBox(std::string const& label, std::function get, std::function set) - { - bool value = get(); - if (ImGui::Checkbox(label.c_str(), &value)) - { - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(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(std::make_shared>(get(), listTypes[i], set)), false); + } + ImGui::SameLine(); + } return true; } - return false; - } - - template - static bool RadioButton(std::vector const& listLabels, std::vector const& listTypes, std::function get, std::function set) - { - T type = get(); - for (size_t i = 0; i < listTypes.size(); i++) + + static bool InputText(const std::string& label, const std::function get, + const std::function 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(std::make_shared>(get(), listTypes[i], set)), false); + if (ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), text, set)), false); + + return true; } - ImGui::SameLine(); + return false; } - return true; - } - - - + + template + static bool DragScalar(const std::string& fieldLabel, ImGuiDataType data_type, std::function get, std::function 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(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + else if (ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + + return true; + } + return false; + } + + static bool DragFloat(const std::string& fieldLabel, std::function get, std::function 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(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + else if (ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + + return true; + } + + return false; + } + + static bool DragInt(const std::string& fieldLabel, std::function get, std::function 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(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + else if (ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + + return true; + } + + return false; + } + template + static bool SliderScalar(const std::string& fieldLabel, ImGuiDataType data_type, T min, T max, std::function get, std::function 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(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + + return true; + } + + return false; + } + + static bool SliderFloat(const std::string& fieldLabel, float min, float max, std::function get, std::function 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(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + + + return true; + } + + return false; + } + + static bool SliderInt(const std::string& fieldLabel, int min, int max, std::function get, std::function 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(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + + return true; + } + + return false; + } + + static bool ComboBox(const std::string& fieldLabel, std::vector list, std::function get, std::function 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(list.size()))) + { + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), selected, set)), false); + } + ImGui::PopID(); + return edited; + } + }; }//namespace SHADE diff --git a/SHADE_Engine/src/Events/SHEventDefines.h b/SHADE_Engine/src/Events/SHEventDefines.h index f1e92b42..317b67c1 100644 --- a/SHADE_Engine/src/Events/SHEventDefines.h +++ b/SHADE_Engine/src/Events/SHEventDefines.h @@ -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 }; diff --git a/SHADE_Engine/src/FRC/SHFramerateController.cpp b/SHADE_Engine/src/FRC/SHFramerateController.cpp index d64c6336..0791d628 100644 --- a/SHADE_Engine/src/FRC/SHFramerateController.cpp +++ b/SHADE_Engine/src/FRC/SHFramerateController.cpp @@ -9,12 +9,31 @@ consent of DigiPen Institute of Technology is prohibited. *********************************************************************/ + +//TODO Legacy code. Delete soon + #include #include #include #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 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 @@ -131,4 +150,5 @@ namespace SHADE currentScene = nextScene; } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/SHADE_Engine/src/FRC/SHFramerateController.h b/SHADE_Engine/src/FRC/SHFramerateController.h index 26f276d8..b9637cf2 100644 --- a/SHADE_Engine/src/FRC/SHFramerateController.h +++ b/SHADE_Engine/src/FRC/SHFramerateController.h @@ -13,6 +13,38 @@ #define SH_FRAMERATECONTROLLER_H #pragma once +#include +#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 \ No newline at end of file diff --git a/SHADE_Engine/src/Filesystem/SHFileSystem.cpp b/SHADE_Engine/src/Filesystem/SHFileSystem.cpp index 16175578..bd34ed71 100644 --- a/SHADE_Engine/src/Filesystem/SHFileSystem.cpp +++ b/SHADE_Engine/src/Filesystem/SHFileSystem.cpp @@ -2,7 +2,6 @@ #include "SHFileSystem.h" #include "fileapi.h" #include -#include #include namespace SHADE @@ -27,8 +26,11 @@ namespace SHADE } auto const count = static_cast(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(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(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(location, name); folders[location]->path = path; diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp index eb65598c..9ebbd227 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp @@ -24,7 +24,7 @@ namespace SHADE /***************************************************************************/ SHVkCommandBuffer::~SHVkCommandBuffer(void) noexcept { - if (vkCommandBuffer) + if (vkCommandBuffer && parentPool) parentPool->GetLogicalDevice()->GetVkLogicalDevice().freeCommandBuffers(parentPool->GetVkCommandPool(), commandBufferCount, &vkCommandBuffer); } diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.cpp b/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.cpp index 881ee998..e1470898 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.cpp +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.cpp @@ -102,8 +102,6 @@ namespace SHADE logicalDeviceHdl = rhs.logicalDeviceHdl; transient = rhs.transient; - static_cast&>(*this) = static_cast&>(rhs); - rhs.vkCommandPool = VK_NULL_HANDLE; return *this; diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h index 91112496..9a533d06 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h @@ -39,8 +39,10 @@ namespace SHADE std::vector 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 } }; /// /// Maximum number of descriptor sets allowed diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp index c1732535..e842df47 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp @@ -155,7 +155,7 @@ namespace SHADE */ /***************************************************************************/ - void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span, Handle>> const& imageViewsAndSamplers) noexcept + void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span, Handle, 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]; diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h index d92d55e9..f2b886e8 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h @@ -1,5 +1,7 @@ #pragma once +#include + // 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, Handle>> const& imageViewsAndSamplers) noexcept; + void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span, Handle, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept; void ModifyWriteDescBuffer (uint32_t set, uint32_t binding, std::span> const& buffers, uint32_t offset, uint32_t range) noexcept; diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp index 5ed17511..4f4f94a4 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp @@ -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(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 SHVkLogicalDevice::CreateSampler(const SHVkSamplerParams& params) noexcept + { + return SHVkInstance::GetResourceManager().Create (GetHandle(), params); + } + Handle SHVkLogicalDevice::CreateRenderpass(std::span const vkDescriptions, std::vector const& subpasses) noexcept { return SHVkInstance::GetResourceManager().Create (GetHandle(), vkDescriptions, subpasses); diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h index 8a197ef8..5c400e02 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h @@ -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 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 CreateSurface (HWND const& windowHandle) const noexcept; @@ -178,6 +181,7 @@ namespace SHADE Handle const& renderpassHdl, Handle subpass ) noexcept; + Handle CreateSampler (const SHVkSamplerParams& params) noexcept; Handle CreateRenderpass (std::span const vkDescriptions, std::vector const& subpasses) noexcept; Handle CreateRenderpass (std::span const vkDescriptions, std::span const spDescs, std::span const spDeps) noexcept; diff --git a/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.cpp b/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.cpp index 1386134f..76e627d3 100644 --- a/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.cpp +++ b/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.cpp @@ -98,6 +98,51 @@ namespace SHADE return *this; } + void SHVkFramebuffer::HandleResize(Handle const& renderpassHdl, std::vector> 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 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(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. "); + } + } + /***************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.h b/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.h index fa9161e8..47bfcf99 100644 --- a/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.h +++ b/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.h @@ -37,6 +37,8 @@ namespace SHADE SHVkFramebuffer(SHVkFramebuffer&& rhs) noexcept; SHVkFramebuffer& operator=(SHVkFramebuffer&& rhs) noexcept; + void HandleResize (Handle const& renderpassHdl, std::vector> const& attachments, uint32_t inWidth, uint32_t inHeight) noexcept; + /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp b/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp index b8bf273e..00cc31bf 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp +++ b/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp @@ -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(stagingBufferMappedPtr), static_cast(data), srcSize); + std::memcpy(static_cast(stagingBufferMappedPtr), static_cast(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 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 SHVkImage::CreateImageView(Handle const& inLogicalDeviceHdl, Handle 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; diff --git a/SHADE_Engine/src/Graphics/Images/SHVkImage.h b/SHADE_Engine/src/Graphics/Images/SHVkImage.h index 91d4f2d2..51b71b26 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkImage.h +++ b/SHADE_Engine/src/Graphics/Images/SHVkImage.h @@ -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 inMipOffsets, VmaMemoryUsage memUsage, @@ -137,7 +137,8 @@ namespace SHADE Handle CreateImageView (Handle const& inLogicalDeviceHdl, Handle const& parent, SHImageViewDetails const& createParams) const noexcept; void TransferToDeviceResource (Handle 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 */ /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/Images/SHVkImageView.cpp b/SHADE_Engine/src/Graphics/Images/SHVkImageView.cpp index 9d12d7cd..44b5718c 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkImageView.cpp +++ b/SHADE_Engine/src/Graphics/Images/SHVkImageView.cpp @@ -6,6 +6,67 @@ namespace SHADE { + + void SHVkImageView::Create(void) noexcept + { + auto parentImageCreateFlags = parentImage->GetImageeCreateFlags(); + + // 2D array image type means parent image must be 2D array compatible + if (imageViewDetails.viewType == vk::ImageViewType::e2DArray) + { + if (!(parentImageCreateFlags & vk::ImageCreateFlagBits::e2DArrayCompatible)) + { + SHLOG_ERROR("Failed to create image view. Parent image not 2D array compatible. "); + return; + } + } + + // Check if its possible for the image view to have different format than parent image + if (imageViewDetails.format != parentImage->GetImageFormat()) + { + if (!(parentImageCreateFlags & vk::ImageCreateFlagBits::eMutableFormat)) + { + SHLOG_ERROR("Failed to create image view. Format for image view not same as image but image not initialized with mutable format bit. "); + return; + } + } + + + 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 = parentImage->GetVkImage(), + .viewType = imageViewDetails.viewType, + .format = imageViewDetails.format, + .components + { + .r = vk::ComponentSwizzle::eR, + .g = vk::ComponentSwizzle::eG, + .b = vk::ComponentSwizzle::eB, + .a = vk::ComponentSwizzle::eA, + }, + .subresourceRange + { + .aspectMask = imageViewDetails.imageAspectFlags, + .baseMipLevel = imageViewDetails.baseMipLevel, + .levelCount = imageViewDetails.mipLevelCount, + .baseArrayLayer = imageViewDetails.baseArrayLayer, + .layerCount = imageViewDetails.layerCount, + }, + }; + + if (auto result = logicalDeviceHdl->GetVkLogicalDevice().createImageView(&viewCreateInfo, nullptr, &vkImageView); result != vk::Result::eSuccess) + { + SHVulkanDebugUtil::ReportVkError(result, "Failed to create image view! "); + return; + } + else + { + SHVulkanDebugUtil::ReportVkSuccess("Successfully created image view. "); + } + + } + /***************************************************************************/ /*! @@ -18,70 +79,12 @@ namespace SHADE */ /***************************************************************************/ SHVkImageView::SHVkImageView(Handle const& inLogicalDeviceHdl, Handle const& parent, SHImageViewDetails const& createParams) noexcept - : parentImage{ } + : parentImage{ parent } , vkImageView{} - , imageViewDetails{} + , imageViewDetails{createParams} , logicalDeviceHdl {inLogicalDeviceHdl} { - auto parentImageCreateFlags = parent->GetImageeCreateFlags(); - - // 2D array image type means parent image must be 2D array compatible - if (createParams.viewType == vk::ImageViewType::e2DArray) - { - if (!(parentImageCreateFlags & vk::ImageCreateFlagBits::e2DArrayCompatible)) - { - SHLOG_ERROR("Failed to create image view. Parent image not 2D array compatible. "); - return; - } - } - - // Check if its possible for the image view to have different format than parent image - if (createParams.format != parent->GetImageFormat()) - { - if (!(parentImageCreateFlags & vk::ImageCreateFlagBits::eMutableFormat)) - { - SHLOG_ERROR("Failed to create image view. Format for image view not same as image but image not initialized with mutable format bit. "); - return; - } - } - - - 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, - .components - { - .r = vk::ComponentSwizzle::eR, - .g = vk::ComponentSwizzle::eG, - .b = vk::ComponentSwizzle::eB, - .a = vk::ComponentSwizzle::eA, - }, - .subresourceRange - { - .aspectMask = createParams.imageAspectFlags, - .baseMipLevel = createParams.baseMipLevel, - .levelCount = createParams.mipLevelCount, - .baseArrayLayer = createParams.baseArrayLayer, - .layerCount = createParams.layerCount, - }, - }; - - if (auto result = inLogicalDeviceHdl->GetVkLogicalDevice().createImageView(&viewCreateInfo, nullptr, &vkImageView); result != vk::Result::eSuccess) - { - SHVulkanDebugUtil::ReportVkError(result, "Failed to create image view! "); - return; - } - else - { - SHVulkanDebugUtil::ReportVkSuccess("Successfully created image view. "); - } - - // After success, THEN assign variables - parentImage = parent; - imageViewDetails = createParams; + Create(); } SHVkImageView::SHVkImageView(SHVkImageView&& rhs) noexcept @@ -94,6 +97,17 @@ namespace SHADE } + void SHVkImageView::ViewNewImage(Handle const& parent, SHImageViewDetails const& createParams) noexcept + { + imageViewDetails = createParams; + parentImage = parent; + + if (vkImageView) + logicalDeviceHdl->GetVkLogicalDevice().destroyImageView(vkImageView, nullptr); + + Create(); + } + Handle const& SHVkImageView::GetParentImage(void) const noexcept { return parentImage; diff --git a/SHADE_Engine/src/Graphics/Images/SHVkImageView.h b/SHADE_Engine/src/Graphics/Images/SHVkImageView.h index afa357ef..ae23d7a7 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkImageView.h +++ b/SHADE_Engine/src/Graphics/Images/SHVkImageView.h @@ -25,12 +25,17 @@ namespace SHADE //! Logical Device needed for creation and destruction Handle logicalDeviceHdl; + //! Create new image view + void Create (void) noexcept; + public: SHVkImageView(Handle const& inLogicalDeviceHdl, Handle const& parent, SHImageViewDetails const& createParams) noexcept; ~SHVkImageView(void) noexcept; SHVkImageView(SHVkImageView&& rhs) noexcept; SHVkImageView& operator=(SHVkImageView&& rhs) noexcept; + void ViewNewImage (Handle const& parent, SHImageViewDetails const& createParams) noexcept; + /*-----------------------------------------------------------------------*/ /* GETTERS AND SETTERS */ /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp index b4bbf89b..f12b834d 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp +++ b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp @@ -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 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; + } } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/Images/SHVkSampler.h b/SHADE_Engine/src/Graphics/Images/SHVkSampler.h index eae23adf..bb878a69 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkSampler.h +++ b/SHADE_Engine/src/Graphics/Images/SHVkSampler.h @@ -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 +// 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: - SHVkSampler () noexcept; - SHVkSampler (SHVkSampler&& rhs) noexcept; - SHVkSampler&& operator=(SHVkSampler&& rhs) noexcept; + public: + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + SHVkSampler(Handle logicalDevice, const SHVkSamplerParams& params = {}) noexcept; + SHVkSampler(SHVkSampler&& rhs) noexcept; + ~SHVkSampler() noexcept; - vk::Sampler GetVkSampler (void) const noexcept; + /*---------------------------------------------------------------------------------*/ + /* Overloaded Operators */ + /*---------------------------------------------------------------------------------*/ + SHVkSampler& operator=(SHVkSampler&& rhs) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + vk::Sampler GetVkSampler(void) const noexcept { return vkSampler; } + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + vk::Sampler vkSampler; //! The Vulkan sampler handler + Handle device; //! Stored device for deallocating the object }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp index f73c5306..181c1f22 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp @@ -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 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(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(transformData.size() * sizeof(SHMatrix)), 0, 0); } - void SHBatch::Build(Handle _device, uint32_t frameIndex) + void SHBatch::Build(Handle _device, Handle 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(singleMatPropSize)); + matPropTotalBytes = numTotalElements * singleMatPropAlignedSize; if (matPropsDataSize < matPropTotalBytes) { matPropsData.reset(new char[matPropTotalBytes]); @@ -267,7 +270,7 @@ namespace SHADE .instanceCount = static_cast(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(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(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(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 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(drawData.size())); } @@ -355,4 +361,39 @@ namespace SHADE dirt = true; isCPUBuffersDirty = true; } + + void SHBatch::rebuildMaterialBuffers(uint32_t frameIndex, Handle descPool) + { + if (matPropsData) + { + SHVkUtil::EnsureBufferAndCopyHostVisibleData + ( + device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast(matPropsDataSize), + vk::BufferUsageFlagBits::eStorageBuffer + ); + + if (!matPropsDescSet[frameIndex]) + { + matPropsDescSet[frameIndex] = descPool->Allocate + ( + { SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE] }, + { 0 } + ); + } + std::array, 1> bufferList = { matPropsBuffer[frameIndex] }; + matPropsDescSet[frameIndex]->ModifyWriteDescBuffer + ( + SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, + SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA, + bufferList, + 0, static_cast(matPropsDataSize) + ); + matPropsDescSet[frameIndex]->UpdateDescriptorSetBuffer + ( + SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, + SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA + ); + } + } + } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h index d40a66ea..abe691ca 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h @@ -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 descPool); void UpdateTransformBuffer(uint32_t frameIndex); - void Build(Handle device, uint32_t frameIndex); + void Build(Handle device, Handle descPool, uint32_t frameIndex) ; void Draw(Handle cmdBuffer, uint32_t frameIndex); /*-----------------------------------------------------------------------------*/ @@ -84,34 +86,44 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ Handle GetPipeline() const noexcept { return pipeline; }; - private: + private: + /*-----------------------------------------------------------------------------*/ + /* Type Definition */ + /*-----------------------------------------------------------------------------*/ + using TripleBool = std::array; + using TripleBuffer = std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS>; + using TripleDescSet = std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS>; + /*-----------------------------------------------------------------------------*/ /* Data Members */ /*-----------------------------------------------------------------------------*/ // Resources - Handle device; + Handle device; // Batch Properties - Handle pipeline; + Handle pipeline; std::unordered_set> referencedMatInstances; - std::array matBufferDirty; + TripleBool matBufferDirty; // Batch Tree - std::vector subBatches; - std::array isDirty; - // CPU Buffers - std::vector drawData; - std::vector transformData; - std::unique_ptr matPropsData; - Byte matPropsDataSize = 0; - Byte singleMatPropSize = 0; - bool isCPUBuffersDirty = true; - // GPU Buffers - std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS> drawDataBuffer; - std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS> transformDataBuffer; - std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS> matPropsBuffer; + std::vector subBatches; + TripleBool isDirty; + // CPU Buffers + std::vector drawData; + std::vector transformData; + std::unique_ptr matPropsData; + Byte matPropsDataSize = 0; + Byte singleMatPropAlignedSize = 0; + Byte singleMatPropSize = 0; + bool isCPUBuffersDirty = true; + // GPU Buffers + TripleBuffer drawDataBuffer; + TripleBuffer transformDataBuffer; + TripleBuffer matPropsBuffer; + TripleDescSet matPropsDescSet; /*-----------------------------------------------------------------------------*/ /* Helper Functions */ /*-----------------------------------------------------------------------------*/ void setAllDirtyFlags(); + void rebuildMaterialBuffers(uint32_t frameIndex, Handle descPool); }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.cpp index c4320aac..dc44e7f9 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.cpp @@ -91,12 +91,12 @@ namespace SHADE (*superBatch)->Remove(renderable); } - void SHBatcher::FinaliseBatches(Handle device, uint32_t frameIndex) + void SHBatcher::FinaliseBatches(Handle device, Handle 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 descPool) { for (auto& batch : superBatches) { - batch->UpdateBuffers(frameIndex); + batch->UpdateBuffers(frameIndex, descPool); } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h index 985e8e16..8074899d 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h @@ -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 device, uint32_t frameIndex); + void FinaliseBatches(Handle device, Handle descPool, uint32_t frameIndex); void ClearBatches(); - void UpdateBuffers(uint32_t frameIndex); + void UpdateBuffers(uint32_t frameIndex, Handle descPool); void RegisterSuperBatch(Handle superBatch); void DeregisterSuperBatch(Handle superBatch); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp index b0173399..0d75dca8 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp @@ -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 descPool) { for (auto& batch : batches) { - batch.UpdateMaterialBuffer(frameIndex); + batch.UpdateMaterialBuffer(frameIndex, descPool); batch.UpdateTransformBuffer(frameIndex); } } - void SHSuperBatch::Build(Handle device, uint32_t frameIndex) noexcept + void SHSuperBatch::Build(Handle device, Handle descPool, uint32_t frameIndex) noexcept { // Build all batches for (auto& batch : batches) { - batch.Build(device, frameIndex); + batch.Build(device, descPool, frameIndex); } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h index a09fc64e..9743e7dc 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h @@ -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 device, uint32_t frameIndex) noexcept; + void UpdateBuffers(uint32_t frameIndex, Handle descPool); + void Build(Handle device, Handle descPool, uint32_t frameIndex) noexcept; void Draw(Handle cmdBuffer, uint32_t frameIndex) noexcept; /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp index ee6d0e8c..6a7b23f2 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp @@ -7,7 +7,22 @@ namespace SHADE { + /*-----------------------------------------------------------------------------------*/ + /* Static Definitions */ + /*-----------------------------------------------------------------------------------*/ + std::vector> SHGraphicsGlobalData::globalDescSetLayouts; + Handle SHGraphicsGlobalData::globalDescSets; + SHVertexInputState SHGraphicsGlobalData::defaultVertexInputState; + Handle SHGraphicsGlobalData::dummyPipelineLayout; + void SHGraphicsGlobalData::InitHighFrequencyGlobalData(void) noexcept + { + + } + + /*-----------------------------------------------------------------------------------*/ + /* Function Definitions */ + /*-----------------------------------------------------------------------------------*/ void SHGraphicsGlobalData::InitDescSetLayouts(Handle logicalDevice) noexcept { SHVkDescriptorSetLayout::Binding genericDataBinding @@ -87,18 +102,18 @@ namespace SHADE InitDefaultVertexInputState(); } - std::vector> const& SHGraphicsGlobalData::GetDescSetLayouts(void) const noexcept + std::vector> const& SHGraphicsGlobalData::GetDescSetLayouts(void) noexcept { return globalDescSetLayouts; } - SHVertexInputState const& SHGraphicsGlobalData::GetDefaultViState(void) const noexcept + SHVertexInputState const& SHGraphicsGlobalData::GetDefaultViState(void) noexcept { return defaultVertexInputState; } - Handle SHGraphicsGlobalData::GetDummyPipelineLayout(void) const noexcept + Handle SHGraphicsGlobalData::GetDummyPipelineLayout(void) noexcept { return dummyPipelineLayout; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h index 9333d0ab..344c2616 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h @@ -15,31 +15,38 @@ namespace SHADE { private: //! Global descriptor set layouts. Used to allocate descriptor sets - std::vector> globalDescSetLayouts; + static std::vector> globalDescSetLayouts; //! Global Descriptor sets - Handle globalDescSets; + static Handle 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 dummyPipelineLayout; + static Handle dummyPipelineLayout; + + static void InitHighFrequencyGlobalData (void) noexcept; + static void InitDescSetLayouts (Handle logicalDevice) noexcept; + static void InitDefaultVertexInputState (void) noexcept; - void InitDescSetLayouts (Handle logicalDevice) noexcept; - void InitDefaultVertexInputState(void) noexcept; public: + /*-----------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------*/ + SHGraphicsGlobalData() = delete; + /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void Init (Handle logicalDevice) noexcept; + static void Init (Handle logicalDevice) noexcept; /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ - std::vector> const& GetDescSetLayouts (void) const noexcept; - SHVertexInputState const& GetDefaultViState (void) const noexcept; - Handle GetDummyPipelineLayout (void) const noexcept; + static std::vector> const& GetDescSetLayouts (void) noexcept; + static SHVertexInputState const& GetDefaultViState (void) noexcept; + static Handle GetDummyPipelineLayout (void) noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.cpp index 4a1117c3..2abdfa86 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.cpp @@ -23,22 +23,40 @@ 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; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.h index c54f29ed..3a945109 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.h @@ -69,7 +69,7 @@ namespace SHADE SHMatrix inverseViewMatrix; SHMatrix inverseProjMatrix; SHMatrix inverseVpMatrix; - bool isDirty; + bool isDirty = true; /*-----------------------------------------------------------------------------*/ /* Helper Functions */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 445d6119..6957aa93 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -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(); - globalData->Init(device); + SHGraphicsGlobalData::Init(device); // Set Up Cameras screenCamera = resourceManager.Create(); 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(windowDims.first), static_cast(windowDims.second), 0.01f, 100.0f); + worldCamera = resourceManager.Create(); - //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(windowDims.first), static_cast(windowDims.second), 0.0f, 100.0f); // Create Default Viewport defaultViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast(window->GetWindowSize().first), static_cast(window->GetWindowSize().second), 0.0f, 1.0f)); // Get render graph from default viewport world renderer - auto worldRenderGraph = resourceManager.Create(); + worldRenderGraph = resourceManager.Create(); std::vector> 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(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(viewports[vpIndex]->GetWidth()); + uint32_t h = static_cast(viewports[vpIndex]->GetHeight()); + currentCmdBuffer->SetViewportScissor (static_cast(w), static_cast(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 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,28 +500,110 @@ namespace SHADE transferCmdBuffer->BeginRecording(); meshLibrary.BuildBuffers(device, transferCmdBuffer); transferCmdBuffer->EndRecording(); - transferQueue->SubmitCommandBuffer({ transferCmdBuffer }); + graphicsQueue->SubmitCommandBuffer({ transferCmdBuffer }); + } + + /*---------------------------------------------------------------------------------*/ + /* Texture Registration Functions */ + /*---------------------------------------------------------------------------------*/ + Handle SHGraphicsSystem::Add(const SHTextureAsset& texAsset) + { + auto sampler = samplerCache.GetSampler(device, SHVkSamplerParams { .maxLod = static_cast(texAsset.mipOffsets.size()) }); + return texLibrary.Add(texAsset, sampler); + } + + SHADE::Handle SHGraphicsSystem::Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector mipOffsets) + { + auto sampler = samplerCache.GetSampler(device, SHVkSamplerParams{ .maxLod = static_cast(mipOffsets.size()) }); + return texLibrary.Add(pixelCount, pixelData, width, height, format, mipOffsets, sampler); + } + + void SHGraphicsSystem::Remove(Handle 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(windowDims.first)); + defaultViewport->SetHeight(static_cast(windowDims.second)); + + worldCamera->SetPerspective(90.0f, static_cast(windowDims.first), static_cast(windowDims.second), 0.0f, 100.0f); } + void SHGraphicsSystem::AwaitGraphicsExecution() + { + device->WaitIdle(); + } + void SHGraphicsSystem::SetWindow(SHWindow* wind) noexcept { window = wind; } + /*-----------------------------------------------------------------------------------*/ + /* System Routine Functions - BeginRoutine */ + /*-----------------------------------------------------------------------------------*/ + SHGraphicsSystem::BeginRoutine::BeginRoutine() + : SHSystemRoutine("Graphics System Frame Set Up", false) + {} + void SHGraphicsSystem::BeginRoutine::Execute(double) noexcept { reinterpret_cast(system)->BeginRender(); } + + /*-----------------------------------------------------------------------------------*/ + /* System Routine Functions - RenderRoutine */ + /*-----------------------------------------------------------------------------------*/ + SHGraphicsSystem::RenderRoutine::RenderRoutine() + : SHSystemRoutine("Graphics System Render", false) + {} void SHGraphicsSystem::RenderRoutine::Execute(double dt) noexcept { reinterpret_cast(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(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(); @@ -493,9 +620,13 @@ namespace SHADE oldSuperBatch->Remove(&renderable); } - // Add to new SuperBatch - Handle newSuperBatch = renderable.GetMaterial()->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch(); - newSuperBatch->Add(&renderable); + // Add to new SuperBatch if there is a material + Handle newMatInstance = renderable.GetMaterial(); + if (newMatInstance) + { + Handle newSuperBatch = newMatInstance->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch(); + newSuperBatch->Add(&renderable); + } // Unset change flag renderable.ResetChangedFlag(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 7e652a02..c89e6ebc 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -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 Add(const SHTextureAsset& texAsset); + Handle Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector 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 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 graphicsQueue; Handle transferQueue; Handle descPool; - Handle transferCmdPool; + Handle graphicsCmdPool; Handle transferCmdBuffer; + Handle graphicsTexCmdBuffer; SHRenderContext renderContext; std::array, 2> graphSemaphores; // Not Owned Resources SHWindow* window = nullptr; - // global data (descriptor sets as well) - Handle globalData; - // Middle End Resources ResourceManager resourceManager; SHMeshLibrary meshLibrary; + SHTextureLibrary texLibrary; + SHSamplerCache samplerCache; SHMaterialInstanceCache materialInstanceCache; // Viewports Handle defaultViewport; // Whole screen @@ -255,5 +320,7 @@ namespace SHADE // Temp Materials Handle defaultMaterial; + + Handle worldRenderGraph; }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h index 692d857f..348efb07 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h @@ -63,7 +63,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ Handle pipeline; std::unique_ptr propMemory; - Byte propMemorySize; + Byte propMemorySize = 0; /*-----------------------------------------------------------------------------*/ /* Helper Functions */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.cpp index 0e5a61dd..350580bf 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.cpp @@ -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!"); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h index 5d6c4925..d111acb9 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h @@ -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: /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.hpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.hpp index b3dc6c3a..4621c273 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.hpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.hpp @@ -48,7 +48,7 @@ namespace SHADE } // Get offset and modify the memory directly - T* dataPtr = dataStore.get() + od.StoredDataOffset; + T* dataPtr = reinterpret_cast(dataStore.get() + od.StoredDataOffset); *dataPtr = value; // Save the override data information diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp index a4cda42d..0b1c1b66 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp @@ -81,7 +81,7 @@ namespace SHADE if (!material) { SHGraphicsSystem* gfxSystem = SHSystemManager::GetSystem(); - material = gfxSystem->AddOrGetBaseMaterialInstance(sharedMaterial->GetBaseMaterial()); + material = gfxSystem->AddMaterialInstanceCopy(sharedMaterial); } return material; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp index c7e2a86d..14af56ee 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp @@ -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 descPool) noexcept { - renderGraph->Execute(frameIndex, commandBuffers[frameIndex]); + renderGraph->Execute(frameIndex, commandBuffers[frameIndex], descPool); } void SHRenderer::UpdateDataAndBind(Handle cmdBuffer, uint32_t frameIndex) noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h index 255ab289..0feea840 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h @@ -65,6 +65,7 @@ namespace SHADE /* Constructor/Destructors */ /*-----------------------------------------------------------------------------*/ SHRenderer(Handle logicalDevice, uint32_t numFrames, std::vector>& cmdPools, Handle descriptorPool, Handle cameraDescLayout, Handle viewport, Handle 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 descPool) noexcept; void UpdateDataAndBind (Handle cmdBuffer, uint32_t frameIndex) noexcept; void UpdateCameraDataToBuffer (void) noexcept; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.cpp index 25c5bca2..dc534a49 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.cpp @@ -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; + + } + } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.h index d97d62ce..221dbe7e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.h @@ -62,6 +62,12 @@ namespace SHADE Handle AddRenderer(ResourceManager& resourceManager, uint32_t numFrames, std::vector>& cmdPools, Handle descriptorPool, Handle cameraDescLayout, Handle renderGraph); void RemoveRenderer(Handle renderer); + /*-----------------------------------------------------------------------------*/ + /* Setters */ + /*-----------------------------------------------------------------------------*/ + void SetWidth(float w) noexcept; + void SetHeight (float h) noexcept; + /*-----------------------------------------------------------------------------*/ /* Getters */ /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp index 2080265b..be181beb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp @@ -196,12 +196,12 @@ namespace SHADE static SHMeshData meshData = Cube(); return meshLibrary.AddMesh ( - meshData.VertexPositions.size(), + static_cast(meshData.VertexPositions.size()), meshData.VertexPositions.data(), meshData.VertexTexCoords.data(), meshData.VertexTangents.data(), meshData.VertexNormals.data(), - meshData.Indices.size(), + static_cast(meshData.Indices.size()), meshData.Indices.data() ); } @@ -211,12 +211,12 @@ namespace SHADE static SHMeshData meshData = Cube(); return gfxSystem.AddMesh ( - meshData.VertexPositions.size(), + static_cast(meshData.VertexPositions.size()), meshData.VertexPositions.data(), meshData.VertexTexCoords.data(), meshData.VertexTangents.data(), meshData.VertexNormals.data(), - meshData.Indices.size(), + static_cast(meshData.Indices.size()), meshData.Indices.data() ); } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.cpp index f31653a8..0ac7013a 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.cpp @@ -168,6 +168,11 @@ namespace SHADE isResized = resized; } + void SHRenderContext::SetWindowIsDead(bool dead) noexcept + { + windowIsDead = dead; + } + /***************************************************************************/ /*! @@ -197,6 +202,11 @@ namespace SHADE return currentFrame; } + bool SHRenderContext::GetResized(void) noexcept + { + return isResized; + } + bool SHRenderContext::GetResizeAndReset(void) noexcept { bool b = isResized; @@ -204,4 +214,9 @@ namespace SHADE return b; } + bool SHRenderContext::GetWindowIsDead(void) const noexcept + { + return windowIsDead; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.h b/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.h index 04cea4e4..bf186922 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.h @@ -36,6 +36,7 @@ namespace SHADE uint32_t currentFrame; bool isResized{ false }; + bool windowIsDead {false}; public: SHRenderContext(void) noexcept; @@ -51,12 +52,15 @@ namespace SHADE bool WaitForFence (void) noexcept; void ResetFence (void) noexcept; - void SetIsResized (bool resized) noexcept; + void SetIsResized (bool resized) noexcept; + void SetWindowIsDead (bool dead) noexcept; SHPerFrameData& GetCurrentFrameData(void) noexcept; SHPerFrameData& GetFrameData (uint32_t index) noexcept; uint32_t GetCurrentFrame (void) const noexcept; + bool GetResized (void) noexcept; bool GetResizeAndReset (void) noexcept; + bool GetWindowIsDead (void) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp index 92d832f1..10b42a9e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp @@ -11,7 +11,7 @@ namespace SHADE SHPipelineLayoutParams params { .shaderModules = {vsFsPair.first, vsFsPair.second}, - .globalDescSetLayouts = globalData->GetDescSetLayouts() + .globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts() }; // Create the pipeline layout @@ -19,7 +19,7 @@ namespace SHADE // Create the pipeline and configure the default vertex input state auto newPipeline = logicalDevice->CreateGraphicsPipeline(pipelineLayout, nullptr, renderpass, subpass); - newPipeline->GetPipelineState().SetVertexInputState(globalData->GetDefaultViState()); + newPipeline->GetPipelineState().SetVertexInputState(SHGraphicsGlobalData::GetDefaultViState()); // Actually construct the pipeline newPipeline->ConstructPipeline(); @@ -30,10 +30,9 @@ namespace SHADE return newPipeline; } - void SHPipelineLibrary::Init(Handle device, Handle inGlobalData) noexcept + void SHPipelineLibrary::Init(Handle device) noexcept { logicalDevice = device; - globalData = inGlobalData; } Handle SHPipelineLibrary::GetDrawPipline(std::pair, Handle> const& vsFsPair) noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h index a16976f7..9a411d25 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h @@ -24,14 +24,9 @@ namespace SHADE //! a map of pipelines that are hashed using a pair of shader module handles std::unordered_map, Handle>, Handle> pipelines; - - // Global data - Handle globalData; - - public: - void Init (Handle device, Handle inGlobalData) noexcept; + void Init (Handle device) noexcept; // Draw pipeline functions. used only when creating pipelines for drawing using a vertex and fragment shader Handle CreateDrawPipeline ( diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp index 6459ff9a..5c315ff6 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp @@ -20,18 +20,36 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/Commands/SHVkCommandBuffer.h" #include "Graphics/SHVkUtil.h" #include "Tools/SHLogger.h" +#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/Images/SHVkImage.h" +#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h" +#include "Assets/Asset Types/SHTextureAsset.h" namespace SHADE { /*---------------------------------------------------------------------------------*/ /* Usage Functions */ /*---------------------------------------------------------------------------------*/ - Handle SHTextureLibrary::Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, SHTexture::TextureFormat format, uint32_t mipLevels) + Handle SHTextureLibrary::Add(const SHTextureAsset& texAsset, Handle sampler) + { + return Add + ( + texAsset.numBytes, + texAsset.pixelData, + texAsset.width, texAsset.height, + texAsset.format, + texAsset.mipOffsets, + sampler + ); + } + + Handle SHTextureLibrary::Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector mipOffsets, Handle sampler) { isDirty = true; auto handle = resourceManager.Create(); - addJobs.emplace_back(AddJob { pixelCount, pixelData, format, mipLevels }); + addJobs.emplace_back(AddJob { pixelCount, pixelData, format, sampler, mipOffsets, width, height, handle }); return handle; } @@ -44,22 +62,48 @@ namespace SHADE isDirty = true; } - void SHTextureLibrary::BuildImages(Handle device, Handle cmdBuffer, Handle graphicsQueue, Handle descPool, Handle descLayout) + void SHTextureLibrary::BuildTextures(Handle device, Handle cmdBuffer, Handle graphicsQueue, Handle descPool) { + // Don't do anything if there are no updates + if (!isDirty) + return; + /* Remove Textures */ - std::vector pipelineBarriers(addJobs.size()); + // TODO /* Add Textures */ - // Transition + // Load Textures - Transitions + std::vector pipelineBarriers(addJobs.size()); for (int i = 0; auto& job : addJobs) { - job.Image = resourceManager.Create(); + job.Image = resourceManager.Create + ( + &device->GetVMAAllocator(), + SHImageCreateParams + { + .imageType = vk::ImageType::e2D, + .width = job.Width, + .height = job.Height, + .depth = 1, + .levels = static_cast(job.MipOffsets.size()), + .arrayLayers = 1, + .imageFormat = job.TextureFormat, + .usageFlags = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst, + .createFlags = {} + }, + job.PixelData, + job.PixelCount, + job.MipOffsets, + VmaMemoryUsage::VMA_MEMORY_USAGE_AUTO, + VmaAllocationCreateFlagBits {} + ); job.Image->PrepareImageTransitionInfo(vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, pipelineBarriers[i]); ++i; } vk::PipelineStageFlagBits srcStage = vk::PipelineStageFlagBits::eTopOfPipe; vk::PipelineStageFlagBits dstStage = vk::PipelineStageFlagBits::eTopOfPipe; preparePipelineBarriers(vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, srcStage, dstStage, pipelineBarriers); + cmdBuffer->BeginRecording(); cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, pipelineBarriers); // Copy @@ -73,13 +117,16 @@ namespace SHADE { // Transition job.Image->PrepareImageTransitionInfo(vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, pipelineBarriers[i]); + ++i; } preparePipelineBarriers(vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, srcStage, dstStage, pipelineBarriers); - cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, pipelineBarriers); + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, pipelineBarriers); // Execute Commands + cmdBuffer->EndRecording(); graphicsQueue->SubmitCommandBuffer({ cmdBuffer }); device->WaitIdle(); + graphicsQueue->GetVkQueue().waitIdle(); // Create Image View for (auto& job : addJobs) @@ -90,16 +137,45 @@ namespace SHADE .format = job.TextureFormat, .imageAspectFlags = vk::ImageAspectFlagBits::eColor, .baseMipLevel = 0, - .mipLevelCount = job.MipLevels, + .mipLevelCount = static_cast(job.MipOffsets.size()), .baseArrayLayer = 0, - .layerCount = 0 + .layerCount = 1 }; - job.Handle->ImageView = job.Image->CreateImageView(device, job.Image, DETAILS); + job.TextureHandle->ImageView = job.Image->CreateImageView(device, job.Image, DETAILS); } - // Build Descriptor - Handle descSetGroup = descPool->Allocate({ descLayout }, { 1 }); - + // Add Textures + for (auto& job : addJobs) + { + texOrder.emplace_back(job.TextureHandle); + combinedImageSamplers.emplace_back(std::make_tuple(job.TextureHandle->ImageView, job.Sampler, vk::ImageLayout::eShaderReadOnlyOptimal)); + job.TextureHandle->TextureArrayIndex = static_cast(texOrder.size()) - 1U; + } + addJobs.clear(); + + /* Build Descriptor Set with all the Textures only if there are textures */ + if (!texOrder.empty()) + { + if (!texDescriptors) + { + texDescriptors = descPool->Allocate + ( + { SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS] }, + { static_cast(texOrder.size()) } + ); + } + texDescriptors->ModifyWriteDescImage + ( + SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS, + SHGraphicsConstants::DescriptorSetBindings::IMAGE_AND_SAMPLERS_DATA, + combinedImageSamplers + ); + texDescriptors->UpdateDescriptorSetImages + ( + SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS, + SHGraphicsConstants::DescriptorSetBindings::IMAGE_AND_SAMPLERS_DATA + ); + } isDirty = false; } @@ -139,4 +215,65 @@ namespace SHADE } } + vk::Format SHTextureLibrary::ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear) + { + switch (format) + { + case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm: + return vk::Format::eBc1RgbaUnormBlock; + case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm_SRGB: + return vk::Format::eBc1RgbaSrgbBlock; + case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm_SRGB: + return isLinear ? vk::Format::eBc2UnormBlock : vk::Format::eBc2SrgbBlock; + case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm_SRGB: + return isLinear ? vk::Format::eBc3UnormBlock : vk::Format::eBc3SrgbBlock; + case tinyddsloader::DDSFile::DXGIFormat::BC5_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::BC5_SNorm: + return isLinear ? vk::Format::eBc5UnormBlock : vk::Format::eBc5SnormBlock; + case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm_SRGB: + return isLinear ? vk::Format::eR8G8B8A8Unorm : vk::Format::eR8G8B8A8Srgb; + case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_SNorm: + return vk::Format::eR8G8B8A8Snorm; + case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm_SRGB: + return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8A8Srgb; + case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm_SRGB: + return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8Srgb; + default: + throw std::runtime_error("Unsupported DDS format."); + } + + //switch (format) + //{ + //case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm: + //case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm_SRGB: + // return (isLinear) ? vk::Format::eR8G8B8A8Unorm : vk::Format::eR8G8B8A8Srgb; + // + + //case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm: + //case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm_SRGB: + // return (isLinear) ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8A8Srgb; + // + + //case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm: + //case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm_SRGB: + // return (isLinear) ? vk::Format::eBc1RgbaUnormBlock : vk::Format::eBc1RgbaSrgbBlock; + + //case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm: + //case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm_SRGB: + // return (isLinear) ? vk::Format::eBc2UnormBlock : vk::Format::eBc2SrgbBlock; + + //case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm: + //case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm_SRGB: + // return (isLinear) ? vk::Format::eBc3UnormBlock : vk::Format::eBc3SrgbBlock; + + //case tinyddsloader::DDSFile::DXGIFormat::BC5_UNorm: + // return (isLinear) ? vk::Format::eBc5UnormBlock : vk::Format::eBc5SnormBlock; + // + //} + } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h index 5cf974ef..c2eb85ec 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h @@ -14,6 +14,8 @@ of DigiPen Institute of Technology is prohibited. // STL Includes #include +// External Dependencies +#include "tinyddsloader.h" // Project Includes #include "Resource/Handle.h" #include "Resource/ResourceLibrary.h" @@ -33,6 +35,9 @@ namespace SHADE class SHVkQueue; class SHVkDescriptorPool; class SHVkDescriptorSetLayout; + class SHVkDescriptorSetGroup; + class SHVkSampler; + struct SHTextureAsset; /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -43,7 +48,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------*/ - using PixelChannel = float; + using PixelChannel = unsigned char; using TextureFormat = vk::Format; // TODO: Change using Index = uint32_t; @@ -71,7 +76,7 @@ namespace SHADE \brief Adds a texture to the Texture Library. But this does not mean that the - textures have been added yet. A call to "BuildImages()" is required to + textures have been added yet. A call to "BuildTextures()" is required to transfer all textures into the GPU. \param pixelCount @@ -88,13 +93,15 @@ namespace SHADE */ /*******************************************************************************/ - Handle Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, SHTexture::TextureFormat format, uint32_t mipLevels); + + Handle Add(const SHTextureAsset& texAsset, Handle sampler); + Handle Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector mipOffsets, Handle sampler); /*******************************************************************************/ /*! \brief Removes a mesh from the Texture Library. But this does not mean that the - textures have been removed yet. A call to "BuildImages()" is required to + textures have been removed yet. A call to "BuildTextures()" is required to finalise all changes. \param mesh @@ -118,12 +125,12 @@ namespace SHADE queue. */ /***************************************************************************/ - void BuildImages(Handle device, Handle cmdBuffer, Handle graphicsQueue, Handle descPool, Handle descLayout); + void BuildTextures(Handle device, Handle cmdBuffer, Handle graphicsQueue, Handle descPool); /*-----------------------------------------------------------------------------*/ /* Getter Functions */ /*-----------------------------------------------------------------------------*/ - Handle GetTextureBuffer() const noexcept { return texStorageBuffer; } + Handle GetTextureDescriptorSetGroup() const noexcept { return texDescriptors; } private: /*-----------------------------------------------------------------------------*/ @@ -134,9 +141,12 @@ namespace SHADE uint32_t PixelCount = 0; const SHTexture::PixelChannel* PixelData = nullptr; SHTexture::TextureFormat TextureFormat = {}; - uint32_t MipLevels = 0; + Handle Sampler; + std::vector MipOffsets; + uint32_t Width; + uint32_t Height; + Handle TextureHandle; Handle Image; - Handle Handle; }; /*-----------------------------------------------------------------------------*/ @@ -149,9 +159,9 @@ namespace SHADE ResourceManager resourceManager; std::vector> texOrder; // CPU Storage - std::vector texStorage; + std::vector, Handle, vk::ImageLayout>> combinedImageSamplers; // GPU Storage - Handle texStorageBuffer{}; + Handle texDescriptors; // Flags bool isDirty = true; @@ -159,5 +169,6 @@ namespace SHADE /* Helper Functions */ /*-----------------------------------------------------------------------------*/ void preparePipelineBarriers(vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::PipelineStageFlagBits& srcStage, vk::PipelineStageFlagBits& dstStage, std::vector& barriers); + vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear); }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.cpp new file mode 100644 index 00000000..6938dae5 --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.cpp @@ -0,0 +1,75 @@ +/************************************************************************************//*! +\file SHVkSamplerCache.cpp +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Mar 16, 2022 +\brief Contains the implementation for the SHVkSamplerCache 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 "SHVkSamplerCache.h" + +// Standard Library +#include +// Project Header +#include "Graphics/Images/SHVkSampler.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Utility Functions */ + /*---------------------------------------------------------------------------------*/ + void SHSamplerCache::Clear() + { + samplersMap.clear(); + } + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + Handle SHSamplerCache::GetSampler(Handle device, const SHVkSamplerParams& params) + { + // Get the hash to check if it was cached + const RawSamplerHash HASH = calcHash + ( + params.minFilter, + params.magFilter, + params.addressMode, + params.mipmapMode, + params.minLod, + params.maxLod + ); + + // Check if it was cached + auto sampler = samplersMap.find(HASH); + if (sampler == samplersMap.end()) + { + const auto BUILD_RESULT = samplersMap.emplace(HASH, device->CreateSampler(params)); + sampler = BUILD_RESULT.first; + } + + return sampler->second; + } + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + SHSamplerCache::RawSamplerHash SHSamplerCache::calcHash(vk::Filter minFilter, vk::Filter magFilter, vk::SamplerAddressMode addressMode, vk::SamplerMipmapMode mipmapMode, float minLod, float maxLod) + { + static auto charHasher = std::hash{}; + static auto floatHasher = std::hash{}; + + const RawSamplerHash H1 = charHasher(static_cast(minFilter)); + const RawSamplerHash H2 = charHasher(static_cast(magFilter)); + const RawSamplerHash H3 = charHasher(static_cast(addressMode)); + const RawSamplerHash H4 = charHasher(static_cast(mipmapMode)); + const RawSamplerHash H5 = floatHasher(minLod); + const RawSamplerHash H6 = floatHasher(maxLod); + + return H1 ^ (H2 << 1) ^ (H3 << 2) ^ (H4 << 3) ^ (H5 << 4) ^ (H6 << 5); + } +} diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.h b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.h new file mode 100644 index 00000000..c1529577 --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.h @@ -0,0 +1,80 @@ +/************************************************************************************//*! +\file SHSamplerCache.h +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Mar 16, 2022 +\brief Contains the interface for the SHSamplerCache 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 + +// Standard Libraries +#include +// External Dependencies +#include "Graphics/SHVulkanIncludes.h" +// Project Includes +#include "Resource/Handle.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + class SHVkLogicalDevice; + class SHVkSampler; + struct SHVkSamplerParams; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + /*************************************************************************************/ + /*! + \brief + Class that is responsible for caching and providing Samplers to the user for + sampling textures. + */ + /*************************************************************************************/ + class SHSamplerCache + { + public: + /*---------------------------------------------------------------------------------*/ + /* Utility Functions */ + /*---------------------------------------------------------------------------------*/ + /// + /// Clears the cache, destroying all created samplers. + /// + void Clear(); + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + /// + /// Retrieves a Vulkan Sampler of the specified type. If this was retrieved + /// before, a cached copy of the Vulkan Sampler will be provided. + /// + /// Logical device to create the sampler with if needed. + /// Describes the parameters for the sampler. + /// Handle to the SHVkSampler object specified. + Handle GetSampler(Handle device, const SHVkSamplerParams& params); + + private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + using RawSamplerHash = size_t; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + // Resources + std::unordered_map> samplersMap; + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + static RawSamplerHash calcHash(vk::Filter minFilter, vk::Filter magFilter, vk::SamplerAddressMode addressMode, vk::SamplerMipmapMode mipmapMode, float minLod, float maxLod); + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp index 25be112e..7a76447d 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp @@ -216,10 +216,13 @@ namespace SHADE /***************************************************************************/ void SHVkPipelineLayout::PrepareVkDescriptorSetLayouts(void) noexcept { + descriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size()); + // Settle allocate layouts first vkDescriptorSetLayoutsAllocate.reserve(descriptorSetLayoutsAllocate.size()); for (auto const& layout : descriptorSetLayoutsAllocate) { + descriptorSetLayoutsPipeline.emplace_back(layout); vkDescriptorSetLayoutsAllocate.emplace_back(layout->GetVkHandle()); } @@ -228,7 +231,10 @@ namespace SHADE // First we insert the global layouts for (auto const& layout : descriptorSetLayoutsGlobal) + { + descriptorSetLayoutsPipeline.emplace_back(layout); vkDescriptorSetLayoutsPipeline.emplace_back(layout->GetVkHandle()); + } // Then we append layouts for allocation at the back of the vector std::copy(vkDescriptorSetLayoutsAllocate.begin(), vkDescriptorSetLayoutsAllocate.end(), std::back_inserter(vkDescriptorSetLayoutsPipeline)); @@ -435,6 +441,16 @@ namespace SHADE return {}; } + std::vector> SHVkPipelineLayout::GetDescriptorSetLayoutsPipeline(void) const noexcept + { + return descriptorSetLayoutsPipeline; + } + + std::vector> SHVkPipelineLayout::GetDescriptorSetLayoutsAllocate(void) const noexcept + { + return descriptorSetLayoutsAllocate; + } + SHVkPipelineLayout& SHVkPipelineLayout::operator=(SHVkPipelineLayout&& rhs) noexcept { if (&rhs == this) diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h index e43ceb73..f5d363fa 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h @@ -42,6 +42,9 @@ namespace SHADE //! We want to store this also because we need to allocate later std::vector vkDescriptorSetLayoutsAllocate; + //! Store for descriptor set group creation + std::vector> descriptorSetLayoutsPipeline; + //! Store for pipeline layout recreation std::vector vkDescriptorSetLayoutsPipeline; @@ -71,10 +74,12 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ - std::vector> const& GetShaderModules (void) const noexcept; - vk::PipelineLayout GetVkPipelineLayout (void) const noexcept; - SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept; - Handle GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept; + std::vector> const& GetShaderModules (void) const noexcept; + vk::PipelineLayout GetVkPipelineLayout (void) const noexcept; + SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept; + Handle GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept; + std::vector> GetDescriptorSetLayoutsPipeline(void) const noexcept; + std::vector> GetDescriptorSetLayoutsAllocate(void) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h new file mode 100644 index 00000000..dc21fa37 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h @@ -0,0 +1,14 @@ +#pragma once + +namespace SHADE +{ + // Used for attachment description creation for renderpass node + enum class SH_ATT_DESC_TYPE + { + COLOR, + COLOR_PRESENT, + DEPTH, + STENCIL, + DEPTH_STENCIL, + }; +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index 3f5641c0..cad6a78e 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -11,655 +11,7 @@ namespace SHADE { - /***************************************************************************/ - /*! - - \brief - Non-default ctor for the resource. Using the type of the resource, we - decide whether or not we create a resource or link with a swapchain - resource (image). - - \param logicalDevice - Logical device required to create an image resource if the type is NOT - SH_ATT_DESC_TYPE::COLOR_PRESENT. - - \param swapchain - Swapchain required to get swapchain image if the type IS - SH_ATT_DESC_TYPE::COLOR_PRESENT. - - \param type - Type of the image resource. - - \param format - Format of the image resource. - - \param w - Width of the image resource. - - \param h - Height of the image resource. - - \param levels - Number of mipmap levels of the image resource. - - \param createFlags - Create flags used when an image resource needs to be created. - - */ - /***************************************************************************/ - SHRenderGraphResource::SHRenderGraphResource(Handle const& logicalDevice, Handle const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept - : resourceType{ type } - , resourceFormat{ format } - , images{} - , imageViews{} - , width{ w } - , height{ h } - , mipLevels{ levels } - , resourceName{ name } - { - // If the resource type is an arbitrary image and not swapchain image - if (type != SH_ATT_DESC_TYPE::COLOR_PRESENT) - { - vk::ImageAspectFlags imageAspectFlags; - vk::ImageUsageFlags usage = {}; - - // Check the resource type and set image usage flags and image aspect flags accordingly - switch (resourceType) - { - case SH_ATT_DESC_TYPE::COLOR: - usage |= vk::ImageUsageFlagBits::eColorAttachment; - imageAspectFlags |= vk::ImageAspectFlagBits::eColor; - break; - case SH_ATT_DESC_TYPE::DEPTH: - usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; - imageAspectFlags |= vk::ImageAspectFlagBits::eDepth; - break; - case SH_ATT_DESC_TYPE::STENCIL: - usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; - imageAspectFlags |= vk::ImageAspectFlagBits::eStencil; - break; - case SH_ATT_DESC_TYPE::DEPTH_STENCIL: - usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; - imageAspectFlags |= vk::ImageAspectFlagBits::eStencil | vk::ImageAspectFlagBits::eDepth; - break; - } - - // The resource is not a swapchain image, just use the first slot of the vector - images.push_back(logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags)); - - // prepare image view details - SHImageViewDetails viewDetails - { - .viewType = vk::ImageViewType::e2D, - .format = images[0]->GetImageFormat(), - .imageAspectFlags = imageAspectFlags, - .baseMipLevel = 0, - .mipLevelCount = mipLevels, - .baseArrayLayer = 0, - .layerCount = 1, - }; - - // just 1 image view created - imageViews.push_back(images[0]->CreateImageView(logicalDevice, images[0], viewDetails)); - } - else // if swapchain image resource - { - // Prepare image view details - SHImageViewDetails viewDetails - { - .viewType = vk::ImageViewType::e2D, - .format = swapchain->GetSurfaceFormatKHR().format, - .imageAspectFlags = vk::ImageAspectFlagBits::eColor, - .baseMipLevel = 0, - .mipLevelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }; - - // We want an image handle for every swapchain image - images.resize(swapchain->GetNumImages()); - imageViews.resize(swapchain->GetNumImages()); - - for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i) - { - images[i] = swapchain->GetSwapchainImage(i); - imageViews[i] = images[i]->CreateImageView(logicalDevice, images[i], viewDetails); - } - } - } - - /***************************************************************************/ - /*! - - \brief - Move ctor for resource. - - \param rhs - The other resource. - - */ - /***************************************************************************/ - SHRenderGraphResource::SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept - : resourceName{ std::move(rhs.resourceName) } - , resourceType{ std::move(rhs.resourceType) } - , images{ std::move(rhs.images) } - , imageViews{ std::move(rhs.imageViews) } - , resourceFormat{ std::move(rhs.resourceFormat) } - , width{ rhs.width } - , height{ rhs.height } - , mipLevels{ rhs.mipLevels } - { - - } - - /***************************************************************************/ - /*! - - \brief - Move assignment operator. - - \param rhs - The other resource. - - \return - - */ - /***************************************************************************/ - SHRenderGraphResource& SHRenderGraphResource::operator=(SHRenderGraphResource&& rhs) noexcept - { - if (this == &rhs) - return *this; - - resourceName = std::move(rhs.resourceName); - resourceType = std::move(rhs.resourceType); - images = std::move(rhs.images); - imageViews = std::move(rhs.imageViews); - resourceFormat = std::move(rhs.resourceFormat); - width = rhs.width; - height = rhs.height; - mipLevels = rhs.mipLevels; - - return *this; - } - - /***************************************************************************/ - /*! - - \brief - Destructor for resource. - - */ - /***************************************************************************/ - SHRenderGraphResource::~SHRenderGraphResource(void) noexcept - { - - } - - /***************************************************************************/ - /*! - - \brief - Subpass non-default constructor. Simply initializes variables. - - \param mapping - Mapping from a resource handle to an attachment reference referencing - the resource. - - \param resources - A mapping from string to render graph resource. - - */ - /***************************************************************************/ - SHSubpass::SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* resources) noexcept - : resourceAttachmentMapping{ mapping } - , ptrToResources{ resources } - , parentNode{ parent } - , subpassIndex{ index } - , superBatch{} - , colorReferences{} - , depthReferences{} - , inputReferences{} - { - } - - /***************************************************************************/ - /*! - - \brief - Move constructor for subpass. - - \param rhs - The subpass the move from. - - */ - /***************************************************************************/ - SHSubpass::SHSubpass(SHSubpass&& rhs) noexcept - : subpassIndex{ std::move(rhs.subpassIndex) } - , parentNode{ std::move(rhs.parentNode) } - , superBatch{ std::move(rhs.superBatch) } - , colorReferences{ std::move(rhs.colorReferences) } - , depthReferences{ std::move(rhs.depthReferences) } - , inputReferences{ std::move(rhs.inputReferences) } - , resourceAttachmentMapping{ rhs.resourceAttachmentMapping } - , ptrToResources{ rhs.ptrToResources } - { - - } - - /***************************************************************************/ - /*! - - \brief - Move assignment operator for subpass. - - \param rhs - subpass to move from. - - */ - /***************************************************************************/ - SHSubpass& SHSubpass::operator=(SHSubpass&& rhs) noexcept - { - if (this == &rhs) - return *this; - - subpassIndex = std::move(rhs.subpassIndex); - parentNode = std::move(rhs.parentNode); - superBatch = std::move(rhs.superBatch); - colorReferences = std::move(rhs.colorReferences); - depthReferences = std::move(rhs.depthReferences); - inputReferences = std::move(rhs.inputReferences); - resourceAttachmentMapping = rhs.resourceAttachmentMapping; - ptrToResources = rhs.ptrToResources; - - return *this; - } - - /***************************************************************************/ - /*! - - \brief - Adds a color output to a subpass. Takes in a string and finds the - attachment index to create the vk::SubpassReference. - - \param resourceToReference - Resource name to find resource to attach. - - */ - /***************************************************************************/ - void SHSubpass::AddColorOutput(std::string resourceToReference) noexcept - { - colorReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal }); - } - - /***************************************************************************/ - /*! - - \brief - Adds a depth output to a subpass. Takes in a string and finds the - attachment index to create the vk::SubpassReference. - - \param resourceToReference - Resource name to find resource to attach. - - \param attachmentDescriptionType - Depending on the type of the resource, initialize the image layout - appropriately. - - */ - /***************************************************************************/ - void SHSubpass::AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE attachmentDescriptionType) noexcept - { - vk::ImageLayout imageLayout; - switch (attachmentDescriptionType) - { - case SH_ATT_DESC_TYPE::DEPTH: - imageLayout = vk::ImageLayout::eDepthAttachmentOptimal; - break; - case SH_ATT_DESC_TYPE::STENCIL: - imageLayout = vk::ImageLayout::eStencilAttachmentOptimal; - break; - case SH_ATT_DESC_TYPE::DEPTH_STENCIL: - imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; - break; - default: - //Invalid - return; - } - depthReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), imageLayout }); - } - - /***************************************************************************/ - /*! - - \brief - Adds a input output to a subpass. Takes in a string and finds the - attachment index to create the vk::SubpassReference. - - \param resourceToReference - Resource name to find resource to attach. - - */ - /***************************************************************************/ - void SHSubpass::AddInput(std::string resourceToReference) noexcept - { - inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal }); - } - - void SHSubpass::Execute(Handle& commandBuffer, uint32_t frameIndex) noexcept - { - // Ensure correct transforms are provided - superBatch->UpdateBuffers(frameIndex); - - // Draw all the batches - superBatch->Draw(commandBuffer, frameIndex); - - // Draw all the exterior draw calls - for (auto& drawCall : exteriorDrawCalls) - { - drawCall(commandBuffer); - } - } - - void SHSubpass::AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept - { - exteriorDrawCalls.push_back(newDrawCall); - } - - void SHSubpass::Init(ResourceManager& resourceManager) noexcept - { - superBatch = resourceManager.Create(GetHandle()); - - } - - /***************************************************************************/ - /*! - - \brief - Getter for parent renderpass. - - \return - Returns the parent renderpass the subpass belongs to. - - */ - /***************************************************************************/ - Handle const& SHSubpass::GetParentNode(void) const noexcept - { - return parentNode; - } - - SHADE::SHSubPassIndex SHSubpass::GetIndex() const noexcept - { - return subpassIndex; - } - - Handle SHSubpass::GetSuperBatch(void) const noexcept - { - return superBatch; - } - - /***************************************************************************/ - /*! - - \brief - Creates a renderpass for the node. Uses subpass and attachment - descriptions already configured beforehand in the render graph. - - */ - /***************************************************************************/ - void SHRenderGraphNode::CreateRenderpass(void) noexcept - { - renderpass = logicalDeviceHdl->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); - } - - /***************************************************************************/ - /*! - - \brief - Creates a framebuffer from the images used in the renderpass. - - */ - /***************************************************************************/ - void SHRenderGraphNode::CreateFramebuffer(void) noexcept - { - for (uint32_t i = 0; i < framebuffers.size(); ++i) - { - std::vector> imageViews(attResources.size()); - uint32_t fbWidth = std::numeric_limits::max(); - uint32_t fbHeight = std::numeric_limits::max(); - - for (uint32_t j = 0; j < attResources.size(); ++j) - { - uint32_t imageViewIndex = (attResources[j]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) ? i : 0; - imageViews[j] = attResources[j]->imageViews[imageViewIndex]; - - // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's - if (fbWidth > attResources[j]->width) - fbWidth = attResources[j]->width; - if (fbHeight > attResources[j]->height) - fbHeight = attResources[j]->height; - } - - - framebuffers[i] = logicalDeviceHdl->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); - } - } - - /***************************************************************************/ - /*! - - \brief - Render Graph node constructor. Note that we do not create the renderpass - yet. This is because layouts of attachment descriptions facilitate image - transitions and we cannot know guarantee layouts until we've seen all - renderpasses and their subpasses in the graph. - - \param swapchain - Swapchain required to query number of images as parameters for number - of framebuffers to create. - - \param attachmentDescriptionTypes - - - \return - - */ - /***************************************************************************/ - SHRenderGraphNode::SHRenderGraphNode(ResourceManager& rm, Handle const& logicalDevice, Handle const& swapchain, std::vector> attRes, std::vector> predecessors, std::unordered_map> const* resources, Handle globalData) noexcept - : logicalDeviceHdl{ logicalDevice } - , renderpass{} - , framebuffers{} - , prereqNodes{ std::move(predecessors) } - , attachmentDescriptions{} - , resourceAttachmentMapping{} - , attResources{ std::move(attRes) } - , subpasses{} - , executed{ false } - , configured{ false } - , resourceManager{ rm } - , ptrToResources{ resources } - { - // pipeline library initialization - pipelineLibrary.Init(logicalDeviceHdl, globalData); - - attachmentDescriptions.resize(attResources.size()); - - bool containsSwapchainImage = false; - for (uint32_t i = 0; i < attResources.size(); ++i) - { - // As mentioned above we don't initialize much here because it's dependent on how other renderpasses are configured. - vk::AttachmentDescription& newDesc = attachmentDescriptions[i]; - newDesc.samples = vk::SampleCountFlagBits::e1; - - // We set this to clear first. If later we find out that some predecessor is writing to the same attachment, - // we set the pred's storeOp to eStore and "this" loadOp to eLoad. - newDesc.loadOp = vk::AttachmentLoadOp::eClear; - newDesc.storeOp = vk::AttachmentStoreOp::eStore; - - newDesc.stencilLoadOp = vk::AttachmentLoadOp::eClear; - newDesc.stencilStoreOp = vk::AttachmentStoreOp::eStore; - - newDesc.format = attResources[i]->resourceFormat; - - if (attResources[i]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) - containsSwapchainImage = true; - - resourceAttachmentMapping.try_emplace(attResources[i].GetId().Raw, i); - } - - if (!containsSwapchainImage) - framebuffers.resize(1); - else - framebuffers.resize(swapchain->GetNumImages()); - - // At this point, we could configure framebuffers if we had the renderpass object but we don't so their creation has to be - // deferred to when renderpasses are also created. - } - - SHRenderGraphNode::SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept - : resourceManager{ rhs.resourceManager } - , logicalDeviceHdl{ rhs.logicalDeviceHdl } - , renderpass{ rhs.renderpass } - , framebuffers{ std::move(rhs.framebuffers) } - , prereqNodes{ std::move(rhs.prereqNodes) } - , attachmentDescriptions{ std::move(rhs.attachmentDescriptions) } - , attResources{ std::move(rhs.attResources) } - , subpasses{ std::move(rhs.subpasses) } - , resourceAttachmentMapping{ std::move(rhs.resourceAttachmentMapping) } - , subpassIndexing{ std::move(rhs.subpassIndexing) } - , configured{ rhs.configured } - , executed{ rhs.executed } - , ptrToResources{ rhs.ptrToResources } - , pipelineLibrary{ std::move(rhs.pipelineLibrary) } - , batcher { std::move(rhs.batcher) } - - { - rhs.renderpass = {}; - } - - SHRenderGraphNode& SHRenderGraphNode::operator=(SHRenderGraphNode&& rhs) noexcept - { - if (&rhs == this) - return *this; - - resourceManager = rhs.resourceManager; - logicalDeviceHdl = rhs.logicalDeviceHdl; - renderpass = rhs.renderpass; - framebuffers = std::move(rhs.framebuffers); - prereqNodes = std::move(rhs.prereqNodes); - attachmentDescriptions = std::move(rhs.attachmentDescriptions); - attResources = std::move(rhs.attResources); - subpasses = std::move(rhs.subpasses); - resourceAttachmentMapping = std::move(rhs.resourceAttachmentMapping); - subpassIndexing = std::move(rhs.subpassIndexing); - ptrToResources = std::move(rhs.ptrToResources); - pipelineLibrary = std::move(rhs.pipelineLibrary); - batcher = std::move(rhs.batcher); - - rhs.renderpass = {}; - - return *this; - } - - /***************************************************************************/ - /*! - - \brief - Add subpasses to the renderpass and returns a reference to it. - - \param subpassName - Name of the subpass. - - \return - Handle to the new subpass. - - */ - /***************************************************************************/ - Handle SHRenderGraphNode::AddSubpass(std::string subpassName) noexcept - { - // if subpass already exists, don't add. - if (subpassIndexing.contains(subpassName)) - { - SHLOG_ERROR("Subpass already exists."); - return{}; - } - - // Add subpass to container and create mapping for it - subpasses.emplace_back(resourceManager.Create(resourceManager, GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources)); - subpassIndexing.try_emplace(subpassName, static_cast(subpasses.size()) - 1u); - Handle subpass = subpasses.back(); - subpass->Init(resourceManager); - - // Register the SuperBatch - batcher.RegisterSuperBatch(subpass->GetSuperBatch()); - - return subpass; - } - - void SHRenderGraphNode::Execute(Handle& commandBuffer, uint32_t frameIndex) noexcept - { - frameIndex = (framebuffers.size() > 1) ? frameIndex : 0; - commandBuffer->BeginRenderpass(renderpass, framebuffers[frameIndex]); - - for (uint32_t i = 0; i < subpasses.size(); ++i) - { - subpasses[i]->Execute(commandBuffer, frameIndex); - - // Go to next subpass if not last subpass - if (i != subpasses.size() - 1) - commandBuffer->NextSubpass(); - } - - commandBuffer->EndRenderpass(); - } - - Handle SHRenderGraphNode::GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept - { - // verify subpass exists - if (subpass->GetIndex() >= subpasses.size()) - { - SHLOG_ERROR("Subpass index passed in is not valid. RenderGraphNode does not have that many passes. "); - return {}; - } - - Handle pipeline = pipelineLibrary.GetDrawPipline(vsFsPair); - if (!pipeline) - { - pipeline = pipelineLibrary.CreateDrawPipeline - ( - vsFsPair, - renderpass, - subpass - ); - } - - return pipeline; - } - - void SHRenderGraphNode::FinaliseBatch(uint32_t frameIndex) - { - batcher.FinaliseBatches(logicalDeviceHdl, frameIndex); - } - - /***************************************************************************/ - /*! - - \brief - Get the renderpass from the node. - - \return - Handle to the renderpass. - - */ - /***************************************************************************/ - Handle SHRenderGraphNode::GetRenderpass(void) const noexcept - { - return renderpass; - } - - Handle SHRenderGraphNode::GetSubpass(std::string_view subpassName) const noexcept - { - return subpasses[subpassIndexing.at(subpassName.data())]; - } + /***************************************************************************/ /*! @@ -694,7 +46,7 @@ namespace SHADE if (w == static_cast(-1) && h == static_cast(-1)) { w = swapchainHdl->GetSwapchainImage(0)->GetWidth(); - w = swapchainHdl->GetSwapchainImage(0)->GetHeight(); + h = swapchainHdl->GetSwapchainImage(0)->GetHeight(); format = swapchainHdl->GetSurfaceFormatKHR().format; } @@ -779,7 +131,7 @@ namespace SHADE attDesc.loadOp = vk::AttachmentLoadOp::eLoad; predAttDesc.storeOp = vk::AttachmentStoreOp::eStore; - // TODO: Stecil load and store + // TODO: Stencil load and store // When an image is done being used in a renderpass, the image layout will end up being the finalLayout // value of the attachment description. We want this to carry over to the next renderpass; specifically @@ -976,11 +328,10 @@ namespace SHADE */ /***************************************************************************/ - void SHRenderGraph::Init(Handle const& logicalDevice, Handle const& swapchain, Handle inGlobalData) noexcept + void SHRenderGraph::Init(Handle const& logicalDevice, Handle const& swapchain) noexcept { logicalDeviceHdl = logicalDevice; swapchainHdl = swapchain; - globalData = inGlobalData; } /***************************************************************************/ @@ -1012,7 +363,6 @@ namespace SHADE , nodes{ std::move(rhs.nodes) } , graphResources{ std::move(rhs.graphResources) } , resourceManager{ std::move(rhs.resourceManager) } - , globalData{ rhs.globalData } { } @@ -1028,7 +378,6 @@ namespace SHADE nodes = std::move(rhs.nodes); graphResources = std::move(rhs.graphResources); resourceManager = std::move(rhs.resourceManager); - globalData = rhs.globalData; return *this; } @@ -1086,7 +435,7 @@ namespace SHADE } } - nodes.emplace_back(resourceManager.Create(resourceManager, logicalDeviceHdl, swapchainHdl, std::move(resources), std::move(predecessors), &graphResources, globalData)); + nodes.emplace_back(resourceManager.Create(resourceManager, logicalDeviceHdl, swapchainHdl, std::move(resources), std::move(predecessors), &graphResources)); nodeIndexing.emplace(nodeName, static_cast(nodes.size()) - 1u); return nodes.at(nodeIndexing[nodeName]); } @@ -1114,20 +463,29 @@ namespace SHADE // TODO: The graph scope buffers were meant to bind vertex buffers and index buffers for meshes. Find a // better way to manage these - void SHRenderGraph::Execute(uint32_t frameIndex, Handle cmdBuffer) noexcept + void SHRenderGraph::Execute(uint32_t frameIndex, Handle cmdBuffer, Handle descPool) noexcept { - // TODO: DON'T HARDCODE THIS - cmdBuffer->SetViewportScissor(1920.0f, 1080.0f, 1920, 1080); - for (auto& node : nodes) - node->Execute(cmdBuffer, frameIndex); + node->Execute(cmdBuffer, descPool, frameIndex); } - void SHRenderGraph::FinaliseBatch(uint32_t frameIndex) + void SHRenderGraph::FinaliseBatch(uint32_t frameIndex, Handle descPool) { for (auto& node : nodes) { - node->FinaliseBatch(frameIndex); + node->FinaliseBatch(frameIndex, descPool); + } + } + + void SHRenderGraph::HandleResize(uint32_t newWidth, uint32_t newHeight) noexcept + { + // resize resources + for (auto& [name, resource]: graphResources) + resource->HandleResize(newWidth, newHeight); + + for (auto& node : nodes) + { + node->HandleResize(); } } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index 91a2f1f5..a3140a4f 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -7,6 +7,12 @@ #include "Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h" #include "Graphics/MiddleEnd/Batching/SHSuperBatch.h" #include "../MiddleEnd/Batching/SHBatcher.h" +#include "SHRenderGraphNode.h" +#include "SHSubpass.h" +#include "SHRenderGraphResource.h" +#include "SHRenderGraphNode.h" +#include "SHSubpass.h" +#include "SHAttachmentDescriptionType.h" #include #include @@ -24,223 +30,6 @@ namespace SHADE class SHRenderGraphNode; class SHGraphicsGlobalData; - // Used for attachment description creation for renderpass node - enum class SH_ATT_DESC_TYPE - { - COLOR, - COLOR_PRESENT, - DEPTH, - STENCIL, - DEPTH_STENCIL, - }; - - - class SH_API SHRenderGraphResource - { - private: - /*-----------------------------------------------------------------------*/ - /* PRIVATE MEMBER VARIABLES */ - /*-----------------------------------------------------------------------*/ - //! Name of the resource - std::string resourceName; - - //! Used for initializing image layouts - SH_ATT_DESC_TYPE resourceType; - - //! The resource itself (this is a vector because if the resource happens - //! to be a swapchain image, then we need however many frames in flight). - //! However when it's not a swapchain image, we want this container to be size 1 - //! because writing to these images will not interfere with images in the previous - //! frame, unlike the swapchain image. - std::vector> images; - - //! Views to resources (vector because same rationale as images. see above). - std::vector> imageViews; - - //! Image format - vk::Format resourceFormat; - - //! width of the resource - uint32_t width; - - //! Height of the resource - uint32_t height; - - //! Number of mipmap levels - uint8_t mipLevels; - public: - /*-----------------------------------------------------------------------*/ - /* CTORS AND DTORS */ - /*-----------------------------------------------------------------------*/ - SHRenderGraphResource(Handle const& logicalDevice, Handle const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept; - SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept; - SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept; - ~SHRenderGraphResource(void) noexcept; - - friend class SHRenderGraphNode; - friend class SHRenderGraph; - }; - - - class SH_API SHSubpass : public ISelfHandle - { - private: - /*---------------------------------------------------------------------*/ - /* PRIVATE MEMBER VARIABLES */ - /*---------------------------------------------------------------------*/ - //! The index of the subpass in the render graph - uint32_t subpassIndex; - - //! The parent renderpass that this subpass belongs to - Handle parentNode; - - //! - Handle superBatch; - - //! Color attachments - std::vector colorReferences; - - //! Depth attachments - std::vector depthReferences; - - //! Input attachments - std::vector inputReferences; - - //! For getting attachment reference indices using handles - std::unordered_map const* resourceAttachmentMapping; - - //! Pointer to resources in the render graph (for getting handle IDs) - std::unordered_map> const* ptrToResources; - - //! Sometimes there exists entities that we want to render onto a render target - //! but don't want it to come from the batching system. An example would be ImGUI. - //! For these entities we want to link a function from the outside and draw them - //! after we draw everything from the batch. Because of this, these draw calls - //! are always the last things drawn, so DO NOT USE THIS FUNCTIONALITY FOR ANYTHING - //! COMPLEX. - std::vector&)>> exteriorDrawCalls; - - public: - /*-----------------------------------------------------------------------*/ - /* CTORS AND DTORS */ - /*-----------------------------------------------------------------------*/ - SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* ptrToResources) noexcept; - SHSubpass(SHSubpass&& rhs) noexcept; - SHSubpass& operator=(SHSubpass&& rhs) noexcept; - - /*-----------------------------------------------------------------------*/ - /* PUBLIC MEMBER FUNCTIONS */ - /*-----------------------------------------------------------------------*/ - // Preparation functions - void AddColorOutput(std::string resourceToReference) noexcept; - void AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE attachmentDescriptionType = SH_ATT_DESC_TYPE::DEPTH_STENCIL) noexcept; - void AddInput(std::string resourceToReference) noexcept; - - // Runtime functions - void Execute(Handle& commandBuffer, uint32_t frameIndex) noexcept; - void AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept; - - void Init (ResourceManager& resourceManager) noexcept; - - /*-----------------------------------------------------------------------*/ - /* GETTERS AND SETTERS */ - /*-----------------------------------------------------------------------*/ - Handle const& GetParentNode(void) const noexcept; - SHSubPassIndex GetIndex() const noexcept; - Handle GetSuperBatch (void) const noexcept; - - - friend class SHRenderGraphNode; - friend class SHRenderGraph; - }; - - class SH_API SHRenderGraphNode : public ISelfHandle - { - private: - /*-----------------------------------------------------------------------*/ - /* PRIVATE MEMBER VARIABLES */ - /*-----------------------------------------------------------------------*/ - ResourceManager& resourceManager; - - //! For Vulkan object creation - Handle logicalDeviceHdl; - - //! Each node will have a renderpass and each renderpass will have its own subpasses. - //! These subpasses will execute sequentially. - Handle renderpass; - - //! Framebuffers used in this renderpass. If renderpass contains usage of a swapchain image - //! used for presenting, then we cannot use just 1 framebuffer, we need to have 1 for however many frames in flight. - std::vector> framebuffers; - - //! Nodes that must finish execution before this node is executed will be in this container - std::vector> prereqNodes; - - //! Container of Attachment descriptions - std::vector attachmentDescriptions; - - //! Resources used in this renderpass - std::vector> attResources; - - //! Vector of subpasses - std::vector> subpasses; - - //! Descriptions to pass to renderpass for renderpass creation. We want to keep this here because - std::vector spDescs; - - //! Subpass dependencies for renderpass creation - std::vector spDeps; - - //! For indexing resources fast - std::unordered_map resourceAttachmentMapping; - - //! For indexing subpasses - std::map subpassIndexing; - - //! Pointer to resources in the render graph (for getting handle IDs) - std::unordered_map> const* ptrToResources; - - //! Every renderpass will require a pipeline library that will contain pipelines compatible with this renderpass - SHPipelineLibrary pipelineLibrary; - - //! Whether or not the node has finished execution - bool executed; - - //! Whether or not the node has been configured already or not - bool configured; - - SHBatcher batcher; - - /*-----------------------------------------------------------------------*/ - /* PRIVATE MEMBER FUNCTIONS */ - /*-----------------------------------------------------------------------*/ - void CreateRenderpass (void) noexcept; - void CreateFramebuffer(void) noexcept; - - public: - /*-----------------------------------------------------------------------*/ - /* CTORS AND DTORS */ - /*-----------------------------------------------------------------------*/ - SHRenderGraphNode (ResourceManager& rm, Handle const& logicalDevice, Handle const& swapchain, std::vector> attRes, std::vector> predecessors, std::unordered_map> const* resources, Handle globalData) noexcept; - SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept; - SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept; - - /*-----------------------------------------------------------------------*/ - /* PUBLIC MEMBER FUNCTIONS */ - /*-----------------------------------------------------------------------*/ - Handle AddSubpass (std::string subpassName) noexcept; - // TODO: RemoveSubpass() - void Execute (Handle& commandBuffer, uint32_t frameIndex) noexcept; - Handle GetOrCreatePipeline (std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; - void FinaliseBatch(uint32_t frameIndex); - - /*-----------------------------------------------------------------------*/ - /* SETTERS AND GETTERS */ - /*-----------------------------------------------------------------------*/ - Handle GetRenderpass (void) const noexcept; - Handle GetSubpass(std::string_view subpassName) const noexcept; - friend class SHRenderGraph; - }; class SH_API SHRenderGraph { @@ -272,9 +61,6 @@ namespace SHADE //! Resource library for graph handles ResourceManager resourceManager; - - //! Handle to global data - Handle globalData; public: /*-----------------------------------------------------------------------*/ @@ -288,12 +74,13 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void Init (Handle const& logicalDevice, Handle const& swapchain, Handle inGlobalData) noexcept; + void Init (Handle const& logicalDevice, Handle const& swapchain) noexcept; void AddResource (std::string resourceName, SH_ATT_DESC_TYPE type, uint32_t w = static_cast(-1), uint32_t h = static_cast(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, uint8_t levels = 1, vk::ImageCreateFlagBits createFlags = {}); Handle AddNode (std::string nodeName, std::initializer_list resourceNames, std::initializer_list predecessorNodes) noexcept; void Generate (void) noexcept; - void Execute (uint32_t frameIndex, Handle cmdBuffer) noexcept; - void FinaliseBatch(uint32_t frameIndex); + void Execute (uint32_t frameIndex, Handle cmdBuffer, Handle descPool) noexcept; + void FinaliseBatch(uint32_t frameIndex, Handle descPool); + void HandleResize (uint32_t newWidth, uint32_t newHeight) noexcept; /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp new file mode 100644 index 00000000..05232af3 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -0,0 +1,304 @@ +#include "SHpch.h" +#include "SHRenderGraphNode.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Graphics/Images/SHVkImageView.h" +#include "Graphics/Swapchain/SHVkSwapchain.h" +#include "Graphics/Framebuffer/SHVkFramebuffer.h" +#include "SHRenderGraphResource.h" +#include "SHSubpass.h" + +namespace SHADE +{ + + /***************************************************************************/ + /*! + + \brief + Creates a renderpass for the node. Uses subpass and attachment + descriptions already configured beforehand in the render graph. + + */ + /***************************************************************************/ + void SHRenderGraphNode::CreateRenderpass(void) noexcept + { + renderpass = logicalDeviceHdl->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); + } + + /***************************************************************************/ + /*! + + \brief + Creates a framebuffer from the images used in the renderpass. + + */ + /***************************************************************************/ + void SHRenderGraphNode::CreateFramebuffer(void) noexcept + { + for (uint32_t i = 0; i < framebuffers.size(); ++i) + { + std::vector> imageViews(attResources.size()); + uint32_t fbWidth = std::numeric_limits::max(); + uint32_t fbHeight = std::numeric_limits::max(); + + for (uint32_t j = 0; j < attResources.size(); ++j) + { + uint32_t imageViewIndex = (attResources[j]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) ? i : 0; + imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + + // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's + if (fbWidth > attResources[j]->width) + fbWidth = attResources[j]->width; + if (fbHeight > attResources[j]->height) + fbHeight = attResources[j]->height; + } + + + framebuffers[i] = logicalDeviceHdl->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); + } + } + + void SHRenderGraphNode::HandleResize(void) noexcept + { + renderpass->HandleResize(); + + for (uint32_t i = 0; i < framebuffers.size(); ++i) + { + std::vector> imageViews(attResources.size()); + uint32_t fbWidth = std::numeric_limits::max(); + uint32_t fbHeight = std::numeric_limits::max(); + + for (uint32_t j = 0; j < attResources.size(); ++j) + { + uint32_t imageViewIndex = (attResources[j]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) ? i : 0; + imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + + // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's + if (fbWidth > attResources[j]->width) + fbWidth = attResources[j]->width; + if (fbHeight > attResources[j]->height) + fbHeight = attResources[j]->height; + } + + + framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight); + } + } + + /***************************************************************************/ + /*! + + \brief + Render Graph node constructor. Note that we do not create the renderpass + yet. This is because layouts of attachment descriptions facilitate image + transitions and we cannot know guarantee layouts until we've seen all + renderpasses and their subpasses in the graph. + + \param swapchain + Swapchain required to query number of images as parameters for number + of framebuffers to create. + + \param attachmentDescriptionTypes + + + \return + + */ + /***************************************************************************/ + SHRenderGraphNode::SHRenderGraphNode(ResourceManager& rm, Handle const& logicalDevice, Handle const& swapchain, std::vector> attRes, std::vector> predecessors, std::unordered_map> const* resources) noexcept + : logicalDeviceHdl{ logicalDevice } + , renderpass{} + , framebuffers{} + , prereqNodes{ std::move(predecessors) } + , attachmentDescriptions{} + , resourceAttachmentMapping{} + , attResources{ std::move(attRes) } + , subpasses{} + , executed{ false } + , configured{ false } + , resourceManager{ rm } + , ptrToResources{ resources } + { + // pipeline library initialization + pipelineLibrary.Init(logicalDeviceHdl); + + attachmentDescriptions.resize(attResources.size()); + + bool containsSwapchainImage = false; + for (uint32_t i = 0; i < attResources.size(); ++i) + { + // As mentioned above we don't initialize much here because it's dependent on how other renderpasses are configured. + vk::AttachmentDescription& newDesc = attachmentDescriptions[i]; + newDesc.samples = vk::SampleCountFlagBits::e1; + + // We set this to clear first. If later we find out that some predecessor is writing to the same attachment, + // we set the pred's storeOp to eStore and "this" loadOp to eLoad. + newDesc.loadOp = vk::AttachmentLoadOp::eClear; + newDesc.storeOp = vk::AttachmentStoreOp::eStore; + + newDesc.stencilLoadOp = vk::AttachmentLoadOp::eClear; + newDesc.stencilStoreOp = vk::AttachmentStoreOp::eStore; + + newDesc.format = attResources[i]->resourceFormat; + + if (attResources[i]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) + containsSwapchainImage = true; + + resourceAttachmentMapping.try_emplace(attResources[i].GetId().Raw, i); + } + + if (!containsSwapchainImage) + framebuffers.resize(1); + else + framebuffers.resize(swapchain->GetNumImages()); + + // At this point, we could configure framebuffers if we had the renderpass object but we don't so their creation has to be + // deferred to when renderpasses are also created. + } + + SHRenderGraphNode::SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept + : resourceManager{ rhs.resourceManager } + , logicalDeviceHdl{ rhs.logicalDeviceHdl } + , renderpass{ rhs.renderpass } + , framebuffers{ std::move(rhs.framebuffers) } + , prereqNodes{ std::move(rhs.prereqNodes) } + , attachmentDescriptions{ std::move(rhs.attachmentDescriptions) } + , attResources{ std::move(rhs.attResources) } + , subpasses{ std::move(rhs.subpasses) } + , resourceAttachmentMapping{ std::move(rhs.resourceAttachmentMapping) } + , subpassIndexing{ std::move(rhs.subpassIndexing) } + , configured{ rhs.configured } + , executed{ rhs.executed } + , ptrToResources{ rhs.ptrToResources } + , pipelineLibrary{ std::move(rhs.pipelineLibrary) } + , batcher{ std::move(rhs.batcher) } + + { + rhs.renderpass = {}; + } + + SHRenderGraphNode& SHRenderGraphNode::operator=(SHRenderGraphNode&& rhs) noexcept + { + if (&rhs == this) + return *this; + + resourceManager = rhs.resourceManager; + logicalDeviceHdl = rhs.logicalDeviceHdl; + renderpass = rhs.renderpass; + framebuffers = std::move(rhs.framebuffers); + prereqNodes = std::move(rhs.prereqNodes); + attachmentDescriptions = std::move(rhs.attachmentDescriptions); + attResources = std::move(rhs.attResources); + subpasses = std::move(rhs.subpasses); + resourceAttachmentMapping = std::move(rhs.resourceAttachmentMapping); + subpassIndexing = std::move(rhs.subpassIndexing); + ptrToResources = std::move(rhs.ptrToResources); + pipelineLibrary = std::move(rhs.pipelineLibrary); + batcher = std::move(rhs.batcher); + + rhs.renderpass = {}; + + return *this; + } + + /***************************************************************************/ + /*! + + \brief + Add subpasses to the renderpass and returns a reference to it. + + \param subpassName + Name of the subpass. + + \return + Handle to the new subpass. + + */ + /***************************************************************************/ + Handle SHRenderGraphNode::AddSubpass(std::string subpassName) noexcept + { + // if subpass already exists, don't add. + if (subpassIndexing.contains(subpassName)) + { + SHLOG_ERROR("Subpass already exists."); + return{}; + } + + // Add subpass to container and create mapping for it + subpasses.emplace_back(resourceManager.Create(resourceManager, GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources)); + subpassIndexing.try_emplace(subpassName, static_cast(subpasses.size()) - 1u); + Handle subpass = subpasses.back(); + subpass->Init(resourceManager); + + // Register the SuperBatch + batcher.RegisterSuperBatch(subpass->GetSuperBatch()); + + return subpass; + } + + void SHRenderGraphNode::Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept + { + frameIndex = (framebuffers.size() > 1) ? frameIndex : 0; + commandBuffer->BeginRenderpass(renderpass, framebuffers[frameIndex]); + + for (uint32_t i = 0; i < subpasses.size(); ++i) + { + subpasses[i]->Execute(commandBuffer, descPool, frameIndex); + + // Go to next subpass if not last subpass + if (i != subpasses.size() - 1) + commandBuffer->NextSubpass(); + } + + commandBuffer->EndRenderpass(); + } + + Handle SHRenderGraphNode::GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept + { + // verify subpass exists + if (subpass->GetIndex() >= subpasses.size()) + { + SHLOG_ERROR("Subpass index passed in is not valid. RenderGraphNode does not have that many passes. "); + return {}; + } + + Handle pipeline = pipelineLibrary.GetDrawPipline(vsFsPair); + if (!pipeline) + { + pipeline = pipelineLibrary.CreateDrawPipeline + ( + vsFsPair, + renderpass, + subpass + ); + } + + return pipeline; + } + + void SHRenderGraphNode::FinaliseBatch(uint32_t frameIndex, Handle descPool) + { + batcher.FinaliseBatches(logicalDeviceHdl, descPool, frameIndex); + } + + /***************************************************************************/ + /*! + + \brief + Get the renderpass from the node. + + \return + Handle to the renderpass. + + */ + /***************************************************************************/ + Handle SHRenderGraphNode::GetRenderpass(void) const noexcept + { + return renderpass; + } + + Handle SHRenderGraphNode::GetSubpass(std::string_view subpassName) const noexcept + { + return subpasses[subpassIndexing.at(subpassName.data())]; + } + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h new file mode 100644 index 00000000..c713f402 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -0,0 +1,111 @@ +#pragma once + +#include +#include +#include +#include +#include "SHAttachmentDescriptionType.h" +#include "Graphics/SHVulkanIncludes.h" +#include "SH_API.h" +#include "Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h" +#include "Graphics/MiddleEnd/Batching/SHBatcher.h" + +namespace SHADE +{ + class ResourceManager; + class SHVkFramebuffer; + class SHRenderGraphResource; + class SHVkLogicalDevice; + class SHVkRenderpass; + class SHVkDescriptorPool; + + class SH_API SHRenderGraphNode : public ISelfHandle + { + private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE MEMBER VARIABLES */ + /*-----------------------------------------------------------------------*/ + ResourceManager& resourceManager; + + //! For Vulkan object creation + Handle logicalDeviceHdl; + + //! Each node will have a renderpass and each renderpass will have its own subpasses. + //! These subpasses will execute sequentially. + Handle renderpass; + + //! Framebuffers used in this renderpass. If renderpass contains usage of a swapchain image + //! used for presenting, then we cannot use just 1 framebuffer, we need to have 1 for however many frames in flight. + std::vector> framebuffers; + + //! Nodes that must finish execution before this node is executed will be in this container + std::vector> prereqNodes; + + //! Container of Attachment descriptions + std::vector attachmentDescriptions; + + //! Resources used in this renderpass + std::vector> attResources; + + //! Vector of subpasses + std::vector> subpasses; + + //! Descriptions to pass to renderpass for renderpass creation. We want to keep this here because + std::vector spDescs; + + //! Subpass dependencies for renderpass creation + std::vector spDeps; + + //! For indexing resources fast + std::unordered_map resourceAttachmentMapping; + + //! For indexing subpasses + std::map subpassIndexing; + + //! Pointer to resources in the render graph (for getting handle IDs) + std::unordered_map> const* ptrToResources; + + //! Every renderpass will require a pipeline library that will contain pipelines compatible with this renderpass + SHPipelineLibrary pipelineLibrary; + + //! Whether or not the node has finished execution + bool executed; + + //! Whether or not the node has been configured already or not + bool configured; + + SHBatcher batcher; + + /*-----------------------------------------------------------------------*/ + /* PRIVATE MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + void CreateRenderpass(void) noexcept; + void CreateFramebuffer(void) noexcept; + void HandleResize (void) noexcept; + + public: + /*-----------------------------------------------------------------------*/ + /* CTORS AND DTORS */ + /*-----------------------------------------------------------------------*/ + SHRenderGraphNode(ResourceManager& rm, Handle const& logicalDevice, Handle const& swapchain, std::vector> attRes, std::vector> predecessors, std::unordered_map> const* resources) noexcept; + SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept; + SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept; + + /*-----------------------------------------------------------------------*/ + /* PUBLIC MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + Handle AddSubpass(std::string subpassName) noexcept; + // TODO: RemoveSubpass() + void Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; + Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; + void FinaliseBatch(uint32_t frameIndex, Handle descPool); + + /*-----------------------------------------------------------------------*/ + /* SETTERS AND GETTERS */ + /*-----------------------------------------------------------------------*/ + Handle GetRenderpass(void) const noexcept; + Handle GetSubpass(std::string_view subpassName) const noexcept; + friend class SHRenderGraph; + }; + +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp new file mode 100644 index 00000000..cc881867 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp @@ -0,0 +1,245 @@ +#include "SHpch.h" +#include "SHRenderGraphResource.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Graphics/Swapchain/SHVkSwapchain.h" +#include "Graphics/Images/SHVkImageView.h" + +namespace SHADE +{ + + /***************************************************************************/ + /*! + + \brief + Non-default ctor for the resource. Using the type of the resource, we + decide whether or not we create a resource or link with a swapchain + resource (image). + + \param logicalDevice + Logical device required to create an image resource if the type is NOT + SH_ATT_DESC_TYPE::COLOR_PRESENT. + + \param swapchain + Swapchain required to get swapchain image if the type IS + SH_ATT_DESC_TYPE::COLOR_PRESENT. + + \param type + Type of the image resource. + + \param format + Format of the image resource. + + \param w + Width of the image resource. + + \param h + Height of the image resource. + + \param levels + Number of mipmap levels of the image resource. + + \param createFlags + Create flags used when an image resource needs to be created. + + */ + /***************************************************************************/ + SHRenderGraphResource::SHRenderGraphResource(Handle const& logicalDevice, Handle const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept + : logicalDevice {logicalDevice} + , swapchain{ swapchain } + , resourceType{ type } + , resourceFormat{ format } + , images{} + , imageViews{} + , width{ w } + , height{ h } + , mipLevels{ levels } + , resourceName{ name } + { + // If the resource type is an arbitrary image and not swapchain image + if (resourceType != SH_ATT_DESC_TYPE::COLOR_PRESENT) + { + imageAspectFlags = vk::ImageAspectFlags{}; + usage = {}; + + // Check the resource type and set image usage flags and image aspect flags accordingly + switch (resourceType) + { + case SH_ATT_DESC_TYPE::COLOR: + usage |= vk::ImageUsageFlagBits::eColorAttachment; + imageAspectFlags |= vk::ImageAspectFlagBits::eColor; + break; + case SH_ATT_DESC_TYPE::DEPTH: + usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; + imageAspectFlags |= vk::ImageAspectFlagBits::eDepth; + break; + case SH_ATT_DESC_TYPE::STENCIL: + usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; + imageAspectFlags |= vk::ImageAspectFlagBits::eStencil; + break; + case SH_ATT_DESC_TYPE::DEPTH_STENCIL: + usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; + imageAspectFlags |= vk::ImageAspectFlagBits::eStencil | vk::ImageAspectFlagBits::eDepth; + break; + } + + // The resource is not a swapchain image, just use the first slot of the vector + images.push_back(logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags)); + + // prepare image view details + SHImageViewDetails viewDetails + { + .viewType = vk::ImageViewType::e2D, + .format = images[0]->GetImageFormat(), + .imageAspectFlags = imageAspectFlags, + .baseMipLevel = 0, + .mipLevelCount = mipLevels, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + // just 1 image view created + imageViews.push_back(images[0]->CreateImageView(logicalDevice, images[0], viewDetails)); + } + else // if swapchain image resource + { + // Prepare image view details + SHImageViewDetails viewDetails + { + .viewType = vk::ImageViewType::e2D, + .format = swapchain->GetSurfaceFormatKHR().format, + .imageAspectFlags = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .mipLevelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + // We want an image handle for every swapchain image + images.resize(swapchain->GetNumImages()); + imageViews.resize(swapchain->GetNumImages()); + + for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i) + { + images[i] = swapchain->GetSwapchainImage(i); + imageViews[i] = images[i]->CreateImageView(logicalDevice, images[i], viewDetails); + } + } + } + + /***************************************************************************/ + /*! + + \brief + Move ctor for resource. + + \param rhs + The other resource. + + */ + /***************************************************************************/ + SHRenderGraphResource::SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept + : resourceName{ std::move(rhs.resourceName) } + , resourceType{ std::move(rhs.resourceType) } + , images{ std::move(rhs.images) } + , imageViews{ std::move(rhs.imageViews) } + , resourceFormat{ std::move(rhs.resourceFormat) } + , width{ rhs.width } + , height{ rhs.height } + , mipLevels{ rhs.mipLevels } + , imageAspectFlags{ rhs.imageAspectFlags } + { + + } + + /***************************************************************************/ + /*! + + \brief + Move assignment operator. + + \param rhs + The other resource. + + \return + + */ + /***************************************************************************/ + SHRenderGraphResource& SHRenderGraphResource::operator=(SHRenderGraphResource&& rhs) noexcept + { + if (this == &rhs) + return *this; + + resourceName = std::move(rhs.resourceName); + resourceType = std::move(rhs.resourceType); + images = std::move(rhs.images); + imageViews = std::move(rhs.imageViews); + resourceFormat = std::move(rhs.resourceFormat); + width = rhs.width; + height = rhs.height; + mipLevels = rhs.mipLevels; + imageAspectFlags = rhs.imageAspectFlags; + + return *this; + } + + /***************************************************************************/ + /*! + + \brief + Destructor for resource. + + */ + /***************************************************************************/ + SHRenderGraphResource::~SHRenderGraphResource(void) noexcept + { + + } + + void SHRenderGraphResource::HandleResize(uint32_t newWidth, uint32_t newHeight) noexcept + { + width = newWidth; + height = newHeight; + + if (resourceType != SH_ATT_DESC_TYPE::COLOR_PRESENT) + { + // prepare image view details + SHImageViewDetails viewDetails + { + .viewType = vk::ImageViewType::e2D, + .format = images[0]->GetImageFormat(), + .imageAspectFlags = imageAspectFlags, + .baseMipLevel = 0, + .mipLevelCount = mipLevels, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + for (uint32_t i = 0; i < images.size(); ++i) + { + images[i]->HandleResizeFramebufferImage(width, height); + imageViews[i]->ViewNewImage(images[i], viewDetails); + } + } + else + { + // Prepare image view details + SHImageViewDetails viewDetails + { + .viewType = vk::ImageViewType::e2D, + .format = swapchain->GetSurfaceFormatKHR().format, + .imageAspectFlags = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .mipLevelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i) + { + images[i] = swapchain->GetSwapchainImage(i); + imageViews[i]->ViewNewImage(images[i], viewDetails); + } + } + } + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h new file mode 100644 index 00000000..ebb699d8 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h @@ -0,0 +1,78 @@ +#pragma once + +#include +#include "SHAttachmentDescriptionType.h" +#include +#include "Resource/Handle.h" +#include "Graphics/SHVulkanIncludes.h" +#include "SH_API.h" + +namespace SHADE +{ + class SHVkImage; + class SHVkImageView; + class SHVkLogicalDevice; + class SHVkSwapchain; + + class SH_API SHRenderGraphResource + { + private: + /*-----------------------------------------------------------------------*/ + /* PRIVATE MEMBER VARIABLES */ + /*-----------------------------------------------------------------------*/ + // for creation/recreation + Handle logicalDevice; + + // for creation/recreation + Handle swapchain; + + //! Name of the resource + std::string resourceName; + + //! Used for initializing image layouts + SH_ATT_DESC_TYPE resourceType; + + //! The resource itself (this is a vector because if the resource happens + //! to be a swapchain image, then we need however many frames in flight). + //! However when it's not a swapchain image, we want this container to be size 1 + //! because writing to these images will not interfere with images in the previous + //! frame, unlike the swapchain image. + std::vector> images; + + //! Views to resources (vector because same rationale as images. see above). + std::vector> imageViews; + + //! Image format + vk::Format resourceFormat; + + //! width of the resource + uint32_t width; + + //! Height of the resource + uint32_t height; + + //! Number of mipmap levels + uint8_t mipLevels; + + //! image aspect flags + vk::ImageAspectFlags imageAspectFlags; + + //! usage flags + vk::ImageUsageFlags usage = {}; + + + public: + /*-----------------------------------------------------------------------*/ + /* CTORS AND DTORS */ + /*-----------------------------------------------------------------------*/ + SHRenderGraphResource(Handle const& logicalDevice, Handle const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept; + SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept; + SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept; + ~SHRenderGraphResource(void) noexcept; + + void HandleResize (uint32_t newWidth, uint32_t newHeight) noexcept; + + friend class SHRenderGraphNode; + friend class SHRenderGraph; + }; +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp new file mode 100644 index 00000000..007502dd --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -0,0 +1,210 @@ +#include "SHpch.h" +#include "SHSubpass.h" +#include "Graphics/MiddleEnd/Batching/SHSuperBatch.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" + +namespace SHADE +{ + + /***************************************************************************/ + /*! + + \brief + Subpass non-default constructor. Simply initializes variables. + + \param mapping + Mapping from a resource handle to an attachment reference referencing + the resource. + + \param resources + A mapping from string to render graph resource. + + */ + /***************************************************************************/ + SHSubpass::SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* resources) noexcept + : resourceAttachmentMapping{ mapping } + , ptrToResources{ resources } + , parentNode{ parent } + , subpassIndex{ index } + , superBatch{} + , colorReferences{} + , depthReferences{} + , inputReferences{} + { + } + + /***************************************************************************/ + /*! + + \brief + Move constructor for subpass. + + \param rhs + The subpass the move from. + + */ + /***************************************************************************/ + SHSubpass::SHSubpass(SHSubpass&& rhs) noexcept + : subpassIndex{ std::move(rhs.subpassIndex) } + , parentNode{ std::move(rhs.parentNode) } + , superBatch{ std::move(rhs.superBatch) } + , colorReferences{ std::move(rhs.colorReferences) } + , depthReferences{ std::move(rhs.depthReferences) } + , inputReferences{ std::move(rhs.inputReferences) } + , resourceAttachmentMapping{ rhs.resourceAttachmentMapping } + , ptrToResources{ rhs.ptrToResources } + { + + } + + /***************************************************************************/ + /*! + + \brief + Move assignment operator for subpass. + + \param rhs + subpass to move from. + + */ + /***************************************************************************/ + SHSubpass& SHSubpass::operator=(SHSubpass&& rhs) noexcept + { + if (this == &rhs) + return *this; + + subpassIndex = std::move(rhs.subpassIndex); + parentNode = std::move(rhs.parentNode); + superBatch = std::move(rhs.superBatch); + colorReferences = std::move(rhs.colorReferences); + depthReferences = std::move(rhs.depthReferences); + inputReferences = std::move(rhs.inputReferences); + resourceAttachmentMapping = rhs.resourceAttachmentMapping; + ptrToResources = rhs.ptrToResources; + + return *this; + } + + /***************************************************************************/ + /*! + + \brief + Adds a color output to a subpass. Takes in a string and finds the + attachment index to create the vk::SubpassReference. + + \param resourceToReference + Resource name to find resource to attach. + + */ + /***************************************************************************/ + void SHSubpass::AddColorOutput(std::string resourceToReference) noexcept + { + colorReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal }); + } + + /***************************************************************************/ + /*! + + \brief + Adds a depth output to a subpass. Takes in a string and finds the + attachment index to create the vk::SubpassReference. + + \param resourceToReference + Resource name to find resource to attach. + + \param attachmentDescriptionType + Depending on the type of the resource, initialize the image layout + appropriately. + + */ + /***************************************************************************/ + void SHSubpass::AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE attachmentDescriptionType) noexcept + { + vk::ImageLayout imageLayout; + switch (attachmentDescriptionType) + { + case SH_ATT_DESC_TYPE::DEPTH: + imageLayout = vk::ImageLayout::eDepthAttachmentOptimal; + break; + case SH_ATT_DESC_TYPE::STENCIL: + imageLayout = vk::ImageLayout::eStencilAttachmentOptimal; + break; + case SH_ATT_DESC_TYPE::DEPTH_STENCIL: + imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; + break; + default: + //Invalid + return; + } + depthReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), imageLayout }); + } + + /***************************************************************************/ + /*! + + \brief + Adds a input output to a subpass. Takes in a string and finds the + attachment index to create the vk::SubpassReference. + + \param resourceToReference + Resource name to find resource to attach. + + */ + /***************************************************************************/ + void SHSubpass::AddInput(std::string resourceToReference) noexcept + { + inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal }); + } + + void SHSubpass::Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept + { + // Ensure correct transforms are provided + superBatch->UpdateBuffers(frameIndex, descPool); + + // Draw all the batches + superBatch->Draw(commandBuffer, frameIndex); + + // Draw all the exterior draw calls + for (auto& drawCall : exteriorDrawCalls) + { + drawCall(commandBuffer); + } + } + + void SHSubpass::AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept + { + exteriorDrawCalls.push_back(newDrawCall); + } + + void SHSubpass::Init(ResourceManager& resourceManager) noexcept + { + superBatch = resourceManager.Create(GetHandle()); + + } + + /***************************************************************************/ + /*! + + \brief + Getter for parent renderpass. + + \return + Returns the parent renderpass the subpass belongs to. + + */ + /***************************************************************************/ + Handle const& SHSubpass::GetParentNode(void) const noexcept + { + return parentNode; + } + + SHADE::SHSubPassIndex SHSubpass::GetIndex() const noexcept + { + return subpassIndex; + } + + Handle SHSubpass::GetSuperBatch(void) const noexcept + { + return superBatch; + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h new file mode 100644 index 00000000..b8b8717f --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h @@ -0,0 +1,94 @@ +#pragma once + +#include "SHAttachmentDescriptionType.h" +#include +#include "SH_API.h" +#include "Resource/Handle.h" +#include "Graphics/SHVulkanIncludes.h" + + +namespace SHADE +{ + class SHRenderGraphNode; + class SHSuperBatch; + class SHRenderGraphResource; + class SHVkCommandBuffer; + class SHVkDescriptorSetLayout; + class SHVkDescriptorPool; + + class SH_API SHSubpass : public ISelfHandle + { + private: + /*---------------------------------------------------------------------*/ + /* PRIVATE MEMBER VARIABLES */ + /*---------------------------------------------------------------------*/ + //! The index of the subpass in the render graph + uint32_t subpassIndex; + + //! The parent renderpass that this subpass belongs to + Handle parentNode; + + //! + Handle superBatch; + + //! Descriptor set layout to hold attachments + Handle descriptorSetLayout; + + //! Color attachments + std::vector colorReferences; + + //! Depth attachments + std::vector depthReferences; + + //! Input attachments + std::vector inputReferences; + + //! For getting attachment reference indices using handles + std::unordered_map const* resourceAttachmentMapping; + + //! Pointer to resources in the render graph (for getting handle IDs) + std::unordered_map> const* ptrToResources; + + //! Sometimes there exists entities that we want to render onto a render target + //! but don't want it to come from the batching system. An example would be ImGUI. + //! For these entities we want to link a function from the outside and draw them + //! after we draw everything from the batch. Because of this, these draw calls + //! are always the last things drawn, so DO NOT USE THIS FUNCTIONALITY FOR ANYTHING + //! COMPLEX. + std::vector&)>> exteriorDrawCalls; + + + public: + /*-----------------------------------------------------------------------*/ + /* CTORS AND DTORS */ + /*-----------------------------------------------------------------------*/ + SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* ptrToResources) noexcept; + SHSubpass(SHSubpass&& rhs) noexcept; + SHSubpass& operator=(SHSubpass&& rhs) noexcept; + + /*-----------------------------------------------------------------------*/ + /* PUBLIC MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + // Preparation functions + void AddColorOutput(std::string resourceToReference) noexcept; + void AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE attachmentDescriptionType = SH_ATT_DESC_TYPE::DEPTH_STENCIL) noexcept; + void AddInput(std::string resourceToReference) noexcept; + + // Runtime functions + void Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; + void AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept; + + void Init(ResourceManager& resourceManager) noexcept; + + /*-----------------------------------------------------------------------*/ + /* GETTERS AND SETTERS */ + /*-----------------------------------------------------------------------*/ + Handle const& GetParentNode(void) const noexcept; + SHSubPassIndex GetIndex() const noexcept; + Handle GetSuperBatch(void) const noexcept; + + + friend class SHRenderGraphNode; + friend class SHRenderGraph; + }; +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp new file mode 100644 index 00000000..ccd0e6c3 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp @@ -0,0 +1,23 @@ +#include "SHpch.h" +#include "SHSubpassCompute.h" +#include "Graphics/Pipeline/SHVkPipeline.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/Descriptors/SHVkDescriptorPool.h" + +namespace SHADE +{ + SHSubpassCompute::SHSubpassCompute(Handle inPipeline, Handle descPool) noexcept + : pipeline {inPipeline} + { + // Get the descriptor set layouts required to allocate. we will bind a different pipeline layout, one that includes the layout for global. + auto const& layouts = pipeline->GetPipelineLayout()->GetDescriptorSetLayoutsAllocate(); + + // Variable counts for the descriptor sets (all should be 1). + std::vector variableCounts{static_cast(layouts.size())}; + std::fill (variableCounts.begin(), variableCounts.end(), 0); + + // Allocate descriptor sets to hold the images for reading (STORAGE_IMAGE) + descPool->Allocate(layouts, variableCounts); + } + +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h new file mode 100644 index 00000000..3ebc5676 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +namespace SHADE +{ + class SHVkPipeline; + class SHVkDescriptorSetGroup; + class SHVkDescriptorPool; + + class SHSubpassCompute + { + private: + //! To run the dispatch command + Handle pipeline; + + //! Descriptor set group + Handle descSetGroup; + + public: + SHSubpassCompute (Handle inPipeline, Handle descPool) noexcept; + + }; +} + diff --git a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.cpp b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.cpp index 29de5954..fee23f13 100644 --- a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.cpp +++ b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.cpp @@ -30,7 +30,10 @@ namespace SHADE SHVkRenderpass::SHVkRenderpass(Handle const& inLogicalDeviceHdl, std::span const vkDescriptions, std::vector const& subpasses) noexcept : logicalDeviceHdl {inLogicalDeviceHdl} , numAttDescs {static_cast(vkDescriptions.size())} + , vkSubpassDescriptions{} + , vkSubpassDeps{} , clearColors{} + , vkAttachmentDescriptions{} { for (uint32_t i = 0; i < vkDescriptions.size(); ++i) { @@ -42,7 +45,6 @@ namespace SHADE vk::RenderPassCreateInfo renderPassCreateInfo{}; - std::vector subpassDeps; // For validating the depth ref auto isValidDepthRef = [&](vk::AttachmentReference const& depthRef) -> bool @@ -50,13 +52,16 @@ namespace SHADE return !(depthRef.attachment == static_cast (-1) && depthRef.layout == vk::ImageLayout::eUndefined); }; + for (uint32_t i = 0; i < vkDescriptions.size(); ++i) + vkAttachmentDescriptions[i] = vkDescriptions[i]; + uint32_t subpassIndex = 0; if (!subpasses.empty()) { for (auto& subpass : subpasses) { - subpassDescriptions.emplace_back(); - auto& spDesc = subpassDescriptions.back(); + vkSubpassDescriptions.emplace_back(); + auto& spDesc = vkSubpassDescriptions.back(); spDesc.pColorAttachments = subpass.colorRefs.data(); spDesc.colorAttachmentCount = static_cast(subpass.colorRefs.size()); @@ -88,18 +93,18 @@ namespace SHADE }; // Push a new dependency - subpassDeps.push_back(dependency); + vkSubpassDeps.push_back(dependency); ++subpassIndex; } // Renderpass create info for render pass creation - renderPassCreateInfo.attachmentCount = static_cast(vkDescriptions.size()); - renderPassCreateInfo.pAttachments = vkDescriptions.data(); - renderPassCreateInfo.subpassCount = static_cast(subpassDescriptions.size()); - renderPassCreateInfo.pSubpasses = subpassDescriptions.data(); - renderPassCreateInfo.dependencyCount = static_cast(subpassDeps.size()); - renderPassCreateInfo.pDependencies = subpassDeps.data(); + renderPassCreateInfo.attachmentCount = static_cast(vkAttachmentDescriptions.size()); + renderPassCreateInfo.pAttachments = vkAttachmentDescriptions.data(); + renderPassCreateInfo.subpassCount = static_cast(vkSubpassDescriptions.size()); + renderPassCreateInfo.pSubpasses = vkSubpassDescriptions.data(); + renderPassCreateInfo.dependencyCount = static_cast(vkSubpassDeps.size()); + renderPassCreateInfo.pDependencies = vkSubpassDeps.data(); } // No subpasses passed in, create a default one. @@ -172,6 +177,8 @@ namespace SHADE : logicalDeviceHdl{ inLogicalDeviceHdl } , numAttDescs{ static_cast(vkDescriptions.size()) } , clearColors{} + , vkSubpassDescriptions{ } + , vkSubpassDeps{ } { for (uint32_t i = 0; i < vkDescriptions.size(); ++i) { @@ -181,18 +188,24 @@ namespace SHADE clearColors[i].color = { {{0.0f, 0.0f, 0.0f, 1.0f}} }; } - subpassDescriptions.resize (spDescs.size()); - for (uint32_t i = 0; i < subpassDescriptions.size(); ++i) - { - subpassDescriptions[i] = spDescs[i]; - } + vkAttachmentDescriptions.resize(vkDescriptions.size()); + for (uint32_t i = 0; i < vkDescriptions.size(); ++i) + vkAttachmentDescriptions[i] = vkDescriptions[i]; + + vkSubpassDescriptions.resize (spDescs.size()); + for (uint32_t i = 0; i < vkSubpassDescriptions.size(); ++i) + vkSubpassDescriptions[i] = spDescs[i]; + + vkSubpassDeps.resize(spDeps.size()); + for (uint32_t i = 0; i < vkSubpassDeps.size(); ++i) + vkSubpassDeps[i] = spDeps[i]; vk::RenderPassCreateInfo renderPassCreateInfo{}; renderPassCreateInfo.attachmentCount = static_cast(vkDescriptions.size()); renderPassCreateInfo.pAttachments = vkDescriptions.data(); - renderPassCreateInfo.subpassCount = static_cast(subpassDescriptions.size()); - renderPassCreateInfo.pSubpasses = subpassDescriptions.data(); + renderPassCreateInfo.subpassCount = static_cast(vkSubpassDescriptions.size()); + renderPassCreateInfo.pSubpasses = vkSubpassDescriptions.data(); renderPassCreateInfo.dependencyCount = static_cast(spDeps.size()); renderPassCreateInfo.pDependencies = spDeps.data(); @@ -210,8 +223,11 @@ namespace SHADE SHVkRenderpass::SHVkRenderpass(SHVkRenderpass&& rhs) noexcept : vkRenderpass {rhs.vkRenderpass} , logicalDeviceHdl {rhs.logicalDeviceHdl} - , subpassDescriptions {std::move (rhs.subpassDescriptions)} - , clearColors {std::move (rhs.clearColors)} + , vkSubpassDescriptions{ std::move(rhs.vkSubpassDescriptions) } + , vkSubpassDeps{ std::move(rhs.vkSubpassDeps) } + , clearColors{ std::move(rhs.clearColors) } + , vkAttachmentDescriptions{ std::move(rhs.vkAttachmentDescriptions) } + , numAttDescs{rhs.numAttDescs} { rhs.vkRenderpass = VK_NULL_HANDLE; } @@ -224,8 +240,11 @@ namespace SHADE vkRenderpass = rhs.vkRenderpass; logicalDeviceHdl = rhs.logicalDeviceHdl; - subpassDescriptions = std::move(rhs.subpassDescriptions); + vkSubpassDescriptions = std::move(rhs.vkSubpassDescriptions); + vkSubpassDeps = std::move(rhs.vkSubpassDeps); clearColors = std::move(rhs.clearColors); + vkAttachmentDescriptions = std::move(rhs.vkAttachmentDescriptions); + numAttDescs = std::move(rhs.numAttDescs); rhs.vkRenderpass = VK_NULL_HANDLE; @@ -238,6 +257,31 @@ namespace SHADE } + void SHVkRenderpass::HandleResize(void) noexcept + { + logicalDeviceHdl->GetVkLogicalDevice().destroyRenderPass(vkRenderpass, nullptr); + + vk::RenderPassCreateInfo renderPassCreateInfo{}; + + renderPassCreateInfo.attachmentCount = static_cast(vkAttachmentDescriptions.size()); + renderPassCreateInfo.pAttachments = vkAttachmentDescriptions.data(); + renderPassCreateInfo.subpassCount = static_cast(vkSubpassDescriptions.size()); + renderPassCreateInfo.pSubpasses = vkSubpassDescriptions.data(); + renderPassCreateInfo.dependencyCount = static_cast(vkSubpassDeps.size()); + renderPassCreateInfo.pDependencies = vkSubpassDeps.data(); + + + if (auto result = logicalDeviceHdl->GetVkLogicalDevice().createRenderPass(&renderPassCreateInfo, nullptr, &vkRenderpass); result != vk::Result::eSuccess) + { + SHVulkanDebugUtil::ReportVkError(result, "Failed to create Renderpass. "); + } + else + { + SHVulkanDebugUtil::ReportVkSuccess("Successfully created Renderpass. "); + } + + } + vk::RenderPass SHVkRenderpass::GetVkRenderpass(void) const noexcept { return vkRenderpass; diff --git a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h index afed0736..70a04bbf 100644 --- a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h +++ b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h @@ -10,10 +10,6 @@ namespace SHADE { class SHVkLogicalDevice; class SHVkFramebuffer; - /*-----------------------------------------------------------------------*/ - /* TYPE DEFINTIIONS */ - /*-----------------------------------------------------------------------*/ - using SHSubPassIndex = uint32_t; class SHVkRenderpass { @@ -33,7 +29,13 @@ namespace SHADE Handle logicalDeviceHdl; //! Container of subpass information used to construct subpasses - std::vector subpassDescriptions; + std::vector vkSubpassDescriptions; + + //! Container of subpass dependencies used to create renderpass + std::vector vkSubpassDeps; + + //! Attachment descriptions + std::vector vkAttachmentDescriptions; //! Clear colors for the color and depth std::array clearColors; @@ -53,6 +55,8 @@ namespace SHADE SHVkRenderpass(SHVkRenderpass&& rhs) noexcept; SHVkRenderpass& operator=(SHVkRenderpass&& rhs) noexcept; + void HandleResize (void) noexcept; + /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/SHVulkanDefines.h b/SHADE_Engine/src/Graphics/SHVulkanDefines.h index 2f625f7e..1cbcae0f 100644 --- a/SHADE_Engine/src/Graphics/SHVulkanDefines.h +++ b/SHADE_Engine/src/Graphics/SHVulkanDefines.h @@ -5,9 +5,13 @@ namespace SHADE { + /*-----------------------------------------------------------------------*/ + /* TYPE DEFINTIIONS */ + /*-----------------------------------------------------------------------*/ using SHQueueFamilyIndex = uint32_t; using BindingAndSetHash = uint64_t; using SetIndex = uint32_t; + using SHSubPassIndex = uint32_t; } diff --git a/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.cpp b/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.cpp index 7ed50c59..75ede865 100644 --- a/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.cpp +++ b/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.cpp @@ -27,7 +27,7 @@ namespace SHADE SHADE::SHShaderBlockInterface::Variable const* const SHShaderBlockInterface::GetVariable(uint32_t index) const noexcept { - if (variableIndexing.size() < index) + if (index < variableIndexing.size()) return &variables.at(index); return nullptr; diff --git a/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h b/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h index ee7e7726..e546b452 100644 --- a/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h +++ b/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h @@ -2,10 +2,12 @@ #include +#include "SH_API.h" + namespace SHADE { - class SHShaderBlockInterface + class SH_API SHShaderBlockInterface { public: struct Variable diff --git a/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp b/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp index 1e5fb074..41327988 100644 --- a/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp +++ b/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp @@ -111,6 +111,7 @@ namespace SHADE biggestAlignment = std::max(biggestAlignment, 4u); break; case SpvOp::SpvOpTypeStruct: + case SpvOp::SpvOpTypeRuntimeArray: recurseForInfo(&member, interfaceHdl, member.offset, biggestAlignment, parentVarName + std::string(member.name) + "."); break; } diff --git a/SHADE_Engine/src/Graphics/Windowing/SHWindow.cpp b/SHADE_Engine/src/Graphics/Windowing/SHWindow.cpp index 4d8dae72..44a1cb0e 100644 --- a/SHADE_Engine/src/Graphics/Windowing/SHWindow.cpp +++ b/SHADE_Engine/src/Graphics/Windowing/SHWindow.cpp @@ -2,7 +2,7 @@ #include "SHWindowMap.h" #include "SHWindow.h" #include "ECS_Base/Managers/SHSystemManager.h" -#include "Input/SHInputManagerSystem.h" +#include "Input/SHInputManager.h" namespace SHADE @@ -272,6 +272,17 @@ namespace SHADE windowResizeCallbacks.erase(callbackid); } + SHWindow::CALLBACKID SHWindow::RegisterWindowCloseCallback(WindowCloseCallbackFn windowCloseCallback) + { + windowCloseCallbacks.try_emplace(windowResizeCallbackCount, windowCloseCallback); + return windowCloseCallbackCount++; + } + + void SHWindow::UnregisterWindowCloseCallback(CALLBACKID const& callbackid) + { + windowCloseCallbacks.erase(callbackid); + } + LRESULT SHWindow::WndProcStatic(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { auto window = windowMap.GetWindow(hwnd); @@ -307,6 +318,8 @@ namespace SHADE case WM_CREATE: OnCreate(hwnd, reinterpret_cast(wparam)); break; + case WM_CLOSE: + case WM_DESTROY: OnDestroy(); return 0; @@ -343,10 +356,7 @@ namespace SHADE } case WM_MOUSEWHEEL: { - if (auto im = SHSystemManager::GetSystem()) - { - im->PollWheelVerticalDelta(wparam); - } + SHInputManager::PollWheelVerticalDelta(wparam); break; } default: @@ -365,8 +375,17 @@ namespace SHADE } + void SHADE::SHWindow::OnClose() + { + for (const auto& callbackFn : windowCloseCallbacks | std::views::values) + { + callbackFn(); + } + } + void SHWindow::OnDestroy() { + OnClose(); this->Destroy(); } @@ -378,6 +397,14 @@ namespace SHADE { wndData.width = static_cast(size.cx); wndData.height = static_cast(size.cy); + + if (type == SIZE_MINIMIZED) + { + wndData.isMinimised = true; + } + else + wndData.isMinimised = false; + for (auto const& entry : windowResizeCallbacks) { entry.second(static_cast(wndData.width), static_cast(wndData.height)); diff --git a/SHADE_Engine/src/Graphics/Windowing/SHWindow.h b/SHADE_Engine/src/Graphics/Windowing/SHWindow.h index 1e08dcb0..0a180285 100644 --- a/SHADE_Engine/src/Graphics/Windowing/SHWindow.h +++ b/SHADE_Engine/src/Graphics/Windowing/SHWindow.h @@ -18,7 +18,7 @@ namespace SHADE }; struct WindowData - { + { unsigned x = 0; unsigned y = 0; @@ -42,7 +42,7 @@ namespace SHADE bool closable = true; bool minimizable = true; - + bool maximizable = true; //bool canFullscreen = true; @@ -56,11 +56,13 @@ namespace SHADE bool shadowEnabled = true; bool isVisible = true; - + bool isFullscreen = false; bool modal = false; + bool isMinimised = false; + std::wstring title = L"SHADE ENGINE"; std::wstring name = L"SHADEEngineApp"; @@ -73,6 +75,7 @@ namespace SHADE public: using SHVec2 = std::pair; typedef std::function WindowResizeCallbackFn; + typedef std::function WindowCloseCallbackFn; typedef uint16_t CALLBACKID; SHWindow(); @@ -103,7 +106,7 @@ namespace SHADE void SetMousePosition(unsigned x, unsigned y); //unsigned GetBGColor(); - + void SetBGColor(unsigned color); void Minimize(); @@ -123,6 +126,9 @@ namespace SHADE CALLBACKID RegisterWindowSizeCallback(WindowResizeCallbackFn); void UnregisterWindowSizeCallback(CALLBACKID const& callbackid); + CALLBACKID RegisterWindowCloseCallback(WindowCloseCallbackFn); + void UnregisterWindowCloseCallback(CALLBACKID const& callbackid); + bool IsMinimized() const { return wndData.isMinimised; } protected: static LRESULT CALLBACK WndProcStatic(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); @@ -154,10 +160,13 @@ namespace SHADE HFONT font; std::unordered_map windowResizeCallbacks; + std::unordered_map windowCloseCallbacks; CALLBACKID windowResizeCallbackCount{}; + CALLBACKID windowCloseCallbackCount{}; //TODO: Shift to events abstraction void OnCreate(HWND hwnd, LPCREATESTRUCT create_struct); + void OnClose(); void OnDestroy(); //void OnFileDrop(HDROP drop); void OnSize(UINT msg, UINT type, SIZE size); diff --git a/SHADE_Engine/src/Input/SHInputManagerSystem.cpp b/SHADE_Engine/src/Input/SHInputManager.cpp similarity index 60% rename from SHADE_Engine/src/Input/SHInputManagerSystem.cpp rename to SHADE_Engine/src/Input/SHInputManager.cpp index 1beabe3f..04f2b02e 100644 --- a/SHADE_Engine/src/Input/SHInputManagerSystem.cpp +++ b/SHADE_Engine/src/Input/SHInputManager.cpp @@ -1,5 +1,5 @@ /********************************************************************* - * \file SHInputManagerSystem.cpp + * \file SHInputManager.cpp * \author Ryan Wang Nian Jing * \brief Definition of input manager. * Handles input from keyboard and mouse. Soon to include controller. @@ -11,7 +11,8 @@ #pragma once #include -#include "SHInputManagerSystem.h" +#include "SHInputManager.h" +#include "../Tools/SHException.h" namespace SHADE { @@ -19,61 +20,34 @@ namespace SHADE /* Static defines */ /*------------------------------------------------------------------------*/ - unsigned SHInputManagerSystem::keyCount = 0; - bool SHInputManagerSystem::keys[MAX_KEYS]; - bool SHInputManagerSystem::keysLast[MAX_KEYS]; - double SHInputManagerSystem::keysHeldTime[MAX_KEYS]; - double SHInputManagerSystem::keysReleasedTime[MAX_KEYS]; + unsigned SHInputManager::keyCount = 0; + bool SHInputManager::keys[MAX_KEYS]; + bool SHInputManager::keysLast[MAX_KEYS]; + double SHInputManager::keysHeldTime[MAX_KEYS]; + double SHInputManager::keysReleasedTime[MAX_KEYS]; - unsigned SHInputManagerSystem::keyToggleCount = 0; - bool SHInputManagerSystem::keysToggle[MAX_KEYS]; - bool SHInputManagerSystem::keysToggleLast[MAX_KEYS]; - double SHInputManagerSystem::keysToggleOnTime[MAX_KEYS]; - double SHInputManagerSystem::keysToggleOffTime[MAX_KEYS]; + unsigned SHInputManager::keyToggleCount = 0; + bool SHInputManager::keysToggle[MAX_KEYS]; + bool SHInputManager::keysToggleLast[MAX_KEYS]; + double SHInputManager::keysToggleOnTime[MAX_KEYS]; + double SHInputManager::keysToggleOffTime[MAX_KEYS]; - int SHInputManagerSystem::mouseScreenX = 0; - int SHInputManagerSystem::mouseScreenY = 0; - int SHInputManagerSystem::mouseScreenXLast = 0; - int SHInputManagerSystem::mouseScreenYLast = 0; - double SHInputManagerSystem::mouseVelocityX = 0; - double SHInputManagerSystem::mouseVelocityY = 0; - int SHInputManagerSystem::mouseWheelVerticalDelta = 0; - int SHInputManagerSystem::mouseWheelVerticalDeltaPoll = 0; + int SHInputManager::mouseScreenX = 0; + int SHInputManager::mouseScreenY = 0; + int SHInputManager::mouseScreenXLast = 0; + int SHInputManager::mouseScreenYLast = 0; + double SHInputManager::mouseVelocityX = 0; + double SHInputManager::mouseVelocityY = 0; + int SHInputManager::mouseWheelVerticalDelta = 0; + int SHInputManager::mouseWheelVerticalDeltaPoll = 0; - void SHInputManagerSystem::Init() - { - keyCount = 0; - SecureZeroMemory(keys, sizeof(keys)); - SecureZeroMemory(keysLast, sizeof(keysLast)); - SecureZeroMemory(keysHeldTime, sizeof(keysHeldTime)); - SecureZeroMemory(keysReleasedTime, sizeof(keysReleasedTime)); - - keyToggleCount = 0; - SecureZeroMemory(keysToggle, sizeof(keysToggle)); - SecureZeroMemory(keysToggleLast, sizeof(keysToggleLast)); - SecureZeroMemory(keysToggleOnTime, sizeof(keysToggleOnTime)); - SecureZeroMemory(keysToggleOffTime, sizeof(keysToggleOffTime)); - - mouseScreenX = 0; - mouseScreenY = 0; - mouseScreenXLast = 0; - mouseScreenYLast = 0; - mouseWheelVerticalDelta = 0; - mouseWheelVerticalDeltaPoll = 0; - } - - void SHInputManagerSystem::Exit() - { - //No dynamically allocated memory. Nothing to do here. - } - - void SHInputManagerSystem::InputManagerRoutine:: - FixedExecute(double dt) noexcept + void SHInputManager::UpdateInput(double dt) noexcept { //Keyboard and Mouse Buttons//////////////////////////////////////////////// //Poll unsigned char keyboardState[MAX_KEYS]; - GetKeyboardState(keyboardState); + //if (GetKeyboardState(keyboardState) == false) return; + SHASSERT(GetKeyboardState(keyboardState), "SHInputManager:GetKeyboardState() failed ({})", GetLastError()); keyCount = 0; keyToggleCount = 0; for (size_t i = 0; i < MAX_KEYS; ++i) @@ -138,13 +112,17 @@ namespace SHADE mouseScreenX = p.x; mouseScreenY = p.y; + //Velocity + mouseVelocityX = static_cast(mouseScreenX - mouseScreenXLast) / dt; + mouseVelocityY = static_cast(mouseScreenY - mouseScreenYLast) / dt; + //Mouse wheel vertical delta updating mouseWheelVerticalDelta = 0; mouseWheelVerticalDelta = mouseWheelVerticalDeltaPoll; mouseWheelVerticalDeltaPoll = 0; } - bool SHInputManagerSystem::AnyKeyDown(SH_KEYCODE* firstDetected) noexcept + bool SHInputManager::AnyKeyDown(SH_KEYCODE* firstDetected) noexcept { for (size_t i = 0; i < MAX_KEYS; ++i) { @@ -157,7 +135,7 @@ namespace SHADE return false; } - bool SHInputManagerSystem::AnyKey(SH_KEYCODE* firstDetected) noexcept + bool SHInputManager::AnyKey(SH_KEYCODE* firstDetected) noexcept { for (size_t i = 0; i < MAX_KEYS; ++i) { @@ -170,7 +148,7 @@ namespace SHADE return false; } - bool SHInputManagerSystem::AnyKeyUp(SH_KEYCODE* firstDetected) noexcept + bool SHInputManager::AnyKeyUp(SH_KEYCODE* firstDetected) noexcept { for (size_t i = 0; i < MAX_KEYS; ++i) { diff --git a/SHADE_Engine/src/Input/SHInputManagerSystem.h b/SHADE_Engine/src/Input/SHInputManager.h similarity index 93% rename from SHADE_Engine/src/Input/SHInputManagerSystem.h rename to SHADE_Engine/src/Input/SHInputManager.h index eb40b240..d3e31004 100644 --- a/SHADE_Engine/src/Input/SHInputManagerSystem.h +++ b/SHADE_Engine/src/Input/SHInputManager.h @@ -1,5 +1,5 @@ /********************************************************************* - * \file SHInputManagerSystem.h + * \file SHInputManager.h * \author Ryan Wang Nian Jing * \brief Declaration of input manager. * Handles input from keyboard and mouse. Soon to include controller. @@ -13,19 +13,12 @@ //#include //#include "../../SHADE_Managed/src/SHpch.h" #include "SH_API.h" -#include "ECS_Base/System/SHSystem.h" -#include "ECS_Base/System/SHFixedSystemRoutine.h" namespace SHADE { - class SH_API SHInputManagerSystem : public SHSystem + class SH_API SHInputManager { public: - class SH_API InputManagerRoutine : public SHFixedSystemRoutine - { - public: - virtual void FixedExecute(double dt) noexcept override final; - }; public: /*------------------------------------------------------------------------*/ @@ -276,23 +269,21 @@ namespace SHADE }; public: + //Updates current state of the input, with dt to be fetched from FRC + //TODO should dt be fixed or variable? + static void UpdateInput(double dt) noexcept; + /*------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*------------------------------------------------------------------------*/ - SHInputManagerSystem() noexcept = default; - ~SHInputManagerSystem() noexcept = default; + SHInputManager() noexcept = default; + ~SHInputManager() noexcept = default; - SHInputManagerSystem(const SHInputManagerSystem&) = delete; - SHInputManagerSystem(SHInputManagerSystem&&) = delete; + SHInputManager(const SHInputManager&) = delete; + SHInputManager(SHInputManager&&) = delete; - SHInputManagerSystem& operator= (const SHInputManagerSystem&) = delete; - SHInputManagerSystem& operator= (SHInputManagerSystem&&) = delete; - - /*------------------------------------------------------------------------*/ - /* SHSystem Overrides */ - /*------------------------------------------------------------------------*/ - virtual void Init() override final; - virtual void Exit() override final; + SHInputManager& operator= (const SHInputManager&) = delete; + SHInputManager& operator= (SHInputManager&&) = delete; /*------------------------------------------------------------------------*/ /* Member Functions */ @@ -417,8 +408,8 @@ namespace SHADE { POINT p{ mouseScreenX, mouseScreenY }; ScreenToClient(GetActiveWindow(), &p); - if (x) *x = mouseScreenX; - if (y) *y = mouseScreenY; + if (x) *x = p.x; + if (y) *y = p.y; } //Get the mouse velocity diff --git a/SHADE_Engine/src/Math/Geometry/SHBoundingBox.cpp b/SHADE_Engine/src/Math/Geometry/SHBoundingBox.cpp index 44f01a4b..3abcc315 100644 --- a/SHADE_Engine/src/Math/Geometry/SHBoundingBox.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHBoundingBox.cpp @@ -21,7 +21,7 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHBoundingBox::SHBoundingBox(const SHVec3& c, SHVec3& hE) noexcept + SHBoundingBox::SHBoundingBox(const SHVec3& c, const SHVec3& hE) noexcept : SHShape {} , center { c } , halfExtents { hE } diff --git a/SHADE_Engine/src/Math/Geometry/SHBoundingBox.h b/SHADE_Engine/src/Math/Geometry/SHBoundingBox.h index b60c6c29..a89c5965 100644 --- a/SHADE_Engine/src/Math/Geometry/SHBoundingBox.h +++ b/SHADE_Engine/src/Math/Geometry/SHBoundingBox.h @@ -10,6 +10,8 @@ #pragma once +#include + // Project Headers #include "SHShape.h" #include "SH_API.h" @@ -20,6 +22,7 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ + // TODO(Diren): Use DirectX BoundingBox instead of custom class SH_API SHBoundingBox : public SHShape { public: @@ -27,15 +30,15 @@ namespace SHADE /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHBoundingBox (const SHVec3& center, SHVec3& halfExtents) noexcept; - SHBoundingBox (const SHVec3* vertices, size_t numVertices) noexcept; - SHBoundingBox (const SHBoundingBox* boxes, size_t numBoxes) noexcept; + SHBoundingBox (const SHVec3& center, const SHVec3& halfExtents) noexcept; + SHBoundingBox (const SHVec3* vertices, size_t numVertices) noexcept; + SHBoundingBox (const SHBoundingBox* boxes, size_t numBoxes) noexcept; - SHBoundingBox (const SHBoundingBox& rhs) noexcept; - SHBoundingBox (SHBoundingBox&& rhs) noexcept; + SHBoundingBox (const SHBoundingBox& rhs) noexcept; + SHBoundingBox (SHBoundingBox&& rhs) noexcept; - SHBoundingBox& operator= (const SHBoundingBox& rhs) noexcept; - SHBoundingBox& operator= (SHBoundingBox&& rhs) noexcept; + SHBoundingBox& operator= (const SHBoundingBox& rhs) noexcept; + SHBoundingBox& operator= (SHBoundingBox&& rhs) noexcept; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ diff --git a/SHADE_Engine/src/Math/Geometry/SHShape.cpp b/SHADE_Engine/src/Math/Geometry/SHShape.cpp index 02aaff58..3fc5775d 100644 --- a/SHADE_Engine/src/Math/Geometry/SHShape.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHShape.cpp @@ -23,4 +23,14 @@ namespace SHADE : type { Type::NONE } {} + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHShape::Type SHShape::GetType() const + { + return type; + } + + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHShape.h b/SHADE_Engine/src/Math/Geometry/SHShape.h index 84b7bbe7..e33ca583 100644 --- a/SHADE_Engine/src/Math/Geometry/SHShape.h +++ b/SHADE_Engine/src/Math/Geometry/SHShape.h @@ -30,7 +30,9 @@ namespace SHADE enum class Type { BOUNDING_BOX - , RAY + , SPHERE + , CAPSULE + , CONVEX_HULL , TRIANGLE , COUNT diff --git a/SHADE_Engine/src/Math/SHMathHelpers.hpp b/SHADE_Engine/src/Math/SHMathHelpers.hpp index 0e5fc5fa..cdbe1643 100644 --- a/SHADE_Engine/src/Math/SHMathHelpers.hpp +++ b/SHADE_Engine/src/Math/SHMathHelpers.hpp @@ -103,6 +103,9 @@ namespace SHADE template T SHMath::GenerateRandomNumber(T lowerBound, T upperBound) { + if (lowerBound > upperBound) + std::swap(lowerBound, upperBound); + if constexpr (IsIntegral) { std::uniform_int_distribution distribution(lowerBound, upperBound); @@ -120,7 +123,7 @@ namespace SHADE bool SHMath::CompareFloat(T lhs, T rhs, T absTolerance, T relTolerance) { const T RTOL = relTolerance * Max(std::fabs(lhs), std::fabs(rhs)); - return std::fabs(lhs - rhs) <= MAX(absTolerance, RTOL); + return std::fabs(lhs - rhs) <= Max(absTolerance, RTOL); } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/SHQuaternion.cpp b/SHADE_Engine/src/Math/SHQuaternion.cpp index 36921f3f..a6428d30 100644 --- a/SHADE_Engine/src/Math/SHQuaternion.cpp +++ b/SHADE_Engine/src/Math/SHQuaternion.cpp @@ -15,6 +15,7 @@ // Project Headers #include "Vector/SHVec3.h" #include "SHMatrix.h" +#include "SHMathHelpers.h" #include "Tools/SHLogger.h" using namespace DirectX; @@ -249,9 +250,30 @@ namespace SHADE SHVec3 SHQuaternion::ToEuler() const noexcept { - // TODO (Diren) + const float xx = x * x; + const float yy = y * y; + const float zz = z * z; - return SHVec3::Zero; + const float m31 = 2.f * x * z + 2.f * y * w; + const float m32 = 2.f * y * z - 2.f * x * w; + const float m33 = 1.f - 2.f * xx - 2.f * yy; + + const float cy = sqrtf(m33 * m33 + m31 * m31); + const float cx = atan2f(-m32, cy); + if (cy > 16.0f * SHMath::EPSILON) + { + const float m12 = 2.f * x * y + 2.f * z * w; + const float m22 = 1.f - 2.f * xx - 2.f * zz; + + return SHVec3(cx, atan2f(m31, m33), atan2f(m12, m22)); + } + else + { + const float m11 = 1.f - 2.f * yy - 2.f * zz; + const float m21 = 2.f * x * y - 2.f * z * w; + + return SHVec3(cx, 0.f, atan2f(-m21, m11)); + } } std::string SHQuaternion::ToString() const noexcept diff --git a/SHADE_Engine/src/Math/Transform/SHTransform.h b/SHADE_Engine/src/Math/Transform/SHTransform.h index 9edd7fdd..c1a0e565 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransform.h +++ b/SHADE_Engine/src/Math/Transform/SHTransform.h @@ -12,7 +12,9 @@ // Project Headers #include "SH_API.h" -#include "Math/SHMath.h" +#include "Math/Vector/SHVec2.h" +#include "Math/Vector/SHVec3.h" +#include "Math/SHMatrix.h" namespace SHADE { diff --git a/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp b/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp index b14e97d6..949cfa67 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp +++ b/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp @@ -24,43 +24,6 @@ namespace SHADE , dirty { true } {} - SHTransformComponent::SHTransformComponent(const SHTransformComponent& rhs) noexcept - : SHComponent {} - , dirty { true } - , local { rhs.local } - , world { rhs.world } - {} - - SHTransformComponent::SHTransformComponent(SHTransformComponent&& rhs) noexcept - : SHComponent {} - , dirty { true } - , local { std::move(rhs.local) } - , world { std::move(rhs.world) } - {} - - /*-----------------------------------------------------------------------------------*/ - /* Operator Overload Definitions */ - /*-----------------------------------------------------------------------------------*/ - - SHTransformComponent& SHTransformComponent::operator=(const SHTransformComponent& rhs) noexcept - { - dirty = true; - local = rhs.local; - world = rhs.world; - - return *this; - } - - SHTransformComponent& SHTransformComponent::operator=(SHTransformComponent&& rhs) noexcept - { - dirty = true; - local = std::move(rhs.local); - world = std::move(rhs.world); - - return *this; - } - - /*-----------------------------------------------------------------------------------*/ /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -189,7 +152,7 @@ RTTR_REGISTRATION using namespace rttr; registration::class_("Transform Component") - .property("Translate", &SHTransformComponent::GetLocalPosition, &SHTransformComponent::SetLocalPosition) - .property("Rotate", &SHTransformComponent::GetLocalRotation, select_overload(&SHTransformComponent::SetLocalRotation)) - .property("Scale", &SHTransformComponent::GetLocalScale, &SHTransformComponent::SetLocalScale); + .property("Translate" , &SHTransformComponent::GetLocalPosition , &SHTransformComponent::SetLocalPosition ) + .property("Rotate" , &SHTransformComponent::GetLocalRotation , select_overload(&SHTransformComponent::SetLocalRotation) ) + .property("Scale" , &SHTransformComponent::GetLocalScale , &SHTransformComponent::SetLocalScale ); } \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Transform/SHTransformComponent.h b/SHADE_Engine/src/Math/Transform/SHTransformComponent.h index 9f20de85..ad355694 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransformComponent.h +++ b/SHADE_Engine/src/Math/Transform/SHTransformComponent.h @@ -13,6 +13,7 @@ #include #include + // Project Headers #include "SH_API.h" #include "ECS_Base/Components/SHComponent.h" @@ -41,15 +42,15 @@ namespace SHADE ~SHTransformComponent () override = default; SHTransformComponent () noexcept; - SHTransformComponent (const SHTransformComponent& rhs) noexcept; - SHTransformComponent (SHTransformComponent&& rhs) noexcept; + SHTransformComponent (const SHTransformComponent& rhs) noexcept = default; + SHTransformComponent (SHTransformComponent&& rhs) noexcept = default; /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ /*---------------------------------------------------------------------------------*/ - SHTransformComponent& operator=(const SHTransformComponent& rhs) noexcept; - SHTransformComponent& operator=(SHTransformComponent&& rhs) noexcept; + SHTransformComponent& operator=(const SHTransformComponent& rhs) noexcept = default; + SHTransformComponent& operator=(SHTransformComponent&& rhs) noexcept = default; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ diff --git a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp index f698bd41..6b05e323 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp +++ b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp @@ -47,7 +47,7 @@ namespace SHADE void SHTransformSystem::Init() { - + } void SHTransformSystem::Exit() diff --git a/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp b/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp new file mode 100644 index 00000000..73e7ccbd --- /dev/null +++ b/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp @@ -0,0 +1,149 @@ +/**************************************************************************************** + * \file SHColliderComponent.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Collider Component. + * + * \copyright 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 + +// Primary Header +#include "SHColliderComponent.h" + +// Project Headers +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Physics/SHPhysicsSystem.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHColliderComponent::SHColliderComponent() noexcept + : system { nullptr } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + + const SHVec3& SHColliderComponent::GetPosition() const noexcept + { + return position; + } + + const SHQuaternion& SHColliderComponent::GetOrientation() const noexcept + { + return orientation; + } + + SHVec3 SHColliderComponent::GetRotation() const noexcept + { + return orientation.ToEuler(); + } + + const SHColliderComponent::Colliders& SHColliderComponent::GetColliders() const noexcept + { + return colliders; + } + + SHCollider& SHColliderComponent::GetCollider(int index) + { + if (index < 0 || static_cast(index) >= colliders.size()) + throw std::invalid_argument("Out-of-range access!"); + + return colliders[index].first; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHColliderComponent::OnCreate() + { + system = SHSystemManager::GetSystem(); + if (!system) + { + SHLOG_ERROR("Physics system does not exist, Collider Component not added!") + return; + } + + system->AddCollider(GetEID()); + } + + void SHColliderComponent::OnDestroy() + { + if (!system) + { + SHLOG_ERROR("Physics system does not exist, unable to remove Collider component!") + return; + } + + system->RemoveCollider(GetEID()); + } + + SHBoundingBox* SHColliderComponent::AddBoundingBox() noexcept + { + const auto TYPE = SHCollider::Type::BOX; + + const auto BOX_PAIR = std::make_pair(SHCollider{TYPE}, true); + auto& collider = colliders.emplace_back(BOX_PAIR).first; + + if (!system) + { + SHLOG_ERROR("Physics system does not exist, unable to add Box Collider!") + return nullptr; + } + + // Notify Physics System + system->AddCollisionShape(GetEID(), collider.GetShape()); + + return reinterpret_cast(collider.GetShape()); + } + + //void SHColliderComponent::AddSphere() noexcept + //{ + // const auto TYPE = SHCollider::Type::SPHERE; + + // if (!system) + // { + // SHLOG_ERROR("Physics system does not exist, unable to add Sphere Collider!") + // return; + // } + + // // Notify Physics System + //} + + void SHColliderComponent::RemoveCollider(int index) + { + if (index < 0 || static_cast(index) >= colliders.size()) + throw std::invalid_argument("Out-of-range access!"); + + int idx = 0; + auto it = colliders.begin(); + for (; it != colliders.end(); ++it) + { + if (idx == index) + break; + + ++idx; + } + + it = colliders.erase(it); + + // Notify Physics System + if (!system) + { + SHLOG_ERROR("Physics system does not exist, unable to remove Collider!") + return; + } + + system->RemoveCollisionShape(GetEID(), index); + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Components/SHColliderComponent.h b/SHADE_Engine/src/Physics/Components/SHColliderComponent.h new file mode 100644 index 00000000..cb9696d9 --- /dev/null +++ b/SHADE_Engine/src/Physics/Components/SHColliderComponent.h @@ -0,0 +1,96 @@ +/**************************************************************************************** + * \file SHColliderComponent.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Collider Component. + * + * \copyright 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 + +// Project Headers +#include "ECS_Base/Components/SHComponent.h" +#include "Physics/SHCollider.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SH_API SHColliderComponent : public SHComponent + { + private: + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHPhysicsSystem; + + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + using ColliderDirtyPair = std::pair; + using Colliders = std::vector; + + public: + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHColliderComponent () noexcept; + SHColliderComponent (const SHColliderComponent& rhs) noexcept = default; + SHColliderComponent (SHColliderComponent&& rhs) noexcept = default; + ~SHColliderComponent () override = default; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHColliderComponent& operator=(const SHColliderComponent& rhs) noexcept = default; + SHColliderComponent& operator=(SHColliderComponent&& rhs) noexcept = default; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] bool HasChanged () const noexcept; + + [[nodiscard]] const SHVec3& GetPosition () const noexcept; + [[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; + [[nodiscard]] SHVec3 GetRotation () const noexcept; + + [[nodiscard]] const Colliders& GetColliders () const noexcept; + [[nodiscard]] SHCollider& GetCollider (int index); + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + void OnCreate () override; + void OnDestroy () override; + + SHBoundingBox* AddBoundingBox () noexcept; + + void RemoveCollider (int index); + + private: + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + SHPhysicsSystem* system; + + SHVec3 position; + SHQuaternion orientation; + Colliders colliders; + + }; +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp new file mode 100644 index 00000000..5f961de4 --- /dev/null +++ b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp @@ -0,0 +1,413 @@ +/**************************************************************************************** + * \file SHRigidBodyComponent.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Rigidbody Component. + * + * \copyright 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 + +// Primary Header +#include "SHRigidBodyComponent.h" + +// Project Headers +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Physics/SHPhysicsSystem.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHRigidBodyComponent::SHRigidBodyComponent() noexcept + : type { Type::DYNAMIC } + , flags { 0 } + , dirtyFlags { 0 } + , interpolate { true } + , system { nullptr } + , mass { 1.0f } + , drag { 0.01f } + , angularDrag { 0.01f } + + { + // Set default flags: Gravity & Sleeping enabled + flags |= 1U << 0; + flags |= 1U << 1; + + // Set all dirty flags to true + dirtyFlags = 1023; + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHRigidBodyComponent::IsGravityEnabled() const noexcept + { + return flags & (1U << 0); + } + + bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept + { + return flags & (1U << 1); + } + + bool SHRigidBodyComponent::IsInterpolating() const noexcept + { + return interpolate; + } + + SHRigidBodyComponent::Type SHRigidBodyComponent::GetType() const noexcept + { + return type; + } + + float SHRigidBodyComponent::GetMass() const noexcept + { + return mass; + } + + float SHRigidBodyComponent::GetDrag() const noexcept + { + return drag; + } + + float SHRigidBodyComponent::GetAngularDrag() const noexcept + { + return angularDrag; + } + + bool SHRigidBodyComponent::GetFreezePositionX() const noexcept + { + return flags & (1U << 2); + } + + bool SHRigidBodyComponent::GetFreezePositionY() const noexcept + { + return flags & (1U << 3); + } + + bool SHRigidBodyComponent::GetFreezePositionZ() const noexcept + { + return flags & (1U << 4); + } + + bool SHRigidBodyComponent::GetFreezeRotationX() const noexcept + { + return flags & (1U << 5); + } + + bool SHRigidBodyComponent::GetFreezeRotationY() const noexcept + { + return flags & (1U << 6); + } + + bool SHRigidBodyComponent::GetFreezeRotationZ() const noexcept + { + return flags & (1U << 7); + } + + const SHVec3& SHRigidBodyComponent::GetForce() const noexcept + { + return force; + } + + const SHVec3& SHRigidBodyComponent::GetTorque() const noexcept + { + return torque; + } + + const SHVec3& SHRigidBodyComponent::GetLinearVelocity() const noexcept + { + return linearVelocity; + } + + const SHVec3& SHRigidBodyComponent::GetAngularVelocity() const noexcept + { + return angularVelocity; + } + + const SHVec3& SHRigidBodyComponent::GetPosition() const noexcept + { + return position; + } + + const SHQuaternion& SHRigidBodyComponent::GetOrientation() const noexcept + { + return orientation; + } + + SHVec3 SHRigidBodyComponent::GetRotation() const noexcept + { + return orientation.ToEuler(); + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHRigidBodyComponent::SetType(Type newType) noexcept + { + if (type == newType) + return; + + dirtyFlags |= 1U << 4; + type = newType; + } + + void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept + { + constexpr int FLAG_POS = 0; + + dirtyFlags |= 1U << FLAG_POS; + enableGravity ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); + } + + void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept + { + constexpr int FLAG_POS = 1; + + dirtyFlags |= 1U << 1; + isAllowedToSleep ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); + } + + void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept + { + constexpr int FLAG_POS = 2; + + dirtyFlags |= 1U << 2; + freezePositionX ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); + } + + void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept + { + constexpr int FLAG_POS = 3; + + dirtyFlags |= 1U << 2; + freezePositionY ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); + } + + void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept + { + constexpr int FLAG_POS = 4; + + dirtyFlags |= 1U << 2; + freezePositionZ ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); + } + + void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept + { + constexpr int FLAG_POS = 5; + + dirtyFlags |= 1U << 3; + freezeRotationX ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); + } + + void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept + { + constexpr int FLAG_POS = 6; + + dirtyFlags |= 1U << 3; + freezeRotationY ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); + } + + void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept + { + constexpr int FLAG_POS = 7; + + dirtyFlags |= 1U << 3; + freezeRotationZ ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); + } + + void SHRigidBodyComponent::SetInterpolate(bool allowInterpolation) noexcept + { + interpolate = allowInterpolation; + } + + void SHRigidBodyComponent::SetMass(float newMass) noexcept + { + dirtyFlags |= 1U << 5; + mass = newMass; + } + + void SHRigidBodyComponent::SetDrag(float newDrag) noexcept + { + dirtyFlags |= 1U << 6; + drag = newDrag; + } + + void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept + { + dirtyFlags |= 1U << 7; + angularDrag = newAngularDrag; + } + + void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept + { + dirtyFlags |= 1U << 8; + linearVelocity = newLinearVelocity; + } + + void SHRigidBodyComponent::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept + { + dirtyFlags |= 1U << 9; + angularVelocity = newAngularVelocity; + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHRigidBodyComponent::OnCreate() + { + system = SHSystemManager::GetSystem(); + if (!system) + { + SHLOG_ERROR("Physics system does not exist, Rigid Body Component not added!") + return; + } + + // Notify Physics System + system->AddRigidBody(GetEID()); + } + + void SHRigidBodyComponent::OnDestroy() + { + // Notify Physics System + if (!system) + { + SHLOG_ERROR("Physics system does not exist, unable to remove Rigid Body Component!") + return; + } + + system->RemoveRigidBody(GetEID()); + } + + void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept + { + if (!system) + { + SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") + return; + } + + // Notify Physics Systems + system->AddForce(GetEID(), force); + } + + void SHRigidBodyComponent::AddForceAtLocalPos(const SHVec3& force, const SHVec3& localPos) const noexcept + { + if (!system) + { + SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") + return; + } + + // Notify Physics Systems + system->AddForceAtLocalPos(GetEID(), force, localPos); + } + + void SHRigidBodyComponent::AddForceAtWorldPos(const SHVec3& force, const SHVec3& worldPos) const noexcept + { + if (!system) + { + SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") + return; + } + + // Notify Physics Systems + system->AddForceAtWorldPos(GetEID(), force, worldPos); + } + + void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept + { + if (!system) + { + SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") + return; + } + + // Notify Physics Systems + system->AddRelativeForce(GetEID(), force); + } + + void SHRigidBodyComponent::AddRelativeForceAtLocalPos(const SHVec3& relativeForce, const SHVec3& localPos) const noexcept + { + if (!system) + { + SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") + return; + } + + // Notify Physics Systems + system->AddRelativeForceAtLocalPos(GetEID(), force, localPos); + } + + void SHRigidBodyComponent::AddRelativeForceAtWorldPos(const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept + { + if (!system) + { + SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") + return; + } + + // Notify Physics Systems + system->AddRelativeForceAtWorldPos(GetEID(), force, worldPos); + } + + void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept + { + if (!system) + { + SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") + return; + } + + // Notify Physics Systems + system->AddTorque(GetEID(), torque); + } + + void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept + { + if (!system) + { + SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") + return; + } + + // Notify Physics Systems + system->AddRelativeTorque(GetEID(), relativeTorque); + } + +} // namespace SHADE + +RTTR_REGISTRATION +{ + using namespace SHADE; + using namespace rttr; + + registration::enumeration("RigidBody Type") + ( + value("Static", SHRigidBodyComponent::Type::STATIC), + value("Dynamic", SHRigidBodyComponent::Type::DYNAMIC), + value("Kinematic", SHRigidBodyComponent::Type::KINEMATIC) + ); + + registration::class_("RigidBody Component") + .property("Type" , &SHRigidBodyComponent::GetType , &SHRigidBodyComponent::SetType ) + .property("Mass" , &SHRigidBodyComponent::GetMass , &SHRigidBodyComponent::SetMass ) + .property("Drag" , &SHRigidBodyComponent::GetDrag , &SHRigidBodyComponent::SetDrag ) + .property("Angular Drag" , &SHRigidBodyComponent::GetAngularDrag , &SHRigidBodyComponent::SetAngularDrag ) + .property("Use Gravity" , &SHRigidBodyComponent::IsGravityEnabled , &SHRigidBodyComponent::SetGravityEnabled ) + .property("Interpolate" , &SHRigidBodyComponent::IsInterpolating , &SHRigidBodyComponent::SetInterpolate ) + .property("Freeze Position X" , &SHRigidBodyComponent::GetFreezePositionX , &SHRigidBodyComponent::SetFreezePositionX ) + .property("Freeze Position Y" , &SHRigidBodyComponent::GetFreezePositionY , &SHRigidBodyComponent::SetFreezePositionY ) + .property("Freeze Position Z" , &SHRigidBodyComponent::GetFreezePositionZ , &SHRigidBodyComponent::SetFreezePositionZ ) + .property("Freeze Rotation X" , &SHRigidBodyComponent::GetFreezeRotationX , &SHRigidBodyComponent::SetFreezeRotationX ) + .property("Freeze Rotation Y" , &SHRigidBodyComponent::GetFreezeRotationY , &SHRigidBodyComponent::SetFreezeRotationY ) + .property("Freeze Rotation Z" , &SHRigidBodyComponent::GetFreezeRotationZ , &SHRigidBodyComponent::SetFreezeRotationZ ); +} \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h new file mode 100644 index 00000000..0793b2ff --- /dev/null +++ b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h @@ -0,0 +1,171 @@ +/**************************************************************************************** + * \file SHRigidBodyComponent.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Rigidbody Component. + * + * \copyright 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 + +// Project Headers +#include "ECS_Base/Components/SHComponent.h" +#include "Physics/SHPhysicsObject.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SH_API SHRigidBodyComponent : public SHComponent + { + private: + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHPhysicsSystem; + + public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + enum class Type + { + STATIC + , KINEMATIC + , DYNAMIC + + , COUNT + }; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHRigidBodyComponent () noexcept; + SHRigidBodyComponent (const SHRigidBodyComponent& rhs) noexcept = default; + SHRigidBodyComponent (SHRigidBodyComponent&& rhs) noexcept = default; + ~SHRigidBodyComponent () override = default; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHRigidBodyComponent& operator=(const SHRigidBodyComponent& rhs) noexcept = default; + SHRigidBodyComponent& operator=(SHRigidBodyComponent&& rhs) noexcept = default; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] bool IsGravityEnabled () const noexcept; + [[nodiscard]] bool IsAllowedToSleep () const noexcept; + [[nodiscard]] bool IsInterpolating () const noexcept; + + [[nodiscard]] Type GetType () const noexcept; + [[nodiscard]] float GetMass () const noexcept; + [[nodiscard]] float GetDrag () const noexcept; + [[nodiscard]] float GetAngularDrag () const noexcept; + + [[nodiscard]] bool GetFreezePositionX () const noexcept; + [[nodiscard]] bool GetFreezePositionY () const noexcept; + [[nodiscard]] bool GetFreezePositionZ () const noexcept; + + [[nodiscard]] bool GetFreezeRotationX () const noexcept; + [[nodiscard]] bool GetFreezeRotationY () const noexcept; + [[nodiscard]] bool GetFreezeRotationZ () const noexcept; + + [[nodiscard]] const SHVec3& GetForce () const noexcept; + [[nodiscard]] const SHVec3& GetTorque () const noexcept; + [[nodiscard]] const SHVec3& GetLinearVelocity () const noexcept; + [[nodiscard]] const SHVec3& GetAngularVelocity () const noexcept; + + [[nodiscard]] const SHVec3& GetPosition () const noexcept; + [[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; + [[nodiscard]] SHVec3 GetRotation () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetType (Type newType) noexcept; + + void SetGravityEnabled (bool enableGravity) noexcept; + void SetIsAllowedToSleep(bool isAllowedToSleep) noexcept; + void SetFreezePositionX (bool freezePositionX) noexcept; + void SetFreezePositionY (bool freezePositionY) noexcept; + void SetFreezePositionZ (bool freezePositionZ) noexcept; + void SetFreezeRotationX (bool freezeRotationX) noexcept; + void SetFreezeRotationY (bool freezeRotationY) noexcept; + void SetFreezeRotationZ (bool freezeRotationZ) noexcept; + void SetInterpolate (bool allowInterpolation) noexcept; + + void SetMass (float newMass) noexcept; + void SetDrag (float newDrag) noexcept; + void SetAngularDrag (float newAngularDrag) noexcept; + + void SetLinearVelocity (const SHVec3& newLinearVelocity) noexcept; + void SetAngularVelocity (const SHVec3& newAngularVelocity) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + void OnCreate () override; + void OnDestroy () override; + + void AddForce (const SHVec3& force) const noexcept; + void AddForceAtLocalPos (const SHVec3& force, const SHVec3& localPos) const noexcept; + void AddForceAtWorldPos (const SHVec3& force, const SHVec3& worldPos) const noexcept; + + void AddRelativeForce (const SHVec3& relativeForce) const noexcept; + void AddRelativeForceAtLocalPos (const SHVec3& relativeForce, const SHVec3& localPos) const noexcept; + void AddRelativeForceAtWorldPos (const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept; + + void AddTorque (const SHVec3& torque) const noexcept; + void AddRelativeTorque (const SHVec3& relativeTorque) const noexcept; + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + Type type; + + // rX rY rZ pX pY pZ slp g + uint8_t flags; + // 0 0 0 0 0 0 aV lV aD d m t ag lc slp g + uint16_t dirtyFlags; + bool interpolate; + + SHPhysicsSystem* system; + + float mass; + float drag; + float angularDrag; + + SHVec3 force; + SHVec3 linearVelocity; + + SHVec3 torque; + SHVec3 angularVelocity; + + // TODO(Diren): Once quaternions have replaced euler angles in transforms, store it for the rigidbody. + + SHVec3 position; + SHQuaternion orientation; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + RTTR_ENABLE() + }; +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHCollider.cpp b/SHADE_Engine/src/Physics/SHCollider.cpp new file mode 100644 index 00000000..724db19c --- /dev/null +++ b/SHADE_Engine/src/Physics/SHCollider.cpp @@ -0,0 +1,215 @@ +/**************************************************************************************** + * \file SHCollider.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Collider. + * + * \copyright 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 + +// Primary Header +#include "SHCollider.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHCollider::SHCollider(Type colliderType) + : type { colliderType } + , isTrigger { false } + , dirty { true } + , shape { nullptr } + { + CreateShape(); + } + + SHCollider::SHCollider(const SHCollider& rhs) noexcept + : type { rhs.type} + , isTrigger { rhs.isTrigger } + , dirty { true } + , shape { nullptr } + { + CreateShape(); + + // TODO(Diren): Copy transform data over + } + + SHCollider::SHCollider(SHCollider&& rhs) noexcept + : type { rhs.type} + , isTrigger { rhs.isTrigger } + , dirty { true } + , shape { nullptr } + { + CreateShape(); + + // TODO(Diren): Copy transform data over + } + + SHCollider::~SHCollider() noexcept + { + delete shape; + } + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHCollider& SHCollider::operator=(const SHCollider& rhs) noexcept + { + type = rhs.type; + isTrigger = rhs.isTrigger; + dirty = true; + + CreateShape(); + + // TODO(Diren): Copy transform data over + + return *this; + } + + SHCollider& SHCollider::operator=(SHCollider&& rhs) noexcept + { + type = rhs.type; + isTrigger = rhs.isTrigger; + dirty = true; + + CreateShape(); + + // TODO(Diren): Copy transform data over + + return *this; + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHCollider::HasChanged() const noexcept + { + return dirty; + } + + bool SHCollider::IsTrigger() const noexcept + { + return isTrigger; + } + + SHCollider::Type SHCollider::GetType() const noexcept + { + return type; + } + + SHShape* SHCollider::GetShape() const noexcept + { + return shape; + } + + float SHCollider::GetFriction() const noexcept + { + // TODO(Diren): Fix after implementing materials + return 0.0f; + } + + float SHCollider::GetBounciness() const noexcept + { + // TODO(Diren): Fix after implementing materials + return 0.0f; + } + float SHCollider::GetDensity() const noexcept + { + // TODO(Diren): Fix after implementing materials + return 0.0f; + } + + SHVec3 SHCollider::GetPosition() const noexcept + { + // TODO(Diren): Fix after linking transform data + return SHVec3::Zero; + } + + const SHVec3& SHCollider::GetPositionOffset() const noexcept + { + return positionOffset; + } + + SHQuaternion SHCollider::GetOrientation() const noexcept + { + // TODO(Diren): Fix after linking transform data + return SHQuaternion::Identity; + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollider::SetType(Type newType) noexcept + { + if (type == newType) + return; + + dirty = true; + + type = newType; + CreateShape(); + } + + void SHCollider::SetIsTrigger(bool trigger) noexcept + { + dirty = true; + isTrigger = trigger; + } + + void SHCollider::SetFriction(float friction) noexcept + { + dirty = true; + } + + void SHCollider::SetBounciness(float bounciness) noexcept + { + dirty = true; + } + + void SHCollider::SetDensity(float density) noexcept + { + dirty = true; + } + + void SHCollider::SetPositionOffset(const SHVec3& posOffset) noexcept + { + dirty = true; + positionOffset = posOffset; + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Member Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollider::CreateShape() + { + // Remove current shape + delete shape; + + switch (type) + { + case Type::BOX: CreateBoundingBox(); break; + case Type::SPHERE: CreateSphere(); break; + default: break; + } + } + + void SHCollider::CreateBoundingBox() + { + shape = new SHBoundingBox{ SHVec3::Zero, SHVec3::One }; + } + + void SHCollider::CreateSphere() + { + + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHCollider.h b/SHADE_Engine/src/Physics/SHCollider.h new file mode 100644 index 00000000..fce4a5b2 --- /dev/null +++ b/SHADE_Engine/src/Physics/SHCollider.h @@ -0,0 +1,108 @@ +/**************************************************************************************** + * \file SHCollider.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Collider. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +// Project Headers +#include "Math/Geometry/SHBoundingBox.h" +#include "Math/SHQuaternion.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SH_API SHCollider + { + public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + enum class Type + { + BOX + , SPHERE + , CAPSULE + , CONVEX_HULL + , CONVEX_MESH + }; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHCollider (Type colliderType); + + SHCollider (const SHCollider& rhs) noexcept; + SHCollider (SHCollider&& rhs) noexcept; + ~SHCollider () noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHCollider& operator=(const SHCollider& rhs) noexcept; + SHCollider& operator=(SHCollider&& rhs) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] bool HasChanged () const noexcept; + + [[nodiscard]] bool IsTrigger () const noexcept; + + [[nodiscard]] Type GetType () const noexcept; + [[nodiscard]] SHShape* GetShape () const noexcept; + + [[nodiscard]] float GetFriction () const noexcept; + [[nodiscard]] float GetBounciness () const noexcept; + [[nodiscard]] float GetDensity () const noexcept; + + [[nodiscard]] SHVec3 GetPosition () const noexcept; + [[nodiscard]] const SHVec3& GetPositionOffset () const noexcept; + [[nodiscard]] SHQuaternion GetOrientation () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetType (Type newType) noexcept; + + void SetIsTrigger (bool isTrigger) noexcept; + void SetFriction (float friction) noexcept; + void SetBounciness (float bounciness) noexcept; + void SetDensity (float density) noexcept; + + void SetPositionOffset (const SHVec3& positionOffset) noexcept; + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + Type type; + bool isTrigger; + bool dirty; + SHShape* shape; + SHVec3 positionOffset; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + void CreateShape (); + void CreateBoundingBox (); + void CreateSphere (); + }; + +} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/SHPhysicsObject.cpp new file mode 100644 index 00000000..844803b1 --- /dev/null +++ b/SHADE_Engine/src/Physics/SHPhysicsObject.cpp @@ -0,0 +1,121 @@ +/**************************************************************************************** + * \file SHPhysicsObject.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Physics Object. + * + * \copyright 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 + +// Primary Header +#include "SHPhysicsObject.h" + +// Project Headers +#include "ECS_Base/Managers/SHSystemManager.h" +#include "SHPhysicsSystem.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObject::SHPhysicsObject() noexcept + : entityID { MAX_EID } + , isRigidBody { false } + , hasColliders{ false } + , rp3dBody { nullptr } + {} + + SHPhysicsObject::~SHPhysicsObject() noexcept + { + rp3dBody = nullptr; + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHVec3 SHPhysicsObject::GetPosition() const noexcept + { + SHVec3 result; + + if (rp3dBody) + { + const auto& RP3D_RESULT = rp3dBody->getTransform().getPosition(); + result = SHVec3{ RP3D_RESULT.x, RP3D_RESULT.y, RP3D_RESULT.z }; + } + + return result; + } + + SHQuaternion SHPhysicsObject::GetOrientation() const noexcept + { + SHQuaternion result; + + if (rp3dBody) + { + const auto& RP3D_RESULT = rp3dBody->getTransform().getOrientation(); + result = SHQuaternion{ RP3D_RESULT.x, RP3D_RESULT.y, RP3D_RESULT.z, RP3D_RESULT.w }; + } + + return result; + } + + SHVec3 SHPhysicsObject::GetRotation() const noexcept + { + SHVec3 result; + + if (rp3dBody) + { + const auto& RP3D_RESULT = rp3dBody->getTransform().getOrientation(); + result = SHQuaternion{ RP3D_RESULT.x, RP3D_RESULT.y, RP3D_RESULT.z, RP3D_RESULT.w }.ToEuler(); + } + + return result; + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsObject::SetPosition(const SHVec3& position) noexcept + { + const rp3d::Vector3 RP3D_POS { position.x, position.y, position.z }; + + rp3d::Transform rp3dTF; + rp3dTF.setPosition(RP3D_POS); + rp3dTF.setOrientation(rp3dBody->getTransform().getOrientation()); + + rp3dBody->setTransform(rp3dTF); + prevTransform = rp3dTF; + } + + void SHPhysicsObject::SetOrientation(const SHQuaternion& orientation) noexcept + { + const rp3d::Quaternion RP3D_ORIENTATION { orientation.x, orientation.y, orientation.z, orientation.w }; + + rp3d::Transform rp3dTF; + rp3dTF.setPosition(rp3dBody->getTransform().getPosition()); + rp3dTF.setOrientation(RP3D_ORIENTATION); + + rp3dBody->setTransform(rp3dTF); + prevTransform = rp3dTF; + } + + void SHPhysicsObject::SetRotation(const SHVec3& rotation) noexcept + { + const rp3d::Quaternion RP3D_ORIENTATION = rp3d::Quaternion::fromEulerAngles( rotation.x, rotation.y, rotation.z ); + + rp3d::Transform rp3dTF; + rp3dTF.setPosition(rp3dBody->getTransform().getPosition()); + rp3dTF.setOrientation(RP3D_ORIENTATION); + + rp3dBody->setTransform(rp3dTF); + prevTransform = rp3dTF; + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsObject.h b/SHADE_Engine/src/Physics/SHPhysicsObject.h new file mode 100644 index 00000000..cdff2f5b --- /dev/null +++ b/SHADE_Engine/src/Physics/SHPhysicsObject.h @@ -0,0 +1,89 @@ +/**************************************************************************************** + * \file SHPhysicsObject.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Physics Object. + * + * \copyright 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 + +// Project Headers +#include "Math/Vector/SHVec3.h" +#include "Math/SHQuaternion.h" +#include "ECS_Base/Entity/SHEntity.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SH_API SHPhysicsObject + { + private: + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHPhysicsSystem; + friend class SHRigidBodyComponent; + friend class SHColliderComponent; + + public: + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHPhysicsObject () noexcept; + SHPhysicsObject (const SHPhysicsObject& rhs) noexcept = default; + SHPhysicsObject (SHPhysicsObject&& rhs) noexcept = default; + virtual ~SHPhysicsObject () noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHPhysicsObject& operator=(const SHPhysicsObject& rhs) noexcept = default; + SHPhysicsObject& operator=(SHPhysicsObject&& rhs) noexcept = default; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] SHVec3 GetPosition () const noexcept; + [[nodiscard]] SHQuaternion GetOrientation () const noexcept; + [[nodiscard]] SHVec3 GetRotation () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetPosition (const SHVec3& position) noexcept; + void SetOrientation (const SHQuaternion& orientation) noexcept; + void SetRotation (const SHVec3& rotation) noexcept; + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + EntityID entityID; + bool isRigidBody; + bool hasColliders; + + rp3d::CollisionBody* rp3dBody; // Can be either a collision body or a rigid body + rp3d::Transform prevTransform; // Cached transform for interpolation + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + + + }; +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp new file mode 100644 index 00000000..f3a4c276 --- /dev/null +++ b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp @@ -0,0 +1,747 @@ +/**************************************************************************************** + * \file SHPhysicsSystem.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for the Physics System + * + * \copyright 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 + +// Primary Header +#include "SHPhysicsSystem.h" + +// Project Headers +#include "ECS_Base/Managers/SHComponentManager.h" +#include "ECS_Base/Managers/SHEntityManager.h" +#include "Scene/SHSceneManager.h" +#include "Math/Transform/SHTransformComponent.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsSystem::SHPhysicsSystem() + : worldUpdated { false } + , interpolationFactor { 0.0 } + , fixedDT { 60.0 } + , world { nullptr } + {} + + SHPhysicsSystem::PhysicsPreUpdate::PhysicsPreUpdate() + : SHSystemRoutine { "Physics PreUpdate", true } + {} + + SHPhysicsSystem::PhysicsFixedUpdate::PhysicsFixedUpdate() + : SHFixedSystemRoutine { DEFAULT_FIXED_STEP, "Physics FixedUpdate", false } + {} + + SHPhysicsSystem::PhysicsPostUpdate::PhysicsPostUpdate() + : SHSystemRoutine { "Physics PostUpdate", false } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + double SHPhysicsSystem::GetFixedDT() const noexcept + { + return fixedDT; + } + + bool SHPhysicsSystem::IsSleepingEnabled() const noexcept + { + if (world) + return world->isSleepingEnabled(); + + SHLOGV_WARNING("No physics world has been initialised!") + return false; + } + + SHVec3 SHPhysicsSystem::GetWorldGravity() const noexcept + { + SHVec3 result; + + if (world) + { + const auto RP3D_GRAVITY = world->getGravity(); + result.x = RP3D_GRAVITY.x; + result.y = RP3D_GRAVITY.y; + result.z = RP3D_GRAVITY.z; + } + else + { + SHLOGV_WARNING("No physics world has been initialised!") + } + + return result; + } + + uint16_t SHPhysicsSystem::GetNumberVelocityIterations() const noexcept + { + if (world) + return world->getNbIterationsVelocitySolver(); + + SHLOGV_WARNING("No physics world has been initialised!") + return 0; + } + + uint16_t SHPhysicsSystem::GetNumberPositionIterations() const noexcept + { + if (world) + return world->getNbIterationsPositionSolver(); + + SHLOGV_WARNING("No physics world has been initialised!") + return 0; + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsSystem::SetFixedDT(double fixedUpdateRate) noexcept + { + fixedDT = fixedUpdateRate; + } + + void SHPhysicsSystem::SetWorldGravity(const SHVec3& gravity) const noexcept + { + if (world) + { + const rp3d::Vector3 G { gravity.x, gravity.y, gravity.z }; + world->setGravity(G); + } + else + { + SHLOGV_WARNING("No physics world has been initialised!") + } + } + + void SHPhysicsSystem::SetNumberVelocityIterations(uint16_t numVelIterations) const noexcept + { + if (world) + { + world->setNbIterationsVelocitySolver(numVelIterations); + } + else + { + SHLOGV_WARNING("No physics world has been initialised!") + } + } + + void SHPhysicsSystem::SetNumberPositionIterations(uint16_t numPosIterations) const noexcept + { + if (world) + { + world->setNbIterationsPositionSolver(numPosIterations); + } + else + { + SHLOGV_WARNING("No physics world has been initialised!") + } + } + + void SHPhysicsSystem::SetSleepingEnabled(bool enableSleeping) const noexcept + { + if (world) + { + world->enableSleeping(enableSleeping); + } + else + { + SHLOGV_WARNING("No physics world has been initialised!") + } + } + + void SHPhysicsSystem::SetWorldSettings(const WorldSettings& settings) const noexcept + { + if (world) + { + const rp3d::Vector3 G { settings.gravity.x, settings.gravity.y, settings.gravity.z }; + world->setGravity(G); + world->setNbIterationsVelocitySolver(settings.numVelocitySolverIterations); + world->setNbIterationsPositionSolver(settings.numPositionSolverIterations); + world->enableSleeping(settings.sleepingEnabled); + } + else + { + SHLOGV_WARNING("No physics world has been initialised!") + } + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsSystem::Init() + { + using namespace rp3d; + + // Create a physics world with the default settings + PhysicsWorld::WorldSettings settings; + settings.gravity = Vector3{ 0.0f, -9.81f, 0.0f }; + settings.isSleepingEnabled = true; + settings.defaultVelocitySolverNbIterations = 8; + settings.defaultPositionSolverNbIterations = 3; + settings.defaultFrictionCoefficient = 0.4f; + settings.defaultBounciness = 0.0f; + + world = factory.createPhysicsWorld(settings); + + // Set up solvers + world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::SPLIT_IMPULSES); + } + + void SHPhysicsSystem::Exit() + { + factory.destroyPhysicsWorld(world); + } + + void SHPhysicsSystem::AddRigidBody(EntityID entityID) noexcept + { + #ifdef _DEBUG + SHLOG_INFO("Adding a Rigidbody to the Physics World.") + #endif + + // Check if entity is already a physics object + auto* physicsObject = GetPhysicsObject(entityID); + if (!physicsObject) + { + physicsObject = &(map.emplace(entityID, SHPhysicsObject{}).first->second); + physicsObject->entityID = entityID; + } + + // Get entity transform + auto const* SHADE_TF = SHComponentManager::GetComponent_s(entityID); + + // Possibly redundant + if (!SHADE_TF) + { + SHComponentManager::AddComponent(entityID); + SHADE_TF = SHComponentManager::GetComponent(entityID); + } + + const SHVec3& SHADE_POS = SHADE_TF->GetWorldPosition(); + const SHVec3& SHADE_ROT = SHADE_TF->GetWorldRotation(); + + const rp3d::Vector3 RP3D_POS { SHADE_POS.x, SHADE_POS.y, SHADE_POS.z }; + const rp3d::Quaternion RP3D_ROT = rp3d::Quaternion::fromEulerAngles( SHADE_ROT.x, SHADE_ROT.y, SHADE_ROT.z ); + + const rp3d::Transform RP3D_TF { RP3D_POS, RP3D_ROT }; + + // If collider already exists + if (physicsObject->hasColliders) + world->destroyCollisionBody(physicsObject->rp3dBody); + + physicsObject->rp3dBody = world->createRigidBody(RP3D_TF); + physicsObject->isRigidBody = true; + + // Recreate colliders + if (physicsObject->hasColliders) + { + const auto& COLLIDERS = SHComponentManager::GetComponent(entityID)->GetColliders(); + for (const auto& collider : COLLIDERS | std::views::keys) + { + switch (collider.GetType()) + { + case SHCollider::Type::BOX: + { + SHBoundingBox* box = reinterpret_cast(collider.GetShape()); + const SHVec3& SHADE_EXTENTS = box->GetHalfExtents(); + + rp3d::Vector3 RP3D_EXTENTS { SHADE_EXTENTS.x, SHADE_EXTENTS.y, SHADE_EXTENTS.z }; + rp3d::BoxShape* newBox = factory.createBoxShape(RP3D_EXTENTS); + + // TODO(Diren): Handle offsets + physicsObject->rp3dBody->addCollider(newBox, RP3D_TF); + break; + } + case SHCollider::Type::SPHERE: + { + break; + } + // TODO(Diren): Add more collider shapes + default: break; + } + } + } + + } + + void SHPhysicsSystem::AddCollider(EntityID entityID) noexcept + { + #ifdef _DEBUG + SHLOG_INFO("Adding a Collider to the Physics World.") + #endif + + // Check if entity is already a physics object + auto* physicsObject = GetPhysicsObject(entityID); + if (!physicsObject) + { + physicsObject = &(map.emplace(entityID, SHPhysicsObject{}).first->second); + physicsObject->entityID = entityID; + } + + // Get entity transform + auto const* SHADE_TF = SHComponentManager::GetComponent_s(entityID); + + // Possibly redundant + if (!SHADE_TF) + { + SHComponentManager::AddComponent(entityID); + SHADE_TF = SHComponentManager::GetComponent(entityID); + } + + const SHVec3& SHADE_POS = SHADE_TF->GetWorldPosition(); + const SHVec3& SHADE_ROT = SHADE_TF->GetWorldRotation(); + + const rp3d::Vector3 RP3D_POS { SHADE_POS.x, SHADE_POS.y, SHADE_POS.z }; + const rp3d::Quaternion RP3D_ROT = rp3d::Quaternion::fromEulerAngles( SHADE_ROT.x, SHADE_ROT.y, SHADE_ROT.z ); + + const rp3d::Transform RP3D_TF { RP3D_POS, RP3D_ROT }; + + // No rb + if (!physicsObject->isRigidBody) + physicsObject->rp3dBody = world->createCollisionBody(RP3D_TF); + + const auto& COLLIDERS = SHComponentManager::GetComponent(entityID)->GetColliders(); + for (const auto& collider : COLLIDERS | std::views::keys) + { + switch (collider.GetType()) + { + case SHCollider::Type::BOX: + { + SHBoundingBox* box = reinterpret_cast(collider.GetShape()); + const SHVec3& SHADE_EXTENTS = box->GetHalfExtents(); + + rp3d::Vector3 RP3D_EXTENTS { SHADE_EXTENTS.x, SHADE_EXTENTS.y, SHADE_EXTENTS.z }; + rp3d::BoxShape* newBox = factory.createBoxShape(RP3D_EXTENTS); + + // TODO(Diren): Handle offsets + physicsObject->rp3dBody->addCollider(newBox, RP3D_TF); + break; + } + case SHCollider::Type::SPHERE: + { + break; + } + // TODO(Diren): Add more collider shapes + default: break; + } + } + + physicsObject->hasColliders = true; + } + + void SHPhysicsSystem::RemoveRigidBody(EntityID entityID) noexcept + { + #ifdef _DEBUG + SHLOG_INFO("Removing a Rigidbody from the Physics World.") + #endif + + } + + void SHPhysicsSystem::RemoveCollider(EntityID entityID) noexcept + { + #ifdef _DEBUG + SHLOG_INFO("Removing a Collider from the Physics World.") + #endif + } + + void SHPhysicsSystem::AddForce(EntityID entityID, const SHVec3& force) const noexcept + { + + } + + void SHPhysicsSystem::AddForceAtLocalPos(EntityID entityID, const SHVec3& force, const SHVec3& localPos) const noexcept + { + + } + + void SHPhysicsSystem::AddForceAtWorldPos(EntityID entityID, const SHVec3& force, const SHVec3& worldPos) const noexcept + { + + } + + void SHPhysicsSystem::AddRelativeForce(EntityID entityID, const SHVec3& relativeForce) const noexcept + { + + } + + void SHPhysicsSystem::AddRelativeForceAtLocalPos(EntityID entityID, const SHVec3& relativeForce, const SHVec3& localPos) const noexcept + { + + } + + void SHPhysicsSystem::AddRelativeForceAtWorldPos(EntityID entityID, const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept + { + + } + + void SHPhysicsSystem::AddTorque(EntityID entityID, const SHVec3& torque) const noexcept + { + + } + + void SHPhysicsSystem::AddRelativeTorque(EntityID entityID, const SHVec3& relativeTorque) const noexcept + { + + } + + void SHPhysicsSystem::AddCollisionShape(EntityID entityID, SHShape* shape) + { + auto* physicsObject = GetPhysicsObject(entityID); + + switch (shape->GetType()) + { + case SHShape::Type::BOUNDING_BOX: + { + auto* box = reinterpret_cast(shape); + const SHVec3& SHADE_EXTENTS = box->GetHalfExtents(); + + rp3d::Vector3 RP3D_EXTENTS { SHADE_EXTENTS.x, SHADE_EXTENTS.y, SHADE_EXTENTS.z }; + rp3d::BoxShape* newBox = factory.createBoxShape(RP3D_EXTENTS); + + // TODO(Diren): Handle offsets + + rp3d::Transform tf = rp3d::Transform::identity(); + physicsObject->rp3dBody->addCollider(newBox, tf); + break; + } + case SHShape::Type::SPHERE: + { + break; + } + // TODO(Diren): Add more collider shapes + default: break; + } + } + + void SHPhysicsSystem::RemoveCollisionShape(EntityID entityID, int index) + { + + } + + void SHPhysicsSystem::PhysicsPreUpdate::Execute(double) noexcept + { + auto* system = reinterpret_cast(GetSystem()); + + // Update bodies and colliders if component is dirty + system->SyncRigidBodyComponents(SHComponentManager::GetDense()); + system->SyncColliderComponents(SHComponentManager::GetDense()); + + // Sync transforms + for (auto& physicsObject : system->map | std::views::values) + { + const auto* TF = SHComponentManager::GetComponent(physicsObject.entityID); + if (TF->HasChanged()) + { + physicsObject.SetPosition(TF->GetWorldPosition()); + physicsObject.SetRotation(TF->GetWorldRotation()); + } + } + } + + void SHPhysicsSystem::PhysicsFixedUpdate::Execute(double dt) noexcept + { + auto* system = reinterpret_cast(GetSystem()); + fixedTimeStep = 1.0 / system->fixedDT; + accumulatedTime += dt; + + int count = 0; + while (accumulatedTime > fixedTimeStep) + { + system->world->update(static_cast(fixedTimeStep)); + + accumulatedTime -= fixedTimeStep; + ++count; + } + + stats.numSteps = count; + system->worldUpdated = count > 0; + + system->interpolationFactor = accumulatedTime / fixedTimeStep; + } + + void SHPhysicsSystem::PhysicsPostUpdate::Execute(double) noexcept + { + auto* system = reinterpret_cast(GetSystem()); + + // Interpolate transforms for rendering + if (system->worldUpdated) + { + system->SyncTransforms(); + // TODO(Diren): Handle trigger messages for scripting + } + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsObject* SHPhysicsSystem::GetPhysicsObject(EntityID entityID) noexcept + { + const auto it = map.find(entityID); + if (it == map.end()) + { + SHLOG_ERROR("Entity {} is not in the physics system!", entityID) + return nullptr; + } + + return &(it->second); + } + + void SHPhysicsSystem::SyncRigidBodyComponents(std::vector& denseArray) noexcept + { + if (denseArray.empty()) + return; + + for (auto& comp : denseArray) + { + const EntityID ENTITY_ID = comp.GetEID(); + + // Get physicsObject + auto const* physicsObject = GetPhysicsObject(ENTITY_ID); + + const bool RP3D_ACTIVE = physicsObject->rp3dBody->isActive(); + // TODO(Diren): Check if active in hierarchy + const bool COMPONENT_ACTIVE = comp.isActive; + + if (RP3D_ACTIVE != COMPONENT_ACTIVE) + physicsObject->rp3dBody->setIsActive(COMPONENT_ACTIVE); + + if (!COMPONENT_ACTIVE) + continue; + + if (comp.dirtyFlags > 0) + { + SyncRigidBody(physicsObject, &comp); + comp.dirtyFlags = 0; + } + } + } + + void SHPhysicsSystem::SyncColliderComponents(std::vector& denseArray) noexcept + { + if (denseArray.empty()) + return; + + for (auto& comp : denseArray) + { + const EntityID ENTITY_ID = comp.GetEID(); + + // Get physicsObject + auto const* physicsObject = GetPhysicsObject(ENTITY_ID); + + const bool RP3D_ACTIVE = physicsObject->rp3dBody->isActive(); + // TODO(Diren): Check if active in hierarchy + const bool COMPONENT_ACTIVE = comp.isActive; + + if (RP3D_ACTIVE != COMPONENT_ACTIVE) + physicsObject->rp3dBody->setIsActive(COMPONENT_ACTIVE); + + if (!COMPONENT_ACTIVE) + continue; + + SyncCollider(physicsObject, &comp); + } + } + + void SHPhysicsSystem::SyncTransforms() noexcept + { + for (auto& pair : map) + { + const EntityID ENTITY_ID = pair.first; + SHPhysicsObject& physicsObject = pair.second; + + rp3d::Vector3 rp3dPos; + rp3d::Quaternion rp3dRot; + + const rp3d::Transform CURRENT_TF = physicsObject.rp3dBody->getTransform(); + + // Check if transform should be interpolated + + if (physicsObject.isRigidBody) + { + auto const* rbComponent = SHComponentManager::GetComponent(ENTITY_ID); + if (rbComponent->GetType() == SHRigidBodyComponent::Type::STATIC) + continue; + + if (rbComponent->IsInterpolating()) + { + const rp3d::Transform PREV_TF = physicsObject.prevTransform; + const rp3d::Transform INTERPOLATED_TF = rp3d::Transform::interpolateTransforms(PREV_TF, CURRENT_TF, static_cast(interpolationFactor)); + + + rp3dPos = INTERPOLATED_TF.getPosition(); + rp3dRot = INTERPOLATED_TF.getOrientation(); + } + else + { + rp3dPos = CURRENT_TF.getPosition(); + rp3dRot = CURRENT_TF.getOrientation(); + } + } + else + { + rp3dPos = CURRENT_TF.getPosition(); + rp3dRot = CURRENT_TF.getOrientation(); + } + + // Convert RP3D Transform to SHADE + const SHVec3 SHADE_POS = SHVec3{ rp3dPos.x, rp3dPos.y, rp3dPos.z }; + const SHVec3 SHADE_ROT = SHQuaternion{ rp3dRot.x, rp3dRot.y, rp3dRot.z, rp3dRot.w }.ToEuler(); + + auto* tfComponent = SHComponentManager::GetComponent(ENTITY_ID); + tfComponent->SetWorldPosition(SHADE_POS); + tfComponent->SetWorldRotation(SHADE_ROT); + + // Cache transforms + physicsObject.prevTransform = CURRENT_TF; + } + } + + void SHPhysicsSystem::SyncRigidBody(SHPhysicsObject const* physicsObject, const SHRigidBodyComponent* comp) noexcept + { + auto* rigidBody = reinterpret_cast(physicsObject->rp3dBody); + + const uint16_t RB_FLAGS = comp->dirtyFlags; + const size_t NUM_FLAGS = sizeof(RB_FLAGS) * 8U; + for (size_t i = 0; i < NUM_FLAGS; ++i) + { + // Check if current dirty flag has been set to true + if (RB_FLAGS & 1U << i) + { + switch (i) + { + case 0: // Gravity + { + rigidBody->enableGravity(comp->IsGravityEnabled()); + break; + } + case 1: // Sleeping + { + rigidBody->setIsAllowedToSleep(comp->IsAllowedToSleep()); + break; + } + case 2: // Linear Constraints + { + SetRP3DLinearConstraints(rigidBody, comp->flags); + break; + } + case 3: // Angular Constraints + { + SetRP3DAngularConstraints(rigidBody, comp->flags); + break; + } + case 4: // Type + { + rigidBody->setType(static_cast(comp->GetType())); + break; + } + case 5: // Mass + { + rigidBody->setMass(comp->GetMass()); + break; + } + case 6: // Drag + { + rigidBody->setLinearDamping(comp->GetDrag()); + break; + } + case 7: // Angular Drag + { + rigidBody->setAngularDamping(comp->GetAngularDrag()); + break; + } + case 8: // Linear Velocity + { + const SHVec3& SHADE_VEL = comp->GetLinearVelocity(); + rp3d::Vector3 RP3D_VEL { SHADE_VEL.x, SHADE_VEL.y, SHADE_VEL.z }; + + rigidBody->setLinearVelocity(RP3D_VEL); + break; + } + case 9: // Angular Velocity + { + const SHVec3& SHADE_VEL = comp->GetAngularVelocity(); + rp3d::Vector3 RP3D_VEL { SHADE_VEL.x, SHADE_VEL.y, SHADE_VEL.z }; + + rigidBody->setAngularVelocity(RP3D_VEL); + break; + } + default: break; + } + } + } + } + + void SHPhysicsSystem::SetRP3DLinearConstraints(rp3d::RigidBody const* rp3dRigidBody, uint8_t rbFlags) noexcept + { + const rp3d::Vector3 CONSTRAINTS + { + rbFlags & 1U << 2 ? 0.0f : 1.0f, + rbFlags & 1U << 3 ? 0.0f : 1.0f, + rbFlags & 1U << 4 ? 0.0f : 1.0f + }; + + + rp3dRigidBody->setLinearLockAxisFactor(CONSTRAINTS); + } + + void SHPhysicsSystem::SetRP3DAngularConstraints(rp3d::RigidBody const* rp3dRigidBody, uint8_t rbFlags) noexcept + { + const rp3d::Vector3 CONSTRAINTS + { + rbFlags & 1U << 5 ? 0.0f : 1.0f, + rbFlags & 1U << 6 ? 0.0f : 1.0f, + rbFlags & 1U << 7 ? 0.0f : 1.0f + }; + + rp3dRigidBody->setAngularLockAxisFactor(CONSTRAINTS); + } + + void SHPhysicsSystem::SyncCollider(SHPhysicsObject const* physicsObject, SHColliderComponent* comp) noexcept + { + int index = 0; + for (auto& [collider, dirty] : comp->colliders) + { + if (!dirty) + continue; + + switch (collider.GetType()) + { + case SHCollider::Type::BOX: + { + SHBoundingBox* box = reinterpret_cast(collider.GetShape()); + const SHVec3& SHADE_EXTENTS = box->GetHalfExtents(); + + rp3d::Vector3 RP3D_EXTENTS { SHADE_EXTENTS.x, SHADE_EXTENTS.y, SHADE_EXTENTS.z }; + + auto* rp3dBoxShape = reinterpret_cast(physicsObject->rp3dBody->getCollider(index)->getCollisionShape()); + rp3dBoxShape->setHalfExtents(RP3D_EXTENTS); + + if (rp3dBoxShape) + { + SHLOG_INFO("Updating box things") + } + + break; + } + case SHCollider::Type::SPHERE: + { + break; + } + default: break; + } + + dirty = false; + ++index; + } + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/SHPhysicsSystem.h new file mode 100644 index 00000000..4eaf4a89 --- /dev/null +++ b/SHADE_Engine/src/Physics/SHPhysicsSystem.h @@ -0,0 +1,203 @@ +/**************************************************************************************** + * \file SHPhysicsSystem.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for the Physics System + * + * \copyright 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 +#include + +#include + +// Project Headers +#include "SHPhysicsObject.h" +#include "Components/SHRigidBodyComponent.h" +#include "Components/SHColliderComponent.h" + +#include "Scene/SHSceneGraph.h" +#include "ECS_Base/System/SHSystemRoutine.h" +#include "ECS_Base/System/SHFixedSystemRoutine.h" + + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SH_API SHPhysicsSystem : public SHSystem + { + public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + struct WorldSettings + { + SHVec3 gravity; + uint16_t numVelocitySolverIterations; + uint16_t numPositionSolverIterations; + bool sleepingEnabled; + }; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHPhysicsSystem(); + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] double GetFixedDT () const noexcept; + + [[nodiscard]] bool IsSleepingEnabled () const noexcept; + + [[nodiscard]] SHVec3 GetWorldGravity () const noexcept; + [[nodiscard]] uint16_t GetNumberVelocityIterations () const noexcept; + [[nodiscard]] uint16_t GetNumberPositionIterations () const noexcept; + + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetFixedDT (double fixedUpdateRate) noexcept; + void SetWorldGravity (const SHVec3& gravity) const noexcept; + void SetNumberVelocityIterations (uint16_t numVelIterations) const noexcept; + void SetNumberPositionIterations (uint16_t numPosIterations) const noexcept; + void SetSleepingEnabled (bool enableSleeping) const noexcept; + + void SetWorldSettings (const WorldSettings& settings) const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + void Init () override; + void Exit () override; + + void AddRigidBody (EntityID entityID) noexcept; + void AddCollider (EntityID entityID) noexcept; + void RemoveRigidBody (EntityID entityID) noexcept; + void RemoveCollider (EntityID entityID) noexcept; + + void AddForce (EntityID entityID, const SHVec3& force) const noexcept; + void AddForceAtLocalPos (EntityID entityID, const SHVec3& force, const SHVec3& localPos) const noexcept; + void AddForceAtWorldPos (EntityID entityID, const SHVec3& force, const SHVec3& worldPos) const noexcept; + + void AddRelativeForce (EntityID entityID, const SHVec3& relativeForce) const noexcept; + void AddRelativeForceAtLocalPos (EntityID entityID, const SHVec3& relativeForce, const SHVec3& localPos) const noexcept; + void AddRelativeForceAtWorldPos (EntityID entityID, const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept; + + void AddTorque (EntityID entityID, const SHVec3& torque) const noexcept; + void AddRelativeTorque (EntityID entityID, const SHVec3& relativeTorque) const noexcept; + + void AddCollisionShape (EntityID entityID, SHShape* shape); + void RemoveCollisionShape (EntityID entityID, int index); + + /*---------------------------------------------------------------------------------*/ + /* System Routines */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief Synchronises RP3D with SHADE + */ + class SH_API PhysicsPreUpdate : public SHSystemRoutine + { + public: + /*-------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-------------------------------------------------------------------------------*/ + + PhysicsPreUpdate(); + + /*-------------------------------------------------------------------------------*/ + /* Function Members */ + /*-------------------------------------------------------------------------------*/ + + void Execute(double dt) noexcept override; + }; + + class SH_API PhysicsFixedUpdate : public SHFixedSystemRoutine + { + public: + /*-------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-------------------------------------------------------------------------------*/ + + PhysicsFixedUpdate(); + + /*-------------------------------------------------------------------------------*/ + /* Function Members */ + /*-------------------------------------------------------------------------------*/ + + void Execute (double dt) noexcept override; + }; + + class SH_API PhysicsPostUpdate : public SHSystemRoutine + { + public: + /*-------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-------------------------------------------------------------------------------*/ + + PhysicsPostUpdate(); + + /*-------------------------------------------------------------------------------*/ + /* Function Members */ + /*-------------------------------------------------------------------------------*/ + + void Execute(double dt) noexcept override; + }; + + private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + using EntityObjectMap = std::unordered_map; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + // TODO(Diren): Store interpFactor + + bool worldUpdated; + + double interpolationFactor; + double fixedDT; + rp3d::PhysicsWorld* world; + + rp3d::PhysicsCommon factory; + EntityObjectMap map; + + + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + SHPhysicsObject* GetPhysicsObject (EntityID entityID) noexcept; + + void SyncRigidBodyComponents (std::vector& denseArray) noexcept; + void SyncColliderComponents (std::vector& denseArray) noexcept; + void SyncTransforms () noexcept; + // TODO(Diren): Trigger handling + + static void SyncRigidBody (SHPhysicsObject const* physicsObject, const SHRigidBodyComponent* comp) noexcept; + static void SetRP3DLinearConstraints (rp3d::RigidBody const* rp3dRigidBody, uint8_t rbFlags) noexcept; + static void SetRP3DAngularConstraints (rp3d::RigidBody const* rp3dRigidBody, uint8_t rbFlags) noexcept; + + static void SyncCollider (SHPhysicsObject const* physicsObject, SHColliderComponent* comp) noexcept; + }; + + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Reflection/SHReflectionMetadata.h b/SHADE_Engine/src/Reflection/SHReflectionMetadata.h new file mode 100644 index 00000000..0cc6d8a5 --- /dev/null +++ b/SHADE_Engine/src/Reflection/SHReflectionMetadata.h @@ -0,0 +1,11 @@ +#pragma once +#include "string_view" +namespace SHADE +{ + namespace META + { + constexpr const char* min = "MIN"; + constexpr const char* max = "MAX"; + constexpr const char* tooltip = "tooltip"; + } +} diff --git a/SHADE_Engine/src/Resource/Handle.h b/SHADE_Engine/src/Resource/Handle.h index a0272290..9579063c 100644 --- a/SHADE_Engine/src/Resource/Handle.h +++ b/SHADE_Engine/src/Resource/Handle.h @@ -54,7 +54,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Usage Functions */ /*-----------------------------------------------------------------------------*/ - inline Id GetId() const; + inline Id GetId() const noexcept; /*-----------------------------------------------------------------------------*/ /* Overloaded Operators */ @@ -62,7 +62,7 @@ namespace SHADE /// /// Converts to true if this is a valid Handle. /// - inline operator bool() const; + inline operator bool() const noexcept; protected: /*-----------------------------------------------------------------------------*/ @@ -101,6 +101,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Overloaded Operators */ /*-----------------------------------------------------------------------------*/ + inline bool operator==(const Handle& rhs) const noexcept; /// /// Returns the underlying object pointed to by the Handle. /// diff --git a/SHADE_Engine/src/Resource/Handle.hpp b/SHADE_Engine/src/Resource/Handle.hpp index 27cdd1cd..45468ec1 100644 --- a/SHADE_Engine/src/Resource/Handle.hpp +++ b/SHADE_Engine/src/Resource/Handle.hpp @@ -8,15 +8,15 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* HandleBase - Usage Functions */ /*---------------------------------------------------------------------------------*/ - inline HandleBase::Id HandleBase::GetId() const + inline HandleBase::Id HandleBase::GetId() const noexcept { return id; } /*---------------------------------------------------------------------------------*/ /* HandleBase - Overloaded Operators */ - inline HandleBase::operator bool() const /*---------------------------------------------------------------------------------*/ + inline HandleBase::operator bool() const noexcept { return id.Raw != INVALID_ID.Raw; } @@ -33,6 +33,12 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Handle - Overloaded Operators */ /*---------------------------------------------------------------------------------*/ + template + bool SHADE::Handle::operator==(const Handle& rhs) const noexcept + { + return id.Raw == rhs.id.Raw && library == rhs.library; + } + template T& Handle::operator*() { diff --git a/SHADE_Engine/src/Resource/ResourceLibrary.cpp b/SHADE_Engine/src/Resource/ResourceLibrary.cpp index 5a3ad9fe..b215b591 100644 --- a/SHADE_Engine/src/Resource/ResourceLibrary.cpp +++ b/SHADE_Engine/src/Resource/ResourceLibrary.cpp @@ -8,9 +8,9 @@ namespace SHADE ResourceManager::~ResourceManager() { // Delete all resources libraries - for (const auto& deleter : deleters) + for (auto iter = deleters.rbegin(); iter != deleters.rend(); ++iter) { - deleter(); + (*iter)(); } deleters.clear(); } diff --git a/SHADE_Engine/src/Resource/ResourceLibrary.h b/SHADE_Engine/src/Resource/ResourceLibrary.h index 4588b9fe..a5bf0a67 100644 --- a/SHADE_Engine/src/Resource/ResourceLibrary.h +++ b/SHADE_Engine/src/Resource/ResourceLibrary.h @@ -118,7 +118,7 @@ namespace SHADE /// Handle to the resource object. /// Read-only reference to the resource object. template - const T& Get(Handle handle) const; + const T& Get(Handle handle) const; private: /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/SHpch.h b/SHADE_Engine/src/SHpch.h index 8b2f11f3..7e308829 100644 --- a/SHADE_Engine/src/SHpch.h +++ b/SHADE_Engine/src/SHpch.h @@ -38,3 +38,4 @@ #include "Common/SHCommonTypes.h" #include "Tools/SHLogger.h" +#include "Tools/SHException.h" diff --git a/SHADE_Engine/src/Scene/SHScene.h b/SHADE_Engine/src/Scene/SHScene.h index 372981a6..a81c70ef 100644 --- a/SHADE_Engine/src/Scene/SHScene.h +++ b/SHADE_Engine/src/Scene/SHScene.h @@ -13,6 +13,7 @@ #include #include "SHSceneGraph.h" +#include "ECS_Base/General/SHFamily.h" namespace SHADE { @@ -42,6 +43,7 @@ namespace SHADE virtual void Unload() = 0; }; + template class SH_API SHFamilyID; } diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.cpp b/SHADE_Engine/src/Scene/SHSceneGraph.cpp index da2dcffd..3fe85809 100644 --- a/SHADE_Engine/src/Scene/SHSceneGraph.cpp +++ b/SHADE_Engine/src/Scene/SHSceneGraph.cpp @@ -90,10 +90,15 @@ namespace SHADE #endif // Go through the map and release all the nodes - for (auto* node : entityNodeMap | std::views::values) - ReleaseNode(node); + for (auto*& node : entityNodeMap | std::views::values) + { + delete node; + node = nullptr; + } - delete root; + entityNodeMap.clear(); + + //delete root; #ifdef _DEBUG SHLOG_INFO("Scene Graph Destroyed Successfully!") diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.h b/SHADE_Engine/src/Scene/SHSceneGraph.h index 39afbb31..3f3ebf92 100644 --- a/SHADE_Engine/src/Scene/SHSceneGraph.h +++ b/SHADE_Engine/src/Scene/SHSceneGraph.h @@ -99,7 +99,7 @@ namespace SHADE using EntityNodeMap = std::unordered_map; - using UnaryPredicate = void (*)(SHSceneNode*); + using UnaryPredicate = std::function; /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Scene/SHSceneManager.h b/SHADE_Engine/src/Scene/SHSceneManager.h index 83ebab0f..2e4b1717 100644 --- a/SHADE_Engine/src/Scene/SHSceneManager.h +++ b/SHADE_Engine/src/Scene/SHSceneManager.h @@ -84,7 +84,8 @@ namespace SHADE { //prevSceneCreate = newScene; newScene = [sceneName]() { currentScene = new T(); currentScene->sceneName = sceneName; }; - nextSceneID = SHFamilyID::template GetID(); + //nextSceneID = SHFamilyID::GetID(); + nextSceneID = 0; sceneChanged = true; } @@ -101,13 +102,13 @@ namespace SHADE static std::enable_if_t, void> ChangeScene(std::string const& sceneName) noexcept { //check if this new Scene is current Scene (Use RestartScene instead) - if (currentSceneID == SHFamilyID::template GetID()) + if (currentSceneID == SHFamilyID::GetID()) { return; } //prevSceneCreate = newScene; newScene = [sceneName]() { currentScene = new T(); currentScene->sceneName; }; - nextSceneID = SHFamilyID::template GetID(); + nextSceneID = SHFamilyID::GetID(); sceneChanged = true; } diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index 0c508a34..65f445a6 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -82,22 +82,18 @@ namespace SHADE void SHScriptEngine::Exit() { - // Do not allow deinitialization if not initialised - if (!dotNet.IsLoaded()) - { - SHLOG_ERROR("[ScriptEngine] Attempted to clean up an unloaded DotNetRuntime."); - return; - } + // Do not allow deinitialization if not initialised + if (!dotNet.IsLoaded()) + { + SHLOG_ERROR("[ScriptEngine] Attempted to clean up an unloaded DotNetRuntime."); + return; + } - // Unlink events - /*ECS::OnEntityCreated -= onEntityCreate; - ECS::OnEntityDestroy -= onEntityDestroy;*/ + // Clean up the CSharp Engine + csEngineExit(); - // Clean up the CSharp Engine - csEngineExit(); - - // Shut down the CLR - dotNet.Exit(); + // Shut down the CLR + dotNet.Exit(); } /*-----------------------------------------------------------------------------------*/ @@ -105,15 +101,15 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ bool SHScriptEngine::AddScript(EntityID entity, const std::string_view& scriptName) { - return csScriptsAdd(entity, scriptName.data()); + return csScriptsAdd(entity, scriptName.data()); } void SHScriptEngine::RemoveAllScripts(EntityID entity) { - csScriptsRemoveAll(entity); + csScriptsRemoveAll(entity); } void SHScriptEngine::RemoveAllScriptsImmediately(EntityID entity, bool callOnDestroy) { - csScriptsRemoveAllImmediately(entity, callOnDestroy); + csScriptsRemoveAllImmediately(entity, callOnDestroy); } /*---------------------------------------------------------------------------------*/ @@ -121,24 +117,24 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ std::string SHScriptEngine::SerialiseScripts(const SHEntity& entity) const { - // Create buffer needed to store serialised script data - constexpr int BUFFER_SIZE = 10240; - std::unique_ptr buffer { new char[BUFFER_SIZE] }; - std::memset(buffer.get(), 0, BUFFER_SIZE); + // Create buffer needed to store serialised script data + constexpr int BUFFER_SIZE = 10240; + std::unique_ptr buffer { new char[BUFFER_SIZE] }; + std::memset(buffer.get(), 0, BUFFER_SIZE); - // Attempt to serialise the script - std::string result; - if (csScriptsSerialise(entity.GetEID(), buffer.get(), BUFFER_SIZE)) - { - result = std::string(buffer.get()); - } - else - { - SHLOG_ERROR("[ScriptEngine] Failed to serialise scripts as string buffer is too small!"); - } + // Attempt to serialise the script + std::string result; + if (csScriptsSerialise(entity.GetEID(), buffer.get(), BUFFER_SIZE)) + { + result = std::string(buffer.get()); + } + else + { + SHLOG_ERROR("[ScriptEngine] Failed to serialise scripts as string buffer is too small!"); + } - // Return an empty string since we failed to serialise - return result; + // Return an empty string since we failed to serialise + return result; } /*-----------------------------------------------------------------------------------*/ @@ -152,18 +148,34 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ /* Script Editor Functions */ /*-----------------------------------------------------------------------------------*/ - void SHScriptEngine::RenderScriptsInInspector(const SHEntity& entity) const + void SHScriptEngine::RenderScriptsInInspector(EntityID entity) const { - csEditorRenderScripts(entity.GetEID()); + csEditorRenderScripts(entity); } + void SHScriptEngine::UndoScriptInspectorChanges() const + { + csEditorUndo(); + } + + void SHScriptEngine::RedoScriptInspectorChanges() const + { + csEditorRedo(); + } + /*-----------------------------------------------------------------------------------*/ /* Static Utility Functions */ /*-----------------------------------------------------------------------------------*/ - bool SHScriptEngine::BuildScriptAssembly(bool debug) const + bool SHScriptEngine::BuildScriptAssembly(bool debug, bool reload) { static const std::string BUILD_LOG_PATH = "../Build.log"; + // Unload if we need to reload + if (reload) + { + UnloadScriptAssembly(); + } + // Generate csproj file if it doesn't exist if (!std::filesystem::exists(CSPROJ_PATH)) { @@ -209,6 +221,12 @@ namespace SHADE // Delete the build log file since we no longer need it deleteFile(BUILD_LOG_PATH); + // If reloading, we need to load + if (reload) + { + LoadScriptAssembly(); + } + return BUILD_SUCCESS; } @@ -246,8 +264,8 @@ namespace SHADE \n\ \n\ \n\ - ..\\bin\\Debug\\SHADE_Managed.dll\ - ..\\bin\\Release\\SHADE_Managed.dll\ + ..\\bin\\Debug\\SHADE_Managed.dll\n\ + ..\\bin\\Release\\SHADE_Managed.dll\n\ \n\ \n\ "; @@ -255,7 +273,7 @@ namespace SHADE // Attempt to create the file std::ofstream file(path); if (!file.is_open()) - throw std::runtime_error("Unable to create CsProj file!"); + throw std::runtime_error("Unable to create CsProj file!"); // Fill the file file << FILE_CONTENTS; @@ -269,9 +287,9 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHEventHandle SHScriptEngine::onEntityDestroyed(SHEventPtr eventPtr) { - auto eventData = reinterpret_cast*>(eventPtr.get()); - csScriptsRemoveAll(eventData->data->eid); - return eventData->handle; + auto eventData = reinterpret_cast*>(eventPtr.get()); + csScriptsRemoveAll(eventData->data->eid); + return eventData->handle; } /*-----------------------------------------------------------------------------------*/ @@ -385,13 +403,25 @@ namespace SHADE DEFAULT_CSHARP_LIB_NAME, DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", "SerialiseScriptsYaml" - ); + );*/ csEditorRenderScripts = dotNet.GetFunctionPtr ( DEFAULT_CSHARP_LIB_NAME, DEFAULT_CSHARP_NAMESPACE + ".Editor", "RenderScriptsInInspector" - );*/ + ); + csEditorUndo = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".Editor", + "Undo" + ); + csEditorRedo = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".Editor", + "Redo" + ); } void SHScriptEngine::registerEvents() @@ -512,7 +542,7 @@ namespace SHADE std::wostringstream oss; oss << "dotnet build \"" << SHStringUtils::StrToWstr(CSPROJ_PATH) << "\" -c "; oss << debug ? "Debug" : "Release"; - oss << " -o \"./tmp/\" -fl -flp:LogFile=build.log;Verbosity=quiet"; + oss << " -o \"./tmp/\" -fl -flp:LogFile=build.log;Verbosity=quiet -r \"win-x64\""; return oss.str(); } } diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.h b/SHADE_Engine/src/Scripting/SHScriptEngine.h index 08852e90..239d6b90 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.h +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.h @@ -170,7 +170,15 @@ namespace SHADE /// rendering code. /// /// The Entity to render the Scripts of. - void RenderScriptsInInspector(const SHEntity& entity) const; + void RenderScriptsInInspector(EntityID entity) const; + /// + /// Performs an undo for script inspector changes if it exists. + /// + void UndoScriptInspectorChanges() const; + /// + /// Performs a redo for script inspector changes if it exists. + /// + void RedoScriptInspectorChanges() const; /*-----------------------------------------------------------------------------*/ /* Static Utility Functions */ @@ -184,13 +192,16 @@ namespace SHADE /// Whether or not a debug build will be built. Only debug built C# assemblies /// can be debugged. /// + /// + /// Whether or not we are reloading the assembly, if so, unload and then reload it. + /// /// Whether or not the build succeeded. - bool BuildScriptAssembly(bool debug = false) const; + bool BuildScriptAssembly(bool debug = false, bool reload = false); /// /// Generates a .csproj file for editing and compiling the C# scripts. /// /// File path to the generated file. - void GenerateScriptsCsProjFile(const std::filesystem::path& path) const; + void GenerateScriptsCsProjFile(const std::filesystem::path& path = CSPROJ_PATH) const; private: /*-----------------------------------------------------------------------------*/ @@ -240,9 +251,8 @@ namespace SHADE CsScriptSerialiseYamlFuncPtr csScriptDeserialiseYaml = nullptr; // - Editor CsScriptEditorFuncPtr csEditorRenderScripts = nullptr; - // Delegates - /*ECS::EntityEvent::Delegate onEntityCreate; - ECS::EntityEvent::Delegate onEntityDestroy;*/ + CsFuncPtr csEditorUndo = nullptr; + CsFuncPtr csEditorRedo = nullptr; /*-----------------------------------------------------------------------------*/ /* Event Handler Functions */ diff --git a/SHADE_Engine/src/Tools/SHException.h b/SHADE_Engine/src/Tools/SHException.h index 251217eb..2e0b82a9 100644 --- a/SHADE_Engine/src/Tools/SHException.h +++ b/SHADE_Engine/src/Tools/SHException.h @@ -75,10 +75,13 @@ namespace SHADE }; } -#define SHASSERT(cond, msg) \ - if (!(cond)) \ - { \ - SHLOGV_CRITICAL(msg) \ - std::abort(); \ - } - +#ifdef _DEBUG + #define SHASSERT(cond, msg) \ + if (!(cond)) \ + { \ + SHLOGV_CRITICAL(msg) \ + std::abort(); \ + } +#else + #define SHASSERT(cond, msg) { } +#endif diff --git a/SHADE_Managed/premake5.lua b/SHADE_Managed/premake5.lua index e50e9e86..052be24a 100644 --- a/SHADE_Managed/premake5.lua +++ b/SHADE_Managed/premake5.lua @@ -30,9 +30,15 @@ project "SHADE_Managed" "%{IncludeDir.imguizmo}", "%{IncludeDir.imnodes}", "%{IncludeDir.yamlcpp}", - "%{IncludeDir.RTTR}/include", + "%{IncludeDir.RTTR}/include", + "%{IncludeDir.dotnet}\\include", "%{wks.location}/SHADE_Engine/src" } + + libdirs + { + "%{IncludeDir.RTTR}/lib" + } links { @@ -56,6 +62,12 @@ project "SHADE_Managed" "MultiProcessorCompile" } + disablewarnings + { + "4275" + } + + dependson { "yaml-cpp", @@ -68,7 +80,14 @@ project "SHADE_Managed" filter "configurations:Debug" symbols "On" defines {"_DEBUG"} + links{"librttr_core_d.lib"} filter "configurations:Release" optimize "On" defines{"_RELEASE"} + links{"librttr_core.lib"} + + filter "configurations:Publish" + optimize "On" + defines{"_RELEASE"} + links{"librttr_core.lib"} diff --git a/SHADE_Managed/src/Components/Transform.cxx b/SHADE_Managed/src/Components/Transform.cxx new file mode 100644 index 00000000..0f0716dc --- /dev/null +++ b/SHADE_Managed/src/Components/Transform.cxx @@ -0,0 +1,107 @@ +/************************************************************************************//*! +\file Transform.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 23, 2022 +\brief Contains the definition of the functions of the managed Transform class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "Transform.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Properties */ + /*---------------------------------------------------------------------------------*/ + Vector3 Transform::LocalPosition::get() + { + return Convert::ToCLI(GetNativeComponent()->GetLocalPosition()); + } + void Transform::LocalPosition::set(Vector3 val) + { + GetNativeComponent()->SetLocalPosition(Convert::ToNative(val)); + } + Vector3 Transform::LocalRotation::get() + { + return Convert::ToCLI(GetNativeComponent()->GetLocalRotation()); + } + void Transform::LocalRotation::set(Vector3 val) + { + GetNativeComponent()->SetLocalRotation(Convert::ToNative(val)); + } + Vector3 Transform::LocalScale::get() + { + return Convert::ToCLI(GetNativeComponent()->GetLocalScale()); + + } + void Transform::LocalScale::set(Vector3 val) + { + GetNativeComponent()->SetLocalScale(Convert::ToNative(val)); + } + Vector3 Transform::GlobalPosition::get() + { + return Convert::ToCLI(GetNativeComponent()->GetWorldPosition()); + } + void Transform::GlobalPosition::set(Vector3 val) + { + GetNativeComponent()->SetWorldPosition(Convert::ToNative(val)); + } + Vector3 Transform::GlobalRotation::get() + { + return Convert::ToCLI(GetNativeComponent()->GetWorldRotation()); + } + void Transform::GlobalRotation::set(Vector3 val) + { + GetNativeComponent()->SetWorldRotation(Convert::ToNative(val)); + } + Vector3 Transform::GlobalScale::get() + { + return Convert::ToCLI(GetNativeComponent()->GetWorldScale()); + + } + void Transform::GlobalScale::set(Vector3 val) + { + GetNativeComponent()->SetWorldScale(Convert::ToNative(val)); + } + Transform^ Transform::Parent::get() + { + auto node = SHSceneManager::GetCurrentSceneGraph().GetNode(owner.GetEntity()); + if (!node) + throw gcnew System::InvalidOperationException("[Transform] Unable to retrieve SceneGraphNode for an Entity."); + + const auto PARENT = node->GetParent(); + return PARENT ? gcnew Transform(PARENT->GetEntityID()) : nullptr; + } + + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + Transform::Transform(Entity entity) + : Component(entity) + {} + + /*---------------------------------------------------------------------------------*/ + /* Usage Functions */ + /*---------------------------------------------------------------------------------*/ + + void Transform::SetParent(Transform^ parent, bool worldPositionStays) + { + auto& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); + auto node = sceneGraph.GetNode(owner.GetEntity()); + if (!node) + throw gcnew System::InvalidOperationException("[Transform] Unable to retrieve SceneGraphNode for an Entity."); + + if (parent) + node->SetParent(sceneGraph.GetNode(parent->owner.GetEntity())); + else + sceneGraph.SetParent(parent->owner.GetEntity(), nullptr); + } +} diff --git a/SHADE_Managed/src/Components/Transform.hxx b/SHADE_Managed/src/Components/Transform.hxx new file mode 100644 index 00000000..9efd2927 --- /dev/null +++ b/SHADE_Managed/src/Components/Transform.hxx @@ -0,0 +1,121 @@ +/************************************************************************************//*! +\file Transform.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 23, 2022 +\brief Contains the definition of the managed Transform class with the + declaration of functions for working with it. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Project Includes +#include "Components/Component.hxx" +#include "Math/Vector3.hxx" +#include "Utility/Convert.hxx" +// External Dependencies +#include "Math/Transform/SHTransformComponent.h" + +namespace SHADE +{ + /// + /// CLR version of the the SHADE Engine's TransformComponent. + /// + public ref class Transform : public Component + { + internal: + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Constructs a Transform Component that represents a native Transform component + /// tied to the specified Entity. + /// + /// Entity that this Component will be tied to. + Transform(Entity entity); + + public: + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ + /// + /// Local position stored by this Transform. + /// + property Vector3 LocalPosition + { + Vector3 get(); + void set(Vector3 val); + } + /// + /// Local Z-axis rotation angle stored by this Transform in Radians. + /// + property Vector3 LocalRotation + { + Vector3 get(); + void set(Vector3 val); + } + /// + /// Local scale stored by this Transform. + /// + property Vector3 LocalScale + { + Vector3 get(); + void set(Vector3 val); + } + /// + /// Global position stored by this Transform. + /// + property Vector3 GlobalPosition + { + Vector3 get(); + void set(Vector3 val); + } + /// + /// Global Z-axis rotation angle stored by this Transform in Radians. + /// + property Vector3 GlobalRotation + { + Vector3 get(); + void set(Vector3 val); + } + /// + /// Global scale stored by this Transform. + /// Note that this operation is expensive. + /// + property Vector3 GlobalScale + { + Vector3 get(); + void set(Vector3 val); + } + /// + /// Parent Transform that affects this Transform. + /// + property Transform^ Parent + { + Transform^ get(); + } + + /*-----------------------------------------------------------------------------*/ + /* Usage Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Sets the parent of this Transform component. + /// + /// + /// Entity that contains the Transform component that this Transform will be + /// parented to. If null, unparenting will occur. + /// + /// + /// If true, the transform values of this Transform component will retain their + /// pre-parent-change global transforms. The local transform values will be + /// modified to ensure that the global transforms do not change. + /// + void SetParent(Transform^ parent, bool worldPositionStays); + }; +} + diff --git a/SHADE_Managed/src/Editor/Editor.cxx b/SHADE_Managed/src/Editor/Editor.cxx new file mode 100644 index 00000000..735f8c2c --- /dev/null +++ b/SHADE_Managed/src/Editor/Editor.cxx @@ -0,0 +1,277 @@ +/************************************************************************************//*! +\file Editor.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 27, 2022 +\brief Contains the definition of the functions for the Editor managed + static class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "Editor/Editor.hxx" +// STL Includes +#include +// External Dependencies +#include "Editor/SHEditorUI.h" +// Project Headers +#include "Components/Component.hxx" +#include "Scripts/ScriptStore.hxx" +#include "Utility/Convert.hxx" +#include "Utility/Debug.hxx" +#include "Serialisation/ReflectionUtilities.hxx" +#include "Editor/IconsMaterialDesign.h" +#include "Editor/Command/SHCommandManager.h" +#include "Editor/Command/SHCommand.hpp" + +// Using Directives +using namespace System; +using namespace System::Collections::Generic; + +/*-------------------------------------------------------------------------------------*/ +/* Macro Functions */ +/*-------------------------------------------------------------------------------------*/ +/// +/// Macro expansion that is used in renderFieldInInspector() to check the type of a field +/// named "field" against the specified type and if it matches, retrieves the value of +/// that field from an object named "object" and pass it into the specified SHEditorUI:: +/// function named "FUNC" by casting it into the NATIVE_TYPE specified. +///
+/// This only works for primitive types that have the same types for managed and native. +///
+/// The managed type of the object to edit. +/// The native type of the object to edit. +/// The SHEditorUI:: function to use for editing. +#define RENDER_FIELD(MANAGED_TYPE, NATIVE_TYPE, FUNC) \ +(field->FieldType == MANAGED_TYPE::typeid) \ +{ \ + NATIVE_TYPE val = safe_cast(field->GetValue(object)); \ + NATIVE_TYPE oldVal = val; \ + if (SHEditorUI::FUNC(Convert::ToNative(field->Name), val)) \ + { \ + field->SetValue(object, val); \ + registerUndoAction(object, field, val, oldVal); \ + } \ +} \ +/// +/// Macro expansion that is used in renderFieldInInspector() to check the type of a field +/// named "field" against the specified type and if it matches, retrieves the value of +/// that field from an object named "object" and pass it into the specified SHEditorUI:: +/// function named "FUNC" by casting it into the NATIVE_TYPE specified. +///
+/// This only works for types that have an implementation of Convert::ToNative and +/// Convert::ToCLI. +///
+/// The managed type of the object to edit. +/// The native type of the object to edit. +/// The SHEditorUI:: function to use for editing. +#define RENDER_FIELD_CASTED(MANAGED_TYPE, NATIVE_TYPE, FUNC) \ +(field->FieldType == MANAGED_TYPE::typeid) \ +{ \ + NATIVE_TYPE val = Convert::ToNative(safe_cast(field->GetValue(object))); \ + NATIVE_TYPE oldVal = val; \ + if (SHEditorUI::FUNC(Convert::ToNative(field->Name), val)) \ + { \ + field->SetValue(object, Convert::ToCLI(val)); \ + registerUndoAction(object, field, Convert::ToCLI(val), Convert::ToCLI(oldVal)); \ + } \ +} \ + +/*-------------------------------------------------------------------------------------*/ +/* Function Definitions */ +/*-------------------------------------------------------------------------------------*/ +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Script Rendering Functions */ + /*---------------------------------------------------------------------------------*/ + void Editor::RenderScriptsInInspector(Entity entity) + { + SAFE_NATIVE_CALL_BEGIN + // Get scripts + IEnumerable^ scripts = ScriptStore::GetAllScripts(entity); + + // Skip if no scripts + if (scripts != nullptr) + { + // Display each script if any + int index = 0; + for each (Script^ script in scripts) + { + renderScriptInInspector(entity, script, index++); + } + } + + // Render Add Script + RenderScriptAddButton(entity); + SAFE_NATIVE_CALL_END_N("SHADE_Managed.Editor.RenderScriptsInInspector") + } + + void Editor::RenderScriptAddButton(Entity entity) + { + // Get list of Scripts + auto scriptTypes = ScriptStore::GetAvailableScriptList(); + + // Define pop up + if (SHEditorUI::BeginMenu("Add Script", ICON_MD_LIBRARY_ADD)) + { + for each (Type ^ type in scriptTypes) + { + if (SHEditorUI::Selectable(Convert::ToNative(type->Name))) + { + // Add the script + ScriptStore::AddScriptViaName(entity, type->Name); + } + } + + SHEditorUI::EndMenu(); + } + } + + /*---------------------------------------------------------------------------------*/ + /* UndoRedoStack Functions */ + /*---------------------------------------------------------------------------------*/ + void Editor::Undo() + { + SAFE_NATIVE_CALL_BEGIN + actionStack.Undo(); + SAFE_NATIVE_CALL_END_N("SHADE_Managed.Editor.Undo") + } + + void Editor::Redo() + { + SAFE_NATIVE_CALL_BEGIN + actionStack.Redo(); + SAFE_NATIVE_CALL_END_N("SHADE_Managed.Editor.Redo") + } + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + void Editor::renderScriptInInspector(Entity entity, Script^ script, int index) + { + // Constants + const std::string LABEL = Convert::ToNative(script->GetType()->Name); + + // Header + SHEditorUI::PushID(index); + if (SHEditorUI::CollapsingHeader(LABEL)) + { + SHEditorUI::PushID(LABEL); + SHEditorUI::Indent(); + { + // Right Click Menu + renderScriptContextMenu(entity, script); + + // Go through all fields and output them + auto fields = ReflectionUtilities::GetInstanceFields(script); + int id = 0; + for each (auto field in fields) + { + // Ignore non-serialisable fields + if (!ReflectionUtilities::FieldIsSerialisable(field)) + continue; + + // Render the input field for this field + SHEditorUI::PushID(LABEL + std::to_string(id++)); + renderFieldInInspector(field, script); + SHEditorUI::PopID(); + } + + } + SHEditorUI::Unindent(); + SHEditorUI::PopID(); + } + else + { + renderScriptContextMenu(entity, script); + } + SHEditorUI::PopID(); + } + void Editor::renderFieldInInspector(Reflection::FieldInfo^ field, Object^ object) + { + if RENDER_FIELD (Int16, int, InputInt) + else if RENDER_FIELD (Int32, int, InputInt) + else if RENDER_FIELD (Int64, int, InputInt) + else if RENDER_FIELD (UInt16, unsigned int, InputUnsignedInt) + else if RENDER_FIELD (UInt32, unsigned int, InputUnsignedInt) + else if RENDER_FIELD (UInt64, unsigned int, InputUnsignedInt) + else if RENDER_FIELD (Byte, int, InputInt) + else if RENDER_FIELD (bool, bool, InputCheckbox) + else if RENDER_FIELD (float, float, InputFloat) + else if RENDER_FIELD (double, double, InputDouble) + else if (field->FieldType->IsSubclassOf(Enum::typeid)) + { + // Get all the names of the enums + const array^ ENUM_NAMES = field->FieldType->GetEnumNames(); + std::vector nativeEnumNames; + for each (String^ str in ENUM_NAMES) + { + nativeEnumNames.emplace_back(Convert::ToNative(str)); + } + + int val = safe_cast(field->GetValue(object)); + int oldVal = val; + if (SHEditorUI::InputEnumCombo(Convert::ToNative(field->Name), val, nativeEnumNames)) + { + field->SetValue(object, val); + registerUndoAction(object, field, val, oldVal); + } + } + else if RENDER_FIELD_CASTED(Vector2, SHVec2, InputVec2) + else if RENDER_FIELD_CASTED(Vector3, SHVec3, InputVec3) + else if (field->FieldType == String::typeid) + { + // Prevent issues where String^ is null due to being empty + String^ stringVal = safe_cast(field->GetValue(object)); + if (stringVal == nullptr) + { + stringVal = ""; + } + + // Actual Field + std::string val = Convert::ToNative(stringVal); + std::string oldVal = val; + if (SHEditorUI::InputTextField(Convert::ToNative(field->Name), val)) + { + field->SetValue(object, Convert::ToCLI(val)); + registerUndoAction(object, field, Convert::ToCLI(val), Convert::ToCLI(oldVal)); + } + } + } + + void Editor::renderScriptContextMenu(Entity entity, Script^ script) + { + // Right Click Menu + if (SHEditorUI::BeginPopupContextItem("scriptContextMenu")) + { + if (SHEditorUI::Selectable("Delete Script", ICON_MD_DELETE)) + { + // Mark script for removal + ScriptStore::RemoveScript(entity, script); + } + SHEditorUI::EndPopup(); + } + } + + void Editor::registerUndoAction(System::Object^ object, System::Reflection::FieldInfo^ field, System::Object^ newData, System::Object^ oldData) + { + // Create command and add it into the undo stack + UndoRedoStack::Command cmd; + cmd.Field = field; + cmd.Object = object; + cmd.NewData = newData; + cmd.OldData = oldData; + actionStack.Add(cmd); + + // Inform the C++ Undo-Redo stack + SHCommandManager::RegisterCommand(std::reinterpret_pointer_cast(std::make_shared())); + } + +} diff --git a/SHADE_Managed/src/Editor/Editor.hxx b/SHADE_Managed/src/Editor/Editor.hxx new file mode 100644 index 00000000..c4800645 --- /dev/null +++ b/SHADE_Managed/src/Editor/Editor.hxx @@ -0,0 +1,90 @@ +/************************************************************************************//*! +\file Editor.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 27, 2022 +\brief Contains the definition of the managed Editor static class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Project Includes +#include "Engine/Entity.hxx" +#include "Scripts/Script.hxx" +#include "UndoRedoStack.hxx" + +namespace SHADE +{ + /// + /// Static class for Editor-related functions + /// + public ref class Editor abstract sealed + { + public: + /*-----------------------------------------------------------------------------*/ + /* Script Rendering Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Renders the set of attached Scripts for the specified Entity into the + /// inspector. + ///
+ /// This function is meant for consumption from native code in the inspector + /// rendering code. + ///
+ /// The Entity to render the Scripts of. + static void RenderScriptsInInspector(Entity entity); + /// + /// Renders a dropdown button that allows for the addition of PlushieScripts + /// onto the specified Entity. + /// + /// The Entity to add PlushieScripts to. + static void RenderScriptAddButton(Entity entity); + + /*-----------------------------------------------------------------------------*/ + /* UndoRedoStack Functions */ + /*-----------------------------------------------------------------------------*/ + static void Undo(); + static void Redo(); + + private: + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + static UndoRedoStack actionStack; + + /*-----------------------------------------------------------------------------*/ + /* Helper Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Renders a single specified Script's inspector. + /// + /// The Entity to render the Scripts of. + /// The Script to render the inspector for. + /// + /// Indices used internally to differentiate each rendered Script + /// inspector. This is required to open and close each Script's inspector + /// independently from each other. + /// + static void renderScriptInInspector(Entity entity, Script^ script, int index); + /// + /// Renders a field specified into the inspector. + /// + /// The field to render. + /// + /// The object that contains the data of the field to render. + /// + static void renderFieldInInspector(System::Reflection::FieldInfo^ field, Object^ object); + /// + /// Renders a context menu when right clicked for the scripts + /// + /// The Entity to render the Scripts of. + /// The Script to render the inspector for. + static void renderScriptContextMenu(Entity entity, Script^ script); + static void registerUndoAction(System::Object^ object, System::Reflection::FieldInfo^ field, System::Object^ newData, System::Object^ oldData); + }; +} diff --git a/SHADE_Managed/src/Editor/UndoRedoStack.cxx b/SHADE_Managed/src/Editor/UndoRedoStack.cxx new file mode 100644 index 00000000..08e289cc --- /dev/null +++ b/SHADE_Managed/src/Editor/UndoRedoStack.cxx @@ -0,0 +1,69 @@ +/************************************************************************************//*! +\file UndoRedoStack.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 29, 2022 +\brief Contains the definition of the functions for the UndoRedoStack managed + class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "UndoRedoStack.hxx" +// External Dependencies +#include "Editor/SHEditorUI.h" +// Project Headers + +namespace SHADE +{ + bool UndoRedoStack::UndoActionPresent::get() + { + return commandStack->Count > 0 && latestActionIndex >= 0; + } + + bool UndoRedoStack::RedoActionPresent::get() + { + return latestActionIndex >= 0 && latestActionIndex < commandStack->Count - 1; + } + + void UndoRedoStack::Add(Command command) + { + // Erase any other actions ahead of the current action + if (latestActionIndex >= 0 && latestActionIndex < commandStack->Count - 1) + { + commandStack->RemoveRange(latestActionIndex, commandStack->Count - latestActionIndex); + } + + // Add the command + commandStack->Add(command); + + // Set the latest command + latestActionIndex = commandStack->Count - 1; + } + + void UndoRedoStack::Undo() + { + if (!UndoActionPresent) + return; + + Command cmd = commandStack[latestActionIndex]; + cmd.Field->SetValue(cmd.Object, cmd.OldData); + --latestActionIndex; + } + + void UndoRedoStack::Redo() + { + if (!RedoActionPresent) + return; + + Command cmd = commandStack[latestActionIndex]; + cmd.Field->SetValue(cmd.Object, cmd.NewData); + ++latestActionIndex; + } +} diff --git a/SHADE_Managed/src/Editor/UndoRedoStack.hxx b/SHADE_Managed/src/Editor/UndoRedoStack.hxx new file mode 100644 index 00000000..4c525228 --- /dev/null +++ b/SHADE_Managed/src/Editor/UndoRedoStack.hxx @@ -0,0 +1,75 @@ +/************************************************************************************//*! +\file UndoRedoStack.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 29, 2022 +\brief Contains the definition of the managed UndoRedoStack class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +namespace SHADE +{ + /// + /// Class that is able to store a stack of actions that can be done and redone. + /// + private ref class UndoRedoStack sealed + { + public: + /*-----------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Command for the stack that represents a data modification. + /// + value struct Command + { + public: + System::Object^ Object; + System::Reflection::FieldInfo^ Field; + System::Object^ NewData; + System::Object^ OldData; + }; + + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ + /// + /// True if there is an undoable action in the stack. + /// + property bool UndoActionPresent { bool get(); } + /// + /// True if there is a redoable action in the stack. + /// + property bool RedoActionPresent { bool get(); } + + /*-----------------------------------------------------------------------------*/ + /* Usage Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Adds a command onto the stack. + /// + /// + void Add(Command command); + /// + /// Undos the last added command if it exists. + /// + void Undo(); + /// + /// Redoes the last undo-ed command if it exists. + /// + void Redo(); + + private: + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + int latestActionIndex = -1; + System::Collections::Generic::List^ commandStack = gcnew System::Collections::Generic::List(); + }; +} diff --git a/SHADE_Managed/src/Engine/ECS.cxx b/SHADE_Managed/src/Engine/ECS.cxx index 36bef851..4d62f643 100644 --- a/SHADE_Managed/src/Engine/ECS.cxx +++ b/SHADE_Managed/src/Engine/ECS.cxx @@ -21,12 +21,14 @@ of DigiPen Institute of Technology is prohibited. #include // External Dependencies #include "ECS_Base/Managers/SHEntityManager.h" +#include "Math/Transform/SHTransformComponent.h" #include "Scene/SHSceneManager.h" #include "Scene/SHSceneGraph.h" #include "Tools/SHLog.h" // Project Headers #include "Utility/Convert.hxx" #include "Utility/Debug.hxx" +#include "Components/Transform.hxx" namespace SHADE { @@ -239,8 +241,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ static ECS::ECS() { - // TODO - // componentMap.Add(createComponentSet()); + componentMap.Add(createComponentSet()); } /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Engine/ECS.h++ b/SHADE_Managed/src/Engine/ECS.h++ index daaa859f..f2588294 100644 --- a/SHADE_Managed/src/Engine/ECS.h++ +++ b/SHADE_Managed/src/Engine/ECS.h++ @@ -28,15 +28,8 @@ namespace SHADE template NativeComponent* ECS::GetNativeComponent(Entity entity) { - // Get native Entity - SHEntity* nativeEntity = SHEntityManager::GetEntityByID(entity); - - // Entity Validity Check - if (nativeEntity == nullptr) - throw gcnew System::InvalidOperationException("Attempted to get native Component to an invalid Entity."); - // Null Check - NativeComponent* component = SHComponentManager::GetComponent_s(nativeEntity); + NativeComponent* component = SHComponentManager::GetComponent_s(entity); if (component == nullptr) throw gcnew System::NullReferenceException("Attempted to get a native Component that does not exist."); @@ -52,7 +45,6 @@ namespace SHADE { ManagedType::typeid, SHComponentManager::AddComponent, - SHComponentManager::EnsureComponent, SHComponentManager::HasComponent, SHComponentManager::RemoveComponent }; diff --git a/SHADE_Managed/src/Engine/ECS.hxx b/SHADE_Managed/src/Engine/ECS.hxx index da73f14c..0563f678 100644 --- a/SHADE_Managed/src/Engine/ECS.hxx +++ b/SHADE_Managed/src/Engine/ECS.hxx @@ -99,8 +99,8 @@ namespace SHADE /// /// Pointer to a function for Component manipulation operations. /// - using ComponentFunc = void(*)(const EntityID&); - using ComponentHasFunc = bool(*)(const EntityID&); + using ComponentFunc = void(*)(EntityID) noexcept; + using ComponentHasFunc = bool(*)(EntityID) noexcept; /// /// Contains a set of Component related data used for resolving operations for /// each Component. @@ -108,11 +108,10 @@ namespace SHADE value struct ComponentSet { public: - System::Type^ Type; + System::Type^ Type; ComponentFunc AddFunction; ComponentHasFunc HasFunction; ComponentFunc RemoveFunction; - }; /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Utility/Convert.cxx b/SHADE_Managed/src/Utility/Convert.cxx index d222fbb3..661eb3e4 100644 --- a/SHADE_Managed/src/Utility/Convert.cxx +++ b/SHADE_Managed/src/Utility/Convert.cxx @@ -17,8 +17,8 @@ of DigiPen Institute of Technology is prohibited. // Primary Header #include "Convert.hxx" // External Dependencies -#include "ECS_Base/Managers/SHEntityManager.h" #include +#include "ECS_Base/Managers/SHEntityManager.h" namespace SHADE { @@ -30,6 +30,32 @@ namespace SHADE return static_cast(entity.GetEID()); } + /*---------------------------------------------------------------------------------*/ + /* Math Conversions */ + /*---------------------------------------------------------------------------------*/ + SHVec3 Convert::ToNative(Vector3 vec) + { + const double X = vec.x; + const double Y = vec.y; + const double Z = vec.z; + return SHVec3(X, Y, Z); + } + Vector3 Convert::ToCLI(const SHVec3& vec) + { + return Vector3(vec.x, vec.y, vec.z); + } + SHVec2 Convert::ToNative(Vector2 vec) + { + const double X = vec.x; + const double Y = vec.y; + return SHVec2(X, Y); + } + + Vector2 Convert::ToCLI(const SHVec2& vec) + { + return Vector2(vec.x, vec.y); + } + /*---------------------------------------------------------------------------------*/ /* String Conversions */ /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Utility/Convert.hxx b/SHADE_Managed/src/Utility/Convert.hxx index 241e5863..b41ffef4 100644 --- a/SHADE_Managed/src/Utility/Convert.hxx +++ b/SHADE_Managed/src/Utility/Convert.hxx @@ -16,8 +16,12 @@ of DigiPen Institute of Technology is prohibited. // External Dependencies #include "ECS_Base/Entity/SHEntity.h" +#include "Math/Vector/SHVec2.h" +#include "Math/Vector/SHVec3.h" // Project Includes #include "Engine/Entity.hxx" +#include "Math/Vector2.hxx" +#include "Math/Vector3.hxx" namespace SHADE { @@ -43,6 +47,34 @@ namespace SHADE /// Managed representation of the specified Entity. static Entity ToCLI(SHEntity entity); + /*-----------------------------------------------------------------------------*/ + /* Math Conversions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Converts from a managed Vector3 to a native Vector3. + /// + /// The managed Vector3 to convert from. + /// Native copy of a managed Vector3. + static SHVec3 ToNative(Vector3 vec); + /// + /// Converts from a native Vector3 to a managed Vector3. + /// + /// The native Vector3 to convert from. + /// Managed copy of a native Vector3. + static Vector3 ToCLI(const SHVec3& vec); + /// + /// Converts from a managed Vector2 to a native Vector2. + /// + /// The managed Vector2 to convert from. + /// Native copy of a managed Vector2. + static SHVec2 ToNative(Vector2 vec); + /// + /// Converts from a native Vector2 to a managed Vector2. + /// + /// The native Vector2 to convert from. + /// Managed copy of a native Vector2. + static Vector2 ToCLI(const SHVec2& vec); + /*-----------------------------------------------------------------------------*/ /* String Conversions */ /*-----------------------------------------------------------------------------*/ diff --git a/TempScriptsFolder/RaccoonShowcase.cs b/TempScriptsFolder/RaccoonShowcase.cs new file mode 100644 index 00000000..e2d6454d --- /dev/null +++ b/TempScriptsFolder/RaccoonShowcase.cs @@ -0,0 +1,31 @@ +using SHADE; +using System; + +public class RaccoonShowcase : Script +{ + public double RotateSpeed = 1.0; + public Vector3 ScaleSpeed = new Vector3(1.0, 1.0, 0.0); + private Transform Transform; + private double rotation = 0.0; + private Vector3 scale = Vector3.Zero; + private double originalScale = 1.0f; + public RaccoonShowcase(GameObject gameObj) : base(gameObj) {} + + protected override void awake() + { + Transform = GetComponent(); + if (Transform == null) + { + Debug.LogError("Transform is NULL!"); + } + + originalScale = Transform.LocalScale.z; + } + protected override void update() + { + rotation += RotateSpeed * 0.16; + scale += ScaleSpeed * 0.16; + Transform.LocalRotation = new Vector3(0.0f, rotation, 0.0f); + Transform.LocalScale = new Vector3(System.Math.Abs(System.Math.Sin(scale.x)) * originalScale, System.Math.Abs(System.Math.Cos(scale.y)) * originalScale, System.Math.Abs(System.Math.Sin(scale.z)) * originalScale); + } +} \ No newline at end of file diff --git a/TempScriptsFolder/RaccoonSpin.cs b/TempScriptsFolder/RaccoonSpin.cs new file mode 100644 index 00000000..7785cfd5 --- /dev/null +++ b/TempScriptsFolder/RaccoonSpin.cs @@ -0,0 +1,24 @@ +using SHADE; +using System; + +public class RaccoonSpin : Script +{ + public double RotateSpeed = 1.0; + private double rotation = 0.0; + private Transform Transform; + public RaccoonSpin(GameObject gameObj) : base(gameObj) { } + + protected override void awake() + { + Transform = GetComponent(); + if (Transform == null) + { + Debug.LogError("Transform is NULL!"); + } + } + protected override void update() + { + rotation += RotateSpeed * 0.16; + Transform.LocalRotation = new Vector3(0.0f, rotation, 0.0f); + } +} \ No newline at end of file diff --git a/TempScriptsFolder/TestScript.cs b/TempScriptsFolder/TestScript.cs deleted file mode 100644 index c1ed5bd5..00000000 --- a/TempScriptsFolder/TestScript.cs +++ /dev/null @@ -1,23 +0,0 @@ -using SHADE; - -public class TestScript : Script -{ - public TestScript(GameObject gameObj) : base(gameObj) {} - - protected override void awake() - { - Debug.Log("TestScript.Awake()"); - } - protected override void start() - { - Debug.Log("TestScript.Start()"); - } - protected override void update() - { - Debug.Log("TestScript.Update()"); - } - protected override void onDestroy() - { - Debug.Log("TestScript.OnDestroy()"); - } -} \ No newline at end of file diff --git a/TempShaderFolder/TestCubeFs.glsl b/TempShaderFolder/TestCubeFs.glsl index 7d49eda4..3a25ad71 100644 --- a/TempShaderFolder/TestCubeFs.glsl +++ b/TempShaderFolder/TestCubeFs.glsl @@ -1,72 +1,44 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable +#extension GL_EXT_nonuniform_qualifier : require + +struct MatPropData +{ + vec4 color; + int textureIndex; + float alpha; + vec3 beta; +}; layout(location = 0) in struct { - //mat3 BTN; vec4 vertColor; - //vec3 localSpacePosition; - //vec2 uv; - //vec3 localLightPosition; - //vec3 localEyePosition; + vec2 uv; } In; -//layout(std140, push_constant) uniform TestPushConstant -//{ -// mat4 pvMat; -// vec4 lightPosition; -// vec4 eyePosition; -// vec4 ambientColor; -// vec4 lightColor; -// -//} testPushConstant; +// material stuff +layout(location = 2) flat in struct +{ + int materialIndex; +} In2; + +//layout (set = 0, binding = ) + +layout (set = 0, binding = 1) uniform sampler2D textures[]; // for textures (global) +layout (set = 3, binding = 0) buffer MaterialProperties // For materials +{ + MatPropData data[]; +} MatProp; layout(location = 0) out vec4 outColor; -//layout(binding = 0) uniform sampler2D diffuseMap; -//layout(binding = 1) uniform sampler2D normalMap; -//layout(binding = 2) uniform sampler2D aoMap; -//layout(binding = 3) uniform sampler2D glossinessMap; -//layout(binding = 4) uniform sampler2D samplerRoughnessMap; - void main() { - //vec3 normal; - //// Get the tangent space normal from normal map. It is a BC5 texture and therefore only use red and green - //normal.xy = (texture (normalMap, In.uv).gr * 2.0f) - 1.0f; + outColor = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) + + MatProp.data[In2.materialIndex].color / MatProp.data[In2.materialIndex].alpha; - //// z value is derived (TODO: Find out what this does) - //normal.z = sqrt(1.0f - dot(normal.xy, normal.xy)); - - //// Transform the normal from tangent space to local space - //normal = In.BTN * normal; - - //// Get the vector from fragment to light - //vec3 localLightDir = normalize(In.localLightPosition - In.localSpacePosition); - - //// get the value of dot between normal from texture and frag to light - //float diffuse = max(0, dot(normal, localLightDir)); - - //// sample the diffuse texture - //vec4 diffuseColor = texture (diffuseMap, In.uv) * In.vertColor; - - //vec3 eyeDirection = normalize(In.localSpacePosition - In.localEyePosition); - - //const float shininess = mix(1, 100, 1 - texture (samplerRoughnessMap, In.uv).r); - - //float specular = pow(max(0, dot(normal, normalize(localLightDir - eyeDirection))), shininess); - - //outColor.rgb = testPushConstant.ambientColor.rgb * diffuseColor.rgb * texture (aoMap, In.uv).rgb; - - //outColor.rgb += testPushConstant.lightColor.rgb * (specular.rrr * 0.4 + diffuse.rrr * diffuseColor.rgb); - - //const float gamma = testPushConstant.eyePosition.w; - //outColor.rgb = pow(outColor.rgb, vec3(1.0f / gamma)); - //outColor.a = diffuseColor.a; - - - outColor = vec4 (1.0f); + //outColor = vec4 (1.0f); } \ No newline at end of file diff --git a/TempShaderFolder/TestCubeFs.spv b/TempShaderFolder/TestCubeFs.spv index 669dc8b8..07f67a45 100644 Binary files a/TempShaderFolder/TestCubeFs.spv and b/TempShaderFolder/TestCubeFs.spv differ diff --git a/TempShaderFolder/TestCubeVs.glsl b/TempShaderFolder/TestCubeVs.glsl index b2d52104..eb5b2dff 100644 --- a/TempShaderFolder/TestCubeVs.glsl +++ b/TempShaderFolder/TestCubeVs.glsl @@ -9,27 +9,20 @@ layout(location = 2) in vec3 aNormal; layout(location = 3) in vec3 aTangent; layout(location = 4) in mat4 worldTransform; -//layout(std140, push_constant) uniform TestPushConstant -//{ -// mat4 pvMat; -// vec4 lightPosition; -// vec4 eyePosition; -// vec4 ambientColor; -// vec4 lightColor; -// -//} testPushConstant; layout(location = 0) out struct { - //mat3 BTN; - vec4 vertColor; - //vec3 localSpacePosition; - //vec2 uv; - //vec3 localLightPosition; - //vec3 localEyePosition; + vec4 vertColor; // location 0 + vec2 uv; // location = 1 } Out; +// material stuff +layout(location = 2) out struct +{ + int materialIndex; +} Out2; + layout(set = 2, binding = 0) uniform CameraData { vec4 position; @@ -38,25 +31,8 @@ layout(set = 2, binding = 0) uniform CameraData void main() { - //const float gamma = testPushConstant.eyePosition.w; - //mat4 W2L = inverse(worldTransform); - - //// Since attributes are instanced we want the local positions of light and eye (camera) - //Out.localLightPosition = vec3(W2L * vec4(testPushConstant.lightPosition.xyz, 1.0f)); - //Out.localEyePosition = vec3(W2L * vec4(testPushConstant.eyePosition.xyz, 1.0f)); - - //vec3 biTangent = normalize(cross(aNormal, aTangent)); - - //gl_Position = testPushConstant.pvMat * worldTransform * vec4(aVertexPos, 1.0); - - //// Since the normal we are sampling is in tangent space, we want to later convert them to local space - //// so we need this matrix to multiply with the sampled texel of the normal map. - //Out.BTN = mat3(aTangent, biTangent, aNormal); - //Out.localSpacePosition = aVertexPos; - //Out.uv = aUV; - - // render NDC first - //gl_Position = vec4(aVertexPos, 1.0f); + Out.uv = aUV; + Out2.materialIndex = gl_InstanceIndex; gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f); Out.vertColor = vec4 (aVertexPos, 1.0f); } \ No newline at end of file diff --git a/TempShaderFolder/TestCubeVs.spv b/TempShaderFolder/TestCubeVs.spv index eb9a1209..dfc9eda1 100644 Binary files a/TempShaderFolder/TestCubeVs.spv and b/TempShaderFolder/TestCubeVs.spv differ