diff --git a/.gitignore b/.gitignore index 1110510c..5d998cfd 100644 --- a/.gitignore +++ b/.gitignore @@ -362,3 +362,5 @@ MigrationBackup/ *.csproj *.filters + +Assets/Editor/Layouts/UserLayout.ini diff --git a/Assets/Cube.003.shmesh.shmeta b/Assets/Cube.003.shmesh.shmeta new file mode 100644 index 00000000..207f3999 --- /dev/null +++ b/Assets/Cube.003.shmesh.shmeta @@ -0,0 +1,3 @@ +Name: Cube.003 +ID: 110152941 +Type: 6 diff --git a/Assets/Cube.012.shmesh.shmeta b/Assets/Cube.012.shmesh.shmeta new file mode 100644 index 00000000..3af04f93 --- /dev/null +++ b/Assets/Cube.012.shmesh.shmeta @@ -0,0 +1,3 @@ +Name: Cube.012 +ID: 107348815 +Type: 6 diff --git a/Assets/Editor/Fonts/fa-solid-900.ttf b/Assets/Editor/Fonts/fa-solid-900.ttf new file mode 100644 index 00000000..f89fc9f8 Binary files /dev/null and b/Assets/Editor/Fonts/fa-solid-900.ttf differ diff --git a/Assets/Editor/Layouts/Default.ini b/Assets/Editor/Layouts/Default.ini new file mode 100644 index 00000000..4ddc46c2 --- /dev/null +++ b/Assets/Editor/Layouts/Default.ini @@ -0,0 +1,48 @@ +[Window][MainStatusBar] +Pos=0,1060 +Size=1920,20 +Collapsed=0 + +[Window][SHEditorMenuBar] +Pos=0,24 +Size=1920,1036 +Collapsed=0 + +[Window][Hierarchy Panel] +Pos=0,120 +Size=225,940 +Collapsed=0 +DockId=0x00000004,0 + +[Window][Debug##Default] +Pos=60,60 +Size=400,400 +Collapsed=0 + +[Window][Inspector] +Pos=1686,24 +Size=234,1036 +Collapsed=0 +DockId=0x00000006,0 + +[Window][Profiler] +Pos=0,24 +Size=225,94 +Collapsed=0 +DockId=0x00000003,0 + +[Window][Viewport] +Pos=227,24 +Size=1457,1036 +Collapsed=0 +DockId=0x00000002,0 + +[Docking][Data] +DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,55 Size=1920,1036 Split=X + DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1684,1036 Split=X + DockNode ID=0x00000001 Parent=0x00000005 SizeRef=225,1036 Split=Y Selected=0x1E6EB881 + DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881 + DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Selected=0xE096E5AE + DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1293,1036 CentralNode=1 Selected=0x13926F0B + DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=234,1036 Selected=0xE7039252 + diff --git a/Assets/Editor/Layouts/UserLayout.ini b/Assets/Editor/Layouts/UserLayout.ini new file mode 100644 index 00000000..baced6b8 --- /dev/null +++ b/Assets/Editor/Layouts/UserLayout.ini @@ -0,0 +1,54 @@ +[Window][MainStatusBar] +Pos=0,1060 +Size=1920,20 +Collapsed=0 + +[Window][SHEditorMenuBar] +Pos=0,48 +Size=1920,1012 +Collapsed=0 + +[Window][Hierarchy Panel] +Pos=0,142 +Size=387,918 +Collapsed=0 +DockId=0x00000004,0 + +[Window][Debug##Default] +Pos=60,60 +Size=400,400 +Collapsed=0 + +[Window][Inspector] +Pos=1649,48 +Size=271,1012 +Collapsed=0 +DockId=0x00000006,0 + +[Window][Profiler] +Pos=0,48 +Size=387,92 +Collapsed=0 +DockId=0x00000003,0 + +[Window][Viewport] +Pos=648,48 +Size=2519,1319 +Collapsed=0 +DockId=0x00000002,0 + +[Window][ Viewport] +Pos=389,48 +Size=1258,1012 +Collapsed=0 +DockId=0x00000002,0 + +[Docking][Data] +DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,79 Size=1920,1012 Split=X + DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1992,1036 Split=X + DockNode ID=0x00000001 Parent=0x00000005 SizeRef=387,1036 Split=Y Selected=0x1E6EB881 + DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881 + DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Selected=0xE096E5AE + DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1258,1036 CentralNode=1 Selected=0xB41284E7 + DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=271,1036 Selected=0xE7039252 + diff --git a/Assets/RaccoonPreTexturedVer1_Base9.shtex.shmeta b/Assets/RaccoonPreTexturedVer1_Base9.shtex.shmeta new file mode 100644 index 00000000..3905aa4f --- /dev/null +++ b/Assets/RaccoonPreTexturedVer1_Base9.shtex.shmeta @@ -0,0 +1,3 @@ +Name: RaccoonPreTexturedVer1_Base9 +ID: 91918845 +Type: 4 diff --git a/SHADE_Application/premake5.lua b/SHADE_Application/premake5.lua index 35ea2c10..395c3a48 100644 --- a/SHADE_Application/premake5.lua +++ b/SHADE_Application/premake5.lua @@ -37,7 +37,8 @@ project "SHADE_Application" "%{IncludeDir.VULKAN}/include", "%{IncludeDir.spdlog}/include", "%{IncludeDir.tinyddsloader}", - "%{IncludeDir.reactphysics3d}\\include" + "%{IncludeDir.reactphysics3d}\\include", + "%{IncludeDir.yamlcpp}" } externalwarnings "Off" @@ -51,6 +52,7 @@ project "SHADE_Application" { "SHADE_Engine", "SHADE_Managed", + "yaml-cpp", "SDL2.lib", "SDL2main.lib" } diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 202a3852..a93148d5 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -30,6 +30,7 @@ #include "Input/SHInputManager.h" #include "FRC/SHFramerateController.h" #include "AudioSystem/SHAudioSystem.h" +#include "Camera/SHCameraSystem.h" // Components #include "Graphics/MiddleEnd/Interface/SHRenderable.h" @@ -67,6 +68,7 @@ namespace Sandbox SHSystemManager::CreateSystem(); SHGraphicsSystem* graphicsSystem = static_cast(SHSystemManager::GetSystem()); SHSystemManager::CreateSystem(); + SHSystemManager::CreateSystem(); #ifdef SHEDITOR SDL_Init(SDL_INIT_VIDEO); @@ -81,14 +83,19 @@ namespace Sandbox SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); + SHSystemManager::RegisterRoutine(); + SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); - SHSystemManager::RegisterRoutine(); + SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); + + SHSystemManager::RegisterRoutine(); + SHSystemManager::RegisterRoutine(); #ifdef SHEDITOR SHSystemManager::RegisterRoutine(); @@ -101,13 +108,14 @@ namespace Sandbox SHComponentManager::CreateComponentSparseSet(); SHComponentManager::CreateComponentSparseSet(); SHComponentManager::CreateComponentSparseSet(); + SHComponentManager::CreateComponentSparseSet(); //TODO: REMOVE AFTER PRESENTATION //SHAssetManager::LoadDataTemp("../../Assets/racoon.gltf"); - SHAssetManager::LoadDataTemp("../../Assets/Cube.012.shmesh"); + //SHAssetManager::LoadDataTemp("../../Assets/Cube.012.shmesh"); //SHAssetManager::LoadDataTemp("../../Assets/RaccoonBag_Color_Ver4.dds"); //SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.dds"); - SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.shtex"); + //SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.shtex"); //TODO: REMOVE AFTER PRESENTATION @@ -125,23 +133,29 @@ namespace Sandbox SHSceneManager::InitSceneManager("TestScene"); SHFrameRateController::UpdateFRC(); + + SHAssetManager::Load(); } void SBApplication::Update(void) { SHGraphicsSystem* graphicsSystem = SHADE::SHSystemManager::GetSystem(); + SHEditor* editor = SHADE::SHSystemManager::GetSystem(); //TODO: Change true to window is open while (!window.WindowShouldClose()) { SHFrameRateController::UpdateFRC(); SHInputManager::UpdateInput(SHFrameRateController::GetRawDeltaTime()); SHSceneManager::UpdateSceneManager(); - SHSceneManager::SceneUpdate(0.016f); - SHSystemManager::RunRoutines(false, 0.016f); +#ifdef SHEDITOR + if(editor->editorState == SHEditor::State::PLAY) + SHSceneManager::SceneUpdate(0.016f); +#endif + SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, 0.016f); + //editor->PollPicking(); } - // Finish all graphics jobs first - graphicsSystem->AwaitGraphicsExecution(); + graphicsSystem->AwaitGraphicsExecution(); } @@ -154,6 +168,7 @@ namespace Sandbox SHSceneManager::Exit(); SHSystemManager::Exit(); + SHAssetManager::Unload(); } } diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index f1d656ee..ad886aa8 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -1,4 +1,4 @@ -#include "SBpch.h" + #include "SBpch.h" #include "SBTestScene.h" #include "ECS_Base/Managers/SHSystemManager.h" @@ -14,6 +14,8 @@ #include "Physics/Components/SHColliderComponent.h" #include "Assets/SHAssetManager.h" +#include "Camera/SHCameraComponent.h" +#include "Resource/SHResourceManager.h" using namespace SHADE; @@ -40,34 +42,22 @@ namespace Sandbox const auto CUBE_MESH = SHADE::SHPrimitiveGenerator::Cube(*graphicsSystem); //Test Racoon mesh - auto meshes = SHADE::SHAssetManager::GetAllMeshes(); std::vector> handles; - for (auto const& mesh : meshes) + std::vector> texHandles; + for (const auto& asset : SHAssetManager::GetAllAssets()) { - if (mesh.header.meshName == "Cube.012") + switch (asset.type) { - 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() - )); + case AssetType::MESH: + if (asset.name == "Cube.012") + handles.emplace_back(SHResourceManager::LoadOrGet(asset.id)); + break; + case AssetType::IMAGE: + texHandles.emplace_back(SHResourceManager::LoadOrGet(asset.id)); + break; } } - graphicsSystem->BuildMeshBuffers(); - - // 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(); + SHResourceManager::FinaliseChanges(); // Create Materials auto matInst = graphicsSystem->AddOrGetBaseMaterialInstance(); @@ -77,9 +67,9 @@ namespace Sandbox customMat->SetProperty("data.alpha", 0.1f); // Create Stress Test Objects - 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_SCALE = SHVec3::One; + constexpr int NUM_ROWS = 3; + constexpr int NUM_COLS = 1; 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 }; @@ -101,13 +91,13 @@ namespace Sandbox //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.SetWorldRotation(SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f)); transform.SetWorldScale(TEST_OBJ_SCALE); - if (const bool IS_EVEN = (y * NUM_ROWS + x) % 2; IS_EVEN) + //if (const bool IS_EVEN = (y * NUM_ROWS + x) % 2; IS_EVEN) collider.AddBoundingBox(SHVec3::One * 0.5f, SHVec3::Zero); - else - collider.AddBoundingSphere(0.5f, SHVec3::Zero); + //else + // collider.AddBoundingSphere(0.5f, SHVec3::Zero); stressTestObjects.emplace_back(entity); } @@ -166,6 +156,10 @@ namespace Sandbox transformShowcase.SetWorldPosition({ 3.0f, -1.0f, -1.0f }); transformShowcase.SetLocalScale({ 5.0f, 5.0f, 5.0f }); scriptEngine->AddScript(raccoonShowcase, "RaccoonShowcase"); + + SHComponentManager::AddComponent(0); + SHComponentManager::RemoveComponent (0); + SHComponentManager::RemoveComponent (0); } void SBTestScene::Update(float dt) diff --git a/SHADE_Engine/SHAnimationAsset.h b/SHADE_Engine/SHAnimationAsset.h new file mode 100644 index 00000000..d8d0ffb1 --- /dev/null +++ b/SHADE_Engine/SHAnimationAsset.h @@ -0,0 +1,30 @@ +/*************************************************************************//** + * \file SHAnimationAsset.h + * \author Loh Xiao Qi + * \date October 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ +#pragma once + +#include +#include +#include "SH_API.power h" + +namespace SHADE +{ + struct SH_API SHAnimationAsset + { + std::string name; + + std::vector nodeChannels; + std::vector meshChannels; + std::vector morphMeshChannels; + + double duration; + double ticksPerSecond; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Asset Types/SHAnimationAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHAnimationAsset.h new file mode 100644 index 00000000..b411a11e --- /dev/null +++ b/SHADE_Engine/src/Assets/Asset Types/SHAnimationAsset.h @@ -0,0 +1,30 @@ +/*************************************************************************//** + * \file SHAnimationAsset.h + * \author Loh Xiao Qi + * \date October 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ +#pragma once + +#include +#include +#include "SHAssetData.h" + +namespace SHADE +{ + struct SH_API SHAnimationAsset : SHAssetData + { + std::string name; + + std::vector nodeChannels; + std::vector meshChannels; + std::vector morphMeshChannels; + + double duration; + double ticksPerSecond; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Asset Types/SHAssetData.h b/SHADE_Engine/src/Assets/Asset Types/SHAssetData.h new file mode 100644 index 00000000..8db9824c --- /dev/null +++ b/SHADE_Engine/src/Assets/Asset Types/SHAssetData.h @@ -0,0 +1,19 @@ +/*************************************************************************//** + * \file SHAssetDataBase.h + * \author Loh Xiao Qi + * \date October 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ +#pragma once + +namespace SHADE +{ + struct SHAssetData + { + virtual ~SHAssetData(){} + }; +} diff --git a/SHADE_Engine/src/Assets/Asset Types/SHAssetIncludes.h b/SHADE_Engine/src/Assets/Asset Types/SHAssetIncludes.h new file mode 100644 index 00000000..1c1ed44a --- /dev/null +++ b/SHADE_Engine/src/Assets/Asset Types/SHAssetIncludes.h @@ -0,0 +1,4 @@ +#pragma once + +#include "SHMeshAsset.h" +#include "SHTextureAsset.h" \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Asset Types/SHInternalAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHInternalAsset.h new file mode 100644 index 00000000..8bef34e9 --- /dev/null +++ b/SHADE_Engine/src/Assets/Asset Types/SHInternalAsset.h @@ -0,0 +1,21 @@ +/*************************************************************************//** + * \file SHInternalAsset.h + * \author Loh Xiao Qi + * \date October 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ +#pragma once + +#include "SHAsset.h" + +namespace SHADE +{ + struct SHInternalAsset : SHAsset + { + + }; +} \ 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 68c0d150..20b442ba 100644 --- a/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h +++ b/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h @@ -14,7 +14,7 @@ #include #include "Math/SHMath.h" -#include "SH_API.h" +#include "SHAssetData.h" namespace SHADE { @@ -22,10 +22,10 @@ namespace SHADE { uint32_t vertexCount; uint32_t indexCount; - std::string meshName; + std::string name; }; - struct SH_API SHMeshAsset + struct SH_API SHMeshAsset : SHAssetData { bool compiled; bool changed; diff --git a/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h index 07cebea9..d26a2c30 100644 --- a/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h +++ b/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h @@ -2,13 +2,15 @@ #include "tinyddsloader.h" #include "Graphics/MiddleEnd/Textures/SHTextureLibrary.h" +#include "SHAssetData.h" namespace SHADE { - struct SHTextureAsset + struct SHTextureAsset : SHAssetData { bool compiled; + std::string name; uint32_t numBytes; uint32_t width; uint32_t height; diff --git a/SHADE_Engine/src/Assets/Libraries/SHAssetLoader.h b/SHADE_Engine/src/Assets/Libraries/SHAssetLoader.h new file mode 100644 index 00000000..41595519 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/SHAssetLoader.h @@ -0,0 +1,21 @@ +/*************************************************************************//** + * \file SHAssetLoader.h + * \author Loh Xiao Qi + * \date October 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ +#pragma once + +#include "Assets/Asset Types/SHAssetData.h" + +namespace SHADE +{ + struct SHAssetLoader + { + virtual SHAssetData* Load(AssetPath path) = 0; + }; +} diff --git a/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.cpp b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.cpp new file mode 100644 index 00000000..f4be0b68 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.cpp @@ -0,0 +1,141 @@ +/*************************************************************************//** + * \file SHAssimpLibrary.cpp + * \author Loh Xiao Qi + * \date October 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ +#include "SHpch.h" +#include "SHAssimpLibrary.h" +#include + +namespace SHADE +{ + Assimp::Importer SHAssimpLibrary::aiImporter; + + void SHAssimpLibrary::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept + { + for (size_t i {0}; i < node.mNumMeshes; ++i) + { + aiMesh* mesh = scene.mMeshes[node.mMeshes[i]]; + meshes.push_back(ProcessMesh(*mesh)); + } + + for (size_t i{ 0 }; i < node.mNumChildren; ++i) + { + ProcessNode(*node.mChildren[i], scene, meshes); + } + } + + void SHAssimpLibrary::ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept + { + if (scene.HasAnimations()) + { + std::vector anims(scene.mNumAnimations); + for (auto i{0}; i < scene.mNumAnimations; ++i) + { + auto const& anim {*scene.mAnimations[i]}; + + anims[i].name = anim.mName.C_Str(); + + anims[i].duration = anim.mDuration; + anims[i].ticksPerSecond = anim.mTicksPerSecond; + + std::copy_n(anim.mChannels, anim.mNumChannels, anims[i].nodeChannels.data()); + std::copy_n(anim.mMeshChannels, anim.mNumMeshChannels, anims[i].meshChannels.data()); + std::copy_n(anim.mMorphMeshChannels, anim.mNumMorphMeshChannels, anims[i].morphMeshChannels.data()); + } + } + } + + SHMeshAsset* SHAssimpLibrary::ProcessMesh(aiMesh const& mesh) noexcept + { + SHMeshAsset* result = new SHMeshAsset(); + result->compiled = false; + result->changed = false; + + for (size_t i{0}; i < mesh.mNumVertices; ++i) + { + // Vertex position + SHVec3 vertex; + vertex.x = mesh.mVertices[i].x; + vertex.y = mesh.mVertices[i].y; + vertex.z = mesh.mVertices[i].z; + result->vertexPosition.push_back(vertex); + + // Tex coords + SHVec2 texCoord{0.f, 0.f}; + if (mesh.mTextureCoords[0]) + { + texCoord.x = mesh.mTextureCoords[0][i].x; + texCoord.y = mesh.mTextureCoords[0][i].y; + } + result->texCoords.push_back(texCoord); + + // Normals + SHVec3 normal{0.f, 0.f, 0.f}; + if (mesh.mNormals) + { + normal.x = mesh.mNormals[i].x; + normal.y = mesh.mNormals[i].y; + normal.z = mesh.mNormals[i].z; + } + result->vertexNormal.push_back(normal); + + // Tangent + SHVec3 tangent{0.f, 0.f, 0.f}; + if (mesh.mTangents) + { + tangent.x = mesh.mTangents[i].x; + tangent.y = mesh.mTangents[i].y; + tangent.z = mesh.mTangents[i].z; + } + result->vertexTangent.push_back(tangent); + } + + for (size_t i {0}; i < mesh.mNumFaces; ++i) + { + aiFace face = mesh.mFaces[i]; + for (size_t j{0}; j < face.mNumIndices; ++j) + { + result->indices.push_back(face.mIndices[j]); + } + } + + result->header.vertexCount = static_cast(result->vertexPosition.size()); + result->header.indexCount = static_cast(result->indices.size()); + result->header.name = mesh.mName.C_Str(); + + return result; + } + + void SHAssimpLibrary::LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept + { + const aiScene* scene = aiImporter.ReadFile(path.string().c_str(), + aiProcess_Triangulate // Make sure we get triangles rather than nvert polygons + | aiProcess_GenUVCoords // Convert any type of mapping to uv mapping + | aiProcess_TransformUVCoords // preprocess UV transformations (scaling, translation ...) + | aiProcess_FindInstances // search for instanced meshes and remove them by references to one master + | aiProcess_CalcTangentSpace // calculate tangents and bitangents if possible + | aiProcess_JoinIdenticalVertices // join identical vertices/ optimize indexing + | aiProcess_RemoveRedundantMaterials // remove redundant materials + | aiProcess_FindInvalidData // detect invalid model data, such as invalid normal vectors + | aiProcess_FlipUVs // flip the V to match the Vulkans way of doing UVs + ); + + if (!scene || !scene->HasMeshes()) + { + SHLOG_ERROR("ERROR in GLTF::ASSIMP: {}\nFile: {}", aiImporter.GetErrorString(), path.string()); + return; + } + + ExtractAnimations(*scene, anims); + + ProcessNode(*scene->mRootNode, *scene, meshes); + + aiImporter.FreeScene(); + } +} diff --git a/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.h b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.h new file mode 100644 index 00000000..83755b4c --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.h @@ -0,0 +1,36 @@ +/*************************************************************************//** + * \file SHAssimpLibrary.h + * \author Loh Xiao Qi + * \date October 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ + +#pragma once +#include +#include +#include +#include "../SHAssetMacros.h" +#include "../Asset Types/SHMeshAsset.h" +#include "../Asset Types/SHAnimationAsset.h" + +namespace SHADE +{ + class SHAssimpLibrary + { + private: + using MeshVectorRef = std::vector&; + using AnimVectorRef = std::vector&; + + static Assimp::Importer aiImporter; + static void ProcessNode(aiNode const& node, aiScene const& scene,MeshVectorRef meshes) noexcept; + static void ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept; + static SHMeshAsset* ProcessMesh(aiMesh const& mesh) noexcept; + + public: + static void LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp b/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp index 12b2517e..2346714e 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp +++ b/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp @@ -16,11 +16,11 @@ #include -void SHADE::SHMeshCompiler::CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept +std::string 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; + newPath += asset.header.name + MESH_EXTENSION.data(); std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc }; if (!file.is_open()) @@ -67,4 +67,6 @@ void SHADE::SHMeshCompiler::CompileMeshBinary(SHMeshAsset const& asset, AssetPat ); file.close(); + + return newPath; } diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.h b/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.h index 6da00525..a8ce67be 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.h +++ b/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.h @@ -21,6 +21,6 @@ namespace SHADE { private: public: - static void CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept; + static std::string 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 3a5fb9ec..90dd58d4 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp +++ b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp @@ -12,129 +12,11 @@ *****************************************************************************/ #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) noexcept - { - for (size_t i {0}; i < node.mNumMeshes; ++i) - { - aiMesh* mesh = scene.mMeshes[node.mMeshes[i]]; - meshes.push_back(ProcessMesh(*mesh, scene)); - } - - for (size_t i{ 0 }; i < node.mNumChildren; ++i) - { - ProcessNode(*node.mChildren[i], scene, meshes); - } - } - - SHMeshAsset SHMeshLoader::ProcessMesh(aiMesh const& mesh, aiScene const& scene) noexcept - { - (void)scene; - - SHMeshAsset result - { - .compiled { false}, - .changed { false } - }; - - for (size_t i{0}; i < mesh.mNumVertices; ++i) - { - // Vertex position - SHVec3 vertex; - vertex.x = mesh.mVertices[i].x; - vertex.y = mesh.mVertices[i].y; - vertex.z = mesh.mVertices[i].z; - result.vertexPosition.push_back(vertex); - - // Tex coords - SHVec2 texCoord{0.f, 0.f}; - if (mesh.mTextureCoords[0]) - { - texCoord.x = mesh.mTextureCoords[0][i].x; - texCoord.y = mesh.mTextureCoords[0][i].y; - } - result.texCoords.push_back(texCoord); - - // Normals - SHVec3 normal{0.f, 0.f, 0.f}; - if (mesh.mNormals) - { - normal.x = mesh.mNormals[i].x; - normal.y = mesh.mNormals[i].y; - normal.z = mesh.mNormals[i].z; - } - result.vertexNormal.push_back(normal); - - // Tangent - SHVec3 tangent{0.f, 0.f, 0.f}; - if (mesh.mTangents) - { - tangent.x = mesh.mTangents[i].x; - tangent.y = mesh.mTangents[i].y; - tangent.z = mesh.mTangents[i].z; - } - result.vertexTangent.push_back(tangent); - } - - for (size_t i {0}; i < mesh.mNumFaces; ++i) - { - aiFace face = mesh.mFaces[i]; - for (size_t j{0}; j < face.mNumIndices; ++j) - { - result.indices.push_back(face.mIndices[j]); - } - } - - result.header.vertexCount = static_cast(result.vertexPosition.size()); - result.header.indexCount = static_cast(result.indices.size()); - result.header.meshName = mesh.mName.C_Str(); - - return result; - } - - 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 - ); - - if (!scene || !scene->HasMeshes()) - { - SHLOG_ERROR("ERROR in GLTF::ASSIMP: {}\nFile: {}", aiImporter.GetErrorString(), path.string()); - return; - } - - //TODO MATERIALS FROM MESHES - //if (scene->HasMaterials()) - //{ - // for (int i{0}; i < scene->mNumMaterials; ++i) - // { - // if (scene->mMaterials[i]->mNumProperties > 0) - // { - // for (int j{0}; j < scene->mMaterials[i]->mProperties[j].) - // } - //std::cout << scene->mMaterials[i]->; - // } - //} - - ProcessNode(*scene->mRootNode, *scene, meshes); - } - - void SHMeshLoader::LoadSHMesh(SHMeshAsset& mesh, AssetPath path) noexcept + void SHMeshLoader::LoadSHMesh(AssetPath path, SHMeshAsset& mesh) noexcept { std::ifstream file{ path.string(), std::ios::in | std::ios::binary }; if (!file.is_open()) @@ -142,8 +24,7 @@ namespace SHADE SHLOG_ERROR("Unable to open SHMesh File: {}", path.string()); } - std::string name{ path.filename().string() }; - name = name.substr(0, name.find_last_of('.')); + const std::string name{ path.stem().string() }; file.seekg(0); @@ -169,45 +50,13 @@ namespace SHADE 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.header.name = name; mesh.vertexPosition = std::move(vertPos); mesh.vertexTangent = std::move(vertTan); @@ -218,15 +67,12 @@ namespace SHADE file.close(); } - void SHMeshLoader::LoadMesh(std::vector& meshes, AssetPath path) noexcept - { - if (path.extension().string() == GLTF_EXTENSION) - { - LoadExternal(meshes, path); - return; - } + SHAssetData* SHMeshLoader::Load(AssetPath path) + { + auto result = new SHMeshAsset(); - meshes.emplace_back(); - LoadSHMesh(meshes.back(), path); + LoadSHMesh(path, *result); + + return result; } } diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h index 3e430aca..34c4e5d2 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h +++ b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h @@ -10,27 +10,15 @@ * of DigiPen Institute of Technology is prohibited. *****************************************************************************/ #pragma once -#include -#include #include "../SHAssetMacros.h" #include "../Asset Types/SHMeshAsset.h" -#include +#include "SHAssetLoader.h" namespace SHADE { - class SHMeshLoader + struct SHMeshLoader : public SHAssetLoader { - private: - static Assimp::Importer aiImporter; - - static void ProcessNode(aiNode const& node, aiScene const& scene, std::vector& meshes) noexcept; - - 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 void LoadMesh(std::vector& meshes, AssetPath path) noexcept; + void LoadSHMesh(AssetPath path, SHMeshAsset& meshes) noexcept; + SHAssetData* Load(AssetPath path) override; }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.cpp b/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.cpp index 62af4da6..49de6b5c 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.cpp +++ b/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.cpp @@ -17,7 +17,7 @@ namespace SHADE { - void SHTextureCompiler::CompileTextureBinary(SHTextureAsset const& asset, AssetPath path) + std::string SHTextureCompiler::CompileTextureBinary(SHTextureAsset const& asset, AssetPath path) { std::string newPath{ path.string() }; newPath = newPath.substr(0, newPath.find_last_of('.')); @@ -69,5 +69,7 @@ namespace SHADE ); file.close(); + + return newPath; } } diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.h b/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.h index d8685795..52980084 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.h +++ b/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.h @@ -19,6 +19,6 @@ namespace SHADE { struct SHTextureCompiler { - static void CompileTextureBinary(SHTextureAsset const& asset, AssetPath path); + static std::string 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 47501d42..8b986524 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp +++ b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp @@ -93,6 +93,7 @@ namespace SHADE std::memcpy(pixel, file.GetImageData()->m_mem, totalBytes); //pixel = std::move(reinterpret_cast(file.GetDDSData())); + asset.name = path.stem().string(); asset.compiled = false; asset.numBytes = static_cast(totalBytes); asset.width = file.GetWidth(); @@ -132,6 +133,15 @@ namespace SHADE file.close(); } + SHAssetData* SHTextureLoader::Load(AssetPath path) + { + auto result = new SHTextureAsset(); + + LoadImageAsset(path, *result); + + return result; + } + void SHTextureLoader::LoadImageAsset(AssetPath path, SHTextureAsset& asset) { if (path.extension().string() == DDS_EXTENSION) diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h index e84fe5cf..8bdf91b1 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h +++ b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h @@ -15,19 +15,20 @@ #include "../SHAssetMacros.h" #include "../Asset Types/SHTextureAsset.h" #include "tinyddsloader.h" +#include "SHAssetLoader.h" namespace SHADE { - class SHTextureLoader + class SHTextureLoader : public SHAssetLoader { private: - 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; + std::string TinyDDSResultToString(tinyddsloader::Result value); + vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear); + + void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept; public: - static void LoadImageAsset(AssetPath paths, SHTextureAsset& image); + void LoadImageAsset(AssetPath paths, SHTextureAsset& image); + void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept; + SHAssetData* Load(AssetPath path) override; }; } diff --git a/SHADE_Engine/src/Assets/SHAsset.h b/SHADE_Engine/src/Assets/SHAsset.h index 8d7b55d1..86e8a722 100644 --- a/SHADE_Engine/src/Assets/SHAsset.h +++ b/SHADE_Engine/src/Assets/SHAsset.h @@ -12,11 +12,12 @@ #pragma once #include "Filesystem/SHFileSystem.h" -#include "SHAssetMacros.h" +#include "Assets/SHAssetMacros.h" +#include "SH_API.h" namespace SHADE { - struct SHAsset + struct SH_API SHAsset { AssetName name; AssetID id; diff --git a/SHADE_Engine/src/Assets/SHAssetMacros.h b/SHADE_Engine/src/Assets/SHAssetMacros.h index 8c462af7..0fdfa04e 100644 --- a/SHADE_Engine/src/Assets/SHAssetMacros.h +++ b/SHADE_Engine/src/Assets/SHAssetMacros.h @@ -32,15 +32,15 @@ typedef std::filesystem::path AssetPath; typedef unsigned char* AssetData; typedef std::string AssetMetaVersion; typedef std::string AssetExtension; -typedef unsigned char AssetTypeMeta; +typedef size_t AssetTypeMeta; typedef FMOD::Sound* SHSound; // Asset Meta Version -#define ASSET_META_VER "1.0" +constexpr std::string_view ASSET_META_VER { "1.0" }; // Asset type enum -enum class AssetType : uint8_t +enum class AssetType : AssetTypeMeta { INVALID = 0, AUDIO = 1, @@ -53,29 +53,35 @@ enum class AssetType : uint8_t SCENE, PREFAB, AUDIO_WAV, - DDS + DDS, + MAX_COUNT }; //Directory -#define ASSET_ROOT "./Assets/" +#ifdef _PUBLISH +constexpr std::string_view ASSET_ROOT {"Assets"}; +#else +constexpr std::string_view ASSET_ROOT {"../../Assets"}; +#endif + // ASSET EXTENSIONS -#define META_EXTENSION ".shmeta" -#define IMAGE_EXTENSION ".png" -#define AUDIO_EXTENSION ".ogg" -#define AUDIO_WAV_EXTENSION ".wav" -#define SHADER_EXTENSION ".glsl" -#define SCRIPT_EXTENSION ".cs" -#define SCENE_EXTENSION ".SHADE" -#define PREFAB_EXTENSION ".SHPrefab" -#define MATERIAL_EXTENSION ".SHMat" -#define TEXTURE_EXTENSION ".shtex" -#define DDS_EXTENSION ".dds" -#define FBX_EXTENSION ".fbx" -#define GLTF_EXTENSION ".gltf" -#define MESH_EXTENSION ".shmesh" +constexpr std::string_view META_EXTENSION {".shmeta"}; +constexpr std::string_view IMAGE_EXTENSION {".png"}; +constexpr std::string_view AUDIO_EXTENSION {".ogg"}; +constexpr std::string_view AUDIO_WAV_EXTENSION {".wav"}; +constexpr std::string_view SHADER_EXTENSION {".glsl"}; +constexpr std::string_view SCRIPT_EXTENSION {".cs"}; +constexpr std::string_view SCENE_EXTENSION {".SHADE"}; +constexpr std::string_view PREFAB_EXTENSION {".SHPrefab"}; +constexpr std::string_view MATERIAL_EXTENSION {".SHMat"}; +constexpr std::string_view TEXTURE_EXTENSION {".shtex"}; +constexpr std::string_view DDS_EXTENSION {".dds"}; +constexpr std::string_view FBX_EXTENSION {".fbx"}; +constexpr std::string_view GLTF_EXTENSION {".gltf"}; +constexpr std::string_view MESH_EXTENSION {".shmesh"}; -std::string const EXTENSIONS[] = { +constexpr std::string_view EXTENSIONS[] = { AUDIO_EXTENSION, SHADER_EXTENSION, MATERIAL_EXTENSION, @@ -91,10 +97,12 @@ std::string const EXTENSIONS[] = { GLTF_EXTENSION }; +constexpr size_t TYPE_COUNT {static_cast(AssetType::MAX_COUNT) }; + // Error flags -#define FILE_NOT_FOUND_ERR "FILE NOT FOUND" -#define META_NOT_FOUND_ERR "META NOT FOUND" -#define ASSET_NOT_FOUND_ERR "ASSET NOT FOUND" -#define EXT_DOES_NOT_EXIST "TYPE DOES NOT HAVE EXTENSION DEFINED" +constexpr std::string_view FILE_NOT_FOUND_ERR {"FILE NOT FOUND"}; +constexpr std::string_view META_NOT_FOUND_ERR {"META NOT FOUND"}; +constexpr std::string_view ASSET_NOT_FOUND_ERR {"ASSET NOT FOUND"}; +constexpr std::string_view EXT_DOES_NOT_EXIST {"TYPE DOES NOT HAVE EXTENSION DEFINED"}; #endif // !SH_ASSET_MACROS_H diff --git a/SHADE_Engine/src/Assets/SHAssetManager.cpp b/SHADE_Engine/src/Assets/SHAssetManager.cpp index 430b8c79..3032ba51 100644 --- a/SHADE_Engine/src/Assets/SHAssetManager.cpp +++ b/SHADE_Engine/src/Assets/SHAssetManager.cpp @@ -14,6 +14,7 @@ #include "SHAssetMetaHandler.h" #include "Filesystem/SHFileSystem.h" +#include "Libraries/SHAssimpLibrary.h" #include "Libraries/SHMeshLoader.h" #include "Libraries/SHTextureLoader.h" @@ -25,11 +26,10 @@ namespace SHADE FMOD::System* SHAssetManager::audioSystem; std::unordered_map* SHAssetManager::audioSoundList; - std::vector SHAssetManager::assetCollection; - std::unordered_map SHAssetManager::assetRegistry; + std::vector SHAssetManager::loaders(TYPE_COUNT); - std::unordered_map SHAssetManager::meshCollection; - std::unordered_map SHAssetManager::textureCollection; + std::vector SHAssetManager::assetCollection; + std::unordered_map SHAssetManager::assetData; /**************************************************************************** * \brief Static function to generate asset ID. @@ -56,13 +56,15 @@ namespace SHADE ****************************************************************************/ void SHAssetManager::Unload() noexcept { - for (auto const& asset : assetCollection) - { - SHAssetMetaHandler::WriteMetaData(asset); - } + } - AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept + void SHAssetManager::Unload(AssetID assetId) noexcept + { + // TODO + } + + AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept { if (!IsRecognised(path.extension().string().c_str())) { @@ -80,7 +82,37 @@ namespace SHADE // return std::filesystem::path(); //} - return std::filesystem::path(ASSET_ROOT + folder + path.filename().string()); + return std::filesystem::path(std::string(ASSET_ROOT) + folder + path.filename().string()); + } + + AssetPath SHAssetManager::GenerateNewPath(AssetName name, AssetType type) + { + std::string folder; + + switch(type) + { + case AssetType::SCENE: + folder = "scenes/"; + break; + + case AssetType::PREFAB: + folder = "prefabs/"; + break; + + case AssetType::MATERIAL: + folder = "materials/"; + break; + + default: + folder = "/"; + } + + return std::filesystem::path{ + std::string(ASSET_ROOT) + + folder + + name + + std::string(EXTENSIONS[static_cast(type)]) + }; } /**************************************************************************** @@ -116,7 +148,7 @@ namespace SHADE // folder = ""; // break; //} - AssetPath path{ ASSET_ROOT + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) }; + AssetPath path{ std::string{ASSET_ROOT} + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) }; SHAssetMetaHandler::WriteMetaData(meta); @@ -125,6 +157,19 @@ namespace SHADE return id; } + AssetID SHAssetManager::CreateAsset(AssetName name, AssetType type) noexcept + { + AssetID id = GenerateAssetID(type); + + assetCollection.emplace_back( + name, + id, + type, + GenerateNewPath(name, type), + 0 + ); + return id; + } /**************************************************************************** * \brief Import new asset from outside editor window. * @@ -133,7 +178,10 @@ namespace SHADE ****************************************************************************/ AssetID SHAssetManager::ImportNewAsset(char const* p) noexcept { - std::filesystem::path const path{ p }; + std::filesystem::path const path{ p }; + + auto const type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string()); + auto const id = GenerateAssetID(type); std::filesystem::path const newPath{ GenerateLocalPath(path) }; if (newPath.empty()) @@ -144,11 +192,7 @@ namespace SHADE std::filesystem::copy(path, newPath); - AssetID id{ RetrieveAsset(newPath.string().c_str()) }; - if (id != 0) - { - LoadData(id); - } + assetCollection.push_back(CreateAssetFromPath(newPath)); return id; } @@ -159,138 +203,14 @@ namespace SHADE ****************************************************************************/ void SHAssetManager::RefreshAllAssets() noexcept { - std::vector metaFiles; - std::vector AssetFiles; - //SHFileSystem::LoadAllFiles(metaFiles, AssetFiles); - //std::vector AssetFilesVerified; - std::vector AssetFilesNew; - - for (auto const& asset : AssetFiles) - { - bool found = false; - for (auto it {metaFiles.begin()}; it != metaFiles.end(); ++it) - { - std::string fileExtCheck{ asset.filename().string() }; - fileExtCheck += META_EXTENSION; - if (it->filename().string() == fileExtCheck) - { - metaFiles.erase(it); - found = true; - break; - } - } - - if (!found && IsRecognised(asset.extension().string().c_str())) - { - AssetFilesNew.push_back(asset); - } - } - - std::vector newLoad; - newLoad.reserve(AssetFilesNew.size()); - - //TODO: Handle if meta does not match all assets (if meta exist and asset doesnt, vice versa) - for (auto const& file : AssetFilesNew) - { - newLoad.push_back(RegisterAssetNew(file)); - } - - //UpdateAllSpriteSets(); - - } - - void SHAssetManager::LoadDataTemp(std::string p) noexcept - { - AssetPath path{ p }; - - if (path.extension().string() == FBX_EXTENSION - || path.extension().string() == GLTF_EXTENSION - || path.extension().string() == MESH_EXTENSION) - { - LoadGLTF( - { - .name {path.filename().string()}, - .id {0}, - .type {AssetType::MESH}, - .path {path}, - .location {0} - } - ); - } - else if (path.extension().string() == DDS_EXTENSION - || path.extension().string() == TEXTURE_EXTENSION) - { - LoadDDS( - { - .name {path.filename().string()}, - .id {0}, - .type {AssetType::DDS}, - .path {path}, - .location {0} - } - ); - } - } - - std::vector SHAssetManager::GetAllMeshes() noexcept - { - std::vector result; - for (auto const& mesh : meshCollection) - { - result.push_back(mesh.second); - } - - return result; - } - - std::vector SHAssetManager::GetAllTextures() noexcept - { - std::vector result; - for (auto const& dds : textureCollection) - { - result.push_back(dds.second); - } - - return result; - } - - /**************************************************************************** - * \param Path for meta data file - * \param Path for asset file - - * \brief Links meta data to asset in registries. Meta data should - * already exist - ****************************************************************************/ - void SHAssetManager::RegisterAsset(AssetPath const& metaPath, AssetPath const& path) noexcept - { - SHAsset const meta = SHAssetMetaHandler::RetrieveMetaData(metaPath); - - assetCollection.push_back(meta); - } - - /**************************************************************************** - * \param Path for asset file - - * \brief Creates new meta data for new asset. - ****************************************************************************/ - SHAsset SHAssetManager::RegisterAssetNew(AssetPath const& asset) noexcept - { - SHAsset meta; - meta.type = SHAssetMetaHandler::GetTypeFromExtension(asset.extension().string()); - meta.id = GenerateAssetID(meta.type); - - assetCollection.push_back(meta); - - SHAssetMetaHandler::WriteMetaData(meta); - return assetCollection.back(); } bool SHAssetManager::IsRecognised(char const* ext) noexcept { for (auto const& e : EXTENSIONS) { - if (strcmp(ext, e.c_str()) == 0) + if (strcmp(ext, e.data()) == 0) { return true; } @@ -299,35 +219,31 @@ namespace SHADE return false; } - void SHAssetManager::LoadGLTF(SHAsset asset) noexcept + SHAsset SHAssetManager::CreateAssetFromPath(AssetPath path) noexcept { - std::vector meshes; + SHAsset result; - SHMeshLoader::LoadMesh(meshes, asset.path); + result.name = path.stem().string(); + result.type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string()); + result.id = GenerateAssetID(result.type); + result.path = path; - for (auto const& mesh : meshes) - { - meshCollection.emplace(GenerateAssetID(AssetType::MESH), mesh); - - if (!mesh.compiled) - { - SHMeshCompiler::CompileMeshBinary(mesh, asset.path); - } - } + return result; } - void SHAssetManager::LoadDDS(SHAsset asset) noexcept + void SHAssetManager::InitLoaders() noexcept { - SHTextureAsset image; - - SHTextureLoader::LoadImageAsset(asset.path, image); - - textureCollection.emplace(GenerateAssetID(AssetType::DDS), image); - - if (!image.compiled) - { - SHTextureCompiler::CompileTextureBinary(image, asset.path); - } + loaders[static_cast(AssetType::AUDIO)] = nullptr; + loaders[static_cast(AssetType::SHADER)] = nullptr; + loaders[static_cast(AssetType::MATERIAL)] = nullptr; + loaders[static_cast(AssetType::IMAGE)] = dynamic_cast(new SHTextureLoader()); + loaders[static_cast(AssetType::TEXTURE)] = nullptr; + loaders[static_cast(AssetType::MESH)] = dynamic_cast(new SHMeshLoader()); + loaders[static_cast(AssetType::SCRIPT)] = nullptr; + loaders[static_cast(AssetType::SCENE)] = nullptr; + loaders[static_cast(AssetType::PREFAB)] = nullptr; + loaders[static_cast(AssetType::AUDIO_WAV)] = nullptr; + loaders[static_cast(AssetType::DDS)] = nullptr; } /**************************************************************************** @@ -335,8 +251,9 @@ namespace SHADE ****************************************************************************/ void SHAssetManager::Load() noexcept { - RetrieveAssets(); - LoadAllData(); + InitLoaders(); + BuildAssetCollection(); + //LoadAllData(); } /**************************************************************************** @@ -346,114 +263,38 @@ namespace SHADE { for (auto const& asset : assetCollection) { + SHAssetData* data = loaders[static_cast(asset.type)]->Load(asset.path); + assetData.emplace(asset.id, data); } } - void SHAssetManager::LoadData(AssetID id) noexcept + SHAssetData* SHAssetManager::LoadData(SHAsset const& asset) noexcept { - (void)id; - } + SHAssetData* data = loaders[static_cast(asset.type)]->Load(asset.path); - /**************************************************************************** - * \brief Retrieve all asset files and meta files from filesystem - ****************************************************************************/ - void SHAssetManager::RetrieveAssets() noexcept - { - std::vector metaFiles; - std::vector AssetFiles; - - //TODO: Write new function for file manager to loop through all files - SHFileSystem::StartupFillDirectories(ASSET_ROOT); - FolderPointer rootFolder = SHFileSystem::GetRoot(); - - for (auto const& meta : metaFiles) + if (data == nullptr) { - for (std::vector::const_iterator it{ AssetFiles.cbegin() }; - it != AssetFiles.cend(); - ++it) - { - // Asset exists for meta file - std::string fileExtCheck{ it->filename().string() }; - fileExtCheck += META_EXTENSION; - if (meta.filename().string() == fileExtCheck) - { - RegisterAsset(meta, *it); - AssetFiles.erase(it); - break; - } - } - } - - //TODO: Handle if meta does not match all assets (if meta exist and asset doesnt, vice versa) - for (auto const& file : AssetFiles) - { - if (IsRecognised(file.extension().string().c_str())) - { - SHAssetMetaHandler::WriteMetaData(RegisterAssetNew(file)); - } - else - { - std::cout << "Unsupported File Format: " << file.filename() << "\n"; - } - } - } - - AssetID SHAssetManager::RetrieveAsset(char const* path) noexcept - { - std::filesystem::path p{ path }; - if (IsRecognised(p.extension().string().c_str())) - { - SHAsset const& meta{ RegisterAssetNew(p) }; - SHAssetMetaHandler::WriteMetaData(meta); - return meta.id; + SHLOG_ERROR("Unable to load asset into memory: {}\n", asset.path.string()); } else { - std::cout << "Unsupported File Format: " << p.filename() << "\n"; + assetData.emplace(asset.id, data); } - // Assert that file imported is not recognised - return 0; + return data; } - /**************************************************************************** - * \param Full path of file - - * \brief Extracts file name from path. Formats file name into readable - * with spaces and capitalises first letter of every word - ****************************************************************************/ - AssetName SHAssetManager::GetNameFromPath(AssetPath filepath) noexcept + void SHAssetManager::BuildAssetCollection() noexcept { - std::string name{ filepath.filename().string() }; - name = name.substr(0, name.find_last_of('.')); - - //if (name[0] <= 122 && name[0] >= 97) - //{ - // name[0] -= 32; - //} - - //for (size_t i{ 1 }; i < name.length(); ++i) - //{ - // // Replace all underscores with spaces - // if (name[i] == '_') - // { - // name[i] = ' '; - // continue; - // } - - // if (name[i + 1] <= 'Z' && name[i + 1] >= 'A' - // && name[i] <= 'z' && name[i] >= 'a') - // { - // name.insert(i + 1, 1, ' '); - // continue; - // } - - // if (name[i - 1] == ' ' && name[i] <= 'z' && name[i] >= 'a') - // { - // name[i] -= 32; - // } - //} - - return name; + for (auto const& dir : std::filesystem::recursive_directory_iterator{ASSET_ROOT}) + { + if (dir.is_regular_file()) + { + if (dir.path().extension().string() == META_EXTENSION.data()) + { + assetCollection.push_back(SHAssetMetaHandler::RetrieveMetaData(dir.path())); + } + } + } } } diff --git a/SHADE_Engine/src/Assets/SHAssetManager.h b/SHADE_Engine/src/Assets/SHAssetManager.h index 7064d63d..9ee7ab92 100644 --- a/SHADE_Engine/src/Assets/SHAssetManager.h +++ b/SHADE_Engine/src/Assets/SHAssetManager.h @@ -11,9 +11,10 @@ #pragma once #include "tinyddsloader.h" #include "SHAsset.h" +#include "Asset Types/SHAssetData.h" +#include "Libraries/SHAssetLoader.h" +#include -#include "Asset Types/SHMeshAsset.h" -#include "Asset Types/SHTextureAsset.h" #include "SH_API.h" namespace SHADE @@ -28,10 +29,13 @@ namespace SHADE static AssetPath GenerateLocalPath(AssetPath path) noexcept; + static AssetPath GenerateNewPath(AssetName name, AssetType type); + /**************************************************************************** * \brief Deallocate all memory used by resource data ****************************************************************************/ static void Unload() noexcept; + static void Unload(AssetID assetId) noexcept; /**************************************************************************** * \brief Load all resources that are in the folder @@ -54,6 +58,7 @@ namespace SHADE * \return resource id generated for new asset ****************************************************************************/ static AssetID CreateNewAsset(AssetType, AssetName) noexcept; + static AssetID CreateAsset(AssetName name, AssetType type) noexcept; /**************************************************************************** * \brief Import new resource from outside editor window. @@ -70,64 +75,33 @@ namespace SHADE static void RefreshAllAssets() noexcept; // -------------------------------------------------------------------------/ - //TODO: TEMPORARY FOR TESTING GLTF & DDS - static void LoadDataTemp(std::string path) noexcept; - static std::vector GetAllMeshes() noexcept; - static std::vector GetAllTextures() noexcept; - + template + static std::enable_if_t, T const* const> GetData(AssetID id) noexcept; private: /**************************************************************************** * \brief Load resource data into memory ****************************************************************************/ static void LoadAllData() noexcept; - static void LoadData(AssetID id) noexcept; + static SHAssetData* LoadData(SHAsset const& asset) noexcept; - /**************************************************************************** - * \brief Retrieve all resource files and meta files from filesystem - ****************************************************************************/ - static void RetrieveAssets() noexcept; - - static AssetID RetrieveAsset(char const* path) noexcept; - - /**************************************************************************** - * \param Full path of file - - * \brief Extracts file name from path. Formats file name into readable - * with spaces and capitalises first letter of every word - ****************************************************************************/ - static AssetName GetNameFromPath(AssetPath) noexcept; - - /**************************************************************************** - * \param Path for meta data file - * \param Path for resource file - - * \brief Links meta data to resource in registries. Meta data should - * already exist - ****************************************************************************/ - static void RegisterAsset(AssetPath const&, AssetPath const&) noexcept; - - /**************************************************************************** - * \param Path for resource file - - * \brief Creates new meta data for new resource. - ****************************************************************************/ - static SHAsset RegisterAssetNew(AssetPath const&) noexcept; + inline static void BuildAssetCollection() noexcept; static bool IsRecognised(char const*) noexcept; + + static SHAsset CreateAssetFromPath(AssetPath path) noexcept; - // Specialised load calls - static void LoadGLTF(SHAsset asset) noexcept; - static void LoadDDS(SHAsset asset) noexcept; + static void InitLoaders() noexcept; static FMOD::System* audioSystem; static std::unordered_map* audioSoundList; + static std::vector loaders; + // For all resources static std::vector assetCollection; - static std::unordered_map assetRegistry; - - static std::unordered_map meshCollection; - static std::unordered_map textureCollection; + static std::unordered_map assetData; }; } + +#include "SHAssetManager.hpp" diff --git a/SHADE_Engine/src/Assets/SHAssetManager.hpp b/SHADE_Engine/src/Assets/SHAssetManager.hpp new file mode 100644 index 00000000..6c420778 --- /dev/null +++ b/SHADE_Engine/src/Assets/SHAssetManager.hpp @@ -0,0 +1,26 @@ + +#include "SHAssetManager.h" + +namespace SHADE +{ + template + std::enable_if_t, T const* const> SHAssetManager::GetData(AssetID id) noexcept + { + if (!assetData.contains(id)) + { + for (auto const& asset : assetCollection) + { + if (asset.id == id) + { + assetData.emplace(id, LoadData(asset)); + return dynamic_cast(assetData[id]); + } + } + + SHLOG_ERROR("Asset ID provided does not exist: {}", id); + return nullptr; + } + + return dynamic_cast(assetData[id]); + } +} diff --git a/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp b/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp index 6554a3e4..1bfec00d 100644 --- a/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp +++ b/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp @@ -37,7 +37,7 @@ namespace SHADE { for (int i{0}; i < EXTENSIONS->size(); ++i) { - if (ext == EXTENSIONS[i]) + if (strcmp(ext.c_str(), EXTENSIONS[i].data()) == 0) { return static_cast(i); } @@ -53,7 +53,7 @@ namespace SHADE ****************************************************************************/ AssetExtension SHAssetMetaHandler::GetExtensionFromType(AssetType type) noexcept { - return EXTENSIONS[static_cast(type)]; + return AssetExtension(EXTENSIONS[static_cast(type)]); } /**************************************************************************** @@ -72,6 +72,13 @@ namespace SHADE std::string line; SHAsset meta; + // Get resource name + GetFieldValue(metaFile, line); + std::stringstream nameStream{ line }; + AssetName name; + nameStream >> name; + meta.name = name; + // Get resource id GetFieldValue(metaFile, line); std::stringstream idStream{ line }; @@ -88,6 +95,8 @@ namespace SHADE metaFile.close(); + meta.path = path.parent_path().string() + "/" + path.stem().string(); + return meta; } @@ -103,7 +112,7 @@ namespace SHADE std::string path{ meta.path.string() }; path.append(META_EXTENSION); - std::ofstream metaFile{ path, std::ios_base::out }; + std::ofstream metaFile{ path, std::ios_base::out | std::ios_base::trunc }; if (!metaFile.is_open()) { @@ -113,17 +122,7 @@ namespace SHADE 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 << "Type: " << static_cast(meta.type) << std::endl; metaFile.close(); } diff --git a/SHADE_Engine/src/Camera/SHCameraComponent.cpp b/SHADE_Engine/src/Camera/SHCameraComponent.cpp new file mode 100644 index 00000000..5d49c887 --- /dev/null +++ b/SHADE_Engine/src/Camera/SHCameraComponent.cpp @@ -0,0 +1,189 @@ +#include "SHpch.h" +#include "SHCameraComponent.h" +#include "ECS_Base/Managers/SHComponentManager.h" +#include "SHCameraSystem.h" +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Math/Transform/SHTransformComponent.h" + +namespace SHADE +{ + SHCameraComponent::SHCameraComponent() + :yaw(0.0f), pitch(0.0f), roll(0.0f) + , width(1920.0f), height(1080.0f), zNear(0.01f), zFar(10000.0f), fov(90.0f), movementSpeed(1.0f), turnSpeed(0.5f) + , perspProj(true), dirtyView(true), dirtyProj(true) + , viewMatrix(), projMatrix() + , position() + { + ComponentFamily::GetID(); + } + + SHCameraComponent::~SHCameraComponent() + { + } + + void SHCameraComponent::SetYaw(float yaw) noexcept + { + this->yaw = yaw; + if (SHComponentManager::HasComponent(GetEID())) + { + auto transform = SHComponentManager::GetComponent(GetEID()); + SHVec3 rotation = transform->GetWorldRotation(); + transform->SetWorldRotation(SHVec3{rotation.x,yaw, rotation.z}); + } + dirtyView = true; + } + + void SHCameraComponent::SetPitch(float pitch) noexcept + { + this->pitch = pitch; + if (SHComponentManager::HasComponent(GetEID())) + { + auto transform = SHComponentManager::GetComponent(GetEID()); + SHVec3 rotation = transform->GetWorldRotation(); + transform->SetWorldRotation(SHVec3{ pitch,rotation.y, rotation.z }); + } + dirtyView = true; + } + + void SHCameraComponent::SetRoll(float roll) noexcept + { + this->roll = roll; + if (SHComponentManager::HasComponent(GetEID())) + { + auto transform = SHComponentManager::GetComponent(GetEID()); + SHVec3 rotation = transform->GetWorldRotation(); + transform->SetWorldRotation(SHVec3{ rotation.x,rotation.y, roll}); + } + dirtyView = true; + } + void SHCameraComponent::SetPositionX(float x) noexcept + { + position.x = x; + if (SHComponentManager::HasComponent(GetEID())) + { + auto transform = SHComponentManager::GetComponent(GetEID()); + SHVec3 position = transform->GetWorldPosition(); + transform->SetWorldRotation(SHVec3{ x,position.y, position.z}); + } + dirtyView = true; + } + void SHCameraComponent::SetPositionY(float y) noexcept + { + position.y = y; + if (SHComponentManager::HasComponent(GetEID())) + { + auto transform = SHComponentManager::GetComponent(GetEID()); + SHVec3 position = transform->GetWorldPosition(); + transform->SetWorldRotation(SHVec3{ position.x,y, position.z }); + } + dirtyView = true; + } + void SHCameraComponent::SetPositionZ(float z) noexcept + { + position.z = z; + if (SHComponentManager::HasComponent(GetEID())) + { + auto transform = SHComponentManager::GetComponent(GetEID()); + SHVec3 position = transform->GetWorldPosition(); + transform->SetWorldRotation(SHVec3{ position.x,position.y, z }); + } + dirtyView = true; + } + void SHCameraComponent::SetPosition(float x,float y, float z) noexcept + { + position.x = x; + position.y = y; + position.z = z; + if (SHComponentManager::HasComponent(GetEID())) + { + auto transform = SHComponentManager::GetComponent(GetEID()); + SHVec3 position = transform->GetWorldPosition(); + transform->SetWorldRotation(SHVec3{ x,y, z }); + } + dirtyView = true; + } + void SHCameraComponent::SetPosition(SHVec3& pos) noexcept + { + this->position = pos; + if (SHComponentManager::HasComponent(GetEID())) + { + auto transform = SHComponentManager::GetComponent(GetEID()); + SHVec3 position = transform->GetWorldPosition(); + transform->SetWorldRotation(pos); + } + dirtyView = true; + } + + void SHCameraComponent::SetWidth(float width) noexcept + { + this->width = width; + dirtyProj = true; + } + + + void SHCameraComponent::SetHeight(float height) noexcept + { + this->height = height; + dirtyProj = true; + } + + void SHCameraComponent::SetNear(float znear) noexcept + { + this->zNear = znear; + dirtyProj = true; + } + + void SHCameraComponent::SetFar(float zFar) noexcept + { + this->zFar = zFar; + dirtyProj = true; + } + + void SHCameraComponent::SetFOV(float fov) noexcept + { + this->fov = fov; + dirtyProj = true; + } + + float SHCameraComponent::GetYaw() const noexcept + { + return yaw; + } + + float SHCameraComponent::GetPitch() const noexcept + { + return pitch; + } + float SHCameraComponent::GetRoll() const noexcept + { + return roll; + } + float SHCameraComponent::GetAspectRatio() const noexcept + { + return width/height; + } + + float SHCameraComponent::GetFOV() const noexcept + { + return fov; + } + + const SHMatrix& SHCameraComponent::GetViewMatrix() const noexcept + { + return viewMatrix; + } + + const SHMatrix& SHCameraComponent::GetProjMatrix() const noexcept + { + return projMatrix; + } + + void SHCameraComponent::SetMainCamera(size_t directorCameraIndex) noexcept + { + auto system = SHSystemManager::GetSystem(); + system->GetDirector(directorCameraIndex)->SetMainCamera(*this); + } + + + +} diff --git a/SHADE_Engine/src/Camera/SHCameraComponent.h b/SHADE_Engine/src/Camera/SHCameraComponent.h new file mode 100644 index 00000000..1149b1e1 --- /dev/null +++ b/SHADE_Engine/src/Camera/SHCameraComponent.h @@ -0,0 +1,87 @@ +#pragma once + +#include "ECS_Base/Components/SHComponent.h" +#include "Math/Vector/SHVec3.h" +#include "Math/SHMatrix.h" +#include "SH_API.h" + +namespace SHADE +{ + + class SH_API SHCameraComponent final : public SHComponent + { + private: + + float yaw; + float pitch; + float roll; + + float width; + float height; + float zNear; + float zFar; + float fov; + + bool dirtyView; + bool dirtyProj; + + + SHMatrix viewMatrix; + SHMatrix projMatrix; + SHVec3 position; + + bool perspProj; + + + + + public: + friend class SHCameraSystem; + + SHCameraComponent(); + ~SHCameraComponent(); + + + //Getters and setters. + void SetYaw(float yaw) noexcept; + void SetPitch(float pitch) noexcept; + void SetRoll(float roll) noexcept; + void SetPositionX(float x) noexcept; + void SetPositionY(float y) noexcept; + void SetPositionZ(float z) noexcept; + void SetPosition(float x, float y, float z) noexcept; + void SetPosition(SHVec3& pos) noexcept; + + void SetWidth(float width) noexcept; + void SetHeight(float height) noexcept; + void SetNear(float znear) noexcept; + void SetFar(float zfar) noexcept; + void SetFOV(float fov) noexcept; + + + + float GetYaw() const noexcept; + float GetPitch() const noexcept; + float GetRoll() const noexcept; + + float GetAspectRatio() const noexcept; + float GetFOV() const noexcept; + + const SHMatrix& GetViewMatrix() const noexcept; + const SHMatrix& GetProjMatrix() const noexcept; + + void SetMainCamera(size_t cameraDirectorIndex = 0) noexcept; + + + float movementSpeed; + SHVec3 turnSpeed; + + protected: + + + + + }; + + +} diff --git a/SHADE_Engine/src/Camera/SHCameraDirector.cpp b/SHADE_Engine/src/Camera/SHCameraDirector.cpp new file mode 100644 index 00000000..559897c0 --- /dev/null +++ b/SHADE_Engine/src/Camera/SHCameraDirector.cpp @@ -0,0 +1,65 @@ +#include "SHpch.h" +#include "SHCameraDirector.h" +#include "SHCameraComponent.h" +#include "ECS_Base/Managers/SHComponentManager.h" +#include "ECS_Base/SHECSMacros.h" +#include "ECS_Base/Managers/SHEntityManager.h" +#include "Tools/SHLog.h" + +namespace SHADE +{ + SHCameraDirector::SHCameraDirector() + :mainCameraEID(MAX_EID), transitionCameraEID(MAX_EID) + { + } + + + SHMatrix SHCameraDirector::GetViewMatrix() const noexcept + { + return viewMatrix; + } + SHMatrix SHCameraDirector::GetProjMatrix() const noexcept + { + return projMatrix; + } + SHMatrix SHCameraDirector::GetVPMatrix() const noexcept + { + return projMatrix * viewMatrix; + } + + void SHCameraDirector::UpdateMatrix() noexcept + { + if (mainCameraEID == MAX_EID) + { + auto& dense = SHComponentManager::GetDense(); + if (dense.size() == 0) + { + return; + } + mainCameraEID = dense[0].GetEID(); + } + SHCameraComponent* camComponent = SHComponentManager::GetComponent_s(mainCameraEID); + if (!camComponent) + { + SHLOG_WARNING("Camera Director warning: Entity does not have a camera"); + } + else + { + viewMatrix = camComponent->GetViewMatrix(); + projMatrix = camComponent->GetProjMatrix(); + } + } + + void SHCameraDirector::SetMainCamera(SHCameraComponent& camera) noexcept + { + if (SHEntityManager::IsValidEID(camera.GetEID()) == false) + { + SHLOG_WARNING("Camera Director Warning: Attempting to set an invalid entity as main camera.") + return; + } + mainCameraEID = camera.GetEID(); + } + + + +} diff --git a/SHADE_Engine/src/Camera/SHCameraDirector.h b/SHADE_Engine/src/Camera/SHCameraDirector.h new file mode 100644 index 00000000..5d09788b --- /dev/null +++ b/SHADE_Engine/src/Camera/SHCameraDirector.h @@ -0,0 +1,43 @@ +#pragma once + +#include "SH_API.h" +#include "ECS_Base/Entity/SHEntity.h" +#include "Math/SHMatrix.h" +#include "Resource/SHHandle.h" + + +namespace SHADE +{ + class SHCameraComponent; + + + + class SH_API SHCameraDirector + { + public: + SHCameraDirector(); + ~SHCameraDirector() = default; + + + EntityID mainCameraEID; + EntityID transitionCameraEID; + + SHMatrix GetViewMatrix() const noexcept; + SHMatrix GetProjMatrix() const noexcept; + SHMatrix GetVPMatrix() const noexcept; + void UpdateMatrix() noexcept; + void SetMainCamera(SHCameraComponent& cam) noexcept; + + + private: + + + protected: + SHMatrix viewMatrix; + SHMatrix projMatrix; + + }; + + typedef Handle DirectorHandle; + +} diff --git a/SHADE_Engine/src/Camera/SHCameraSystem.cpp b/SHADE_Engine/src/Camera/SHCameraSystem.cpp new file mode 100644 index 00000000..0d86c17a --- /dev/null +++ b/SHADE_Engine/src/Camera/SHCameraSystem.cpp @@ -0,0 +1,291 @@ +#include "SHpch.h" +#include "SHCameraSystem.h" +#include "Math/SHMathHelpers.h" +#include "Input/SHInputManager.h" +#include "Math/Vector/SHVec2.h" +#include "ECS_Base/Managers/SHComponentManager.h" +#include "Math/Transform/SHTransformComponent.h" + + +namespace SHADE +{ + void SHCameraSystem::UpdateEditorCamera(double dt) noexcept + { + + auto& camera = editorCamera; + SHVec3 view, right, UP; + GetCameraAxis(camera, view, right, UP); + + if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::A)) + { + camera.position -= right * dt * camera.movementSpeed; + camera.dirtyView = true; + } + if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::D)) + { + camera.position += right * dt * camera.movementSpeed; + camera.dirtyView = true; + } + if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::W)) + { + camera.position += view * dt * camera.movementSpeed; + camera.dirtyView = true; + } + if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::S)) + { + camera.position -= view * dt * camera.movementSpeed; + camera.dirtyView = true; + } + if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::Q)) + { + camera.position += UP * dt * camera.movementSpeed; + camera.dirtyView = true; + } + if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::E)) + { + camera.position -= UP * dt * camera.movementSpeed; + camera.dirtyView = true; + } + if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::RMB)) + { + double mouseX, mouseY; + SHInputManager::GetMouseVelocity(&mouseX, &mouseY); + + //std::cout << camera.yaw << std::endl; + + camera.pitch -= mouseY * dt * camera.turnSpeed.x; + camera.yaw -= mouseX * dt * camera.turnSpeed.y; + camera.dirtyView = true; + } + + UpdateCameraComponent(editorCamera); + } + void SHCameraSystem::EditorCameraUpdate::Execute(double dt) noexcept + { + SHCameraSystem* system = static_cast(GetSystem()); + auto& camera = system->editorCamera; + SHVec3 view, right, UP; + system->GetCameraAxis(camera, view, right, UP); + + if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::A)) + { + //std::cout << "Camera movement: "<UpdateCameraComponent(system->editorCamera); + } + + void SHCameraSystem::Init(void) + { + editorCamera.SetPosition(0.0f, 0.0f, 0.0f); + editorCamera.SetPitch(0.0f); + editorCamera.SetYaw(0.0f); + editorCamera.SetRoll(0.0f); + editorCamera.movementSpeed = 2.0f; + + } + + void SHCameraSystem::Exit(void) + { + + } + + SHCameraComponent* SHCameraSystem::GetEditorCamera(void) noexcept + { + return &editorCamera; + } + + void SHCameraSystem::UpdateCameraComponent(SHCameraComponent& camera) noexcept + { + if (SHComponentManager::HasComponent(camera.GetEID()) == true && &camera != &editorCamera) + { + auto transform = SHComponentManager::GetComponent(camera.GetEID()); + SHVec3 rotation = transform->GetWorldRotation(); + camera.pitch = SHMath::RadiansToDegrees(rotation.x); + camera.yaw = SHMath::RadiansToDegrees(rotation.y); + camera.roll = SHMath::RadiansToDegrees(rotation.z); + camera.position = transform->GetWorldPosition(); + camera.dirtyView = true; + } + + + if (camera.dirtyView) + { + + SHVec3 view, right, UP; + + + //ClampCameraRotation(camera); + + GetCameraAxis(camera, view, right, UP); + + camera.viewMatrix = SHMatrix::Identity; + camera.viewMatrix(0, 0) = right[0]; + camera.viewMatrix(0, 1) = right[1]; + camera.viewMatrix(0, 2) = right[2]; + + camera.viewMatrix(1, 0) = UP[0]; + camera.viewMatrix(1, 1) = UP[1]; + camera.viewMatrix(1, 2) = UP[2]; + + camera.viewMatrix(2, 0) = view[0]; + camera.viewMatrix(2, 1) = view[1]; + camera.viewMatrix(2, 2) = view[2]; + + camera.viewMatrix(0, 3) = -right.Dot(camera.position); + camera.viewMatrix(1, 3) = -UP.Dot(camera.position); + camera.viewMatrix(2, 3) = -view.Dot(camera.position); + + camera.dirtyView = false; + } + if (camera.dirtyProj == true) + { + if (camera.perspProj == true) + { + const float ASPECT_RATIO = (camera.GetAspectRatio()); + const float TAN_HALF_FOV = tan(SHMath::DegreesToRadians(camera.fov) * 0.5f); + camera.projMatrix = SHMatrix::Identity; + camera.projMatrix(0, 0) = 1.0f / (ASPECT_RATIO * TAN_HALF_FOV); + camera.projMatrix(1, 1) = 1.0f / TAN_HALF_FOV; + camera.projMatrix(2, 2) = camera.zFar / (camera.zFar - camera.zNear); + camera.projMatrix(3, 3) = 0.0f; + + camera.projMatrix(3, 2) = 1.0f; + camera.projMatrix(2, 3) = -(camera.zFar * camera.zNear) / (camera.zFar - camera.zNear); + + + camera.dirtyProj = false; + } + else + { + //const float R = camera.width * 0.5f; + //const float L = -R; + //const float T = camera.height * 0.5f; + //const float B = -T; + + //camera.projMatrix = SHMatrix::Identity; + //camera.projMatrix(0, 0) = 2.0f / (R - L); + //camera.projMatrix(1, 1) = 2.0f / (B - T); + //camera.projMatrix(2, 2) = 1.0f / (camera.zFar - camera.zNear); + //camera.projMatrix(3, 0) = -(R + L) / (R - L); + //camera.projMatrix(3, 1) = -(B + T) / (B - T); + //camera.projMatrix(3, 2) = -camera.zNear / (camera.zFar - camera.zNear); + + camera.dirtyProj = false; + } + } + } + + void SHCameraSystem::GetCameraAxis(SHCameraComponent const& camera, SHVec3& forward, SHVec3& right, SHVec3& upVec) const noexcept + { + SHVec3 target{ 0.0f,0.0f,-1.0f }; + SHVec3 up = { 0.0f,1.0f,0.0f }; + + + target = SHVec3::RotateY(target, SHMath::DegreesToRadians(camera.yaw)); + target =SHVec3::RotateX(target, SHMath::DegreesToRadians(camera.pitch)); + target += camera.position; + ////SHVec3::RotateZ(target, SHMath::DegreesToRadians(camera.roll)); + + //target = SHVec3::Normalise(target); + + SHVec3::RotateZ(up, camera.roll); + up = SHVec3::Normalise(up); + + + forward = target - camera.position; forward = SHVec3::Normalise(forward); + right = SHVec3::Cross(forward, up); right = SHVec3::Normalise(right); + upVec = SHVec3::Cross(forward, right); + } + + void SHCameraSystem::CameraSystemUpdate::Execute(double dt) noexcept + { + SHCameraSystem* system = static_cast(GetSystem()); + auto& dense = SHComponentManager::GetDense(); + for (auto& cam : dense) + { + system->UpdateCameraComponent(cam); + } + for (auto& handle : system->directorHandleList) + { + handle->UpdateMatrix(); + } + + + } + + + DirectorHandle SHCameraSystem::CreateDirector() noexcept + { + auto handle = directorLibrary.Create(); + directorHandleList.emplace_back(handle); + return handle; + } + + DirectorHandle SHCameraSystem::GetDirector(size_t index) noexcept + { + if (index < directorHandleList.size()) + { + return directorHandleList[index]; + } + else + { + return CreateDirector(); + } + } + void SHCameraSystem::ClampCameraRotation(SHCameraComponent& camera) noexcept + { + + + + if (camera.pitch > 85) + camera.SetPitch(85); + if (camera.pitch < -85) + camera.SetPitch(-85); + if (camera.roll > 85) + camera.SetRoll(85); + if (camera.roll < -85) + camera.SetRoll(-85); + + } + +} diff --git a/SHADE_Engine/src/Camera/SHCameraSystem.h b/SHADE_Engine/src/Camera/SHCameraSystem.h new file mode 100644 index 00000000..68071160 --- /dev/null +++ b/SHADE_Engine/src/Camera/SHCameraSystem.h @@ -0,0 +1,64 @@ +#pragma once + +#include "ECS_Base/System/SHSystem.h" +#include "SHCameraComponent.h" +#include "ECS_Base/System/SHSystemRoutine.h" +#include "Resource/SHResourceLibrary.h" +#include "SHCameraDirector.h" +#include "SH_API.h" + +namespace SHADE +{ + class SH_API SHCameraSystem final : public SHSystem + { + private: + //A camera component that represents editor camera. + //This is not tied to any entity. Hence this EID should not be used. + SHCameraComponent editorCamera; + + SHResourceLibrary directorLibrary; + std::vector directorHandleList; + + public: + SHCameraSystem(void) = default; + virtual ~SHCameraSystem(void) = default; + + void Init (void); + void Exit (void); + + class SH_API EditorCameraUpdate final : public SHSystemRoutine + { + public: + + EditorCameraUpdate() : SHSystemRoutine("Editor Camera Update", true) { }; + virtual void Execute(double dt) noexcept override final; + + }; + friend class EditorCameraUpdate; + + class SH_API CameraSystemUpdate final: public SHSystemRoutine + { + public: + CameraSystemUpdate() : SHSystemRoutine("Camera System Update", false) {}; + virtual void Execute(double dt)noexcept override final; + }; + friend class CameraSystemUpdate; + + + SHCameraComponent* GetEditorCamera (void) noexcept; + void GetCameraAxis(SHCameraComponent const& camera, SHVec3& forward, SHVec3& right, SHVec3& up) const noexcept; + DirectorHandle CreateDirector() noexcept; + DirectorHandle GetDirector(size_t index) noexcept; + void ClampCameraRotation(SHCameraComponent& camera) noexcept; + void UpdateEditorCamera(double dt) noexcept; + protected: + + void UpdateCameraComponent(SHCameraComponent& camera) noexcept; + + + + }; + + + +} diff --git a/SHADE_Engine/src/ECS_Base/Components/SHComponent.h b/SHADE_Engine/src/ECS_Base/Components/SHComponent.h index cfcd724c..1c4e5de6 100644 --- a/SHADE_Engine/src/ECS_Base/Components/SHComponent.h +++ b/SHADE_Engine/src/ECS_Base/Components/SHComponent.h @@ -48,6 +48,9 @@ namespace SHADE { } + + + public: //Whether or not this component is active. //Systems using this component should are responsible for checking the active state of the component before running their functionality. @@ -59,7 +62,7 @@ namespace SHADE * \return uint32_t * The entityID that this component belongs to. ***************************************************************************/ - uint32_t GetEID()const + uint32_t GetEID()const noexcept { return this->entityID; } diff --git a/SHADE_Engine/src/Editor/Command/SHCommand.hpp b/SHADE_Engine/src/Editor/Command/SHCommand.hpp index 7a526506..149c8986 100644 --- a/SHADE_Engine/src/Editor/Command/SHCommand.hpp +++ b/SHADE_Engine/src/Editor/Command/SHCommand.hpp @@ -24,6 +24,7 @@ namespace SHADE class SHCommand : SHBaseCommand { public: + using SHCommandPtr = std::unique_ptr; typedef std::function SetterFunction; SHCommand(T const& oldVal, T const& value, SetterFunction setFnc) diff --git a/SHADE_Engine/src/Editor/Command/SHCommandManager.cpp b/SHADE_Engine/src/Editor/Command/SHCommandManager.cpp index ee2d316d..3c0ee5dd 100644 --- a/SHADE_Engine/src/Editor/Command/SHCommandManager.cpp +++ b/SHADE_Engine/src/Editor/Command/SHCommandManager.cpp @@ -13,7 +13,7 @@ namespace SHADE SHCommandManager::CommandStack SHCommandManager::undoStack{}; SHCommandManager::CommandStack SHCommandManager::redoStack{}; - void SHCommandManager::PerformCommand(CommandPtr commandPtr, bool const& overrideValue) + void SHCommandManager::PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue) { redoStack = CommandStack(); commandPtr->Execute(); @@ -27,9 +27,9 @@ namespace SHADE } } - void SHCommandManager::RegisterCommand(CommandPtr commandPtr) + void SHCommandManager::RegisterCommand(BaseCommandPtr commandPtr) { - undoStack.push(commandPtr); + undoStack.push(commandPtr); } void SHCommandManager::UndoCommand() @@ -59,4 +59,14 @@ namespace SHADE { return redoStack.size(); } + + void SHCommandManager::PopLatestCommandFromRedoStack() + { + redoStack.pop(); + } + + void SHCommandManager::PopLatestCommandFromUndoStack() + { + undoStack.pop(); + } }//namespace SHADE diff --git a/SHADE_Engine/src/Editor/Command/SHCommandManager.h b/SHADE_Engine/src/Editor/Command/SHCommandManager.h index 9152c3cb..a514c464 100644 --- a/SHADE_Engine/src/Editor/Command/SHCommandManager.h +++ b/SHADE_Engine/src/Editor/Command/SHCommandManager.h @@ -19,16 +19,21 @@ namespace SHADE //#==============================================================# //|| Type Aliases || //#==============================================================# - using CommandPtr = std::shared_ptr; - using CommandStack = std::stack; + using BaseCommandPtr = std::shared_ptr; + template + using SHCommandPtr = std::shared_ptr>; + using CommandStack = std::stack; - static void PerformCommand(CommandPtr commandPtr, bool const& overrideValue = false); - static void RegisterCommand(CommandPtr commandPtr); + static void PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue = false); + static void RegisterCommand(BaseCommandPtr commandPtr); static void UndoCommand(); static void RedoCommand(); static std::size_t GetUndoStackSize(); static std::size_t GetRedoStackSize(); + static void PopLatestCommandFromRedoStack(); + static void PopLatestCommandFromUndoStack(); + private: static CommandStack undoStack; static CommandStack redoStack; diff --git a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp index 0f25175f..27e46d98 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp @@ -21,6 +21,9 @@ //#==============================================================# #include +#include "Serialization/SHSerialization.h" +#include "Tools/SHClipboardUtilities.h" + namespace SHADE { @@ -50,6 +53,7 @@ namespace SHADE if(const auto root = sceneGraph.GetRoot()) { auto const& children = root->GetChildren(); + for (const auto child : children) { RecursivelyDrawEntityNode(child); @@ -66,8 +70,8 @@ namespace SHADE editor->selectedEntities.clear(); } ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal); - ImGui::End(); } + ImGui::End(); } void SHHierarchyPanel::Exit() @@ -75,6 +79,13 @@ namespace SHADE SHEditorWindow::Exit(); } + void SHHierarchyPanel::SetScrollTo(EntityID eid) + { + if(eid == MAX_EID) + return; + scrollTo = eid; + } + //#==============================================================# //|| Private Member Functions || //#==============================================================# @@ -82,9 +93,22 @@ namespace SHADE { if (ImGui::BeginMenuBar()) { - if (ImGui::SmallButton(ICON_MD_ADD)) + + ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x - 35.0f); + if(ImGui::SmallButton(ICON_MD_DESELECT)) { - SHEntityManager::CreateEntity(); + auto editor = SHSystemManager::GetSystem(); + editor->selectedEntities.clear(); + } + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Clear Selections"); + ImGui::EndTooltip(); + } + if (ImGui::SmallButton(ICON_MD_ADD_CIRCLE)) + { + SHCommandManager::PerformCommand(std::make_shared()); } if (ImGui::IsItemHovered()) { @@ -103,6 +127,13 @@ namespace SHADE //Get node data (Children, eid, selected) auto& children = currentNode->GetChildren(); EntityID eid = currentNode->GetEntityID(); + + if(scrollTo != MAX_EID && eid == scrollTo) + { + ImGui::SetScrollHereY(); + scrollTo = MAX_EID; + } + auto editor = SHSystemManager::GetSystem(); const bool isSelected = (std::ranges::find(editor->selectedEntities, eid) != editor->selectedEntities.end()); @@ -117,23 +148,32 @@ namespace SHADE auto* entity = SHEntityManager::GetEntityByID(currentNode->GetEntityID()); //Draw Node - bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast(entity), nodeFlags, "%u: %s", EntityHandleGenerator::GetIndex(eid), entity->name.c_str()); + bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast(entity), nodeFlags, "%u: %s", SHEntityManager::GetEntityIndex(eid), entity->name.c_str()); const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); //Check For Begin Drag if (SHDragDrop::BeginSource()) { - ImGui::Text("Moving EID: %zu", eid); - SHDragDrop::SetPayload(DRAG_EID, &eid); + std::string moveLabel = "Moving EID: "; + if(!isSelected) + editor->selectedEntities.push_back(eid); + for(int i = 0; i < static_cast(editor->selectedEntities.size()); ++i) + { + moveLabel.append(std::to_string(editor->selectedEntities[i])); + if(i + 1 < static_cast(editor->selectedEntities.size())) + { + moveLabel.append(", "); + } + } + ImGui::Text(moveLabel.c_str()); + SHDragDrop::SetPayload>(DRAG_EID, &editor->selectedEntities); SHDragDrop::EndSource(); } else if (SHDragDrop::BeginTarget()) //If Received DragDrop { - if (const EntityID* eidPayload = SHDragDrop::AcceptPayload(DRAG_EID)) //If payload is valid + if (const std::vector* eidPayload = SHDragDrop::AcceptPayload>(DRAG_EID)) //If payload is valid { - EntityID const dropEID = *eidPayload; - if(!sceneGraph.GetChild(dropEID, eid)) - sceneGraph.SetParent(dropEID, eid); //Set dropEID parent to eid (belonging to current Node) + ParentSelectedEntities(eid); SHDragDrop::EndTarget(); } } @@ -146,6 +186,18 @@ namespace SHADE editor->selectedEntities.clear(); editor->selectedEntities.push_back(eid); } + if(ImGui::Selectable("Copy")) + { + SHClipboardUtilities::WriteToClipboard(SHSerialization::SerializeEntitiesToString(editor->selectedEntities)); + } + if(ImGui::Selectable("Paste")) + { + SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard())); + } + if(ImGui::Selectable("Paste as Child")) + { + SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard(), eid)); + } if(ImGui::Selectable(std::format("{} Delete", ICON_MD_DELETE).data())) { SHEntityManager::DestroyEntity(eid); @@ -153,11 +205,11 @@ namespace SHADE if((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data())) { - sceneGraph.SetParent(currentNode->GetEntityID(), nullptr); + ParentSelectedEntities(MAX_EID); } ImGui::EndPopup(); } - + //Handle node selection if (ImGui::IsItemHovered()) { @@ -165,7 +217,15 @@ namespace SHADE { if (!isSelected) { - if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl)) + if(ImGui::IsKeyDown(ImGuiKey_LeftShift)) + { + if(editor->selectedEntities.size() >= 1) + { + SelectRangeOfEntities(editor->selectedEntities[0], eid); + } + else editor->selectedEntities.clear(); + } + else if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl)) editor->selectedEntities.clear(); editor->selectedEntities.push_back(eid); }//if not selected @@ -212,4 +272,90 @@ namespace SHADE { SHEntityManager::CreateEntity(MAX_EID, "DefaultChild", parentEID); } + + void SHHierarchyPanel::ParentSelectedEntities(EntityID parentEID) const noexcept + { + auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); + auto const editor = SHSystemManager::GetSystem(); + SHEntityParentCommand::EntityParentData entityParentData; + std::vector parentedEIDS; + for(auto const& eid : editor->selectedEntities) + { + if(sceneGraph.GetChild(eid, parentEID) == nullptr) + { + parentedEIDS.push_back(eid); + if(auto parent = sceneGraph.GetParent(eid)) + entityParentData[eid].oldParentEID = parent->GetEntityID(); + entityParentData[eid].newParentEID = parentEID; + } + } + SHCommandManager::PerformCommand(std::make_shared(parentedEIDS, entityParentData)); + } + + void SHHierarchyPanel::SelectRangeOfEntities(EntityID beginEID, EntityID endEID) + { + bool startSelecting = false; bool endSelecting = false; + auto const editor = SHSystemManager::GetSystem(); + editor->selectedEntities.clear(); + auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); + sceneGraph.Traverse([&](SHSceneNode* nodePtr) + { + auto eid = nodePtr->GetEntityID(); + if(!startSelecting) + { + if(eid == beginEID || eid == endEID) + { + startSelecting = true; + editor->selectedEntities.push_back(eid); + } + } + else + { + if(!endSelecting) + { + editor->selectedEntities.push_back(eid); + if(eid == endEID || eid == beginEID) + { + endSelecting = true; + } + } + } + }); + } + + void SHCreateEntityCommand::Execute() + { + EntityID newEID = SHEntityManager::CreateEntity(eid); + if(eid == MAX_EID) + eid = newEID; + } + + void SHCreateEntityCommand::Undo() + { + SHEntityManager::DestroyEntity(eid); + } + + void SHEntityParentCommand::Execute() + { + auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); + for(auto const& eid : entities) + { + if(entityParentData[eid].newParentEID == MAX_EID) + sceneGraph.SetParent(eid, nullptr); + else + sceneGraph.SetParent(eid, entityParentData[eid].newParentEID); + } + } + + void SHEntityParentCommand::Undo() + { + auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); + for(auto const& eid : entities) + { + if(entityParentData[eid].oldParentEID == MAX_EID) + sceneGraph.SetParent(eid, nullptr); + else + sceneGraph.SetParent(eid, entityParentData[eid].oldParentEID); + } + } }//namespace SHADE diff --git a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h index 78e445fd..0cfe6474 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h +++ b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h @@ -10,7 +10,7 @@ #include "imgui_internal.h" #include "ECS_Base/SHECSMacros.h" #include "Editor/EditorWindow/SHEditorWindow.h" - +#include "Editor/Command/SHCommand.hpp" namespace SHADE { class SHSceneNode; @@ -23,11 +23,45 @@ namespace SHADE void Init() override; void Update() override; void Exit() override; + void SetScrollTo(EntityID eid); private: void DrawMenuBar() const noexcept; ImRect RecursivelyDrawEntityNode(SHSceneNode*); void CreateChildEntity(EntityID parentEID) const noexcept; + void ParentSelectedEntities(EntityID parentEID) const noexcept; + void SelectRangeOfEntities(EntityID beginEID, EntityID EndEID); std::string filter; bool isAnyNodeSelected = false; + EntityID scrollTo = MAX_EID; };//class SHHierarchyPanel + + //Might move to a different file + class SHCreateEntityCommand final : public SHBaseCommand + { + public: + void Execute() override; + void Undo() override; + private: + EntityID eid = MAX_EID; + }; + + class SHEntityParentCommand final : public SHBaseCommand + { + public: + struct Data + { + EntityID oldParentEID = MAX_EID; + EntityID newParentEID = MAX_EID; + }; + using EntityParentData = std::unordered_map; + + SHEntityParentCommand(std::vector entityIDs, EntityParentData inEntityParentData):entities(entityIDs),entityParentData(inEntityParentData){} + + void Execute() override; + void Undo() override; + private: + std::vector entities; + std::unordered_map entityParentData; + }; + }//namespace SHADE diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 93f6984e..08f5695b 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -10,6 +10,7 @@ //|| SHADE Includes || //#==============================================================# #include "Editor/IconsMaterialDesign.h" +#include "Editor/IconsFontAwesome6.h" #include "ECS_Base/Components/SHComponent.h" #include "Editor/SHEditorWidgets.hpp" #include "Physics/Components/SHColliderComponent.h" @@ -207,14 +208,16 @@ namespace SHADE auto& colliders = component->GetColliders(); int const size = static_cast(colliders.size()); ImGui::BeginChild("Colliders", {0.0f, colliders.empty() ? 1.0f : 250.0f}, true); + std::optional colliderToDelete{std::nullopt}; for (int i{}; i < size; ++i) { + ImGui::PushID(i); SHCollider& collider = component->GetCollider(i); auto cursorPos = ImGui::GetCursorPos(); if (collider.GetType() == SHCollider::Type::BOX) { - SHEditorWidgets::BeginPanel( std::format("{} Box Collider #{}", ICON_MD_VIEW_IN_AR, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); + SHEditorWidgets::BeginPanel( std::format("{} Box Collider #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); auto box = reinterpret_cast(collider.GetShape()); SHEditorWidgets::DragVec3("Half Extents", { "X", "Y", "Z" }, [box] {return box->GetHalfExtents(); }, [box](SHVec3 const& vec) {box->SetHalfExtents(vec);}); } @@ -235,9 +238,14 @@ namespace SHADE } if(ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data())) { - component->RemoveCollider(i); + colliderToDelete = i; } SHEditorWidgets::EndPanel(); + ImGui::PopID(); + } + if(colliderToDelete.has_value()) + { + component->RemoveCollider(colliderToDelete.value()); } ImGui::EndChild(); diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index a9b1c724..b59ce9cc 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -55,7 +55,11 @@ namespace SHADE { EntityID const& eid = editor->selectedEntities[0]; SHEntity* entity = SHEntityManager::GetEntityByID(eid); - + if(!entity) + { + ImGui::End(); + return; + } ImGui::TextColored(ImGuiColors::green, "EID: %zu", eid); SHEditorWidgets::CheckBox("##IsActive", [entity]()->bool {return entity->GetActive(); }, [entity](bool const& active) {entity->SetActive(active); }); ImGui::SameLine(); @@ -99,8 +103,8 @@ namespace SHADE } } - ImGui::End(); } + ImGui::End(); } void SHEditorInspector::Exit() diff --git a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp index a49af994..c33f4fb6 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp @@ -17,6 +17,8 @@ #include #include +#include "Serialization/SHSerialization.h" + namespace SHADE { constexpr ImGuiWindowFlags editorMenuBarFlags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | @@ -36,6 +38,11 @@ namespace SHADE void SHEditorMenuBar::Init() { SHEditorWindow::Init(); + constexpr std::string_view path = "../../Assets/Editor/Layouts"; + for(auto const& entry : std::filesystem::directory_iterator(path)) + { + layoutPaths.push_back(entry.path()); + } } void SHEditorMenuBar::Update() @@ -68,7 +75,14 @@ namespace SHADE { if (ImGui::BeginMenu("File")) { - + if(ImGui::Selectable("Save")) + { + SHSerialization::SerializeSceneToFile("../../Assets/Scenes/Test.SHADE"); + } + if(ImGui::Selectable("Load")) + { + SHSerialization::DeserializeSceneFromFile("../../Assets/Scenes/Test.SHADE"); + } ImGui::EndMenu(); } if(ImGui::BeginMenu("Edit")) @@ -87,20 +101,6 @@ namespace SHADE ImGui::EndDisabled(); ImGui::EndMenu(); } - if(ImGui::BeginMenu("Theme")) - { - auto styles = rttr::type::get().get_enumeration(); - auto values = styles.get_values(); - for (auto style : values) - { - if(ImGui::Selectable(style.to_string().c_str())) - { - if(auto editor = SHSystemManager::GetSystem()) - editor->SetStyle(style.convert()); - } - } - ImGui::EndMenu(); - } if (ImGui::BeginMenu("Scripts")) { if (ImGui::Selectable("Generate Visual Studio Project")) @@ -120,18 +120,79 @@ namespace SHADE } ImGui::EndMenu(); } + + if (ImGui::BeginMenu("Window")) + { + for (const auto& window : SHEditorWindowManager::editorWindows | std::views::values) + { + if (window.get() != this) + ImGui::Checkbox(window->windowName.data(), &window->isOpen); + } + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Theme")) + { + const auto styles = rttr::type::get().get_enumeration(); + auto values = styles.get_values(); + for (auto style : values) + { + if (ImGui::Selectable(style.to_string().c_str())) + { + if (auto editor = SHSystemManager::GetSystem()) + editor->SetStyle(style.convert()); + } + } + ImGui::EndMenu(); + } + if(ImGui::BeginMenu("Layout")) + { + for(auto const& entry : layoutPaths) + { + if(ImGui::Selectable(entry.stem().string().c_str())) + { + ImGui::LoadIniSettingsFromDisk(entry.string().c_str()); + } + } + ImGui::EndMenu(); + } ImGui::EndMainMenuBar(); } - const ImGuiID dockspace_id = ImGui::GetID("DockSpace"); - ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspaceFlags); + const ImGuiID dockspaceId = ImGui::GetID("DockSpace"); + ImGui::DockSpace(dockspaceId, ImVec2(0.0f, 0.0f), dockspaceFlags); ImGui::End(); } } void SHEditorMenuBar::DrawSecondaryBar() const noexcept { - + ImGuiViewport* viewport = ImGui::GetMainViewport(); + if(ImGui::BeginViewportSideBar("##SecondaryMenuBar", viewport, ImGuiDir_Up, ImGui::GetFrameHeight(), ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_MenuBar)) + { + ImGui::BeginMenuBar(); + ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x * 0.5f - 80.f); + const auto editor = SHSystemManager::GetSystem(); + ImGui::BeginDisabled(editor->editorState == SHEditor::State::PLAY); + if(ImGui::SmallButton(ICON_MD_PLAY_ARROW)) + { + editor->editorState = SHEditor::State::PLAY; + } + ImGui::EndDisabled(); + ImGui::BeginDisabled(editor->editorState == SHEditor::State::PAUSE); + if(ImGui::SmallButton(ICON_MD_PAUSE)) + { + editor->editorState = SHEditor::State::PAUSE; + } + ImGui::EndDisabled(); + ImGui::BeginDisabled(editor->editorState == SHEditor::State::STOP); + if(ImGui::SmallButton(ICON_MD_STOP)) + { + editor->editorState = SHEditor::State::STOP; + } + ImGui::EndDisabled(); + ImGui::EndMenuBar(); + } + ImGui::End(); } void SHEditorMenuBar::DrawStatusBar() const noexcept @@ -142,8 +203,8 @@ namespace SHADE if (ImGui::BeginViewportSideBar("MainStatusBar", ImGui::GetMainViewport(), ImGuiDir_Down, menuBarHeight, editorMenuBarFlags)) { ImGui::Text("Entity count: "); - ImGui::End(); } + ImGui::End(); ImGui::PopStyleVar(3); } diff --git a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.h b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.h index 616ba43e..7cbcd696 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.h +++ b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.h @@ -18,5 +18,6 @@ namespace SHADE void DrawSecondaryBar() const noexcept; void DrawStatusBar() const noexcept; float menuBarHeight = 20.0f; + std::vector layoutPaths; };//class SHEditorMenuBar }//namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/Profiling/SHEditorProfiler.cpp b/SHADE_Engine/src/Editor/EditorWindow/Profiling/SHEditorProfiler.cpp index 4b36fe5d..11fcb7c2 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Profiling/SHEditorProfiler.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Profiling/SHEditorProfiler.cpp @@ -3,6 +3,7 @@ #include #include "ECS_Base/Managers/SHSystemManager.h" +#include "Editor/Command/SHCommandManager.h" #include "FRC/SHFramerateController.h" namespace SHADE @@ -37,8 +38,13 @@ namespace SHADE if(Begin()) { ImGui::PlotLines("DT", frames.data(), static_cast(frames.size()), 0, nullptr, 0.0f, 16.0f); - ImGui::End(); } + if(ImGui::CollapsingHeader("Command Manager")) + { + ImGui::Text("Undo: %zu", SHCommandManager::GetUndoStackSize()); + ImGui::Text("Redo: %zu", SHCommandManager::GetRedoStackSize()); + } + ImGui::End(); } void SHEditorProfiler::Exit() diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.cpp b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.cpp index 2e2c820c..b5a691d8 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.cpp @@ -19,7 +19,7 @@ namespace SHADE //|| Public Member Functions || //#==============================================================# SHEditorWindow::SHEditorWindow(std::string_view const& name, ImGuiWindowFlags const& inFlags) - : isOpen(true), windowName(name), windowFlags(inFlags), io(ImGui::GetIO()) + : windowName(name), windowFlags(inFlags), io(ImGui::GetIO()) { } @@ -40,7 +40,33 @@ namespace SHADE //#==============================================================# bool SHEditorWindow::Begin() { - return ImGui::Begin(windowName.data(), &isOpen, windowFlags); + bool result = ImGui::Begin(windowName.data(), &isOpen, windowFlags); + + auto wndSize = ImGui::GetWindowSize(); + auto contentRegionAvail = ImGui::GetContentRegionAvail(); + if( beginContentRegionAvailable.x != contentRegionAvail.x || beginContentRegionAvailable.y != contentRegionAvail.y || windowSize.x != wndSize.x || windowSize.y != wndSize.y) + { + windowSize = {wndSize.x, wndSize.y}; + beginContentRegionAvailable = {contentRegionAvail.x, contentRegionAvail.y}; + + OnResize(); + } + auto wndPos = ImGui::GetWindowPos(); + if(windowPos.x != wndPos.x || windowPos.y != wndPos.y) + { + windowPos = {wndPos.x, wndPos.y}; + OnPosChange(); + } + isWindowHovered = ImGui::IsWindowHovered(); + return result; + } + + void SHEditorWindow::OnResize() + { + } + + void SHEditorWindow::OnPosChange() + { } }//namespace SHADE diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.h b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.h index 244ef677..239d8223 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.h +++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindow.h @@ -5,6 +5,8 @@ //#==============================================================# #include +#include "Math/Vector/SHVec2.h" + //#==============================================================# //|| Forward Declarations || //#==============================================================# @@ -21,11 +23,20 @@ namespace SHADE virtual void Init(); virtual void Update(); virtual void Exit(); - bool isOpen = false; + bool isOpen; + bool isWindowHovered; std::string_view windowName; + SHVec2 windowSize; + SHVec2 windowPos; + SHVec2 viewportMousePos; + SHVec2 beginContentRegionAvailable; protected: virtual bool Begin(); + virtual void OnResize(); + virtual void OnPosChange(); + ImGuiWindowFlags windowFlags = 0; ImGuiIO& io; + };//class SHEditorWindow }//namespace SHADE diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h index d1ebfbf4..f0267b06 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h +++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h @@ -2,4 +2,5 @@ #include "MenuBar/SHEditorMenuBar.h" //Menu Bar #include "HierarchyPanel/SHHierarchyPanel.h" //Hierarchy Panel #include "Inspector/SHEditorInspector.h" //Inspector -#include "Profiling/SHEditorProfiler.h" //Profiler \ No newline at end of file +#include "Profiling/SHEditorProfiler.h" //Profiler +#include "ViewportWindow/SHEditorViewport.h" //Editor Viewport \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp b/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp new file mode 100644 index 00000000..b06c37c7 --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp @@ -0,0 +1,129 @@ +#include "SHpch.h" +#include "Editor/SHImGuiHelpers.hpp" +#include "SHEditorViewport.h" + +#include "ImGuizmo.h" +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Editor/IconsMaterialDesign.h" +#include "Editor/SHEditor.hpp" +#include "Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h" +#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h" +#include + +constexpr std::string_view windowName = "\xef\x80\x95 Viewport"; + +namespace SHADE +{ + SHEditorViewport::SHEditorViewport() + :SHEditorWindow("\xee\x90\x8b Viewport", ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoScrollbar) + { + } + + void SHEditorViewport::Init() + { + SHEditorWindow::Init(); + + } + + void SHEditorViewport::Update() + { + SHEditorWindow::Update(); + if(Begin()) + { + ImGuizmo::SetDrawlist(); + DrawMenuBar(); + auto gfxSystem = SHSystemManager::GetSystem(); + auto const& descriptorSet = gfxSystem->GetPostOffscreenRenderSystem()->GetDescriptorSetGroup()->GetVkHandle()[0]; + auto mousePos = ImGui::GetMousePos(); + beginCursorPos = ImGui::GetCursorScreenPos(); + viewportMousePos = {mousePos.x - beginCursorPos.x, mousePos.y - beginCursorPos.y}; + gfxSystem->GetMousePickSystem ()->SetViewportMousePos (viewportMousePos); + + ImGui::Image((ImTextureID)descriptorSet, {beginContentRegionAvailable.x, beginContentRegionAvailable.y}); + + if(ImGui::IsWindowHovered() && ImGui::IsMouseDown(ImGuiMouseButton_Right)) + { + ImGui::SetMouseCursor(ImGuiMouseCursor_None); + ImGui::SetCursorScreenPos(ImGui::GetMousePos()); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiColors::green); + ImGui::Text(ICON_FA_EYE); + ImGui::PopStyleColor(); + } + } + ImGuizmo::SetRect(beginCursorPos.x , beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y); + transformGizmo.Draw(); + ImGui::End(); + + } + + void SHEditorViewport::Exit() + { + SHEditorWindow::Exit(); + } + + void SHEditorViewport::OnResize() + { + SHEditorWindow::OnResize(); + //Get graphics system to resize swapchain image + auto gfxSystem = SHSystemManager::GetSystem(); + + //auto pos = ImGui::GetCursorPos(); + //windowCursorPos = {} + if(beginContentRegionAvailable.x == 0 || beginContentRegionAvailable.y == 0) + { + beginContentRegionAvailable = windowSize; + } + gfxSystem->PrepareResize(static_cast(beginContentRegionAvailable.x), static_cast(beginContentRegionAvailable.y)); + } + + void SHEditorViewport::OnPosChange() + { + SHEditorWindow::OnPosChange(); + } + + void SHEditorViewport::DrawMenuBar() noexcept + { + if(ImGui::BeginMenuBar()) + { + bool const isTranslate = transformGizmo.operation == SHTransformGizmo::Operation::TRANSLATE; + ImGui::BeginDisabled(isTranslate); + if(isTranslate) + ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]); + if(ImGui::Button(ICON_MD_OPEN_WITH)) + { + transformGizmo.operation = SHTransformGizmo::Operation::TRANSLATE; + } + ImGui::EndDisabled(); + if(isTranslate) + ImGui::PopStyleColor(); + + bool const isRotate = transformGizmo.operation == SHTransformGizmo::Operation::ROTATE; + ImGui::BeginDisabled(isRotate); + if(isRotate) + ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]); + if(ImGui::Button(ICON_MD_AUTORENEW)) + { + transformGizmo.operation = SHTransformGizmo::Operation::ROTATE; + } + ImGui::EndDisabled(); + if(isRotate) + ImGui::PopStyleColor(); + + bool const isScale = transformGizmo.operation == SHTransformGizmo::Operation::SCALE; + ImGui::BeginDisabled(isScale); + if(isScale) + ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]); + if(ImGui::Button(ICON_MD_EXPAND)) + { + transformGizmo.operation = SHTransformGizmo::Operation::SCALE; + } + ImGui::EndDisabled(); + if(isScale) + ImGui::PopStyleColor(); + + ImGui::EndMenuBar(); + } + } +}//namespace SHADE diff --git a/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.h b/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.h new file mode 100644 index 00000000..80b13285 --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.h @@ -0,0 +1,32 @@ +#pragma once +//#==============================================================# +//|| Library Includes || +//#==============================================================# +#include + +//#==============================================================# +//|| SHADE Includes || +//#==============================================================# +#include "imgui_internal.h" +#include "ECS_Base/SHECSMacros.h" +#include "Editor/EditorWindow/SHEditorWindow.h" +#include "Editor/Gizmos/SHTransformGizmo.h" + +namespace SHADE +{ + class SHEditorViewport final : public SHEditorWindow + { + public: + SHEditorViewport(); + void Init() override; + void Update() override; + void Exit() override; + SHTransformGizmo transformGizmo; + protected: + void OnResize() override; + void OnPosChange() override; + private: + void DrawMenuBar() noexcept; + SHVec2 beginCursorPos; + };//class SHEditorViewport +}//namespace SHADE diff --git a/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.cpp b/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.cpp new file mode 100644 index 00000000..a53b8c10 --- /dev/null +++ b/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.cpp @@ -0,0 +1,85 @@ +#include "SHpch.h" +#include "SHTransformGizmo.h" + +#include "ECS_Base/Managers/SHComponentManager.h" +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Editor/SHEditor.hpp" +#include "Editor/SHImGuiHelpers.hpp" +#include +#include + +#include "Camera/SHCameraSystem.h" +#include "Editor/Command/SHCommandManager.h" +#include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h" +namespace SHADE +{ + void SHTransformGizmo::Draw() + { + bool justChangedTfm = false; + if (!editorCamera) + { + auto const cameraSystem = SHSystemManager::GetSystem(); + editorCamera = cameraSystem->GetEditorCamera(); + } + auto viewportWindow = SHEditorWindowManager::GetEditorWindow(); + ImGuizmo::SetOrthographic(false); + + SHMatrix view = SHMatrix::Transpose(editorCamera->GetViewMatrix()); + SHMatrix proj = SHMatrix::Transpose(editorCamera->GetProjMatrix()); + proj(1, 1) *= -1; + static SHMatrix gridMat = SHMatrix::Translate(0, -0.5f, 0.f) * SHMatrix::Identity; + //ImGuizmo::DrawGrid(&view._11, &proj._11, &gridMat._11, 100.f); + if (selectedEntityTransformComponent == nullptr) + { + SHEditor* editor = SHSystemManager::GetSystem(); + if (editor->selectedEntities.empty()) + return; + EntityID eid = editor->selectedEntities.back(); + selectedEntityTransformComponent = SHComponentManager::GetComponent_s(eid); + justChangedTfm = true; + } + else + { + SHEditor* editor = SHSystemManager::GetSystem(); + if (editor->selectedEntities.empty()) + return; + EntityID eid = editor->selectedEntities.back(); + auto tfmComponent = SHComponentManager::GetComponent_s(eid); + if (selectedEntityTransformComponent != tfmComponent) + { + selectedEntityTransformComponent = tfmComponent; + justChangedTfm = true; + } + } + if (selectedEntityTransformComponent == nullptr) + return; + + SHMatrix mat = selectedEntityTransformComponent->GetTRS(); + isManipulating = ImGuizmo::Manipulate(&view._11, &proj._11, static_cast(operation), ImGuizmo::MODE::WORLD, &mat._11); + if (!justChangedTfm) + { + if (ImGui::IsItemClicked()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = std::move(selectedEntityTransformComponent)](SHMatrix const& mtx) + { + if (!tfm) + return; + SHVec3 translate{}, rotate{}, scale{}; + mtx.Decompose(translate, rotate, scale); + tfm->SetWorldPosition(translate); + tfm->SetWorldRotation(rotate); + tfm->SetWorldScale(scale); + }))); + else if (ImGui::IsItemHovered(ImGuiMouseButton_Left) && ImGui::IsMouseDown(ImGuiMouseButton_Left) && isManipulating) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = std::move(selectedEntityTransformComponent)](SHMatrix const& mtx) + { + if (!tfm) + return; + SHVec3 translate{}, rotate{}, scale{}; + mtx.Decompose(translate, rotate, scale); + tfm->SetWorldPosition(translate); + tfm->SetWorldRotation(rotate); + tfm->SetWorldScale(scale); + })), true); + } + } +} diff --git a/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.h b/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.h new file mode 100644 index 00000000..2565575f --- /dev/null +++ b/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.h @@ -0,0 +1,48 @@ +#pragma once +#include "Camera/SHCameraComponent.h" +#include "Math/Transform/SHTransformComponent.h" + +namespace SHADE +{ + class SHTransformGizmo + { + public: + enum class Mode + { + WORLD, + LOCAL + }; + + enum class Operation + { + TRANSLATE_X = (1u << 0), + TRANSLATE_Y = (1u << 1), + TRANSLATE_Z = (1u << 2), + ROTATE_X = (1u << 3), + ROTATE_Y = (1u << 4), + ROTATE_Z = (1u << 5), + ROTATE_SCREEN = (1u << 6), + SCALE_X = (1u << 7), + SCALE_Y = (1u << 8), + SCALE_Z = (1u << 9), + BOUNDS = (1u << 10), + SCALE_XU = (1u << 11), + SCALE_YU = (1u << 12), + SCALE_ZU = (1u << 13), + + TRANSLATE = TRANSLATE_X | TRANSLATE_Y | TRANSLATE_Z, + ROTATE = ROTATE_X | ROTATE_Y | ROTATE_Z | ROTATE_SCREEN, + SCALE = SCALE_X | SCALE_Y | SCALE_Z, + SCALEU = SCALE_XU | SCALE_YU | SCALE_ZU, // universal + UNIVERSAL = TRANSLATE | ROTATE | SCALEU + }; + + void Draw(); + bool isManipulating = false; + Mode mode = Mode::WORLD; + Operation operation = Operation::TRANSLATE; + private: + SHTransformComponent* selectedEntityTransformComponent{nullptr}; + SHCameraComponent* editorCamera{nullptr}; + }; +} diff --git a/SHADE_Engine/src/Editor/IconsFontAwesome6.h b/SHADE_Engine/src/Editor/IconsFontAwesome6.h new file mode 100644 index 00000000..77831d94 --- /dev/null +++ b/SHADE_Engine/src/Editor/IconsFontAwesome6.h @@ -0,0 +1,1400 @@ +#pragma once +// Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py for languages C and C++ +// from https://github.com/FortAwesome/Font-Awesome/raw/6.x/metadata/icons.yml +// for use with https://github.com/FortAwesome/Font-Awesome/blob/6.x/webfonts/fa-regular-400.ttf, https://github.com/FortAwesome/Font-Awesome/blob/6.x/webfonts/fa-solid-900.ttf +#pragma once + +#define FONT_ICON_FILE_NAME_FAR "fa-regular-400.ttf" +#define FONT_ICON_FILE_NAME_FAS "fa-solid-900.ttf" + +#define ICON_MIN_FA 0xe005 +#define ICON_MAX_16_FA 0xf8ff +#define ICON_MAX_FA 0xf8ff +#define ICON_FA_0 "0" // U+0030 +#define ICON_FA_1 "1" // U+0031 +#define ICON_FA_2 "2" // U+0032 +#define ICON_FA_3 "3" // U+0033 +#define ICON_FA_4 "4" // U+0034 +#define ICON_FA_5 "5" // U+0035 +#define ICON_FA_6 "6" // U+0036 +#define ICON_FA_7 "7" // U+0037 +#define ICON_FA_8 "8" // U+0038 +#define ICON_FA_9 "9" // U+0039 +#define ICON_FA_A "A" // U+0041 +#define ICON_FA_ADDRESS_BOOK "\xef\x8a\xb9" // U+f2b9 +#define ICON_FA_ADDRESS_CARD "\xef\x8a\xbb" // U+f2bb +#define ICON_FA_ALIGN_CENTER "\xef\x80\xb7" // U+f037 +#define ICON_FA_ALIGN_JUSTIFY "\xef\x80\xb9" // U+f039 +#define ICON_FA_ALIGN_LEFT "\xef\x80\xb6" // U+f036 +#define ICON_FA_ALIGN_RIGHT "\xef\x80\xb8" // U+f038 +#define ICON_FA_ANCHOR "\xef\x84\xbd" // U+f13d +#define ICON_FA_ANCHOR_CIRCLE_CHECK "\xee\x92\xaa" // U+e4aa +#define ICON_FA_ANCHOR_CIRCLE_EXCLAMATION "\xee\x92\xab" // U+e4ab +#define ICON_FA_ANCHOR_CIRCLE_XMARK "\xee\x92\xac" // U+e4ac +#define ICON_FA_ANCHOR_LOCK "\xee\x92\xad" // U+e4ad +#define ICON_FA_ANGLE_DOWN "\xef\x84\x87" // U+f107 +#define ICON_FA_ANGLE_LEFT "\xef\x84\x84" // U+f104 +#define ICON_FA_ANGLE_RIGHT "\xef\x84\x85" // U+f105 +#define ICON_FA_ANGLE_UP "\xef\x84\x86" // U+f106 +#define ICON_FA_ANGLES_DOWN "\xef\x84\x83" // U+f103 +#define ICON_FA_ANGLES_LEFT "\xef\x84\x80" // U+f100 +#define ICON_FA_ANGLES_RIGHT "\xef\x84\x81" // U+f101 +#define ICON_FA_ANGLES_UP "\xef\x84\x82" // U+f102 +#define ICON_FA_ANKH "\xef\x99\x84" // U+f644 +#define ICON_FA_APPLE_WHOLE "\xef\x97\x91" // U+f5d1 +#define ICON_FA_ARCHWAY "\xef\x95\x97" // U+f557 +#define ICON_FA_ARROW_DOWN "\xef\x81\xa3" // U+f063 +#define ICON_FA_ARROW_DOWN_1_9 "\xef\x85\xa2" // U+f162 +#define ICON_FA_ARROW_DOWN_9_1 "\xef\xa2\x86" // U+f886 +#define ICON_FA_ARROW_DOWN_A_Z "\xef\x85\x9d" // U+f15d +#define ICON_FA_ARROW_DOWN_LONG "\xef\x85\xb5" // U+f175 +#define ICON_FA_ARROW_DOWN_SHORT_WIDE "\xef\xa2\x84" // U+f884 +#define ICON_FA_ARROW_DOWN_UP_ACROSS_LINE "\xee\x92\xaf" // U+e4af +#define ICON_FA_ARROW_DOWN_UP_LOCK "\xee\x92\xb0" // U+e4b0 +#define ICON_FA_ARROW_DOWN_WIDE_SHORT "\xef\x85\xa0" // U+f160 +#define ICON_FA_ARROW_DOWN_Z_A "\xef\xa2\x81" // U+f881 +#define ICON_FA_ARROW_LEFT "\xef\x81\xa0" // U+f060 +#define ICON_FA_ARROW_LEFT_LONG "\xef\x85\xb7" // U+f177 +#define ICON_FA_ARROW_POINTER "\xef\x89\x85" // U+f245 +#define ICON_FA_ARROW_RIGHT "\xef\x81\xa1" // U+f061 +#define ICON_FA_ARROW_RIGHT_ARROW_LEFT "\xef\x83\xac" // U+f0ec +#define ICON_FA_ARROW_RIGHT_FROM_BRACKET "\xef\x82\x8b" // U+f08b +#define ICON_FA_ARROW_RIGHT_LONG "\xef\x85\xb8" // U+f178 +#define ICON_FA_ARROW_RIGHT_TO_BRACKET "\xef\x82\x90" // U+f090 +#define ICON_FA_ARROW_RIGHT_TO_CITY "\xee\x92\xb3" // U+e4b3 +#define ICON_FA_ARROW_ROTATE_LEFT "\xef\x83\xa2" // U+f0e2 +#define ICON_FA_ARROW_ROTATE_RIGHT "\xef\x80\x9e" // U+f01e +#define ICON_FA_ARROW_TREND_DOWN "\xee\x82\x97" // U+e097 +#define ICON_FA_ARROW_TREND_UP "\xee\x82\x98" // U+e098 +#define ICON_FA_ARROW_TURN_DOWN "\xef\x85\x89" // U+f149 +#define ICON_FA_ARROW_TURN_UP "\xef\x85\x88" // U+f148 +#define ICON_FA_ARROW_UP "\xef\x81\xa2" // U+f062 +#define ICON_FA_ARROW_UP_1_9 "\xef\x85\xa3" // U+f163 +#define ICON_FA_ARROW_UP_9_1 "\xef\xa2\x87" // U+f887 +#define ICON_FA_ARROW_UP_A_Z "\xef\x85\x9e" // U+f15e +#define ICON_FA_ARROW_UP_FROM_BRACKET "\xee\x82\x9a" // U+e09a +#define ICON_FA_ARROW_UP_FROM_GROUND_WATER "\xee\x92\xb5" // U+e4b5 +#define ICON_FA_ARROW_UP_FROM_WATER_PUMP "\xee\x92\xb6" // U+e4b6 +#define ICON_FA_ARROW_UP_LONG "\xef\x85\xb6" // U+f176 +#define ICON_FA_ARROW_UP_RIGHT_DOTS "\xee\x92\xb7" // U+e4b7 +#define ICON_FA_ARROW_UP_RIGHT_FROM_SQUARE "\xef\x82\x8e" // U+f08e +#define ICON_FA_ARROW_UP_SHORT_WIDE "\xef\xa2\x85" // U+f885 +#define ICON_FA_ARROW_UP_WIDE_SHORT "\xef\x85\xa1" // U+f161 +#define ICON_FA_ARROW_UP_Z_A "\xef\xa2\x82" // U+f882 +#define ICON_FA_ARROWS_DOWN_TO_LINE "\xee\x92\xb8" // U+e4b8 +#define ICON_FA_ARROWS_DOWN_TO_PEOPLE "\xee\x92\xb9" // U+e4b9 +#define ICON_FA_ARROWS_LEFT_RIGHT "\xef\x81\xbe" // U+f07e +#define ICON_FA_ARROWS_LEFT_RIGHT_TO_LINE "\xee\x92\xba" // U+e4ba +#define ICON_FA_ARROWS_ROTATE "\xef\x80\xa1" // U+f021 +#define ICON_FA_ARROWS_SPIN "\xee\x92\xbb" // U+e4bb +#define ICON_FA_ARROWS_SPLIT_UP_AND_LEFT "\xee\x92\xbc" // U+e4bc +#define ICON_FA_ARROWS_TO_CIRCLE "\xee\x92\xbd" // U+e4bd +#define ICON_FA_ARROWS_TO_DOT "\xee\x92\xbe" // U+e4be +#define ICON_FA_ARROWS_TO_EYE "\xee\x92\xbf" // U+e4bf +#define ICON_FA_ARROWS_TURN_RIGHT "\xee\x93\x80" // U+e4c0 +#define ICON_FA_ARROWS_TURN_TO_DOTS "\xee\x93\x81" // U+e4c1 +#define ICON_FA_ARROWS_UP_DOWN "\xef\x81\xbd" // U+f07d +#define ICON_FA_ARROWS_UP_DOWN_LEFT_RIGHT "\xef\x81\x87" // U+f047 +#define ICON_FA_ARROWS_UP_TO_LINE "\xee\x93\x82" // U+e4c2 +#define ICON_FA_ASTERISK "*" // U+002a +#define ICON_FA_AT "@" // U+0040 +#define ICON_FA_ATOM "\xef\x97\x92" // U+f5d2 +#define ICON_FA_AUDIO_DESCRIPTION "\xef\x8a\x9e" // U+f29e +#define ICON_FA_AUSTRAL_SIGN "\xee\x82\xa9" // U+e0a9 +#define ICON_FA_AWARD "\xef\x95\x99" // U+f559 +#define ICON_FA_B "B" // U+0042 +#define ICON_FA_BABY "\xef\x9d\xbc" // U+f77c +#define ICON_FA_BABY_CARRIAGE "\xef\x9d\xbd" // U+f77d +#define ICON_FA_BACKWARD "\xef\x81\x8a" // U+f04a +#define ICON_FA_BACKWARD_FAST "\xef\x81\x89" // U+f049 +#define ICON_FA_BACKWARD_STEP "\xef\x81\x88" // U+f048 +#define ICON_FA_BACON "\xef\x9f\xa5" // U+f7e5 +#define ICON_FA_BACTERIA "\xee\x81\x99" // U+e059 +#define ICON_FA_BACTERIUM "\xee\x81\x9a" // U+e05a +#define ICON_FA_BAG_SHOPPING "\xef\x8a\x90" // U+f290 +#define ICON_FA_BAHAI "\xef\x99\xa6" // U+f666 +#define ICON_FA_BAHT_SIGN "\xee\x82\xac" // U+e0ac +#define ICON_FA_BAN "\xef\x81\x9e" // U+f05e +#define ICON_FA_BAN_SMOKING "\xef\x95\x8d" // U+f54d +#define ICON_FA_BANDAGE "\xef\x91\xa2" // U+f462 +#define ICON_FA_BARCODE "\xef\x80\xaa" // U+f02a +#define ICON_FA_BARS "\xef\x83\x89" // U+f0c9 +#define ICON_FA_BARS_PROGRESS "\xef\xa0\xa8" // U+f828 +#define ICON_FA_BARS_STAGGERED "\xef\x95\x90" // U+f550 +#define ICON_FA_BASEBALL "\xef\x90\xb3" // U+f433 +#define ICON_FA_BASEBALL_BAT_BALL "\xef\x90\xb2" // U+f432 +#define ICON_FA_BASKET_SHOPPING "\xef\x8a\x91" // U+f291 +#define ICON_FA_BASKETBALL "\xef\x90\xb4" // U+f434 +#define ICON_FA_BATH "\xef\x8b\x8d" // U+f2cd +#define ICON_FA_BATTERY_EMPTY "\xef\x89\x84" // U+f244 +#define ICON_FA_BATTERY_FULL "\xef\x89\x80" // U+f240 +#define ICON_FA_BATTERY_HALF "\xef\x89\x82" // U+f242 +#define ICON_FA_BATTERY_QUARTER "\xef\x89\x83" // U+f243 +#define ICON_FA_BATTERY_THREE_QUARTERS "\xef\x89\x81" // U+f241 +#define ICON_FA_BED "\xef\x88\xb6" // U+f236 +#define ICON_FA_BED_PULSE "\xef\x92\x87" // U+f487 +#define ICON_FA_BEER_MUG_EMPTY "\xef\x83\xbc" // U+f0fc +#define ICON_FA_BELL "\xef\x83\xb3" // U+f0f3 +#define ICON_FA_BELL_CONCIERGE "\xef\x95\xa2" // U+f562 +#define ICON_FA_BELL_SLASH "\xef\x87\xb6" // U+f1f6 +#define ICON_FA_BEZIER_CURVE "\xef\x95\x9b" // U+f55b +#define ICON_FA_BICYCLE "\xef\x88\x86" // U+f206 +#define ICON_FA_BINOCULARS "\xef\x87\xa5" // U+f1e5 +#define ICON_FA_BIOHAZARD "\xef\x9e\x80" // U+f780 +#define ICON_FA_BITCOIN_SIGN "\xee\x82\xb4" // U+e0b4 +#define ICON_FA_BLENDER "\xef\x94\x97" // U+f517 +#define ICON_FA_BLENDER_PHONE "\xef\x9a\xb6" // U+f6b6 +#define ICON_FA_BLOG "\xef\x9e\x81" // U+f781 +#define ICON_FA_BOLD "\xef\x80\xb2" // U+f032 +#define ICON_FA_BOLT "\xef\x83\xa7" // U+f0e7 +#define ICON_FA_BOLT_LIGHTNING "\xee\x82\xb7" // U+e0b7 +#define ICON_FA_BOMB "\xef\x87\xa2" // U+f1e2 +#define ICON_FA_BONE "\xef\x97\x97" // U+f5d7 +#define ICON_FA_BONG "\xef\x95\x9c" // U+f55c +#define ICON_FA_BOOK "\xef\x80\xad" // U+f02d +#define ICON_FA_BOOK_ATLAS "\xef\x95\x98" // U+f558 +#define ICON_FA_BOOK_BIBLE "\xef\x99\x87" // U+f647 +#define ICON_FA_BOOK_BOOKMARK "\xee\x82\xbb" // U+e0bb +#define ICON_FA_BOOK_JOURNAL_WHILLS "\xef\x99\xaa" // U+f66a +#define ICON_FA_BOOK_MEDICAL "\xef\x9f\xa6" // U+f7e6 +#define ICON_FA_BOOK_OPEN "\xef\x94\x98" // U+f518 +#define ICON_FA_BOOK_OPEN_READER "\xef\x97\x9a" // U+f5da +#define ICON_FA_BOOK_QURAN "\xef\x9a\x87" // U+f687 +#define ICON_FA_BOOK_SKULL "\xef\x9a\xb7" // U+f6b7 +#define ICON_FA_BOOK_TANAKH "\xef\xa0\xa7" // U+f827 +#define ICON_FA_BOOKMARK "\xef\x80\xae" // U+f02e +#define ICON_FA_BORDER_ALL "\xef\xa1\x8c" // U+f84c +#define ICON_FA_BORDER_NONE "\xef\xa1\x90" // U+f850 +#define ICON_FA_BORDER_TOP_LEFT "\xef\xa1\x93" // U+f853 +#define ICON_FA_BORE_HOLE "\xee\x93\x83" // U+e4c3 +#define ICON_FA_BOTTLE_DROPLET "\xee\x93\x84" // U+e4c4 +#define ICON_FA_BOTTLE_WATER "\xee\x93\x85" // U+e4c5 +#define ICON_FA_BOWL_FOOD "\xee\x93\x86" // U+e4c6 +#define ICON_FA_BOWL_RICE "\xee\x8b\xab" // U+e2eb +#define ICON_FA_BOWLING_BALL "\xef\x90\xb6" // U+f436 +#define ICON_FA_BOX "\xef\x91\xa6" // U+f466 +#define ICON_FA_BOX_ARCHIVE "\xef\x86\x87" // U+f187 +#define ICON_FA_BOX_OPEN "\xef\x92\x9e" // U+f49e +#define ICON_FA_BOX_TISSUE "\xee\x81\x9b" // U+e05b +#define ICON_FA_BOXES_PACKING "\xee\x93\x87" // U+e4c7 +#define ICON_FA_BOXES_STACKED "\xef\x91\xa8" // U+f468 +#define ICON_FA_BRAILLE "\xef\x8a\xa1" // U+f2a1 +#define ICON_FA_BRAIN "\xef\x97\x9c" // U+f5dc +#define ICON_FA_BRAZILIAN_REAL_SIGN "\xee\x91\xac" // U+e46c +#define ICON_FA_BREAD_SLICE "\xef\x9f\xac" // U+f7ec +#define ICON_FA_BRIDGE "\xee\x93\x88" // U+e4c8 +#define ICON_FA_BRIDGE_CIRCLE_CHECK "\xee\x93\x89" // U+e4c9 +#define ICON_FA_BRIDGE_CIRCLE_EXCLAMATION "\xee\x93\x8a" // U+e4ca +#define ICON_FA_BRIDGE_CIRCLE_XMARK "\xee\x93\x8b" // U+e4cb +#define ICON_FA_BRIDGE_LOCK "\xee\x93\x8c" // U+e4cc +#define ICON_FA_BRIDGE_WATER "\xee\x93\x8e" // U+e4ce +#define ICON_FA_BRIEFCASE "\xef\x82\xb1" // U+f0b1 +#define ICON_FA_BRIEFCASE_MEDICAL "\xef\x91\xa9" // U+f469 +#define ICON_FA_BROOM "\xef\x94\x9a" // U+f51a +#define ICON_FA_BROOM_BALL "\xef\x91\x98" // U+f458 +#define ICON_FA_BRUSH "\xef\x95\x9d" // U+f55d +#define ICON_FA_BUCKET "\xee\x93\x8f" // U+e4cf +#define ICON_FA_BUG "\xef\x86\x88" // U+f188 +#define ICON_FA_BUG_SLASH "\xee\x92\x90" // U+e490 +#define ICON_FA_BUGS "\xee\x93\x90" // U+e4d0 +#define ICON_FA_BUILDING "\xef\x86\xad" // U+f1ad +#define ICON_FA_BUILDING_CIRCLE_ARROW_RIGHT "\xee\x93\x91" // U+e4d1 +#define ICON_FA_BUILDING_CIRCLE_CHECK "\xee\x93\x92" // U+e4d2 +#define ICON_FA_BUILDING_CIRCLE_EXCLAMATION "\xee\x93\x93" // U+e4d3 +#define ICON_FA_BUILDING_CIRCLE_XMARK "\xee\x93\x94" // U+e4d4 +#define ICON_FA_BUILDING_COLUMNS "\xef\x86\x9c" // U+f19c +#define ICON_FA_BUILDING_FLAG "\xee\x93\x95" // U+e4d5 +#define ICON_FA_BUILDING_LOCK "\xee\x93\x96" // U+e4d6 +#define ICON_FA_BUILDING_NGO "\xee\x93\x97" // U+e4d7 +#define ICON_FA_BUILDING_SHIELD "\xee\x93\x98" // U+e4d8 +#define ICON_FA_BUILDING_UN "\xee\x93\x99" // U+e4d9 +#define ICON_FA_BUILDING_USER "\xee\x93\x9a" // U+e4da +#define ICON_FA_BUILDING_WHEAT "\xee\x93\x9b" // U+e4db +#define ICON_FA_BULLHORN "\xef\x82\xa1" // U+f0a1 +#define ICON_FA_BULLSEYE "\xef\x85\x80" // U+f140 +#define ICON_FA_BURGER "\xef\xa0\x85" // U+f805 +#define ICON_FA_BURST "\xee\x93\x9c" // U+e4dc +#define ICON_FA_BUS "\xef\x88\x87" // U+f207 +#define ICON_FA_BUS_SIMPLE "\xef\x95\x9e" // U+f55e +#define ICON_FA_BUSINESS_TIME "\xef\x99\x8a" // U+f64a +#define ICON_FA_C "C" // U+0043 +#define ICON_FA_CABLE_CAR "\xef\x9f\x9a" // U+f7da +#define ICON_FA_CAKE_CANDLES "\xef\x87\xbd" // U+f1fd +#define ICON_FA_CALCULATOR "\xef\x87\xac" // U+f1ec +#define ICON_FA_CALENDAR "\xef\x84\xb3" // U+f133 +#define ICON_FA_CALENDAR_CHECK "\xef\x89\xb4" // U+f274 +#define ICON_FA_CALENDAR_DAY "\xef\x9e\x83" // U+f783 +#define ICON_FA_CALENDAR_DAYS "\xef\x81\xb3" // U+f073 +#define ICON_FA_CALENDAR_MINUS "\xef\x89\xb2" // U+f272 +#define ICON_FA_CALENDAR_PLUS "\xef\x89\xb1" // U+f271 +#define ICON_FA_CALENDAR_WEEK "\xef\x9e\x84" // U+f784 +#define ICON_FA_CALENDAR_XMARK "\xef\x89\xb3" // U+f273 +#define ICON_FA_CAMERA "\xef\x80\xb0" // U+f030 +#define ICON_FA_CAMERA_RETRO "\xef\x82\x83" // U+f083 +#define ICON_FA_CAMERA_ROTATE "\xee\x83\x98" // U+e0d8 +#define ICON_FA_CAMPGROUND "\xef\x9a\xbb" // U+f6bb +#define ICON_FA_CANDY_CANE "\xef\x9e\x86" // U+f786 +#define ICON_FA_CANNABIS "\xef\x95\x9f" // U+f55f +#define ICON_FA_CAPSULES "\xef\x91\xab" // U+f46b +#define ICON_FA_CAR "\xef\x86\xb9" // U+f1b9 +#define ICON_FA_CAR_BATTERY "\xef\x97\x9f" // U+f5df +#define ICON_FA_CAR_BURST "\xef\x97\xa1" // U+f5e1 +#define ICON_FA_CAR_ON "\xee\x93\x9d" // U+e4dd +#define ICON_FA_CAR_REAR "\xef\x97\x9e" // U+f5de +#define ICON_FA_CAR_SIDE "\xef\x97\xa4" // U+f5e4 +#define ICON_FA_CAR_TUNNEL "\xee\x93\x9e" // U+e4de +#define ICON_FA_CARAVAN "\xef\xa3\xbf" // U+f8ff +#define ICON_FA_CARET_DOWN "\xef\x83\x97" // U+f0d7 +#define ICON_FA_CARET_LEFT "\xef\x83\x99" // U+f0d9 +#define ICON_FA_CARET_RIGHT "\xef\x83\x9a" // U+f0da +#define ICON_FA_CARET_UP "\xef\x83\x98" // U+f0d8 +#define ICON_FA_CARROT "\xef\x9e\x87" // U+f787 +#define ICON_FA_CART_ARROW_DOWN "\xef\x88\x98" // U+f218 +#define ICON_FA_CART_FLATBED "\xef\x91\xb4" // U+f474 +#define ICON_FA_CART_FLATBED_SUITCASE "\xef\x96\x9d" // U+f59d +#define ICON_FA_CART_PLUS "\xef\x88\x97" // U+f217 +#define ICON_FA_CART_SHOPPING "\xef\x81\xba" // U+f07a +#define ICON_FA_CASH_REGISTER "\xef\x9e\x88" // U+f788 +#define ICON_FA_CAT "\xef\x9a\xbe" // U+f6be +#define ICON_FA_CEDI_SIGN "\xee\x83\x9f" // U+e0df +#define ICON_FA_CENT_SIGN "\xee\x8f\xb5" // U+e3f5 +#define ICON_FA_CERTIFICATE "\xef\x82\xa3" // U+f0a3 +#define ICON_FA_CHAIR "\xef\x9b\x80" // U+f6c0 +#define ICON_FA_CHALKBOARD "\xef\x94\x9b" // U+f51b +#define ICON_FA_CHALKBOARD_USER "\xef\x94\x9c" // U+f51c +#define ICON_FA_CHAMPAGNE_GLASSES "\xef\x9e\x9f" // U+f79f +#define ICON_FA_CHARGING_STATION "\xef\x97\xa7" // U+f5e7 +#define ICON_FA_CHART_AREA "\xef\x87\xbe" // U+f1fe +#define ICON_FA_CHART_BAR "\xef\x82\x80" // U+f080 +#define ICON_FA_CHART_COLUMN "\xee\x83\xa3" // U+e0e3 +#define ICON_FA_CHART_GANTT "\xee\x83\xa4" // U+e0e4 +#define ICON_FA_CHART_LINE "\xef\x88\x81" // U+f201 +#define ICON_FA_CHART_PIE "\xef\x88\x80" // U+f200 +#define ICON_FA_CHART_SIMPLE "\xee\x91\xb3" // U+e473 +#define ICON_FA_CHECK "\xef\x80\x8c" // U+f00c +#define ICON_FA_CHECK_DOUBLE "\xef\x95\xa0" // U+f560 +#define ICON_FA_CHECK_TO_SLOT "\xef\x9d\xb2" // U+f772 +#define ICON_FA_CHEESE "\xef\x9f\xaf" // U+f7ef +#define ICON_FA_CHESS "\xef\x90\xb9" // U+f439 +#define ICON_FA_CHESS_BISHOP "\xef\x90\xba" // U+f43a +#define ICON_FA_CHESS_BOARD "\xef\x90\xbc" // U+f43c +#define ICON_FA_CHESS_KING "\xef\x90\xbf" // U+f43f +#define ICON_FA_CHESS_KNIGHT "\xef\x91\x81" // U+f441 +#define ICON_FA_CHESS_PAWN "\xef\x91\x83" // U+f443 +#define ICON_FA_CHESS_QUEEN "\xef\x91\x85" // U+f445 +#define ICON_FA_CHESS_ROOK "\xef\x91\x87" // U+f447 +#define ICON_FA_CHEVRON_DOWN "\xef\x81\xb8" // U+f078 +#define ICON_FA_CHEVRON_LEFT "\xef\x81\x93" // U+f053 +#define ICON_FA_CHEVRON_RIGHT "\xef\x81\x94" // U+f054 +#define ICON_FA_CHEVRON_UP "\xef\x81\xb7" // U+f077 +#define ICON_FA_CHILD "\xef\x86\xae" // U+f1ae +#define ICON_FA_CHILD_DRESS "\xee\x96\x9c" // U+e59c +#define ICON_FA_CHILD_REACHING "\xee\x96\x9d" // U+e59d +#define ICON_FA_CHILD_RIFLE "\xee\x93\xa0" // U+e4e0 +#define ICON_FA_CHILDREN "\xee\x93\xa1" // U+e4e1 +#define ICON_FA_CHURCH "\xef\x94\x9d" // U+f51d +#define ICON_FA_CIRCLE "\xef\x84\x91" // U+f111 +#define ICON_FA_CIRCLE_ARROW_DOWN "\xef\x82\xab" // U+f0ab +#define ICON_FA_CIRCLE_ARROW_LEFT "\xef\x82\xa8" // U+f0a8 +#define ICON_FA_CIRCLE_ARROW_RIGHT "\xef\x82\xa9" // U+f0a9 +#define ICON_FA_CIRCLE_ARROW_UP "\xef\x82\xaa" // U+f0aa +#define ICON_FA_CIRCLE_CHECK "\xef\x81\x98" // U+f058 +#define ICON_FA_CIRCLE_CHEVRON_DOWN "\xef\x84\xba" // U+f13a +#define ICON_FA_CIRCLE_CHEVRON_LEFT "\xef\x84\xb7" // U+f137 +#define ICON_FA_CIRCLE_CHEVRON_RIGHT "\xef\x84\xb8" // U+f138 +#define ICON_FA_CIRCLE_CHEVRON_UP "\xef\x84\xb9" // U+f139 +#define ICON_FA_CIRCLE_DOLLAR_TO_SLOT "\xef\x92\xb9" // U+f4b9 +#define ICON_FA_CIRCLE_DOT "\xef\x86\x92" // U+f192 +#define ICON_FA_CIRCLE_DOWN "\xef\x8d\x98" // U+f358 +#define ICON_FA_CIRCLE_EXCLAMATION "\xef\x81\xaa" // U+f06a +#define ICON_FA_CIRCLE_H "\xef\x91\xbe" // U+f47e +#define ICON_FA_CIRCLE_HALF_STROKE "\xef\x81\x82" // U+f042 +#define ICON_FA_CIRCLE_INFO "\xef\x81\x9a" // U+f05a +#define ICON_FA_CIRCLE_LEFT "\xef\x8d\x99" // U+f359 +#define ICON_FA_CIRCLE_MINUS "\xef\x81\x96" // U+f056 +#define ICON_FA_CIRCLE_NODES "\xee\x93\xa2" // U+e4e2 +#define ICON_FA_CIRCLE_NOTCH "\xef\x87\x8e" // U+f1ce +#define ICON_FA_CIRCLE_PAUSE "\xef\x8a\x8b" // U+f28b +#define ICON_FA_CIRCLE_PLAY "\xef\x85\x84" // U+f144 +#define ICON_FA_CIRCLE_PLUS "\xef\x81\x95" // U+f055 +#define ICON_FA_CIRCLE_QUESTION "\xef\x81\x99" // U+f059 +#define ICON_FA_CIRCLE_RADIATION "\xef\x9e\xba" // U+f7ba +#define ICON_FA_CIRCLE_RIGHT "\xef\x8d\x9a" // U+f35a +#define ICON_FA_CIRCLE_STOP "\xef\x8a\x8d" // U+f28d +#define ICON_FA_CIRCLE_UP "\xef\x8d\x9b" // U+f35b +#define ICON_FA_CIRCLE_USER "\xef\x8a\xbd" // U+f2bd +#define ICON_FA_CIRCLE_XMARK "\xef\x81\x97" // U+f057 +#define ICON_FA_CITY "\xef\x99\x8f" // U+f64f +#define ICON_FA_CLAPPERBOARD "\xee\x84\xb1" // U+e131 +#define ICON_FA_CLIPBOARD "\xef\x8c\xa8" // U+f328 +#define ICON_FA_CLIPBOARD_CHECK "\xef\x91\xac" // U+f46c +#define ICON_FA_CLIPBOARD_LIST "\xef\x91\xad" // U+f46d +#define ICON_FA_CLIPBOARD_QUESTION "\xee\x93\xa3" // U+e4e3 +#define ICON_FA_CLIPBOARD_USER "\xef\x9f\xb3" // U+f7f3 +#define ICON_FA_CLOCK "\xef\x80\x97" // U+f017 +#define ICON_FA_CLOCK_ROTATE_LEFT "\xef\x87\x9a" // U+f1da +#define ICON_FA_CLONE "\xef\x89\x8d" // U+f24d +#define ICON_FA_CLOSED_CAPTIONING "\xef\x88\x8a" // U+f20a +#define ICON_FA_CLOUD "\xef\x83\x82" // U+f0c2 +#define ICON_FA_CLOUD_ARROW_DOWN "\xef\x83\xad" // U+f0ed +#define ICON_FA_CLOUD_ARROW_UP "\xef\x83\xae" // U+f0ee +#define ICON_FA_CLOUD_BOLT "\xef\x9d\xac" // U+f76c +#define ICON_FA_CLOUD_MEATBALL "\xef\x9c\xbb" // U+f73b +#define ICON_FA_CLOUD_MOON "\xef\x9b\x83" // U+f6c3 +#define ICON_FA_CLOUD_MOON_RAIN "\xef\x9c\xbc" // U+f73c +#define ICON_FA_CLOUD_RAIN "\xef\x9c\xbd" // U+f73d +#define ICON_FA_CLOUD_SHOWERS_HEAVY "\xef\x9d\x80" // U+f740 +#define ICON_FA_CLOUD_SHOWERS_WATER "\xee\x93\xa4" // U+e4e4 +#define ICON_FA_CLOUD_SUN "\xef\x9b\x84" // U+f6c4 +#define ICON_FA_CLOUD_SUN_RAIN "\xef\x9d\x83" // U+f743 +#define ICON_FA_CLOVER "\xee\x84\xb9" // U+e139 +#define ICON_FA_CODE "\xef\x84\xa1" // U+f121 +#define ICON_FA_CODE_BRANCH "\xef\x84\xa6" // U+f126 +#define ICON_FA_CODE_COMMIT "\xef\x8e\x86" // U+f386 +#define ICON_FA_CODE_COMPARE "\xee\x84\xba" // U+e13a +#define ICON_FA_CODE_FORK "\xee\x84\xbb" // U+e13b +#define ICON_FA_CODE_MERGE "\xef\x8e\x87" // U+f387 +#define ICON_FA_CODE_PULL_REQUEST "\xee\x84\xbc" // U+e13c +#define ICON_FA_COINS "\xef\x94\x9e" // U+f51e +#define ICON_FA_COLON_SIGN "\xee\x85\x80" // U+e140 +#define ICON_FA_COMMENT "\xef\x81\xb5" // U+f075 +#define ICON_FA_COMMENT_DOLLAR "\xef\x99\x91" // U+f651 +#define ICON_FA_COMMENT_DOTS "\xef\x92\xad" // U+f4ad +#define ICON_FA_COMMENT_MEDICAL "\xef\x9f\xb5" // U+f7f5 +#define ICON_FA_COMMENT_SLASH "\xef\x92\xb3" // U+f4b3 +#define ICON_FA_COMMENT_SMS "\xef\x9f\x8d" // U+f7cd +#define ICON_FA_COMMENTS "\xef\x82\x86" // U+f086 +#define ICON_FA_COMMENTS_DOLLAR "\xef\x99\x93" // U+f653 +#define ICON_FA_COMPACT_DISC "\xef\x94\x9f" // U+f51f +#define ICON_FA_COMPASS "\xef\x85\x8e" // U+f14e +#define ICON_FA_COMPASS_DRAFTING "\xef\x95\xa8" // U+f568 +#define ICON_FA_COMPRESS "\xef\x81\xa6" // U+f066 +#define ICON_FA_COMPUTER "\xee\x93\xa5" // U+e4e5 +#define ICON_FA_COMPUTER_MOUSE "\xef\xa3\x8c" // U+f8cc +#define ICON_FA_COOKIE "\xef\x95\xa3" // U+f563 +#define ICON_FA_COOKIE_BITE "\xef\x95\xa4" // U+f564 +#define ICON_FA_COPY "\xef\x83\x85" // U+f0c5 +#define ICON_FA_COPYRIGHT "\xef\x87\xb9" // U+f1f9 +#define ICON_FA_COUCH "\xef\x92\xb8" // U+f4b8 +#define ICON_FA_COW "\xef\x9b\x88" // U+f6c8 +#define ICON_FA_CREDIT_CARD "\xef\x82\x9d" // U+f09d +#define ICON_FA_CROP "\xef\x84\xa5" // U+f125 +#define ICON_FA_CROP_SIMPLE "\xef\x95\xa5" // U+f565 +#define ICON_FA_CROSS "\xef\x99\x94" // U+f654 +#define ICON_FA_CROSSHAIRS "\xef\x81\x9b" // U+f05b +#define ICON_FA_CROW "\xef\x94\xa0" // U+f520 +#define ICON_FA_CROWN "\xef\x94\xa1" // U+f521 +#define ICON_FA_CRUTCH "\xef\x9f\xb7" // U+f7f7 +#define ICON_FA_CRUZEIRO_SIGN "\xee\x85\x92" // U+e152 +#define ICON_FA_CUBE "\xef\x86\xb2" // U+f1b2 +#define ICON_FA_CUBES "\xef\x86\xb3" // U+f1b3 +#define ICON_FA_CUBES_STACKED "\xee\x93\xa6" // U+e4e6 +#define ICON_FA_D "D" // U+0044 +#define ICON_FA_DATABASE "\xef\x87\x80" // U+f1c0 +#define ICON_FA_DELETE_LEFT "\xef\x95\x9a" // U+f55a +#define ICON_FA_DEMOCRAT "\xef\x9d\x87" // U+f747 +#define ICON_FA_DESKTOP "\xef\x8e\x90" // U+f390 +#define ICON_FA_DHARMACHAKRA "\xef\x99\x95" // U+f655 +#define ICON_FA_DIAGRAM_NEXT "\xee\x91\xb6" // U+e476 +#define ICON_FA_DIAGRAM_PREDECESSOR "\xee\x91\xb7" // U+e477 +#define ICON_FA_DIAGRAM_PROJECT "\xef\x95\x82" // U+f542 +#define ICON_FA_DIAGRAM_SUCCESSOR "\xee\x91\xba" // U+e47a +#define ICON_FA_DIAMOND "\xef\x88\x99" // U+f219 +#define ICON_FA_DIAMOND_TURN_RIGHT "\xef\x97\xab" // U+f5eb +#define ICON_FA_DICE "\xef\x94\xa2" // U+f522 +#define ICON_FA_DICE_D20 "\xef\x9b\x8f" // U+f6cf +#define ICON_FA_DICE_D6 "\xef\x9b\x91" // U+f6d1 +#define ICON_FA_DICE_FIVE "\xef\x94\xa3" // U+f523 +#define ICON_FA_DICE_FOUR "\xef\x94\xa4" // U+f524 +#define ICON_FA_DICE_ONE "\xef\x94\xa5" // U+f525 +#define ICON_FA_DICE_SIX "\xef\x94\xa6" // U+f526 +#define ICON_FA_DICE_THREE "\xef\x94\xa7" // U+f527 +#define ICON_FA_DICE_TWO "\xef\x94\xa8" // U+f528 +#define ICON_FA_DISEASE "\xef\x9f\xba" // U+f7fa +#define ICON_FA_DISPLAY "\xee\x85\xa3" // U+e163 +#define ICON_FA_DIVIDE "\xef\x94\xa9" // U+f529 +#define ICON_FA_DNA "\xef\x91\xb1" // U+f471 +#define ICON_FA_DOG "\xef\x9b\x93" // U+f6d3 +#define ICON_FA_DOLLAR_SIGN "$" // U+0024 +#define ICON_FA_DOLLY "\xef\x91\xb2" // U+f472 +#define ICON_FA_DONG_SIGN "\xee\x85\xa9" // U+e169 +#define ICON_FA_DOOR_CLOSED "\xef\x94\xaa" // U+f52a +#define ICON_FA_DOOR_OPEN "\xef\x94\xab" // U+f52b +#define ICON_FA_DOVE "\xef\x92\xba" // U+f4ba +#define ICON_FA_DOWN_LEFT_AND_UP_RIGHT_TO_CENTER "\xef\x90\xa2" // U+f422 +#define ICON_FA_DOWN_LONG "\xef\x8c\x89" // U+f309 +#define ICON_FA_DOWNLOAD "\xef\x80\x99" // U+f019 +#define ICON_FA_DRAGON "\xef\x9b\x95" // U+f6d5 +#define ICON_FA_DRAW_POLYGON "\xef\x97\xae" // U+f5ee +#define ICON_FA_DROPLET "\xef\x81\x83" // U+f043 +#define ICON_FA_DROPLET_SLASH "\xef\x97\x87" // U+f5c7 +#define ICON_FA_DRUM "\xef\x95\xa9" // U+f569 +#define ICON_FA_DRUM_STEELPAN "\xef\x95\xaa" // U+f56a +#define ICON_FA_DRUMSTICK_BITE "\xef\x9b\x97" // U+f6d7 +#define ICON_FA_DUMBBELL "\xef\x91\x8b" // U+f44b +#define ICON_FA_DUMPSTER "\xef\x9e\x93" // U+f793 +#define ICON_FA_DUMPSTER_FIRE "\xef\x9e\x94" // U+f794 +#define ICON_FA_DUNGEON "\xef\x9b\x99" // U+f6d9 +#define ICON_FA_E "E" // U+0045 +#define ICON_FA_EAR_DEAF "\xef\x8a\xa4" // U+f2a4 +#define ICON_FA_EAR_LISTEN "\xef\x8a\xa2" // U+f2a2 +#define ICON_FA_EARTH_AFRICA "\xef\x95\xbc" // U+f57c +#define ICON_FA_EARTH_AMERICAS "\xef\x95\xbd" // U+f57d +#define ICON_FA_EARTH_ASIA "\xef\x95\xbe" // U+f57e +#define ICON_FA_EARTH_EUROPE "\xef\x9e\xa2" // U+f7a2 +#define ICON_FA_EARTH_OCEANIA "\xee\x91\xbb" // U+e47b +#define ICON_FA_EGG "\xef\x9f\xbb" // U+f7fb +#define ICON_FA_EJECT "\xef\x81\x92" // U+f052 +#define ICON_FA_ELEVATOR "\xee\x85\xad" // U+e16d +#define ICON_FA_ELLIPSIS "\xef\x85\x81" // U+f141 +#define ICON_FA_ELLIPSIS_VERTICAL "\xef\x85\x82" // U+f142 +#define ICON_FA_ENVELOPE "\xef\x83\xa0" // U+f0e0 +#define ICON_FA_ENVELOPE_CIRCLE_CHECK "\xee\x93\xa8" // U+e4e8 +#define ICON_FA_ENVELOPE_OPEN "\xef\x8a\xb6" // U+f2b6 +#define ICON_FA_ENVELOPE_OPEN_TEXT "\xef\x99\x98" // U+f658 +#define ICON_FA_ENVELOPES_BULK "\xef\x99\xb4" // U+f674 +#define ICON_FA_EQUALS "=" // U+003d +#define ICON_FA_ERASER "\xef\x84\xad" // U+f12d +#define ICON_FA_ETHERNET "\xef\x9e\x96" // U+f796 +#define ICON_FA_EURO_SIGN "\xef\x85\x93" // U+f153 +#define ICON_FA_EXCLAMATION "!" // U+0021 +#define ICON_FA_EXPAND "\xef\x81\xa5" // U+f065 +#define ICON_FA_EXPLOSION "\xee\x93\xa9" // U+e4e9 +#define ICON_FA_EYE "\xef\x81\xae" // U+f06e +#define ICON_FA_EYE_DROPPER "\xef\x87\xbb" // U+f1fb +#define ICON_FA_EYE_LOW_VISION "\xef\x8a\xa8" // U+f2a8 +#define ICON_FA_EYE_SLASH "\xef\x81\xb0" // U+f070 +#define ICON_FA_F "F" // U+0046 +#define ICON_FA_FACE_ANGRY "\xef\x95\x96" // U+f556 +#define ICON_FA_FACE_DIZZY "\xef\x95\xa7" // U+f567 +#define ICON_FA_FACE_FLUSHED "\xef\x95\xb9" // U+f579 +#define ICON_FA_FACE_FROWN "\xef\x84\x99" // U+f119 +#define ICON_FA_FACE_FROWN_OPEN "\xef\x95\xba" // U+f57a +#define ICON_FA_FACE_GRIMACE "\xef\x95\xbf" // U+f57f +#define ICON_FA_FACE_GRIN "\xef\x96\x80" // U+f580 +#define ICON_FA_FACE_GRIN_BEAM "\xef\x96\x82" // U+f582 +#define ICON_FA_FACE_GRIN_BEAM_SWEAT "\xef\x96\x83" // U+f583 +#define ICON_FA_FACE_GRIN_HEARTS "\xef\x96\x84" // U+f584 +#define ICON_FA_FACE_GRIN_SQUINT "\xef\x96\x85" // U+f585 +#define ICON_FA_FACE_GRIN_SQUINT_TEARS "\xef\x96\x86" // U+f586 +#define ICON_FA_FACE_GRIN_STARS "\xef\x96\x87" // U+f587 +#define ICON_FA_FACE_GRIN_TEARS "\xef\x96\x88" // U+f588 +#define ICON_FA_FACE_GRIN_TONGUE "\xef\x96\x89" // U+f589 +#define ICON_FA_FACE_GRIN_TONGUE_SQUINT "\xef\x96\x8a" // U+f58a +#define ICON_FA_FACE_GRIN_TONGUE_WINK "\xef\x96\x8b" // U+f58b +#define ICON_FA_FACE_GRIN_WIDE "\xef\x96\x81" // U+f581 +#define ICON_FA_FACE_GRIN_WINK "\xef\x96\x8c" // U+f58c +#define ICON_FA_FACE_KISS "\xef\x96\x96" // U+f596 +#define ICON_FA_FACE_KISS_BEAM "\xef\x96\x97" // U+f597 +#define ICON_FA_FACE_KISS_WINK_HEART "\xef\x96\x98" // U+f598 +#define ICON_FA_FACE_LAUGH "\xef\x96\x99" // U+f599 +#define ICON_FA_FACE_LAUGH_BEAM "\xef\x96\x9a" // U+f59a +#define ICON_FA_FACE_LAUGH_SQUINT "\xef\x96\x9b" // U+f59b +#define ICON_FA_FACE_LAUGH_WINK "\xef\x96\x9c" // U+f59c +#define ICON_FA_FACE_MEH "\xef\x84\x9a" // U+f11a +#define ICON_FA_FACE_MEH_BLANK "\xef\x96\xa4" // U+f5a4 +#define ICON_FA_FACE_ROLLING_EYES "\xef\x96\xa5" // U+f5a5 +#define ICON_FA_FACE_SAD_CRY "\xef\x96\xb3" // U+f5b3 +#define ICON_FA_FACE_SAD_TEAR "\xef\x96\xb4" // U+f5b4 +#define ICON_FA_FACE_SMILE "\xef\x84\x98" // U+f118 +#define ICON_FA_FACE_SMILE_BEAM "\xef\x96\xb8" // U+f5b8 +#define ICON_FA_FACE_SMILE_WINK "\xef\x93\x9a" // U+f4da +#define ICON_FA_FACE_SURPRISE "\xef\x97\x82" // U+f5c2 +#define ICON_FA_FACE_TIRED "\xef\x97\x88" // U+f5c8 +#define ICON_FA_FAN "\xef\xa1\xa3" // U+f863 +#define ICON_FA_FAUCET "\xee\x80\x85" // U+e005 +#define ICON_FA_FAUCET_DRIP "\xee\x80\x86" // U+e006 +#define ICON_FA_FAX "\xef\x86\xac" // U+f1ac +#define ICON_FA_FEATHER "\xef\x94\xad" // U+f52d +#define ICON_FA_FEATHER_POINTED "\xef\x95\xab" // U+f56b +#define ICON_FA_FERRY "\xee\x93\xaa" // U+e4ea +#define ICON_FA_FILE "\xef\x85\x9b" // U+f15b +#define ICON_FA_FILE_ARROW_DOWN "\xef\x95\xad" // U+f56d +#define ICON_FA_FILE_ARROW_UP "\xef\x95\xb4" // U+f574 +#define ICON_FA_FILE_AUDIO "\xef\x87\x87" // U+f1c7 +#define ICON_FA_FILE_CIRCLE_CHECK "\xee\x96\xa0" // U+e5a0 +#define ICON_FA_FILE_CIRCLE_EXCLAMATION "\xee\x93\xab" // U+e4eb +#define ICON_FA_FILE_CIRCLE_MINUS "\xee\x93\xad" // U+e4ed +#define ICON_FA_FILE_CIRCLE_PLUS "\xee\x92\x94" // U+e494 +#define ICON_FA_FILE_CIRCLE_QUESTION "\xee\x93\xaf" // U+e4ef +#define ICON_FA_FILE_CIRCLE_XMARK "\xee\x96\xa1" // U+e5a1 +#define ICON_FA_FILE_CODE "\xef\x87\x89" // U+f1c9 +#define ICON_FA_FILE_CONTRACT "\xef\x95\xac" // U+f56c +#define ICON_FA_FILE_CSV "\xef\x9b\x9d" // U+f6dd +#define ICON_FA_FILE_EXCEL "\xef\x87\x83" // U+f1c3 +#define ICON_FA_FILE_EXPORT "\xef\x95\xae" // U+f56e +#define ICON_FA_FILE_IMAGE "\xef\x87\x85" // U+f1c5 +#define ICON_FA_FILE_IMPORT "\xef\x95\xaf" // U+f56f +#define ICON_FA_FILE_INVOICE "\xef\x95\xb0" // U+f570 +#define ICON_FA_FILE_INVOICE_DOLLAR "\xef\x95\xb1" // U+f571 +#define ICON_FA_FILE_LINES "\xef\x85\x9c" // U+f15c +#define ICON_FA_FILE_MEDICAL "\xef\x91\xb7" // U+f477 +#define ICON_FA_FILE_PDF "\xef\x87\x81" // U+f1c1 +#define ICON_FA_FILE_PEN "\xef\x8c\x9c" // U+f31c +#define ICON_FA_FILE_POWERPOINT "\xef\x87\x84" // U+f1c4 +#define ICON_FA_FILE_PRESCRIPTION "\xef\x95\xb2" // U+f572 +#define ICON_FA_FILE_SHIELD "\xee\x93\xb0" // U+e4f0 +#define ICON_FA_FILE_SIGNATURE "\xef\x95\xb3" // U+f573 +#define ICON_FA_FILE_VIDEO "\xef\x87\x88" // U+f1c8 +#define ICON_FA_FILE_WAVEFORM "\xef\x91\xb8" // U+f478 +#define ICON_FA_FILE_WORD "\xef\x87\x82" // U+f1c2 +#define ICON_FA_FILE_ZIPPER "\xef\x87\x86" // U+f1c6 +#define ICON_FA_FILL "\xef\x95\xb5" // U+f575 +#define ICON_FA_FILL_DRIP "\xef\x95\xb6" // U+f576 +#define ICON_FA_FILM "\xef\x80\x88" // U+f008 +#define ICON_FA_FILTER "\xef\x82\xb0" // U+f0b0 +#define ICON_FA_FILTER_CIRCLE_DOLLAR "\xef\x99\xa2" // U+f662 +#define ICON_FA_FILTER_CIRCLE_XMARK "\xee\x85\xbb" // U+e17b +#define ICON_FA_FINGERPRINT "\xef\x95\xb7" // U+f577 +#define ICON_FA_FIRE "\xef\x81\xad" // U+f06d +#define ICON_FA_FIRE_BURNER "\xee\x93\xb1" // U+e4f1 +#define ICON_FA_FIRE_EXTINGUISHER "\xef\x84\xb4" // U+f134 +#define ICON_FA_FIRE_FLAME_CURVED "\xef\x9f\xa4" // U+f7e4 +#define ICON_FA_FIRE_FLAME_SIMPLE "\xef\x91\xaa" // U+f46a +#define ICON_FA_FISH "\xef\x95\xb8" // U+f578 +#define ICON_FA_FISH_FINS "\xee\x93\xb2" // U+e4f2 +#define ICON_FA_FLAG "\xef\x80\xa4" // U+f024 +#define ICON_FA_FLAG_CHECKERED "\xef\x84\x9e" // U+f11e +#define ICON_FA_FLAG_USA "\xef\x9d\x8d" // U+f74d +#define ICON_FA_FLASK "\xef\x83\x83" // U+f0c3 +#define ICON_FA_FLASK_VIAL "\xee\x93\xb3" // U+e4f3 +#define ICON_FA_FLOPPY_DISK "\xef\x83\x87" // U+f0c7 +#define ICON_FA_FLORIN_SIGN "\xee\x86\x84" // U+e184 +#define ICON_FA_FOLDER "\xef\x81\xbb" // U+f07b +#define ICON_FA_FOLDER_CLOSED "\xee\x86\x85" // U+e185 +#define ICON_FA_FOLDER_MINUS "\xef\x99\x9d" // U+f65d +#define ICON_FA_FOLDER_OPEN "\xef\x81\xbc" // U+f07c +#define ICON_FA_FOLDER_PLUS "\xef\x99\x9e" // U+f65e +#define ICON_FA_FOLDER_TREE "\xef\xa0\x82" // U+f802 +#define ICON_FA_FONT "\xef\x80\xb1" // U+f031 +#define ICON_FA_FONT_AWESOME "\xef\x8a\xb4" // U+f2b4 +#define ICON_FA_FOOTBALL "\xef\x91\x8e" // U+f44e +#define ICON_FA_FORWARD "\xef\x81\x8e" // U+f04e +#define ICON_FA_FORWARD_FAST "\xef\x81\x90" // U+f050 +#define ICON_FA_FORWARD_STEP "\xef\x81\x91" // U+f051 +#define ICON_FA_FRANC_SIGN "\xee\x86\x8f" // U+e18f +#define ICON_FA_FROG "\xef\x94\xae" // U+f52e +#define ICON_FA_FUTBOL "\xef\x87\xa3" // U+f1e3 +#define ICON_FA_G "G" // U+0047 +#define ICON_FA_GAMEPAD "\xef\x84\x9b" // U+f11b +#define ICON_FA_GAS_PUMP "\xef\x94\xaf" // U+f52f +#define ICON_FA_GAUGE "\xef\x98\xa4" // U+f624 +#define ICON_FA_GAUGE_HIGH "\xef\x98\xa5" // U+f625 +#define ICON_FA_GAUGE_SIMPLE "\xef\x98\xa9" // U+f629 +#define ICON_FA_GAUGE_SIMPLE_HIGH "\xef\x98\xaa" // U+f62a +#define ICON_FA_GAVEL "\xef\x83\xa3" // U+f0e3 +#define ICON_FA_GEAR "\xef\x80\x93" // U+f013 +#define ICON_FA_GEARS "\xef\x82\x85" // U+f085 +#define ICON_FA_GEM "\xef\x8e\xa5" // U+f3a5 +#define ICON_FA_GENDERLESS "\xef\x88\xad" // U+f22d +#define ICON_FA_GHOST "\xef\x9b\xa2" // U+f6e2 +#define ICON_FA_GIFT "\xef\x81\xab" // U+f06b +#define ICON_FA_GIFTS "\xef\x9e\x9c" // U+f79c +#define ICON_FA_GLASS_WATER "\xee\x93\xb4" // U+e4f4 +#define ICON_FA_GLASS_WATER_DROPLET "\xee\x93\xb5" // U+e4f5 +#define ICON_FA_GLASSES "\xef\x94\xb0" // U+f530 +#define ICON_FA_GLOBE "\xef\x82\xac" // U+f0ac +#define ICON_FA_GOLF_BALL_TEE "\xef\x91\x90" // U+f450 +#define ICON_FA_GOPURAM "\xef\x99\xa4" // U+f664 +#define ICON_FA_GRADUATION_CAP "\xef\x86\x9d" // U+f19d +#define ICON_FA_GREATER_THAN ">" // U+003e +#define ICON_FA_GREATER_THAN_EQUAL "\xef\x94\xb2" // U+f532 +#define ICON_FA_GRIP "\xef\x96\x8d" // U+f58d +#define ICON_FA_GRIP_LINES "\xef\x9e\xa4" // U+f7a4 +#define ICON_FA_GRIP_LINES_VERTICAL "\xef\x9e\xa5" // U+f7a5 +#define ICON_FA_GRIP_VERTICAL "\xef\x96\x8e" // U+f58e +#define ICON_FA_GROUP_ARROWS_ROTATE "\xee\x93\xb6" // U+e4f6 +#define ICON_FA_GUARANI_SIGN "\xee\x86\x9a" // U+e19a +#define ICON_FA_GUITAR "\xef\x9e\xa6" // U+f7a6 +#define ICON_FA_GUN "\xee\x86\x9b" // U+e19b +#define ICON_FA_H "H" // U+0048 +#define ICON_FA_HAMMER "\xef\x9b\xa3" // U+f6e3 +#define ICON_FA_HAMSA "\xef\x99\xa5" // U+f665 +#define ICON_FA_HAND "\xef\x89\x96" // U+f256 +#define ICON_FA_HAND_BACK_FIST "\xef\x89\x95" // U+f255 +#define ICON_FA_HAND_DOTS "\xef\x91\xa1" // U+f461 +#define ICON_FA_HAND_FIST "\xef\x9b\x9e" // U+f6de +#define ICON_FA_HAND_HOLDING "\xef\x92\xbd" // U+f4bd +#define ICON_FA_HAND_HOLDING_DOLLAR "\xef\x93\x80" // U+f4c0 +#define ICON_FA_HAND_HOLDING_DROPLET "\xef\x93\x81" // U+f4c1 +#define ICON_FA_HAND_HOLDING_HAND "\xee\x93\xb7" // U+e4f7 +#define ICON_FA_HAND_HOLDING_HEART "\xef\x92\xbe" // U+f4be +#define ICON_FA_HAND_HOLDING_MEDICAL "\xee\x81\x9c" // U+e05c +#define ICON_FA_HAND_LIZARD "\xef\x89\x98" // U+f258 +#define ICON_FA_HAND_MIDDLE_FINGER "\xef\xa0\x86" // U+f806 +#define ICON_FA_HAND_PEACE "\xef\x89\x9b" // U+f25b +#define ICON_FA_HAND_POINT_DOWN "\xef\x82\xa7" // U+f0a7 +#define ICON_FA_HAND_POINT_LEFT "\xef\x82\xa5" // U+f0a5 +#define ICON_FA_HAND_POINT_RIGHT "\xef\x82\xa4" // U+f0a4 +#define ICON_FA_HAND_POINT_UP "\xef\x82\xa6" // U+f0a6 +#define ICON_FA_HAND_POINTER "\xef\x89\x9a" // U+f25a +#define ICON_FA_HAND_SCISSORS "\xef\x89\x97" // U+f257 +#define ICON_FA_HAND_SPARKLES "\xee\x81\x9d" // U+e05d +#define ICON_FA_HAND_SPOCK "\xef\x89\x99" // U+f259 +#define ICON_FA_HANDCUFFS "\xee\x93\xb8" // U+e4f8 +#define ICON_FA_HANDS "\xef\x8a\xa7" // U+f2a7 +#define ICON_FA_HANDS_ASL_INTERPRETING "\xef\x8a\xa3" // U+f2a3 +#define ICON_FA_HANDS_BOUND "\xee\x93\xb9" // U+e4f9 +#define ICON_FA_HANDS_BUBBLES "\xee\x81\x9e" // U+e05e +#define ICON_FA_HANDS_CLAPPING "\xee\x86\xa8" // U+e1a8 +#define ICON_FA_HANDS_HOLDING "\xef\x93\x82" // U+f4c2 +#define ICON_FA_HANDS_HOLDING_CHILD "\xee\x93\xba" // U+e4fa +#define ICON_FA_HANDS_HOLDING_CIRCLE "\xee\x93\xbb" // U+e4fb +#define ICON_FA_HANDS_PRAYING "\xef\x9a\x84" // U+f684 +#define ICON_FA_HANDSHAKE "\xef\x8a\xb5" // U+f2b5 +#define ICON_FA_HANDSHAKE_ANGLE "\xef\x93\x84" // U+f4c4 +#define ICON_FA_HANDSHAKE_SIMPLE "\xef\x93\x86" // U+f4c6 +#define ICON_FA_HANDSHAKE_SIMPLE_SLASH "\xee\x81\x9f" // U+e05f +#define ICON_FA_HANDSHAKE_SLASH "\xee\x81\xa0" // U+e060 +#define ICON_FA_HANUKIAH "\xef\x9b\xa6" // U+f6e6 +#define ICON_FA_HARD_DRIVE "\xef\x82\xa0" // U+f0a0 +#define ICON_FA_HASHTAG "#" // U+0023 +#define ICON_FA_HAT_COWBOY "\xef\xa3\x80" // U+f8c0 +#define ICON_FA_HAT_COWBOY_SIDE "\xef\xa3\x81" // U+f8c1 +#define ICON_FA_HAT_WIZARD "\xef\x9b\xa8" // U+f6e8 +#define ICON_FA_HEAD_SIDE_COUGH "\xee\x81\xa1" // U+e061 +#define ICON_FA_HEAD_SIDE_COUGH_SLASH "\xee\x81\xa2" // U+e062 +#define ICON_FA_HEAD_SIDE_MASK "\xee\x81\xa3" // U+e063 +#define ICON_FA_HEAD_SIDE_VIRUS "\xee\x81\xa4" // U+e064 +#define ICON_FA_HEADING "\xef\x87\x9c" // U+f1dc +#define ICON_FA_HEADPHONES "\xef\x80\xa5" // U+f025 +#define ICON_FA_HEADPHONES_SIMPLE "\xef\x96\x8f" // U+f58f +#define ICON_FA_HEADSET "\xef\x96\x90" // U+f590 +#define ICON_FA_HEART "\xef\x80\x84" // U+f004 +#define ICON_FA_HEART_CIRCLE_BOLT "\xee\x93\xbc" // U+e4fc +#define ICON_FA_HEART_CIRCLE_CHECK "\xee\x93\xbd" // U+e4fd +#define ICON_FA_HEART_CIRCLE_EXCLAMATION "\xee\x93\xbe" // U+e4fe +#define ICON_FA_HEART_CIRCLE_MINUS "\xee\x93\xbf" // U+e4ff +#define ICON_FA_HEART_CIRCLE_PLUS "\xee\x94\x80" // U+e500 +#define ICON_FA_HEART_CIRCLE_XMARK "\xee\x94\x81" // U+e501 +#define ICON_FA_HEART_CRACK "\xef\x9e\xa9" // U+f7a9 +#define ICON_FA_HEART_PULSE "\xef\x88\x9e" // U+f21e +#define ICON_FA_HELICOPTER "\xef\x94\xb3" // U+f533 +#define ICON_FA_HELICOPTER_SYMBOL "\xee\x94\x82" // U+e502 +#define ICON_FA_HELMET_SAFETY "\xef\xa0\x87" // U+f807 +#define ICON_FA_HELMET_UN "\xee\x94\x83" // U+e503 +#define ICON_FA_HIGHLIGHTER "\xef\x96\x91" // U+f591 +#define ICON_FA_HILL_AVALANCHE "\xee\x94\x87" // U+e507 +#define ICON_FA_HILL_ROCKSLIDE "\xee\x94\x88" // U+e508 +#define ICON_FA_HIPPO "\xef\x9b\xad" // U+f6ed +#define ICON_FA_HOCKEY_PUCK "\xef\x91\x93" // U+f453 +#define ICON_FA_HOLLY_BERRY "\xef\x9e\xaa" // U+f7aa +#define ICON_FA_HORSE "\xef\x9b\xb0" // U+f6f0 +#define ICON_FA_HORSE_HEAD "\xef\x9e\xab" // U+f7ab +#define ICON_FA_HOSPITAL "\xef\x83\xb8" // U+f0f8 +#define ICON_FA_HOSPITAL_USER "\xef\xa0\x8d" // U+f80d +#define ICON_FA_HOT_TUB_PERSON "\xef\x96\x93" // U+f593 +#define ICON_FA_HOTDOG "\xef\xa0\x8f" // U+f80f +#define ICON_FA_HOTEL "\xef\x96\x94" // U+f594 +#define ICON_FA_HOURGLASS "\xef\x89\x94" // U+f254 +#define ICON_FA_HOURGLASS_END "\xef\x89\x93" // U+f253 +#define ICON_FA_HOURGLASS_HALF "\xef\x89\x92" // U+f252 +#define ICON_FA_HOURGLASS_START "\xef\x89\x91" // U+f251 +#define ICON_FA_HOUSE "\xef\x80\x95" // U+f015 +#define ICON_FA_HOUSE_CHIMNEY "\xee\x8e\xaf" // U+e3af +#define ICON_FA_HOUSE_CHIMNEY_CRACK "\xef\x9b\xb1" // U+f6f1 +#define ICON_FA_HOUSE_CHIMNEY_MEDICAL "\xef\x9f\xb2" // U+f7f2 +#define ICON_FA_HOUSE_CHIMNEY_USER "\xee\x81\xa5" // U+e065 +#define ICON_FA_HOUSE_CHIMNEY_WINDOW "\xee\x80\x8d" // U+e00d +#define ICON_FA_HOUSE_CIRCLE_CHECK "\xee\x94\x89" // U+e509 +#define ICON_FA_HOUSE_CIRCLE_EXCLAMATION "\xee\x94\x8a" // U+e50a +#define ICON_FA_HOUSE_CIRCLE_XMARK "\xee\x94\x8b" // U+e50b +#define ICON_FA_HOUSE_CRACK "\xee\x8e\xb1" // U+e3b1 +#define ICON_FA_HOUSE_FIRE "\xee\x94\x8c" // U+e50c +#define ICON_FA_HOUSE_FLAG "\xee\x94\x8d" // U+e50d +#define ICON_FA_HOUSE_FLOOD_WATER "\xee\x94\x8e" // U+e50e +#define ICON_FA_HOUSE_FLOOD_WATER_CIRCLE_ARROW_RIGHT "\xee\x94\x8f" // U+e50f +#define ICON_FA_HOUSE_LAPTOP "\xee\x81\xa6" // U+e066 +#define ICON_FA_HOUSE_LOCK "\xee\x94\x90" // U+e510 +#define ICON_FA_HOUSE_MEDICAL "\xee\x8e\xb2" // U+e3b2 +#define ICON_FA_HOUSE_MEDICAL_CIRCLE_CHECK "\xee\x94\x91" // U+e511 +#define ICON_FA_HOUSE_MEDICAL_CIRCLE_EXCLAMATION "\xee\x94\x92" // U+e512 +#define ICON_FA_HOUSE_MEDICAL_CIRCLE_XMARK "\xee\x94\x93" // U+e513 +#define ICON_FA_HOUSE_MEDICAL_FLAG "\xee\x94\x94" // U+e514 +#define ICON_FA_HOUSE_SIGNAL "\xee\x80\x92" // U+e012 +#define ICON_FA_HOUSE_TSUNAMI "\xee\x94\x95" // U+e515 +#define ICON_FA_HOUSE_USER "\xee\x86\xb0" // U+e1b0 +#define ICON_FA_HRYVNIA_SIGN "\xef\x9b\xb2" // U+f6f2 +#define ICON_FA_HURRICANE "\xef\x9d\x91" // U+f751 +#define ICON_FA_I "I" // U+0049 +#define ICON_FA_I_CURSOR "\xef\x89\x86" // U+f246 +#define ICON_FA_ICE_CREAM "\xef\xa0\x90" // U+f810 +#define ICON_FA_ICICLES "\xef\x9e\xad" // U+f7ad +#define ICON_FA_ICONS "\xef\xa1\xad" // U+f86d +#define ICON_FA_ID_BADGE "\xef\x8b\x81" // U+f2c1 +#define ICON_FA_ID_CARD "\xef\x8b\x82" // U+f2c2 +#define ICON_FA_ID_CARD_CLIP "\xef\x91\xbf" // U+f47f +#define ICON_FA_IGLOO "\xef\x9e\xae" // U+f7ae +#define ICON_FA_IMAGE "\xef\x80\xbe" // U+f03e +#define ICON_FA_IMAGE_PORTRAIT "\xef\x8f\xa0" // U+f3e0 +#define ICON_FA_IMAGES "\xef\x8c\x82" // U+f302 +#define ICON_FA_INBOX "\xef\x80\x9c" // U+f01c +#define ICON_FA_INDENT "\xef\x80\xbc" // U+f03c +#define ICON_FA_INDIAN_RUPEE_SIGN "\xee\x86\xbc" // U+e1bc +#define ICON_FA_INDUSTRY "\xef\x89\xb5" // U+f275 +#define ICON_FA_INFINITY "\xef\x94\xb4" // U+f534 +#define ICON_FA_INFO "\xef\x84\xa9" // U+f129 +#define ICON_FA_ITALIC "\xef\x80\xb3" // U+f033 +#define ICON_FA_J "J" // U+004a +#define ICON_FA_JAR "\xee\x94\x96" // U+e516 +#define ICON_FA_JAR_WHEAT "\xee\x94\x97" // U+e517 +#define ICON_FA_JEDI "\xef\x99\xa9" // U+f669 +#define ICON_FA_JET_FIGHTER "\xef\x83\xbb" // U+f0fb +#define ICON_FA_JET_FIGHTER_UP "\xee\x94\x98" // U+e518 +#define ICON_FA_JOINT "\xef\x96\x95" // U+f595 +#define ICON_FA_JUG_DETERGENT "\xee\x94\x99" // U+e519 +#define ICON_FA_K "K" // U+004b +#define ICON_FA_KAABA "\xef\x99\xab" // U+f66b +#define ICON_FA_KEY "\xef\x82\x84" // U+f084 +#define ICON_FA_KEYBOARD "\xef\x84\x9c" // U+f11c +#define ICON_FA_KHANDA "\xef\x99\xad" // U+f66d +#define ICON_FA_KIP_SIGN "\xee\x87\x84" // U+e1c4 +#define ICON_FA_KIT_MEDICAL "\xef\x91\xb9" // U+f479 +#define ICON_FA_KITCHEN_SET "\xee\x94\x9a" // U+e51a +#define ICON_FA_KIWI_BIRD "\xef\x94\xb5" // U+f535 +#define ICON_FA_L "L" // U+004c +#define ICON_FA_LAND_MINE_ON "\xee\x94\x9b" // U+e51b +#define ICON_FA_LANDMARK "\xef\x99\xaf" // U+f66f +#define ICON_FA_LANDMARK_DOME "\xef\x9d\x92" // U+f752 +#define ICON_FA_LANDMARK_FLAG "\xee\x94\x9c" // U+e51c +#define ICON_FA_LANGUAGE "\xef\x86\xab" // U+f1ab +#define ICON_FA_LAPTOP "\xef\x84\x89" // U+f109 +#define ICON_FA_LAPTOP_CODE "\xef\x97\xbc" // U+f5fc +#define ICON_FA_LAPTOP_FILE "\xee\x94\x9d" // U+e51d +#define ICON_FA_LAPTOP_MEDICAL "\xef\xa0\x92" // U+f812 +#define ICON_FA_LARI_SIGN "\xee\x87\x88" // U+e1c8 +#define ICON_FA_LAYER_GROUP "\xef\x97\xbd" // U+f5fd +#define ICON_FA_LEAF "\xef\x81\xac" // U+f06c +#define ICON_FA_LEFT_LONG "\xef\x8c\x8a" // U+f30a +#define ICON_FA_LEFT_RIGHT "\xef\x8c\xb7" // U+f337 +#define ICON_FA_LEMON "\xef\x82\x94" // U+f094 +#define ICON_FA_LESS_THAN "<" // U+003c +#define ICON_FA_LESS_THAN_EQUAL "\xef\x94\xb7" // U+f537 +#define ICON_FA_LIFE_RING "\xef\x87\x8d" // U+f1cd +#define ICON_FA_LIGHTBULB "\xef\x83\xab" // U+f0eb +#define ICON_FA_LINES_LEANING "\xee\x94\x9e" // U+e51e +#define ICON_FA_LINK "\xef\x83\x81" // U+f0c1 +#define ICON_FA_LINK_SLASH "\xef\x84\xa7" // U+f127 +#define ICON_FA_LIRA_SIGN "\xef\x86\x95" // U+f195 +#define ICON_FA_LIST "\xef\x80\xba" // U+f03a +#define ICON_FA_LIST_CHECK "\xef\x82\xae" // U+f0ae +#define ICON_FA_LIST_OL "\xef\x83\x8b" // U+f0cb +#define ICON_FA_LIST_UL "\xef\x83\x8a" // U+f0ca +#define ICON_FA_LITECOIN_SIGN "\xee\x87\x93" // U+e1d3 +#define ICON_FA_LOCATION_ARROW "\xef\x84\xa4" // U+f124 +#define ICON_FA_LOCATION_CROSSHAIRS "\xef\x98\x81" // U+f601 +#define ICON_FA_LOCATION_DOT "\xef\x8f\x85" // U+f3c5 +#define ICON_FA_LOCATION_PIN "\xef\x81\x81" // U+f041 +#define ICON_FA_LOCATION_PIN_LOCK "\xee\x94\x9f" // U+e51f +#define ICON_FA_LOCK "\xef\x80\xa3" // U+f023 +#define ICON_FA_LOCK_OPEN "\xef\x8f\x81" // U+f3c1 +#define ICON_FA_LOCUST "\xee\x94\xa0" // U+e520 +#define ICON_FA_LUNGS "\xef\x98\x84" // U+f604 +#define ICON_FA_LUNGS_VIRUS "\xee\x81\xa7" // U+e067 +#define ICON_FA_M "M" // U+004d +#define ICON_FA_MAGNET "\xef\x81\xb6" // U+f076 +#define ICON_FA_MAGNIFYING_GLASS "\xef\x80\x82" // U+f002 +#define ICON_FA_MAGNIFYING_GLASS_ARROW_RIGHT "\xee\x94\xa1" // U+e521 +#define ICON_FA_MAGNIFYING_GLASS_CHART "\xee\x94\xa2" // U+e522 +#define ICON_FA_MAGNIFYING_GLASS_DOLLAR "\xef\x9a\x88" // U+f688 +#define ICON_FA_MAGNIFYING_GLASS_LOCATION "\xef\x9a\x89" // U+f689 +#define ICON_FA_MAGNIFYING_GLASS_MINUS "\xef\x80\x90" // U+f010 +#define ICON_FA_MAGNIFYING_GLASS_PLUS "\xef\x80\x8e" // U+f00e +#define ICON_FA_MANAT_SIGN "\xee\x87\x95" // U+e1d5 +#define ICON_FA_MAP "\xef\x89\xb9" // U+f279 +#define ICON_FA_MAP_LOCATION "\xef\x96\x9f" // U+f59f +#define ICON_FA_MAP_LOCATION_DOT "\xef\x96\xa0" // U+f5a0 +#define ICON_FA_MAP_PIN "\xef\x89\xb6" // U+f276 +#define ICON_FA_MARKER "\xef\x96\xa1" // U+f5a1 +#define ICON_FA_MARS "\xef\x88\xa2" // U+f222 +#define ICON_FA_MARS_AND_VENUS "\xef\x88\xa4" // U+f224 +#define ICON_FA_MARS_AND_VENUS_BURST "\xee\x94\xa3" // U+e523 +#define ICON_FA_MARS_DOUBLE "\xef\x88\xa7" // U+f227 +#define ICON_FA_MARS_STROKE "\xef\x88\xa9" // U+f229 +#define ICON_FA_MARS_STROKE_RIGHT "\xef\x88\xab" // U+f22b +#define ICON_FA_MARS_STROKE_UP "\xef\x88\xaa" // U+f22a +#define ICON_FA_MARTINI_GLASS "\xef\x95\xbb" // U+f57b +#define ICON_FA_MARTINI_GLASS_CITRUS "\xef\x95\xa1" // U+f561 +#define ICON_FA_MARTINI_GLASS_EMPTY "\xef\x80\x80" // U+f000 +#define ICON_FA_MASK "\xef\x9b\xba" // U+f6fa +#define ICON_FA_MASK_FACE "\xee\x87\x97" // U+e1d7 +#define ICON_FA_MASK_VENTILATOR "\xee\x94\xa4" // U+e524 +#define ICON_FA_MASKS_THEATER "\xef\x98\xb0" // U+f630 +#define ICON_FA_MATTRESS_PILLOW "\xee\x94\xa5" // U+e525 +#define ICON_FA_MAXIMIZE "\xef\x8c\x9e" // U+f31e +#define ICON_FA_MEDAL "\xef\x96\xa2" // U+f5a2 +#define ICON_FA_MEMORY "\xef\x94\xb8" // U+f538 +#define ICON_FA_MENORAH "\xef\x99\xb6" // U+f676 +#define ICON_FA_MERCURY "\xef\x88\xa3" // U+f223 +#define ICON_FA_MESSAGE "\xef\x89\xba" // U+f27a +#define ICON_FA_METEOR "\xef\x9d\x93" // U+f753 +#define ICON_FA_MICROCHIP "\xef\x8b\x9b" // U+f2db +#define ICON_FA_MICROPHONE "\xef\x84\xb0" // U+f130 +#define ICON_FA_MICROPHONE_LINES "\xef\x8f\x89" // U+f3c9 +#define ICON_FA_MICROPHONE_LINES_SLASH "\xef\x94\xb9" // U+f539 +#define ICON_FA_MICROPHONE_SLASH "\xef\x84\xb1" // U+f131 +#define ICON_FA_MICROSCOPE "\xef\x98\x90" // U+f610 +#define ICON_FA_MILL_SIGN "\xee\x87\xad" // U+e1ed +#define ICON_FA_MINIMIZE "\xef\x9e\x8c" // U+f78c +#define ICON_FA_MINUS "\xef\x81\xa8" // U+f068 +#define ICON_FA_MITTEN "\xef\x9e\xb5" // U+f7b5 +#define ICON_FA_MOBILE "\xef\x8f\x8e" // U+f3ce +#define ICON_FA_MOBILE_BUTTON "\xef\x84\x8b" // U+f10b +#define ICON_FA_MOBILE_RETRO "\xee\x94\xa7" // U+e527 +#define ICON_FA_MOBILE_SCREEN "\xef\x8f\x8f" // U+f3cf +#define ICON_FA_MOBILE_SCREEN_BUTTON "\xef\x8f\x8d" // U+f3cd +#define ICON_FA_MONEY_BILL "\xef\x83\x96" // U+f0d6 +#define ICON_FA_MONEY_BILL_1 "\xef\x8f\x91" // U+f3d1 +#define ICON_FA_MONEY_BILL_1_WAVE "\xef\x94\xbb" // U+f53b +#define ICON_FA_MONEY_BILL_TRANSFER "\xee\x94\xa8" // U+e528 +#define ICON_FA_MONEY_BILL_TREND_UP "\xee\x94\xa9" // U+e529 +#define ICON_FA_MONEY_BILL_WAVE "\xef\x94\xba" // U+f53a +#define ICON_FA_MONEY_BILL_WHEAT "\xee\x94\xaa" // U+e52a +#define ICON_FA_MONEY_BILLS "\xee\x87\xb3" // U+e1f3 +#define ICON_FA_MONEY_CHECK "\xef\x94\xbc" // U+f53c +#define ICON_FA_MONEY_CHECK_DOLLAR "\xef\x94\xbd" // U+f53d +#define ICON_FA_MONUMENT "\xef\x96\xa6" // U+f5a6 +#define ICON_FA_MOON "\xef\x86\x86" // U+f186 +#define ICON_FA_MORTAR_PESTLE "\xef\x96\xa7" // U+f5a7 +#define ICON_FA_MOSQUE "\xef\x99\xb8" // U+f678 +#define ICON_FA_MOSQUITO "\xee\x94\xab" // U+e52b +#define ICON_FA_MOSQUITO_NET "\xee\x94\xac" // U+e52c +#define ICON_FA_MOTORCYCLE "\xef\x88\x9c" // U+f21c +#define ICON_FA_MOUND "\xee\x94\xad" // U+e52d +#define ICON_FA_MOUNTAIN "\xef\x9b\xbc" // U+f6fc +#define ICON_FA_MOUNTAIN_CITY "\xee\x94\xae" // U+e52e +#define ICON_FA_MOUNTAIN_SUN "\xee\x94\xaf" // U+e52f +#define ICON_FA_MUG_HOT "\xef\x9e\xb6" // U+f7b6 +#define ICON_FA_MUG_SAUCER "\xef\x83\xb4" // U+f0f4 +#define ICON_FA_MUSIC "\xef\x80\x81" // U+f001 +#define ICON_FA_N "N" // U+004e +#define ICON_FA_NAIRA_SIGN "\xee\x87\xb6" // U+e1f6 +#define ICON_FA_NETWORK_WIRED "\xef\x9b\xbf" // U+f6ff +#define ICON_FA_NEUTER "\xef\x88\xac" // U+f22c +#define ICON_FA_NEWSPAPER "\xef\x87\xaa" // U+f1ea +#define ICON_FA_NOT_EQUAL "\xef\x94\xbe" // U+f53e +#define ICON_FA_NOTE_STICKY "\xef\x89\x89" // U+f249 +#define ICON_FA_NOTES_MEDICAL "\xef\x92\x81" // U+f481 +#define ICON_FA_O "O" // U+004f +#define ICON_FA_OBJECT_GROUP "\xef\x89\x87" // U+f247 +#define ICON_FA_OBJECT_UNGROUP "\xef\x89\x88" // U+f248 +#define ICON_FA_OIL_CAN "\xef\x98\x93" // U+f613 +#define ICON_FA_OIL_WELL "\xee\x94\xb2" // U+e532 +#define ICON_FA_OM "\xef\x99\xb9" // U+f679 +#define ICON_FA_OTTER "\xef\x9c\x80" // U+f700 +#define ICON_FA_OUTDENT "\xef\x80\xbb" // U+f03b +#define ICON_FA_P "P" // U+0050 +#define ICON_FA_PAGER "\xef\xa0\x95" // U+f815 +#define ICON_FA_PAINT_ROLLER "\xef\x96\xaa" // U+f5aa +#define ICON_FA_PAINTBRUSH "\xef\x87\xbc" // U+f1fc +#define ICON_FA_PALETTE "\xef\x94\xbf" // U+f53f +#define ICON_FA_PALLET "\xef\x92\x82" // U+f482 +#define ICON_FA_PANORAMA "\xee\x88\x89" // U+e209 +#define ICON_FA_PAPER_PLANE "\xef\x87\x98" // U+f1d8 +#define ICON_FA_PAPERCLIP "\xef\x83\x86" // U+f0c6 +#define ICON_FA_PARACHUTE_BOX "\xef\x93\x8d" // U+f4cd +#define ICON_FA_PARAGRAPH "\xef\x87\x9d" // U+f1dd +#define ICON_FA_PASSPORT "\xef\x96\xab" // U+f5ab +#define ICON_FA_PASTE "\xef\x83\xaa" // U+f0ea +#define ICON_FA_PAUSE "\xef\x81\x8c" // U+f04c +#define ICON_FA_PAW "\xef\x86\xb0" // U+f1b0 +#define ICON_FA_PEACE "\xef\x99\xbc" // U+f67c +#define ICON_FA_PEN "\xef\x8c\x84" // U+f304 +#define ICON_FA_PEN_CLIP "\xef\x8c\x85" // U+f305 +#define ICON_FA_PEN_FANCY "\xef\x96\xac" // U+f5ac +#define ICON_FA_PEN_NIB "\xef\x96\xad" // U+f5ad +#define ICON_FA_PEN_RULER "\xef\x96\xae" // U+f5ae +#define ICON_FA_PEN_TO_SQUARE "\xef\x81\x84" // U+f044 +#define ICON_FA_PENCIL "\xef\x8c\x83" // U+f303 +#define ICON_FA_PEOPLE_ARROWS "\xee\x81\xa8" // U+e068 +#define ICON_FA_PEOPLE_CARRY_BOX "\xef\x93\x8e" // U+f4ce +#define ICON_FA_PEOPLE_GROUP "\xee\x94\xb3" // U+e533 +#define ICON_FA_PEOPLE_LINE "\xee\x94\xb4" // U+e534 +#define ICON_FA_PEOPLE_PULLING "\xee\x94\xb5" // U+e535 +#define ICON_FA_PEOPLE_ROBBERY "\xee\x94\xb6" // U+e536 +#define ICON_FA_PEOPLE_ROOF "\xee\x94\xb7" // U+e537 +#define ICON_FA_PEPPER_HOT "\xef\xa0\x96" // U+f816 +#define ICON_FA_PERCENT "%" // U+0025 +#define ICON_FA_PERSON "\xef\x86\x83" // U+f183 +#define ICON_FA_PERSON_ARROW_DOWN_TO_LINE "\xee\x94\xb8" // U+e538 +#define ICON_FA_PERSON_ARROW_UP_FROM_LINE "\xee\x94\xb9" // U+e539 +#define ICON_FA_PERSON_BIKING "\xef\xa1\x8a" // U+f84a +#define ICON_FA_PERSON_BOOTH "\xef\x9d\x96" // U+f756 +#define ICON_FA_PERSON_BREASTFEEDING "\xee\x94\xba" // U+e53a +#define ICON_FA_PERSON_BURST "\xee\x94\xbb" // U+e53b +#define ICON_FA_PERSON_CANE "\xee\x94\xbc" // U+e53c +#define ICON_FA_PERSON_CHALKBOARD "\xee\x94\xbd" // U+e53d +#define ICON_FA_PERSON_CIRCLE_CHECK "\xee\x94\xbe" // U+e53e +#define ICON_FA_PERSON_CIRCLE_EXCLAMATION "\xee\x94\xbf" // U+e53f +#define ICON_FA_PERSON_CIRCLE_MINUS "\xee\x95\x80" // U+e540 +#define ICON_FA_PERSON_CIRCLE_PLUS "\xee\x95\x81" // U+e541 +#define ICON_FA_PERSON_CIRCLE_QUESTION "\xee\x95\x82" // U+e542 +#define ICON_FA_PERSON_CIRCLE_XMARK "\xee\x95\x83" // U+e543 +#define ICON_FA_PERSON_DIGGING "\xef\xa1\x9e" // U+f85e +#define ICON_FA_PERSON_DOTS_FROM_LINE "\xef\x91\xb0" // U+f470 +#define ICON_FA_PERSON_DRESS "\xef\x86\x82" // U+f182 +#define ICON_FA_PERSON_DRESS_BURST "\xee\x95\x84" // U+e544 +#define ICON_FA_PERSON_DROWNING "\xee\x95\x85" // U+e545 +#define ICON_FA_PERSON_FALLING "\xee\x95\x86" // U+e546 +#define ICON_FA_PERSON_FALLING_BURST "\xee\x95\x87" // U+e547 +#define ICON_FA_PERSON_HALF_DRESS "\xee\x95\x88" // U+e548 +#define ICON_FA_PERSON_HARASSING "\xee\x95\x89" // U+e549 +#define ICON_FA_PERSON_HIKING "\xef\x9b\xac" // U+f6ec +#define ICON_FA_PERSON_MILITARY_POINTING "\xee\x95\x8a" // U+e54a +#define ICON_FA_PERSON_MILITARY_RIFLE "\xee\x95\x8b" // U+e54b +#define ICON_FA_PERSON_MILITARY_TO_PERSON "\xee\x95\x8c" // U+e54c +#define ICON_FA_PERSON_PRAYING "\xef\x9a\x83" // U+f683 +#define ICON_FA_PERSON_PREGNANT "\xee\x8c\x9e" // U+e31e +#define ICON_FA_PERSON_RAYS "\xee\x95\x8d" // U+e54d +#define ICON_FA_PERSON_RIFLE "\xee\x95\x8e" // U+e54e +#define ICON_FA_PERSON_RUNNING "\xef\x9c\x8c" // U+f70c +#define ICON_FA_PERSON_SHELTER "\xee\x95\x8f" // U+e54f +#define ICON_FA_PERSON_SKATING "\xef\x9f\x85" // U+f7c5 +#define ICON_FA_PERSON_SKIING "\xef\x9f\x89" // U+f7c9 +#define ICON_FA_PERSON_SKIING_NORDIC "\xef\x9f\x8a" // U+f7ca +#define ICON_FA_PERSON_SNOWBOARDING "\xef\x9f\x8e" // U+f7ce +#define ICON_FA_PERSON_SWIMMING "\xef\x97\x84" // U+f5c4 +#define ICON_FA_PERSON_THROUGH_WINDOW "\xee\x96\xa9" // U+e5a9 +#define ICON_FA_PERSON_WALKING "\xef\x95\x94" // U+f554 +#define ICON_FA_PERSON_WALKING_ARROW_LOOP_LEFT "\xee\x95\x91" // U+e551 +#define ICON_FA_PERSON_WALKING_ARROW_RIGHT "\xee\x95\x92" // U+e552 +#define ICON_FA_PERSON_WALKING_DASHED_LINE_ARROW_RIGHT "\xee\x95\x93" // U+e553 +#define ICON_FA_PERSON_WALKING_LUGGAGE "\xee\x95\x94" // U+e554 +#define ICON_FA_PERSON_WALKING_WITH_CANE "\xef\x8a\x9d" // U+f29d +#define ICON_FA_PESETA_SIGN "\xee\x88\xa1" // U+e221 +#define ICON_FA_PESO_SIGN "\xee\x88\xa2" // U+e222 +#define ICON_FA_PHONE "\xef\x82\x95" // U+f095 +#define ICON_FA_PHONE_FLIP "\xef\xa1\xb9" // U+f879 +#define ICON_FA_PHONE_SLASH "\xef\x8f\x9d" // U+f3dd +#define ICON_FA_PHONE_VOLUME "\xef\x8a\xa0" // U+f2a0 +#define ICON_FA_PHOTO_FILM "\xef\xa1\xbc" // U+f87c +#define ICON_FA_PIGGY_BANK "\xef\x93\x93" // U+f4d3 +#define ICON_FA_PILLS "\xef\x92\x84" // U+f484 +#define ICON_FA_PIZZA_SLICE "\xef\xa0\x98" // U+f818 +#define ICON_FA_PLACE_OF_WORSHIP "\xef\x99\xbf" // U+f67f +#define ICON_FA_PLANE "\xef\x81\xb2" // U+f072 +#define ICON_FA_PLANE_ARRIVAL "\xef\x96\xaf" // U+f5af +#define ICON_FA_PLANE_CIRCLE_CHECK "\xee\x95\x95" // U+e555 +#define ICON_FA_PLANE_CIRCLE_EXCLAMATION "\xee\x95\x96" // U+e556 +#define ICON_FA_PLANE_CIRCLE_XMARK "\xee\x95\x97" // U+e557 +#define ICON_FA_PLANE_DEPARTURE "\xef\x96\xb0" // U+f5b0 +#define ICON_FA_PLANE_LOCK "\xee\x95\x98" // U+e558 +#define ICON_FA_PLANE_SLASH "\xee\x81\xa9" // U+e069 +#define ICON_FA_PLANE_UP "\xee\x88\xad" // U+e22d +#define ICON_FA_PLANT_WILT "\xee\x96\xaa" // U+e5aa +#define ICON_FA_PLATE_WHEAT "\xee\x95\x9a" // U+e55a +#define ICON_FA_PLAY "\xef\x81\x8b" // U+f04b +#define ICON_FA_PLUG "\xef\x87\xa6" // U+f1e6 +#define ICON_FA_PLUG_CIRCLE_BOLT "\xee\x95\x9b" // U+e55b +#define ICON_FA_PLUG_CIRCLE_CHECK "\xee\x95\x9c" // U+e55c +#define ICON_FA_PLUG_CIRCLE_EXCLAMATION "\xee\x95\x9d" // U+e55d +#define ICON_FA_PLUG_CIRCLE_MINUS "\xee\x95\x9e" // U+e55e +#define ICON_FA_PLUG_CIRCLE_PLUS "\xee\x95\x9f" // U+e55f +#define ICON_FA_PLUG_CIRCLE_XMARK "\xee\x95\xa0" // U+e560 +#define ICON_FA_PLUS "+" // U+002b +#define ICON_FA_PLUS_MINUS "\xee\x90\xbc" // U+e43c +#define ICON_FA_PODCAST "\xef\x8b\x8e" // U+f2ce +#define ICON_FA_POO "\xef\x8b\xbe" // U+f2fe +#define ICON_FA_POO_STORM "\xef\x9d\x9a" // U+f75a +#define ICON_FA_POOP "\xef\x98\x99" // U+f619 +#define ICON_FA_POWER_OFF "\xef\x80\x91" // U+f011 +#define ICON_FA_PRESCRIPTION "\xef\x96\xb1" // U+f5b1 +#define ICON_FA_PRESCRIPTION_BOTTLE "\xef\x92\x85" // U+f485 +#define ICON_FA_PRESCRIPTION_BOTTLE_MEDICAL "\xef\x92\x86" // U+f486 +#define ICON_FA_PRINT "\xef\x80\xaf" // U+f02f +#define ICON_FA_PUMP_MEDICAL "\xee\x81\xaa" // U+e06a +#define ICON_FA_PUMP_SOAP "\xee\x81\xab" // U+e06b +#define ICON_FA_PUZZLE_PIECE "\xef\x84\xae" // U+f12e +#define ICON_FA_Q "Q" // U+0051 +#define ICON_FA_QRCODE "\xef\x80\xa9" // U+f029 +#define ICON_FA_QUESTION "?" // U+003f +#define ICON_FA_QUOTE_LEFT "\xef\x84\x8d" // U+f10d +#define ICON_FA_QUOTE_RIGHT "\xef\x84\x8e" // U+f10e +#define ICON_FA_R "R" // U+0052 +#define ICON_FA_RADIATION "\xef\x9e\xb9" // U+f7b9 +#define ICON_FA_RADIO "\xef\xa3\x97" // U+f8d7 +#define ICON_FA_RAINBOW "\xef\x9d\x9b" // U+f75b +#define ICON_FA_RANKING_STAR "\xee\x95\xa1" // U+e561 +#define ICON_FA_RECEIPT "\xef\x95\x83" // U+f543 +#define ICON_FA_RECORD_VINYL "\xef\xa3\x99" // U+f8d9 +#define ICON_FA_RECTANGLE_AD "\xef\x99\x81" // U+f641 +#define ICON_FA_RECTANGLE_LIST "\xef\x80\xa2" // U+f022 +#define ICON_FA_RECTANGLE_XMARK "\xef\x90\x90" // U+f410 +#define ICON_FA_RECYCLE "\xef\x86\xb8" // U+f1b8 +#define ICON_FA_REGISTERED "\xef\x89\x9d" // U+f25d +#define ICON_FA_REPEAT "\xef\x8d\xa3" // U+f363 +#define ICON_FA_REPLY "\xef\x8f\xa5" // U+f3e5 +#define ICON_FA_REPLY_ALL "\xef\x84\xa2" // U+f122 +#define ICON_FA_REPUBLICAN "\xef\x9d\x9e" // U+f75e +#define ICON_FA_RESTROOM "\xef\x9e\xbd" // U+f7bd +#define ICON_FA_RETWEET "\xef\x81\xb9" // U+f079 +#define ICON_FA_RIBBON "\xef\x93\x96" // U+f4d6 +#define ICON_FA_RIGHT_FROM_BRACKET "\xef\x8b\xb5" // U+f2f5 +#define ICON_FA_RIGHT_LEFT "\xef\x8d\xa2" // U+f362 +#define ICON_FA_RIGHT_LONG "\xef\x8c\x8b" // U+f30b +#define ICON_FA_RIGHT_TO_BRACKET "\xef\x8b\xb6" // U+f2f6 +#define ICON_FA_RING "\xef\x9c\x8b" // U+f70b +#define ICON_FA_ROAD "\xef\x80\x98" // U+f018 +#define ICON_FA_ROAD_BARRIER "\xee\x95\xa2" // U+e562 +#define ICON_FA_ROAD_BRIDGE "\xee\x95\xa3" // U+e563 +#define ICON_FA_ROAD_CIRCLE_CHECK "\xee\x95\xa4" // U+e564 +#define ICON_FA_ROAD_CIRCLE_EXCLAMATION "\xee\x95\xa5" // U+e565 +#define ICON_FA_ROAD_CIRCLE_XMARK "\xee\x95\xa6" // U+e566 +#define ICON_FA_ROAD_LOCK "\xee\x95\xa7" // U+e567 +#define ICON_FA_ROAD_SPIKES "\xee\x95\xa8" // U+e568 +#define ICON_FA_ROBOT "\xef\x95\x84" // U+f544 +#define ICON_FA_ROCKET "\xef\x84\xb5" // U+f135 +#define ICON_FA_ROTATE "\xef\x8b\xb1" // U+f2f1 +#define ICON_FA_ROTATE_LEFT "\xef\x8b\xaa" // U+f2ea +#define ICON_FA_ROTATE_RIGHT "\xef\x8b\xb9" // U+f2f9 +#define ICON_FA_ROUTE "\xef\x93\x97" // U+f4d7 +#define ICON_FA_RSS "\xef\x82\x9e" // U+f09e +#define ICON_FA_RUBLE_SIGN "\xef\x85\x98" // U+f158 +#define ICON_FA_RUG "\xee\x95\xa9" // U+e569 +#define ICON_FA_RULER "\xef\x95\x85" // U+f545 +#define ICON_FA_RULER_COMBINED "\xef\x95\x86" // U+f546 +#define ICON_FA_RULER_HORIZONTAL "\xef\x95\x87" // U+f547 +#define ICON_FA_RULER_VERTICAL "\xef\x95\x88" // U+f548 +#define ICON_FA_RUPEE_SIGN "\xef\x85\x96" // U+f156 +#define ICON_FA_RUPIAH_SIGN "\xee\x88\xbd" // U+e23d +#define ICON_FA_S "S" // U+0053 +#define ICON_FA_SACK_DOLLAR "\xef\xa0\x9d" // U+f81d +#define ICON_FA_SACK_XMARK "\xee\x95\xaa" // U+e56a +#define ICON_FA_SAILBOAT "\xee\x91\x85" // U+e445 +#define ICON_FA_SATELLITE "\xef\x9e\xbf" // U+f7bf +#define ICON_FA_SATELLITE_DISH "\xef\x9f\x80" // U+f7c0 +#define ICON_FA_SCALE_BALANCED "\xef\x89\x8e" // U+f24e +#define ICON_FA_SCALE_UNBALANCED "\xef\x94\x95" // U+f515 +#define ICON_FA_SCALE_UNBALANCED_FLIP "\xef\x94\x96" // U+f516 +#define ICON_FA_SCHOOL "\xef\x95\x89" // U+f549 +#define ICON_FA_SCHOOL_CIRCLE_CHECK "\xee\x95\xab" // U+e56b +#define ICON_FA_SCHOOL_CIRCLE_EXCLAMATION "\xee\x95\xac" // U+e56c +#define ICON_FA_SCHOOL_CIRCLE_XMARK "\xee\x95\xad" // U+e56d +#define ICON_FA_SCHOOL_FLAG "\xee\x95\xae" // U+e56e +#define ICON_FA_SCHOOL_LOCK "\xee\x95\xaf" // U+e56f +#define ICON_FA_SCISSORS "\xef\x83\x84" // U+f0c4 +#define ICON_FA_SCREWDRIVER "\xef\x95\x8a" // U+f54a +#define ICON_FA_SCREWDRIVER_WRENCH "\xef\x9f\x99" // U+f7d9 +#define ICON_FA_SCROLL "\xef\x9c\x8e" // U+f70e +#define ICON_FA_SCROLL_TORAH "\xef\x9a\xa0" // U+f6a0 +#define ICON_FA_SD_CARD "\xef\x9f\x82" // U+f7c2 +#define ICON_FA_SECTION "\xee\x91\x87" // U+e447 +#define ICON_FA_SEEDLING "\xef\x93\x98" // U+f4d8 +#define ICON_FA_SERVER "\xef\x88\xb3" // U+f233 +#define ICON_FA_SHAPES "\xef\x98\x9f" // U+f61f +#define ICON_FA_SHARE "\xef\x81\xa4" // U+f064 +#define ICON_FA_SHARE_FROM_SQUARE "\xef\x85\x8d" // U+f14d +#define ICON_FA_SHARE_NODES "\xef\x87\xa0" // U+f1e0 +#define ICON_FA_SHEET_PLASTIC "\xee\x95\xb1" // U+e571 +#define ICON_FA_SHEKEL_SIGN "\xef\x88\x8b" // U+f20b +#define ICON_FA_SHIELD "\xef\x84\xb2" // U+f132 +#define ICON_FA_SHIELD_CAT "\xee\x95\xb2" // U+e572 +#define ICON_FA_SHIELD_DOG "\xee\x95\xb3" // U+e573 +#define ICON_FA_SHIELD_HALVED "\xef\x8f\xad" // U+f3ed +#define ICON_FA_SHIELD_HEART "\xee\x95\xb4" // U+e574 +#define ICON_FA_SHIELD_VIRUS "\xee\x81\xac" // U+e06c +#define ICON_FA_SHIP "\xef\x88\x9a" // U+f21a +#define ICON_FA_SHIRT "\xef\x95\x93" // U+f553 +#define ICON_FA_SHOE_PRINTS "\xef\x95\x8b" // U+f54b +#define ICON_FA_SHOP "\xef\x95\x8f" // U+f54f +#define ICON_FA_SHOP_LOCK "\xee\x92\xa5" // U+e4a5 +#define ICON_FA_SHOP_SLASH "\xee\x81\xb0" // U+e070 +#define ICON_FA_SHOWER "\xef\x8b\x8c" // U+f2cc +#define ICON_FA_SHRIMP "\xee\x91\x88" // U+e448 +#define ICON_FA_SHUFFLE "\xef\x81\xb4" // U+f074 +#define ICON_FA_SHUTTLE_SPACE "\xef\x86\x97" // U+f197 +#define ICON_FA_SIGN_HANGING "\xef\x93\x99" // U+f4d9 +#define ICON_FA_SIGNAL "\xef\x80\x92" // U+f012 +#define ICON_FA_SIGNATURE "\xef\x96\xb7" // U+f5b7 +#define ICON_FA_SIGNS_POST "\xef\x89\xb7" // U+f277 +#define ICON_FA_SIM_CARD "\xef\x9f\x84" // U+f7c4 +#define ICON_FA_SINK "\xee\x81\xad" // U+e06d +#define ICON_FA_SITEMAP "\xef\x83\xa8" // U+f0e8 +#define ICON_FA_SKULL "\xef\x95\x8c" // U+f54c +#define ICON_FA_SKULL_CROSSBONES "\xef\x9c\x94" // U+f714 +#define ICON_FA_SLASH "\xef\x9c\x95" // U+f715 +#define ICON_FA_SLEIGH "\xef\x9f\x8c" // U+f7cc +#define ICON_FA_SLIDERS "\xef\x87\x9e" // U+f1de +#define ICON_FA_SMOG "\xef\x9d\x9f" // U+f75f +#define ICON_FA_SMOKING "\xef\x92\x8d" // U+f48d +#define ICON_FA_SNOWFLAKE "\xef\x8b\x9c" // U+f2dc +#define ICON_FA_SNOWMAN "\xef\x9f\x90" // U+f7d0 +#define ICON_FA_SNOWPLOW "\xef\x9f\x92" // U+f7d2 +#define ICON_FA_SOAP "\xee\x81\xae" // U+e06e +#define ICON_FA_SOCKS "\xef\x9a\x96" // U+f696 +#define ICON_FA_SOLAR_PANEL "\xef\x96\xba" // U+f5ba +#define ICON_FA_SORT "\xef\x83\x9c" // U+f0dc +#define ICON_FA_SORT_DOWN "\xef\x83\x9d" // U+f0dd +#define ICON_FA_SORT_UP "\xef\x83\x9e" // U+f0de +#define ICON_FA_SPA "\xef\x96\xbb" // U+f5bb +#define ICON_FA_SPAGHETTI_MONSTER_FLYING "\xef\x99\xbb" // U+f67b +#define ICON_FA_SPELL_CHECK "\xef\xa2\x91" // U+f891 +#define ICON_FA_SPIDER "\xef\x9c\x97" // U+f717 +#define ICON_FA_SPINNER "\xef\x84\x90" // U+f110 +#define ICON_FA_SPLOTCH "\xef\x96\xbc" // U+f5bc +#define ICON_FA_SPOON "\xef\x8b\xa5" // U+f2e5 +#define ICON_FA_SPRAY_CAN "\xef\x96\xbd" // U+f5bd +#define ICON_FA_SPRAY_CAN_SPARKLES "\xef\x97\x90" // U+f5d0 +#define ICON_FA_SQUARE "\xef\x83\x88" // U+f0c8 +#define ICON_FA_SQUARE_ARROW_UP_RIGHT "\xef\x85\x8c" // U+f14c +#define ICON_FA_SQUARE_CARET_DOWN "\xef\x85\x90" // U+f150 +#define ICON_FA_SQUARE_CARET_LEFT "\xef\x86\x91" // U+f191 +#define ICON_FA_SQUARE_CARET_RIGHT "\xef\x85\x92" // U+f152 +#define ICON_FA_SQUARE_CARET_UP "\xef\x85\x91" // U+f151 +#define ICON_FA_SQUARE_CHECK "\xef\x85\x8a" // U+f14a +#define ICON_FA_SQUARE_ENVELOPE "\xef\x86\x99" // U+f199 +#define ICON_FA_SQUARE_FULL "\xef\x91\x9c" // U+f45c +#define ICON_FA_SQUARE_H "\xef\x83\xbd" // U+f0fd +#define ICON_FA_SQUARE_MINUS "\xef\x85\x86" // U+f146 +#define ICON_FA_SQUARE_NFI "\xee\x95\xb6" // U+e576 +#define ICON_FA_SQUARE_PARKING "\xef\x95\x80" // U+f540 +#define ICON_FA_SQUARE_PEN "\xef\x85\x8b" // U+f14b +#define ICON_FA_SQUARE_PERSON_CONFINED "\xee\x95\xb7" // U+e577 +#define ICON_FA_SQUARE_PHONE "\xef\x82\x98" // U+f098 +#define ICON_FA_SQUARE_PHONE_FLIP "\xef\xa1\xbb" // U+f87b +#define ICON_FA_SQUARE_PLUS "\xef\x83\xbe" // U+f0fe +#define ICON_FA_SQUARE_POLL_HORIZONTAL "\xef\x9a\x82" // U+f682 +#define ICON_FA_SQUARE_POLL_VERTICAL "\xef\x9a\x81" // U+f681 +#define ICON_FA_SQUARE_ROOT_VARIABLE "\xef\x9a\x98" // U+f698 +#define ICON_FA_SQUARE_RSS "\xef\x85\x83" // U+f143 +#define ICON_FA_SQUARE_SHARE_NODES "\xef\x87\xa1" // U+f1e1 +#define ICON_FA_SQUARE_UP_RIGHT "\xef\x8d\xa0" // U+f360 +#define ICON_FA_SQUARE_VIRUS "\xee\x95\xb8" // U+e578 +#define ICON_FA_SQUARE_XMARK "\xef\x8b\x93" // U+f2d3 +#define ICON_FA_STAFF_SNAKE "\xee\x95\xb9" // U+e579 +#define ICON_FA_STAIRS "\xee\x8a\x89" // U+e289 +#define ICON_FA_STAMP "\xef\x96\xbf" // U+f5bf +#define ICON_FA_STAPLER "\xee\x96\xaf" // U+e5af +#define ICON_FA_STAR "\xef\x80\x85" // U+f005 +#define ICON_FA_STAR_AND_CRESCENT "\xef\x9a\x99" // U+f699 +#define ICON_FA_STAR_HALF "\xef\x82\x89" // U+f089 +#define ICON_FA_STAR_HALF_STROKE "\xef\x97\x80" // U+f5c0 +#define ICON_FA_STAR_OF_DAVID "\xef\x9a\x9a" // U+f69a +#define ICON_FA_STAR_OF_LIFE "\xef\x98\xa1" // U+f621 +#define ICON_FA_STERLING_SIGN "\xef\x85\x94" // U+f154 +#define ICON_FA_STETHOSCOPE "\xef\x83\xb1" // U+f0f1 +#define ICON_FA_STOP "\xef\x81\x8d" // U+f04d +#define ICON_FA_STOPWATCH "\xef\x8b\xb2" // U+f2f2 +#define ICON_FA_STOPWATCH_20 "\xee\x81\xaf" // U+e06f +#define ICON_FA_STORE "\xef\x95\x8e" // U+f54e +#define ICON_FA_STORE_SLASH "\xee\x81\xb1" // U+e071 +#define ICON_FA_STREET_VIEW "\xef\x88\x9d" // U+f21d +#define ICON_FA_STRIKETHROUGH "\xef\x83\x8c" // U+f0cc +#define ICON_FA_STROOPWAFEL "\xef\x95\x91" // U+f551 +#define ICON_FA_SUBSCRIPT "\xef\x84\xac" // U+f12c +#define ICON_FA_SUITCASE "\xef\x83\xb2" // U+f0f2 +#define ICON_FA_SUITCASE_MEDICAL "\xef\x83\xba" // U+f0fa +#define ICON_FA_SUITCASE_ROLLING "\xef\x97\x81" // U+f5c1 +#define ICON_FA_SUN "\xef\x86\x85" // U+f185 +#define ICON_FA_SUN_PLANT_WILT "\xee\x95\xba" // U+e57a +#define ICON_FA_SUPERSCRIPT "\xef\x84\xab" // U+f12b +#define ICON_FA_SWATCHBOOK "\xef\x97\x83" // U+f5c3 +#define ICON_FA_SYNAGOGUE "\xef\x9a\x9b" // U+f69b +#define ICON_FA_SYRINGE "\xef\x92\x8e" // U+f48e +#define ICON_FA_T "T" // U+0054 +#define ICON_FA_TABLE "\xef\x83\x8e" // U+f0ce +#define ICON_FA_TABLE_CELLS "\xef\x80\x8a" // U+f00a +#define ICON_FA_TABLE_CELLS_LARGE "\xef\x80\x89" // U+f009 +#define ICON_FA_TABLE_COLUMNS "\xef\x83\x9b" // U+f0db +#define ICON_FA_TABLE_LIST "\xef\x80\x8b" // U+f00b +#define ICON_FA_TABLE_TENNIS_PADDLE_BALL "\xef\x91\x9d" // U+f45d +#define ICON_FA_TABLET "\xef\x8f\xbb" // U+f3fb +#define ICON_FA_TABLET_BUTTON "\xef\x84\x8a" // U+f10a +#define ICON_FA_TABLET_SCREEN_BUTTON "\xef\x8f\xba" // U+f3fa +#define ICON_FA_TABLETS "\xef\x92\x90" // U+f490 +#define ICON_FA_TACHOGRAPH_DIGITAL "\xef\x95\xa6" // U+f566 +#define ICON_FA_TAG "\xef\x80\xab" // U+f02b +#define ICON_FA_TAGS "\xef\x80\xac" // U+f02c +#define ICON_FA_TAPE "\xef\x93\x9b" // U+f4db +#define ICON_FA_TARP "\xee\x95\xbb" // U+e57b +#define ICON_FA_TARP_DROPLET "\xee\x95\xbc" // U+e57c +#define ICON_FA_TAXI "\xef\x86\xba" // U+f1ba +#define ICON_FA_TEETH "\xef\x98\xae" // U+f62e +#define ICON_FA_TEETH_OPEN "\xef\x98\xaf" // U+f62f +#define ICON_FA_TEMPERATURE_ARROW_DOWN "\xee\x80\xbf" // U+e03f +#define ICON_FA_TEMPERATURE_ARROW_UP "\xee\x81\x80" // U+e040 +#define ICON_FA_TEMPERATURE_EMPTY "\xef\x8b\x8b" // U+f2cb +#define ICON_FA_TEMPERATURE_FULL "\xef\x8b\x87" // U+f2c7 +#define ICON_FA_TEMPERATURE_HALF "\xef\x8b\x89" // U+f2c9 +#define ICON_FA_TEMPERATURE_HIGH "\xef\x9d\xa9" // U+f769 +#define ICON_FA_TEMPERATURE_LOW "\xef\x9d\xab" // U+f76b +#define ICON_FA_TEMPERATURE_QUARTER "\xef\x8b\x8a" // U+f2ca +#define ICON_FA_TEMPERATURE_THREE_QUARTERS "\xef\x8b\x88" // U+f2c8 +#define ICON_FA_TENGE_SIGN "\xef\x9f\x97" // U+f7d7 +#define ICON_FA_TENT "\xee\x95\xbd" // U+e57d +#define ICON_FA_TENT_ARROW_DOWN_TO_LINE "\xee\x95\xbe" // U+e57e +#define ICON_FA_TENT_ARROW_LEFT_RIGHT "\xee\x95\xbf" // U+e57f +#define ICON_FA_TENT_ARROW_TURN_LEFT "\xee\x96\x80" // U+e580 +#define ICON_FA_TENT_ARROWS_DOWN "\xee\x96\x81" // U+e581 +#define ICON_FA_TENTS "\xee\x96\x82" // U+e582 +#define ICON_FA_TERMINAL "\xef\x84\xa0" // U+f120 +#define ICON_FA_TEXT_HEIGHT "\xef\x80\xb4" // U+f034 +#define ICON_FA_TEXT_SLASH "\xef\xa1\xbd" // U+f87d +#define ICON_FA_TEXT_WIDTH "\xef\x80\xb5" // U+f035 +#define ICON_FA_THERMOMETER "\xef\x92\x91" // U+f491 +#define ICON_FA_THUMBS_DOWN "\xef\x85\xa5" // U+f165 +#define ICON_FA_THUMBS_UP "\xef\x85\xa4" // U+f164 +#define ICON_FA_THUMBTACK "\xef\x82\x8d" // U+f08d +#define ICON_FA_TICKET "\xef\x85\x85" // U+f145 +#define ICON_FA_TICKET_SIMPLE "\xef\x8f\xbf" // U+f3ff +#define ICON_FA_TIMELINE "\xee\x8a\x9c" // U+e29c +#define ICON_FA_TOGGLE_OFF "\xef\x88\x84" // U+f204 +#define ICON_FA_TOGGLE_ON "\xef\x88\x85" // U+f205 +#define ICON_FA_TOILET "\xef\x9f\x98" // U+f7d8 +#define ICON_FA_TOILET_PAPER "\xef\x9c\x9e" // U+f71e +#define ICON_FA_TOILET_PAPER_SLASH "\xee\x81\xb2" // U+e072 +#define ICON_FA_TOILET_PORTABLE "\xee\x96\x83" // U+e583 +#define ICON_FA_TOILETS_PORTABLE "\xee\x96\x84" // U+e584 +#define ICON_FA_TOOLBOX "\xef\x95\x92" // U+f552 +#define ICON_FA_TOOTH "\xef\x97\x89" // U+f5c9 +#define ICON_FA_TORII_GATE "\xef\x9a\xa1" // U+f6a1 +#define ICON_FA_TORNADO "\xef\x9d\xaf" // U+f76f +#define ICON_FA_TOWER_BROADCAST "\xef\x94\x99" // U+f519 +#define ICON_FA_TOWER_CELL "\xee\x96\x85" // U+e585 +#define ICON_FA_TOWER_OBSERVATION "\xee\x96\x86" // U+e586 +#define ICON_FA_TRACTOR "\xef\x9c\xa2" // U+f722 +#define ICON_FA_TRADEMARK "\xef\x89\x9c" // U+f25c +#define ICON_FA_TRAFFIC_LIGHT "\xef\x98\xb7" // U+f637 +#define ICON_FA_TRAILER "\xee\x81\x81" // U+e041 +#define ICON_FA_TRAIN "\xef\x88\xb8" // U+f238 +#define ICON_FA_TRAIN_SUBWAY "\xef\x88\xb9" // U+f239 +#define ICON_FA_TRAIN_TRAM "\xee\x96\xb4" // U+e5b4 +#define ICON_FA_TRANSGENDER "\xef\x88\xa5" // U+f225 +#define ICON_FA_TRASH "\xef\x87\xb8" // U+f1f8 +#define ICON_FA_TRASH_ARROW_UP "\xef\xa0\xa9" // U+f829 +#define ICON_FA_TRASH_CAN "\xef\x8b\xad" // U+f2ed +#define ICON_FA_TRASH_CAN_ARROW_UP "\xef\xa0\xaa" // U+f82a +#define ICON_FA_TREE "\xef\x86\xbb" // U+f1bb +#define ICON_FA_TREE_CITY "\xee\x96\x87" // U+e587 +#define ICON_FA_TRIANGLE_EXCLAMATION "\xef\x81\xb1" // U+f071 +#define ICON_FA_TROPHY "\xef\x82\x91" // U+f091 +#define ICON_FA_TROWEL "\xee\x96\x89" // U+e589 +#define ICON_FA_TROWEL_BRICKS "\xee\x96\x8a" // U+e58a +#define ICON_FA_TRUCK "\xef\x83\x91" // U+f0d1 +#define ICON_FA_TRUCK_ARROW_RIGHT "\xee\x96\x8b" // U+e58b +#define ICON_FA_TRUCK_DROPLET "\xee\x96\x8c" // U+e58c +#define ICON_FA_TRUCK_FAST "\xef\x92\x8b" // U+f48b +#define ICON_FA_TRUCK_FIELD "\xee\x96\x8d" // U+e58d +#define ICON_FA_TRUCK_FIELD_UN "\xee\x96\x8e" // U+e58e +#define ICON_FA_TRUCK_FRONT "\xee\x8a\xb7" // U+e2b7 +#define ICON_FA_TRUCK_MEDICAL "\xef\x83\xb9" // U+f0f9 +#define ICON_FA_TRUCK_MONSTER "\xef\x98\xbb" // U+f63b +#define ICON_FA_TRUCK_MOVING "\xef\x93\x9f" // U+f4df +#define ICON_FA_TRUCK_PICKUP "\xef\x98\xbc" // U+f63c +#define ICON_FA_TRUCK_PLANE "\xee\x96\x8f" // U+e58f +#define ICON_FA_TRUCK_RAMP_BOX "\xef\x93\x9e" // U+f4de +#define ICON_FA_TTY "\xef\x87\xa4" // U+f1e4 +#define ICON_FA_TURKISH_LIRA_SIGN "\xee\x8a\xbb" // U+e2bb +#define ICON_FA_TURN_DOWN "\xef\x8e\xbe" // U+f3be +#define ICON_FA_TURN_UP "\xef\x8e\xbf" // U+f3bf +#define ICON_FA_TV "\xef\x89\xac" // U+f26c +#define ICON_FA_U "U" // U+0055 +#define ICON_FA_UMBRELLA "\xef\x83\xa9" // U+f0e9 +#define ICON_FA_UMBRELLA_BEACH "\xef\x97\x8a" // U+f5ca +#define ICON_FA_UNDERLINE "\xef\x83\x8d" // U+f0cd +#define ICON_FA_UNIVERSAL_ACCESS "\xef\x8a\x9a" // U+f29a +#define ICON_FA_UNLOCK "\xef\x82\x9c" // U+f09c +#define ICON_FA_UNLOCK_KEYHOLE "\xef\x84\xbe" // U+f13e +#define ICON_FA_UP_DOWN "\xef\x8c\xb8" // U+f338 +#define ICON_FA_UP_DOWN_LEFT_RIGHT "\xef\x82\xb2" // U+f0b2 +#define ICON_FA_UP_LONG "\xef\x8c\x8c" // U+f30c +#define ICON_FA_UP_RIGHT_AND_DOWN_LEFT_FROM_CENTER "\xef\x90\xa4" // U+f424 +#define ICON_FA_UP_RIGHT_FROM_SQUARE "\xef\x8d\x9d" // U+f35d +#define ICON_FA_UPLOAD "\xef\x82\x93" // U+f093 +#define ICON_FA_USER "\xef\x80\x87" // U+f007 +#define ICON_FA_USER_ASTRONAUT "\xef\x93\xbb" // U+f4fb +#define ICON_FA_USER_CHECK "\xef\x93\xbc" // U+f4fc +#define ICON_FA_USER_CLOCK "\xef\x93\xbd" // U+f4fd +#define ICON_FA_USER_DOCTOR "\xef\x83\xb0" // U+f0f0 +#define ICON_FA_USER_GEAR "\xef\x93\xbe" // U+f4fe +#define ICON_FA_USER_GRADUATE "\xef\x94\x81" // U+f501 +#define ICON_FA_USER_GROUP "\xef\x94\x80" // U+f500 +#define ICON_FA_USER_INJURED "\xef\x9c\xa8" // U+f728 +#define ICON_FA_USER_LARGE "\xef\x90\x86" // U+f406 +#define ICON_FA_USER_LARGE_SLASH "\xef\x93\xba" // U+f4fa +#define ICON_FA_USER_LOCK "\xef\x94\x82" // U+f502 +#define ICON_FA_USER_MINUS "\xef\x94\x83" // U+f503 +#define ICON_FA_USER_NINJA "\xef\x94\x84" // U+f504 +#define ICON_FA_USER_NURSE "\xef\xa0\xaf" // U+f82f +#define ICON_FA_USER_PEN "\xef\x93\xbf" // U+f4ff +#define ICON_FA_USER_PLUS "\xef\x88\xb4" // U+f234 +#define ICON_FA_USER_SECRET "\xef\x88\x9b" // U+f21b +#define ICON_FA_USER_SHIELD "\xef\x94\x85" // U+f505 +#define ICON_FA_USER_SLASH "\xef\x94\x86" // U+f506 +#define ICON_FA_USER_TAG "\xef\x94\x87" // U+f507 +#define ICON_FA_USER_TIE "\xef\x94\x88" // U+f508 +#define ICON_FA_USER_XMARK "\xef\x88\xb5" // U+f235 +#define ICON_FA_USERS "\xef\x83\x80" // U+f0c0 +#define ICON_FA_USERS_BETWEEN_LINES "\xee\x96\x91" // U+e591 +#define ICON_FA_USERS_GEAR "\xef\x94\x89" // U+f509 +#define ICON_FA_USERS_LINE "\xee\x96\x92" // U+e592 +#define ICON_FA_USERS_RAYS "\xee\x96\x93" // U+e593 +#define ICON_FA_USERS_RECTANGLE "\xee\x96\x94" // U+e594 +#define ICON_FA_USERS_SLASH "\xee\x81\xb3" // U+e073 +#define ICON_FA_USERS_VIEWFINDER "\xee\x96\x95" // U+e595 +#define ICON_FA_UTENSILS "\xef\x8b\xa7" // U+f2e7 +#define ICON_FA_V "V" // U+0056 +#define ICON_FA_VAN_SHUTTLE "\xef\x96\xb6" // U+f5b6 +#define ICON_FA_VAULT "\xee\x8b\x85" // U+e2c5 +#define ICON_FA_VECTOR_SQUARE "\xef\x97\x8b" // U+f5cb +#define ICON_FA_VENUS "\xef\x88\xa1" // U+f221 +#define ICON_FA_VENUS_DOUBLE "\xef\x88\xa6" // U+f226 +#define ICON_FA_VENUS_MARS "\xef\x88\xa8" // U+f228 +#define ICON_FA_VEST "\xee\x82\x85" // U+e085 +#define ICON_FA_VEST_PATCHES "\xee\x82\x86" // U+e086 +#define ICON_FA_VIAL "\xef\x92\x92" // U+f492 +#define ICON_FA_VIAL_CIRCLE_CHECK "\xee\x96\x96" // U+e596 +#define ICON_FA_VIAL_VIRUS "\xee\x96\x97" // U+e597 +#define ICON_FA_VIALS "\xef\x92\x93" // U+f493 +#define ICON_FA_VIDEO "\xef\x80\xbd" // U+f03d +#define ICON_FA_VIDEO_SLASH "\xef\x93\xa2" // U+f4e2 +#define ICON_FA_VIHARA "\xef\x9a\xa7" // U+f6a7 +#define ICON_FA_VIRUS "\xee\x81\xb4" // U+e074 +#define ICON_FA_VIRUS_COVID "\xee\x92\xa8" // U+e4a8 +#define ICON_FA_VIRUS_COVID_SLASH "\xee\x92\xa9" // U+e4a9 +#define ICON_FA_VIRUS_SLASH "\xee\x81\xb5" // U+e075 +#define ICON_FA_VIRUSES "\xee\x81\xb6" // U+e076 +#define ICON_FA_VOICEMAIL "\xef\xa2\x97" // U+f897 +#define ICON_FA_VOLCANO "\xef\x9d\xb0" // U+f770 +#define ICON_FA_VOLLEYBALL "\xef\x91\x9f" // U+f45f +#define ICON_FA_VOLUME_HIGH "\xef\x80\xa8" // U+f028 +#define ICON_FA_VOLUME_LOW "\xef\x80\xa7" // U+f027 +#define ICON_FA_VOLUME_OFF "\xef\x80\xa6" // U+f026 +#define ICON_FA_VOLUME_XMARK "\xef\x9a\xa9" // U+f6a9 +#define ICON_FA_VR_CARDBOARD "\xef\x9c\xa9" // U+f729 +#define ICON_FA_W "W" // U+0057 +#define ICON_FA_WALKIE_TALKIE "\xef\xa3\xaf" // U+f8ef +#define ICON_FA_WALLET "\xef\x95\x95" // U+f555 +#define ICON_FA_WAND_MAGIC "\xef\x83\x90" // U+f0d0 +#define ICON_FA_WAND_MAGIC_SPARKLES "\xee\x8b\x8a" // U+e2ca +#define ICON_FA_WAND_SPARKLES "\xef\x9c\xab" // U+f72b +#define ICON_FA_WAREHOUSE "\xef\x92\x94" // U+f494 +#define ICON_FA_WATER "\xef\x9d\xb3" // U+f773 +#define ICON_FA_WATER_LADDER "\xef\x97\x85" // U+f5c5 +#define ICON_FA_WAVE_SQUARE "\xef\xa0\xbe" // U+f83e +#define ICON_FA_WEIGHT_HANGING "\xef\x97\x8d" // U+f5cd +#define ICON_FA_WEIGHT_SCALE "\xef\x92\x96" // U+f496 +#define ICON_FA_WHEAT_AWN "\xee\x8b\x8d" // U+e2cd +#define ICON_FA_WHEAT_AWN_CIRCLE_EXCLAMATION "\xee\x96\x98" // U+e598 +#define ICON_FA_WHEELCHAIR "\xef\x86\x93" // U+f193 +#define ICON_FA_WHEELCHAIR_MOVE "\xee\x8b\x8e" // U+e2ce +#define ICON_FA_WHISKEY_GLASS "\xef\x9e\xa0" // U+f7a0 +#define ICON_FA_WIFI "\xef\x87\xab" // U+f1eb +#define ICON_FA_WIND "\xef\x9c\xae" // U+f72e +#define ICON_FA_WINDOW_MAXIMIZE "\xef\x8b\x90" // U+f2d0 +#define ICON_FA_WINDOW_MINIMIZE "\xef\x8b\x91" // U+f2d1 +#define ICON_FA_WINDOW_RESTORE "\xef\x8b\x92" // U+f2d2 +#define ICON_FA_WINE_BOTTLE "\xef\x9c\xaf" // U+f72f +#define ICON_FA_WINE_GLASS "\xef\x93\xa3" // U+f4e3 +#define ICON_FA_WINE_GLASS_EMPTY "\xef\x97\x8e" // U+f5ce +#define ICON_FA_WON_SIGN "\xef\x85\x99" // U+f159 +#define ICON_FA_WORM "\xee\x96\x99" // U+e599 +#define ICON_FA_WRENCH "\xef\x82\xad" // U+f0ad +#define ICON_FA_X "X" // U+0058 +#define ICON_FA_X_RAY "\xef\x92\x97" // U+f497 +#define ICON_FA_XMARK "\xef\x80\x8d" // U+f00d +#define ICON_FA_XMARKS_LINES "\xee\x96\x9a" // U+e59a +#define ICON_FA_Y "Y" // U+0059 +#define ICON_FA_YEN_SIGN "\xef\x85\x97" // U+f157 +#define ICON_FA_YIN_YANG "\xef\x9a\xad" // U+f6ad +#define ICON_FA_Z "Z" // U+005a \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index d9fc8373..aff1eaad 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -4,6 +4,7 @@ #include "SHpch.h" #include "IconsMaterialDesign.h" +#include "IconsFontAwesome6.h" #include "DragDrop/SHDragDrop.hpp" //#==============================================================# @@ -36,6 +37,7 @@ #include #include #include +#include //#==============================================================# //|| ImGui Backend Includes || @@ -43,6 +45,8 @@ #include #include +#include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h" + RTTR_REGISTRATION { using namespace SHADE; @@ -73,6 +77,7 @@ namespace SHADE //#==============================================================# void SHEditor::Init() { + IMGUI_CHECKVERSION(); if(auto context = ImGui::CreateContext()) { @@ -82,11 +87,21 @@ namespace SHADE } } - ImGuiIO& io = ImGui::GetIO(); (void)io; + //Add editor windows + SHEditorWindowManager::CreateEditorWindow(); + SHEditorWindowManager::CreateEditorWindow(); + SHEditorWindowManager::CreateEditorWindow(); + SHEditorWindowManager::CreateEditorWindow(); + SHEditorWindowManager::CreateEditorWindow(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls - io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; //Enable for Multi-Viewports - io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; //Enable docking + io = &ImGui::GetIO(); + + io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; //Enable for Multi-Viewports + io->ConfigFlags |= ImGuiConfigFlags_DockingEnable; //Enable docking + io->IniFilename = "../../Assets/Editor/Layouts/UserLayout.ini"; + io->ConfigWindowsMoveFromTitleBarOnly = true; + InitLayout(); InitFonts(); @@ -98,11 +113,11 @@ namespace SHADE SetStyle(Style::SHADE); - //Add editor windows - SHEditorWindowManager::CreateEditorWindow(); - SHEditorWindowManager::CreateEditorWindow(); - SHEditorWindowManager::CreateEditorWindow(); - SHEditorWindowManager::CreateEditorWindow(); + + for (const auto& window : SHEditorWindowManager::editorWindows | std::views::values) + { + window->Init(); + } SHLOG_INFO("Successfully initialised SHADE Engine Editor") } @@ -114,8 +129,12 @@ namespace SHADE for (const auto& window : SHEditorWindowManager::editorWindows | std::views::values) { if(window->isOpen) + { window->Update(); + } } + + PollPicking(); if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z)) { @@ -125,36 +144,47 @@ namespace SHADE { SHCommandManager::UndoCommand(); } - - + Render(); } void SHEditor::Render() { ImGui::Render(); - ImGuiIO& io = ImGui::GetIO(); - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + if (io->ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); } } + void SHEditor::InitLayout() noexcept + { + if(!std::filesystem::exists(io->IniFilename)) + { + std::filesystem::copy_file("../../Assets/Editor/Layouts/Default.ini", io->IniFilename); + } + //eventually load preferred layout here + } + void SHEditor::InitFonts() noexcept { - ImGuiIO& io = ImGui::GetIO(); - ImFont* mainFont = io.Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/Segoe UI.ttf", 20.f);//TODO: Change to config based assets path + ImFont* mainFont = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/Segoe UI.ttf", 20.f);//TODO: Change to config based assets path - static const ImWchar icon_ranges[] = { ICON_MIN_MD, ICON_MAX_16_MD, 0 }; ImFontConfig icons_config{}; icons_config.MergeMode = true; icons_config.GlyphOffset.y = 5.f; - ImFont* UIFont = io.Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/MaterialIcons-Regular.ttf", 20.f, &icons_config, icon_ranges); //TODO: Change to config based assets path - - io.Fonts->Build(); + constexpr ImWchar icon_ranges_fa[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; + ImFont* UIFontFA = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/fa-solid-900.ttf", 20.f, &icons_config, icon_ranges_fa); //TODO: Change to config based assets path + constexpr ImWchar icon_ranges_md[] = { ICON_MIN_MD, ICON_MAX_MD, 0 }; + ImFont* UIFontMD = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/MaterialIcons-Regular.ttf", 20.f, &icons_config, icon_ranges_md); //TODO: Change to config based assets path + io->Fonts->Build(); } void SHEditor::Exit() { + for (const auto& window : SHEditorWindowManager::editorWindows | std::views::values) + { + window->Init(); + } ImGui_ImplVulkan_Shutdown(); ImGui_ImplSDL2_Shutdown(); ImGui::DestroyContext(); @@ -167,86 +197,86 @@ namespace SHADE default: case Style::SHADE: { - ImGuiStyle& imStyle = ImGui::GetStyle(); - ImVec4* colors = imStyle.Colors; - colors[ImGuiCol_Text] = ImVec4(0.706f, 0.729f, 0.757f, 1.00f); - colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); - colors[ImGuiCol_WindowBg] = ImVec4(0.172f, 0.184f, 0.203f, 1.f); - colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - colors[ImGuiCol_PopupBg] = ImVec4(0.19f, 0.19f, 0.19f, 0.92f); - colors[ImGuiCol_Border] = ImVec4(0.19f, 0.19f, 0.19f, 0.29f); - colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.24f); - colors[ImGuiCol_FrameBg] = ImVec4(0.05f, 0.05f, 0.05f, 0.54f); - colors[ImGuiCol_FrameBgHovered] = ImVec4(0.19f, 0.19f, 0.19f, 0.54f); - colors[ImGuiCol_FrameBgActive] = ImVec4(0.20f, 0.22f, 0.23f, 1.00f); - colors[ImGuiCol_TitleBg] = colors[ImGuiCol_WindowBg]; - colors[ImGuiCol_TitleBgActive] = colors[ImGuiCol_WindowBg]; - colors[ImGuiCol_TitleBgCollapsed] = colors[ImGuiCol_WindowBg]; - colors[ImGuiCol_MenuBarBg] = ImVec4(0.129f, 0.141f, 0.157f, 1.f); - colors[ImGuiCol_ScrollbarBg] = colors[ImGuiCol_WindowBg]; - colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.34f, 0.34f, 0.34f, 0.54f); - colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.40f, 0.54f); - colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.56f, 0.56f, 0.56f, 0.54f); - colors[ImGuiCol_CheckMark] = ImVec4(0.627f, 0.239f, 0.761f, 1.00f); - colors[ImGuiCol_SliderGrab] = ImVec4(0.34f, 0.34f, 0.34f, 0.54f); - colors[ImGuiCol_SliderGrabActive] = ImVec4(0.56f, 0.56f, 0.56f, 0.54f); - colors[ImGuiCol_Button] = ImVec4(0.05f, 0.05f, 0.05f, 0.54f); - colors[ImGuiCol_ButtonHovered] = ImVec4(0.15f, 0.15f, 0.15f, 0.54f); - colors[ImGuiCol_ButtonActive] = ImVec4(0.20f, 0.22f, 0.23f, 1.00f); - colors[ImGuiCol_Header] = ImVec4(0.00f, 0.00f, 0.00f, 0.52f); - colors[ImGuiCol_HeaderHovered] = ImVec4(0.00f, 0.00f, 0.00f, 0.36f); - colors[ImGuiCol_HeaderActive] = ImVec4(0.20f, 0.22f, 0.23f, 0.33f); - colors[ImGuiCol_Separator] = colors[ImGuiCol_MenuBarBg]; - colors[ImGuiCol_SeparatorHovered] = ImVec4(0.44f, 0.44f, 0.44f, 0.29f); - colors[ImGuiCol_SeparatorActive] = ImVec4(0.40f, 0.44f, 0.47f, 1.00f); - colors[ImGuiCol_ResizeGrip] = ImVec4(0.28f, 0.28f, 0.28f, 0.29f); - colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.44f, 0.44f, 0.44f, 0.29f); - colors[ImGuiCol_ResizeGripActive] = ImVec4(0.40f, 0.44f, 0.47f, 1.00f); - colors[ImGuiCol_Tab] = colors[ImGuiCol_WindowBg]; - colors[ImGuiCol_TabHovered] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f); - colors[ImGuiCol_TabActive] = ImVec4(0.14f, 0.14f, 0.14f, 0.8f); - colors[ImGuiCol_TabUnfocused] = colors[ImGuiCol_WindowBg]; - colors[ImGuiCol_TabUnfocusedActive] = colors[ImGuiCol_WindowBg]; - colors[ImGuiCol_DockingPreview] = ImVec4(0.627f, 0.239f, 0.761f, 1.00f); - colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.855f, 0.6f, 0.941f, 1.00f); - colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); - colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); - colors[ImGuiCol_PlotHistogram] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); - colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); - colors[ImGuiCol_TableHeaderBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.52f); - colors[ImGuiCol_TableBorderStrong] = ImVec4(0.00f, 0.00f, 0.00f, 0.52f); - colors[ImGuiCol_TableBorderLight] = ImVec4(0.28f, 0.28f, 0.28f, 0.29f); - colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f); - colors[ImGuiCol_TextSelectedBg] = ImVec4(0.20f, 0.22f, 0.23f, 1.00f); - colors[ImGuiCol_DragDropTarget] = ImVec4(0.33f, 0.67f, 0.86f, 1.00f); - colors[ImGuiCol_NavHighlight] = ImVec4(0.73f, 0.73f, 0.73f, 0.7f); + ImGuiStyle& imStyle = ImGui::GetStyle(); + ImVec4* colors = imStyle.Colors; + colors[ImGuiCol_Text] = ImVec4(0.706f, 0.729f, 0.757f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.172f, 0.184f, 0.203f, 1.f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(0.19f, 0.19f, 0.19f, 0.92f); + colors[ImGuiCol_Border] = ImVec4(0.19f, 0.19f, 0.19f, 0.29f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.24f); + colors[ImGuiCol_FrameBg] = ImVec4(0.05f, 0.05f, 0.05f, 0.54f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.19f, 0.19f, 0.19f, 0.54f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.20f, 0.22f, 0.23f, 1.00f); + colors[ImGuiCol_TitleBg] = colors[ImGuiCol_WindowBg]; + colors[ImGuiCol_TitleBgActive] = colors[ImGuiCol_WindowBg]; + colors[ImGuiCol_TitleBgCollapsed] = colors[ImGuiCol_WindowBg]; + colors[ImGuiCol_MenuBarBg] = ImVec4(0.129f, 0.141f, 0.157f, 1.f); + colors[ImGuiCol_ScrollbarBg] = colors[ImGuiCol_WindowBg]; + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.34f, 0.34f, 0.34f, 0.54f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.40f, 0.54f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.56f, 0.56f, 0.56f, 0.54f); + colors[ImGuiCol_CheckMark] = ImVec4(0.627f, 0.239f, 0.761f, 1.00f); + colors[ImGuiCol_SliderGrab] = ImVec4(0.34f, 0.34f, 0.34f, 0.54f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.56f, 0.56f, 0.56f, 0.54f); + colors[ImGuiCol_Button] = ImVec4(0.05f, 0.05f, 0.05f, 0.54f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.15f, 0.15f, 0.15f, 0.54f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.20f, 0.22f, 0.23f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.00f, 0.00f, 0.00f, 0.52f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.00f, 0.00f, 0.00f, 0.36f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.20f, 0.22f, 0.23f, 0.33f); + colors[ImGuiCol_Separator] = colors[ImGuiCol_MenuBarBg]; + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.44f, 0.44f, 0.44f, 0.29f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.40f, 0.44f, 0.47f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(0.28f, 0.28f, 0.28f, 0.29f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.44f, 0.44f, 0.44f, 0.29f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.40f, 0.44f, 0.47f, 1.00f); + colors[ImGuiCol_Tab] = colors[ImGuiCol_WindowBg]; + colors[ImGuiCol_TabHovered] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f); + colors[ImGuiCol_TabActive] = ImVec4(0.14f, 0.14f, 0.14f, 0.8f); + colors[ImGuiCol_TabUnfocused] = colors[ImGuiCol_WindowBg]; + colors[ImGuiCol_TabUnfocusedActive] = colors[ImGuiCol_WindowBg]; + colors[ImGuiCol_DockingPreview] = ImVec4(0.627f, 0.239f, 0.761f, 1.00f); + colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.855f, 0.6f, 0.941f, 1.00f); + colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); + colors[ImGuiCol_TableHeaderBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.52f); + colors[ImGuiCol_TableBorderStrong] = ImVec4(0.00f, 0.00f, 0.00f, 0.52f); + colors[ImGuiCol_TableBorderLight] = ImVec4(0.28f, 0.28f, 0.28f, 0.29f); + colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.20f, 0.22f, 0.23f, 1.00f); + colors[ImGuiCol_DragDropTarget] = ImVec4(0.33f, 0.67f, 0.86f, 1.00f); + colors[ImGuiCol_NavHighlight] = ImVec4(0.73f, 0.73f, 0.73f, 0.7f); colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.141f, 0.141f, 0.141f, 0.70f); - colors[ImGuiCol_NavWindowingDimBg] = colors[ImGuiCol_NavHighlight]; - colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.2f, 0.2f, 0.2f, 0.65f); + colors[ImGuiCol_NavWindowingDimBg] = colors[ImGuiCol_NavHighlight]; + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.2f, 0.2f, 0.2f, 0.65f); - imStyle.WindowPadding = ImVec2(8.00f, 8.00f); - imStyle.FramePadding = ImVec2(5.00f, 2.00f); - imStyle.CellPadding = ImVec2(6.00f, 8.00f); - imStyle.ItemSpacing = ImVec2(6.00f, 6.00f); - imStyle.ItemInnerSpacing = ImVec2(6.00f, 6.00f); - imStyle.TouchExtraPadding = ImVec2(0.00f, 0.00f); - imStyle.IndentSpacing = 25; - imStyle.ScrollbarSize = 15; - imStyle.GrabMinSize = 10; - imStyle.WindowBorderSize = 0.6f; - imStyle.ChildBorderSize = 1; - imStyle.PopupBorderSize = 1; - imStyle.FrameBorderSize = 1; - imStyle.TabBorderSize = 1; - imStyle.WindowRounding = 7; - imStyle.ChildRounding = 4; - imStyle.FrameRounding = 3; - imStyle.PopupRounding = 4; - imStyle.ScrollbarRounding = 9; - imStyle.GrabRounding = 3; - imStyle.LogSliderDeadzone = 4; - imStyle.TabRounding = 4; + imStyle.WindowPadding = ImVec2(8.00f, 8.00f); + imStyle.FramePadding = ImVec2(5.00f, 2.00f); + imStyle.CellPadding = ImVec2(6.00f, 8.00f); + imStyle.ItemSpacing = ImVec2(6.00f, 6.00f); + imStyle.ItemInnerSpacing = ImVec2(6.00f, 6.00f); + imStyle.TouchExtraPadding = ImVec2(0.00f, 0.00f); + imStyle.IndentSpacing = 25; + imStyle.ScrollbarSize = 15; + imStyle.GrabMinSize = 10; + imStyle.WindowBorderSize = 0.6f; + imStyle.ChildBorderSize = 1; + imStyle.PopupBorderSize = 1; + imStyle.FrameBorderSize = 1; + imStyle.TabBorderSize = 1; + imStyle.WindowRounding = 7; + imStyle.ChildRounding = 4; + imStyle.FrameRounding = 3; + imStyle.PopupRounding = 4; + imStyle.ScrollbarRounding = 9; + imStyle.GrabRounding = 3; + imStyle.LogSliderDeadzone = 4; + imStyle.TabRounding = 4; imStyle.WindowMenuButtonPosition = ImGuiDir_None; } break; @@ -281,10 +311,11 @@ namespace SHADE imguiCommandPool = gfxSystem->GetDevice()->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true); imguiCommandBuffer = imguiCommandPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); - auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers(); + //auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers(); + auto const& renderers = gfxSystem->GetEditorViewport()->GetRenderers(); SHASSERT(!renderers.empty(), "No Renderers available") - auto renderGraph = renderers[0]->GetRenderGraph(); + auto renderGraph = renderers[SHGraphicsConstants::RenderGraphIndices::EDITOR]->GetRenderGraph(); auto renderPass = renderGraph->GetNode("ImGui Node")->GetRenderpass(); if(ImGui_ImplVulkan_Init(&initInfo, renderPass->GetVkRenderpass()) == false) @@ -309,6 +340,29 @@ namespace SHADE }); } + void SHEditor::PollPicking() + { + if (auto gfxSystem = SHSystemManager::GetSystem()) + { + auto viewportWindow = SHEditorWindowManager::GetEditorWindow(); + if (viewportWindow->isWindowHovered && !viewportWindow->transformGizmo.isManipulating && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) + { + EntityID pickedEID = gfxSystem->GetMousePickSystem()->GetPickedEntity(); + if(pickedEID == MAX_EID) + return; + if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl)) + { + if (const auto hierarchyPanel = SHEditorWindowManager::GetEditorWindow()) + { + hierarchyPanel->SetScrollTo(pickedEID); + } + selectedEntities.clear(); + } + selectedEntities.push_back(pickedEID); + } + } + } + void SHEditor::NewFrame() { SDL_Event event; @@ -319,6 +373,7 @@ namespace SHADE ImGui_ImplVulkan_NewFrame(); ImGui_ImplSDL2_NewFrame(); ImGui::NewFrame(); + ImGuizmo::BeginFrame(); } diff --git a/SHADE_Engine/src/Editor/SHEditor.hpp b/SHADE_Engine/src/Editor/SHEditor.hpp index d579a9b5..34405390 100644 --- a/SHADE_Engine/src/Editor/SHEditor.hpp +++ b/SHADE_Engine/src/Editor/SHEditor.hpp @@ -13,9 +13,11 @@ #include "ECS_Base/SHECSMacros.h" #include "ECS_Base/System/SHSystem.h" #include "ECS_Base/System/SHSystemRoutine.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include "EditorWindow/SHEditorWindow.h" #include "Tools/SHLogger.h" +#include "Gizmos/SHTransformGizmo.h" + //#==============================================================# //|| Library Includes || @@ -90,11 +92,11 @@ namespace SHADE return reinterpret_cast(editorWindows[GetEditorWindowID()].get()); } + static EditorWindowMap editorWindows; private: // Number of windows; used for Editor Window ID Generation static EditorWindowID windowCount; // Map of Editor Windows - static EditorWindowMap editorWindows; friend class SHEditor; }; @@ -110,10 +112,17 @@ namespace SHADE class SH_API EditorRoutine final : public SHSystemRoutine { public: - EditorRoutine() = default; + EditorRoutine():SHSystemRoutine("Editor routine", true) {}; void Execute(double dt) noexcept override final; }; + enum class State : uint8_t + { + PLAY, + PAUSE, + STOP + }; + /** * @brief Style options * @@ -162,9 +171,13 @@ namespace SHADE void SetSDLWindow(SDL_Window* inSDLWindow){sdlWindow = inSDLWindow;}; + void PollPicking(); + // List of selected entities std::vector selectedEntities; + State editorState = State::STOP; + private: /** * @brief Start new frame for editor @@ -177,7 +190,7 @@ namespace SHADE */ void Render(); - + void InitLayout() noexcept; void InitFonts() noexcept; @@ -186,6 +199,10 @@ namespace SHADE // Handle to command buffer used for ImGui Vulkan Backend Handle imguiCommandBuffer; - SDL_Window* sdlWindow; + SDL_Window* sdlWindow {nullptr}; + + ImGuiIO* io{nullptr}; + + //SHTransformGizmo transformGizmo; };//class SHEditor }//namespace SHADE diff --git a/SHADE_Engine/src/Editor/SHEditorUI.cpp b/SHADE_Engine/src/Editor/SHEditorUI.cpp index 65b65827..7107778d 100644 --- a/SHADE_Engine/src/Editor/SHEditorUI.cpp +++ b/SHADE_Engine/src/Editor/SHEditorUI.cpp @@ -67,6 +67,11 @@ namespace SHADE ImGui::Separator(); } + bool SHEditorUI::IsItemHovered() + { + return ImGui::IsItemHovered(); + } + bool SHEditorUI::BeginMenu(const std::string& label) { return ImGui::BeginMenu(label.data()); @@ -82,6 +87,16 @@ namespace SHADE ImGui::EndMenu(); } + void SHEditorUI::BeginTooltip() + { + ImGui::BeginTooltip(); + } + + void SHEditorUI::EndTooltip() + { + ImGui::EndTooltip(); + } + /*-----------------------------------------------------------------------------------*/ /* ImGui Wrapper Functions - Pop Ups */ /*-----------------------------------------------------------------------------------*/ @@ -135,24 +150,30 @@ namespace SHADE return ImGui::Selectable(std::format("{} {}", icon, label).data()); } - bool SHEditorUI::InputCheckbox(const std::string& label, bool& value) + bool SHEditorUI::InputCheckbox(const std::string& label, bool& value, bool* isHovered) { ImGui::Text(label.c_str()); + if (isHovered) + *isHovered = ImGui::IsItemHovered(); ImGui::SameLine(); return ImGui::Checkbox("#", &value); } - bool SHEditorUI::InputInt(const std::string& label, int& value) + bool SHEditorUI::InputInt(const std::string& label, int& value, bool* isHovered) { ImGui::Text(label.c_str()); + if (isHovered) + *isHovered = ImGui::IsItemHovered(); ImGui::SameLine(); return ImGui::InputInt("#", &value, 1, 10, ImGuiInputTextFlags_EnterReturnsTrue); } - bool SHEditorUI::InputUnsignedInt(const std::string& label, unsigned int& value) + bool SHEditorUI::InputUnsignedInt(const std::string& label, unsigned int& value, bool* isHovered) { int signedVal = static_cast(value); ImGui::Text(label.c_str()); + if (isHovered) + *isHovered = ImGui::IsItemHovered(); ImGui::SameLine(); const bool CHANGED = InputInt("#", signedVal); if (CHANGED) @@ -162,64 +183,101 @@ namespace SHADE } return CHANGED; } - bool SHEditorUI::InputFloat(const std::string& label, float& value) + bool SHEditorUI::InputFloat(const std::string& label, float& value, bool* isHovered) { ImGui::Text(label.c_str()); + if (isHovered) + *isHovered = ImGui::IsItemHovered(); ImGui::SameLine(); return ImGui::InputFloat("#", &value, 0.1f, 1.0f, "%.3f", ImGuiInputTextFlags_EnterReturnsTrue); } - bool SHEditorUI::InputDouble(const std::string& label, double& value) + bool SHEditorUI::InputDouble(const std::string& label, double& value, bool* isHovered) { ImGui::Text(label.c_str()); + if (isHovered) + *isHovered = ImGui::IsItemHovered(); ImGui::SameLine(); return ImGui::InputDouble("#", &value, 0.1, 1.0, "%.3f", ImGuiInputTextFlags_EnterReturnsTrue); } - bool SHEditorUI::InputAngle(const std::string& label, double& value) + bool SHEditorUI::InputAngle(const std::string& label, double& value, bool* isHovered) { ImGui::Text(label.c_str()); + if (isHovered) + *isHovered = ImGui::IsItemHovered(); 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) + bool SHEditorUI::InputSlider(const std::string& label, int min, int max, int& value, bool* isHovered /*= nullptr*/) { - 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; + ImGui::Text(label.c_str()); + if (isHovered) + *isHovered = ImGui::IsItemHovered(); + ImGui::SameLine(); + return ImGui::SliderInt("##", &value, + static_cast(min), static_cast(max), "%d", + ImGuiInputTextFlags_EnterReturnsTrue); } - bool SHEditorUI::InputVec2(const std::string& label, SHVec2& value) + bool SHEditorUI::InputSlider(const std::string& label, unsigned int min, unsigned int max, unsigned int& value, bool* isHovered /*= nullptr*/) + { + int val = static_cast(value); + const bool CHANGED = InputSlider(label, min, max, val, isHovered); + if (CHANGED) + { + value = static_cast(val); + } + + return CHANGED; + } + + bool SHEditorUI::InputSlider(const std::string& label, float min, float max, float& value, bool* isHovered) + { + ImGui::Text(label.c_str()); + if (isHovered) + *isHovered = ImGui::IsItemHovered(); + ImGui::SameLine(); + return ImGui::SliderFloat("##", &value, + static_cast(min), static_cast(max), "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + } + + bool SHEditorUI::InputSlider(const std::string& label, double min, double max, double& value, bool* isHovered /*= nullptr*/) + { + float val = static_cast(value); + const bool CHANGED = InputSlider(label, min, max, val, isHovered); + if (CHANGED) + { + value = static_cast(val); + } + + return CHANGED; + } + + bool SHEditorUI::InputVec2(const std::string& label, SHVec2& value, bool* isHovered) { static const std::vector COMPONENT_LABELS = { "X", "Y" }; - return SHEditorWidgets::DragN(label, COMPONENT_LABELS, { &value.x, &value.y }); + return SHEditorWidgets::DragN(label, COMPONENT_LABELS, { &value.x, &value.y }, 0.1f, "%.3f", float{}, float{}, 0, isHovered); } - bool SHEditorUI::InputVec3(const std::string& label, SHVec3& value, float speed) + bool SHEditorUI::InputVec3(const std::string& label, SHVec3& value, bool* isHovered, 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"); + return SHEditorWidgets::DragN(label, COMPONENT_LABELS, { &value.x, &value.y, &value.z }, speed, "%.3f", float{}, float{}, 0, isHovered); } - bool SHEditorUI::InputTextField(const std::string& label, std::string& value) + bool SHEditorUI::InputTextField(const std::string& label, std::string& value, bool* isHovered) { std::array buffer = { '\0' }; strcpy_s(buffer.data(), TEXT_FIELD_MAX_LENGTH, value.c_str()); ImGui::Text(label.c_str()); + if (isHovered) + *isHovered = ImGui::IsItemHovered(); ImGui::SameLine(); const bool CHANGED = ImGui::InputText("#", &buffer[0], TEXT_FIELD_MAX_LENGTH); if (CHANGED) @@ -229,13 +287,15 @@ namespace SHADE return CHANGED; } - bool SHEditorUI::InputEnumCombo(const std::string& label, int& v, const std::vector& enumNames) + bool SHEditorUI::InputEnumCombo(const std::string& label, int& v, const std::vector& enumNames, bool* isHovered) { // Clamp input value const std::string& INITIAL_NAME = v >= static_cast(enumNames.size()) ? "Unknown" : enumNames[v]; bool b = false; ImGui::Text(label.c_str()); + if (isHovered) + *isHovered = ImGui::IsItemHovered(); ImGui::SameLine(); if (ImGui::BeginCombo("#", INITIAL_NAME.c_str(), ImGuiComboFlags_None)) { diff --git a/SHADE_Engine/src/Editor/SHEditorUI.h b/SHADE_Engine/src/Editor/SHEditorUI.h index 13468215..f3051aa1 100644 --- a/SHADE_Engine/src/Editor/SHEditorUI.h +++ b/SHADE_Engine/src/Editor/SHEditorUI.h @@ -90,12 +90,19 @@ namespace SHADE static void SameLine(); static void Separator(); - /*-----------------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Queries */ + /*-----------------------------------------------------------------------------*/ + static bool IsItemHovered(); + + /*-----------------------------------------------------------------------------*/ /* ImGui Wrapper Functions - Menu */ /*-----------------------------------------------------------------------------*/ static bool BeginMenu(const std::string& label); static bool BeginMenu(const std::string& label, const char* icon); static void EndMenu(); + static void BeginTooltip(); + static void EndTooltip(); /*-----------------------------------------------------------------------------*/ /* ImGui Wrapper Functions - Pop Ups */ @@ -165,8 +172,9 @@ namespace SHADE /// /// Label used to identify this widget. /// Reference to the variable to store the result. + /// Label used to identify this widget. /// Reference to the variable to store the result. + /// Label used to identify this widget. /// Reference to the variable to store the result. + /// Label used to identify this widget. /// Reference to the variable to store the result. + /// Label used to identify this widget. /// Reference to the variable to store the result. + /// Label used to identify this widget. /// Reference to the variable to store the result. + /// Label used to identify this widget. /// Minimum value of the slider. /// Maximum value of the slider. /// Reference to the variable to store the result. + /// Label used to identify this widget. + /// Minimum value of the slider. + /// Maximum value of the slider. + /// Reference to the variable to store the result. + /// Label used to identify this widget. + /// Minimum value of the slider. + /// Maximum value of the slider. + /// Reference to the variable to store the result. + /// Label used to identify this widget. + /// Minimum value of the slider. + /// Maximum value of the slider. + /// Reference to the variable to store the result. + /// Label used to identify this widget. /// Reference to the variable to store the result. + /// Label used to identify this widget. /// Reference to the variable to store the result. + /// Label used to identify this widget. /// Reference to the variable to store the result. + /// /// Conversion function from the type of enum to C-style string. /// + /// The name of the input. /// The reference to the value to modify. /// Vector of names for each enumeration value. + /// SkipItems) @@ -174,6 +174,8 @@ namespace SHADE ImGui::BeginColumns("DragVecCol", 2, ImGuiOldColumnFlags_NoBorder | ImGuiOldColumnFlags_NoResize); ImGui::SetColumnWidth(-1, 80.0f); ImGui::Text(fieldLabel.c_str()); + if (isHovered) + *isHovered = ImGui::IsItemHovered(); ImGui::NextColumn(); for (std::size_t i = 0; i < N; ++i) { diff --git a/SHADE_Engine/src/Editor/SHImGuiHelpers.hpp b/SHADE_Engine/src/Editor/SHImGuiHelpers.hpp index 66eeb8c4..0c7c1ecf 100644 --- a/SHADE_Engine/src/Editor/SHImGuiHelpers.hpp +++ b/SHADE_Engine/src/Editor/SHImGuiHelpers.hpp @@ -15,7 +15,7 @@ //#==============================================================# #ifndef SH_IM_MATH #define IM_VEC2_CLASS_EXTRA \ - ImVec2(const SHADE::SHVec2& vec) {x = vec.x; y = vec.y;} \ + ImVec2(const SHADE::SHVec2& vec) {x = vec.x; y = vec.y;} \ operator SHADE::SHVec2() const {return SHADE::SHVec2(x,y);} #define IM_VEC3_CLASS_EXTRA \ ImVec3(const SHADE::SHVec3& vec) {x = vec.x; y = vec.y; z = vec.z;} \ @@ -43,6 +43,10 @@ namespace SHADE constexpr ImVec4 blue = {0.0f, 0.0f, 1.0f, 1.f}; constexpr ImVec4 white = {1.0f, 1.0f, 1.0f, 1.f}; + constexpr int colors_red = 0; + constexpr int colors_green = 1; + constexpr int colors_blue = 2; + constexpr int colors_white = 3; constexpr ImU32 colors[] = { 0xBB0000FF, // red 0xBB00FF00, // green diff --git a/SHADE_Engine/src/Events/SHEventDefines.h b/SHADE_Engine/src/Events/SHEventDefines.h index 317b67c1..fc9f41e1 100644 --- a/SHADE_Engine/src/Events/SHEventDefines.h +++ b/SHADE_Engine/src/Events/SHEventDefines.h @@ -5,8 +5,9 @@ typedef uint32_t SHEventIdentifier; typedef uint32_t SHEventHandle; //Add your event identifiers here: -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 }; +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 }; +constexpr SHEventIdentifier SH_SCENEGRAPH_CHANGE_PARENT_EVENT { 5 }; diff --git a/SHADE_Engine/src/FRC/SHFramerateController.h b/SHADE_Engine/src/FRC/SHFramerateController.h index b9637cf2..dbabbac5 100644 --- a/SHADE_Engine/src/FRC/SHFramerateController.h +++ b/SHADE_Engine/src/FRC/SHFramerateController.h @@ -14,7 +14,6 @@ #pragma once #include -#include "Tools/SHLogger.h" #include "SH_API.h" namespace SHADE diff --git a/SHADE_Engine/src/Graphics/Buffers/SHVkBuffer.h b/SHADE_Engine/src/Graphics/Buffers/SHVkBuffer.h index e931fec5..aeda7d18 100644 --- a/SHADE_Engine/src/Graphics/Buffers/SHVkBuffer.h +++ b/SHADE_Engine/src/Graphics/Buffers/SHVkBuffer.h @@ -3,7 +3,7 @@ #include "Graphics/SHVulkanIncludes.h" #include "vk_mem_alloc.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" namespace SHADE { diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp index 4501ba7b..a744c795 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp @@ -10,6 +10,7 @@ #include "Graphics/Buffers/SHVkBuffer.h" #include "Graphics/Images/SHVkImage.h" #include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/SHVkUtil.h" namespace SHADE @@ -299,7 +300,7 @@ namespace SHADE SHLOG_ERROR("Command buffer must have started recording before a pipeline can be bound. "); return; } - boundPipelineLayoutHdl = pipelineHdl->GetPipelineLayout(); + bindPointData[static_cast(pipelineHdl->GetPipelineType())].boundPipelineLayoutHdl = pipelineHdl->GetPipelineLayout(); vkCommandBuffer.bindPipeline(pipelineHdl->GetPipelineBindPoint(), pipelineHdl->GetVkPipeline()); } @@ -358,9 +359,10 @@ namespace SHADE } } - void SHVkCommandBuffer::BindDescriptorSet(Handle descSetGroup, vk::PipelineBindPoint bindPoint, uint32_t firstSet, std::span dynamicOffsets) + void SHVkCommandBuffer::BindDescriptorSet(Handle descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span dynamicOffsets) { - vkCommandBuffer.bindDescriptorSets(bindPoint, boundPipelineLayoutHdl->GetVkPipelineLayout(), firstSet, descSetGroup->GetVkHandle(), dynamicOffsets); + uint32_t bindPointIndex = static_cast(bindPoint); + vkCommandBuffer.bindDescriptorSets(SHVkUtil::GetPipelineBindPointFromType(bindPoint), bindPointData[bindPointIndex].boundPipelineLayoutHdl->GetVkPipelineLayout(), firstSet, descSetGroup->GetVkHandle(), dynamicOffsets); } /***************************************************************************/ @@ -452,6 +454,11 @@ namespace SHADE vkCommandBuffer.drawIndexedIndirect(indirectDrawData->GetVkBuffer(), 0, drawCount, sizeof(vk::DrawIndexedIndirectCommand)); } + void SHVkCommandBuffer::ComputeDispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept + { + vkCommandBuffer.dispatch (groupCountX, groupCountY, groupCountZ); + } + void SHVkCommandBuffer::CopyBufferToImage(const vk::Buffer& src, const vk::Image& dst, const std::vector& copyInfo) { vkCommandBuffer.copyBufferToImage @@ -500,9 +507,9 @@ namespace SHADE // //vkCommandBuffer.pipelineBarrier() //} - void SHVkCommandBuffer::ForceSetPipelineLayout(Handle pipelineLayout) noexcept + void SHVkCommandBuffer::ForceSetPipelineLayout(Handle pipelineLayout, SH_PIPELINE_TYPE pipelineType) noexcept { - boundPipelineLayoutHdl = pipelineLayout; + bindPointData[static_cast(pipelineType)].boundPipelineLayoutHdl = pipelineLayout; } /***************************************************************************/ @@ -513,12 +520,13 @@ namespace SHADE */ /***************************************************************************/ - void SHVkCommandBuffer::SubmitPushConstants(void) const noexcept + void SHVkCommandBuffer::SubmitPushConstants(SH_PIPELINE_TYPE bindPoint) const noexcept { - vkCommandBuffer.pushConstants(boundPipelineLayoutHdl->GetVkPipelineLayout(), - boundPipelineLayoutHdl->GetPushConstantInterface().GetShaderStageFlags(), + auto layoutHdl = bindPointData[static_cast(bindPoint)].boundPipelineLayoutHdl; + vkCommandBuffer.pushConstants(layoutHdl->GetVkPipelineLayout(), + layoutHdl->GetPushConstantInterface().GetShaderStageFlags(), 0, - boundPipelineLayoutHdl->GetPushConstantInterface().GetSize(), pushConstantData); + layoutHdl->GetPushConstantInterface().GetSize(), pushConstantData); } /***************************************************************************/ @@ -695,7 +703,7 @@ namespace SHADE , usageFlags{ rhs.usageFlags } , commandBufferCount{ rhs.commandBufferCount } , parentPool{ rhs.parentPool } - , boundPipelineLayoutHdl{ rhs.boundPipelineLayoutHdl } + , bindPointData{ std::move (rhs.bindPointData)} { memcpy(pushConstantData, rhs.pushConstantData, PUSH_CONSTANT_SIZE); @@ -728,7 +736,7 @@ namespace SHADE usageFlags = rhs.usageFlags; commandBufferCount = rhs.commandBufferCount; parentPool = rhs.parentPool; - boundPipelineLayoutHdl = rhs.boundPipelineLayoutHdl; + bindPointData = std::move(rhs.bindPointData); memcpy(pushConstantData, rhs.pushConstantData, PUSH_CONSTANT_SIZE); rhs.vkCommandBuffer = VK_NULL_HANDLE; diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h index 9416a1aa..4c978c34 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h @@ -4,8 +4,9 @@ #include "Graphics/SHVulkanIncludes.h" #include "Graphics/SHVulkanDefines.h" #include "SHCommandPoolResetMode.h" -#include "Resource/ResourceLibrary.h" +#include "Resource/SHResourceLibrary.h" #include "Graphics/Pipeline/SHVkPipelineLayout.h" +#include "Graphics/Pipeline/SHPipelineType.h" namespace SHADE { @@ -36,10 +37,17 @@ namespace SHADE class SHVkCommandBuffer { friend class SHVkCommandPool; - friend class ResourceLibrary; + friend class SHResourceLibrary; static constexpr uint16_t PUSH_CONSTANT_SIZE = 512; + private: + struct PipelineBindPointData + { + //! The currently bound pipeline + Handle boundPipelineLayoutHdl; + }; + /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ @@ -66,8 +74,8 @@ namespace SHADE //! The command pool that this command buffer belongs to Handle parentPool; - //! The currently bound pipeline - Handle boundPipelineLayoutHdl; + //! Every command buffer will have a set of pipeline bind point specific data + std::array(SH_PIPELINE_TYPE::NUM_TYPES)> bindPointData; //! The push constant data for the command buffer uint8_t pushConstantData[PUSH_CONSTANT_SIZE]; @@ -112,13 +120,16 @@ namespace SHADE void BindPipeline (Handle const& pipelineHdl) noexcept; void BindVertexBuffer (uint32_t bindingPoint, Handle const& buffer, vk::DeviceSize offset) noexcept; void BindIndexBuffer (Handle const& buffer, uint32_t startingIndex) const noexcept; - void BindDescriptorSet (Handle descSetGroup, vk::PipelineBindPoint bindPoint, uint32_t firstSet, std::span dynamicOffsets); + void BindDescriptorSet (Handle descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span dynamicOffsets); // Draw Commands void DrawArrays (uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept; void DrawIndexed (uint32_t indexCount, uint32_t firstIndex, uint32_t vertexOffset) const noexcept; void DrawMultiIndirect (Handle indirectDrawData, uint32_t drawCount); + // Compute Commands + void ComputeDispatch (uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept; + // Buffer Copy void CopyBufferToImage (const vk::Buffer& src, const vk::Image& dst, const std::vector& copyInfo); void CopyImageToBuffer (const vk::Image& src, const vk::Buffer& dst, const std::vector& copyInfo); @@ -138,13 +149,13 @@ namespace SHADE // Push Constant variable setting template - void SetPushConstantVariable(std::string variableName, T const& data) noexcept + void SetPushConstantVariable(std::string variableName, T const& data, SH_PIPELINE_TYPE bindPoint) noexcept { - memcpy (static_cast(pushConstantData) + boundPipelineLayoutHdl->GetPushConstantInterface().GetOffset(variableName), &data, sizeof (T)); + memcpy (static_cast(pushConstantData) + bindPointData[static_cast(bindPoint)].boundPipelineLayoutHdl->GetPushConstantInterface().GetOffset(variableName), &data, sizeof (T)); }; - void ForceSetPipelineLayout (Handle pipelineLayout) noexcept; + void ForceSetPipelineLayout (Handle pipelineLayout, SH_PIPELINE_TYPE pipelineType) noexcept; - void SubmitPushConstants (void) const noexcept; + void SubmitPushConstants (SH_PIPELINE_TYPE bindPoint) const noexcept; /*-----------------------------------------------------------------------*/ /* GETTERS AND SETTERS */ diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.cpp b/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.cpp index e1470898..375ece4d 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.cpp +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.cpp @@ -2,7 +2,7 @@ #include "SHVkCommandPool.h" #include "Graphics/Devices/SHVkLogicalDevice.h" #include "Graphics/Instance/SHVkInstance.h" -#include "Resource/ResourceLibrary.h" +#include "Resource/SHResourceLibrary.h" #include "Tools/SHLogger.h" namespace SHADE diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.h b/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.h index 2bb290a7..fcc0ce41 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.h +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.h @@ -6,7 +6,7 @@ #include "Graphics/Queues/SHVkQueue.h" #include "SHCommandPoolResetMode.h" #include "SHVkCommandBuffer.h" -#include "Resource/ResourceLibrary.h" +#include "Resource/SHResourceLibrary.h" namespace SHADE { diff --git a/SHADE_Engine/src/Graphics/Debugging/SHVulkanDebugUtil.cpp b/SHADE_Engine/src/Graphics/Debugging/SHVulkanDebugUtil.cpp index c8a1fe1a..fd39da24 100644 --- a/SHADE_Engine/src/Graphics/Debugging/SHVulkanDebugUtil.cpp +++ b/SHADE_Engine/src/Graphics/Debugging/SHVulkanDebugUtil.cpp @@ -99,7 +99,7 @@ namespace SHADE void SHVulkanDebugUtil::ReportVkSuccess(std::string_view message) noexcept { - SHLOGV_INFO(message); + //SHLOGV_INFO(message); } /***************************************************************************/ diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.cpp index 6b770c3d..e5618c9c 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.cpp +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.cpp @@ -25,7 +25,8 @@ namespace SHADE } SHVkDescriptorPool::SHVkDescriptorPool(SHVkDescriptorPool&& rhs) noexcept - : device{ rhs.device } + : ISelfHandle (rhs) + , device{ rhs.device } , pool{ rhs.pool } { rhs.pool = VK_NULL_HANDLE; diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h index 9a533d06..c822829a 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h @@ -2,7 +2,7 @@ // Project Includes #include "Graphics/SHVulkanIncludes.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" namespace SHADE { diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp index e842df47..de68c583 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp @@ -91,7 +91,7 @@ namespace SHADE // new write for the binding updater.writeInfos.emplace_back(); - updater.writeHashMap.try_emplace(writeHash, updater.writeInfos.size() - 1); + updater.writeHashMap.try_emplace(writeHash, static_cast(updater.writeInfos.size()) - 1u); auto& writeInfo = updater.writeInfos.back(); // Descriptor count for the write descriptor set. Usually this is set to 1, but if binding is variable sized, set to info passed in @@ -102,10 +102,10 @@ namespace SHADE //case vk::DescriptorType::eSampler: //case vk::DescriptorType::eSampledImage: case vk::DescriptorType::eCombinedImageSampler: + case vk::DescriptorType::eStorageImage: + case vk::DescriptorType::eInputAttachment: writeInfo.descImageInfos.resize(descriptorCount); - break; - //case vk::DescriptorType::eStorageImage: - // break; + break; case vk::DescriptorType::eUniformTexelBuffer: case vk::DescriptorType::eStorageTexelBuffer: case vk::DescriptorType::eUniformBuffer: @@ -165,6 +165,7 @@ namespace SHADE if (imageViewsAndSamplers.size() > writeInfo.descImageInfos.size()) { SHLOG_ERROR("Attempting write too many descriptors into descriptor set. Failed to write to vk::WriteDescriptorSet. "); + return; } for (uint32_t i = 0; i < imageViewsAndSamplers.size(); ++i) @@ -172,7 +173,7 @@ namespace SHADE // write sampler and image view auto& [view, sampler, layout] = imageViewsAndSamplers[i]; writeInfo.descImageInfos[i].imageView = view->GetImageView(); - writeInfo.descImageInfos[i].sampler = sampler->GetVkSampler(); + writeInfo.descImageInfos[i].sampler = sampler ? sampler->GetVkSampler() : nullptr; writeInfo.descImageInfos[i].imageLayout = layout; } } diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h index f2b886e8..3f42afcc 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h @@ -4,7 +4,7 @@ // Project Includes #include "Graphics/SHVulkanIncludes.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include "Graphics/Shaders/SHShaderReflected.h" #include "SHDescriptorSetUpdater.h" @@ -31,6 +31,8 @@ namespace SHADE class SHVkDescriptorSetGroup { public: + using viewSamplerLayout = std::tuple, Handle, vk::ImageLayout>; + /*-----------------------------------------------------------------------------*/ /* Constructor/Destructors */ /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetLayout.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetLayout.cpp index 002aa29d..0943c489 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetLayout.cpp +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetLayout.cpp @@ -1,16 +1,18 @@ #include "SHPch.h" #include "SHVkDescriptorSetLayout.h" #include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Graphics/Images/SHVkSampler.h" namespace SHADE { /*---------------------------------------------------------------------------------*/ /* Constructor/Destructor */ /*---------------------------------------------------------------------------------*/ - SHVkDescriptorSetLayout::SHVkDescriptorSetLayout(Handle device, SetIndex set, const std::vector& bindings) + SHVkDescriptorSetLayout::SHVkDescriptorSetLayout(Handle device, SetIndex set, const std::vector& bindings, bool genImmutableSamplers/* = false*/) : device { device } , layoutDesc { bindings } , setIndex {set} + , immutableSampler{} { // Check if auto-binding point calculation configuration is valid bool autoCalc = false; @@ -26,6 +28,25 @@ namespace SHADE } } + vk::Sampler tempVkSampler = nullptr; + if (genImmutableSamplers) + { + // Create sampler + immutableSampler = device->CreateSampler( + { + .minFilter = vk::Filter::eLinear, + .magFilter = vk::Filter::eLinear, + .addressMode = vk::SamplerAddressMode::eRepeat, + .mipmapMode = vk::SamplerMipmapMode::eLinear, + .minLod = -1000, + .maxLod = 1000 + } + ); + + tempVkSampler = immutableSampler->GetVkSampler(); + } + + // Fill up VK bindings with auto calculated bind points if needed std::vector layoutBindings; layoutBindings.reserve(bindings.size()); @@ -39,7 +60,7 @@ namespace SHADE .descriptorType = binding.Type, .descriptorCount = binding.DescriptorCount, .stageFlags = binding.Stage, - .pImmutableSamplers = nullptr // We will create our own samplers + .pImmutableSamplers = genImmutableSamplers ? &tempVkSampler : nullptr, }; layoutBindings.emplace_back(VK_BINDING); @@ -75,7 +96,8 @@ namespace SHADE : device {rhs.device} , setLayout {rhs.setLayout} , layoutDesc{std::move (rhs.layoutDesc)} - , setIndex {rhs.setIndex} + , setIndex{ rhs.setIndex } + , immutableSampler{ rhs.immutableSampler } { rhs.setLayout = VK_NULL_HANDLE; } @@ -106,6 +128,7 @@ namespace SHADE setLayout = rhs.setLayout; layoutDesc = std::move(rhs.layoutDesc); setIndex = rhs.setIndex; + immutableSampler = rhs.immutableSampler; rhs.setLayout = VK_NULL_HANDLE; diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetLayout.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetLayout.h index 9b436026..1639901d 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetLayout.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetLayout.h @@ -2,7 +2,7 @@ // Project Includes #include "Graphics/SHVulkanIncludes.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" namespace SHADE { @@ -10,6 +10,7 @@ namespace SHADE /* Forward Declarations */ /*---------------------------------------------------------------------------------*/ class SHVkLogicalDevice; + class SHVkSampler; /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -74,7 +75,7 @@ namespace SHADE /// /// /// - SHVkDescriptorSetLayout(Handle device, SetIndex setIndex, const std::vector& bindings); + SHVkDescriptorSetLayout(Handle device, SetIndex setIndex, const std::vector& bindings, bool genImmutableSamplers = false); SHVkDescriptorSetLayout(const SHVkDescriptorSetLayout&) = delete; SHVkDescriptorSetLayout(SHVkDescriptorSetLayout&& rhs) noexcept; /// @@ -107,5 +108,6 @@ namespace SHADE vk::DescriptorSetLayout setLayout; std::vector layoutDesc; // Stores description of the layout SetIndex setIndex; // Index of the set + Handle immutableSampler; }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp index 4f4f94a4..a6b415a9 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp @@ -233,6 +233,8 @@ namespace SHADE , vmaAllocator{rhs.vmaAllocator} , nonDedicatedBestIndex {0} , parentPhysicalDeviceHdl {rhs.parentPhysicalDeviceHdl} + , uboBufferMemoryAlignment{ 0 } + , ssboBufferMemoryAlignment{ 0 } { rhs.vkLogicalDevice = VK_NULL_HANDLE; } @@ -261,6 +263,8 @@ namespace SHADE vmaAllocator = rhs.vmaAllocator; nonDedicatedBestIndex = 0; parentPhysicalDeviceHdl = rhs.parentPhysicalDeviceHdl; + uboBufferMemoryAlignment = rhs.uboBufferMemoryAlignment; + ssboBufferMemoryAlignment = rhs.ssboBufferMemoryAlignment; rhs.vkLogicalDevice = VK_NULL_HANDLE; @@ -529,6 +533,11 @@ namespace SHADE } + Handle SHVkLogicalDevice::CreateComputePipeline(Handle const& pipelineLayoutHdl) noexcept + { + return SHVkInstance::GetResourceManager().Create (GetHandle(), pipelineLayoutHdl); + } + Handle SHVkLogicalDevice::CreateSampler(const SHVkSamplerParams& params) noexcept { return SHVkInstance::GetResourceManager().Create (GetHandle(), params); @@ -550,10 +559,9 @@ namespace SHADE } - Handle SHVkLogicalDevice::CreateDescriptorSetLayout(SetIndex setIndex, std::vector const& bindings) noexcept + Handle SHVkLogicalDevice::CreateDescriptorSetLayout(SetIndex setIndex, std::vector const& bindings, bool genImmutableSamplers/* = false*/) noexcept { - return SHVkInstance::GetResourceManager().Create (GetHandle(), setIndex, bindings); - + return SHVkInstance::GetResourceManager().Create (GetHandle(), setIndex, bindings, genImmutableSamplers); } Handle SHVkLogicalDevice::CreateDescriptorPools(const SHVkDescriptorPool::Config& config /*= {}*/) noexcept diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h index 5c400e02..2aa59941 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h @@ -8,8 +8,8 @@ #include "Graphics/SHVulkanIncludes.h" #include "Graphics/Devices/SHVkPhysicalDevice.h" #include "Graphics/Queues/SHVkQueue.h" -#include "Resource/Handle.h" -#include "Resource/ResourceLibrary.h" +#include "Resource/SHHandle.h" +#include "Resource/SHResourceLibrary.h" #include "Graphics/Swapchain/SHSwapchainParams.h" #include "Graphics/Commands/SHCommandPoolResetMode.h" #include "Graphics/Commands/SHVkCommandPool.h" @@ -175,18 +175,23 @@ namespace SHADE std::string const& shaderName ) noexcept; - Handle CreateGraphicsPipeline ( + Handle CreateGraphicsPipeline ( Handle const& pipelineLayoutHdl, SHVkPipelineState const* const state, Handle const& renderpassHdl, Handle subpass ) noexcept; + + Handle CreateComputePipeline ( + Handle const& pipelineLayoutHdl + ) 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; Handle CreateFramebuffer (Handle const& renderpassHdl, std::vector> const& attachments, uint32_t inWidth, uint32_t inHeight) noexcept; - Handle CreateDescriptorSetLayout (SetIndex setIndex, std::vector const& bindings) noexcept; + Handle CreateDescriptorSetLayout (SetIndex setIndex, std::vector const& bindings, bool genImmutableSamplers = false) noexcept; Handle CreateDescriptorPools (const SHVkDescriptorPool::Config& config = {}) noexcept; Handle CreateDescriptorSetGroup(Handle pool, std::vector> const& layouts, diff --git a/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.h b/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.h index 47bfcf99..4a02408c 100644 --- a/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.h +++ b/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.h @@ -2,7 +2,7 @@ #define SH_VK_FRAMEBUFFER_H #include "Graphics/SHVulkanIncludes.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include namespace SHADE diff --git a/SHADE_Engine/src/Graphics/Images/SHVkImage.h b/SHADE_Engine/src/Graphics/Images/SHVkImage.h index 51b71b26..4fb16017 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkImage.h +++ b/SHADE_Engine/src/Graphics/Images/SHVkImage.h @@ -3,7 +3,7 @@ #include "SHImageViewDetails.h" #include "Graphics/SHVulkanDefines.h" -#include "Resource/ResourceLibrary.h" +#include "Resource/SHResourceLibrary.h" #include "vk_mem_alloc.h" namespace SHADE diff --git a/SHADE_Engine/src/Graphics/Images/SHVkImageView.h b/SHADE_Engine/src/Graphics/Images/SHVkImageView.h index ae23d7a7..79bb5dca 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkImageView.h +++ b/SHADE_Engine/src/Graphics/Images/SHVkImageView.h @@ -2,7 +2,7 @@ #define SH_VK_IMAGE_VIEW_H #include "Graphics/SHVulkanIncludes.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include "SHImageViewDetails.h" namespace SHADE diff --git a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp index 30bcde79..4300f2bd 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp +++ b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp @@ -24,14 +24,15 @@ namespace SHADE { 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 + .magFilter = params.magFilter, + .minFilter = params.minFilter, + .mipmapMode = params.mipmapMode, + .addressModeU = params.addressMode, + .addressModeV = params.addressMode, + .addressModeW = params.addressMode, + .maxAnisotropy = 1.0f, + .minLod = params.minLod, + .maxLod = params.maxLod, }; // Create the sampler diff --git a/SHADE_Engine/src/Graphics/Images/SHVkSampler.h b/SHADE_Engine/src/Graphics/Images/SHVkSampler.h index bb878a69..3a989553 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkSampler.h +++ b/SHADE_Engine/src/Graphics/Images/SHVkSampler.h @@ -15,7 +15,7 @@ of DigiPen Institute of Technology is prohibited. #include // Project Includes #include "Graphics/SHVulkanIncludes.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" namespace SHADE { diff --git a/SHADE_Engine/src/Graphics/Instance/SHVkInstance.cpp b/SHADE_Engine/src/Graphics/Instance/SHVkInstance.cpp index 6688f9a6..191bc563 100644 --- a/SHADE_Engine/src/Graphics/Instance/SHVkInstance.cpp +++ b/SHADE_Engine/src/Graphics/Instance/SHVkInstance.cpp @@ -15,7 +15,7 @@ namespace SHADE bool SHVkInstance::validationLayersOn; vk::Instance SHVkInstance::vkInstance; SHVkDebugMessenger SHVkInstance::debugMessenger; - ResourceManager SHVkInstance::resourceManager; + SHResourceHub SHVkInstance::resourceManager; /***************************************************************************/ /*! @@ -258,7 +258,7 @@ namespace SHADE return vkInstance; } - ResourceManager& SHVkInstance::GetResourceManager(void) noexcept + SHResourceHub& SHVkInstance::GetResourceManager(void) noexcept { return resourceManager; } diff --git a/SHADE_Engine/src/Graphics/Instance/SHVkInstance.h b/SHADE_Engine/src/Graphics/Instance/SHVkInstance.h index a6fb4f0f..55adc774 100644 --- a/SHADE_Engine/src/Graphics/Instance/SHVkInstance.h +++ b/SHADE_Engine/src/Graphics/Instance/SHVkInstance.h @@ -18,7 +18,7 @@ written consent of DigiPen Institute of Technology is prohibited. #include "Graphics/Debugging/SHVkDebugMessenger.h" #include "Graphics/Devices/SHVkPhysicalDevice.h" #include "Graphics/Devices/SHVkLogicalDevice.h" -#include "Resource/ResourceLibrary.h" +#include "Resource/SHResourceLibrary.h" namespace SHADE @@ -61,7 +61,7 @@ namespace SHADE static SHVkDebugMessenger debugMessenger; //! Resource management for vulkan project - static ResourceManager resourceManager; + static SHResourceHub resourceManager; /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER FUNCTIONS */ @@ -85,7 +85,7 @@ namespace SHADE /* Getters and Setters */ /*-----------------------------------------------------------------------*/ static vk::Instance const& GetVkInstance (void) noexcept; - static ResourceManager& GetResourceManager(void) noexcept; + static SHResourceHub& GetResourceManager(void) noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp index 2705b4d1..40826047 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp @@ -369,7 +369,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ void SHBatch::Draw(Handle cmdBuffer, uint32_t frameIndex) { - if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) + if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) { SHLOG_WARNING("[SHBatch] Attempted to draw a batch with an invalid frame index."); return; @@ -385,7 +385,7 @@ namespace SHADE cmdBuffer->BindDescriptorSet ( matPropsDescSet[frameIndex], - vk::PipelineBindPoint::eGraphics, + SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, dynamicOffset ); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h index 37c57396..193fff0d 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h @@ -18,7 +18,7 @@ of DigiPen Institute of Technology is prohibited. // External Dependencies #include "Graphics/SHVulkanIncludes.h" // Project Includes -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include "Graphics/MiddleEnd/Interface/SHMaterial.h" #include "Math/SHMatrix.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h index 8074899d..f299906c 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h @@ -15,7 +15,7 @@ of DigiPen Institute of Technology is prohibited. // STL Includes #include // Project Includes -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" namespace SHADE { diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp index add51196..14f2aa76 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp @@ -20,91 +20,91 @@ of DigiPen Institute of Technology is prohibited. namespace SHADE { - /*---------------------------------------------------------------------------------*/ - /* Constructor/Destructors */ - /*---------------------------------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + /* Constructor/Destructors */ + /*---------------------------------------------------------------------------------*/ - SHSuperBatch::SHSuperBatch(Handle sp) - : subpass { sp } - {} + SHSuperBatch::SHSuperBatch(Handle sp) + : subpass{ sp } + {} - /*---------------------------------------------------------------------------------*/ - /* Usage Functions */ - /*---------------------------------------------------------------------------------*/ - void SHSuperBatch::Add(const SHRenderable* renderable) noexcept + /*---------------------------------------------------------------------------------*/ + /* Usage Functions */ + /*---------------------------------------------------------------------------------*/ + void SHSuperBatch::Add(const SHRenderable* renderable) noexcept + { + const Handle PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline(); + + // Check if we have a batch with the same pipeline first + auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch) + { + return batch.GetPipeline() == PIPELINE; + }); + + + // Create one if not found + if (batch == batches.end()) { - const Handle PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline(); - - // Check if we have a batch with the same pipeline first - auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch) - { - return batch.GetPipeline() == PIPELINE; - }); - - - // Create one if not found - if (batch == batches.end()) - { - batches.emplace_back(PIPELINE); - batch = batches.end() - 1; - } - - // Add renderable in - batch->Add(renderable); + batches.emplace_back(PIPELINE); + batch = batches.end() - 1; } - void SHSuperBatch::Remove(const SHRenderable* renderable) noexcept + // Add renderable in + batch->Add(renderable); + } + + void SHSuperBatch::Remove(const SHRenderable* renderable) noexcept + { + const Handle PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline(); + + // Check if we have a Batch with the same pipeline yet + auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch) + { + return batch.GetPipeline() == PIPELINE; + }); + + // Attempt to remove if it exists + if (batch == batches.end()) + return; + + batch->Remove(renderable); + } + + void SHSuperBatch::Clear() noexcept + { + for (auto& batch : batches) { - const Handle PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline(); - - // Check if we have a Batch with the same pipeline yet - auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch) - { - return batch.GetPipeline() == PIPELINE; - }); - - // Attempt to remove if it exists - if (batch == batches.end()) - return; - - batch->Remove(renderable); + batch.Clear(); } + batches.clear(); + } - void SHSuperBatch::Clear() noexcept + void SHSuperBatch::UpdateBuffers(uint32_t frameIndex, Handle descPool) + { + for (auto& batch : batches) { - for (auto& batch : batches) - { - batch.Clear(); - } - batches.clear(); + batch.UpdateMaterialBuffer(frameIndex, descPool); + batch.UpdateTransformBuffer(frameIndex); + batch.UpdateEIDBuffer(frameIndex); } + } - void SHSuperBatch::UpdateBuffers(uint32_t frameIndex, Handle descPool) + void SHSuperBatch::Build(Handle device, Handle descPool, uint32_t frameIndex) noexcept + { + // Build all batches + for (auto& batch : batches) { - for (auto& batch : batches) - { - batch.UpdateMaterialBuffer(frameIndex, descPool); - batch.UpdateTransformBuffer(frameIndex); - batch.UpdateEIDBuffer(frameIndex); - } + batch.Build(device, descPool, frameIndex); } + } - void SHSuperBatch::Build(Handle device, Handle descPool, uint32_t frameIndex) noexcept + void SHSuperBatch::Draw(Handle cmdBuffer, uint32_t frameIndex) noexcept + { + // Build all batches + for (auto& batch : batches) { - // Build all batches - for (auto& batch : batches) - { - batch.Build(device, descPool, frameIndex); - } - } - - void SHSuperBatch::Draw(Handle cmdBuffer, uint32_t frameIndex) noexcept - { - // Build all batches - for (auto& batch : batches) - { - batch.Draw(cmdBuffer, frameIndex); - } + batch.Draw(cmdBuffer, frameIndex); } + } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h index 9743e7dc..9877e04e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h @@ -15,7 +15,7 @@ of DigiPen Institute of Technology is prohibited. // External Dependencies #include "Graphics/SHVulkanIncludes.h" // Project Includes -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include "SHBatch.h" #include "Graphics/Pipeline/SHVkPipeline.h" diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.cpp index 2abdfa86..194febbf 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.cpp @@ -97,14 +97,16 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - SHMatrix SHCamera::GetViewMatrix() const + SHMatrix SHCamera::GetViewMatrix() { - return viewMatrix; + updateMatrices(); + return viewMatrix; } - SHMatrix SHCamera::GetProjectionMatrix() const + SHMatrix SHCamera::GetProjectionMatrix() { - return projMatrix; + updateMatrices(); + return projMatrix; } SHMatrix SHCamera::GetViewProjectionMatrix() { diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.h index 3a945109..b23614aa 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.h @@ -3,11 +3,11 @@ \author Tng Kah Wei, kahwei.tng, 390009620 \par email: kahwei.tng\@digipen.edu \date Aug 21, 2022 -\brief +\brief + - Copyright (C) 2022 DigiPen Institute of Technology. -Reproduction or disclosure of this file or its contents without the prior written consent +Reproduction or disclosure of this file or its contents without the prior written consent of DigiPen Institute of Technology is prohibited. *//*************************************************************************************/ #pragma once @@ -17,64 +17,66 @@ of DigiPen Institute of Technology is prohibited. namespace SHADE { - /***********************************************************************************/ - /*! - \brief - Object that manages the view and projection transformations for rendering - a 3D scene. - */ - /***********************************************************************************/ - class SHCamera - { - public: - /*-----------------------------------------------------------------------------*/ - /* Constructor/Destructors */ - /*-----------------------------------------------------------------------------*/ - /*-----------------------------------------------------------------------------*/ - /* View Set Functions */ - /*-----------------------------------------------------------------------------*/ - void SetLookAt(const SHVec3& pos, const SHVec3& target, const SHVec3& up); + /***********************************************************************************/ + /*! + \brief + Object that manages the view and projection transformations for rendering + a 3D scene. + */ + /***********************************************************************************/ + class SHCamera + { + public: + /*-----------------------------------------------------------------------------*/ + /* Constructor/Destructors */ + /*-----------------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------------*/ + /* View Set Functions */ + /*-----------------------------------------------------------------------------*/ + void SetLookAt(const SHVec3& pos, const SHVec3& target, const SHVec3& up); - /*-----------------------------------------------------------------------------*/ - /* Projection Set Functions */ - /*-----------------------------------------------------------------------------*/ - void SetPerspective(float fov, float width, float height, float zNear, float zFar); - void SetOrthographic(float width, float height, float zNear, float zFar); + /*-----------------------------------------------------------------------------*/ + /* Projection Set Functions */ + /*-----------------------------------------------------------------------------*/ + void SetPerspective(float fov, float width, float height, float zNear, float zFar); + void SetOrthographic(float width, float height, float zNear, float zFar); + + //void SetPerspectiveMatrixExplicit ( - /*-----------------------------------------------------------------------------*/ - /* Getter Functions */ - /*-----------------------------------------------------------------------------*/ - SHMatrix GetViewMatrix() const; - SHMatrix GetProjectionMatrix() const; - SHMatrix GetViewProjectionMatrix(); - SHMatrix GetInverseViewMatrix() const; - SHMatrix GetInverseProjectionMatrix() const; - SHMatrix GetInverseViewProjectionMatrix(); + /*-----------------------------------------------------------------------------*/ + /* Getter Functions */ + /*-----------------------------------------------------------------------------*/ + SHMatrix GetViewMatrix(); + SHMatrix GetProjectionMatrix(); + SHMatrix GetViewProjectionMatrix(); + SHMatrix GetInverseViewMatrix() const; + SHMatrix GetInverseProjectionMatrix() const; + SHMatrix GetInverseViewProjectionMatrix(); - /*-----------------------------------------------------------------------------*/ - /* Mapping Functions */ - /*-----------------------------------------------------------------------------*/ - SHVec3 ScreenToWorld(const SHVec3& vec) const; - SHVec3 WorldToScreen(const SHVec3& vec) const; - SHVec3 CameraToWorld(const SHVec3& vec) const; - SHVec3 WorldToCamera(const SHVec3& vec) const; + /*-----------------------------------------------------------------------------*/ + /* Mapping Functions */ + /*-----------------------------------------------------------------------------*/ + SHVec3 ScreenToWorld(const SHVec3& vec) const; + SHVec3 WorldToScreen(const SHVec3& vec) const; + SHVec3 CameraToWorld(const SHVec3& vec) const; + SHVec3 WorldToCamera(const SHVec3& vec) const; - private: - /*-----------------------------------------------------------------------------*/ - /* Data Members */ - /*-----------------------------------------------------------------------------*/ - SHMatrix viewMatrix; - SHMatrix projMatrix; - SHMatrix vpMatrix; - SHMatrix inverseViewMatrix; - SHMatrix inverseProjMatrix; - SHMatrix inverseVpMatrix; - bool isDirty = true; + private: + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + SHMatrix viewMatrix; + SHMatrix projMatrix; + SHMatrix vpMatrix; + SHMatrix inverseViewMatrix; + SHMatrix inverseProjMatrix; + SHMatrix inverseVpMatrix; + bool isDirty = true; - /*-----------------------------------------------------------------------------*/ - /* Helper Functions */ - /*-----------------------------------------------------------------------------*/ - void updateMatrices(); - static SHVec3 multiplyHomogenous(const SHMatrix& mat, const SHVec3& vec); - }; + /*-----------------------------------------------------------------------------*/ + /* Helper Functions */ + /*-----------------------------------------------------------------------------*/ + void updateMatrices(); + static SHVec3 multiplyHomogenous(const SHMatrix& mat, const SHVec3& vec); + }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h index ac2f1f8c..a0457b65 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h @@ -25,6 +25,12 @@ namespace SHADE struct SHGraphicsConstants { public: + struct RenderGraphIndices + { + static constexpr uint32_t WORLD = 0; + static constexpr uint32_t EDITOR = 0; + }; + struct DescriptorSetIndex { /***************************************************************************/ @@ -57,6 +63,14 @@ namespace SHADE */ /***************************************************************************/ static constexpr uint32_t PER_INSTANCE = 3; + /***************************************************************************/ + /*! + \brief + DescriptorSet Index for render graph resources. + */ + /***************************************************************************/ + static constexpr uint32_t RENDERGRAPH_RESOURCE = 4; + }; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index cd99648c..7ecd92d2 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -16,6 +16,9 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/Instance/SHVkInstance.h" #include "Graphics/Windowing/Surface/SHVkSurface.h" #include "Graphics/Swapchain/SHVkSwapchain.h" +#include "Camera/SHCameraSystem.h" +#include "Editor/SHEditor.hpp" +#include "ECS_Base/Managers/SHSystemManager.h" //#include "SHRenderer.h" #include "Graphics/Windowing/SHWindow.h" #include "Graphics/MiddleEnd/PerFrame/SHPerFrameData.h" @@ -36,11 +39,9 @@ of DigiPen Institute of Technology is prohibited. namespace SHADE { +#pragma region INIT_EXIT - /*---------------------------------------------------------------------------------*/ - /* Constructor/Destructors */ - /*---------------------------------------------------------------------------------*/ - void SHGraphicsSystem::Init(void) + void SHGraphicsSystem::InitBoilerplate(void) noexcept { /*-----------------------------------------------------------------------*/ /* BACKEND BOILERPLATE */ @@ -51,7 +52,7 @@ namespace SHADE // Get Physical Device and Construct Logical Device physicalDevice = SHVkInstance::CreatePhysicalDevice(SH_PHYSICAL_DEVICE_TYPE::BEST); device = SHVkInstance::CreateLogicalDevice({ SHQueueParams(SH_Q_FAM::GRAPHICS, SH_QUEUE_SELECT::DEDICATED), SHQueueParams(SH_Q_FAM::TRANSFER, SH_QUEUE_SELECT::DEDICATED) }, physicalDevice); - + // Construct surface surface = device->CreateSurface(window->GetHWND()); @@ -71,7 +72,15 @@ namespace SHADE if (width == 0 || height == 0) return; - renderContext.SetIsResized(true); +#ifdef SHEDITOR + + //PrepareResize(1, 1, SHVec2(0, 0)); + +#else + + PrepareResize(resizeWidth, resizeHeight, SHVec2(0, 0)); + +#endif }); window->RegisterWindowCloseCallback([&](void) @@ -108,9 +117,27 @@ namespace SHADE graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); + // TODO: This is VERY temporarily here until a more solid resource management system is implemented + shaderSourceLibrary.Init("../../TempShaderFolder/"); + shaderSourceLibrary.LoadShader(0, "TestCubeVs.glsl", SH_SHADER_TYPE::VERTEX, true); + shaderSourceLibrary.LoadShader(1, "TestCubeFs.glsl", SH_SHADER_TYPE::FRAGMENT, true); + + shaderSourceLibrary.LoadShader(2, "KirschCs.glsl", SH_SHADER_TYPE::COMPUTE, true); + + shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary); + auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl"); + auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl"); + auto greyscale = shaderModuleLibrary.GetShaderModule("KirschCs.glsl"); + cubeVS->Reflect(); + cubeFS->Reflect(); + greyscale->Reflect(); + } + + void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept + { /*-----------------------------------------------------------------------*/ - /* MIDDLE END SETUP + /* MIDDLE END SETUP - Viewports - Renderer - Render graph in renderers @@ -118,8 +145,9 @@ namespace SHADE - Default vertex input state - Global data /*-----------------------------------------------------------------------*/ + auto windowDims = window->GetWindowSize(); - SHGraphicsGlobalData::Init(device); + auto cameraSystem = SHSystemManager::GetSystem(); // Set Up Cameras screenCamera = resourceManager.Create(); @@ -131,12 +159,12 @@ namespace SHADE 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)); - + worldViewport = 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 worldRenderGraph = resourceManager.Create(); - - std::vector> renderContextCmdPools{swapchain->GetNumImages()}; + + std::vector> renderContextCmdPools{ swapchain->GetNumImages() }; for (uint32_t i = 0; i < renderContextCmdPools.size(); ++i) { renderContextCmdPools[i] = renderContext.GetFrameData(i).cmdPoolHdls[0]; @@ -144,71 +172,64 @@ namespace SHADE // Initialize world render graph worldRenderGraph->Init(device, swapchain); - worldRenderGraph->AddResource("Present", {SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT}, windowDims.first, windowDims.second); - worldRenderGraph->AddResource("Scene", {SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT}, windowDims.first, windowDims.second); - worldRenderGraph->AddResource("Depth Buffer", {SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL}, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); - worldRenderGraph->AddResource("Entity ID", {SH_ATT_DESC_TYPE_FLAGS::COLOR}, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); + worldRenderGraph->AddResource("Scene Pre-Process", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second); + worldRenderGraph->AddResource("Scene", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second); + worldRenderGraph->AddResource("Depth Buffer", { SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint); + worldRenderGraph->AddResource("Entity ID", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc); - //worldRenderGraph->AddResource("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); - auto node = worldRenderGraph->AddNode("G-Buffer", { "Entity ID", "Depth Buffer", "Scene"}, {}); // no predecessors + auto node = worldRenderGraph->AddNode("G-Buffer", { "Entity ID", "Depth Buffer", "Scene", "Scene Pre-Process"}, {}); // no predecessors //First subpass to write to G-Buffer auto gBufferWriteSubpass = node->AddSubpass("G-Buffer Write"); - gBufferWriteSubpass->AddColorOutput("Scene"); + gBufferWriteSubpass->AddColorOutput("Scene Pre-Process"); gBufferWriteSubpass->AddColorOutput("Entity ID"); - gBufferWriteSubpass->AddDepthOutput ("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL); + gBufferWriteSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL); - // We do this to just transition our scene layout to shader read - auto sceneLayoutTransitionSubpass = node->AddSubpass("Scene Layout Transition"); - sceneLayoutTransitionSubpass->AddInput("Scene"); + auto greyscale = shaderModuleLibrary.GetShaderModule("KirschCs.glsl"); + node->AddNodeCompute (greyscale, {"Scene Pre-Process", "Scene"}); + + // Generate world render graph + worldRenderGraph->Generate(); + + // Add world renderer to default viewport + worldRenderer = worldViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph); + worldRenderer->SetCamera(worldCamera); + + worldRenderer->SetCameraDirector(cameraSystem->CreateDirector()); + + auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl"); + auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl"); + + defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferWriteSubpass); + + } + + void SHGraphicsSystem::InitMiddleEnd(void) noexcept + { + SHGraphicsGlobalData::Init(device); + + InitSceneRenderGraph(); #ifdef SHEDITOR - auto imguiNode = worldRenderGraph->AddNode("ImGui Node", { "Present" }, {"G-Buffer"}); - auto imguiSubpass = imguiNode->AddSubpass("ImGui Draw"); - imguiSubpass->AddColorOutput("Present"); + InitEditorRenderGraph(); #endif - worldRenderGraph->Generate(); - // Create Semaphore for (auto& semaHandle : graphSemaphores) { semaHandle = device->CreateSemaphore(); } + } - // Create Debug Renderers - /*debugScreenRenderer = defaultViewport->AddRenderer(resourceManager, worldRenderGraph); - debugScreenRenderer->SetCamera(screenCamera); - debugWorldRenderer = defaultViewport->AddRenderer(resourceManager, worldRenderGraph); - debugWorldRenderer->SetCamera(worldCamera);*/ - - // Add world renderer to default viewport - worldRenderer = defaultViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph); - worldRenderer->SetCamera(worldCamera); - - // TODO: This is VERY temporarily here until a more solid resource management system is implemented - shaderSourceLibrary.Init("../../TempShaderFolder/"); - - shaderSourceLibrary.LoadShader(0, "TestCubeVs.glsl", SH_SHADER_TYPE::VERTEX, true); - shaderSourceLibrary.LoadShader(1, "TestCubeFs.glsl", SH_SHADER_TYPE::FRAGMENT, true); - - shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary); - auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl"); - auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl"); - cubeVS->Reflect(); - cubeFS->Reflect(); - - defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferWriteSubpass); + void SHGraphicsSystem::InitSubsystems(void) noexcept + { mousePickSystem = resourceManager.Create(); std::vector> cmdPools; cmdPools.reserve(swapchain->GetNumImages()); for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i) - cmdPools.push_back(renderContext.GetFrameData(i).cmdPoolHdls[0]); + cmdPools.push_back(renderContext.GetFrameData(i).cmdPoolHdls[0]); mousePickSystem->Init(device, cmdPools, worldRenderGraph->GetRenderGraphResource("Entity ID")); @@ -217,6 +238,61 @@ namespace SHADE postOffscreenRender->Init(device, worldRenderGraph->GetRenderGraphResource("Scene"), descPool); } +#ifdef SHEDITOR + void SHGraphicsSystem::InitEditorRenderGraph(void) noexcept + { + auto windowDims = window->GetWindowSize(); + + // Create Default Viewport + editorViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast(windowDims.first), static_cast(windowDims.second), 0.0f, 1.0f)); + + // Get render graph from viewport editor renderer + editorRenderGraph = resourceManager.Create(); + + std::vector> renderContextCmdPools{ swapchain->GetNumImages() }; + for (uint32_t i = 0; i < renderContextCmdPools.size(); ++i) + renderContextCmdPools[i] = renderContext.GetFrameData(i).cmdPoolHdls[0]; + + editorRenderGraph->Init(device, swapchain); + editorRenderGraph->AddResource("Present", { SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT }, windowDims.first, windowDims.second); + + + auto imguiNode = editorRenderGraph->AddNode("ImGui Node", { "Present"}, {}); + auto imguiSubpass = imguiNode->AddSubpass("ImGui Draw"); + imguiSubpass->AddColorOutput("Present"); + + // Generate world render graph + editorRenderGraph->Generate(); + + // Add world renderer to default viewport + editorRenderer = editorViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], editorRenderGraph); + editorRenderer->SetCamera(worldCamera); + } +#endif + + /*---------------------------------------------------------------------------------*/ + /* Constructor/Destructors */ + /*---------------------------------------------------------------------------------*/ + void SHGraphicsSystem::Init(void) + { + InitBoilerplate(); + InitMiddleEnd(); + InitSubsystems(); + + + } + + void SHGraphicsSystem::Exit(void) + { + } + +#pragma endregion INIT_EXIT + +#pragma region LIFECYCLE + + /*---------------------------------------------------------------------------------*/ + /* Lifecycle Functions */ + /*---------------------------------------------------------------------------------*/ /***************************************************************************/ /*! @@ -235,12 +311,6 @@ namespace SHADE 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(); @@ -262,6 +332,9 @@ namespace SHADE // Bind textures + auto cameraSystem = SHSystemManager::GetSystem(); + + // For every viewport for (int vpIndex = 0; vpIndex < static_cast(viewports.size()); ++vpIndex) @@ -284,7 +357,7 @@ namespace SHADE uint32_t h = static_cast(viewports[vpIndex]->GetHeight()); currentCmdBuffer->SetViewportScissor (static_cast(w), static_cast(h), w, h); - currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout()); + currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout(), SH_PIPELINE_TYPE::GRAPHICS); // Bind all the buffers required for meshes for (auto& [buffer, bindingPoint] : MESH_DATA) @@ -304,14 +377,29 @@ namespace SHADE currentCmdBuffer->BindDescriptorSet ( textureDescSet, - vk::PipelineBindPoint::eGraphics, + SH_PIPELINE_TYPE::GRAPHICS, 0, texDynamicOffset ); } // bind camera data + //renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex); + +#ifdef SHEDITOR + if (renderers[renIndex] == worldRenderer) + { + auto editorSystem = SHSystemManager::GetSystem(); + if (editorSystem->editorState != SHEditor::State::PLAY) + worldRenderer->UpdateDataAndBind(currentCmdBuffer, frameIndex, SHMatrix::Transpose(cameraSystem->GetEditorCamera()->GetProjMatrix() * cameraSystem->GetEditorCamera()->GetViewMatrix())); + else + renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex); + } + else + renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex); +#else renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex); +#endif // Draw first renderers[renIndex]->Draw(frameIndex, descPool); @@ -336,14 +424,7 @@ namespace SHADE } } } - - void SHGraphicsSystem::Exit(void) - { - } - - /*---------------------------------------------------------------------------------*/ - /* Lifecycle Functions */ - /*---------------------------------------------------------------------------------*/ + /***************************************************************************/ /*! @@ -408,12 +489,6 @@ namespace SHADE if (window->IsMinimized() || renderContext.GetWindowIsDead()) return; - if (renderContext.GetResized()) - { - return; - } - - const uint32_t CURR_FRAME_IDX = renderContext.GetCurrentFrame(); auto& currFrameData = renderContext.GetCurrentFrameData(); @@ -425,9 +500,7 @@ namespace SHADE // If swapchain is incompatible/outdated if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR) { - HandleResize(); - } } @@ -435,6 +508,10 @@ namespace SHADE renderContext.AdvanceFrame(); } +#pragma endregion LIFECYCLE + +#pragma region ADD_REMOVE_BUILD + Handle SHGraphicsSystem::AddViewport(const vk::Viewport& viewport) { // Create the viewport @@ -520,19 +597,19 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Texture Registration Functions */ /*---------------------------------------------------------------------------------*/ - Handle SHGraphicsSystem::Add(const SHTextureAsset& texAsset) + Handle SHGraphicsSystem::AddTexture(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) + SHADE::Handle SHGraphicsSystem::AddTexture(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) + void SHGraphicsSystem::RemoveTexture(Handle tex) { texLibrary.Remove(tex); } @@ -545,43 +622,14 @@ namespace SHADE ); } - 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); - - mousePickSystem->HandleResize(); - - 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; - } +#pragma endregion ADD_REMOVE +#pragma region ROUTINES /*-----------------------------------------------------------------------------------*/ /* System Routine Functions - BeginRoutine */ /*-----------------------------------------------------------------------------------*/ SHGraphicsSystem::BeginRoutine::BeginRoutine() - : SHSystemRoutine("Graphics System Frame Set Up", false) + : SHSystemRoutine("Graphics System Frame Set Up", true) {} void SHGraphicsSystem::BeginRoutine::Execute(double) noexcept @@ -593,7 +641,7 @@ namespace SHADE /* System Routine Functions - RenderRoutine */ /*-----------------------------------------------------------------------------------*/ SHGraphicsSystem::RenderRoutine::RenderRoutine() - : SHSystemRoutine("Graphics System Render", false) + : SHSystemRoutine("Graphics System Render", true) {} void SHGraphicsSystem::RenderRoutine::Execute(double dt) noexcept @@ -605,7 +653,7 @@ namespace SHADE /* System Routine Functions - EndRoutine */ /*-----------------------------------------------------------------------------------*/ SHGraphicsSystem::EndRoutine::EndRoutine() - : SHSystemRoutine("Graphics System Frame Clean Up", false) + : SHSystemRoutine("Graphics System Frame Clean Up", true) {} void SHGraphicsSystem::EndRoutine::Execute(double) noexcept @@ -617,7 +665,7 @@ namespace SHADE /* System Routine Functions - BatcherDispatcherRoutine */ /*-----------------------------------------------------------------------------------*/ SHGraphicsSystem::BatcherDispatcherRoutine::BatcherDispatcherRoutine() - : SHSystemRoutine("Graphics System Batcher Dispatcher", false) + : SHSystemRoutine("Graphics System Batcher Dispatcher", true) {} void SHGraphicsSystem::BatcherDispatcherRoutine::Execute(double) noexcept @@ -648,5 +696,70 @@ namespace SHADE renderable.ResetChangedFlag(); } } +#pragma endregion ROUTINES +#pragma region MISC + + void SHGraphicsSystem::PrepareResize(uint32_t newWidth, uint32_t newHeight) noexcept + { + resizeWidth = newWidth; + resizeHeight = newHeight; + + renderContext.SetIsResized(true); + } + + void SHGraphicsSystem::HandleResize(void) noexcept + { + device->WaitIdle(); + + if (window->IsMinimized() || renderContext.GetWindowIsDead()) + return; + + graphSemaphores[0].Free(); + graphSemaphores[1].Free(); + + auto windowDims = window->GetWindowSize(); + + // Resize the swapchain + swapchain->Resize(surface, windowDims.first, windowDims.second); + + renderContext.HandleResize(); + + worldRenderGraph->HandleResize(resizeWidth, resizeHeight); + editorRenderGraph->HandleResize(windowDims.first, windowDims.second); + + mousePickSystem->HandleResize(); + postOffscreenRender->HandleResize(); + + worldViewport->SetWidth(static_cast(resizeWidth)); + worldViewport->SetHeight(static_cast(resizeHeight)); + + worldCamera->SetPerspective(90.0f, static_cast(resizeWidth), static_cast(resizeHeight), 0.0f, 100.0f); + + auto cameraSystem = SHSystemManager::GetSystem(); +#ifdef SHEDITOR + cameraSystem->GetEditorCamera()->SetWidth(static_cast(resizeWidth)); + cameraSystem->GetEditorCamera()->SetHeight(static_cast(resizeHeight)); +#else + +#endif + + for (auto& semaHandle : graphSemaphores) + semaHandle = device->CreateSemaphore(); + + + } + + void SHGraphicsSystem::AwaitGraphicsExecution() + { + device->WaitIdle(); + } + + void SHGraphicsSystem::SetWindow(SHWindow* wind) noexcept + { + window = wind; + } + + +#pragma endregion MISC } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 517b5999..870325ac 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -17,7 +17,7 @@ of DigiPen Institute of Technology is prohibited. #include // Project Includes -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include "Graphics/SHVulkanIncludes.h" #include "Graphics/MiddleEnd/PerFrame/SHRenderContext.h" #include "Graphics/RenderGraph/SHRenderGraph.h" @@ -67,6 +67,16 @@ namespace SHADE /***********************************************************************************/ class SH_API SHGraphicsSystem : public SHSystem { + private: + void InitBoilerplate (void) noexcept; + void InitSceneRenderGraph (void) noexcept; + void InitMiddleEnd (void) noexcept; + void InitSubsystems (void) noexcept; + +#ifdef SHEDITOR + void InitEditorRenderGraph (void) noexcept; +#endif + public: class SH_API BeginRoutine final : public SHSystemRoutine { @@ -221,8 +231,8 @@ namespace SHADE */ /*******************************************************************************/ - 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); + Handle AddTexture(const SHTextureAsset& texAsset); + Handle AddTexture(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector mipOffsets); /*******************************************************************************/ /*! @@ -236,7 +246,7 @@ namespace SHADE */ /*******************************************************************************/ - void Remove(Handle tex); + void RemoveTexture(Handle tex); /***************************************************************************/ /*! @@ -252,6 +262,7 @@ namespace SHADE /***************************************************************************/ void BuildTextures(); + void PrepareResize(uint32_t newWidth, uint32_t newHeight) noexcept; void HandleResize(void) noexcept; void AwaitGraphicsExecution(); @@ -269,7 +280,10 @@ namespace SHADE Handle GetPhysicalDevice() const { return physicalDevice; } Handle GetQueue() const { return graphicsQueue; } Handle GetDescriptorPool() const { return descPool; } - Handle GetDefaultViewport() const {return defaultViewport;} + Handle GetDefaultViewport() const {return worldViewport;} +#ifdef SHEDITOR + Handle GetEditorViewport () const {return editorViewport;}; +#endif Handle GetMousePickSystem(void) const noexcept {return mousePickSystem;}; Handle GetPostOffscreenRenderSystem(void) const noexcept {return postOffscreenRender;}; //SHRenderGraph const& GetRenderGraph(void) const noexcept; @@ -278,6 +292,7 @@ namespace SHADE private: + /*-----------------------------------------------------------------------------*/ /* Data Members */ /*-----------------------------------------------------------------------------*/ @@ -298,13 +313,19 @@ namespace SHADE SHWindow* window = nullptr; // Middle End Resources - ResourceManager resourceManager; + SHResourceHub resourceManager; SHMeshLibrary meshLibrary; SHTextureLibrary texLibrary; SHSamplerCache samplerCache; SHMaterialInstanceCache materialInstanceCache; // Viewports - Handle defaultViewport; // Whole screen +#ifdef SHEDITOR + Handle editorViewport; + Handle editorRenderer; + Handle editorRenderGraph; +#endif + + Handle worldViewport; // Whole screen std::vector> viewports; // Additional viewports // Debug Renderers @@ -331,5 +352,7 @@ namespace SHADE Handle mousePickSystem; Handle postOffscreenRender; + uint32_t resizeWidth; + uint32_t resizeHeight; }; } \ 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 348efb07..ec546fd5 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h @@ -15,7 +15,7 @@ of DigiPen Institute of Technology is prohibited. // STL Includes #include // Project Includes -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include "SHCommonTypes.h" namespace SHADE diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h index d111acb9..b6fcc830 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h @@ -13,7 +13,7 @@ of DigiPen Institute of Technology is prohibited. // STL Includes #include // Project Includes -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include "Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h" #include "SH_API.h" diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMeshLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMeshLibrary.h index e9923385..72ac1878 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMeshLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMeshLibrary.h @@ -15,8 +15,8 @@ of DigiPen Institute of Technology is prohibited. // STL Includes #include // Project Includes -#include "Resource/Handle.h" -#include "Resource/ResourceLibrary.h" +#include "Resource/SHHandle.h" +#include "Resource/SHResourceLibrary.h" #include "Math/SHMath.h" namespace SHADE @@ -167,7 +167,7 @@ namespace SHADE std::vector meshAddJobs; std::vector> meshRemoveJobs; // Tracking - ResourceLibrary meshes{}; + SHResourceLibrary meshes{}; std::vector> meshOrder; // CPU Storage std::vector vertPosStorage; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMousePickSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMousePickSystem.cpp index e4ac92e5..57a08d47 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMousePickSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMousePickSystem.cpp @@ -6,6 +6,7 @@ #include "Graphics/Synchronization/SHVkFence.h" #include "Graphics/Buffers/SHVkBuffer.h" #include "Graphics/SHVkUtil.h" +#include "Graphics/MiddleEnd/Interface/SHViewport.h" namespace SHADE { @@ -13,7 +14,7 @@ namespace SHADE { logicalDevice = device; - pickedEID = 0; + pickedEID = MAX_EID; // Create command buffers for (auto& pool : cmdPools) @@ -30,7 +31,7 @@ namespace SHADE void SHMousePickSystem::Run(Handle queue, uint32_t frameIndex) noexcept { // if input detected - if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::LEFT_CTRL) && SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) + if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::LMB)) { afterCopyFence->Reset(); @@ -52,17 +53,18 @@ namespace SHADE // wait for the copy to be done afterCopyFence->Wait(true, std::numeric_limits::max()); - int mouseX = 0, mouseY = 0; - SHInputManager::GetMouseWindowPosition(&mouseX, &mouseY); + pickedEID = imageDataDstBuffer->GetDataFromMappedPointer(static_cast(viewportMousePos.y) * entityIDAttachment->GetWidth() + static_cast(viewportMousePos.x)); - pickedEID = imageDataDstBuffer->GetDataFromMappedPointer(mouseY * entityIDAttachment->GetWidth() + mouseX); } } void SHMousePickSystem::HandleResize(void) noexcept { if (afterCopyFence) + { + afterCopyFence->Reset(); afterCopyFence.Free(); + } if (imageDataDstBuffer) imageDataDstBuffer.Free(); @@ -76,6 +78,11 @@ namespace SHADE imageDataDstBuffer = logicalDevice->CreateBuffer(bufferSize, nullptr, bufferSize, vk::BufferUsageFlagBits::eTransferDst, VMA_MEMORY_USAGE_AUTO, VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); } + void SHMousePickSystem::SetViewportMousePos(SHVec2 vpMousePos) noexcept + { + viewportMousePos = vpMousePos; + } + EntityID SHMousePickSystem::GetPickedEntity(void) const noexcept { return pickedEID; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMousePickSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMousePickSystem.h index 4b84c1df..85e86969 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMousePickSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMousePickSystem.h @@ -13,6 +13,7 @@ namespace SHADE class SHVkFence; class SHVkQueue; class SHVkBuffer; + class SHViewport; class SHMousePickSystem { @@ -33,6 +34,10 @@ namespace SHADE //! eid picked from screen EntityID pickedEID; + + //! mouse position relative to the viewport window displaying the world + SHVec2 viewportMousePos; + public: /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ @@ -44,6 +49,8 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ + void SetViewportMousePos (SHVec2 vpMousePos) noexcept; + EntityID GetPickedEntity (void) const noexcept; }; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.cpp index 7d40d9bd..ebce5c9e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.cpp @@ -56,14 +56,19 @@ namespace SHADE }; // Create descriptor set layout - offscreenRenderDescSetLayout = logicalDevice->CreateDescriptorSetLayout(0, { imageBinding }); + offscreenRenderDescSetLayout = logicalDevice->CreateDescriptorSetLayout(0, { imageBinding }, false); // Create descriptor set offscreenRenderDescSet = descriptorPool->Allocate({ offscreenRenderDescSetLayout }, { 1 }); + HandleResize(); + } + + void SHPostOffscreenRenderSystem::HandleResize(void) noexcept + { std::vector combinedImageSampler { - std::make_tuple(renderGraphResource->GetImageView(), offscreenRenderSampler, vk::ImageLayout::eShaderReadOnlyOptimal), + std::make_tuple(offscreenRender->GetImageView(), offscreenRenderSampler, vk::ImageLayout::eGeneral), }; // Register the image view and sampler with the descriptor set. Now whenever rendering to the offscreen image is done, the descriptor set will see the change diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.h index 90767bc2..7a236eaf 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.h @@ -1,6 +1,6 @@ #pragma once -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" namespace SHADE { @@ -24,6 +24,8 @@ namespace SHADE void Init (Handle logicalDevice, Handle renderGraphResource, Handle descriptorPool) noexcept; //void Run () + void HandleResize (void) noexcept; + Handle GetDescriptorSetGroup (void) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.h index 3bb7cfda..bc885ca2 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.h @@ -12,7 +12,7 @@ of DigiPen Institute of Technology is prohibited. #pragma once // Project Includes -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" //#include "SHTransform.h" #include "ECS_Base/Components/SHComponent.h" #include "Math/SHMatrix.h" diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp index 14af56ee..962130be 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp @@ -21,6 +21,7 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" #include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" #include "Graphics/Buffers/SHVkBuffer.h" +#include "Camera/SHCameraDirector.h" namespace SHADE { @@ -65,6 +66,11 @@ namespace SHADE camera = _camera; } + void SHRenderer::SetCameraDirector(Handle director) noexcept + { + cameraDirector = director; + } + /*-----------------------------------------------------------------------------------*/ /* Drawing Functions */ /*-----------------------------------------------------------------------------------*/ @@ -75,18 +81,34 @@ namespace SHADE void SHRenderer::UpdateDataAndBind(Handle cmdBuffer, uint32_t frameIndex) noexcept { - cpuCameraData.viewProjectionMatrix = camera->GetViewProjectionMatrix(); + if (camera && cameraDirector) + { + UpdateDataAndBind(cmdBuffer, frameIndex, SHMatrix::Transpose(cameraDirector->GetVPMatrix())); + } + } + + void SHRenderer::UpdateDataAndBind(Handle cmdBuffer, uint32_t frameIndex, SHMatrix exteriorMatrix) noexcept + { + SetViewProjectionMatrix(exteriorMatrix); + + //cpuCameraData.viewProjectionMatrix = camera->GetViewProjectionMatrix(); cameraBuffer->WriteToMemory(&cpuCameraData, sizeof(SHShaderCameraData), 0, cameraDataAlignedSize * frameIndex); - std::array dynamicOffsets{ frameIndex * cameraDataAlignedSize }; + std::array dynamicOffsets{ frameIndex * cameraDataAlignedSize }; - cmdBuffer->BindDescriptorSet(cameraDescriptorSet, vk::PipelineBindPoint::eGraphics, SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, std::span{ dynamicOffsets.data(), 1 }); + cmdBuffer->BindDescriptorSet(cameraDescriptorSet, SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, std::span{ dynamicOffsets.data(), 1 }); } void SHRenderer::UpdateCameraDataToBuffer(void) noexcept { } + void SHRenderer::SetViewProjectionMatrix(SHMatrix const& vpMatrix) noexcept + { + //cpuCameraData.viewProjectionMatrix = camera->GetViewMatrix() * camera->GetProjectionMatrix(); + cpuCameraData.viewProjectionMatrix = vpMatrix; + } + Handle SHRenderer::GetRenderGraph(void) const noexcept { return renderGraph; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h index 0feea840..87cf8ee9 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h @@ -17,7 +17,7 @@ of DigiPen Institute of Technology is prohibited. // Project Includes #include "SHCamera.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include "Graphics/RenderGraph/SHRenderGraph.h" #include "Math/SHMath.h" #include @@ -40,6 +40,7 @@ namespace SHADE class SHGraphicsGlobalData; class SHVkDescriptorPool; class SHVkBuffer; + class SHCameraDirector; struct SHShaderCameraData { @@ -71,13 +72,16 @@ namespace SHADE /* Camera Registration */ /*-----------------------------------------------------------------------------*/ void SetCamera(Handle _camera); + void SetCameraDirector (Handle director) noexcept; /*-----------------------------------------------------------------------------*/ /* Drawing Functions */ /*-----------------------------------------------------------------------------*/ void Draw(uint32_t frameIndex, Handle descPool) noexcept; - void UpdateDataAndBind (Handle cmdBuffer, uint32_t frameIndex) noexcept; + void UpdateDataAndBind(Handle cmdBuffer, uint32_t frameIndex) noexcept; + void UpdateDataAndBind(Handle cmdBuffer, uint32_t frameIndex, SHMatrix exteriorMatrix) noexcept; void UpdateCameraDataToBuffer (void) noexcept; + void SetViewProjectionMatrix (SHMatrix const& vpMatrix) noexcept; /*-----------------------------------------------------------------------------*/ /* Setters and Getters */ @@ -98,6 +102,8 @@ namespace SHADE Handle cameraDescriptorSet; Handle cameraBuffer; + Handle cameraDirector; + // we really only need 1 copy even though we need %swapchainImages copies for // GPU. SHShaderCameraData cpuCameraData; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.cpp index dc534a49..df9e244e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.cpp @@ -17,7 +17,7 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/Instance/SHVkInstance.h" #include "Tools/SHLogger.h" #include "SHRenderer.h" -#include "Resource/ResourceLibrary.h" +#include "Resource/SHResourceLibrary.h" #include "Graphics/RenderGraph/SHRenderGraph.h" namespace SHADE @@ -49,7 +49,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Renderer Registration Functions */ /*---------------------------------------------------------------------------------*/ - Handle SHViewport::AddRenderer(ResourceManager& resourceManager, uint32_t numFrames, std::vector>& cmdPools, Handle descriptorPool, Handle cameraDescLayout, Handle renderGraph) + Handle SHViewport::AddRenderer(SHResourceHub& resourceManager, uint32_t numFrames, std::vector>& cmdPools, Handle descriptorPool, Handle cameraDescLayout, Handle renderGraph) { // Create the renderer auto renderer = resourceManager.Create(device, numFrames, cmdPools, descriptorPool, cameraDescLayout, GetHandle(), renderGraph); @@ -85,4 +85,14 @@ namespace SHADE } + void SHViewport::SetX(float x) noexcept + { + viewport.x = x; + } + + void SHViewport::SetY(float y) noexcept + { + viewport.y = y; + } + } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.h index 221dbe7e..26c0a6bd 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.h @@ -17,7 +17,7 @@ of DigiPen Institute of Technology is prohibited. // External Dependencies #include "Graphics/SHVulkanIncludes.h" // Project Includes -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" namespace SHADE { @@ -28,7 +28,7 @@ namespace SHADE class SHVkCommandBuffer; class SHVkLogicalDevice; class SHVkImageView; - class ResourceManager; + class SHResourceHub; class SHRenderGraph; class SHVkDescriptorPool; class SHVkDescriptorSetLayout; @@ -59,7 +59,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Renderers Registration Functions */ /*-----------------------------------------------------------------------------*/ - Handle AddRenderer(ResourceManager& resourceManager, uint32_t numFrames, std::vector>& cmdPools, Handle descriptorPool, Handle cameraDescLayout, Handle renderGraph); + Handle AddRenderer(SHResourceHub& resourceManager, uint32_t numFrames, std::vector>& cmdPools, Handle descriptorPool, Handle cameraDescLayout, Handle renderGraph); void RemoveRenderer(Handle renderer); /*-----------------------------------------------------------------------------*/ @@ -67,6 +67,8 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ void SetWidth(float w) noexcept; void SetHeight (float h) noexcept; + void SetX (float x) noexcept; + void SetY (float y) noexcept; /*-----------------------------------------------------------------------------*/ /* Getters */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.cpp index ed3d27c3..624956da 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.cpp @@ -14,7 +14,7 @@ of DigiPen Institute of Technology is prohibited. #include "SHMaterialInstanceCache.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" -#include "Resource/ResourceLibrary.h" +#include "Resource/SHResourceLibrary.h" namespace SHADE @@ -22,7 +22,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Usage Functions */ /*---------------------------------------------------------------------------------*/ - SHADE::Handle SHMaterialInstanceCache::CreateOrGet(ResourceManager& manager, Handle material) + SHADE::Handle SHMaterialInstanceCache::CreateOrGet(SHResourceHub& manager, Handle material) { // Check if there is already an existing instance auto matInst = cache.find(material); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.h b/SHADE_Engine/src/Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.h index d85cb553..6612faf6 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.h @@ -15,7 +15,7 @@ of DigiPen Institute of Technology is prohibited. // STL Includes #include // Project Includes -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" namespace SHADE { @@ -24,7 +24,7 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ class SHMaterial; class SHMaterialInstance; - class ResourceManager; + class SHResourceHub; /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -56,7 +56,7 @@ namespace SHADE */ /***********************************************************************************/ - Handle CreateOrGet(ResourceManager& manager, Handle material); + Handle CreateOrGet(SHResourceHub& manager, Handle material); /***********************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.cpp index 0ac7013a..8041adfd 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.cpp @@ -52,7 +52,6 @@ namespace SHADE { frameData[i].cmdPoolHdls.push_back(logicalDeviceHdl->CreateCommandPool(params.cmdPoolQueueFamilyType, params.cmdPoolResetMode, params.cmdBufferTransient)); } - } // Initialize all the info. diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp index 682b549c..495a3d37 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp @@ -8,7 +8,7 @@ namespace SHADE { - Handle SHPipelineLibrary::CreateDrawPipeline(std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass) noexcept + Handle SHPipelineLibrary::CreateGraphicsPipelines(std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass) noexcept { SHPipelineLayoutParams params { @@ -52,7 +52,7 @@ namespace SHADE newPipeline->ConstructPipeline(); // Emplace the new pipeline - pipelines.emplace (vsFsPair, newPipeline); + graphicsPipelines.emplace (vsFsPair, newPipeline); return newPipeline; } @@ -62,19 +62,19 @@ namespace SHADE logicalDevice = device; } - Handle SHPipelineLibrary::GetDrawPipline(std::pair, Handle> const& vsFsPair) noexcept + Handle SHPipelineLibrary::GetGraphicsPipeline(std::pair, Handle> const& vsFsPair) noexcept { // return the pipeline requested for - if (pipelines.contains(vsFsPair)) - return pipelines.at(vsFsPair); + if (graphicsPipelines.contains(vsFsPair)) + return graphicsPipelines.at(vsFsPair); else return {}; } - bool SHPipelineLibrary::CheckDrawPipelineExistence(std::pair, Handle> const& vsFsPair) noexcept + bool SHPipelineLibrary::CheckGraphicsPipelineExistence(std::pair, Handle> const& vsFsPair) noexcept { // Returns if a pipeline exists or not - return pipelines.contains(vsFsPair); + return graphicsPipelines.contains(vsFsPair); } } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h index 9a411d25..aeb023c5 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h @@ -23,19 +23,19 @@ namespace SHADE Handle logicalDevice; //! a map of pipelines that are hashed using a pair of shader module handles - std::unordered_map, Handle>, Handle> pipelines; + std::unordered_map, Handle>, Handle> graphicsPipelines; public: void Init (Handle device) noexcept; // Draw pipeline functions. used only when creating pipelines for drawing using a vertex and fragment shader - Handle CreateDrawPipeline ( + Handle CreateGraphicsPipelines ( std::pair, Handle> const& vsFsPair, Handle renderpass, Handle subpass ) noexcept; - Handle GetDrawPipline (std::pair, Handle> const& vsFsPair) noexcept; - bool CheckDrawPipelineExistence (std::pair, Handle> const& vsFsPair) noexcept; + Handle GetGraphicsPipeline (std::pair, Handle> const& vsFsPair) noexcept; + bool CheckGraphicsPipelineExistence (std::pair, Handle> const& vsFsPair) noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h index c2eb85ec..935a7a4d 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h @@ -17,8 +17,8 @@ of DigiPen Institute of Technology is prohibited. // External Dependencies #include "tinyddsloader.h" // Project Includes -#include "Resource/Handle.h" -#include "Resource/ResourceLibrary.h" +#include "Resource/SHHandle.h" +#include "Resource/SHResourceLibrary.h" #include "Math/SHMath.h" #include "Graphics/SHVulkanIncludes.h" @@ -156,7 +156,7 @@ namespace SHADE std::vector addJobs; std::vector> removeJobs; // Tracking - ResourceManager resourceManager; + SHResourceHub resourceManager; std::vector> texOrder; // CPU Storage std::vector, Handle, vk::ImageLayout>> combinedImageSamplers; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.h b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.h index c1529577..1adbcb8c 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHVkSamplerCache.h @@ -16,7 +16,7 @@ of DigiPen Institute of Technology is prohibited. // External Dependencies #include "Graphics/SHVulkanIncludes.h" // Project Includes -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" namespace SHADE { diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineLayoutParams.h b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineLayoutParams.h index 093e03d4..d696e4a3 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineLayoutParams.h +++ b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineLayoutParams.h @@ -2,7 +2,7 @@ #define SH_PIPELINE_LAYOUT_PARAMS_H #include "Graphics/SHVulkanIncludes.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include "Graphics/Descriptors/SHVkDescriptorSetLayout.h" namespace SHADE diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineType.h b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineType.h index e7f5b6a8..2c1c80ff 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineType.h +++ b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineType.h @@ -5,9 +5,13 @@ namespace SHADE { enum class SH_PIPELINE_TYPE { - GRAPHICS, + GRAPHICS = 0, COMPUTE, + RAY_TRACING, + NUM_TYPES, }; + + } #endif \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp index c03fd2a7..973ae72f 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp @@ -4,6 +4,7 @@ #include "Graphics/Shaders/SHVkShaderModule.h" #include "Graphics/Debugging/SHVulkanDebugUtil.h" #include "Graphics/RenderGraph/SHRenderGraph.h" +#include "Graphics/SHVkUtil.h" namespace SHADE { @@ -171,6 +172,29 @@ namespace SHADE void SHVkPipeline::CreateComputePipeline(void) noexcept { + auto shaderModule = pipelineLayout->GetShaderModules()[0]; + + vk::PipelineShaderStageCreateInfo shaderStageCreateInfo + { + .stage = vk::ShaderStageFlagBits::eCompute, + .module = shaderModule->GetVkShaderModule(), + .pName = shaderModule->GetEntryPoint().c_str(), + }; + + vk::ComputePipelineCreateInfo cpCreateInfo + { + .flags = {}, + .stage = shaderStageCreateInfo, + .layout = pipelineLayout->GetVkPipelineLayout(), + }; + + if (auto result = logicalDeviceHdl->GetVkLogicalDevice().createComputePipelines({}, 1, &cpCreateInfo, nullptr, &vkPipeline); result != vk::Result::eSuccess) + SHVulkanDebugUtil::ReportVkError(result, "Failed to create Compute Pipeline. "); + else + { + SHVulkanDebugUtil::ReportVkSuccess("Successfully created a Compute Pipeline. "); + created = true; + } } @@ -245,7 +269,7 @@ namespace SHADE , logicalDeviceHdl{ rhs.logicalDeviceHdl } , pipelineLayout { rhs.pipelineLayout } { - vkPipeline = VK_NULL_HANDLE; + rhs.vkPipeline = VK_NULL_HANDLE; } /***************************************************************************/ @@ -285,7 +309,8 @@ namespace SHADE /***************************************************************************/ SHVkPipeline::~SHVkPipeline(void) noexcept { - logicalDeviceHdl->GetVkLogicalDevice().destroyPipeline(vkPipeline, nullptr); + if (vkPipeline) + logicalDeviceHdl->GetVkLogicalDevice().destroyPipeline(vkPipeline, nullptr); } /***************************************************************************/ @@ -313,7 +338,7 @@ namespace SHADE created = rhs.created; logicalDeviceHdl = rhs.logicalDeviceHdl; - vkPipeline = VK_NULL_HANDLE; + rhs.vkPipeline = VK_NULL_HANDLE; return *this; } @@ -399,18 +424,7 @@ namespace SHADE /***************************************************************************/ vk::PipelineBindPoint SHVkPipeline::GetPipelineBindPoint(void) const noexcept { - switch (pipelineType) - { - case SH_PIPELINE_TYPE::GRAPHICS: - return vk::PipelineBindPoint::eGraphics; - case SH_PIPELINE_TYPE::COMPUTE: - return vk::PipelineBindPoint::eCompute; - break; - default: - return vk::PipelineBindPoint::eGraphics; - break; - - } + return SHVkUtil::GetPipelineBindPointFromType(pipelineType); } /***************************************************************************/ @@ -450,4 +464,9 @@ namespace SHADE return pipelineLayout; } + SH_PIPELINE_TYPE SHVkPipeline::GetPipelineType(void) const noexcept + { + return pipelineType; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.h b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.h index fe55a41e..7378cc48 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.h +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.h @@ -3,7 +3,7 @@ #include "SHPipelineState.h" #include "SHPipelineType.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include "Graphics/Pipeline/SHVkPipelineLayout.h" namespace SHADE @@ -77,6 +77,7 @@ namespace SHADE vk::Pipeline GetVkPipeline (void) const noexcept; bool GetIsCreated (void) const noexcept; Handle GetPipelineLayout (void) const noexcept; + SH_PIPELINE_TYPE GetPipelineType (void) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp index 7a76447d..37d00795 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp @@ -216,9 +216,18 @@ namespace SHADE /***************************************************************************/ void SHVkPipelineLayout::PrepareVkDescriptorSetLayouts(void) noexcept { + // pipeline layouts contain global layouts first, then layouts for allocation descriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size()); + vkDescriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size()); - // Settle allocate layouts first + // First we insert the global layouts + for (auto const& layout : descriptorSetLayoutsGlobal) + { + descriptorSetLayoutsPipeline.emplace_back(layout); + //vkDescriptorSetLayoutsPipeline.emplace_back(layout->GetVkHandle()); + } + + // Then the allocate layouts vkDescriptorSetLayoutsAllocate.reserve(descriptorSetLayoutsAllocate.size()); for (auto const& layout : descriptorSetLayoutsAllocate) { @@ -226,18 +235,13 @@ namespace SHADE vkDescriptorSetLayoutsAllocate.emplace_back(layout->GetVkHandle()); } - // pipeline layouts contain global layouts first, then layouts for allocation - vkDescriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size()); - - // First we insert the global layouts - for (auto const& layout : descriptorSetLayoutsGlobal) + for (auto const& layout : descriptorSetLayoutsPipeline) { - 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)); + //std::copy(vkDescriptorSetLayoutsAllocate.begin(), vkDescriptorSetLayoutsAllocate.end(), std::back_inserter(vkDescriptorSetLayoutsPipeline)); } /***************************************************************************/ @@ -294,6 +298,7 @@ namespace SHADE , descriptorSetLayoutsGlobal{pipelineLayoutParams.globalDescSetLayouts } // do a copy, some other pipeline layout might need this , descriptorSetLayoutsAllocate{} , vkDescriptorSetLayoutsAllocate{} + , descriptorSetLayoutsPipeline{} , vkDescriptorSetLayoutsPipeline{} { for (auto& mod : shaderModules) @@ -318,6 +323,7 @@ namespace SHADE , descriptorSetLayoutsGlobal{} , descriptorSetLayoutsAllocate{} , vkDescriptorSetLayoutsAllocate{} + , descriptorSetLayoutsPipeline{} , vkDescriptorSetLayoutsPipeline{} { @@ -368,7 +374,8 @@ namespace SHADE , descriptorSetLayoutsGlobal {std::move (rhs.descriptorSetLayoutsGlobal)} , descriptorSetLayoutsAllocate {std::move (rhs.descriptorSetLayoutsAllocate)} , vkDescriptorSetLayoutsAllocate{std::move (rhs.vkDescriptorSetLayoutsAllocate)} - , vkDescriptorSetLayoutsPipeline{std::move (rhs.vkDescriptorSetLayoutsAllocate)} + , descriptorSetLayoutsPipeline { std::move(rhs.descriptorSetLayoutsPipeline) } + , vkDescriptorSetLayoutsPipeline{ std::move(rhs.vkDescriptorSetLayoutsPipeline) } { rhs.vkPipelineLayout = VK_NULL_HANDLE; } @@ -441,12 +448,12 @@ namespace SHADE return {}; } - std::vector> SHVkPipelineLayout::GetDescriptorSetLayoutsPipeline(void) const noexcept + std::vector> const& SHVkPipelineLayout::GetDescriptorSetLayoutsPipeline(void) const noexcept { return descriptorSetLayoutsPipeline; } - std::vector> SHVkPipelineLayout::GetDescriptorSetLayoutsAllocate(void) const noexcept + std::vector> const& SHVkPipelineLayout::GetDescriptorSetLayoutsAllocate(void) const noexcept { return descriptorSetLayoutsAllocate; } @@ -464,7 +471,8 @@ namespace SHADE descriptorSetLayoutsGlobal = std::move(rhs.descriptorSetLayoutsGlobal); descriptorSetLayoutsAllocate = std::move(rhs.descriptorSetLayoutsAllocate); vkDescriptorSetLayoutsAllocate = std::move(rhs.vkDescriptorSetLayoutsAllocate); - vkDescriptorSetLayoutsPipeline = std::move(rhs.vkDescriptorSetLayoutsAllocate); + descriptorSetLayoutsPipeline = std::move(rhs.descriptorSetLayoutsPipeline); + vkDescriptorSetLayoutsPipeline = std::move(rhs.vkDescriptorSetLayoutsPipeline); rhs.vkPipelineLayout = VK_NULL_HANDLE; diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h index f5d363fa..b4298e00 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h @@ -74,12 +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> GetDescriptorSetLayoutsPipeline(void) const noexcept; - std::vector> GetDescriptorSetLayoutsAllocate(void) 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> const& GetDescriptorSetLayoutsPipeline(void) const noexcept; + std::vector> const& GetDescriptorSetLayoutsAllocate(void) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/Queues/SHVkQueue.h b/SHADE_Engine/src/Graphics/Queues/SHVkQueue.h index 9d865ee9..a647cb72 100644 --- a/SHADE_Engine/src/Graphics/Queues/SHVkQueue.h +++ b/SHADE_Engine/src/Graphics/Queues/SHVkQueue.h @@ -3,7 +3,7 @@ #include "Graphics/SHVulkanIncludes.h" #include "Graphics/SHVulkanDefines.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" namespace SHADE { diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescInitParams.h b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescInitParams.h index 20e924cb..845a19a4 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescInitParams.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescInitParams.h @@ -1,6 +1,6 @@ #pragma once -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" namespace SHADE { diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h index 241292d4..c4d44ea8 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h @@ -10,6 +10,8 @@ namespace SHADE DEPTH = 0x04, STENCIL = 0x08, DEPTH_STENCIL = 0x10, - INPUT = 0x20 + INPUT = 0x20, + STORAGE = 0x40 }; + } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index 51584300..4684419a 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -9,6 +9,8 @@ #include "Graphics/Buffers/SHVkBuffer.h" #include "Tools/SHLogger.h" #include "SHAttachmentDescInitParams.h" +#include "SHRenderGraphStorage.h" +#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h" namespace SHADE { @@ -52,12 +54,12 @@ namespace SHADE // If we set to if (w == static_cast(-1) && h == static_cast(-1)) { - w = swapchainHdl->GetSwapchainImage(0)->GetWidth(); - h = swapchainHdl->GetSwapchainImage(0)->GetHeight(); - format = swapchainHdl->GetSurfaceFormatKHR().format; + w = renderGraphStorage->swapchain->GetSwapchainImage(0)->GetWidth(); + h = renderGraphStorage->swapchain->GetSwapchainImage(0)->GetHeight(); + format = renderGraphStorage->swapchain->GetSurfaceFormatKHR().format; } - graphResources.try_emplace(resourceName, resourceManager.Create(logicalDeviceHdl, swapchainHdl, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags)); + renderGraphStorage->graphResources->try_emplace(resourceName, resourceManager->Create(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags)); } /***************************************************************************/ @@ -77,36 +79,38 @@ namespace SHADE for (uint32_t i = 0; auto& node : nodes) { - // key is handle ID, value is pair (first is initial layout, second is final layout). - std::unordered_map resourceAttLayouts; + // key is handle ID, value is final layout. + std::unordered_map resourceAttFinalLayouts; if (node->subpasses.empty()) { SHLOG_ERROR("Node does not contain a subpass. Cannot configure attachment descriptions as a result. "); return; } + // attempt to get all final layouts for all resources for (auto& subpass : node->subpasses) { for (auto& color : subpass->colorReferences) { + // If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass if (i == nodes.size() - 1 && (node->attResources[color.attachment]->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT))) - resourceAttLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; + resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR; else - resourceAttLayouts[color.attachment] = color.layout; + resourceAttFinalLayouts[color.attachment] = color.layout; } for (auto& depth : subpass->depthReferences) - resourceAttLayouts[depth.attachment] = depth.layout; + resourceAttFinalLayouts[depth.attachment] = depth.layout; for (auto& input : subpass->inputReferences) - resourceAttLayouts[input.attachment] = input.layout; + resourceAttFinalLayouts[input.attachment] = input.layout; } - for (uint32_t i = 0; i < node->attachmentDescriptions.size(); ++i) + for (uint32_t j = 0; j < node->attachmentDescriptions.size(); ++j) { - auto& att = node->attachmentDescriptions[i]; + auto& att = node->attachmentDescriptions[j]; att.initialLayout = vk::ImageLayout::eUndefined; - att.finalLayout = resourceAttLayouts[i]; + att.finalLayout = resourceAttFinalLayouts[j]; } ++i; } @@ -292,6 +296,9 @@ namespace SHADE dep.dstAccessMask = dstAccess; dep.srcStageMask = srcStage; + + // initialize input descriptors + node->subpasses[i]->CreateInputDescriptors(); } } } @@ -343,10 +350,18 @@ namespace SHADE */ /***************************************************************************/ - void SHRenderGraph::Init(Handle const& logicalDevice, Handle const& swapchain) noexcept + void SHRenderGraph::Init(Handle logicalDevice, Handle swapchain) noexcept { - logicalDeviceHdl = logicalDevice; - swapchainHdl = swapchain; + resourceManager = std::make_shared(); + + renderGraphStorage = resourceManager->Create(); + renderGraphStorage->graphResources = resourceManager->Create>>(); + + renderGraphStorage->logicalDevice = logicalDevice; + renderGraphStorage->swapchain = swapchain; + + renderGraphStorage->resourceManager = resourceManager; + renderGraphStorage->descriptorPool = logicalDevice->CreateDescriptorPools(); } /***************************************************************************/ @@ -361,25 +376,19 @@ namespace SHADE */ /***************************************************************************/ SHRenderGraph::SHRenderGraph(void) noexcept - : logicalDeviceHdl{ } - , swapchainHdl{ } + : renderGraphStorage{} , nodes{} - , graphResources{} - , resourceManager{} - + , resourceManager{nullptr} { - } SHRenderGraph::SHRenderGraph(SHRenderGraph&& rhs) noexcept - : logicalDeviceHdl{ rhs.logicalDeviceHdl } - , swapchainHdl{ rhs.swapchainHdl } + : renderGraphStorage{ rhs.renderGraphStorage } , nodeIndexing{ std::move(rhs.nodeIndexing) } , nodes{ std::move(rhs.nodes) } - , graphResources{ std::move(rhs.graphResources) } , resourceManager{ std::move(rhs.resourceManager) } { - + } SHRenderGraph& SHRenderGraph::operator=(SHRenderGraph&& rhs) noexcept @@ -387,11 +396,9 @@ namespace SHADE if (&rhs == this) return *this; - logicalDeviceHdl = rhs.logicalDeviceHdl; - swapchainHdl = rhs.swapchainHdl; + renderGraphStorage = rhs.renderGraphStorage; nodeIndexing = std::move(rhs.nodeIndexing); nodes = std::move(rhs.nodes); - graphResources = std::move(rhs.graphResources); resourceManager = std::move(rhs.resourceManager); return *this; @@ -427,12 +434,12 @@ namespace SHADE for (auto const& instruction : resourceInstruction) { // If the resource that the new node is requesting for exists, allow the graph to reference it - if (graphResources.contains(instruction.resourceName)) + if (renderGraphStorage->graphResources->contains(instruction.resourceName)) { descInitParams.push_back( { - .resourceHdl = graphResources.at(instruction.resourceName), - .dontClearOnLoad = false, + .resourceHdl = renderGraphStorage->graphResources->at(instruction.resourceName), + .dontClearOnLoad = instruction.dontClearOnLoad, } ); } @@ -457,7 +464,7 @@ namespace SHADE } } - nodes.emplace_back(resourceManager.Create(resourceManager, logicalDeviceHdl, swapchainHdl, std::move(descInitParams), std::move(predecessors), &graphResources)); + nodes.emplace_back(resourceManager->Create(renderGraphStorage, std::move(descInitParams), std::move(predecessors))); nodeIndexing.emplace(nodeName, static_cast(nodes.size()) - 1u); return nodes.at(nodeIndexing[nodeName]); } @@ -477,12 +484,31 @@ namespace SHADE /***************************************************************************/ void SHRenderGraph::Generate(void) noexcept { + CheckForNodeComputes(); ConfigureAttachmentDescriptions(); ConfigureSubpasses(); ConfigureRenderpasses(); ConfigureFramebuffers(); } + /***************************************************************************/ + /*! + + \brief + This function goes through all renderpasses and checks for existence of + node computes. If they exist, adds dummy subpasses to transition resources + into general. + + */ + /***************************************************************************/ + void SHRenderGraph::CheckForNodeComputes(void) noexcept + { + for (auto& node : nodes) + { + node->AddDummySubpassIfNeeded(); + } + } + // TODO: The graph scope buffers were meant to bind vertex buffers and index buffers for meshes. Find a // better way to manage these void SHRenderGraph::Execute(uint32_t frameIndex, Handle cmdBuffer, Handle descPool) noexcept @@ -502,7 +528,7 @@ namespace SHADE void SHRenderGraph::HandleResize(uint32_t newWidth, uint32_t newHeight) noexcept { // resize resources - for (auto& [name, resource]: graphResources) + for (auto& [name, resource] : *renderGraphStorage->graphResources) resource->HandleResize(newWidth, newHeight); for (auto& node : nodes) @@ -522,9 +548,9 @@ namespace SHADE Handle SHRenderGraph::GetRenderGraphResource(std::string const& resourceName) const noexcept { - if (graphResources.contains(resourceName)) + if (renderGraphStorage->graphResources->contains(resourceName)) { - return graphResources.at(resourceName); + return renderGraphStorage->graphResources->at(resourceName); } return {}; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index 8eb458aa..d90b66df 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -2,7 +2,7 @@ #define SH_RENDER_GRAPH_H #include "Graphics/Renderpass/SHVkRenderpass.h" -#include "Resource/ResourceLibrary.h" +#include "Resource/SHResourceLibrary.h" #include "SH_API.h" #include "Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h" #include "Graphics/MiddleEnd/Batching/SHSuperBatch.h" @@ -16,6 +16,7 @@ #include #include +#include namespace SHADE { @@ -29,7 +30,8 @@ namespace SHADE class SHVkCommandBuffer; class SHRenderGraphNode; class SHGraphicsGlobalData; - + class SHVkDescriptorPool; + class SHRenderGraphStorage; class SH_API SHRenderGraph { @@ -55,10 +57,8 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ - Handle logicalDeviceHdl; - //! swapchain used for querying image count - Handle swapchainHdl; + Handle renderGraphStorage; //! For indexing render graph node container std::map nodeIndexing; @@ -66,11 +66,8 @@ namespace SHADE //! Render graph nodes std::vector> nodes; - //! Resources that exist for the entire render graph - std::unordered_map> graphResources; - //! Resource library for graph handles - ResourceManager resourceManager; + std::shared_ptr resourceManager; public: /*-----------------------------------------------------------------------*/ @@ -84,14 +81,15 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void Init (Handle const& logicalDevice, Handle const& swapchain) noexcept; + void Init (Handle logicalDevice, Handle swapchain) noexcept; void AddResource(std::string resourceName, std::initializer_list typeFlags, uint32_t w = static_cast(-1), uint32_t h = static_cast(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, uint8_t levels = 1, vk::ImageUsageFlagBits usageFlags = {}, vk::ImageCreateFlagBits createFlags = {}); Handle AddNode (std::string nodeName, std::initializer_list resourceInstruction, std::initializer_list predecessorNodes) noexcept; - void Generate (void) noexcept; - 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; + void Generate (void) noexcept; + void CheckForNodeComputes (void) noexcept; + 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 index 0ff8fe96..c315bffd 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -6,6 +6,9 @@ #include "Graphics/Framebuffer/SHVkFramebuffer.h" #include "SHRenderGraphResource.h" #include "SHSubpass.h" +#include "SHRenderGraphStorage.h" +#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h" +#include "Graphics/SHVkUtil.h" namespace SHADE { @@ -21,7 +24,7 @@ namespace SHADE /***************************************************************************/ void SHRenderGraphNode::CreateRenderpass(void) noexcept { - renderpass = logicalDeviceHdl->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); + renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); } /***************************************************************************/ @@ -53,7 +56,7 @@ namespace SHADE } - framebuffers[i] = logicalDeviceHdl->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); + framebuffers[i] = graphStorage->logicalDevice->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); } } @@ -79,9 +82,18 @@ namespace SHADE fbHeight = attResources[j]->height; } - framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight); } + + for (auto& subpass : subpasses) + { + subpass->HandleResize(); + } + + for (auto& nodeCompute : nodeComputes) + { + nodeCompute->HandleResize(); + } } /***************************************************************************/ @@ -104,8 +116,8 @@ namespace SHADE */ /***************************************************************************/ - SHRenderGraphNode::SHRenderGraphNode(ResourceManager& rm, Handle const& logicalDevice, Handle const& swapchain, std::vector attDescInitParams, std::vector> predecessors, std::unordered_map> const* resources) noexcept - : logicalDeviceHdl{ logicalDevice } + SHRenderGraphNode::SHRenderGraphNode(Handle renderGraphStorage, std::vector attDescInitParams, std::vector> predecessors) noexcept + : graphStorage{ renderGraphStorage} , renderpass{} , framebuffers{} , prereqNodes{ std::move(predecessors) } @@ -115,11 +127,10 @@ namespace SHADE , subpasses{} , executed{ false } , configured{ false } - , resourceManager{ rm } - , ptrToResources{ resources } + , nodeComputes{} { // pipeline library initialization - pipelineLibrary.Init(logicalDeviceHdl); + pipelineLibrary.Init(graphStorage->logicalDevice); // Store all the handles to resources attResources.reserve (attDescInitParams.size()); @@ -155,15 +166,14 @@ namespace SHADE if (!containsSwapchainImage) framebuffers.resize(1); else - framebuffers.resize(swapchain->GetNumImages()); + framebuffers.resize(graphStorage->swapchain->GetNumImages()); // At this point, we could configure framebuffers if we had the renderpass object but we don't so their creation has to be // deferred to when renderpasses are also created. } SHRenderGraphNode::SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept - : resourceManager{ rhs.resourceManager } - , logicalDeviceHdl{ rhs.logicalDeviceHdl } + : graphStorage{ rhs.graphStorage} , renderpass{ rhs.renderpass } , framebuffers{ std::move(rhs.framebuffers) } , prereqNodes{ std::move(rhs.prereqNodes) } @@ -174,9 +184,11 @@ namespace SHADE , subpassIndexing{ std::move(rhs.subpassIndexing) } , configured{ rhs.configured } , executed{ rhs.executed } - , ptrToResources{ rhs.ptrToResources } , pipelineLibrary{ std::move(rhs.pipelineLibrary) } , batcher{ std::move(rhs.batcher) } + , spDescs{ std::move(rhs.spDescs) } + , spDeps{ std::move(rhs.spDeps) } + , nodeComputes{ std::move(rhs.nodeComputes) } { rhs.renderpass = {}; @@ -187,8 +199,7 @@ namespace SHADE if (&rhs == this) return *this; - resourceManager = rhs.resourceManager; - logicalDeviceHdl = rhs.logicalDeviceHdl; + graphStorage = rhs.graphStorage; renderpass = rhs.renderpass; framebuffers = std::move(rhs.framebuffers); prereqNodes = std::move(rhs.prereqNodes); @@ -197,9 +208,12 @@ namespace SHADE 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); + spDescs = std::move(rhs.spDescs); + spDeps = std::move(rhs.spDeps); + nodeComputes = std::move(rhs.nodeComputes); + rhs.renderpass = {}; @@ -230,10 +244,10 @@ namespace SHADE } // Add subpass to container and create mapping for it - subpasses.emplace_back(resourceManager.Create(resourceManager, GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources)); + subpasses.emplace_back(graphStorage->resourceManager->Create(graphStorage, GetHandle(), static_cast(subpasses.size()), &resourceAttachmentMapping)); subpassIndexing.try_emplace(subpassName, static_cast(subpasses.size()) - 1u); Handle subpass = subpasses.back(); - subpass->Init(resourceManager); + subpass->Init(*graphStorage->resourceManager); // Register the SuperBatch batcher.RegisterSuperBatch(subpass->GetSuperBatch()); @@ -241,21 +255,84 @@ namespace SHADE return subpass; } + Handle SHRenderGraphNode::AddNodeCompute(Handle computeShaderModule, std::initializer_list resources, float numWorkGroupScale/* = 1.0f*/) noexcept + { + // Look for the required resources in the graph + std::vector> nodeComputeResources{}; + nodeComputeResources.reserve(resources.size()); + + for (auto& resourceName : resources) + { + auto resource = graphStorage->graphResources->at(resourceName); + nodeComputeResources.push_back(resource); + } + + // Create the subpass compute with the resources + auto nodeCompute = graphStorage->resourceManager->Create(graphStorage, computeShaderModule, std::move(nodeComputeResources)); + nodeComputes.push_back(nodeCompute); + + return nodeCompute; + } + + /***************************************************************************/ + /*! + + \brief + This function checks all node computes and adds a subpass to transition + all needed resources to general. + + */ + /***************************************************************************/ + void SHRenderGraphNode::AddDummySubpassIfNeeded(void) noexcept + { + if (!nodeComputes.empty()) + { + // we save the resource names involved + std::unordered_set resourcesInvolved; + for (auto& compute : nodeComputes) + { + for (auto& resource : compute->resources) + { + resourcesInvolved.emplace(resource->GetName()); + } + } + + // insert them all for a subpass to transition them. This subpass is the last subpass + auto dummySubpass = AddSubpass("dummy"); + for (auto& resource : resourcesInvolved) + { + dummySubpass->AddGeneralInput(resource); + + if (SHVkUtil::IsDepthStencilAttachment(graphStorage->graphResources->at(resource)->GetResourceFormat())) + dummySubpass->AddGeneralDepthOutput(resource); + else + dummySubpass->AddGeneralColorOutput(resource); + } + } + } + void SHRenderGraphNode::Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept { - frameIndex = (framebuffers.size() > 1) ? frameIndex : 0; - commandBuffer->BeginRenderpass(renderpass, framebuffers[frameIndex]); + uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0; + commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]); 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) + if (i != static_cast(subpasses.size()) - 1u) commandBuffer->NextSubpass(); } commandBuffer->EndRenderpass(); + + + // Execute all subpass computes + for (auto& sbCompute : nodeComputes) + { + sbCompute->Execute(commandBuffer, frameIndex); + } } Handle SHRenderGraphNode::GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept @@ -268,10 +345,10 @@ namespace SHADE } - Handle pipeline = pipelineLibrary.GetDrawPipline(vsFsPair); + Handle pipeline = pipelineLibrary.GetGraphicsPipeline(vsFsPair); if (!pipeline) { - pipeline = pipelineLibrary.CreateDrawPipeline + pipeline = pipelineLibrary.CreateGraphicsPipelines ( vsFsPair, renderpass, @@ -284,7 +361,7 @@ namespace SHADE void SHRenderGraphNode::FinaliseBatch(uint32_t frameIndex, Handle descPool) { - batcher.FinaliseBatches(logicalDeviceHdl, descPool, frameIndex); + batcher.FinaliseBatches(graphStorage->logicalDevice, descPool, frameIndex); } /***************************************************************************/ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index f36e7622..16f3f914 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -13,12 +13,15 @@ namespace SHADE { - class ResourceManager; + class SHResourceHub; class SHVkFramebuffer; class SHRenderGraphResource; class SHVkLogicalDevice; class SHVkRenderpass; class SHVkDescriptorPool; + class SHGraphicsGlobalData; + class SHRenderGraphStorage; + class SHRenderGraphNodeCompute; class SH_API SHRenderGraphNode : public ISelfHandle { @@ -26,10 +29,9 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ - ResourceManager& resourceManager; - //! For Vulkan object creation - Handle logicalDeviceHdl; + //Handle logicalDeviceHdl; + Handle graphStorage; //! Each node will have a renderpass and each renderpass will have its own subpasses. //! These subpasses will execute sequentially. @@ -63,12 +65,13 @@ namespace SHADE //! 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; + //! Sometimes we want the subpass to do something to the images instead + //! of drawing objects on the image (i.e. compute). + std::vector> nodeComputes; + //! Whether or not the node has finished execution bool executed; @@ -77,6 +80,7 @@ namespace SHADE SHBatcher batcher; + /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ @@ -88,7 +92,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ /*-----------------------------------------------------------------------*/ - SHRenderGraphNode(ResourceManager& rm, Handle const& logicalDevice, Handle const& swapchain, std::vector attDescInitParams, std::vector> predecessors, std::unordered_map> const* resources) noexcept; + SHRenderGraphNode(Handle renderGraphStorage, std::vector attDescInitParams, std::vector> predecessors) noexcept; SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept; SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept; @@ -96,6 +100,9 @@ namespace SHADE /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ Handle AddSubpass(std::string subpassName) noexcept; + Handle AddNodeCompute(Handle computeShaderModule, std::initializer_list resources, float numWorkGroupScale = 1.0f) noexcept; + void AddDummySubpassIfNeeded (void) noexcept; + // TODO: RemoveSubpass() void Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp new file mode 100644 index 00000000..a5208fcf --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp @@ -0,0 +1,109 @@ +#include "SHpch.h" +#include "SHRenderGraphNodeCompute.h" +#include "Graphics/Pipeline/SHVkPipeline.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/Descriptors/SHVkDescriptorPool.h" +#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Graphics/Pipeline/SHVkPipelineLayout.h" +#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h" +#include "SHRenderGraphStorage.h" +#include "SHRenderGraphResource.h" +#include "Graphics/Commands/SHVkCommandBuffer.h" + +namespace SHADE +{ + SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, float inNumWorkGroupScale/* = 1.0f*/) noexcept + : computePipeline{} + , pipelineLayout{} + , resources{} + , groupSizeX{0} + , groupSizeY{0} + , numWorkGroupScale {std::clamp(inNumWorkGroupScale, 0.0f, 1.0f)} + { + SHPipelineLayoutParams pipelineLayoutParams + { + .shaderModules = {computeShaderModule}, + .globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts() + }; + + // Create pipeline layout from parameters + pipelineLayout = graphStorage->logicalDevice->CreatePipelineLayout (pipelineLayoutParams); + + // Create the compute pipeline + computePipeline = graphStorage->logicalDevice->CreateComputePipeline(pipelineLayout); + + // and construct it + computePipeline->ConstructPipeline(); + + // save the resources + resources = std::move (subpassComputeResources); + + //Get the descriptor set layouts required to allocate. We only want the ones for allocate because + //global descriptors are already bound in the main system. + auto const& layouts = computePipeline->GetPipelineLayout()->GetDescriptorSetLayoutsAllocate(); + + //Variable counts for the descriptor sets (all should be 1). + std::vector variableCounts{ static_cast(layouts.size()) }; + std::fill(variableCounts.begin(), variableCounts.end(), 0); + + // Allocate descriptor sets to hold the images for reading (STORAGE_IMAGE) + for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i) + { + descSetGroups[i] = graphStorage->descriptorPool->Allocate(layouts, variableCounts); + } + + + HandleResize(); + } + + void SHRenderGraphNodeCompute::Execute(Handle cmdBuffer, uint32_t frameIndex) noexcept + { + // bind the compute pipeline + cmdBuffer->BindPipeline(computePipeline); + + // bind descriptor sets + cmdBuffer->BindDescriptorSet(descSetGroups[frameIndex], SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, {}); + + // dispatch compute + cmdBuffer->ComputeDispatch(groupSizeX, groupSizeY, 1); + + // TODO: barrier + + } + + void SHRenderGraphNodeCompute::HandleResize(void) noexcept + { + // Get the layout for the render graph resource. We can index it this way because the container returned is a container of layouts that includes the global ones + auto pipelineDescSetLayouts = computePipeline->GetPipelineLayout()->GetDescriptorSetLayoutsPipeline()[SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE]; + + // everything below here needs resizing + for (uint32_t frameIndex = 0; frameIndex < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++frameIndex) + { + uint32_t i = 0; + + // loop through bindings and write descriptor sets + for (auto& binding : pipelineDescSetLayouts->GetBindings()) + { + uint32_t imageIndex = (resources[i]->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? frameIndex : 0; + + SHVkDescriptorSetGroup::viewSamplerLayout vsl = std::make_tuple(resources[i]->GetImageView(imageIndex), Handle{}, vk::ImageLayout::eGeneral); + descSetGroups[frameIndex]->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint, { &vsl, 1 }); + descSetGroups[frameIndex]->UpdateDescriptorSetImages(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint); + ++i; + } + } + + // Get the group size from the max width and height + uint32_t maxWidth = 0, maxHeight = 0; + for (auto& resource : resources) + { + maxWidth = std::max(resource->GetWidth(), maxWidth); + maxHeight = std::max(resource->GetHeight(), maxHeight); + } + + groupSizeX = maxWidth / workGroupSizeX; + groupSizeY = maxHeight / workGroupSizeY; + } + +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h new file mode 100644 index 00000000..ba4cf387 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h @@ -0,0 +1,57 @@ +#pragma once + +#include "Resource/SHHandle.h" +#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" +#include +#include +#include + +namespace SHADE +{ + class SHVkPipeline; + class SHVkDescriptorSetGroup; + class SHVkDescriptorPool; + class SHVkLogicalDevice; + class SHVkPipelineLayout; + class SHRenderGraphStorage; + class SHRenderGraphResource; + class SHVkShaderModule; + class SHVkCommandBuffer; + + class SHRenderGraphNodeCompute + { + private: + static constexpr uint32_t workGroupSizeX = 16; + static constexpr uint32_t workGroupSizeY = 16; + + //! To run the dispatch command + Handle computePipeline; + + //! Pipeline layout for the pipeline creation + Handle pipelineLayout; + + //! Descriptor set group to hold the images for reading (STORAGE_IMAGE) + std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS> descSetGroups; + + //! vector of resources needed by the subpass compute + std::vector> resources; + + //! X dimension work group size. Should scale with resource size. + uint32_t groupSizeX; + + //! Y dimension work group size + uint32_t groupSizeY; + + float numWorkGroupScale; + + public: + SHRenderGraphNodeCompute(Handle graphStorage, Handle computeShaderModule, std::vector>&& subpassComputeResources, float inNumWorkGroupScale = 1.0f) noexcept; + + void Execute (Handle cmdBuffer, uint32_t frameIndex) noexcept; + void HandleResize (void) noexcept; + + friend class SHRenderGraph; + friend class SHRenderGraphNode; + }; +} + diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp index adf3b6cd..502e09b2 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp @@ -5,6 +5,7 @@ #include "Graphics/Images/SHVkImageView.h" #include "Graphics/Buffers/SHVkBuffer.h" #include "Graphics/SHVkUtil.h" +#include "SHRenderGraphStorage.h" namespace SHADE { @@ -45,9 +46,8 @@ namespace SHADE */ /***************************************************************************/ - SHRenderGraphResource::SHRenderGraphResource(Handle const& logicalDevice, Handle const& swapchain, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept - : logicalDevice {logicalDevice} - , swapchain{ swapchain } + SHRenderGraphResource::SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept + : graphStorage{renderGraphStorage} , resourceTypeFlags{ } , resourceFormat{ format } , images{} @@ -66,7 +66,7 @@ namespace SHADE SHImageViewDetails viewDetails { .viewType = vk::ImageViewType::e2D, - .format = swapchain->GetSurfaceFormatKHR().format, + .format = graphStorage->swapchain->GetSurfaceFormatKHR().format, .imageAspectFlags = vk::ImageAspectFlagBits::eColor, .baseMipLevel = 0, .mipLevelCount = 1, @@ -75,13 +75,13 @@ namespace SHADE }; // We want an image handle for every swapchain image - images.resize(swapchain->GetNumImages()); - imageViews.resize(swapchain->GetNumImages()); + images.resize(graphStorage->swapchain->GetNumImages()); + imageViews.resize(graphStorage->swapchain->GetNumImages()); - for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i) + for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i) { - images[i] = swapchain->GetSwapchainImage(i); - imageViews[i] = images[i]->CreateImageView(logicalDevice, images[i], viewDetails); + images[i] = graphStorage->swapchain->GetSwapchainImage(i); + imageViews[i] = images[i]->CreateImageView(graphStorage->logicalDevice, images[i], viewDetails); } } else // if swapchain image resource @@ -117,6 +117,9 @@ namespace SHADE usage |= vk::ImageUsageFlagBits::eInputAttachment; usage |= vk::ImageUsageFlagBits::eSampled; break; + case SH_ATT_DESC_TYPE_FLAGS::STORAGE: + usage |= vk::ImageUsageFlagBits::eStorage; + break; case SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT: { SHLOG_ERROR ("COLOR_PRESENT cannot be with other resource type flags. "); @@ -126,7 +129,7 @@ namespace SHADE } // The resource is not a swapchain image, just use the first slot of the vector - images.push_back(logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags)); + images.push_back(graphStorage->logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags)); // prepare image view details SHImageViewDetails viewDetails @@ -141,7 +144,7 @@ namespace SHADE }; // just 1 image view created - imageViews.push_back(images[0]->CreateImageView(logicalDevice, images[0], viewDetails)); + imageViews.push_back(images[0]->CreateImageView(graphStorage->logicalDevice, images[0], viewDetails)); } } @@ -166,7 +169,7 @@ namespace SHADE , height{ rhs.height } , mipLevels{ rhs.mipLevels } , imageAspectFlags{ rhs.imageAspectFlags } - , swapchain {rhs.swapchain} + , graphStorage{rhs.graphStorage} { } @@ -198,7 +201,7 @@ namespace SHADE height = rhs.height; mipLevels = rhs.mipLevels; imageAspectFlags = rhs.imageAspectFlags; - swapchain = rhs.swapchain; + graphStorage = rhs.graphStorage; return *this; } @@ -247,7 +250,7 @@ namespace SHADE SHImageViewDetails viewDetails { .viewType = vk::ImageViewType::e2D, - .format = swapchain->GetSurfaceFormatKHR().format, + .format = graphStorage->swapchain->GetSurfaceFormatKHR().format, .imageAspectFlags = vk::ImageAspectFlagBits::eColor, .baseMipLevel = 0, .mipLevelCount = 1, @@ -255,9 +258,9 @@ namespace SHADE .layerCount = 1, }; - for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i) + for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i) { - images[i] = swapchain->GetSwapchainImage(i); + images[i] = graphStorage->swapchain->GetSwapchainImage(i); imageViews[i]->ViewNewImage(images[i], viewDetails); } } @@ -308,6 +311,7 @@ namespace SHADE return resourceFormat; } + uint32_t SHRenderGraphResource::GetWidth(void) const noexcept { return width; @@ -323,4 +327,19 @@ namespace SHADE return imageViews [index]; } + Handle SHRenderGraphResource::GetImage(uint32_t index /*= NON_SWAPCHAIN_RESOURCE_INDEX*/) const noexcept + { + return images[index]; + } + + uint8_t SHRenderGraphResource::GetMipLevels(void) const noexcept + { + return mipLevels; + } + + std::string SHRenderGraphResource::GetName(void) const noexcept + { + return resourceName; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h index efaf9bf5..e2fc5d8d 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h @@ -3,7 +3,7 @@ #include #include "SHAttachmentDescriptionType.h" #include -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include "Graphics/SHVulkanIncludes.h" #include "SH_API.h" @@ -15,6 +15,7 @@ namespace SHADE class SHVkSwapchain; class SHVkCommandBuffer; class SHVkBuffer; + class SHRenderGraphStorage; static constexpr uint32_t NON_SWAPCHAIN_RESOURCE_INDEX = 0; @@ -24,11 +25,8 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ - // for creation/recreation - Handle logicalDevice; - - // for creation/recreation - Handle swapchain; + //! Storage from the render graph + Handle graphStorage; //! Name of the resource std::string resourceName; @@ -69,7 +67,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ /*-----------------------------------------------------------------------*/ - SHRenderGraphResource(Handle const& logicalDevice, Handle const& swapchain, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept; + SHRenderGraphResource(Handle renderGraphStorage, std::string const& name, std::initializer_list typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept; SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept; SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept; ~SHRenderGraphResource(void) noexcept; @@ -84,12 +82,17 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ - vk::Format GetResourceFormat (void) const noexcept; - uint32_t GetWidth (void) const noexcept; - uint32_t GetHeight (void) const noexcept; - Handle GetImageView (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept; + vk::Format GetResourceFormat (void) const noexcept; + uint32_t GetWidth (void) const noexcept; + uint32_t GetHeight (void) const noexcept; + Handle GetImageView (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept; + Handle GetImage (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept; + uint8_t GetMipLevels (void) const noexcept; + std::string GetName (void) const noexcept; friend class SHRenderGraphNode; friend class SHRenderGraph; + friend class SHSubpass; + friend class SHRenderGraphNodeCompute; }; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h new file mode 100644 index 00000000..54ef705a --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h @@ -0,0 +1,43 @@ +#pragma once + +#include "Resource/SHHandle.h" +#include + +namespace SHADE +{ + class SHVkLogicalDevice; + class SHVkSwapchain; + class SHGraphicsGlobalData; + class SHVkDescriptorPool; + class SHRenderGraphResource; + + class SHRenderGraphStorage + { + //! Logical device for creation of vulkan objects + Handle logicalDevice; + + //! swapchain handle + Handle swapchain; + + //! Resource manager for creation of objects + std::shared_ptr resourceManager; + + //! Descriptor pool for the descriptor sets to be created in the subpasses + Handle descriptorPool; + + //! For accessing resources anywhere in the graph + Handle>> graphResources; + + //SHRenderGraphStorage(void) noexcept; + //SHRenderGraphStorage(SHRenderGraphStorage&& rhs) noexcept; + //SHRenderGraphStorage& operator=(SHRenderGraphStorage&& rhs) noexcept; + + friend class SHRenderGraph; + friend class SHRenderGraphNode; + friend class SHSubpass; + friend class SHRenderGraphResource; + friend class SHRenderGraphNodeCompute; + }; + + +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index 6afbfb09..af6f3089 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -4,6 +4,13 @@ #include "Graphics/Devices/SHVkLogicalDevice.h" #include "SHRenderGraphNode.h" #include "SHRenderGraphResource.h" +#include "Graphics/Shaders/SHVkShaderModule.h" +#include "SHRenderGraphNode.h" +#include "SHRenderGraphStorage.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/Swapchain/SHVkSwapchain.h" +#include "Graphics/Images/SHVkSampler.h" +#include "SHRenderGraphResource.h" namespace SHADE { @@ -23,15 +30,16 @@ namespace SHADE */ /***************************************************************************/ - SHSubpass::SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* resources) noexcept + SHSubpass::SHSubpass(Handle renderGraphStorage, Handle const& parent, uint32_t index, std::unordered_map const* mapping) noexcept : resourceAttachmentMapping{ mapping } - , ptrToResources{ resources } , parentNode{ parent } , subpassIndex{ index } , superBatch{} , colorReferences{} , depthReferences{} , inputReferences{} + , graphStorage{ renderGraphStorage } + , inputImageDescriptors {SHGraphicsConstants::NUM_FRAME_BUFFERS} { } @@ -54,7 +62,14 @@ namespace SHADE , depthReferences{ std::move(rhs.depthReferences) } , inputReferences{ std::move(rhs.inputReferences) } , resourceAttachmentMapping{ rhs.resourceAttachmentMapping } - , ptrToResources{ rhs.ptrToResources } + , descriptorSetLayout{ rhs.descriptorSetLayout } + , exteriorDrawCalls{ std::move(rhs.exteriorDrawCalls) } + , graphStorage{ rhs.graphStorage } + , inputNames{ std::move(rhs.inputNames) } + , inputImageDescriptors{ std::move(rhs.inputImageDescriptors) } + , inputDescriptorLayout{ rhs.inputDescriptorLayout } + , inputSamplers{ rhs.inputSamplers } + { } @@ -82,7 +97,13 @@ namespace SHADE depthReferences = std::move(rhs.depthReferences); inputReferences = std::move(rhs.inputReferences); resourceAttachmentMapping = rhs.resourceAttachmentMapping; - ptrToResources = rhs.ptrToResources; + descriptorSetLayout = rhs.descriptorSetLayout; + exteriorDrawCalls = std::move(rhs.exteriorDrawCalls); + graphStorage = rhs.graphStorage; + inputNames = std::move(rhs.inputNames); + inputImageDescriptors = std::move(rhs.inputImageDescriptors); + inputDescriptorLayout = rhs.inputDescriptorLayout; + inputSamplers = rhs.inputSamplers; return *this; } @@ -101,7 +122,12 @@ namespace SHADE /***************************************************************************/ void SHSubpass::AddColorOutput(std::string resourceToReference) noexcept { - colorReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal }); + colorReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal }); + } + + void SHSubpass::AddGeneralColorOutput(std::string resourceToReference) noexcept + { + colorReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eGeneral }); } /***************************************************************************/ @@ -138,7 +164,13 @@ namespace SHADE //Invalid return; } - depthReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), imageLayout }); + depthReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), imageLayout }); + } + + void SHSubpass::AddGeneralDepthOutput(std::string resourceToReference) noexcept + { + depthReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eGeneral }); + } /***************************************************************************/ @@ -155,7 +187,14 @@ namespace SHADE /***************************************************************************/ void SHSubpass::AddInput(std::string resourceToReference) noexcept { - inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal }); + inputReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal }); + + inputNames.push_back(resourceToReference); + } + + void SHSubpass::AddGeneralInput(std::string resourceToReference) noexcept + { + inputReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eGeneral }); } void SHSubpass::Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept @@ -171,6 +210,12 @@ namespace SHADE { drawCall(commandBuffer); } + + } + + void SHSubpass::HandleResize(void) noexcept + { + UpdateWriteDescriptors(); } void SHSubpass::AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept @@ -178,12 +223,158 @@ namespace SHADE exteriorDrawCalls.push_back(newDrawCall); } - void SHSubpass::Init(ResourceManager& resourceManager) noexcept + void SHSubpass::Init(SHResourceHub& resourceManager) noexcept { superBatch = resourceManager.Create(GetHandle()); } + void SHSubpass::CreateInputDescriptors(void) noexcept + { + if (inputNames.empty()) + return; + + std::vector bindings{}; + + for (auto& input : inputReferences) + { + SHVkDescriptorSetLayout::Binding newBinding + { + .Type = (input.layout == vk::ImageLayout::eShaderReadOnlyOptimal) ? vk::DescriptorType::eInputAttachment : vk::DescriptorType::eStorageImage, + .Stage = vk::ShaderStageFlagBits::eFragment, + .BindPoint = static_cast(bindings.size()), + .DescriptorCount = 1, + .flags = {}, + }; + + bindings.push_back(newBinding); + } + + // We build a new descriptor set layout to store our images + inputDescriptorLayout = graphStorage->logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, bindings); + + // we store a sampler if its an input attachment. if it is storage image, no need sampler, store an empty handle. + for (uint32_t i = 0; i < bindings.size(); ++i) + { + if (bindings[i].Type == vk::DescriptorType::eInputAttachment) + { + auto newSampler = graphStorage->logicalDevice->CreateSampler(SHVkSamplerParams + { + .minFilter = vk::Filter::eLinear, + .magFilter = vk::Filter::eLinear, + .addressMode = vk::SamplerAddressMode::eRepeat, + .mipmapMode = vk::SamplerMipmapMode::eLinear, + .minLod = -1000, + .maxLod = 1000 + } + ); + + inputSamplers.push_back(newSampler); + } + else + { + inputSamplers.push_back({}); + } + } + + //// maybe do this in handle resize? + //UpdateWriteDescriptors(); + } + + void SHSubpass::UpdateWriteDescriptors(void) noexcept + { + if (inputNames.empty()) + return; + + auto const& bindings = inputDescriptorLayout->GetBindings(); + + std::vector variableCounts{ static_cast(bindings.size()) }; + std::fill (variableCounts.begin(), variableCounts.end(), 0u); + + + // For every frame's descriptor set + for (auto& group : inputImageDescriptors) + { + if (group) + group.Free(); + + group = graphStorage->descriptorPool->Allocate({ inputDescriptorLayout }, variableCounts); + + uint32_t i = 0; + for (auto& binding : bindings) + { + // get the resource + auto resource = graphStorage->graphResources->at(inputNames[binding.BindPoint]); + + // If resource is swapchain image, get the correct image, if not just get 0. + uint32_t viewIndex = (resource->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? i : 0; + + // layout is GENERAL if image is meant to be used as storage image, if not use SHADER_READ_ONLY_OPTINAL + vk::ImageLayout descriptorLayout = (binding.Type == vk::DescriptorType::eStorageImage) ? vk::ImageLayout::eGeneral : vk::ImageLayout::eShaderReadOnlyOptimal; + + // Update descriptor sets + auto args = std::make_tuple(resource->GetImageView(viewIndex), inputSamplers[i], descriptorLayout); + group->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint, std::span{&args, 1}); + group->UpdateDescriptorSetImages(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint); + } + + ++i; + } + } + + //void SHSubpass::InitComputeBarriers(void) noexcept + //{ + // std::unordered_set handleBarriers{}; + + // // we will have swapchainNumImages vectors of vector of barriers + // subpassComputeBarriers.resize(graphStorage->swapchain->GetNumImages()); + + // for (auto sbCompute : subpassComputes) + // { + // // for every resource the subpass compute is using + // for (auto resource : sbCompute->resources) + // { + // // Get the resource handle + // uint64_t resourceRaw = resource.GetId().Raw; + + // // if the barrier is not registered + // if (!handleBarriers.contains(resourceRaw)) + // { + // // If the resource is a swapchain image + // bool isSwapchainImage = (resource->resourceTypeFlags & static_cast(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)); + // for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i) + // { + // // if swapchain image, we want the index of the swapchain image, if not take base image + // uint32_t imageIndex = isSwapchainImage ? i : 0; + + // // Prepare image barrier + // vk::ImageMemoryBarrier imageBarrier + // { + // .oldLayout = colorReferences[resourceAttachmentMapping->at(resource.GetId().Raw)].layout, + // .newLayout = vk::ImageLayout::eGeneral, + // .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + // .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + // .image = resource->GetImage(imageIndex)->GetVkImage(), + // .subresourceRange = + // { + // .aspectMask = resource->imageAspectFlags, + // .levelCount = resource->GetMipLevels(), + // .baseArrayLayer = 0, + // .layerCount = 1 + // } + // }; + + // // push the barrier + // subpassComputeBarriers[i].push_back(imageBarrier); + // } + + // // Image transition registered + // handleBarriers.emplace(resourceRaw); + // } + // } + // } + //} + /***************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h index 2e883ebc..166f0d76 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h @@ -3,7 +3,7 @@ #include "SHAttachmentDescriptionType.h" #include #include "SH_API.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include "Graphics/SHVulkanIncludes.h" @@ -14,7 +14,11 @@ namespace SHADE class SHRenderGraphResource; class SHVkCommandBuffer; class SHVkDescriptorSetLayout; + class SHVkDescriptorSetGroup; class SHVkDescriptorPool; + class SHRenderGraphStorage; + class SHVkShaderModule; + class SHVkSampler; class SH_API SHSubpass : public ISelfHandle { @@ -22,32 +26,49 @@ namespace SHADE /*---------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ /*---------------------------------------------------------------------*/ + Handle graphStorage; + //! The index of the subpass in the render graph - uint32_t subpassIndex; + uint32_t subpassIndex; //! The parent renderpass that this subpass belongs to - Handle parentNode; + Handle parentNode; //! - Handle superBatch; + Handle superBatch; //! Descriptor set layout to hold attachments - Handle descriptorSetLayout; + Handle descriptorSetLayout; //! Color attachments - std::vector colorReferences; + std::vector colorReferences; //! Depth attachments - std::vector depthReferences; + std::vector depthReferences; //! Input attachments - std::vector inputReferences; + std::vector inputReferences; + + //! This is mainly for when we want to retrieve resources using names. + std::vector inputNames; //! 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; + //! Descriptor set group to hold the images for input + std::vector> inputImageDescriptors; + + //! Descriptor set layout for allocating descriptor set for inputs + Handle inputDescriptorLayout; + + std::vector> inputSamplers; + + + ////! subpass compute image barriers. We do this because every frame has a different + ////! swapchain image. If the resource we want to transition is not a swapchain image, + ////! we duplicate the barrier anyway, not much memory wasted. ;) + //std::vector> subpassComputeBarriers{}; + //! 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. @@ -62,7 +83,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ /*-----------------------------------------------------------------------*/ - SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* ptrToResources) noexcept; + SHSubpass(Handle renderGraphStorage, Handle const& parent, uint32_t index, std::unordered_map const* mapping) noexcept; SHSubpass(SHSubpass&& rhs) noexcept; SHSubpass& operator=(SHSubpass&& rhs) noexcept; @@ -71,14 +92,22 @@ namespace SHADE /*-----------------------------------------------------------------------*/ // Preparation functions void AddColorOutput(std::string resourceToReference) noexcept; + void AddGeneralColorOutput(std::string resourceToReference) noexcept; void AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE_FLAGS attachmentDescriptionType = SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL) noexcept; + void AddGeneralDepthOutput(std::string resourceToReference) noexcept; void AddInput(std::string resourceToReference) noexcept; + void AddGeneralInput (std::string resourceToReference) noexcept; + void AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept; // Runtime functions void Execute(Handle& commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; - void AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept; + void HandleResize (void) noexcept; - void Init(ResourceManager& resourceManager) noexcept; + void Init(SHResourceHub& resourceManager) noexcept; + + //void InitComputeBarriers (void) noexcept; + void CreateInputDescriptors (void) noexcept; + void UpdateWriteDescriptors (void) noexcept; /*-----------------------------------------------------------------------*/ /* GETTERS AND SETTERS */ @@ -91,5 +120,6 @@ namespace SHADE friend class SHRenderGraphNode; friend class SHRenderGraph; + friend class SHSubpass; }; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp deleted file mode 100644 index ccd0e6c3..00000000 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "SHpch.h" -#include "SHSubpassCompute.h" -#include "Graphics/Pipeline/SHVkPipeline.h" -#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" -#include "Graphics/Descriptors/SHVkDescriptorPool.h" - -namespace SHADE -{ - SHSubpassCompute::SHSubpassCompute(Handle 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 deleted file mode 100644 index 3ebc5676..00000000 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h +++ /dev/null @@ -1,25 +0,0 @@ -#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/SHVkAttachDescGen.h b/SHADE_Engine/src/Graphics/Renderpass/SHVkAttachDescGen.h index a44f4f27..8cbf72af 100644 --- a/SHADE_Engine/src/Graphics/Renderpass/SHVkAttachDescGen.h +++ b/SHADE_Engine/src/Graphics/Renderpass/SHVkAttachDescGen.h @@ -2,7 +2,7 @@ #define SH_VK_ATTACHMENT_DESC_GEN_H #include "Graphics/SHVulkanIncludes.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" namespace SHADE { diff --git a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.cpp b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.cpp index fee23f13..74128ec8 100644 --- a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.cpp +++ b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.cpp @@ -253,7 +253,8 @@ namespace SHADE SHVkRenderpass::~SHVkRenderpass(void) noexcept { - logicalDeviceHdl->GetVkLogicalDevice().destroyRenderPass(vkRenderpass, nullptr); + if (vkRenderpass) + logicalDeviceHdl->GetVkLogicalDevice().destroyRenderPass(vkRenderpass, nullptr); } diff --git a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h index 70a04bbf..c265e603 100644 --- a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h +++ b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h @@ -3,7 +3,7 @@ #include "SHVkAttachDescGen.h" #include "SHVkSubpassParams.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include namespace SHADE diff --git a/SHADE_Engine/src/Graphics/Renderpass/SHVkSubpassParams.h b/SHADE_Engine/src/Graphics/Renderpass/SHVkSubpassParams.h index bf789c54..6f722f5a 100644 --- a/SHADE_Engine/src/Graphics/Renderpass/SHVkSubpassParams.h +++ b/SHADE_Engine/src/Graphics/Renderpass/SHVkSubpassParams.h @@ -2,7 +2,7 @@ #define SH_VK_SUBPASS_PARAMS_H #include "Graphics/SHVulkanIncludes.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include namespace SHADE diff --git a/SHADE_Engine/src/Graphics/SHVkUtil.cpp b/SHADE_Engine/src/Graphics/SHVkUtil.cpp index c8c563a1..cf486a7a 100644 --- a/SHADE_Engine/src/Graphics/SHVkUtil.cpp +++ b/SHADE_Engine/src/Graphics/SHVkUtil.cpp @@ -55,6 +55,21 @@ namespace SHADE return 0; } + vk::PipelineBindPoint SHVkUtil::GetPipelineBindPointFromType(SH_PIPELINE_TYPE pipelineType) noexcept + { + switch (pipelineType) + { + case SH_PIPELINE_TYPE::GRAPHICS: + return vk::PipelineBindPoint::eGraphics; + case SH_PIPELINE_TYPE::COMPUTE: + return vk::PipelineBindPoint::eCompute; + case SH_PIPELINE_TYPE::RAY_TRACING: + return vk::PipelineBindPoint::eRayTracingKHR; + default: + return vk::PipelineBindPoint::eGraphics; + } + } + void SHVkUtil::EnsureBufferAndCopyData(Handle device, Handle cmdBuffer, Handle& bufferHandle, void* src, uint32_t size, vk::BufferUsageFlagBits usage) { if (bufferHandle) diff --git a/SHADE_Engine/src/Graphics/SHVkUtil.h b/SHADE_Engine/src/Graphics/SHVkUtil.h index ca3b6f83..de700ea5 100644 --- a/SHADE_Engine/src/Graphics/SHVkUtil.h +++ b/SHADE_Engine/src/Graphics/SHVkUtil.h @@ -3,7 +3,8 @@ #include "SHVulkanIncludes.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" +#include "Graphics/Pipeline/SHPipelineType.h" namespace SHADE { @@ -20,11 +21,12 @@ namespace SHADE class SHVkUtil { public: - static bool IsDepthOnlyFormat (vk::Format format) noexcept; - static bool IsDepthStencilAttachment (vk::Format format) noexcept; - static bool IsBlendCompatible (vk::Format format) noexcept; - static uint32_t GetBytesPerPixelFromFormat (vk::Format format) noexcept; - + static bool IsDepthOnlyFormat (vk::Format format) noexcept; + static bool IsDepthStencilAttachment (vk::Format format) noexcept; + static bool IsBlendCompatible (vk::Format format) noexcept; + static uint32_t GetBytesPerPixelFromFormat (vk::Format format) noexcept; + static vk::PipelineBindPoint GetPipelineBindPointFromType (SH_PIPELINE_TYPE pipelineType) noexcept; + /***********************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp b/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp index 41327988..e635f763 100644 --- a/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp +++ b/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp @@ -177,6 +177,9 @@ namespace SHADE return vk::DescriptorType::eStorageBufferDynamic; case SpvReflectDescriptorType::SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: return vk::DescriptorType::eInputAttachment; + case SpvReflectDescriptorType::SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE: + return vk::DescriptorType::eStorageImage; + break; default: return vk::DescriptorType::eCombinedImageSampler; break; diff --git a/SHADE_Engine/src/Graphics/Shaders/SHVkShaderModule.h b/SHADE_Engine/src/Graphics/Shaders/SHVkShaderModule.h index 2973d734..492710f2 100644 --- a/SHADE_Engine/src/Graphics/Shaders/SHVkShaderModule.h +++ b/SHADE_Engine/src/Graphics/Shaders/SHVkShaderModule.h @@ -2,7 +2,7 @@ #define SH_VK_SHADER_MODULE_H #include "Graphics/SHVulkanIncludes.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" #include "SHShaderReflected.h" #include diff --git a/SHADE_Engine/src/Graphics/Swapchain/SHVkSwapchain.h b/SHADE_Engine/src/Graphics/Swapchain/SHVkSwapchain.h index 28bd7a4e..384665d3 100644 --- a/SHADE_Engine/src/Graphics/Swapchain/SHVkSwapchain.h +++ b/SHADE_Engine/src/Graphics/Swapchain/SHVkSwapchain.h @@ -4,7 +4,7 @@ #include #include #include "Graphics/SHVulkanIncludes.h" -#include "Resource/ResourceLibrary.h" +#include "Resource/SHResourceLibrary.h" #include "Graphics/Swapchain/SHSwapchainParams.h" namespace SHADE diff --git a/SHADE_Engine/src/Graphics/Synchronization/SHVkFence.h b/SHADE_Engine/src/Graphics/Synchronization/SHVkFence.h index 02445d42..7c48a5f6 100644 --- a/SHADE_Engine/src/Graphics/Synchronization/SHVkFence.h +++ b/SHADE_Engine/src/Graphics/Synchronization/SHVkFence.h @@ -2,7 +2,7 @@ #define SH_VK_FENCE_H #include "Graphics/SHVulkanIncludes.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" namespace SHADE { diff --git a/SHADE_Engine/src/Graphics/Synchronization/SHVkSemaphore.h b/SHADE_Engine/src/Graphics/Synchronization/SHVkSemaphore.h index 57f7d7df..f03cad65 100644 --- a/SHADE_Engine/src/Graphics/Synchronization/SHVkSemaphore.h +++ b/SHADE_Engine/src/Graphics/Synchronization/SHVkSemaphore.h @@ -2,7 +2,7 @@ #define SH_VK_SEMAPHORE_H #include "Graphics/SHVulkanIncludes.h" -#include "Resource/Handle.h" +#include "Resource/SHHandle.h" namespace SHADE { diff --git a/SHADE_Engine/src/Graphics/Windowing/Surface/SHVkSurface.h b/SHADE_Engine/src/Graphics/Windowing/Surface/SHVkSurface.h index 0328fecc..bf01dc9c 100644 --- a/SHADE_Engine/src/Graphics/Windowing/Surface/SHVkSurface.h +++ b/SHADE_Engine/src/Graphics/Windowing/Surface/SHVkSurface.h @@ -3,7 +3,7 @@ #include #include "Graphics/SHVulkanIncludes.h" -#include "Resource/ResourceLibrary.h" +#include "Resource/SHResourceLibrary.h" namespace SHADE { diff --git a/SHADE_Engine/src/Input/SHInputManager.cpp b/SHADE_Engine/src/Input/SHInputManager.cpp index 18d9e3e2..c665a9c9 100644 --- a/SHADE_Engine/src/Input/SHInputManager.cpp +++ b/SHADE_Engine/src/Input/SHInputManager.cpp @@ -19,6 +19,10 @@ namespace SHADE /*------------------------------------------------------------------------*/ /* Static defines */ /*------------------------------------------------------------------------*/ + + bool SHInputManager::controllerInUse = false; + + std::map SHInputManager::bindings; unsigned SHInputManager::keyCount = 0; bool SHInputManager::keys[MAX_KEYS]; @@ -41,6 +45,60 @@ namespace SHADE int SHInputManager::mouseWheelVerticalDelta = 0; int SHInputManager::mouseWheelVerticalDeltaPoll = 0; + unsigned char SHInputManager::controllersConnectedCount = 0; + unsigned SHInputManager::controllersInputCount[XUSER_MAX_COUNT]; + unsigned SHInputManager::controllersButtonCount[XUSER_MAX_COUNT]; + short SHInputManager::controllers[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT]; + short SHInputManager::controllersLast[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT]; + double SHInputManager::controllersHeldTime[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT]; + double SHInputManager::controllersReleasedTime[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT]; + + //Internal helper function for splitting between inputs + bool SHInputManager::controllerConsideredHeld(size_t inputIdx, short value) noexcept + { + if (inputIdx >= MAX_CONTROLLER_INPUT) return false; //Bounds check + else + { + if (inputIdx < NUM_CONTROLLER_BUTTON) + { + return static_cast(value); + } + else if (inputIdx < NUM_CONTROLLER_BUTTON + NUM_CONTROLLER_TRIGGER) + { + return (value > XINPUT_GAMEPAD_TRIGGER_THRESHOLD); + } + else if (inputIdx < NUM_CONTROLLER_BUTTON + NUM_CONTROLLER_TRIGGER + NUM_CONTROLLER_TRIGGER) + { + return (std::abs(value) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); + } + else + { + return (std::abs(value) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); + } + } + } + + //Internal helper function for getting normalised input value + double SHInputManager::controllerNormalisedValue(size_t inputIdx, short value) noexcept + { + if (inputIdx >= MAX_CONTROLLER_INPUT) return 0.0; //Bounds check + else + { + if (inputIdx < NUM_CONTROLLER_BUTTON) + { + return static_cast(value); + } + else if (inputIdx < NUM_CONTROLLER_BUTTON + NUM_CONTROLLER_TRIGGER) //8-bit triggers, 0 to 255 + { + return static_cast(value) / static_cast(UCHAR_MAX); + } + else //16-bit thumbsticks, -32768 to 32767 + { + return static_cast(value) / static_cast(SHRT_MAX); + } + } + } + void SHInputManager::UpdateInput(double dt) noexcept { //Keyboard and Mouse Buttons//////////////////////////////////////////////// @@ -120,6 +178,273 @@ namespace SHADE mouseWheelVerticalDelta = 0; mouseWheelVerticalDelta = mouseWheelVerticalDeltaPoll; mouseWheelVerticalDeltaPoll = 0; + + //Controllers////////////////////////////////////////////////////////////// + + controllersConnectedCount = 0; + + //Set last controller states + memcpy(controllersLast, controllers, sizeof(controllers)); + + //Reset controller states + SecureZeroMemory(&controllers, sizeof(controllers)); + + //https://learn.microsoft.com/en-us/windows/win32/xinput/getting-started-with-xinput#getting-controller-state + for (DWORD c = 0; c < XUSER_MAX_COUNT; ++c) + { + controllersInputCount[c] = 0; + controllersButtonCount[c] = 0; + + XINPUT_STATE state; + SecureZeroMemory(&state, sizeof(XINPUT_STATE)); + + //Get the state of controller from XInput + DWORD result = XInputGetState(c, &state); + + //Write gamepad data + if (result == ERROR_SUCCESS) + { + ++controllersConnectedCount; + + //DIGITAL BUTTONS/////////////////////////////////////// + + //DPAD UP + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) + { + controllers[c][static_cast(SH_CONTROLLERCODE::DPAD_UP)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::DPAD_UP)] = 0; + } + + //DPAD DOWN + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) + { + controllers[c][static_cast(SH_CONTROLLERCODE::DPAD_DOWN)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::DPAD_DOWN)] = 0; + } + + //DPAD LEFT + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) + { + controllers[c][static_cast(SH_CONTROLLERCODE::DPAD_LEFT)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::DPAD_LEFT)] = 0; + } + + //DPAD RIGHT + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) + { + controllers[c][static_cast(SH_CONTROLLERCODE::DPAD_RIGHT)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::DPAD_RIGHT)] = 0; + } + + //START + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_START) + { + controllers[c][static_cast(SH_CONTROLLERCODE::START)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::START)] = 0; + } + + //BACK + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) + { + controllers[c][static_cast(SH_CONTROLLERCODE::BACK)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::BACK)] = 0; + } + + //LEFT THUMBSTICK BUTTON + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) + { + controllers[c][static_cast(SH_CONTROLLERCODE::LEFT_THUMBSTICK)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::LEFT_THUMBSTICK)] = 0; + } + + //RIGHT THUMBSTICK BUTTON + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) + { + controllers[c][static_cast(SH_CONTROLLERCODE::RIGHT_THUMBSTICK)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::RIGHT_THUMBSTICK)] = 0; + } + + //LEFT SHOULDER BUTTON + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) + { + controllers[c][static_cast(SH_CONTROLLERCODE::LEFT_SHOULDER)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::LEFT_SHOULDER)] = 0; + } + + //RIGHT SHOULDER BUTTON + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) + { + controllers[c][static_cast(SH_CONTROLLERCODE::RIGHT_SHOULDER)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::RIGHT_SHOULDER)] = 0; + } + + //A + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_A) + { + controllers[c][static_cast(SH_CONTROLLERCODE::A)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::A)] = 0; + } + + //B + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_B) + { + controllers[c][static_cast(SH_CONTROLLERCODE::B)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::B)] = 0; + } + + //X + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_X) + { + controllers[c][static_cast(SH_CONTROLLERCODE::X)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::X)] = 0; + } + + //Y + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_Y) + { + controllers[c][static_cast(SH_CONTROLLERCODE::Y)] = 1; + ++controllersInputCount[c]; + ++controllersButtonCount[c]; + } + else + { + controllers[c][static_cast(SH_CONTROLLERCODE::Y)] = 0; + } + + //8 BIT VALUES (0 - 255)/////////////////////////////////// + + //LEFT TRIGGER + controllers[c][static_cast(SH_CONTROLLERCODE::LEFT_TRIGGER)] = state.Gamepad.bLeftTrigger; + if (state.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) + { + ++controllersInputCount[c]; //Registered as held + } + + //RIGHT TRIGGER + controllers[c][static_cast(SH_CONTROLLERCODE::RIGHT_TRIGGER)] = state.Gamepad.bRightTrigger; + if (state.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) + { + ++controllersInputCount[c]; //Registered as held + } + + //16 BIT VALUES (0 - 65535)//////////////////////////////// + + //LEFT THUMBSTICK X + controllers[c][static_cast(SH_CONTROLLERCODE::LEFT_THUMBSTICK_X)] = state.Gamepad.sThumbLX; + if (std::abs(state.Gamepad.sThumbLX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) + { + ++controllersInputCount[c]; + } + + //LEFT THUMBSTICK Y + controllers[c][static_cast(SH_CONTROLLERCODE::LEFT_THUMBSTICK_Y)] = state.Gamepad.sThumbLY; + if (std::abs(state.Gamepad.sThumbLY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) + { + ++controllersInputCount[c]; + } + + //RIGHT THUMBSTICK X + controllers[c][static_cast(SH_CONTROLLERCODE::RIGHT_THUMBSTICK_X)] = state.Gamepad.sThumbRX; + if (std::abs(state.Gamepad.sThumbRX) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) + { + ++controllersInputCount[c]; + } + + //RIGHT THUMBSTICK Y + controllers[c][static_cast(SH_CONTROLLERCODE::RIGHT_THUMBSTICK_Y)] = state.Gamepad.sThumbRY; + if (std::abs(state.Gamepad.sThumbRY) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) + { + ++controllersInputCount[c]; + } + } + + //Timers and updating if controller is presently in use + for (size_t i = 0; i < MAX_CONTROLLER_INPUT; ++i) + { + if (controllerConsideredHeld(i, controllers[c][i])) //Considered on + { + controllerInUse = true; + if (!controllerConsideredHeld(i, controllersLast[c][i])) //Just on + { + controllersHeldTime[c][i] = 0.0; //Reset timer + } + controllersHeldTime[c][i] += dt; //Tick up + } + else //Considered off + { + if (controllerConsideredHeld(i, controllersLast[c][i])) //Just off + { + controllersReleasedTime[c][i] = 0.0; //Reset timer + } + controllersReleasedTime[c][i] += dt; //Tick up + } + } + } } bool SHInputManager::AnyKeyDown(SH_KEYCODE* firstDetected) noexcept @@ -161,4 +486,336 @@ namespace SHADE return false; } + //Any controller input being held + //For analog, this means going being deadzone values + bool SHInputManager::AnyControllerInput(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + for (size_t i = 0; i < MAX_CONTROLLER_INPUT; ++i) + { + if (controllerConsideredHeld(i, controllers[cNum][i])) + { + if (firstDetected) *firstDetected = static_cast(i); + return true; + } + } + return false; + } + + bool SHInputManager::AnyControllerInputDown(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + for (size_t i = 0; i < MAX_CONTROLLER_INPUT; ++i) + { + if (controllerConsideredHeld(i, controllers[cNum][i]) && !controllerConsideredHeld(i, controllersLast[cNum][i])) + { + if (firstDetected) *firstDetected = static_cast(i); + return true; + } + } + return false; + } + + bool SHInputManager::AnyControllerInputUp(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + for (size_t i = 0; i < MAX_CONTROLLER_INPUT; ++i) + { + if (!controllerConsideredHeld(i, controllers[cNum][i]) && controllerConsideredHeld(i, controllersLast[cNum][i])) + { + if (firstDetected) *firstDetected = static_cast(i); + return true; + } + } + return false; + } + + bool SHInputManager::AnyControllerButton(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + for (size_t i = 0; i < NUM_CONTROLLER_BUTTON; ++i) + { + if (controllerConsideredHeld(i, controllers[cNum][i])) + { + if (firstDetected) *firstDetected = static_cast(i); + return true; + } + } + return false; + } + + bool SHInputManager::AnyControllerButtonDown(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + for (size_t i = 0; i < NUM_CONTROLLER_BUTTON; ++i) + { + if (controllerConsideredHeld(i, controllers[cNum][i]) && !controllerConsideredHeld(i, controllersLast[cNum][i])) + { + if (firstDetected) *firstDetected = static_cast(i); + return true; + } + } + return false; + } + + bool SHInputManager::AnyControllerButtonUp(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + for (size_t i = 0; i < NUM_CONTROLLER_BUTTON; ++i) + { + if (!controllerConsideredHeld(i, controllers[cNum][i]) && controllerConsideredHeld(i, controllersLast[cNum][i])) + { + if (firstDetected) *firstDetected = static_cast(i); + return true; + } + } + return false; + } + + //Only get of largest magnitude + double SHInputManager::GetBindingAxis(std::string bindingName, size_t cNum) noexcept + { + //Over keycodes, prioritise positive + for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes) + { + if (GetKey(k)) return 1.0; + } + for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes) + { + if (GetKey(k)) return -1.0; + } + + double largestMagnitude = 0.0; + + //Over controllerCodes + for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes) + { + double newValue = 0.0; + if (GetControllerInput(c, &newValue, nullptr, nullptr, cNum)) + if (std::abs(newValue) > std::abs(largestMagnitude)) largestMagnitude = newValue; + } + for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes) + { + double newValue = 0.0; + if (GetControllerInput(c, &newValue, nullptr, nullptr, cNum)) + if (std::abs(newValue) > std::abs(largestMagnitude)) largestMagnitude = -newValue; + } + + return largestMagnitude; + } + + bool SHInputManager::GetBindingPositiveButton(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes) + { + if (GetKey(k)) return true; + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes) + { + if (GetControllerInput(c, nullptr, nullptr, nullptr, cNum)) return true; + } + + return false; + } + + bool SHInputManager::GetBindingNegativeButton(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes) + { + if (GetKey(k)) return true; + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes) + { + if (GetControllerInput(c, nullptr, nullptr, nullptr, cNum)) return true; + } + + return false; + } + + bool SHInputManager::GetBindingPositiveButtonDown(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes) + { + if (GetKeyDown(k)) return true; + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes) + { + if (GetControllerInputDown(c, nullptr, cNum)) return true; + } + + return false; + } + + bool SHInputManager::GetBindingNegativeButtonDown(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes) + { + if (GetKeyDown(k)) return true; + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes) + { + if (GetControllerInputDown(c, nullptr, cNum)) return true; + } + + return false; + } + + bool SHInputManager::GetBindingPositiveButtonUp(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes) + { + if (GetKeyUp(k)) return true; + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes) + { + if (GetControllerInputUp(c, nullptr, cNum)) return true; + } + + return false; + } + + bool SHInputManager::GetBindingNegativeButtonUp(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return false; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes) + { + if (GetKeyUp(k)) return true; + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes) + { + if (GetControllerInputUp(c, nullptr, cNum)) return true; + } + + return false; + } + + //Fetches longest hold time + double SHInputManager::GetBindingPositiveHeldTime(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return 0.0; + + double maxHeldTime = 0.0; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes) + { + if (GetKeyHeldTime(k) > maxHeldTime) maxHeldTime = GetKeyHeldTime(k); + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes) + { + if (GetControllerInputHeldTime(c, cNum) > maxHeldTime) maxHeldTime = GetControllerInputHeldTime(c); + } + + return maxHeldTime; + } + + double SHInputManager::GetBindingNegativeHeldTime(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return 0.0; + + double maxHeldTime = 0.0; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes) + { + if (GetKeyHeldTime(k) > maxHeldTime) maxHeldTime = GetKeyHeldTime(k); + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes) + { + if (GetControllerInputHeldTime(c, cNum) > maxHeldTime) maxHeldTime = GetControllerInputHeldTime(c); + } + + return maxHeldTime; + } + + //Fetches shortest release time + double SHInputManager::GetBindingPositiveReleasedTime(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return 0.0; + + double minReleaseTime = _HUGE_ENUF; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes) + { + if (GetKeyReleasedTime(k) < minReleaseTime) minReleaseTime = GetKeyReleasedTime(k); + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes) + { + if (GetControllerInputReleasedTime(c, cNum) < minReleaseTime) minReleaseTime = GetControllerInputReleasedTime(c); + } + + return minReleaseTime; + } + + double SHInputManager::GetBindingNegativeReleasedTime(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return 0.0; + + double minReleaseTime = _HUGE_ENUF; + + //Over keycodes + for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes) + { + if (GetKeyReleasedTime(k) < minReleaseTime) minReleaseTime = GetKeyReleasedTime(k); + } + + //Over controller buttons + for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes) + { + if (GetControllerInputReleasedTime(c, cNum) < minReleaseTime) minReleaseTime = GetControllerInputReleasedTime(c); + } + + return minReleaseTime; + } + + //Only for mouse movement + //Get largest delta + double SHInputManager::GetBindingMouseVelocity(std::string bindingName, size_t cNum) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return 0.0; + + //Mouse velocity + double velX = 0.0; + double velY = 0.0; + GetMouseVelocity(&velX, &velY); + + return bindings[bindingName].mouseXPositiveMultiplier * velX + bindings[bindingName].mouseYPositiveMultiplier * velY; + } + } //namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Input/SHInputManager.h b/SHADE_Engine/src/Input/SHInputManager.h index d3e31004..04e5871d 100644 --- a/SHADE_Engine/src/Input/SHInputManager.h +++ b/SHADE_Engine/src/Input/SHInputManager.h @@ -10,9 +10,12 @@ *********************************************************************/ #pragma once -//#include -//#include "../../SHADE_Managed/src/SHpch.h" +#include +#include +#include +#include "../../SHADE_Managed/src/SHpch.h" #include "SH_API.h" +#pragma comment(lib, "xinput.lib") namespace SHADE { @@ -268,6 +271,58 @@ namespace SHADE OEM_CLEAR }; + enum class SH_CONTROLLERCODE + { + //Digital + DPAD_UP, + DPAD_DOWN, + DPAD_LEFT, + DPAD_RIGHT, + START, + BACK, + LEFT_THUMBSTICK, + RIGHT_THUMBSTICK, + LEFT_SHOULDER, + RIGHT_SHOULDER, + A, + B, + X, + Y, + + //1 Byte Unsigned Analog + LEFT_TRIGGER, + RIGHT_TRIGGER, + + //2 Byte Signed Analog + LEFT_THUMBSTICK_X, + LEFT_THUMBSTICK_Y, + RIGHT_THUMBSTICK_X, + RIGHT_THUMBSTICK_Y + }; + + private: + /*------------------------------------------------------------------------*/ + /* Struct for logical bindings */ + /*------------------------------------------------------------------------*/ + struct SH_API SHLogicalBindingData + { + //Key codes mapped to positive + std::set positiveKeyCodes; + + //Key codes mapped to negative + std::set negativeKeyCodes; + + //Controller Codes mapped to positive + std::set positiveControllerCodes; + + //Controller Codes mapped to negative + std::set negativeControllerCodes; + + //Mouse movement mapped to axes? + double mouseXPositiveMultiplier; + double mouseYPositiveMultiplier; + }; + public: //Updates current state of the input, with dt to be fetched from FRC //TODO should dt be fixed or variable? @@ -392,7 +447,7 @@ namespace SHADE keysToggleLast[static_cast(key)]); } - //Mouse///////////// + //Mouse///////////////////////////////////////////////////// //Get the mouse location with respect to the screen static inline void GetMouseScreenPosition (int* x = nullptr, @@ -428,7 +483,95 @@ namespace SHADE return mouseWheelVerticalDelta; } - //GET INPUT TIMINGS/////////////////////////////////////////////////////////// + /*------------------------------------------------------------------------*/ + /* Input state accessors (KB & M) */ + /*------------------------------------------------------------------------*/ + + //How many controller inputs of any kind are being used now + static inline unsigned GetControllerInputCount(size_t cNum = 0) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return 0; + return controllersInputCount[cNum]; + } + + //How many controller buttons are being pressed now + //Subtract from getControllerInputCount() for analog triggers / thumbsticks + static inline unsigned GetControllerButtonCount(size_t cNum = 0) noexcept + { + if (cNum >= XUSER_MAX_COUNT) return 0; + return controllersButtonCount[cNum]; + } + + //Any controller input being held + //For analog, this means going being deadzone values + //controllerNum should be between 0 and 3 + static bool AnyControllerInput(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept; + + //Any controller input activated in THIS FRAME ONLY + //For analog, this means going being deadzone values + //controllerNum should be between 0 and 3 + static bool AnyControllerInputDown(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept; + + //Any controller input deactivated in THIS FRAME ONLY + //For analog, this means going below deadzone values + //controllerNum should be between 0 and 3 + static bool AnyControllerInputUp(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept; + + //Any DIGITAL controller buttons being held + //controllerNum should be between 0 and 3 + static bool AnyControllerButton(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept; + + //Any DIGITAL controller button activated in THIS FRAME ONLY + //controllerNum should be between 0 and 3 + static bool AnyControllerButtonDown(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept; + + //Any DIGITAL controller button deactivated in THIS FRAME ONLY + //controllerNum should be between 0 and 3 + static bool AnyControllerButtonUp(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept; + + //If controller input is being held in the current frame + //normalisedValue is the value of the input between 0 and 1, relevant for trigger and thumbstick data + //controllerNum should be between 0 and 3 + static inline bool GetControllerInput(SH_CONTROLLERCODE input, + double* normalisedValue = nullptr, + double* heldTime = nullptr, + double* releasedTime = nullptr, + size_t controllerNum = 0) noexcept + { + if (controllerNum >= XUSER_MAX_COUNT) return false; + if (normalisedValue) *normalisedValue = controllerNormalisedValue(static_cast(input), controllers[controllerNum][static_cast(input)]); + if (heldTime) *heldTime = controllersHeldTime[controllerNum][static_cast(input)]; + if (releasedTime) *releasedTime = controllersReleasedTime[controllerNum][static_cast(input)]; + return controllerConsideredHeld(static_cast(input), controllers[controllerNum][static_cast(input)]); + } + + //If controller input was considered to be held down in THIS FRAME ONLY + //controllerNum should be between 0 and 3 + static inline bool GetControllerInputDown(SH_CONTROLLERCODE input, + double* releasedTime = nullptr, + size_t controllerNum = 0) noexcept + { + if (controllerNum >= XUSER_MAX_COUNT) return false; + if (releasedTime) *releasedTime = controllersReleasedTime[controllerNum][static_cast(input)]; + return (controllerConsideredHeld(static_cast(input), controllers[controllerNum][static_cast(input)]) && + !controllerConsideredHeld(static_cast(input), controllersLast[controllerNum][static_cast(input)])); + } + + //If controller input was considered to be released in THIS FRAME ONLY + //controllerNum should be between 0 and 3 + static inline bool GetControllerInputUp(SH_CONTROLLERCODE input, + double* releasedTime = nullptr, + size_t controllerNum = 0) noexcept + { + if (controllerNum >= XUSER_MAX_COUNT) return false; + if (releasedTime) *releasedTime = controllersReleasedTime[controllerNum][static_cast(input)]; + return (!controllerConsideredHeld(static_cast(input), controllers[controllerNum][static_cast(input)]) && + controllerConsideredHeld(static_cast(input), controllersLast[controllerNum][static_cast(input)])); + } + + /*------------------------------------------------------------------------*/ + /* Timing accessors */ + /*------------------------------------------------------------------------*/ //Keyboard///////////// @@ -456,6 +599,191 @@ namespace SHADE return keysToggleOffTime[static_cast(key)]; } + //Controller////////////////////// + + //How long has this controller input been considered to be held down for + static inline double GetControllerInputHeldTime(SH_CONTROLLERCODE code, + size_t controllerNum = 0) noexcept + { + if (controllerNum >= XUSER_MAX_COUNT) return 0.0; + return controllersHeldTime[controllerNum][static_cast(code)]; + } + + //How long has this controller input been considered to be released for + static inline double GetControllerInputReleasedTime(SH_CONTROLLERCODE code, + size_t controllerNum = 0) noexcept + { + if (controllerNum >= XUSER_MAX_COUNT) return 0.0; + return controllersReleasedTime[controllerNum][static_cast(code)]; + } + + /*------------------------------------------------------------------------*/ + /* Binding Functions */ + /*------------------------------------------------------------------------*/ + + //Add a new binding to the map + static inline void BindingsAdd(std::string newBindingName) noexcept + { + bindings.insert({ newBindingName, SHLogicalBindingData() }); + } + + //Remove a binding from the map + //Returns 1 if found and removed, 0 if not found + static inline size_t BindingsRemove(std::string targetBindingName) noexcept + { + return bindings.erase(targetBindingName); + } + + //Clears all bindings from the list + static inline void BindingsClear() noexcept + { + bindings.clear(); + } + + //Get the number of bindings present + static inline size_t BindingsCount() noexcept + { + return bindings.size(); + } + + //Check positive keycodes to binding + static inline std::set const& BindingsGetPositiveKeyCodes(std::string bindingName) noexcept + { + return bindings[bindingName].positiveKeyCodes; + } + + //Add positive SH_KEYCODE to binding + static inline void BindingsAddPositiveKeyCode(std::string targetBindingName, + SH_KEYCODE toAdd) noexcept + { + bindings[targetBindingName].positiveKeyCodes.insert(toAdd); + } + + //Remove positive SH_KEYCODE from binding + //If toRemove found and removed, returns 1. Otherwise, 0. + static inline size_t BindingsRemovePositiveKeyCode(std::string targetBindingName, + SH_KEYCODE toRemove) noexcept + { + return bindings[targetBindingName].positiveKeyCodes.erase(toRemove); + } + + //Check negative keycodes to binding + static inline std::set const& BindingsGetNegativeKeyCodes(std::string bindingName) noexcept + { + return bindings[bindingName].negativeKeyCodes; + } + + //Add negative SH_KEYCODE to binding + static inline void BindingsAddNegativeKeyCode(std::string targetBindingName, + SH_KEYCODE toAdd) noexcept + { + bindings[targetBindingName].negativeKeyCodes.insert(toAdd); + } + + //Remove negative SH_KEYCODE from binding + //If toRemove found and removed, returns 1. Otherwise, 0. + static inline size_t BindingsRemoveNegativeKeyCode(std::string targetBindingName, + SH_KEYCODE toRemove) noexcept + { + return bindings[targetBindingName].negativeKeyCodes.erase(toRemove); + } + + //Check positive controllercodes to binding + static inline std::set const& BindingsGetPositiveControllerCodes(std::string bindingName) noexcept + { + return bindings[bindingName].positiveControllerCodes; + } + + //Add positive SH_CONTROLLERCODE to binding + static inline void BindingsAddPositiveControllerCode(std::string targetBindingName, + SH_CONTROLLERCODE toAdd) noexcept + { + bindings[targetBindingName].positiveControllerCodes.insert(toAdd); + } + + //Remove positive SH_CONTROLLERCODE from binding + //If toRemove found and removed, returns 1. Otherwise, 0. + static inline size_t BindingsRemovePositiveControllerCode(std::string targetBindingName, + SH_CONTROLLERCODE toRemove) noexcept + { + return bindings[targetBindingName].positiveControllerCodes.erase(toRemove); + } + + //Check negative controllercodes to binding + static inline std::set const& BindingsGetNegativeControllerCodes(std::string bindingName) noexcept + { + return bindings[bindingName].negativeControllerCodes; + } + + //Add negative SH_CONTROLLERCODE to binding + static inline void BindingsAddNegativeControllerCode(std::string targetBindingName, + SH_CONTROLLERCODE toAdd) noexcept + { + bindings[targetBindingName].negativeControllerCodes.insert(toAdd); + } + + //Remove negative SH_CONTROLLERCODE from binding + //If toRemove found and removed, returns 1. Otherwise, 0. + static inline size_t BindingsRemoveNegativeControllerCode(std::string targetBindingName, + SH_CONTROLLERCODE toRemove) noexcept + { + return bindings[targetBindingName].negativeControllerCodes.erase(toRemove); + } + + //Mouse movement bindings + + static inline double const BindingsGetMouseXPositiveMultiplier(std::string bindingName) noexcept + { + return bindings[bindingName].mouseXPositiveMultiplier; + } + + static inline void BindingsSetMouseXPositiveMultiplier(std::string bindingName, double newValue) noexcept + { + bindings[bindingName].mouseXPositiveMultiplier = newValue; + } + + static inline double const BindingsGetMouseYPositiveMultiplier(std::string bindingName) noexcept + { + return bindings[bindingName].mouseXPositiveMultiplier; + } + + static inline void BindingsSetMouseYPositiveMultiplier(std::string bindingName, double newValue) noexcept + { + bindings[bindingName].mouseXPositiveMultiplier = newValue; + } + + //Get the axis value of binding, between -1 and 1 + static double GetBindingAxis(std::string bindingName, size_t controllerNumber = 0) noexcept; + + //Whether binding is being held or not + //Does not work for mouse movement + static bool GetBindingPositiveButton(std::string bindingName, size_t controllerNumber = 0) noexcept; + static bool GetBindingNegativeButton(std::string bindingName, size_t controllerNumber = 0) noexcept; + + //Whether binding is pressed down IN THIS FRAME ONLY + //Does not work for mouse movement + static bool GetBindingPositiveButtonDown(std::string bindingName, size_t controllerNumber = 0) noexcept; + static bool GetBindingNegativeButtonDown(std::string bindingName, size_t controllerNumber = 0) noexcept; + + //Whether binding is released IN THIS FRAME ONLY + //Does not work for mouse movement + static bool GetBindingPositiveButtonUp(std::string bindingName, size_t controllerNumber = 0) noexcept; + static bool GetBindingNegativeButtonUp(std::string bindingName, size_t controllerNumber = 0) noexcept; + + //Binding times + + //Does not work for mouse movement + static double GetBindingPositiveHeldTime(std::string bindingName, size_t controllerNumber = 0) noexcept; + static double GetBindingNegativeHeldTime(std::string bindingName, size_t controllerNumber = 0) noexcept; + + //Does not work for mouse movement + static double GetBindingPositiveReleasedTime(std::string bindingName, size_t controllerNumber = 0) noexcept; + static double GetBindingNegativeReleasedTime(std::string bindingName, size_t controllerNumber = 0) noexcept; + + //Binding mouse velocity + //Only for mouse movement + static double GetBindingMouseVelocity(std::string bindingName, size_t controllerNumber = 0) noexcept; + /*------------------------------------------------------------------------*/ /* Other Functions */ /*------------------------------------------------------------------------*/ @@ -482,10 +810,36 @@ namespace SHADE /*------------------------------------------------------------------------*/ static constexpr size_t MAX_KEYS = UCHAR_MAX + 1; + //How many recognised controller inputs there are + //To see the list, see the enum class in this file + static constexpr size_t MAX_CONTROLLER_INPUT = 20; + + //On/off button count + static constexpr size_t NUM_CONTROLLER_BUTTON = 14; + + //8-bit trigger values + static constexpr size_t NUM_CONTROLLER_TRIGGER = 2; + + //16-bit thumbstick values + static constexpr size_t NUM_CONTROLLER_THUMBSTICK = 4; + /*------------------------------------------------------------------------*/ /* Data Members */ /*------------------------------------------------------------------------*/ + //If the last input is from controller(s) or KB/M + //True if from controller(s), False if from KB/M + //Useful for switching control hints between controllers and KB/M + static bool controllerInUse; + + //BINDINGS////////////////////////////////////////////////////////////////// + + //Key is for binding names, they must be unique + //Multiple physical inputs per virtual/logical input are to be added to + //sets inside the logicalBinding values + //TODO make this an array of 4 / 5 users for multiplayer support + static std::map bindings; + //KEYBOARD AND MOUSE BUTTONS//////////////////////////////////////////////// //How many keys are presently being pressed @@ -558,15 +912,48 @@ namespace SHADE //CONTROLLER VARIABLES////////////////////////////////////////////////////// - //OTHER VARIABLES/////////////////////////////////////////////////////////// + //Count how many controllers are presently connected + //Useful for if the game is to decide to take in controller or KB/M input + //Between 0 and 4 (inclusive) + static unsigned char controllersConnectedCount; - //Axis bindings - //X - - //Y + //How many inputs (of any kind) on the controller are being used now + //Includes analog triggers and thumbsticks + static unsigned controllersInputCount[XUSER_MAX_COUNT]; - //Other mappings + //How many DIGITAL buttons on the controller are being pressed now + static unsigned controllersButtonCount[XUSER_MAX_COUNT]; - //Buffer + //Current state of controllers + //First index is for controller number + //Second index is for input type + static short controllers[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT]; + + //State of controllers in the last frame + //First index is for controller number + //Second index is for input type + static short controllersLast[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT]; + + //Held and released times + + //Controller held durations + //Stops ticking up when released + //Will be reset when held again + static double controllersHeldTime[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT]; + + //Key released durations + //Stops ticking up when held + //Will be reset when off again + static double controllersReleasedTime[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT]; + + /*------------------------------------------------------------------------*/ + /* Internal Helper Functions */ + /*------------------------------------------------------------------------*/ + + //Internal helper function for checking if input is considered held or not + static bool controllerConsideredHeld(size_t inputIdx, short value) noexcept; + + //Internal helper function for getting normalised controller value + static double controllerNormalisedValue(size_t inputIdx, short value) noexcept; }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Math/SHMatrix.cpp b/SHADE_Engine/src/Math/SHMatrix.cpp index 571fa4e0..ec3951e2 100644 --- a/SHADE_Engine/src/Math/SHMatrix.cpp +++ b/SHADE_Engine/src/Math/SHMatrix.cpp @@ -295,32 +295,33 @@ namespace SHADE ) != 0; } + SHMatrix::operator XMMATRIX() const noexcept + { + return XMLoadFloat4x4(this); + } + SHMatrix operator*(float lhs, const SHMatrix& rhs) noexcept { return rhs * lhs; } - /*-----------------------------------------------------------------------------------*/ /* Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ void SHMatrix::Transpose() noexcept { - const XMMATRIX M = XMLoadFloat4x4(this); - XMStoreFloat4x4(this, XMMatrixTranspose(M)); + XMStoreFloat4x4(this, XMMatrixTranspose(*this)); } void SHMatrix::Invert() noexcept { - const XMMATRIX M = XMLoadFloat4x4(this); - XMStoreFloat4x4(this, XMMatrixInverse(nullptr, M)); + XMStoreFloat4x4(this, XMMatrixInverse(nullptr, *this)); } float SHMatrix::Determinant() const noexcept { - const XMMATRIX M = XMLoadFloat4x4(this); - return XMVectorGetX(XMMatrixDeterminant(M)); + return XMVectorGetX(XMMatrixDeterminant(*this)); } std::string SHMatrix::ToString() const noexcept @@ -337,9 +338,8 @@ namespace SHADE bool SHMatrix::Decompose(SHVec3& translation, SHVec3& rotation, SHVec3& scale) const noexcept { XMVECTOR s, r, t; - const XMMATRIX M = XMLoadFloat4x4(this); - if (!XMMatrixDecompose(&s, &r, &t, M)) + if (!XMMatrixDecompose(&s, &r, &t, *this)) return false; SHQuaternion orientation; @@ -356,9 +356,8 @@ namespace SHADE bool SHMatrix::Decompose(SHVec3& translation, SHQuaternion& orientation, SHVec3& scale) const noexcept { XMVECTOR s, r, t; - const XMMATRIX M = XMLoadFloat4x4(this); - if (!XMMatrixDecompose(&s, &r, &t, M)) + if (!XMMatrixDecompose(&s, &r, &t, *this)) return false; XMStoreFloat3(&scale, s); @@ -376,8 +375,7 @@ namespace SHADE { SHMatrix result; - const XMMATRIX M = XMLoadFloat4x4(&matrix); - XMStoreFloat4x4(&result, XMMatrixTranspose(M)); + XMStoreFloat4x4(&result, XMMatrixTranspose(matrix)); return result; } @@ -385,8 +383,7 @@ namespace SHADE { SHMatrix result; - const XMMATRIX M = XMLoadFloat4x4(&matrix); - XMStoreFloat4x4(&result, XMMatrixInverse(nullptr, M)); + XMStoreFloat4x4(&result, XMMatrixInverse(nullptr, matrix)); return result; } @@ -401,8 +398,8 @@ namespace SHADE SHMatrix SHMatrix::Translate(const SHVec3& pos) noexcept { SHMatrix result; - XMStoreFloat4x4(&result, XMMatrixTranslation(pos.x, pos.y, pos.z)); + XMStoreFloat4x4(&result, XMMatrixTranslation(pos.x, pos.y, pos.z)); return result; } @@ -410,25 +407,23 @@ namespace SHADE { SHMatrix result; - const XMVECTOR A = XMLoadFloat3(&axis); - XMStoreFloat4x4(&result, XMMatrixRotationAxis(A, angleInRad)); - + XMStoreFloat4x4(&result, XMMatrixRotationAxis(axis, angleInRad)); return result; } SHMatrix SHMatrix::Rotate(float yaw, float pitch, float roll) noexcept { SHMatrix result; - XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(pitch, yaw, roll)); + XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(pitch, yaw, roll)); return result; } SHMatrix SHMatrix::Rotate(const SHVec3& eulerAngles) noexcept { SHMatrix result; - XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(eulerAngles.x, eulerAngles.y, eulerAngles.z)); + XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYawFromVector(eulerAngles)); return result; } @@ -436,57 +431,55 @@ namespace SHADE { SHMatrix result; - const XMVECTOR Q = XMLoadFloat4(&q); - XMStoreFloat4x4(&result, XMMatrixRotationQuaternion(Q)); - + XMStoreFloat4x4(&result, XMMatrixRotationQuaternion(q)); return result; } SHMatrix SHMatrix::RotateX(float angleInRad) noexcept { SHMatrix result; - XMStoreFloat4x4(&result, XMMatrixRotationX(angleInRad)); + XMStoreFloat4x4(&result, XMMatrixRotationX(angleInRad)); return result; } SHMatrix SHMatrix::RotateY(float angleInRad) noexcept { SHMatrix result; - XMStoreFloat4x4(&result, XMMatrixRotationY(angleInRad)); + XMStoreFloat4x4(&result, XMMatrixRotationY(angleInRad)); return result; } SHMatrix SHMatrix::RotateZ(float angleInRad) noexcept { SHMatrix result; - XMStoreFloat4x4(&result, XMMatrixRotationZ(angleInRad)); + XMStoreFloat4x4(&result, XMMatrixRotationZ(angleInRad)); return result; } SHMatrix SHMatrix::Scale(float uniformScaleFactor) noexcept { SHMatrix result; - XMStoreFloat4x4(&result, XMMatrixScaling(uniformScaleFactor, uniformScaleFactor, uniformScaleFactor)); + XMStoreFloat4x4(&result, XMMatrixScaling(uniformScaleFactor, uniformScaleFactor, uniformScaleFactor)); return result; } SHMatrix SHMatrix::Scale(float x, float y, float z) noexcept { SHMatrix result; - XMStoreFloat4x4(&result, XMMatrixScaling(x, y, z)); + XMStoreFloat4x4(&result, XMMatrixScaling(x, y, z)); return result; } SHMatrix SHMatrix::Scale(const SHVec3& scale) noexcept { SHMatrix result; - XMStoreFloat4x4(&result, XMMatrixScaling(scale.x, scale.y, scale.z)); + XMStoreFloat4x4(&result, XMMatrixScalingFromVector(scale)); return result; } @@ -494,12 +487,7 @@ namespace SHADE { SHMatrix result; - const XMVECTOR EYE = XMLoadFloat3(&eye); - const XMVECTOR TGT = XMLoadFloat3(&target); - const XMVECTOR UP = XMLoadFloat3(&up); - - XMStoreFloat4x4(&result, XMMatrixLookAtRH(EYE, TGT, UP)); - + XMStoreFloat4x4(&result, XMMatrixLookAtRH(eye, target, up)); return result; } @@ -507,12 +495,7 @@ namespace SHADE { SHMatrix result; - const XMVECTOR EYE = XMLoadFloat3(&eye); - const XMVECTOR TGT = XMLoadFloat3(&target); - const XMVECTOR UP = XMLoadFloat3(&up); - - XMStoreFloat4x4(&result, XMMatrixLookAtLH(EYE, TGT, UP)); - + XMStoreFloat4x4(&result, XMMatrixLookAtLH(eye, target, up)); return result; } @@ -522,8 +505,8 @@ namespace SHADE const SHVec3 FWD_HAT = SHVec3::Normalise(-forward); - const XMVECTOR Z_HAT = XMVector3Normalize(XMLoadFloat3(&FWD_HAT)); - const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(XMLoadFloat3(&up), Z_HAT)); + const XMVECTOR Z_HAT = XMVector3Normalize(FWD_HAT); + const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(up, Z_HAT)); const XMVECTOR Y_HAT = XMVector3Cross(Z_HAT, X_HAT); XMStoreFloat3(reinterpret_cast(&result._11), X_HAT); @@ -543,8 +526,8 @@ namespace SHADE const SHVec3 FWD_HAT = SHVec3::Normalise(forward); - const XMVECTOR Z_HAT = XMVector3Normalize(XMLoadFloat3(&FWD_HAT)); - const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(XMLoadFloat3(&up), Z_HAT)); + const XMVECTOR Z_HAT = XMVector3Normalize(FWD_HAT); + const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(up, Z_HAT)); const XMVECTOR Y_HAT = XMVector3Cross(Z_HAT, X_HAT); XMStoreFloat3(reinterpret_cast(&result._11), X_HAT); @@ -563,7 +546,6 @@ namespace SHADE SHMatrix result; XMStoreFloat4x4(&result, XMMatrixPerspectiveFovRH(fov, aspectRatio, nearPlane, farPlane)); - return result; } @@ -572,7 +554,6 @@ namespace SHADE SHMatrix result; XMStoreFloat4x4(&result, XMMatrixPerspectiveFovLH(fov, aspectRatio, nearPlane, farPlane)); - return result; } @@ -581,7 +562,6 @@ namespace SHADE SHMatrix result; XMStoreFloat4x4(&result, XMMatrixPerspectiveRH(width, height, nearPlane, farPlane)); - return result; } @@ -590,7 +570,6 @@ namespace SHADE SHMatrix result; XMStoreFloat4x4(&result, XMMatrixPerspectiveLH(width, height, nearPlane, farPlane)); - return result; } @@ -599,7 +578,6 @@ namespace SHADE SHMatrix result; XMStoreFloat4x4(&result, XMMatrixOrthographicRH(width, height, nearPlane, farPlane)); - return result; } @@ -608,7 +586,6 @@ namespace SHADE SHMatrix result; XMStoreFloat4x4(&result, XMMatrixOrthographicLH(width, height, nearPlane, farPlane)); - return result; } diff --git a/SHADE_Engine/src/Math/SHMatrix.h b/SHADE_Engine/src/Math/SHMatrix.h index 7a662478..4d8f1bfe 100644 --- a/SHADE_Engine/src/Math/SHMatrix.h +++ b/SHADE_Engine/src/Math/SHMatrix.h @@ -77,6 +77,8 @@ namespace SHADE SHMatrix& operator= (const SHMatrix& rhs) = default; SHMatrix& operator= (SHMatrix&& rhs) = default; + operator DirectX::XMMATRIX () const noexcept; + SHMatrix& operator+= (const SHMatrix& rhs) noexcept; SHMatrix& operator-= (const SHMatrix& rhs) noexcept; SHMatrix& operator*= (const SHMatrix& rhs) noexcept; diff --git a/SHADE_Engine/src/Math/SHQuaternion.cpp b/SHADE_Engine/src/Math/SHQuaternion.cpp index 33c568a5..3564916a 100644 --- a/SHADE_Engine/src/Math/SHQuaternion.cpp +++ b/SHADE_Engine/src/Math/SHQuaternion.cpp @@ -36,44 +36,18 @@ namespace SHADE : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) {} + SHQuaternion::SHQuaternion(const SHVec4& vec4) noexcept + : XMFLOAT4( vec4.x, vec4.y, vec4.z, vec4.w ) + {} + SHQuaternion::SHQuaternion(float _x, float _y, float _z, float _w) noexcept : XMFLOAT4( _x, _y, _z, _w ) {} - SHQuaternion::SHQuaternion(float yaw, float pitch, float roll) noexcept - : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) - { - XMStoreFloat4(this, XMQuaternionRotationRollPitchYaw(pitch, yaw, roll)); - } - - SHQuaternion::SHQuaternion(const SHVec3& eulerAngles) noexcept - : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) - { - const XMVECTOR V = XMLoadFloat3(&eulerAngles); - XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(V)); - } - - SHQuaternion::SHQuaternion(const SHVec3& axis, float angleInRad) noexcept - : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) - { - const XMVECTOR AXIS = XMLoadFloat3(&axis); - XMStoreFloat4(this, XMQuaternionRotationAxis(AXIS, angleInRad)); - } - - SHQuaternion::SHQuaternion(const SHMatrix& rotationMatrix) noexcept - : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) - { - const XMMATRIX M = XMLoadFloat4x4(&rotationMatrix); - XMStoreFloat4(this, XMQuaternionRotationMatrix(M)); - } - SHQuaternion::SHQuaternion(const reactphysics3d::Vector3& rp3dEuler) noexcept : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) { - const SHVec3& SHADE_VEC{ rp3dEuler }; - - const XMVECTOR V = XMLoadFloat3(&SHADE_VEC); - XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(V)); + XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(SHVec3 { rp3dEuler })); } SHQuaternion::SHQuaternion(const reactphysics3d::Quaternion& rp3dQuat) noexcept @@ -113,10 +87,7 @@ namespace SHADE { SHQuaternion result; - const XMVECTOR Q1 = XMLoadFloat4(this); - const XMVECTOR Q2 = XMLoadFloat4(&rhs); - - XMStoreFloat4(&result, XMVectorAdd(Q1, Q2)); + XMStoreFloat4(&result, XMVectorAdd(*this, rhs)); return result; } @@ -124,10 +95,7 @@ namespace SHADE { SHQuaternion result; - const XMVECTOR Q1 = XMLoadFloat4(this); - const XMVECTOR Q2 = XMLoadFloat4(&rhs); - - XMStoreFloat4(&result, XMVectorSubtract(Q1, Q2)); + XMStoreFloat4(&result, XMVectorSubtract(*this, rhs)); return result; } @@ -135,9 +103,7 @@ namespace SHADE { SHQuaternion result; - const XMVECTOR Q = XMLoadFloat4(this); - - XMStoreFloat4(&result, XMVectorNegate(Q)); + XMStoreFloat4(&result, XMVectorNegate(*this)); return result; } @@ -145,10 +111,7 @@ namespace SHADE { SHQuaternion result; - const XMVECTOR Q1 = XMLoadFloat4(this); - const XMVECTOR Q2 = XMLoadFloat4(&rhs); - - XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q2)); + XMStoreFloat4(&result, XMQuaternionMultiply(*this, rhs)); return result; } @@ -156,9 +119,7 @@ namespace SHADE { SHQuaternion result; - const XMVECTOR Q = XMLoadFloat4(this); - - XMStoreFloat4(&result, XMVectorScale(Q, rhs)); + XMStoreFloat4(&result, XMVectorScale(*this, rhs)); return result; } @@ -166,27 +127,18 @@ namespace SHADE { SHQuaternion result; - const XMVECTOR Q1 = XMLoadFloat4(this); - const XMVECTOR Q2 = XMQuaternionInverse(XMLoadFloat4(&rhs)); - - XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q2)); + XMStoreFloat4(&result, XMQuaternionMultiply(*this, XMQuaternionInverse(rhs))); return result; } bool SHQuaternion::operator==(const SHQuaternion& rhs) const noexcept { - const XMVECTOR Q1 = XMLoadFloat4(this); - const XMVECTOR Q2 = XMLoadFloat4(&rhs); - - return XMQuaternionEqual(Q1, Q2); + return XMQuaternionEqual(*this, rhs); } bool SHQuaternion::operator!=(const SHQuaternion& rhs) const noexcept { - const XMVECTOR Q1 = XMLoadFloat4(this); - const XMVECTOR Q2 = XMLoadFloat4(&rhs); - - return XMQuaternionNotEqual(Q1, Q2); + return XMQuaternionNotEqual(*this, rhs); } SHQuaternion::operator reactphysics3d::Quaternion() const noexcept @@ -199,6 +151,11 @@ namespace SHADE return reactphysics3d::Vector3{ ToEuler() }; } + SHQuaternion::operator XMVECTOR() const noexcept + { + return XMLoadFloat4(this); + } + SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept { return rhs * lhs; @@ -213,8 +170,7 @@ namespace SHADE XMVECTOR axis; float angle; - const XMVECTOR Q = XMLoadFloat4(this); - XMQuaternionToAxisAngle(&axis, &angle, Q); + XMQuaternionToAxisAngle(&axis, &angle, *this); return angle; } @@ -223,8 +179,7 @@ namespace SHADE XMVECTOR axis; float angle; - const XMVECTOR Q = XMLoadFloat4(this); - XMQuaternionToAxisAngle(&axis, &angle, Q); + XMQuaternionToAxisAngle(&axis, &angle, *this); return SHVec4{XMVectorGetX(axis), XMVectorGetY(axis), XMVectorGetZ(axis), angle}; @@ -238,64 +193,49 @@ namespace SHADE void SHQuaternion::Invert() noexcept { - const XMVECTOR Q = XMLoadFloat4(this); - XMStoreFloat4(this, XMQuaternionInverse(Q)); + XMStoreFloat4(this, XMQuaternionInverse(*this)); } float SHQuaternion::Length() const noexcept { - const XMVECTOR Q = XMLoadFloat4(this); - return XMVectorGetX(XMQuaternionLength(Q)); + return XMVectorGetX(XMQuaternionLength(*this)); } float SHQuaternion::LengthSquared() const noexcept { - const XMVECTOR Q = XMLoadFloat4(this); - return XMVectorGetX(XMQuaternionLengthSq(Q)); + return XMVectorGetX(XMQuaternionLengthSq(*this)); } float SHQuaternion::Dot(const SHQuaternion& rhs) const noexcept { - const XMVECTOR Q1 = XMLoadFloat4(this); - const XMVECTOR Q2 = XMLoadFloat4(&rhs); - - return XMVectorGetX(XMQuaternionDot(Q1, Q2)); - } - - SHQuaternion SHQuaternion::RotateTowards(const SHQuaternion&, float) const noexcept - { - SHQuaternion result; - - // TODO (Diren) - - return result; + return XMVectorGetX(XMQuaternionDot(*this, rhs)); } SHVec3 SHQuaternion::ToEuler() const noexcept { - const float xx = x * x; - const float yy = y * y; - const float zz = z * z; + const float XX = x * x; + const float YY = y * y; + const float ZZ = z * z; - 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 M_31 = 2.f * x * z + 2.f * y * w; + const float M_32 = 2.f * y * z - 2.f * x * w; + const float M_33 = 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 CY = sqrtf(M_33 * M_33 + M_31 * M_31); + const float CX = atan2f(-M_32, 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; + const float M_12 = 2.f * x * y + 2.f * z * w; + const float M_22 = 1.f - 2.f * XX - 2.f * ZZ; - return SHVec3(cx, atan2f(m31, m33), atan2f(m12, m22)); + return SHVec3(CX, atan2f(M_31, M_33), atan2f(M_12, M_22)); } else { - const float m11 = 1.f - 2.f * yy - 2.f * zz; - const float m21 = 2.f * x * y - 2.f * z * w; + 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)); + return SHVec3(CX, 0.f, atan2f(-m21, m11)); } } @@ -311,13 +251,43 @@ namespace SHADE /* Static Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ + SHQuaternion SHQuaternion::FromEuler(const SHVec3& eulerAngles) noexcept + { + SHQuaternion result; + + XMStoreFloat4(&result, XMQuaternionRotationRollPitchYawFromVector(eulerAngles)); + return result; + } + + SHQuaternion SHQuaternion::FromPitchYawRoll(float pitch, float yaw, float roll) noexcept + { + SHQuaternion result; + + XMStoreFloat4(&result, XMQuaternionRotationRollPitchYaw(pitch, yaw, roll)); + return result; + } + + SHQuaternion SHQuaternion::FromAxisAngle(const SHVec3& axis, float angle) noexcept + { + SHQuaternion result; + + XMStoreFloat4(&result, XMQuaternionRotationAxis(axis, angle)); + return result; + } + + SHQuaternion SHQuaternion::FromRotationMatrix(const SHMatrix& rotationMatrix) noexcept + { + SHQuaternion result; + + XMStoreFloat4(&result, XMQuaternionRotationMatrix(rotationMatrix)); + return result; + } + SHQuaternion SHQuaternion::Normalise(const SHQuaternion& q) noexcept { SHQuaternion result; - const XMVECTOR Q = XMLoadFloat4(&q); - - XMStoreFloat4(&result, XMQuaternionNormalize(Q)); + XMStoreFloat4(&result, XMQuaternionNormalize(q)); return result; } @@ -325,9 +295,7 @@ namespace SHADE { SHQuaternion result; - const XMVECTOR Q = XMLoadFloat4(&q); - - XMStoreFloat4(&result, XMQuaternionConjugate(Q)); + XMStoreFloat4(&result, XMQuaternionConjugate(q)); return result; } @@ -335,26 +303,37 @@ namespace SHADE { SHQuaternion result; - const XMVECTOR Q = XMLoadFloat4(&q); - XMStoreFloat4(&result, XMQuaternionInverse(Q)); - + XMStoreFloat4(&result, XMQuaternionInverse(q)); return result; } - float SHQuaternion::Angle(const SHQuaternion&, const SHQuaternion&) noexcept + float SHQuaternion::Angle(const SHQuaternion& q1, const SHQuaternion& q2) noexcept { - // TODO (Diren) + XMVECTOR R = XMQuaternionMultiply(XMQuaternionConjugate(q1), q2); - return 0.0f; + const float RS = XMVectorGetW(R); + R = XMVector3Length(R); + return 2.0f * atan2f(XMVectorGetX(R), RS); } - SHQuaternion SHQuaternion::Lerp(const SHQuaternion&, const SHQuaternion&, float) noexcept + SHQuaternion SHQuaternion::Lerp(const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept { SHQuaternion result; - // TODO (Diren) + XMVECTOR R = XMVectorZero(); + if (XMVector4GreaterOrEqual(XMVector4Dot(q1, q2), R)) + { + R = XMVectorLerp(q1, q2, t); + } + else + { + const XMVECTOR X0 = XMVectorMultiply(q1, XMVectorReplicate(1.f - t)); + const XMVECTOR X1 = XMVectorMultiply(q2, XMVectorReplicate(t)); + R = XMVectorSubtract(X0, X1); + } + XMStoreFloat4(&result, XMQuaternionNormalize(R)); return result; } @@ -362,19 +341,105 @@ namespace SHADE { SHQuaternion result; - const XMVECTOR Q1 = XMLoadFloat4(&q1); - const XMVECTOR Q2 = XMLoadFloat4(&q2); - - XMStoreFloat4(&result, XMQuaternionSlerp(Q1, Q2, t)); + XMStoreFloat4(&result, XMQuaternionSlerp(q1, q2, t)); return result; } - SHQuaternion SHQuaternion::Rotate(const SHVec3& , const SHVec3&) noexcept + SHQuaternion SHQuaternion::ClampedLerp(const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin, float tMax) noexcept + { + return Lerp(q1, q2, std::clamp(t, tMin, tMax)); + } + + + SHQuaternion SHQuaternion::ClampedSlerp(const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin, float tMax) noexcept + { + return Slerp(q1, q2, std::clamp(t, tMin, tMax)); + } + + SHQuaternion SHQuaternion::FromToRotation(const SHVec3& from, const SHVec3& to) noexcept + { + // Melax, "The Shortest Arc Quaternion", Game Programming Gems + + SHQuaternion result; + + const XMVECTOR F = XMVector3Normalize(from); + const XMVECTOR T = XMVector3Normalize(to); + + const float dot = XMVectorGetX(XMVector3Dot(F, T)); + if (dot >= 1.f) + { + result = Identity; + } + else if (dot <= -1.f) + { + XMVECTOR axis = XMVector3Cross(F, SHVec3::Right); + if (XMVector3NearEqual(XMVector3LengthSq(axis), g_XMZero, g_XMEpsilon)) + { + axis = XMVector3Cross(F, SHVec3::Up); + } + + const XMVECTOR Q = XMQuaternionRotationAxis(axis, XM_PI); + XMStoreFloat4(&result, Q); + } + else + { + const XMVECTOR C = XMVector3Cross(F, T); + XMStoreFloat4(&result, C); + + const float s = sqrtf((1.f + dot) * 2.f); + result.x /= s; + result.y /= s; + result.z /= s; + result.w = s * 0.5f; + } + + return result; + } + + SHQuaternion SHQuaternion::LookRotation(const SHVec3& forward, const SHVec3& up) noexcept { SHQuaternion result; - // TODO (Diren) + const SHQuaternion Q1 = FromToRotation(SHVec3::Forward, forward); + const XMVECTOR C = XMVector3Cross(forward, up); + if (XMVector3NearEqual(XMVector3LengthSq(C), g_XMZero, g_XMEpsilon)) + { + // forward and up are co-linear + return Q1; + } + + SHVec3 qU; + XMStoreFloat3(&qU, XMQuaternionMultiply(Q1, SHVec3::Up)); + + const SHQuaternion Q2 = FromToRotation(qU, up); + + XMStoreFloat4(&result, XMQuaternionMultiply(Q2, Q1)); + + return result; + } + + SHQuaternion SHQuaternion::RotateTowards(const SHQuaternion& from, const SHQuaternion& to, float maxAngleInRad) noexcept + { + SHQuaternion result; + + // We can use the conjugate here instead of inverse assuming q1 & q2 are normalized. + const XMVECTOR R = XMQuaternionMultiply(XMQuaternionConjugate(from), to); + + const float RS = XMVectorGetW(R); + const XMVECTOR L = XMVector3Length(R); + const float angle = 2.f * atan2f(XMVectorGetX(L), RS); + if (angle > maxAngleInRad) + { + const XMVECTOR delta = XMQuaternionRotationAxis(R, maxAngleInRad); + const XMVECTOR Q = XMQuaternionMultiply(delta, from); + XMStoreFloat4(&result, Q); + } + else + { + // Don't overshoot. + result = to; + } return result; } diff --git a/SHADE_Engine/src/Math/SHQuaternion.h b/SHADE_Engine/src/Math/SHQuaternion.h index c94907b5..fa5b5d36 100644 --- a/SHADE_Engine/src/Math/SHQuaternion.h +++ b/SHADE_Engine/src/Math/SHQuaternion.h @@ -49,11 +49,8 @@ namespace SHADE SHQuaternion (SHQuaternion&& rhs) = default; SHQuaternion () noexcept; + SHQuaternion (const SHVec4& vec4) noexcept; SHQuaternion (float x, float y, float z, float w) noexcept; - SHQuaternion (float yaw, float pitch, float roll) noexcept; - SHQuaternion (const SHVec3& eulerAngles) noexcept; - SHQuaternion (const SHVec3& axis, float angleInRad) noexcept; - SHQuaternion (const SHMatrix& rotationMatrix) noexcept; // Conversion from other math types @@ -87,6 +84,7 @@ namespace SHADE operator reactphysics3d::Quaternion () const noexcept; operator reactphysics3d::Vector3 () const noexcept; + operator DirectX::XMVECTOR () const noexcept; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ @@ -99,29 +97,37 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ - void Invert () noexcept; + void Invert () noexcept; - [[nodiscard]] float Length () const noexcept; - [[nodiscard]] float LengthSquared () const noexcept; - [[nodiscard]] float Dot (const SHQuaternion& rhs) const noexcept; - [[nodiscard]] SHQuaternion RotateTowards (const SHQuaternion& target, float maxAngleInRad) const noexcept; + [[nodiscard]] float Length () const noexcept; + [[nodiscard]] float LengthSquared () const noexcept; + [[nodiscard]] float Dot (const SHQuaternion& rhs) const noexcept; - [[nodiscard]] SHVec3 ToEuler () const noexcept; - [[nodiscard]] std::string ToString () const noexcept; + [[nodiscard]] SHVec3 ToEuler () const noexcept; + [[nodiscard]] std::string ToString () const noexcept; /*---------------------------------------------------------------------------------*/ /* Static Function Members */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] static SHQuaternion Normalise (const SHQuaternion& q) noexcept; - [[nodiscard]] static SHQuaternion Conjugate (const SHQuaternion& q) noexcept; - [[nodiscard]] static SHQuaternion Inverse (const SHQuaternion& q) noexcept; - [[nodiscard]] static float Angle (const SHQuaternion& q1, const SHQuaternion& q2) noexcept; + [[nodiscard]] static SHQuaternion FromEuler (const SHVec3& eulerAngles) noexcept; + [[nodiscard]] static SHQuaternion FromPitchYawRoll (float pitch, float yaw, float roll) noexcept; + [[nodiscard]] static SHQuaternion FromAxisAngle (const SHVec3& axis, float angle) noexcept; + [[nodiscard]] static SHQuaternion FromRotationMatrix(const SHMatrix& rotationMatrix) noexcept; - [[nodiscard]] static SHQuaternion Lerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept; - [[nodiscard]] static SHQuaternion Slerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept; + [[nodiscard]] static SHQuaternion Normalise (const SHQuaternion& q) noexcept; + [[nodiscard]] static SHQuaternion Conjugate (const SHQuaternion& q) noexcept; + [[nodiscard]] static SHQuaternion Inverse (const SHQuaternion& q) noexcept; + [[nodiscard]] static float Angle (const SHQuaternion& q1, const SHQuaternion& q2) noexcept; - [[nodiscard]] static SHQuaternion Rotate (const SHVec3& from, const SHVec3& to) noexcept; + [[nodiscard]] static SHQuaternion Lerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept; + [[nodiscard]] static SHQuaternion Slerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept; + [[nodiscard]] static SHQuaternion ClampedLerp (const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept; + [[nodiscard]] static SHQuaternion ClampedSlerp (const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept; + + [[nodiscard]] static SHQuaternion FromToRotation (const SHVec3& from, const SHVec3& to) noexcept; + [[nodiscard]] static SHQuaternion LookRotation (const SHVec3& forward, const SHVec3& up) noexcept; + [[nodiscard]] static SHQuaternion RotateTowards (const SHQuaternion& from, const SHQuaternion& to, float maxAngleInRad) noexcept; }; SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept; diff --git a/SHADE_Engine/src/Math/Transform/SHTransform.cpp b/SHADE_Engine/src/Math/Transform/SHTransform.cpp index f51d73ec..ef7c5fda 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransform.cpp +++ b/SHADE_Engine/src/Math/Transform/SHTransform.cpp @@ -26,15 +26,15 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHTransform::SHTransform() noexcept - : position { SHVec3::Zero } - , rotation { SHVec3::Zero } - , scale { SHVec3::One } + : position { SHVec3::Zero } + , orientation { SHQuaternion::Identity } + , scale { SHVec3::One } {} SHTransform::SHTransform(const SHVec3& pos, const SHVec3& rot, const SHVec3& scl) noexcept - : position { pos } - , rotation { rot } - , scale { scl } + : position { pos } + , orientation { SHQuaternion::FromEuler(rot) } + , scale { scl } {} /*-----------------------------------------------------------------------------------*/ @@ -43,12 +43,12 @@ namespace SHADE bool SHTransform::operator==(const SHTransform& rhs) const noexcept { - return !(position != rhs.position || rotation != rhs.rotation || scale != rhs.scale); + return !(position != rhs.position || orientation != rhs.orientation || scale != rhs.scale); } bool SHTransform::operator!=(const SHTransform& rhs) const noexcept { - return (position != rhs.position || rotation != rhs.rotation || scale != rhs.scale); + return (position != rhs.position || orientation != rhs.orientation || scale != rhs.scale); } /*-----------------------------------------------------------------------------------*/ @@ -59,7 +59,7 @@ namespace SHADE { const SHMatrix T = SHMatrix::Translate(position); - const SHMatrix R = SHMatrix::Rotate(rotation); + const SHMatrix R = SHMatrix::Rotate(orientation); const SHMatrix S = SHMatrix::Scale(scale); trs = S * R * T; diff --git a/SHADE_Engine/src/Math/Transform/SHTransform.h b/SHADE_Engine/src/Math/Transform/SHTransform.h index c1a0e565..2e7d236c 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransform.h +++ b/SHADE_Engine/src/Math/Transform/SHTransform.h @@ -12,8 +12,8 @@ // Project Headers #include "SH_API.h" -#include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec3.h" +#include "Math/SHQuaternion.h" #include "Math/SHMatrix.h" namespace SHADE @@ -31,22 +31,23 @@ namespace SHADE static const SHTransform Identity; - SHVec3 position; - SHVec3 rotation; - SHVec3 scale; + SHVec3 position; + SHQuaternion orientation; + SHVec3 scale; - SHMatrix trs; + SHMatrix trs; /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHTransform (const SHTransform&) = default; - SHTransform (SHTransform&&) = default; - ~SHTransform () = default; + SHTransform (const SHTransform&) = default; + SHTransform (SHTransform&&) = default; + ~SHTransform () = default; - SHTransform () noexcept; - SHTransform (const SHVec3& pos, const SHVec3& rot, const SHVec3& scl) noexcept; + SHTransform () noexcept; + SHTransform (const SHVec3& pos, const SHVec3& rot, const SHVec3& scl) noexcept; + SHTransform (const SHVec3& pos, const SHQuaternion& quat, const SHVec3& scl) noexcept; /*---------------------------------------------------------------------------------*/ /* Operator Overloads */ @@ -63,7 +64,6 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ const SHMatrix& ComputeTRS(); - }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp b/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp index 949cfa67..e56cbc8d 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp +++ b/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp @@ -12,6 +12,8 @@ // Primary Header #include "SHTransformComponent.h" +// Project Headers +#include "Math/SHMathHelpers.h" namespace SHADE { @@ -40,7 +42,12 @@ namespace SHADE const SHVec3& SHTransformComponent::GetLocalRotation() const noexcept { - return local.rotation; + return localRotation; + } + + const SHQuaternion& SHTransformComponent::GetLocalOrientation() const noexcept + { + return local.orientation; } const SHVec3& SHTransformComponent::GetLocalScale() const noexcept @@ -55,7 +62,12 @@ namespace SHADE const SHVec3& SHTransformComponent::GetWorldRotation() const noexcept { - return world.rotation; + return worldRotation; + } + + const SHQuaternion& SHTransformComponent::GetWorldOrientation() const noexcept + { + return world.orientation; } const SHVec3& SHTransformComponent::GetWorldScale() const noexcept @@ -91,16 +103,28 @@ namespace SHADE void SHTransformComponent::SetLocalRotation(const SHVec3& newLocalRotation) noexcept { dirty = true; - local.rotation = newLocalRotation; + + localRotation = newLocalRotation; + updateQueue.push({ UpdateCommandType::LOCAL_ROTATION, newLocalRotation }); } void SHTransformComponent::SetLocalRotation(float pitch, float yaw, float roll) noexcept { dirty = true; - local.rotation.x = pitch; - local.rotation.y = yaw; - local.rotation.z = roll; + localRotation.x = pitch; + localRotation.y = yaw; + localRotation.z = roll; + + updateQueue.push({ UpdateCommandType::LOCAL_ROTATION, SHVec3{pitch, yaw, roll} }); + } + + void SHTransformComponent::SetLocalOrientation(const SHQuaternion& newLocalOrientation) noexcept + { + dirty = true; + + local.orientation = newLocalOrientation; + updateQueue.push({ UpdateCommandType::LOCAL_ORIENTATION, newLocalOrientation }); } void SHTransformComponent::SetLocalScale(const SHVec3& newLocalScale) noexcept @@ -121,7 +145,7 @@ namespace SHADE { dirty = true; - world.rotation = newWorldRotation; + worldRotation = newWorldRotation; updateQueue.push({ UpdateCommandType::WORLD_ROTATION, newWorldRotation }); } @@ -129,13 +153,21 @@ namespace SHADE { dirty = true; - world.rotation.x = pitch; - world.rotation.y = yaw; - world.rotation.z = roll; + worldRotation.x = pitch; + worldRotation.y = yaw; + worldRotation.z = roll; updateQueue.push({ UpdateCommandType::WORLD_ROTATION, SHVec3{ pitch, yaw, roll} }); } + void SHTransformComponent::SetWorldOrientation(const SHQuaternion& newWorldOrientation) noexcept + { + dirty = true; + + world.orientation = newWorldOrientation; + updateQueue.push({ UpdateCommandType::WORLD_ORIENTATION, newWorldOrientation }); + } + void SHTransformComponent::SetWorldScale(const SHVec3& newWorldScale) noexcept { dirty = true; @@ -153,6 +185,6 @@ RTTR_REGISTRATION registration::class_("Transform Component") .property("Translate" , &SHTransformComponent::GetLocalPosition , &SHTransformComponent::SetLocalPosition ) - .property("Rotate" , &SHTransformComponent::GetLocalRotation , select_overload(&SHTransformComponent::SetLocalRotation) ) + .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 ad355694..2fe67bdd 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransformComponent.h +++ b/SHADE_Engine/src/Math/Transform/SHTransformComponent.h @@ -56,42 +56,52 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] bool HasChanged () const noexcept; + [[nodiscard]] bool HasChanged () const noexcept; - [[nodiscard]] const SHVec3& GetLocalPosition () const noexcept; - [[nodiscard]] const SHVec3& GetLocalRotation () const noexcept; - [[nodiscard]] const SHVec3& GetLocalScale () const noexcept; - [[nodiscard]] const SHVec3& GetWorldPosition () const noexcept; - [[nodiscard]] const SHVec3& GetWorldRotation () const noexcept; - [[nodiscard]] const SHVec3& GetWorldScale () const noexcept; + [[nodiscard]] const SHVec3& GetLocalPosition () const noexcept; + [[nodiscard]] const SHVec3& GetLocalRotation () const noexcept; + [[nodiscard]] const SHQuaternion& GetLocalOrientation () const noexcept; + [[nodiscard]] const SHVec3& GetLocalScale () const noexcept; + [[nodiscard]] const SHVec3& GetWorldPosition () const noexcept; + [[nodiscard]] const SHVec3& GetWorldRotation () const noexcept; + [[nodiscard]] const SHQuaternion& GetWorldOrientation () const noexcept; + [[nodiscard]] const SHVec3& GetWorldScale () const noexcept; - [[nodiscard]] const SHMatrix& GetLocalToWorld () const noexcept; - [[nodiscard]] SHMatrix GetWorldToLocal () const noexcept; + [[nodiscard]] const SHMatrix& GetLocalToWorld () const noexcept; + [[nodiscard]] SHMatrix GetWorldToLocal () const noexcept; - [[nodiscard]] const SHMatrix& GetTRS () const noexcept; + [[nodiscard]] const SHMatrix& GetTRS () const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetLocalPosition (const SHVec3& newLocalPosition) noexcept; - void SetLocalRotation (const SHVec3& newLocalRotation) noexcept; - void SetLocalRotation (float pitch, float yaw, float roll) noexcept; - void SetLocalScale (const SHVec3& newLocalScale) noexcept; - void SetWorldPosition (const SHVec3& newWorldPosition) noexcept; - void SetWorldRotation (const SHVec3& newWorldRotation) noexcept; - void SetWorldRotation (float pitch, float yaw, float roll) noexcept; - void SetWorldScale (const SHVec3& newWorldScale) noexcept; + void SetLocalPosition (const SHVec3& newLocalPosition) noexcept; + void SetLocalRotation (const SHVec3& newLocalRotation) noexcept; + void SetLocalRotation (float pitch, float yaw, float roll) noexcept; + void SetLocalOrientation (const SHQuaternion& newLocalOrientation) noexcept; + void SetLocalScale (const SHVec3& newLocalScale) noexcept; + void SetWorldPosition (const SHVec3& newWorldPosition) noexcept; + void SetWorldRotation (const SHVec3& newWorldRotation) noexcept; + void SetWorldRotation (float pitch, float yaw, float roll) noexcept; + void SetWorldOrientation (const SHQuaternion& newWorldOrientation) noexcept; + void SetWorldScale (const SHVec3& newWorldScale) noexcept; private: /*---------------------------------------------------------------------------------*/ /* Type Definitions */ /*---------------------------------------------------------------------------------*/ + // Differentiate between rotation and orientation for setters + // Setting a quaternion directly is different from using euler angle rotations. + enum class UpdateCommandType { - WORLD_POSITION + LOCAL_ROTATION + , LOCAL_ORIENTATION + , WORLD_POSITION , WORLD_ROTATION + , WORLD_ORIENTATION , WORLD_SCALE }; @@ -103,7 +113,7 @@ namespace SHADE /*-------------------------------------------------------------------------------*/ UpdateCommandType type; - SHVec3 data; + SHVec4 data; }; using UpdateQueue = std::queue; @@ -114,6 +124,12 @@ namespace SHADE bool dirty; + // We store euler angle rotations separately to interface with transform quaternions. + // Reading quaternions are unreliable. + + SHVec3 localRotation; // Stored in Radians + SHVec3 worldRotation; // Stored in Radians + SHTransform local; // Local TRS holds Local To World Transform SHTransform world; diff --git a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp index 6b05e323..5a540cd4 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp +++ b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp @@ -17,7 +17,8 @@ #include "Scene/SHSceneManager.h" #include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHEntityManager.h" -#include "Tools/SHException.h" +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Math/SHMathHelpers.h" namespace SHADE { @@ -29,8 +30,12 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHTransformSystem::TransformUpdateRoutine::TransformUpdateRoutine() - : SHSystemRoutine { "Transform Update", true } + SHTransformSystem::TransformPostLogicUpdate::TransformPostLogicUpdate() + : SHSystemRoutine { "Transform Post-Logic Update", true } + {} + + SHTransformSystem::TransformPostPhysicsUpdate::TransformPostPhysicsUpdate() + : SHSystemRoutine { "Transform Post-Physics Update", false } {} @@ -38,16 +43,27 @@ namespace SHADE /* Public Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHTransformSystem::TransformUpdateRoutine::Execute(double) noexcept + void SHTransformSystem::TransformPostLogicUpdate::Execute(double) noexcept { // Get the current scene graph to traverse and update const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph(); - UpdateEntity(SCENE_GRAPH.GetRoot()); + + // TODO(Diren): Consider how to clear dirty in pause / stop mode and update physics, but do not clear in play mode. + UpdateEntity(SCENE_GRAPH.GetRoot(), false); + } + + void SHTransformSystem::TransformPostPhysicsUpdate::Execute(double) noexcept + { + // Get the current scene graph to traverse and update + const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph(); + UpdateEntity(SCENE_GRAPH.GetRoot(), true); } void SHTransformSystem::Init() { - + std::shared_ptr thisReceiver { std::make_shared>(this, &SHTransformSystem::ChangeParent) }; + ReceiverPtr receiver = std::dynamic_pointer_cast(thisReceiver); + SHEventManager::SubscribeTo(SH_SCENEGRAPH_CHANGE_PARENT_EVENT, receiver); } void SHTransformSystem::Exit() @@ -59,7 +75,97 @@ namespace SHADE /* Private Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHTransformSystem::UpdateEntity(const SHSceneNode* node) + SHEventHandle SHTransformSystem::ChangeParent(SHEventPtr changeParentEvent) + { + const auto& eventData = reinterpret_cast*>(changeParentEvent.get()); + + auto* node = eventData->data->node; + auto* tf = SHComponentManager::GetComponent_s(node->GetEntityID()); + + // Recompute local transform and store localToWorld Matrix + SHMatrix localToWorld = SHMatrix::Identity; + SHMatrix worldToLocal = SHMatrix::Identity; + + auto* newParent = eventData->data->newParent; + const auto* PARENT_TF = SHComponentManager::GetComponent_s(newParent->GetEntityID()); + if (PARENT_TF != nullptr) // Not the root + { + localToWorld = PARENT_TF->GetTRS(); + worldToLocal = SHMatrix::Inverse(localToWorld); + } + + // Maintain World Transform and recompute Local Transform + + // Compute Local Position + tf->local.position = SHVec3::Transform(tf->world.position, worldToLocal); + + + tf->localRotation = tf->worldRotation; + tf->local.scale = tf->world.scale; + + if (PARENT_TF != nullptr) + { + // Compute Local Rotation + tf->localRotation -= PARENT_TF->GetLocalRotation(); + + // Compute Local Scale + tf->local.scale /= PARENT_TF->GetLocalScale(); + } + + tf->local.trs = localToWorld; + + // Propagate maintaining world transform down the branch + UpdateChildrenLocalTransforms(node); + return eventData->handle; + } + + void SHTransformSystem::UpdateChildrenLocalTransforms(SHSceneNode* node) + { + // Structure is similar to update entity, albeit without a queue to do being a forced update + for (const auto* child : node->GetChildren()) + { + if (auto* childTransform = SHComponentManager::GetComponent_s(child->GetEntityID()); childTransform) + { + const bool IS_NODE_ACTIVE = child->IsActive(); + if (IS_NODE_ACTIVE && childTransform->isActive) + { + // Recompute local transform and store localToWorld Matrix + SHMatrix localToWorld = SHMatrix::Identity; + SHMatrix worldToLocal = SHMatrix::Identity; + + const auto* parent = SHComponentManager::GetComponent_s(node->GetEntityID()); + + if (parent != nullptr) // Not the root + { + localToWorld = parent->GetTRS(); + worldToLocal = SHMatrix::Inverse(localToWorld); + } + + // Maintain World Transform and recompute Local Transform + + // Compute Local Position + childTransform->local.position = SHVec3::Transform(childTransform->world.position, worldToLocal); + + + childTransform->localRotation = childTransform->worldRotation; + childTransform->local.scale = childTransform->world.scale; + + if (parent) + { + // Compute Local Rotation + childTransform->localRotation -= parent->GetLocalRotation(); + + // Compute Local Scale + childTransform->local.scale /= parent->GetLocalScale(); + } + + childTransform->local.trs = localToWorld; + } + } + } + } + + void SHTransformSystem::UpdateEntity(const SHSceneNode* node, bool clearDirtyFlag) { const auto* NODE_TRANSFORM = SHComponentManager::GetComponent_s(node->GetEntityID()); const bool HAS_PARENT_CHANGED = NODE_TRANSFORM && NODE_TRANSFORM->dirty; @@ -74,14 +180,17 @@ namespace SHADE if (IS_NODE_ACTIVE && childTransform->isActive) { if (childTransform->dirty || HAS_PARENT_CHANGED) + { UpdateTransform(*childTransform, NODE_TRANSFORM); + childTransform->dirty = true; + } } } - UpdateEntity(child); + UpdateEntity(child, clearDirtyFlag); // Clear dirty flag after all children are updated - if (childTransform) + if (childTransform && clearDirtyFlag) childTransform->dirty = false; } } @@ -91,6 +200,8 @@ namespace SHADE SHMatrix localToWorld = SHMatrix::Identity; SHMatrix worldToLocal = SHMatrix::Identity; + bool convertRotation = true; + if (parent) { localToWorld = parent->GetTRS(); @@ -103,22 +214,44 @@ namespace SHADE switch (UPDATE_COMMAND.type) { + case SHTransformComponent::UpdateCommandType::LOCAL_ROTATION: + { + convertRotation = true; + break; + } + case SHTransformComponent::UpdateCommandType::LOCAL_ORIENTATION: + { + convertRotation = false; + break; + } case SHTransformComponent::UpdateCommandType::WORLD_POSITION: { - tf.local.position = SHVec3::Transform(UPDATE_COMMAND.data, worldToLocal); + tf.local.position = SHVec3::Transform(UPDATE_COMMAND.data.ToVec3(), worldToLocal); break; } case SHTransformComponent::UpdateCommandType::WORLD_ROTATION: { - tf.local.rotation = tf.world.rotation; + tf.localRotation = UPDATE_COMMAND.data.ToVec3(); if (parent) - tf.local.rotation -= parent->GetLocalRotation(); + tf.localRotation -= parent->GetLocalRotation(); + + convertRotation = true; + + break; + } + case SHTransformComponent::UpdateCommandType::WORLD_ORIENTATION: + { + tf.local.orientation = UPDATE_COMMAND.data; + if (parent) + tf.local.orientation /= parent->GetLocalOrientation(); + + convertRotation = false; break; } case SHTransformComponent::UpdateCommandType::WORLD_SCALE: { - tf.local.scale = tf.world.scale; + tf.local.scale = UPDATE_COMMAND.data.ToVec3(); if (parent) tf.local.scale /= parent->GetLocalScale(); @@ -133,15 +266,38 @@ namespace SHADE tf.local.trs = localToWorld; + // Compute world transforms tf.world.position = SHVec3::Transform(tf.local.position, localToWorld); - tf.world.rotation = tf.local.rotation + (parent ? parent->GetLocalRotation() : SHVec3::Zero); tf.world.scale = tf.local.scale * (parent ? parent->GetLocalScale() : SHVec3::One); - tf.world.ComputeTRS(); + - // Transpose TRS to column major - //tf.local.trs.Transpose(); - //tf.world.trs.Transpose(); + if (convertRotation) + { + tf.worldRotation = tf.localRotation + (parent ? parent->GetLocalRotation() : SHVec3::Zero); + + // Set the orientation + // Wrap rotations between -360 and 360 and convert to radians + SHVec3 worldRotRad, localRotRad; + for (size_t i = 0; i < SHVec3::SIZE; ++i) + { + worldRotRad[i] = SHMath::Wrap(tf.worldRotation[i], -SHMath::TWO_PI, SHMath::TWO_PI); + localRotRad[i] = SHMath::Wrap(tf.localRotation[i], -SHMath::TWO_PI, SHMath::TWO_PI); + } + + tf.world.orientation = SHQuaternion::FromEuler(worldRotRad); + tf.local.orientation = SHQuaternion::FromEuler(localRotRad); + } + else + { + tf.world.orientation = (parent ? parent->GetLocalOrientation() : SHQuaternion::Identity) * tf.local.orientation; + + // Set the euler angle rotations + tf.worldRotation = tf.world.orientation.ToEuler(); + tf.localRotation = tf.local.orientation.ToEuler(); + } + + tf.world.ComputeTRS(); } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Transform/SHTransformSystem.h b/SHADE_Engine/src/Math/Transform/SHTransformSystem.h index 02c3b6c6..e63969ce 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransformSystem.h +++ b/SHADE_Engine/src/Math/Transform/SHTransformSystem.h @@ -45,25 +45,52 @@ namespace SHADE /* System Routines */ /*---------------------------------------------------------------------------------*/ - class SH_API TransformUpdateRoutine final: public SHSystemRoutine + class SH_API TransformPostLogicUpdate final: public SHSystemRoutine { public: /*-------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*-------------------------------------------------------------------------------*/ - TransformUpdateRoutine (); - ~TransformUpdateRoutine () = default; + TransformPostLogicUpdate (); + ~TransformPostLogicUpdate () = default; - TransformUpdateRoutine (const TransformUpdateRoutine&) = delete; - TransformUpdateRoutine (TransformUpdateRoutine&&) = delete; + TransformPostLogicUpdate (const TransformPostLogicUpdate&) = delete; + TransformPostLogicUpdate (TransformPostLogicUpdate&&) = delete; /*-------------------------------------------------------------------------------*/ /* Operator Overloads */ /*-------------------------------------------------------------------------------*/ - TransformUpdateRoutine& operator= (const TransformUpdateRoutine&) = delete; - TransformUpdateRoutine& operator= (TransformUpdateRoutine&&) = delete; + TransformPostLogicUpdate& operator= (const TransformPostLogicUpdate&) = delete; + TransformPostLogicUpdate& operator= (TransformPostLogicUpdate&&) = delete; + + /*-------------------------------------------------------------------------------*/ + /* Function Members */ + /*-------------------------------------------------------------------------------*/ + + void Execute(double dt) noexcept override; + }; + + class SH_API TransformPostPhysicsUpdate final: public SHSystemRoutine + { + public: + /*-------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*-------------------------------------------------------------------------------*/ + + TransformPostPhysicsUpdate (); + ~TransformPostPhysicsUpdate () = default; + + TransformPostPhysicsUpdate (const TransformPostPhysicsUpdate&) = delete; + TransformPostPhysicsUpdate (TransformPostPhysicsUpdate&&) = delete; + + /*-------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*-------------------------------------------------------------------------------*/ + + TransformPostPhysicsUpdate& operator= (const TransformPostPhysicsUpdate&) = delete; + TransformPostPhysicsUpdate& operator= (TransformPostPhysicsUpdate&&) = delete; /*-------------------------------------------------------------------------------*/ /* Function Members */ @@ -84,8 +111,11 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ - static void UpdateEntity (const SHSceneNode* node); - static void UpdateTransform(SHTransformComponent& tf, const SHTransformComponent* parent = nullptr); + SHEventHandle ChangeParent (SHEventPtr changeParentEvent); + static void UpdateChildrenLocalTransforms (SHSceneNode* node); + + static void UpdateEntity (const SHSceneNode* node, bool clearDirtyFlag); + static void UpdateTransform (SHTransformComponent& tf, const SHTransformComponent* parent = nullptr); }; diff --git a/SHADE_Engine/src/Math/Vector/SHVec4.cpp b/SHADE_Engine/src/Math/Vector/SHVec4.cpp index bcf2ef97..9857818a 100644 --- a/SHADE_Engine/src/Math/Vector/SHVec4.cpp +++ b/SHADE_Engine/src/Math/Vector/SHVec4.cpp @@ -38,6 +38,10 @@ namespace SHADE : XMFLOAT4( 0.0f, 0.0f, 0.0f, 0.0f ) {} + SHVec4::SHVec4(const SHVec3& vec3) noexcept + : XMFLOAT4( vec3.x, vec3.y, vec3.z, 1.0f ) + {} + SHVec4::SHVec4(const XMFLOAT4& xmfloat4) noexcept : XMFLOAT4( xmfloat4.x, xmfloat4.y, xmfloat4.z, xmfloat4.w ) {} @@ -271,6 +275,11 @@ namespace SHADE return result; } + SHVec3 SHVec4::ToVec3() const noexcept + { + return SHVec3{ x, y, z }; + } + /*-----------------------------------------------------------------------------------*/ /* Static Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Math/Vector/SHVec4.h b/SHADE_Engine/src/Math/Vector/SHVec4.h index 911a714e..ce341bed 100644 --- a/SHADE_Engine/src/Math/Vector/SHVec4.h +++ b/SHADE_Engine/src/Math/Vector/SHVec4.h @@ -16,6 +16,7 @@ // Project Headers #include "SH_API.h" +#include "SHVec3.h" namespace SHADE { @@ -53,6 +54,7 @@ namespace SHADE ~SHVec4 () = default; SHVec4 () noexcept; + SHVec4 (const SHVec3& vec3) noexcept; SHVec4 (const XMFLOAT4& xmfloat4) noexcept; SHVec4 (float x, float y, float z, float w) noexcept; @@ -102,16 +104,18 @@ namespace SHADE [[nodiscard]] float Dot3D (const SHVec4& rhs) const noexcept; [[nodiscard]] SHVec4 Cross3D (const SHVec4& rhs) const noexcept; [[nodiscard]] SHVec4 Cross (const SHVec4& v1, const SHVec4& v2) const noexcept; + + [[nodiscard]] SHVec3 ToVec3 () const noexcept; /*---------------------------------------------------------------------------------*/ /* Static Function Members */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] static SHVec4 Normalise (const SHVec4& v) noexcept; - [[nodiscard]] static SHVec4 Normalise3D (const SHVec4& v) noexcept; - [[nodiscard]] static SHVec4 Abs (const SHVec4& v) noexcept; - [[nodiscard]] static SHVec4 Min (const std::initializer_list& vs) noexcept; - [[nodiscard]] static SHVec4 Max (const std::initializer_list& vs) noexcept; + [[nodiscard]] static SHVec4 Normalise (const SHVec4& v) noexcept; + [[nodiscard]] static SHVec4 Normalise3D (const SHVec4& v) noexcept; + [[nodiscard]] static SHVec4 Abs (const SHVec4& v) noexcept; + [[nodiscard]] static SHVec4 Min (const std::initializer_list& vs) noexcept; + [[nodiscard]] static SHVec4 Max (const std::initializer_list& vs) noexcept; [[nodiscard]] static SHVec4 Clamp (const SHVec4& v, const SHVec4& vMin, const SHVec4& vMax) noexcept; [[nodiscard]] static SHVec4 Lerp (const SHVec4& a, const SHVec4& b, float t) noexcept; [[nodiscard]] static SHVec4 ClampedLerp (const SHVec4& a, const SHVec4& b, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept; diff --git a/SHADE_Engine/src/Physics/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/SHPhysicsObject.cpp index 36f7c57e..f9b476ef 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsObject.cpp +++ b/SHADE_Engine/src/Physics/SHPhysicsObject.cpp @@ -140,12 +140,12 @@ namespace SHADE isRigidBody = true; rb->position = tf->GetWorldPosition(); - rb->orientation = tf->GetWorldRotation(); + rb->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation()); if (hasColliders) { c->position = tf->GetWorldPosition(); - c->orientation = tf->GetWorldRotation(); + c->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation()); // Get array of colliders and add them back into the rigidbody for (auto& collider : c->colliders | std::views::keys) AddCollider(&collider); @@ -160,7 +160,7 @@ namespace SHADE hasColliders = true; c->position = tf->GetWorldPosition(); - c->orientation = tf->GetWorldRotation(); + c->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation()); for (auto& collider : c->colliders | std::views::keys) AddCollider(&collider); diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp index 7dc6c44e..a1994ad2 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp @@ -16,6 +16,7 @@ // Project Headers #include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHEntityManager.h" +#include "Math/SHMathHelpers.h" #include "Scene/SHSceneManager.h" #include "Math/Transform/SHTransformComponent.h" @@ -315,7 +316,7 @@ namespace SHADE if (TF->HasChanged()) { physicsObject.SetPosition(TF->GetWorldPosition()); - physicsObject.SetRotation(TF->GetWorldRotation()); + physicsObject.SetOrientation(TF->GetWorldOrientation()); } } } @@ -492,8 +493,7 @@ namespace SHADE // Convert RP3D Transform to SHADE auto* tfComponent = SHComponentManager::GetComponent(entityID); tfComponent->SetWorldPosition(rp3dPos); - tfComponent->SetWorldRotation(SHQuaternion{ rp3dRot }.ToEuler()); - + tfComponent->SetWorldOrientation(SHQuaternion{ rp3dRot }); // Cache transforms physicsObject.prevTransform = CURRENT_TF; diff --git a/SHADE_Engine/src/Resource/Handle.h b/SHADE_Engine/src/Resource/SHHandle.h similarity index 76% rename from SHADE_Engine/src/Resource/Handle.h rename to SHADE_Engine/src/Resource/SHHandle.h index 9579063c..6acc85ed 100644 --- a/SHADE_Engine/src/Resource/Handle.h +++ b/SHADE_Engine/src/Resource/SHHandle.h @@ -8,8 +8,9 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Forward Declarations */ /*---------------------------------------------------------------------------------*/ + class SHResourceLibraryBase; template - class ResourceLibrary; + class SHResourceLibrary; /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -25,6 +26,20 @@ namespace SHADE using std::runtime_error::runtime_error; }; + /// + /// Exception thrown when a generic Handle is being casted to the wrong type. + /// + class BadHandleCastException : std::runtime_error + { + public: + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + BadHandleCastException() + : std::runtime_error("Attempted to cast a generic Handle to the wrong type. ") + {} + }; + /// /// Base implementation of the Handle that is not templated to allow for holding /// generic non-type-specific Handles. @@ -80,7 +95,7 @@ namespace SHADE /// Generic implementation of a Handle object /// /// Type of the handle. - template + template class Handle : public HandleBase { public: @@ -88,6 +103,16 @@ namespace SHADE /* Constructors */ /*-----------------------------------------------------------------------------*/ Handle() = default; + /// + /// Converts a generic/void Handle to a specific type. + /// Runtime type checking is enabled to ensure that Handles are only being casted + /// to the correct type. + /// + /// Generic handle to convert. + /// + /// Thrown if an invalid conversion is made. + /// + explicit Handle(const Handle& genericHandle); ~Handle() = default; /*-----------------------------------------------------------------------------*/ @@ -140,13 +165,48 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Data Members */ /*-----------------------------------------------------------------------------*/ - ResourceLibrary* library = nullptr; + SHResourceLibrary* library = nullptr; /*-----------------------------------------------------------------------------*/ /* Friend Declarations */ /*-----------------------------------------------------------------------------*/ - friend class ResourceLibrary; - }; + friend class SHResourceLibrary; + friend class Handle; + }; + + /// + /// Template Specialization for Handle that represents a type-less Handle. + /// + template<> + class Handle : public HandleBase + { + public: + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + Handle() = default; + template + explicit Handle(const Handle& handle); + ~Handle() = default; + + /*-----------------------------------------------------------------------------*/ + /* Overloaded Operators */ + /*-----------------------------------------------------------------------------*/ + template + inline bool operator==(const Handle& rhs) const noexcept; + + protected: + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + SHResourceLibraryBase* library = nullptr; + + /*-----------------------------------------------------------------------------*/ + /* Friend Declarations */ + /*-----------------------------------------------------------------------------*/ + template + friend class Handle; + }; /// /// Interface that needs to be implemented by classes that want to store a Handle to @@ -155,7 +215,7 @@ namespace SHADE template class ISelfHandle { - public: + public: /*-----------------------------------------------------------------------------*/ /* Constructors */ /*-----------------------------------------------------------------------------*/ @@ -183,7 +243,7 @@ namespace SHADE /// /// Required to lock usage to ResourceLibrary only. /// Handle to set. - void SetHandle(const ResourceLibrary& rscLib, Handle hdl); + void SetHandle(const SHResourceLibrary& rscLib, Handle hdl); private: /*-----------------------------------------------------------------------------*/ @@ -220,4 +280,4 @@ namespace std }; } -#include "Handle.hpp" \ No newline at end of file +#include "SHHandle.hpp" \ No newline at end of file diff --git a/SHADE_Engine/src/Resource/Handle.hpp b/SHADE_Engine/src/Resource/SHHandle.hpp similarity index 63% rename from SHADE_Engine/src/Resource/Handle.hpp rename to SHADE_Engine/src/Resource/SHHandle.hpp index 45468ec1..53061ac7 100644 --- a/SHADE_Engine/src/Resource/Handle.hpp +++ b/SHADE_Engine/src/Resource/SHHandle.hpp @@ -1,7 +1,7 @@ #pragma once // Primary Header -#include "Handle.h" -#include "ResourceLibrary.h" +#include "SHHandle.h" +#include "SHResourceLibrary.h" namespace SHADE { @@ -20,7 +20,21 @@ namespace SHADE { return id.Raw != INVALID_ID.Raw; } - + + /*---------------------------------------------------------------------------------*/ + /* Handle - Constructors */ + /*---------------------------------------------------------------------------------*/ + template + Handle::Handle(const Handle& genericHandle) + : library { reinterpret_cast*>(genericHandle.library) } + { + id = genericHandle.id; + + // Check if valid + if (library != nullptr && library->GetType() != typeid(T)) + throw BadHandleCastException(); + } + /*---------------------------------------------------------------------------------*/ /* Handle - Usage Functions */ /*---------------------------------------------------------------------------------*/ @@ -63,6 +77,28 @@ namespace SHADE return &library->Get(*this); } + /*---------------------------------------------------------------------------------*/ + /* Handle - Constructors */ + /*---------------------------------------------------------------------------------*/ + template + Handle::Handle(const Handle& handle) + : library{ static_cast(handle.library) } + { + id = handle.id; + } + + /*---------------------------------------------------------------------------------*/ + /* Handle - Overloaded Operators */ + /*---------------------------------------------------------------------------------*/ + template + bool SHADE::Handle::operator==(const Handle& rhs) const noexcept + { + return id.Raw == rhs.id.Raw && library == static_cast(rhs.library); + } + + /*---------------------------------------------------------------------------------*/ + /* ISelfHandle - Constructors */ + /*---------------------------------------------------------------------------------*/ template inline ISelfHandle::ISelfHandle(const ISelfHandle& rhs) : handle { rhs.handle } @@ -73,6 +109,9 @@ namespace SHADE : handle { rhs.handle } {} + /*---------------------------------------------------------------------------------*/ + /* ISelfHandle - Overloaded Operators */ + /*---------------------------------------------------------------------------------*/ template inline ISelfHandle& ISelfHandle::operator=(const ISelfHandle& rhs) { @@ -96,7 +135,7 @@ namespace SHADE return handle; } template - inline void ISelfHandle::SetHandle(const ResourceLibrary&, Handle hdl) + inline void ISelfHandle::SetHandle(const SHResourceLibrary&, Handle hdl) { handle = hdl; } diff --git a/SHADE_Engine/src/Resource/ResourceLibrary.cpp b/SHADE_Engine/src/Resource/SHResourceLibrary.cpp similarity index 87% rename from SHADE_Engine/src/Resource/ResourceLibrary.cpp rename to SHADE_Engine/src/Resource/SHResourceLibrary.cpp index b215b591..db4a8f48 100644 --- a/SHADE_Engine/src/Resource/ResourceLibrary.cpp +++ b/SHADE_Engine/src/Resource/SHResourceLibrary.cpp @@ -1,11 +1,11 @@ #include "SHPch.h" -#include "ResourceLibrary.h" +#include "SHResourceLibrary.h" namespace SHADE { /*-----------------------------------------------------------------------------*/ /* Constructors/Destructors */ /*-----------------------------------------------------------------------------*/ - ResourceManager::~ResourceManager() + SHResourceHub::~SHResourceHub() { // Delete all resources libraries for (auto iter = deleters.rbegin(); iter != deleters.rend(); ++iter) diff --git a/SHADE_Engine/src/Resource/ResourceLibrary.h b/SHADE_Engine/src/Resource/SHResourceLibrary.h similarity index 85% rename from SHADE_Engine/src/Resource/ResourceLibrary.h rename to SHADE_Engine/src/Resource/SHResourceLibrary.h index a5bf0a67..46ae4572 100644 --- a/SHADE_Engine/src/Resource/ResourceLibrary.h +++ b/SHADE_Engine/src/Resource/SHResourceLibrary.h @@ -6,24 +6,42 @@ #include // Project Headers -#include "Handle.h" +#include "SHHandle.h" #include "Resource/SparseSet.h" namespace SHADE { + /// + /// Base class for SHResourceLibrary that holds information about the library type. + /// + class SHResourceLibraryBase + { + public: + /*-----------------------------------------------------------------------------*/ + /* Getter Functions */ + /*-----------------------------------------------------------------------------*/ + inline std::type_index GetType() { return libraryType; } + + protected: + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + std::type_index libraryType = typeid(void); + }; + /// /// Generic Resource Library for a specified type of Resource. This object will own /// any resources created using it. /// /// Type of resources that this library stores. template - class ResourceLibrary + class SHResourceLibrary : public SHResourceLibraryBase { public: /*-----------------------------------------------------------------------------*/ /* Constructor */ /*-----------------------------------------------------------------------------*/ - ResourceLibrary(); + SHResourceLibrary(); /*-----------------------------------------------------------------------------*/ /* Usage Functions */ @@ -75,13 +93,13 @@ namespace SHADE /// /// Manages all resources in multiple ResourceLibraries. /// - class ResourceManager final + class SHResourceHub final { public: /*-----------------------------------------------------------------------------*/ /* Constructors/Destructors */ /*-----------------------------------------------------------------------------*/ - ~ResourceManager(); + ~SHResourceHub(); /*-----------------------------------------------------------------------------*/ /* Usage Functions */ @@ -136,10 +154,10 @@ namespace SHADE /* Helper Functions */ /*-----------------------------------------------------------------------------*/ template - ResourceLibrary& getLibrary(); + SHResourceLibrary& getLibrary(); template - const ResourceLibrary& getLibrary() const; + const SHResourceLibrary& getLibrary() const; }; } -#include "ResourceLibrary.hpp" \ No newline at end of file +#include "SHResourceLibrary.hpp" \ No newline at end of file diff --git a/SHADE_Engine/src/Resource/ResourceLibrary.hpp b/SHADE_Engine/src/Resource/SHResourceLibrary.hpp similarity index 79% rename from SHADE_Engine/src/Resource/ResourceLibrary.hpp rename to SHADE_Engine/src/Resource/SHResourceLibrary.hpp index 9aa72ead..411f6bf5 100644 --- a/SHADE_Engine/src/Resource/ResourceLibrary.hpp +++ b/SHADE_Engine/src/Resource/SHResourceLibrary.hpp @@ -1,6 +1,6 @@ #pragma once // Primary Header -#include "ResourceLibrary.h" +#include "SHResourceLibrary.h" // Standard Library #include @@ -10,13 +10,14 @@ namespace SHADE /* ResourceLibrary - Constructor */ /*---------------------------------------------------------------------------------*/ template - ResourceLibrary::ResourceLibrary() + SHResourceLibrary::SHResourceLibrary() { // Type Checking - //static_assert(std::is_copy_assignable_v, "Resource Library's resources must be copy assignable."); - //static_assert(std::is_copy_constructible_v, "Resource Library's resources must be copy constructible."); static_assert(std::is_move_assignable_v, "Resource Library's resources must be move assignable."); static_assert(std::is_move_constructible_v, "Resource Library's resources must be move constructible."); + + // Keep track of the type for conversions + libraryType = typeid(T); } /*---------------------------------------------------------------------------------*/ @@ -24,7 +25,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ template template - Handle ResourceLibrary::Create(Args&&... args) + Handle SHResourceLibrary::Create(Args&&... args) { // Create the handle Handle handle; @@ -55,7 +56,7 @@ namespace SHADE } template - void ResourceLibrary::Free(Handle handle) + void SHResourceLibrary::Free(Handle handle) { assertHandleValid(handle); @@ -63,7 +64,7 @@ namespace SHADE } template - T& ResourceLibrary::Get(Handle handle) + T& SHResourceLibrary::Get(Handle handle) { assertHandleValid(handle); @@ -71,7 +72,7 @@ namespace SHADE } template - const T& ResourceLibrary::Get(Handle handle) const + const T& SHResourceLibrary::Get(Handle handle) const { assertHandleValid(handle); @@ -82,14 +83,14 @@ namespace SHADE /* ResourceLibrary - Helper Functions */ /*---------------------------------------------------------------------------------*/ template - void ResourceLibrary::assertHandleValid(Handle handle) const + void SHResourceLibrary::assertHandleValid(Handle handle) const { if (!handle || handle.id.Data.Version != versionCounts[handle.id.Data.Index]) throw std::invalid_argument("Invalid handle provided!"); } template - inline uint32_t ResourceLibrary::getAvailableFreeIndex() + inline uint32_t SHResourceLibrary::getAvailableFreeIndex() { // Get from the free list if present if (!freeList.empty()) @@ -107,25 +108,25 @@ namespace SHADE /* ResourceManager - Usage Functions */ /*---------------------------------------------------------------------------------*/ template - Handle ResourceManager::Create(Args&&... args) + Handle SHResourceHub::Create(Args&&... args) { return getLibrary().Create(std::forward(args) ...); } template - void ResourceManager::Free(Handle handle) + void SHResourceHub::Free(Handle handle) { getLibrary().Free(handle); } template - T& ResourceManager::Get(Handle handle) + T& SHResourceHub::Get(Handle handle) { return getLibrary().Get(handle); } template - const T& ResourceManager::Get(Handle handle) const + const T& SHResourceHub::Get(Handle handle) const { return getLibrary().Get(handle); } @@ -134,18 +135,18 @@ namespace SHADE /* ResourceManager - Helper Functions */ /*-----------------------------------------------------------------------------*/ template - ResourceLibrary& ResourceManager::getLibrary() + SHResourceLibrary& SHResourceHub::getLibrary() { // Attempt to retrieve the library const std::type_index RSC_TYPE = typeid(T); if (resourceLibs.contains(RSC_TYPE)) { - return *static_cast*>(resourceLibs.at(RSC_TYPE)); + return *static_cast*>(resourceLibs.at(RSC_TYPE)); } else { // Construct library if doesn't exist - ResourceLibrary* lib = new ResourceLibrary(); + SHResourceLibrary* lib = new SHResourceLibrary(); resourceLibs.emplace(RSC_TYPE, static_cast(lib)); // Construct deleter to properly delete objects with void* @@ -156,8 +157,8 @@ namespace SHADE } template - const ResourceLibrary& ResourceManager::getLibrary() const + const SHResourceLibrary& SHResourceHub::getLibrary() const { - return const_cast(this).getLibrary(); + return const_cast(this).getLibrary(); } } diff --git a/SHADE_Engine/src/Resource/SHResourceManager.cpp b/SHADE_Engine/src/Resource/SHResourceManager.cpp new file mode 100644 index 00000000..156c31c7 --- /dev/null +++ b/SHADE_Engine/src/Resource/SHResourceManager.cpp @@ -0,0 +1,95 @@ +/************************************************************************************//*! +\file SHResourceManager.cpp +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 21, 2022 +\brief Contains the definition of the functions of the SHResourceManager static + 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" +// Primary Include +#include "SHResourceManager.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Static Data Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + SHResourceHub SHResourceManager::resourceHub; + std::unordered_map>> SHResourceManager::handlesMap; + std::unordered_map SHResourceManager::assetIdMap; + std::unordered_map> SHResourceManager::typedFreeFuncMap; + std::vector SHResourceManager::loadedAssetData; + + /*-----------------------------------------------------------------------------------*/ + /* Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + void SHResourceManager::Unload(AssetID assetId) + { + // Search each library for the asset ID and try to free it + Handle handle; + for (auto& typedHandleMap : handlesMap) + { + if (typedHandleMap.second.contains(assetId)) + { + // Save handle for later + handle = typedHandleMap.second[assetId]; + // Dispose + typedFreeFuncMap[typedHandleMap.first](assetId); + typedHandleMap.second.erase(assetId); + } + } + + // No handles were found + if (!handle) + return; + + for (auto& typedAssetIdsMap : assetIdMap) + { + if (typedAssetIdsMap.second.contains(handle)) + { + // Dispose + typedAssetIdsMap.second.erase(handle); + } + } + } + + void SHResourceManager::FinaliseChanges() + { + SHGraphicsSystem* gfxSystem = SHSystemManager::GetSystem(); + if (gfxSystem == nullptr) + throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed."); + gfxSystem->BuildMeshBuffers(); + gfxSystem->BuildTextures(); + + // Free CPU Resources + for (auto assetId : loadedAssetData) + { + SHAssetManager::Unload(assetId); + } + loadedAssetData.clear(); + } + + /*-----------------------------------------------------------------------------------*/ + /* Query Functions */ + /*-----------------------------------------------------------------------------------*/ + std::optional SHResourceManager::GetAssetID(Handle handle) + { + const Handle GENERIC_HANDLE = Handle(handle); + + // Search each library for the asset ID and try to free it + for (auto& typedAssetIdsMap : assetIdMap) + { + if (typedAssetIdsMap.second.contains(GENERIC_HANDLE)) + { + return typedAssetIdsMap.second[GENERIC_HANDLE]; + } + } + + return {}; + } +} diff --git a/SHADE_Engine/src/Resource/SHResourceManager.h b/SHADE_Engine/src/Resource/SHResourceManager.h new file mode 100644 index 00000000..84f93b10 --- /dev/null +++ b/SHADE_Engine/src/Resource/SHResourceManager.h @@ -0,0 +1,130 @@ +/************************************************************************************//*! +\file SHResourceManager.h +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 21, 2022 +\brief Contains the definition of the SHResourceManager static 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 "SH_API.h" +#include "SHResourceLibrary.h" +#include "Assets/SHAssetMacros.h" + +namespace SHADE +{ + /// + /// Static class responsible for loading and caching runtime resources from their + /// serialised Asset IDs. + /// + class SH_API SHResourceManager + { + public: + /*---------------------------------------------------------------------------------*/ + /* Loading Functions */ + /*---------------------------------------------------------------------------------*/ + /// + /// Loads or retrieves an existing loaded object of the specified type with the + /// specified asset ID. + /// Note that for specific types, the retrieved Handle may not be valid until after + /// FinaliseChanges() is called. + /// + /// + /// Type of resource to load. + /// + /// Asset ID of the resource to load. + /// Handle to a loaded runtime asset. + template + static Handle LoadOrGet(AssetID assetId); + /// + /// Unloads an existing loaded asset. Attempting to unload an invalid Handle will + /// simply do nothing except emit a warning. + /// Faster than the untemplated version. + /// + /// Type of resource to unload. + /// Handle to the resource to unload. + template + static void Unload(Handle assetId); + /// + /// Unloads an existing loaded asset. Attempting to unload an invalid Handle will + /// simply do nothing except emit a warning. + /// Compared to the templated version, this function is slower as it requires + /// searching through the storage of all resource types. + /// + /// Handle to the resource to unload. + static void Unload(AssetID assetId); + /// + /// Needs to be called to finalise all changes to loads. + /// + static void FinaliseChanges(); + + /*---------------------------------------------------------------------------------*/ + /* Query Functions */ + /*---------------------------------------------------------------------------------*/ + /// + /// Retrieves the AssetID associated with a specified Handle. + /// Faster than the untemplated version. + /// + /// Type of resource to get the ID of. + /// Handle to get the AssetID of. + /// + /// AssetID for the specified Handle. If the Handle is invalid, there will be no + /// value. + /// + template + static std::optional GetAssetID(Handle handle); + /// + /// Retrieves the AssetID associated with a specified Handle. + /// Compared to the templated version, this function is slower as it requires + /// searching through the storage of all resource types. + /// + /// Handle to get the AssetID of. + /// + /// AssetID for the specified Handle. If the Handle is invalid, there will be no + /// value. + /// + static std::optional GetAssetID(Handle handle); + + private: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + using AssetHandleMap = std::unordered_map>; + using HandleAssetMap = std::unordered_map, AssetID>; + using AssetHandleMapRef = std::reference_wrapper; + using HandleAssetMapRef = std::reference_wrapper; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + // Handles + static SHResourceHub resourceHub; + static std::unordered_map handlesMap; + static std::unordered_map assetIdMap; + static std::unordered_map> typedFreeFuncMap; + // Pointers to temp CPU resources + static std::vector loadedAssetData; + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + /// + /// Retrieves or creates the AssetHandleMap for the specific type if it doesn't exist + /// + /// + /// The type of AssetHandleMap to retrieve. + /// + /// Reference to the AssetHandleMap of the specified type. + template + static std::pair getAssetHandleMap(); + }; +} + +#include "SHResourceManager.hpp" diff --git a/SHADE_Engine/src/Resource/SHResourceManager.hpp b/SHADE_Engine/src/Resource/SHResourceManager.hpp new file mode 100644 index 00000000..cff4e84b --- /dev/null +++ b/SHADE_Engine/src/Resource/SHResourceManager.hpp @@ -0,0 +1,172 @@ +/************************************************************************************//*! +\file SHResourceManager.hpp +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 21, 2022 +\brief Contains the definition of the function templates of the + SHResourceManager static 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 +// Primary Include +#include "SHResourceManager.h" +// Project Includes +#include "Assets/SHAssetManager.h" +#include "Assets/Asset Types/SHAssetIncludes.h" +#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h" +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Tools/SHLog.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Loading Functions */ + /*-----------------------------------------------------------------------------------*/ + template + Handle SHResourceManager::LoadOrGet(AssetID assetId) + { + // Check if it is an unsupported type + if (!std::is_same_v && !std::is_same_v) + { + static_assert(true, "Unsupported Resource Type specified for SHResourceManager."); + } + + /* Attempt to get existing loaded asset */ + auto [typedHandleMap, typedAssetIdMap] = getAssetHandleMap(); + if (typedHandleMap.get().contains(assetId)) + return Handle(typedHandleMap.get()[assetId]); + + /* Otherwise, we need to load it! */ + // Meshes + if constexpr (std::is_same_v) + { + // Get system + SHGraphicsSystem* gfxSystem = SHSystemManager::GetSystem(); + if (gfxSystem == nullptr) + throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed."); + + // Load + const SHMeshAsset* assetData = SHAssetManager::GetData(assetId); + if (assetData == nullptr) + { + SHLog::Warning("[SHResourceManager] Attempted to load an asset with an invalid Asset ID."); + return {}; + } + loadedAssetData.emplace_back(assetId); + + Handle meshHandle = gfxSystem->AddMesh + ( + assetData->vertexPosition.size(), + assetData->vertexPosition.data(), + assetData->texCoords.data(), + assetData->vertexTangent.data(), + assetData->vertexNormal.data(), + assetData->indices.size(), + assetData->indices.data() + ); + Handle genericHandle = Handle(meshHandle); + typedHandleMap.get().emplace(assetId, genericHandle); + typedAssetIdMap.get().emplace(genericHandle, assetId); + return meshHandle; + } + // Textures + else if constexpr (std::is_same_v) + { + // Get system + SHGraphicsSystem* gfxSystem = SHSystemManager::GetSystem(); + if (gfxSystem == nullptr) + throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed."); + + // Load + const SHTextureAsset* assetData = SHAssetManager::GetData(assetId); + if (assetData == nullptr) + { + SHLog::Warning("[SHResourceManager] Attempted to load an asset with an invalid Asset ID."); + return {}; + } + loadedAssetData.emplace_back(assetId); + + Handle texHandle = gfxSystem->AddTexture + ( + assetData->numBytes, + assetData->pixelData, + assetData->width, + assetData->height, + assetData->format, + assetData->mipOffsets + ); + typedHandleMap.get().emplace(assetId, Handle(texHandle)); + return texHandle; + } + } + + template + void SHResourceManager::Unload(Handle assetId) + { + // Check if it is an unsupported type + if (!std::is_same_v && !std::is_same_v) + { + static_assert(true, "Unsupported Resource Type specified for SHResourceManager."); + } + + /* Attempt to get existing loaded asset */ + auto [typedHandleMap, typedAssetIdMap] = getAssetHandleMap(); + if (typedHandleMap.get().contains(assetId)) + { + // Dispose + Handle handle = typedHandleMap.get()[assetId]; + Handle typedHandle = static_cast>(handle); + typedHandle.Free(); + typedAssetIdMap.get().erase(handle); + typedHandleMap.get().erase(assetId); + } + else + { + // There's nothing to remove + SHLog::Warning("[SHResourceManager] Attempted to unload an invalid resource. Ignoring."); + } + } + + /*-----------------------------------------------------------------------------------*/ + /* Query Functions */ + /*-----------------------------------------------------------------------------------*/ + template + std::optional SHResourceManager::GetAssetID(Handle handle) + { + const Handle GENERIC_HANDLE = Handle(handle); + auto [typedHandleMap, typedAssetIdMap] = getAssetHandleMap(); + if (typedAssetIdMap.get().contains(GENERIC_HANDLE)) + { + return typedAssetIdMap.GetId()[GENERIC_HANDLE]; + } + + return {}; + } + + /*-----------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*-----------------------------------------------------------------------------------*/ + template + std::pair SHResourceManager::getAssetHandleMap() + { + const std::type_index TYPE = typeid(ResourceType); + + if (!handlesMap.contains(TYPE)) + { + handlesMap.emplace(TYPE, AssetHandleMap{}); + assetIdMap.emplace(TYPE, HandleAssetMap{}); + typedFreeFuncMap.emplace + ( + TYPE, + [TYPE](AssetID assetId) + { + static_cast>(SHResourceManager::handlesMap[TYPE][assetId]).Free(); + } + ); + } + return std::make_pair(std::ref(handlesMap[TYPE]), std::ref(assetIdMap[TYPE])); + } +} diff --git a/SHADE_Engine/src/Resource/SparseSet.h b/SHADE_Engine/src/Resource/SparseSet.h index 8a3f9c6e..fb4a8311 100644 --- a/SHADE_Engine/src/Resource/SparseSet.h +++ b/SHADE_Engine/src/Resource/SparseSet.h @@ -59,9 +59,9 @@ namespace SHADE SparseSet(); ~SparseSet() = default; - // Disallow moving or copying - SparseSet(const SparseSet&) = delete; - SparseSet(SparseSet&&) = delete; + //// Disallow moving or copying + //SparseSet(const SparseSet&) = delete; + //SparseSet(SparseSet&&) = delete; /*-----------------------------------------------------------------------------*/ /* Usage Functions */ diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.cpp b/SHADE_Engine/src/Scene/SHSceneGraph.cpp index bbbdb7e4..950fd6a0 100644 --- a/SHADE_Engine/src/Scene/SHSceneGraph.cpp +++ b/SHADE_Engine/src/Scene/SHSceneGraph.cpp @@ -15,6 +15,7 @@ // Project Headers #include "ECS_Base/Managers/SHEntityManager.h" +#include "Events/SHEventManager.hpp" #include "Tools/SHLogger.h" #include "Tools/SHException.h" @@ -317,6 +318,11 @@ namespace SHADE if (parentNode == nullptr) { SHLOG_WARNING("Removing Entity {}'s parent", entityID) + + if (parent) + parent->RemoveChild(this); + + return; } // Handle self assignment @@ -359,10 +365,19 @@ namespace SHADE } //////////////////////////////////////// + const SHSceneGraphChangeParentEvent EVENT_DATA + { + .node = NODE_ITER->second + , .oldParent = NODE_ITER->second->GetParent() + , .newParent = parent ? parent : root + }; + if (parent == nullptr) parent = root; NODE_ITER->second->SetParent(parent); + + SHEventManager::BroadcastEvent(EVENT_DATA, SH_SCENEGRAPH_CHANGE_PARENT_EVENT); } void SHSceneGraph::SetParent(EntityID entityID, EntityID parent) const noexcept @@ -396,8 +411,17 @@ namespace SHADE } //////////////////////////////////////// + const SHSceneGraphChangeParentEvent EVENT_DATA + { + .node = NODE_ITER->second + , .oldParent = NODE_ITER->second->GetParent() + , .newParent = PARENT_ITER->second + }; + SHSceneNode* currentNode = NODE_ITER->second; currentNode->SetParent(PARENT_ITER->second); + + SHEventManager::BroadcastEvent(EVENT_DATA, SH_SCENEGRAPH_CHANGE_PARENT_EVENT); } /*-----------------------------------------------------------------------------------*/ @@ -558,7 +582,7 @@ namespace SHADE ReleaseNode(node); } - void SHSceneGraph::Traverse (const UnaryPredicate& predicate) const + void SHSceneGraph::Traverse (const UnaryFunction& predicate) const { TraverseAndInvokePredicate(root, predicate); } @@ -597,7 +621,7 @@ namespace SHADE delete node; } - void SHSceneGraph::TraverseAndInvokePredicate(const SHSceneNode* node, const UnaryPredicate& predicate) + void SHSceneGraph::TraverseAndInvokePredicate(const SHSceneNode* node, const UnaryFunction& predicate) { for (auto* child : node->children) { diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.h b/SHADE_Engine/src/Scene/SHSceneGraph.h index 3f3ebf92..a4cf45eb 100644 --- a/SHADE_Engine/src/Scene/SHSceneGraph.h +++ b/SHADE_Engine/src/Scene/SHSceneGraph.h @@ -97,9 +97,8 @@ namespace SHADE /* Type Definitions */ /*---------------------------------------------------------------------------------*/ - using EntityNodeMap = std::unordered_map; - - using UnaryPredicate = std::function; + using EntityNodeMap = std::unordered_map; + using UnaryFunction = std::function; /*---------------------------------------------------------------------------------*/ @@ -143,8 +142,7 @@ namespace SHADE bool RemoveNode (SHSceneNode* nodeToRemove) noexcept; void Reset () noexcept; - void Traverse (const UnaryPredicate& predicate) const; - + void Traverse (const UnaryFunction& predicate) const; private: /*---------------------------------------------------------------------------------*/ @@ -160,8 +158,14 @@ namespace SHADE SHSceneNode* AllocateNode (EntityID entityID); void ReleaseNode (SHSceneNode* node) noexcept; - static void TraverseAndInvokePredicate (const SHSceneNode* node, const UnaryPredicate& predicate); + static void TraverseAndInvokePredicate (const SHSceneNode* node, const UnaryFunction& predicate); }; + struct SHSceneGraphChangeParentEvent + { + SHSceneNode* node; + SHSceneNode* oldParent; + SHSceneNode* newParent; + }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index 65f445a6..fea59353 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -115,34 +115,22 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Script Serialisation Functions */ /*---------------------------------------------------------------------------------*/ - std::string SHScriptEngine::SerialiseScripts(const SHEntity& entity) const + bool SHScriptEngine::SerialiseScripts(EntityID entity, YAML::Node& scriptsNode) 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); - // 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!"); - } + if (csScriptsSerialiseYaml(entity, &scriptsNode)) + return true; - // Return an empty string since we failed to serialise - return result; + SHLOG_ERROR("[ScriptEngine] Failed to serialise scripts for entity #{}.", entity); + return false; } /*-----------------------------------------------------------------------------------*/ /* Script Serialisation Functions */ /*-----------------------------------------------------------------------------------*/ - void SHScriptEngine::DeserialiseScript(const SHEntity& entity, const std::string& yaml) const + bool SHScriptEngine::DeserialiseScripts(EntityID entity, const YAML::Node& scriptsNode) const { - csScriptDeserialise(entity.GetEID(), yaml.c_str()); + return csScriptsDeserialiseYaml(entity, &scriptsNode); } /*-----------------------------------------------------------------------------------*/ @@ -380,30 +368,18 @@ namespace SHADE DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", "RemoveAllScriptsImmediately" ); - /*csScriptsSerialise = dotNet.GetFunctionPtr + csScriptsSerialiseYaml = dotNet.GetFunctionPtr ( DEFAULT_CSHARP_LIB_NAME, DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", "SerialiseScripts" ); - csScriptsSerialiseYaml = dotNet.GetFunctionPtr + csScriptsDeserialiseYaml = dotNet.GetFunctionPtr ( DEFAULT_CSHARP_LIB_NAME, DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", - "SerialiseScriptsYaml" + "DeserialiseScripts" ); - csScriptDeserialise = dotNet.GetFunctionPtr - ( - DEFAULT_CSHARP_LIB_NAME, - DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", - "DeserialiseScript" - ); - csScriptDeserialiseYaml = dotNet.GetFunctionPtr - ( - DEFAULT_CSHARP_LIB_NAME, - DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", - "SerialiseScriptsYaml" - );*/ csEditorRenderScripts = dotNet.GetFunctionPtr ( DEFAULT_CSHARP_LIB_NAME, diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.h b/SHADE_Engine/src/Scripting/SHScriptEngine.h index 239d6b90..137d978f 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.h +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.h @@ -13,7 +13,8 @@ of DigiPen Institute of Technology is prohibited. // STL Includes #include - +// External Dependencies +#include // Project Headers #include "SH_API.h" #include "SHDotNetRuntime.h" @@ -141,23 +142,26 @@ namespace SHADE /* Script Serialisation Functions */ /*-----------------------------------------------------------------------------*/ /// - /// Generates a JSON string that represents the set of Scripts attached to the - /// specified Entity. + /// Performs serialization of all scripts for the specified entity into the + /// YAML::Node specified. This node will contain all serialised scripts after + /// calling this function. /// - /// The Entity to Serialise. - /// - /// String that represents the set of scripts attached to the specified Entity. - /// - std::string SerialiseScripts(const SHEntity& entity) const; + /// The Entity to Serialise. + /// + /// YAML Node that will store the serialised scripts. + /// + /// True if successfully serialised. + bool SerialiseScripts(EntityID entity, YAML::Node& scriptsNode) const; /// - /// Loads the specified JSON string and creates a Script for the specified Entity - /// based on the specified JSON string. + /// Creates scripts and sets fields for the specified Entity based on the specified + /// YAML node. /// /// The Entity to deserialise a Script on to. - /// - /// The YAML string that represents the Script to load into the Entity. + /// + /// YAML Node that contains the serialised script data. /// - void DeserialiseScript(const SHEntity& entity, const std::string& yaml) const; + /// True if successfully deserialised. + bool DeserialiseScripts(EntityID entity, const YAML::Node& scriptsNode) const; /*-----------------------------------------------------------------------------*/ /* Script Editor Functions */ @@ -207,14 +211,13 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------*/ - using CsFuncPtr = void(*)(void); - using CsScriptManipFuncPtr = bool(*)(EntityID, const char*); - using CsScriptBasicFuncPtr = void(*)(EntityID); - using CsScriptOptionalFuncPtr = void(*)(EntityID, bool); - using CsScriptSerialiseFuncPtr = bool(*)(EntityID, char*, int); - using CsScriptDeserialiseFuncPtr = bool(*)(EntityID, const char*); - using CsScriptSerialiseYamlFuncPtr = bool(*)(EntityID, void*); - using CsScriptEditorFuncPtr = void(*)(EntityID); + using CsFuncPtr = void(*)(void); + using CsScriptManipFuncPtr = bool(*)(EntityID, const char*); + using CsScriptBasicFuncPtr = void(*)(EntityID); + using CsScriptOptionalFuncPtr = void(*)(EntityID, bool); + using CsScriptSerialiseYamlFuncPtr = bool(*)(EntityID, void*); + using CsScriptDeserialiseYamlFuncPtr = bool(*)(EntityID, const void*); + using CsScriptEditorFuncPtr = void(*)(EntityID); /*-----------------------------------------------------------------------------*/ /* Constants */ @@ -228,31 +231,29 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Data Members */ /*-----------------------------------------------------------------------------*/ - SHDotNetRuntime dotNet { false }; + SHDotNetRuntime dotNet { false }; // Function Pointers to CLR Code // - Engine Lifecycle - CsFuncPtr csEngineInit = nullptr; - CsFuncPtr csEngineLoadScripts = nullptr; - CsFuncPtr csEngineUnloadScripts = nullptr; - CsFuncPtr csEngineReloadScripts = nullptr; - CsFuncPtr csEngineExit = nullptr; + CsFuncPtr csEngineInit = nullptr; + CsFuncPtr csEngineLoadScripts = nullptr; + CsFuncPtr csEngineUnloadScripts = nullptr; + CsFuncPtr csEngineReloadScripts = nullptr; + CsFuncPtr csEngineExit = nullptr; // - Scripts Store - CsFuncPtr csScriptsFrameSetUp = nullptr; - CsFuncPtr csScriptsExecuteFixedUpdate = nullptr; - CsFuncPtr csScriptsExecuteUpdate = nullptr; - CsFuncPtr csScriptsExecuteLateUpdate = nullptr; - CsFuncPtr csScriptsFrameCleanUp = nullptr; - CsScriptManipFuncPtr csScriptsAdd = nullptr; - CsScriptBasicFuncPtr csScriptsRemoveAll = nullptr; - CsScriptOptionalFuncPtr csScriptsRemoveAllImmediately = nullptr; - CsScriptSerialiseFuncPtr csScriptsSerialise = nullptr; - CsScriptDeserialiseFuncPtr csScriptDeserialise = nullptr; - CsScriptSerialiseYamlFuncPtr csScriptsSerialiseYaml = nullptr; - CsScriptSerialiseYamlFuncPtr csScriptDeserialiseYaml = nullptr; + CsFuncPtr csScriptsFrameSetUp = nullptr; + CsFuncPtr csScriptsExecuteFixedUpdate = nullptr; + CsFuncPtr csScriptsExecuteUpdate = nullptr; + CsFuncPtr csScriptsExecuteLateUpdate = nullptr; + CsFuncPtr csScriptsFrameCleanUp = nullptr; + CsScriptManipFuncPtr csScriptsAdd = nullptr; + CsScriptBasicFuncPtr csScriptsRemoveAll = nullptr; + CsScriptOptionalFuncPtr csScriptsRemoveAllImmediately = nullptr; + CsScriptSerialiseYamlFuncPtr csScriptsSerialiseYaml = nullptr; + CsScriptDeserialiseYamlFuncPtr csScriptsDeserialiseYaml = nullptr; // - Editor - CsScriptEditorFuncPtr csEditorRenderScripts = nullptr; - CsFuncPtr csEditorUndo = nullptr; - CsFuncPtr csEditorRedo = nullptr; + CsScriptEditorFuncPtr csEditorRenderScripts = nullptr; + CsFuncPtr csEditorUndo = nullptr; + CsFuncPtr csEditorRedo = nullptr; /*-----------------------------------------------------------------------------*/ /* Event Handler Functions */ diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp new file mode 100644 index 00000000..3804db95 --- /dev/null +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -0,0 +1,263 @@ +#include "SHpch.h" +#include "SHSerializationHelper.hpp" +#include "SHSerialization.h" + +#include + +#include "ECS_Base/Managers/SHEntityManager.h" +#include "Scene/SHSceneManager.h" +#include "Tools/SHException.h" +#include "Assets/SHAssetManager.h" +#include + +#include "Graphics/MiddleEnd/Interface/SHRenderable.h" +#include "Math/Transform/SHTransformComponent.h" +#include "Physics/Components/SHRigidBodyComponent.h" +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Scripting/SHScriptEngine.h" + +namespace SHADE +{ + void SHSerialization::SerializeSceneToFile(std::filesystem::path const& path) + { + YAML::Emitter out; + SerializeSceneToEmitter(out); + std::ofstream file(path.c_str()); + if (file.good()) + { + file << out.c_str(); + file.close(); + } + } + + std::string SHSerialization::SerializeSceneToString() + { + YAML::Emitter out; + SerializeSceneToEmitter(out); + return std::basic_string(out.c_str()); + } + + void SHSerialization::SerializeSceneToEmitter(YAML::Emitter& out) + { + auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); + auto root = sceneGraph.GetRoot(); + + SHASSERT(root != nullptr, "Root is null. Failed to serialize scene to node."); + + auto const& children = root->GetChildren(); + out << YAML::BeginSeq; + + auto pred = [&out](SHSceneNode* node) {out << SerializeEntityToNode(node); }; + sceneGraph.Traverse(pred); + //out << SerializeEntityToNode(child); + + out << YAML::EndSeq; + } + + static EntityID DeserializeEntity(YAML::iterator& it, YAML::Node const& node, std::vector& createdEntities, EntityID parentEID = MAX_EID) + { + EntityID eid = MAX_EID; + if(!node) + return eid; + if (node[EIDNode]) + eid = node[EIDNode].as(); + std::string name = "Default"; + if (node[EntityNameNode]) + name = node[EntityNameNode].as(); + //Compile component IDs + const auto componentIDList = SHSerialization::GetComponentIDList(node[ComponentsNode]); + eid = SHEntityManager::CreateEntity(componentIDList, eid, name, parentEID); + createdEntities.push_back(eid); + if (node[NumberOfChildrenNode]) + { + if(const int numOfChildren = node[NumberOfChildrenNode].as(); numOfChildren > 0) + { + ++it; + for (int i = 0; i < numOfChildren; ++i) + { + DeserializeEntity(it, (*it), createdEntities, eid); + if((i + 1) < numOfChildren) + ++it; + } + } + } + + // Deserialise scripts + if (node[ScriptsNode]) + SHSystemManager::GetSystem()->DeserialiseScripts(eid, node[ScriptsNode]); + } + + void SHSerialization::DeserializeSceneFromFile(std::filesystem::path const& path) + { + //TODO:Shift to using XQ's FileIO + std::ifstream iFile; + iFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); + std::string fileContent = ""; + + try + { + // Open file + // Read file's buffer contents into streams + iFile.open(path); + std::stringstream fileStream; + fileStream << iFile.rdbuf(); + + fileContent = fileStream.str(); + + // Close file handler + iFile.close(); + } + catch (std::ifstream::failure e) + { + SHLOG_ERROR("Could not read file"); + } + YAML::Node entities = YAML::Load(fileContent); + std::vector createdEntities{}; + + //Create Entities + for (auto it = entities.begin(); it != entities.end(); ++it) + { + DeserializeEntity(it, (*it), createdEntities); + } + if(createdEntities.empty()) + { + SHLOG_ERROR("Failed to create entities from deserializaiton") + return; + } + //Initialize Entity + auto entityVecIt = createdEntities.begin(); + for (auto it = entities.begin(); it != entities.end(); ++it) + { + InitializeEntity(*it, *entityVecIt++); + } + } + + void SHSerialization::EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out) + { + out << SerializeEntityToNode(entityNode); + auto const& children = entityNode->GetChildren(); + for(auto const& child : children) + { + EmitEntity(child, out); + } + } + + std::string SHSerialization::SerializeEntitiesToString(std::vector const& entities) noexcept + { + YAML::Emitter out; + YAML::Node node; + auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); + out << YAML::BeginSeq; + for (auto const& eid : entities) + { + auto entityNode = sceneGraph.GetNode(eid); + EmitEntity(entityNode, out); + } + out << YAML::EndSeq; + return std::string(out.c_str()); + } + + void SHSerialization::SerializeEntityToFile(std::filesystem::path const& path) + { + } + + YAML::Node SHSerialization::SerializeEntityToNode(SHSceneNode* sceneNode) + { + YAML::Node node; + auto eid = sceneNode->GetEntityID(); + auto entity = SHEntityManager::GetEntityByID(eid); + if (!sceneNode || !entity) + { + node = YAML::Null; + return node; + } + node.SetStyle(YAML::EmitterStyle::Block); + node[EIDNode] = eid; + node[EntityNameNode] = entity->name; + node[IsActiveNode] = sceneNode->IsActive(); + auto const& children = sceneNode->GetChildren(); + node[NumberOfChildrenNode] = children.size(); + + YAML::Node components; + + if (const auto transform = SHComponentManager::GetComponent_s(eid)) + { + components[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(transform); + } + if (const auto renderable = SHComponentManager::GetComponent_s(eid)) + { + components[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(renderable); + } + if (const auto rigidbody = SHComponentManager::GetComponent_s(eid)) + { + components[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(rigidbody); + } + node[ComponentsNode] = components; + + YAML::Node scripts; + SHSystemManager::GetSystem()->SerialiseScripts(eid, scripts); + node[ScriptsNode] = scripts; + + return node; + } + + EntityID SHSerialization::DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID) noexcept + { + if(data.empty()) + return MAX_EID; + YAML::Node entities = YAML::Load(data.c_str()); + EntityID eid{MAX_EID}; + std::vector createdEntities; + for(auto it = entities.begin(); it != entities.end(); ++it) + { + eid = DeserializeEntity(it, *it, createdEntities, parentEID); + } + if(createdEntities.empty()) + { + SHLOG_ERROR("Failed to create entities from deserializaiton") + return MAX_EID; + } + auto entityVecIt = createdEntities.begin(); + for(auto it = entities.begin(); it != entities.end(); ++it) + { + InitializeEntity(*it, *entityVecIt++); + } + return eid; + } + + template, bool> = true> + std::optional GetComponentID(YAML::Node const& componentNode) + { + if (componentNode[rttr::type::get().get_name().data()]) + return { SHFamilyID::GetID() }; + else + return std::nullopt; + } + + std::vector SHSerialization::GetComponentIDList(YAML::Node const& componentsNode) + { + std::vector componentIDList; + + auto id = GetComponentID(componentsNode); + if (id.has_value()) + componentIDList.push_back(id.value()); + + id = GetComponentID(componentsNode); + if (id.has_value()) + componentIDList.push_back(id.value()); + + id = GetComponentID(componentsNode); + if (id.has_value()) + componentIDList.push_back(id.value()); + + return componentIDList; + } + + void SHSerialization::InitializeEntity(YAML::Node const& entityNode, EntityID const& eid) + { + auto const componentsNode = entityNode[ComponentsNode]; + if (!componentsNode) + return; + SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); + } +} diff --git a/SHADE_Engine/src/Serialization/SHSerialization.h b/SHADE_Engine/src/Serialization/SHSerialization.h new file mode 100644 index 00000000..018bf0c3 --- /dev/null +++ b/SHADE_Engine/src/Serialization/SHSerialization.h @@ -0,0 +1,48 @@ +#pragma once + +#include "SH_API.h" +#include +#include + +#include + +namespace YAML +{ + class Emitter; + class Node; +} + +namespace SHADE +{ + class SHSceneNode; + + constexpr const char* ComponentsNode = "Components"; + constexpr const char* EntityNameNode = "Name"; + constexpr const char* EIDNode = "EID"; + constexpr const char* IsActiveNode = "IsActive"; + constexpr const char* NumberOfChildrenNode = "NumberOfChildren"; + constexpr const char* ScriptsNode = "Scripts"; + + struct SH_API SHSerialization + { + //TODO: change paths to resource ID + static void SerializeSceneToFile(std::filesystem::path const& path); + static std::string SerializeSceneToString(); + static void SerializeSceneToEmitter(YAML::Emitter& out); + + static void DeserializeSceneFromFile(std::filesystem::path const& path); + + + static void EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out); + + static std::string SerializeEntitiesToString(std::vector const& entities) noexcept; + static void SerializeEntityToFile(std::filesystem::path const& path); + static YAML::Node SerializeEntityToNode(SHSceneNode* sceneNode); + + static EntityID DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID = MAX_EID) noexcept; + + static std::vector GetComponentIDList(YAML::Node const& componentsNode); + private: + static void InitializeEntity(YAML::Node const& entityNode, EntityID const& eid); + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp b/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp new file mode 100644 index 00000000..da98c885 --- /dev/null +++ b/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp @@ -0,0 +1,204 @@ +#pragma once + +#include "ECS_Base/Components/SHComponent.h" +#include + +#include + +#include "ECS_Base/Managers/SHComponentManager.h" +#include "Math/Vector/SHVec2.h" +#include "Math/Vector/SHVec3.h" +#include "Math/Vector/SHVec4.h" + +namespace SHADE +{ + struct SHSerializationHelper + { + template , bool> = true> + static std::string SerializeComponentToString(ComponentType* component) + { + return std::string(); + } + + template , bool> = true> + static void SerializeComponentToFile(ComponentType* component, std::filesystem::path const& path) + { + } + + static YAML::Node RTTRToNode(const rttr::variant& var) + { + YAML::Node node; + auto varType = var.get_type(); + if (varType == rttr::type::get()) + { + node.SetStyle(YAML::EmitterStyle::Flow); + node["X"] = var.convert().x; + node["Y"] = var.convert().y; + node["Z"] = var.convert().z; + node["W"] = var.convert().w; + } + else if (varType == rttr::type::get()) + { + node.SetStyle(YAML::EmitterStyle::Flow); + node["X"] = var.convert().x; + node["Y"] = var.convert().y; + node["Z"] = var.convert().z; + } + else if (varType == rttr::type::get()) + { + node.SetStyle(YAML::EmitterStyle::Flow); + node["X"] = var.convert().x; + node["Y"] = var.convert().y; + } + else if (varType.is_arithmetic()) + { + bool ok = false; + if (varType == rttr::type::get()) + node = var.to_bool(); + else if (varType == rttr::type::get()) + node = var.to_int8(&ok); + else if (varType == rttr::type::get()) + node = var.to_int16(&ok); + else if (varType == rttr::type::get()) + node = var.to_int32(&ok); + else if (varType == rttr::type::get()) + node = var.to_int64(&ok); + else if (varType == rttr::type::get()) + node = var.to_uint8(&ok); + else if (varType == rttr::type::get()) + node = var.to_uint16(&ok); + else if (varType == rttr::type::get()) + node = var.to_uint32(&ok); + else if (varType == rttr::type::get()) + node = var.to_uint64(&ok); + else if (varType == rttr::type::get()) + node = var.to_float(&ok); + else if (varType == rttr::type::get()) + node = var.to_double(&ok); + //else if (varType == rttr::type::get()) //same as uint8_t + // node = var.to_uint8(); + } + else if (varType.is_enumeration()) + { + bool ok = false; + auto result = var.to_string(&ok); + if (ok) + { + node = var.to_string(); + } + else + { + ok = false; + auto value = var.to_uint64(&ok); + if (ok) + node = value; + else + node = YAML::Null; + } + } + else + { + auto properties = var.get_type().get_properties(); + for (auto property : properties) + { + node[property.get_name().data()] = RTTRToNode(property.get_value(var)); + } + } + return node; + } + + template , bool> = true> + static YAML::Node SerializeComponentToNode(ComponentType* component) + { + YAML::Node node{}; + if (!component) + return node; + + auto componentType = rttr::type::get(); + node = RTTRToNode(*component); + + return node; + } + + template , bool> = true> + static void InitializeProperty(ComponentType* component, rttr::property const& prop, YAML::Node const& propertyNode) + { + auto propType = prop.get_type(); + if (propType == rttr::type::get()) + { + SHVec4 vec{ propertyNode["X"].as(), propertyNode["Y"].as(), propertyNode["Z"].as(), propertyNode["W"].as() }; + prop.set_value(component, vec); + } + else if (propType == rttr::type::get()) + { + SHVec3 vec{ propertyNode["X"].as(), propertyNode["Y"].as(), propertyNode["Z"].as() }; + prop.set_value(component, vec); + } + else if (propType == rttr::type::get()) + { + SHVec2 vec{ propertyNode["X"].as(), propertyNode["Y"].as() }; + prop.set_value(component, vec); + } + else if (propType.is_arithmetic()) + { + bool ok = false; + if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + } + else if (propType.is_enumeration()) + { + auto enumAlign = prop.get_enumeration(); + prop.set_value(component, enumAlign.name_to_value(propertyNode.as())); + } + else + { + auto properties = propType.get_properties(); + for (auto property : properties) + { + InitializeProperty(component, property, propertyNode[property.get_name().data()]); + } + } + } + + template , bool> = true> + static void InitializeComponentFromNode(YAML::Node const& componentsNode, EntityID const& eid) + { + auto component = SHComponentManager::GetComponent_s(eid); + if (componentsNode.IsNull() && !component) + return; + auto rttrType = rttr::type::get(); + auto componentNode = componentsNode[rttrType.get_name().data()]; + if (componentsNode.IsNull()) + return; + auto properties = rttrType.get_properties(); + for (auto const& prop : properties) + { + if (componentNode[prop.get_name().data()]) + { + InitializeProperty(component, prop, componentNode[prop.get_name().data()]); + } + } + } + + }; +} diff --git a/SHADE_Engine/src/Tools/SHClipboardUtilities.cpp b/SHADE_Engine/src/Tools/SHClipboardUtilities.cpp new file mode 100644 index 00000000..061a5ec6 --- /dev/null +++ b/SHADE_Engine/src/Tools/SHClipboardUtilities.cpp @@ -0,0 +1,49 @@ +#include "SHpch.h" +#include "SHClipboardUtilities.h" + +namespace SHADE +{ + void SHClipboardUtilities::WriteToClipboard(std::string const& str) noexcept + { + if(str.empty()) + return; + HWND const hwnd = GetDesktopWindow(); + OpenClipboard(hwnd); + EmptyClipboard(); + + auto const size = str.size() + 1; + const HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, size); + if(hGlobal) + { + std::memcpy(GlobalLock(hGlobal), str.c_str(), size); + GlobalUnlock(hGlobal); + SetClipboardData(CF_TEXT, hGlobal); + } + else + { + SHLOG_ERROR("Failed to write to clipboard: {}", str.c_str()) + } + CloseClipboard(); + GlobalFree(hGlobal); + } + + std::string const SHClipboardUtilities::GetDataFromClipboard() noexcept + { + HWND const hwnd = GetDesktopWindow(); + if(!OpenClipboard(hwnd)) + { + SHLOG_ERROR("Failed to open clipboard") + return std::string(); + } + + if(HANDLE const dataHandle = GetClipboardData(CF_TEXT); dataHandle) + { + std::string data(static_cast(GlobalLock(dataHandle))); + GlobalUnlock(dataHandle); + CloseClipboard(); + return data; + } + CloseClipboard(); + return std::string(); + } +} diff --git a/SHADE_Engine/src/Tools/SHClipboardUtilities.h b/SHADE_Engine/src/Tools/SHClipboardUtilities.h new file mode 100644 index 00000000..7f3acdbe --- /dev/null +++ b/SHADE_Engine/src/Tools/SHClipboardUtilities.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace SHADE +{ + class SHClipboardUtilities + { + public: + static void WriteToClipboard(std::string const& str) noexcept; + static std::string const GetDataFromClipboard() noexcept; + }; +} \ No newline at end of file diff --git a/SHADE_Managed/Quaternion.hxx b/SHADE_Managed/Quaternion.hxx new file mode 100644 index 00000000..0b07a34e --- /dev/null +++ b/SHADE_Managed/Quaternion.hxx @@ -0,0 +1,17 @@ +/************************************************************************************//*! +\file Quaternion.hxx +\author Diren D Bharwani, diren.dbharwani, 390002520 +\par email: diren.dbharwani\@digipen.edu +\date Oct 23, 2022 +\brief Contains the definitions of Quaternion struct. + + Note: This file is written in C++17/CLI. + +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 + +// TODO(Diren) diff --git a/SHADE_Managed/src/Editor/Editor.cxx b/SHADE_Managed/src/Editor/Editor.cxx index 735f8c2c..120f0274 100644 --- a/SHADE_Managed/src/Editor/Editor.cxx +++ b/SHADE_Managed/src/Editor/Editor.cxx @@ -29,6 +29,8 @@ of DigiPen Institute of Technology is prohibited. #include "Editor/IconsMaterialDesign.h" #include "Editor/Command/SHCommandManager.h" #include "Editor/Command/SHCommand.hpp" +#include "TooltipAttribute.hxx" +#include "RangeAttribute.hxx" // Using Directives using namespace System; @@ -48,17 +50,54 @@ using namespace System::Collections::Generic; /// 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); \ - } \ -} \ +#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, &isHovered))\ + { \ + field->SetValue(object, val); \ + registerUndoAction(object, field, val, oldVal); \ + } \ +} \ +/// +/// Alternative to RENDER_FIELD that checks for RangeAttribute and switches to a slider +/// instead. +/// +/// 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_RANGE(MANAGED_TYPE, NATIVE_TYPE, FUNC) \ +(field->FieldType == MANAGED_TYPE::typeid) \ +{ \ + NATIVE_TYPE val = safe_cast(field->GetValue(object)); \ + NATIVE_TYPE oldVal = val; \ + \ + RangeAttribute^ rangeAttrib = hasAttribute(field); \ + const std::string FIELD_NAME = Convert::ToNative(field->Name); \ + bool changed = false; \ + if (rangeAttrib) \ + { \ + changed = SHEditorUI::InputSlider \ + ( \ + FIELD_NAME, \ + static_cast(rangeAttrib->Min), \ + static_cast(rangeAttrib->Max), \ + val, &isHovered \ + ); \ + } \ + else \ + { \ + changed = SHEditorUI::FUNC(FIELD_NAME, val, &isHovered); \ + } \ + \ + if (changed) \ + { \ + 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 @@ -76,7 +115,8 @@ using namespace System::Collections::Generic; { \ NATIVE_TYPE val = Convert::ToNative(safe_cast(field->GetValue(object))); \ NATIVE_TYPE oldVal = val; \ - if (SHEditorUI::FUNC(Convert::ToNative(field->Name), val)) \ + \ + if (SHEditorUI::FUNC(Convert::ToNative(field->Name), val, &isHovered)) \ { \ field->SetValue(object, Convert::ToCLI(val)); \ registerUndoAction(object, field, Convert::ToCLI(val), Convert::ToCLI(oldVal)); \ @@ -196,16 +236,18 @@ namespace SHADE } 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) + bool isHovered = false; + + if RENDER_FIELD_RANGE (Int16, int, InputInt) + else if RENDER_FIELD_RANGE (Int32, int, InputInt) + else if RENDER_FIELD_RANGE (Int64, int, InputInt) + else if RENDER_FIELD_RANGE (UInt16, unsigned int, InputUnsignedInt) + else if RENDER_FIELD_RANGE (UInt32, unsigned int, InputUnsignedInt) + else if RENDER_FIELD_RANGE (UInt64, unsigned int, InputUnsignedInt) + else if RENDER_FIELD_RANGE (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 RENDER_FIELD_RANGE (float, float, InputFloat) + else if RENDER_FIELD_RANGE (double, double, InputDouble) else if (field->FieldType->IsSubclassOf(Enum::typeid)) { // Get all the names of the enums @@ -244,6 +286,15 @@ namespace SHADE registerUndoAction(object, field, Convert::ToCLI(val), Convert::ToCLI(oldVal)); } } + + // Check if the field has a specific attribute + TooltipAttribute^ toolTip = hasAttribute(field); + if (toolTip && isHovered) + { + SHEditorUI::BeginTooltip(); + SHEditorUI::Text(Convert::ToNative(toolTip->Description)); + SHEditorUI::EndTooltip(); + } } void Editor::renderScriptContextMenu(Entity entity, Script^ script) @@ -274,4 +325,24 @@ namespace SHADE SHCommandManager::RegisterCommand(std::reinterpret_pointer_cast(std::make_shared())); } + generic + Attribute Editor::hasAttribute(System::Reflection::FieldInfo^ field) + { + array^ attributes = field->GetCustomAttributes(true); + for each (System::Object^ attrib in attributes) + { + try + { + Attribute attribute = safe_cast(attrib); + if (attribute != nullptr) + return attribute; + } + catch (System::InvalidCastException^) + { + continue; + } + } + // Failed to find + return Attribute{}; + } } diff --git a/SHADE_Managed/src/Editor/Editor.hxx b/SHADE_Managed/src/Editor/Editor.hxx index c4800645..6b59589a 100644 --- a/SHADE_Managed/src/Editor/Editor.hxx +++ b/SHADE_Managed/src/Editor/Editor.hxx @@ -23,7 +23,7 @@ namespace SHADE /// /// Static class for Editor-related functions /// - public ref class Editor abstract sealed + private ref class Editor abstract sealed { public: /*-----------------------------------------------------------------------------*/ @@ -48,7 +48,13 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* UndoRedoStack Functions */ /*-----------------------------------------------------------------------------*/ + /// + /// Undoes the last script inspector change if there is any. + /// static void Undo(); + /// + /// Redoes the last script inspector change if there is any. + /// static void Redo(); private: @@ -86,5 +92,7 @@ namespace SHADE /// 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); + generic where Attribute : System::Attribute + static Attribute hasAttribute(System::Reflection::FieldInfo^ field); }; } diff --git a/SHADE_Managed/src/Editor/RangeAttribute.cxx b/SHADE_Managed/src/Editor/RangeAttribute.cxx new file mode 100644 index 00000000..0d548cf7 --- /dev/null +++ b/SHADE_Managed/src/Editor/RangeAttribute.cxx @@ -0,0 +1,39 @@ +/************************************************************************************//*! +\file RangeAttribute.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 18, 2022 +\brief Contains the definition of the functions of the managed Range Attribute + 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. +*//*************************************************************************************/ +#include "SHpch.h" +#include "RangeAttribute.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Properties */ + /*---------------------------------------------------------------------------------*/ + float RangeAttribute::Min::get() + { + return minVal; + } + float RangeAttribute::Max::get() + { + return maxVal; + } + + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + RangeAttribute::RangeAttribute(float min, float max) + : minVal { min } + , maxVal { max } + {} +} diff --git a/SHADE_Managed/src/Editor/RangeAttribute.hxx b/SHADE_Managed/src/Editor/RangeAttribute.hxx new file mode 100644 index 00000000..a724816d --- /dev/null +++ b/SHADE_Managed/src/Editor/RangeAttribute.hxx @@ -0,0 +1,61 @@ +/************************************************************************************//*! +\file RangeAttribute.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 18, 2022 +\brief Contains the definition of the managed Range Attribute 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 + +namespace SHADE +{ + /// + /// Simple attribute to constrain the range of values for a field on the editor. + /// + [System::AttributeUsage(System::AttributeTargets::Field)] + public ref class RangeAttribute : public System::Attribute + { + public: + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ + /// + /// Minimum value for the Ranged field. + /// + property float Min + { + float get(); + } + /// + /// Maximum value for the Ranged field. + /// + property float Max + { + float get(); + } + + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Constructor for a Tooltip attribute that fills in the description. + /// + /// Text to be shown when a field is hovered. + RangeAttribute(float min, float max); + + private: + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + float minVal; + float maxVal; + }; +} + diff --git a/SHADE_Managed/src/Editor/TooltipAttribute.cxx b/SHADE_Managed/src/Editor/TooltipAttribute.cxx new file mode 100644 index 00000000..8d5a5d55 --- /dev/null +++ b/SHADE_Managed/src/Editor/TooltipAttribute.cxx @@ -0,0 +1,34 @@ +/************************************************************************************//*! +\file TooltipAttribute.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 18, 2022 +\brief Contains the definition of the functions of the managed Tooltip Attribute + 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. +*//*************************************************************************************/ +#include "SHpch.h" +#include "TooltipAttribute.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Properties */ + /*---------------------------------------------------------------------------------*/ + System::String^ TooltipAttribute::Description::get() + { + return desc; + } + + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + TooltipAttribute::TooltipAttribute(System::String^ description) + : desc { description } + {} +} diff --git a/SHADE_Managed/src/Editor/TooltipAttribute.hxx b/SHADE_Managed/src/Editor/TooltipAttribute.hxx new file mode 100644 index 00000000..18cbec3a --- /dev/null +++ b/SHADE_Managed/src/Editor/TooltipAttribute.hxx @@ -0,0 +1,53 @@ +/************************************************************************************//*! +\file TooltipAttribute.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 18, 2022 +\brief Contains the definition of the managed Tooltip Attribute 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 + +namespace SHADE +{ + /// + /// Simple attribute to provide a field in a script with a tooltip. + /// + [System::AttributeUsage(System::AttributeTargets::Field)] + public ref class TooltipAttribute : public System::Attribute + { + public: + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ + /// + /// Description that is to be shown in the Tooltip. + /// + property System::String^ Description + { + System::String^ get(); + } + + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Constructor for a Tooltip attribute that fills in the description. + /// + /// Text to be shown when a field is hovered. + TooltipAttribute(System::String^ description); + + private: + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + System::String^ desc; + }; +} + diff --git a/SHADE_Managed/src/Serialisation/SerialiseFieldAttribute.cxx b/SHADE_Managed/src/Engine/Time.cxx similarity index 64% rename from SHADE_Managed/src/Serialisation/SerialiseFieldAttribute.cxx rename to SHADE_Managed/src/Engine/Time.cxx index c371d200..ff0628e7 100644 --- a/SHADE_Managed/src/Serialisation/SerialiseFieldAttribute.cxx +++ b/SHADE_Managed/src/Engine/Time.cxx @@ -1,27 +1,29 @@ /************************************************************************************//*! -\file SerializeFieldAttribute.cxx +\file Time.cxx \author Tng Kah Wei, kahwei.tng, 390009620 \par email: kahwei.tng\@digipen.edu -\date Nov 5, 2021 -\brief Contains the definition of the functions of the managed SerializeField - Attribute class. +\date Oct 19, 2022 +\brief This file is present so that the properties in Time.hxx would be compiled + into the DLL. Note: This file is written in C++17/CLI. -Copyright (C) 2021 DigiPen Institute of Technology. +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 "SerializeFieldAttribute.hxx" +#include "Time.hxx" namespace SHADE { /*---------------------------------------------------------------------------------*/ - /* Constructors */ + /* Properties */ /*---------------------------------------------------------------------------------*/ - SerializeField::SerializeField() - {} -} + double Time::DeltaTime::get() + { + return SHFrameRateController::GetRawDeltaTime(); + } +} \ No newline at end of file diff --git a/SHADE_Managed/src/Engine/Time.hxx b/SHADE_Managed/src/Engine/Time.hxx new file mode 100644 index 00000000..969eea03 --- /dev/null +++ b/SHADE_Managed/src/Engine/Time.hxx @@ -0,0 +1,41 @@ +/************************************************************************************//*! +\file Time.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 19, 2022 +\brief Contains the definition of the Time static class and the definition of + its properties. + + 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 + +#include "FRC/SHFramerateController.h" + +namespace SHADE +{ + /// + /// Static class that contains the functions for working with time. + /// + public ref class Time abstract sealed + { + public: + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ + /// + /// Time taken to process the previous frame. + /// Note, is affected by TimeScale. Use UnscaledDeltaTime if you wish to retrieve + /// real world time. This is also affected by MaxDeltaTime clamping that + /// UnscaledDeltaTime is subject to. + /// + static property double DeltaTime + { + double get(); + } + }; +} \ No newline at end of file diff --git a/SHADE_Managed/src/Math/Vector3.hxx b/SHADE_Managed/src/Math/Vector3.hxx index e6cdc7d4..8b66439c 100644 --- a/SHADE_Managed/src/Math/Vector3.hxx +++ b/SHADE_Managed/src/Math/Vector3.hxx @@ -11,6 +11,7 @@ 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 // Standard Libraries diff --git a/SHADE_Managed/src/Scripts/ScriptStore.cxx b/SHADE_Managed/src/Scripts/ScriptStore.cxx index 252ab071..b6bc1815 100644 --- a/SHADE_Managed/src/Scripts/ScriptStore.cxx +++ b/SHADE_Managed/src/Scripts/ScriptStore.cxx @@ -26,6 +26,7 @@ of DigiPen Institute of Technology is prohibited. #include "Utility/Convert.hxx" #include "Script.hxx" #include "Engine/Entity.hxx" +#include "Serialisation/ReflectionUtilities.hxx" namespace SHADE { @@ -470,72 +471,90 @@ namespace SHADE } SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") } - bool ScriptStore::SerialiseScripts(Entity entity, System::Text::StringBuilder^ buffer, int bufferSize) + + bool ScriptStore::SerialiseScripts(Entity entity, System::IntPtr yamlNodePtr) { SAFE_NATIVE_CALL_BEGIN - // Create a buffer that we can work with temporarily - System::Text::StringBuilder^ jsonString = gcnew System::Text::StringBuilder(); + // Convert to pointer + YAML::Node* yamlNode = reinterpret_cast(yamlNodePtr.ToPointer()); + // Check if yamlNode is valid + if (yamlNode == nullptr) + { + Debug::LogWarning("[ScriptStore] Attempted to serialise scripts with an invalid YAML Node! Skipping."); + return false; + } + // Check if entity exists, otherwise nothing if (!EntityUtils::IsValid(entity)) - return true; - + { + Debug::LogWarning("[ScriptStore] Attempted to serialise scripts for an invalid Entity! Skipping."); + return false; + } + // Check if entity exists in the script storage - if (!scripts.ContainsKey(entity)) + if (!scripts.ContainsKey(entity)) return true; // Serialise each script + yamlNode->SetStyle(YAML::EmitterStyle::Block); System::Collections::Generic::List^ scriptList = scripts[entity]; - for (int i = 0; i < scriptList->Count; ++i) + for each (Script^ script in scriptList) { - throw gcnew System::NotImplementedException; - //jsonString->Append(ReflectionUtilities::Serialise(scriptList[i])); - - // Only add separator if is not last script - if (i != scriptList->Count - 1) - { - jsonString->Append(",\r\n"); - } + ReflectionUtilities::Serialise(script, *yamlNode); } - // Check if the size is too big - if (jsonString->Length > bufferSize) - return false; - - // Otherwise we copy it over - buffer->Clear(); - buffer->Append(jsonString->ToString()); return true; SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") return false; } - bool ScriptStore::DeserialiseScript(Entity entity, System::String^ yaml) + bool ScriptStore::DeserialiseScripts(Entity entity, System::IntPtr yamlNodePtr) { SAFE_NATIVE_CALL_BEGIN + // Convert to pointer + YAML::Node* yamlNode = reinterpret_cast(yamlNodePtr.ToPointer()); + + // Check if yamlNode is valid + if (yamlNode == nullptr) + { + Debug::LogWarning("[ScriptStore] Attempted to deserialise scripts with an invalid YAML Node! Skipping."); + return false; + } + // Check if entity exists, otherwise nothing if (!EntityUtils::IsValid(entity)) - return false; - - // Get the name of the script - const int FIRST_QUOTE = yaml->IndexOf('\"'); - const int FIRST_COLON = yaml->IndexOf(':'); - if (FIRST_QUOTE < 0 || FIRST_COLON < 0) // No script name, it's invalid - return false; - const int SCRIPT_NAME_START = FIRST_QUOTE + 1; - const int SCRIPT_NAME_END = FIRST_COLON - 1; - System::String^ typeName = yaml->Substring(SCRIPT_NAME_START, SCRIPT_NAME_END - SCRIPT_NAME_START); - - // Create the script - Script^ script; - if (AddScriptViaNameWithRef(entity, typeName, script)) { - // Copy the data in - throw gcnew System::NotImplementedException; - //ReflectionUtilities::Deserialise(json, script); - return true; + Debug::LogWarning("[ScriptStore] Attempted to deserialise scripts for an invalid Entity! Skipping."); + return false; } + // Go through all elements in the node + for (YAML::Node& node : *yamlNode) + { + // Get the name of the script + if (!node["Type"]) + { + Debug::LogWarning("[ScriptStore] Script with no type detected, skipping."); + continue; + } + + System::String^ typeName = Convert::ToCLI(node["Type"].as()); + + // Create + Script^ script; + if (AddScriptViaNameWithRef(entity, typeName, script)) + { + // Copy the data in + ReflectionUtilities::Deserialise(script, node); + } + else + { + Debug::LogWarning("[ScriptStore] Script with unloaded type detected, skipping."); + } + } + return true; + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") return false; } diff --git a/SHADE_Managed/src/Scripts/ScriptStore.hxx b/SHADE_Managed/src/Scripts/ScriptStore.hxx index cc0c1db5..4a9be721 100644 --- a/SHADE_Managed/src/Scripts/ScriptStore.hxx +++ b/SHADE_Managed/src/Scripts/ScriptStore.hxx @@ -17,6 +17,7 @@ of DigiPen Institute of Technology is prohibited. // Project Includes #include "Engine/Entity.hxx" #include "Script.hxx" +#include "Serialization/SHSerialization.h" namespace SHADE { @@ -237,27 +238,23 @@ namespace SHADE /* Serialisation Functions */ /*-----------------------------------------------------------------------------*/ /// - /// Generates a JSON string that represents the set of Scripts attached - /// to the specified Entity. + /// Populates a YAML node with the scripts for a specified Entity. ///

/// This function should only be called from native unmanaged code. ///
/// The Entity to Serialise. - /// - /// StringBuilder handle that maps to a native char array that will contain the - /// serialised string. - /// - /// - /// The size of the char array. + /// + /// Pointer to a YAML::Node that will be populated with all of the serialised + /// scripts and their associated fields. /// /// /// True if serialisation is successful. False if the buffer is too small for /// the serialised output. /// - static bool SerialiseScripts(Entity entity, System::Text::StringBuilder^ buffer, int bufferSize); + static bool SerialiseScripts(Entity entity, System::IntPtr yamlNode); /// - /// Processes a JSON string that represents a single Script and attaches - /// it onto the specified Entity. + /// Processes a YAML node that contains a list of multiple scripts to be loaded + /// into the specified Entity. ///

/// This function should only be called from native unmanaged code. ///
@@ -265,10 +262,10 @@ namespace SHADE /// The Entity to attach the deserialised Scripts to. /// /// - /// JSON string that describes the Script to serialise. + /// Pointer to the YAML::Node that contains serialized script data. /// /// - static bool DeserialiseScript(Entity entity, System::String^ yaml); + static bool DeserialiseScripts(Entity entity, System::IntPtr yamlNode); private: /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Serialisation/ReflectionUtilities.cxx b/SHADE_Managed/src/Serialisation/ReflectionUtilities.cxx index 2a9cc57c..3e963818 100644 --- a/SHADE_Managed/src/Serialisation/ReflectionUtilities.cxx +++ b/SHADE_Managed/src/Serialisation/ReflectionUtilities.cxx @@ -38,6 +38,11 @@ if (iter != jsonValue.MemberEnd()) \ vec.MEMBER = iter->value.GetDouble(); \ } \ +/*-------------------------------------------------------------------------------------*/ +/* File-Level Constants */ +/*-------------------------------------------------------------------------------------*/ +static const std::string_view SCRIPT_TYPE_YAMLTAG = "Type"; + /*-------------------------------------------------------------------------------------*/ /* Function Definitions */ /*-------------------------------------------------------------------------------------*/ @@ -61,13 +66,14 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Serialisation Functions */ /*---------------------------------------------------------------------------------*/ - void ReflectionUtilities::Serialise(System::Object^ object, YAML::Emitter& yaml) + void ReflectionUtilities::Serialise(System::Object^ object, YAML::Node& scriptListNode) { using namespace System::Reflection; // Create YAML object - yaml << YAML::Key << Convert::ToNative(object->GetType()->FullName); - yaml << YAML::BeginMap; + YAML::Node scriptNode; + scriptNode.SetStyle(YAML::EmitterStyle::Block); + scriptNode[SCRIPT_TYPE_YAMLTAG.data()] = Convert::ToNative(object->GetType()->FullName); // Get all fields System::Collections::Generic::IEnumerable^ fields = GetInstanceFields(object); @@ -78,12 +84,12 @@ namespace SHADE continue; // Serialise - writeFieldIntoYaml(field, object, yaml); + writeFieldIntoYaml(field, object, scriptNode); } - yaml << YAML::EndMap; + scriptListNode.push_back(scriptNode); } - void ReflectionUtilities::Deserialise(YAML::Node& yamlNode, Object^ object) + void ReflectionUtilities::Deserialise(Object^ object, YAML::Node& yamlNode) { using namespace System::Reflection; @@ -117,53 +123,63 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Serialization Helper Functions */ /*---------------------------------------------------------------------------------*/ - void ReflectionUtilities::writeFieldIntoYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Emitter& yaml) + void ReflectionUtilities::writeFieldIntoYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& yamlNode) { - // Field Name - yaml << YAML::Key << Convert::ToNative(fieldInfo->Name); - - // Field Value - yaml << YAML::Value; - if (fieldInsertYaml (fieldInfo, object, yaml) || - fieldInsertYaml (fieldInfo, object, yaml) || - fieldInsertYaml (fieldInfo, object, yaml) || - fieldInsertYaml(fieldInfo, object, yaml) || - fieldInsertYaml(fieldInfo, object, yaml) || - fieldInsertYaml(fieldInfo, object, yaml) || - fieldInsertYaml (fieldInfo, object, yaml) || - fieldInsertYaml (fieldInfo, object, yaml) || - fieldInsertYaml (fieldInfo, object, yaml) || - fieldInsertYaml (fieldInfo, object, yaml)) + // Field YAML Node + YAML::Node fieldNode; + + // Retrieve string for the YAML + const bool PRIMITIVE_SERIALIZED = fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode); + + // Serialization of more complex types + if (!PRIMITIVE_SERIALIZED) { - return; - } - else if (fieldInfo->FieldType->IsSubclassOf(System::Enum::typeid)) - { - yaml << safe_cast(fieldInfo->GetValue(object)); - } - else if (fieldInfo->FieldType == System::String::typeid) - { - System::String^ str = safe_cast(fieldInfo->GetValue(object)); - yaml << Convert::ToNative(str); - } - else if (fieldInfo->FieldType == Vector2::typeid) - { - Vector2 vec = safe_cast(fieldInfo->GetValue(object)); - yaml << YAML::BeginSeq << YAML::Flow << vec.x << vec.y << YAML::EndSeq; - } - else if (fieldInfo->FieldType == Vector3::typeid) - { - Vector3 vec = safe_cast(fieldInfo->GetValue(object)); - yaml << YAML::BeginSeq << YAML::Flow << vec.x << vec.y << vec.z << YAML::EndSeq; - } - else // Not any of the supported types - { - Debug::LogWarning(Convert::ToNative(System::String::Format - ( - "[ReflectionUtilities] Failed to parse \"{0}\" of \"{1}\" type for serialization.", - fieldInfo->Name, fieldInfo->FieldType) - )); + if (fieldInfo->FieldType->IsSubclassOf(System::Enum::typeid)) + { + fieldNode = std::to_string(safe_cast(fieldInfo->GetValue(object))); + } + else if (fieldInfo->FieldType == System::String::typeid) + { + System::String^ str = safe_cast(fieldInfo->GetValue(object)); + fieldNode = Convert::ToNative(str); + } + else if (fieldInfo->FieldType == Vector2::typeid) + { + Vector2 vec = safe_cast(fieldInfo->GetValue(object)); + fieldNode.SetStyle(YAML::EmitterStyle::Flow); + fieldNode.push_back(vec.x); + fieldNode.push_back(vec.y); + } + else if (fieldInfo->FieldType == Vector3::typeid) + { + Vector3 vec = safe_cast(fieldInfo->GetValue(object)); + fieldNode.SetStyle(YAML::EmitterStyle::Flow); + fieldNode.push_back(vec.x); + fieldNode.push_back(vec.y); + fieldNode.push_back(vec.z); + } + else // Not any of the supported types + { + Debug::LogWarning(Convert::ToNative(System::String::Format + ( + "[ReflectionUtilities] Failed to parse \"{0}\" of \"{1}\" type for serialization.", + fieldInfo->Name, fieldInfo->FieldType) + )); + return; + } } + + // Store the field into YAML + yamlNode[Convert::ToNative(fieldInfo->Name)] = fieldNode; } void ReflectionUtilities::writeYamlIntoField(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node) diff --git a/SHADE_Managed/src/Serialisation/ReflectionUtilities.h++ b/SHADE_Managed/src/Serialisation/ReflectionUtilities.h++ index 88469b34..7c39232a 100644 --- a/SHADE_Managed/src/Serialisation/ReflectionUtilities.h++ +++ b/SHADE_Managed/src/Serialisation/ReflectionUtilities.h++ @@ -23,11 +23,12 @@ namespace SHADE /* Serialization Helper Functions */ /*---------------------------------------------------------------------------------*/ template - bool ReflectionUtilities::fieldInsertYaml(System::Reflection::FieldInfo^ fieldInfo, System::Object^ object, YAML::Emitter& emitter) + bool ReflectionUtilities::fieldInsertYaml(System::Reflection::FieldInfo^ fieldInfo, System::Object^ object, YAML::Node& fieldNode) { if (fieldInfo->FieldType == FieldType::typeid) { - emitter << safe_cast(fieldInfo->GetValue(object)); + const FieldType VALUE = safe_cast(fieldInfo->GetValue(object)); + fieldNode = static_cast(VALUE); return true; } @@ -37,7 +38,7 @@ namespace SHADE template bool ReflectionUtilities::fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node) { - return fieldAssignYaml(fieldInfo, object, node); + return fieldAssignYaml>(fieldInfo, object, node); } template diff --git a/SHADE_Managed/src/Serialisation/ReflectionUtilities.hxx b/SHADE_Managed/src/Serialisation/ReflectionUtilities.hxx index 53f8fa1d..403c913c 100644 --- a/SHADE_Managed/src/Serialisation/ReflectionUtilities.hxx +++ b/SHADE_Managed/src/Serialisation/ReflectionUtilities.hxx @@ -52,24 +52,24 @@ namespace SHADE /// attribute will be serialised. ///
/// The object to serialise. - static void Serialise(System::Object^ object, YAML::Emitter& yaml); + static void Serialise(System::Object^ object, YAML::Node& yamlNode); /// /// Deserialises a YAML node that contains a map of Scripts and copies the /// deserialised data into the specified object if there are matching fields. /// /// - /// The JSON string that contains the data to copy into this PlushieScript - /// object. + /// The JSON string that contains the data to copy into this Script object. /// /// The object to copy deserialised data into. - static void Deserialise(YAML::Node& yamlNode, Object^ object); + static void Deserialise(System::Object^ object, YAML::Node& yamlNode); + private: /*-----------------------------------------------------------------------------*/ /* Serialization Helper Functions */ /*-----------------------------------------------------------------------------*/ - static void writeFieldIntoYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Emitter& yaml); + static void writeFieldIntoYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& yamlNode); template - static bool fieldInsertYaml(System::Reflection::FieldInfo^ fieldInfo, System::Object^ object, YAML::Emitter& emitter); + static bool fieldInsertYaml(System::Reflection::FieldInfo^ fieldInfo, System::Object^ object, YAML::Node& fieldNode); static void writeYamlIntoField(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node); template static bool fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node); diff --git a/SHADE_Managed/src/Serialisation/SerializeFieldAttribute.hxx b/SHADE_Managed/src/Serialisation/SerializeFieldAttribute.hxx index 533ded2a..7a7bb83c 100644 --- a/SHADE_Managed/src/Serialisation/SerializeFieldAttribute.hxx +++ b/SHADE_Managed/src/Serialisation/SerializeFieldAttribute.hxx @@ -21,15 +21,6 @@ namespace SHADE ///
[System::AttributeUsage(System::AttributeTargets::Field)] public ref class SerializeField : public System::Attribute - { - public: - /*-----------------------------------------------------------------------------*/ - /* Constructors */ - /*-----------------------------------------------------------------------------*/ - /// - /// Default Constructor - /// - SerializeField(); - }; + {}; } diff --git a/SHADE_Managed/src/Utility/Convert.hxx b/SHADE_Managed/src/Utility/Convert.hxx index b41ffef4..f04cbf4b 100644 --- a/SHADE_Managed/src/Utility/Convert.hxx +++ b/SHADE_Managed/src/Utility/Convert.hxx @@ -91,4 +91,68 @@ namespace SHADE /// Managed copy of a native std::string. static System::String^ ToCLI(const std::string& str); }; + + /// + /// Type Transformer for managed types to native types. + /// + /// + /// Managed type to get the native type for. + /// + template + struct ToNativeType + { + public: + using Value = void; + }; + template<> struct ToNativeType { using Value = int16_t; }; + template<> struct ToNativeType { using Value = int32_t; }; + template<> struct ToNativeType { using Value = int64_t; }; + template<> struct ToNativeType { using Value = uint16_t; }; + template<> struct ToNativeType { using Value = uint32_t; }; + template<> struct ToNativeType { using Value = uint64_t; }; + template<> struct ToNativeType { using Value = int8_t; }; + template<> struct ToNativeType { using Value = bool; }; + template<> struct ToNativeType { using Value = double; }; + template<> struct ToNativeType { using Value = float; }; + + /// + /// Alias for ToNativeType::Value + /// + /// + /// Managed type to get the native type for. + /// + template + using ToNativeType_T = typename ToNativeType::Value; + + /// + /// Type Transformer for native types to managed types. + /// + /// + /// Managed type to get the native type for. + /// + template + struct ToManagedType + { + public: + using Value = void; + }; + template<> struct ToManagedType { using Value = System::Byte; }; + template<> struct ToManagedType { using Value = System::Int16; }; + template<> struct ToManagedType { using Value = System::Int32; }; + template<> struct ToManagedType { using Value = System::Int64; }; + template<> struct ToManagedType { using Value = System::UInt16; }; + template<> struct ToManagedType { using Value = System::UInt32; }; + template<> struct ToManagedType { using Value = System::UInt64; }; + template<> struct ToManagedType { using Value = bool; }; + template<> struct ToManagedType { using Value = double; }; + template<> struct ToManagedType { using Value = float; }; + + /// + /// Alias for ToManagedType::Value + /// + /// + /// Managed type to get the native type for. + /// + template + using ToManagedType_T = typename ToManagedType::Value; } diff --git a/TempScriptsFolder/RaccoonShowcase.cs b/TempScriptsFolder/RaccoonShowcase.cs index e2d6454d..4191a6e5 100644 --- a/TempScriptsFolder/RaccoonShowcase.cs +++ b/TempScriptsFolder/RaccoonShowcase.cs @@ -3,8 +3,16 @@ using System; public class RaccoonShowcase : Script { - public double RotateSpeed = 1.0; - public Vector3 ScaleSpeed = new Vector3(1.0, 1.0, 0.0); + [SerializeField] + [Tooltip("Speed of the rotation in radians per second.")] + [Range(-1.0f, 2.0f)] + private double RotateSpeed = 1.0; + //[SerializeField] + //[Range(-5, 20)] + //private int test = 5; + [SerializeField] + [Tooltip("Speed of the scaling in radians per second around each axis.")] + private Vector3 ScaleSpeed = new Vector3(1.0, 1.0, 0.0); private Transform Transform; private double rotation = 0.0; private Vector3 scale = Vector3.Zero; diff --git a/TempScriptsFolder/RaccoonSpin.cs b/TempScriptsFolder/RaccoonSpin.cs index 7785cfd5..d6ee1c9f 100644 --- a/TempScriptsFolder/RaccoonSpin.cs +++ b/TempScriptsFolder/RaccoonSpin.cs @@ -3,7 +3,9 @@ using System; public class RaccoonSpin : Script { - public double RotateSpeed = 1.0; + [SerializeField] + [Tooltip("Speed of the rotation in radians per second.")] + private double RotateSpeed = 1.0; private double rotation = 0.0; private Transform Transform; public RaccoonSpin(GameObject gameObj) : base(gameObj) { } diff --git a/TempShaderFolder/KirschCs.glsl b/TempShaderFolder/KirschCs.glsl new file mode 100644 index 00000000..3dec174d --- /dev/null +++ b/TempShaderFolder/KirschCs.glsl @@ -0,0 +1,167 @@ +//#version 450 +// +//layout(local_size_x = 16, local_size_y = 16) in; +//layout(set = 4, binding = 0, rgba8) uniform image2D targetImage; +// +// +//void main() +//{ +// ivec2 imageSize = imageSize (targetImage); +// +// if (gl_GlobalInvocationID.x >= imageSize.x && gl_GlobalInvocationID.y >= imageSize.y) +// return; +// +// // load the image +// vec4 color = imageLoad (targetImage, ivec2 (gl_GlobalInvocationID)); +// +// // get the average +// float average = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b; +// +// // store result into result image +// imageStore(targetImage, ivec2(gl_GlobalInvocationID), vec4(average, average, average, 1.0f)); +// +//} +// +// +// +// + +/* Start Header *****************************************************************/ + +/*! \file (e.g. kirsch.comp) + + \author William Zheng, william.zheng, 60001906. Brandon Mak, brandon.hao 390003920. + + \par william.zheng\@digipen.edu. brandon.hao\@digipen.edu. + + \date Sept 20, 2022 + + \brief Copyright (C) 20xx 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. */ + + /* End Header *******************************************************************/ + +#version 450 + +#define MASK_WIDTH 3 +#define HALF_M_WIDTH MASK_WIDTH / 2 +#define SHM_WIDTH 18 +#define NUM_MASKS 8 + +layout(local_size_x = 16, local_size_y = 16) in; +layout(set = 4, binding = 0, rgba8) uniform image2D inputImage; +layout(set = 4, binding = 1, rgba8) uniform image2D resultImage; + +const float kirsch[8][3][3] = { + { + {5, 5, 5}, + {-3, 0, -3}, /*rotation 1 */ + {-3, -3, -3} + }, + { + {5, 5, -3}, + {5, 0, -3}, /*rotation 2 */ + {-3, -3, -3} + }, + { + {5, -3, -3}, + {5, 0, -3}, /*rotation 3 */ + {5, -3, -3} + }, + { + {-3, -3, -3}, + {5, 0, -3}, /*rotation 4 */ + {5, 5, -3} + }, + { + {-3, -3, -3}, + {-3, 0, -3}, /*rotation 5 */ + {5, 5, 5} + }, + { + {-3, -3, -3}, + {-3, 0, 5}, /*rotation 6 */ + {-3, 5, 5} + }, + { + {-3, -3, 5}, + {-3, 0, 5}, /*rotation 7 */ + {-3, -3, 5} + }, + { + {-3, 5, 5}, + {-3, 0, 5}, /*rotation 8 */ + {-3, -3, -3} + } +}; + +vec3 GetImageValues(ivec2 uv, ivec2 inputImageSize) +{ + if (uv.x >= 0 && uv.y >= 0 && uv.x < inputImageSize.x && uv.y < inputImageSize.y) + { + return imageLoad(inputImage, uv).rgb; + } + else + return vec3(0.0f); +} + +//two extra row/col +shared vec3 sData[16 + 2][16 + 2]; + +void main() +{ + // convenient variables + ivec3 globalThread = ivec3(gl_GlobalInvocationID); + ivec3 localThread = ivec3(gl_LocalInvocationID); + ivec2 inputImageSize = imageSize(inputImage); + + // load shared memory + ivec2 start = ivec2(gl_WorkGroupID) * ivec2(gl_WorkGroupSize) - ivec2(HALF_M_WIDTH); + for (int i = localThread.x; i < SHM_WIDTH; i += int(gl_WorkGroupSize.x)) + { + for (int j = localThread.y; j < SHM_WIDTH; j += int(gl_WorkGroupSize.y)) + { + // get from source image (either real values or 0) + vec3 sourceValue = GetImageValues(start + ivec2(i, j), inputImageSize); + sData[i][j] = sourceValue; + } + } + + // wait for shared memory to finish loading + barrier(); + + // max (between all 8 masks) + vec3 maxSum = vec3(0.0f); + + // loop through all masks + for (int i = 0; i < NUM_MASKS; ++i) + { + vec3 sum = vec3(0.0f); + + // start of shared memory + ivec2 shmStart = ivec2(localThread + HALF_M_WIDTH); + for (int j = -1; j < HALF_M_WIDTH + 1; ++j) + { + for (int k = -1; k < HALF_M_WIDTH + 1; ++k) + { + // Perform convolution using shared_memory + sum += sData[shmStart.x + j][shmStart.y + k] * kirsch[i][j + 1][k + 1]; + } + } + + // Get highest sum + maxSum = max(sum, maxSum); + } + + // average the max sum + maxSum = min(max(maxSum / 8, 0), 1.0f); + + // store result into result image + imageStore(resultImage, ivec2(gl_GlobalInvocationID.xy), vec4(maxSum, 1.0f)); + +} + + + + diff --git a/TempShaderFolder/KirschCs.spv b/TempShaderFolder/KirschCs.spv new file mode 100644 index 00000000..1ae5408b Binary files /dev/null and b/TempShaderFolder/KirschCs.spv differ