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

This commit is contained in:
maverickdgg 2022-10-19 09:57:52 +08:00
commit 33b173ab9e
238 changed files with 13201 additions and 2893 deletions

2
.gitignore vendored
View File

@ -362,3 +362,5 @@ MigrationBackup/
*.csproj
*.filters
Assets/Editor/Layouts/UserLayout.ini

BIN
Assets/Audio/Master.bank Normal file

Binary file not shown.

Binary file not shown.

BIN
Assets/Audio/footsteps.bank Normal file

Binary file not shown.

BIN
Assets/Cube.003.shmesh Normal file

Binary file not shown.

View File

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

BIN
Assets/Cube.012.shmesh Normal file

Binary file not shown.

View File

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

View File

@ -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

Binary file not shown.

View File

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

Binary file not shown.

View File

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

View File

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

View File

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

View File

@ -14,22 +14,34 @@
#include <chrono>
#include <ratio>
#include <ctime>
#define SDL_HINT_VIDEO_FOREIGN_WINDOW_VULKAN 1
#include <SDL.h>
#include "Scripting/SHScriptEngine.h"
#include "Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Scene/SHSceneManager.h"
#include "Math/Transform/SHTransformSystem.h"
#include "Input/SHInputManagerSystem.h"
#include "Scenes/SBTestScene.h"
#include "Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h"
// Managers
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Scene/SHSceneManager.h"
// Systems
#include "Scripting/SHScriptEngine.h"
#include "Physics/SHPhysicsSystem.h"
#include "Math/Transform/SHTransformSystem.h"
#include "Input/SHInputManager.h"
#include "FRC/SHFramerateController.h"
#include "AudioSystem/SHAudioSystem.h"
// Components
#include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Scenes/SBTestScene.h"
#include "Assets/SHAssetManager.h"
#include "Tools/SHLogger.h"
using namespace SHADE;
namespace Sandbox
@ -44,93 +56,112 @@ namespace Sandbox
)
{
// Set working directory
SHADE::SHFileUtilities::SetWorkDirToExecDir();
SHFileUtilities::SetWorkDirToExecDir();
window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
// Create Systems
SHADE::SHSystemManager::CreateSystem<SHADE::SHGraphicsSystem>();
SHADE::SHSystemManager::CreateSystem<SHADE::SHScriptEngine>();
// TODO(Diren): Create Physics System here
SHADE::SHSystemManager::CreateSystem<SHADE::SHTransformSystem>();
SHADE::SHGraphicsSystem* graphicsSystem = static_cast<SHADE::SHGraphicsSystem*>(SHADE::SHSystemManager::GetSystem<SHADE::SHGraphicsSystem>());
SHADE::SHSystemManager::CreateSystem<SHADE::SHInputManagerSystem>();
SHSystemManager::CreateSystem<SHGraphicsSystem>();
SHSystemManager::CreateSystem<SHScriptEngine>();
SHSystemManager::CreateSystem<SHPhysicsSystem>();
SHSystemManager::CreateSystem<SHTransformSystem>();
SHGraphicsSystem* graphicsSystem = static_cast<SHGraphicsSystem*>(SHSystemManager::GetSystem<SHGraphicsSystem>());
SHSystemManager::CreateSystem<SHAudioSystem>();
#ifdef SHEDITOR
SDL_Init(SDL_INIT_VIDEO);
sdlWindow = SDL_CreateWindowFrom(window.GetHWND());
SHSystemManager::CreateSystem<SHEditor>();
SHSystemManager::GetSystem<SHEditor>()->SetSDLWindow(sdlWindow);
#endif
// Create Routines
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHScriptEngine, SHADE::SHScriptEngine::FrameSetUpRoutine>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHScriptEngine, SHADE::SHScriptEngine::UpdateRoutine>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHScriptEngine, SHADE::SHScriptEngine::LateUpdateRoutine>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHScriptEngine, SHADE::SHScriptEngine::FrameCleanUpRoutine>();
SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::FrameSetUpRoutine>();
SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::UpdateRoutine>();
SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::LateUpdateRoutine>();
SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::FrameCleanUpRoutine>();
// TODO(Diren): Register Physics System & Routines here
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHTransformSystem, SHADE::SHTransformSystem::TransformUpdateRoutine>();
SHADE::SHComponentManager::CreateComponentSparseSet<SHADE::SHTransformComponent>();
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformUpdateRoutine>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHGraphicsSystem, SHADE::SHGraphicsSystem::BatcherDispatcherRoutine>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHGraphicsSystem, SHADE::SHGraphicsSystem::BeginRoutine>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHGraphicsSystem, SHADE::SHGraphicsSystem::RenderRoutine>();
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHGraphicsSystem, SHADE::SHGraphicsSystem::EndRoutine>();
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BatcherDispatcherRoutine>();
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BeginRoutine>();
SHADE::SHComponentManager::CreateComponentSparseSet<SHADE::SHRenderable>();
SHADE::SHComponentManager::CreateComponentSparseSet<SHADE::SHTransformComponent>();
#ifdef SHEDITOR
SHSystemManager::RegisterRoutine<SHEditor, SHEditor::EditorRoutine>();
#endif
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHInputManagerSystem, SHADE::SHInputManagerSystem::InputManagerRoutine>();
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::RenderRoutine>();
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::EndRoutine>();
SHComponentManager::CreateComponentSparseSet<SHRigidBodyComponent>();
SHComponentManager::CreateComponentSparseSet<SHColliderComponent>();
SHComponentManager::CreateComponentSparseSet<SHTransformComponent>();
SHComponentManager::CreateComponentSparseSet<SHRenderable>();
//TODO: REMOVE AFTER PRESENTATION
SHADE::SHAssetManager::LoadDataTemp("../../Assets/racoon.gltf");
SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonBag_Color_Ver4.dds");
SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.dds");
//SHAssetManager::LoadDataTemp("../../Assets/racoon.gltf");
//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");
//TODO: REMOVE AFTER PRESENTATION
auto id = SHFamilyID<SHSystem>::GetID<SHGraphicsSystem>();
auto id2 = SHFamilyID<SHSystem>::GetID<SHGraphicsSystem>();
auto id3 = SHFamilyID<SHSystem>::GetID<SHGraphicsSystem>();
SHSystemManager::RegisterRoutine<SHAudioSystem, SHAudioSystem::AudioRoutine>();
// Set up graphics system and windows
graphicsSystem->SetWindow(&window);
SHADE::SHSystemManager::Init();
#ifdef SHEDITOR
SDL_Init(SDL_INIT_VIDEO);
sdlWindow = SDL_CreateWindowFrom(window.GetHWND());
SHADE::SHEditor::Initialise(sdlWindow);
#else
#endif
SHSystemManager::Init();
SHSceneManager::InitSceneManager<SBTestScene>("TestScene");
SHFrameRateController::UpdateFRC();
SHAssetManager::Load();
}
void SBApplication::Update(void)
{
SHADE::SHGraphicsSystem* graphicsSystem = static_cast<SHADE::SHGraphicsSystem*>(SHADE::SHSystemManager::GetSystem<SHADE::SHGraphicsSystem>());
SHGraphicsSystem* graphicsSystem = SHADE::SHSystemManager::GetSystem<SHGraphicsSystem>();
SHEditor* editor = SHADE::SHSystemManager::GetSystem<SHEditor>();
//TODO: Change true to window is open
while (!window.WindowShouldClose())
{
SHFrameRateController::UpdateFRC();
SHInputManager::UpdateInput(SHFrameRateController::GetRawDeltaTime());
SHSceneManager::UpdateSceneManager();
SHSceneManager::SceneUpdate(1/60.0f);
//#ifdef SHEDITOR
//#endif
graphicsSystem->BeginRender();
#ifdef SHEDITOR
SHADE::SHEditor::Update(0.16f);
#endif
graphicsSystem->Run(1.0f);
graphicsSystem->EndRender();
SHADE::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();
}
void SBApplication::Exit(void)
{
#ifdef SHEDITOR
SHADE::SHEditor::Exit();
SDL_DestroyWindow(sdlWindow);
SDL_Quit();
#endif
SHSceneManager::Exit();
SHADE::SHSystemManager::Exit();
SHSystemManager::Exit();
SHAssetManager::Unload();
}
}

View File

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

View File

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

View File

@ -1,25 +1,37 @@
/*************************************************************************//**
* \file SHMeshAsset.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Struct to contain ready data for loading into GPU. Also used for
* compilation into binary files
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#include <vector>
#include "Math/SHMath.h"
#include "SH_API.h"
namespace SHADE
{
struct SHMeshAssetHeader
struct SH_API SHMeshAssetHeader
{
uint32_t vertexCount;
uint32_t indexCount;
std::string meshName;
};
struct SHMeshAsset
struct SH_API SHMeshAsset
{
bool compiled;
bool changed;
SHMeshAssetHeader header;
std::string meshName;
std::vector<SHVec3> vertexPosition;
std::vector<SHVec3> vertexTangent;
std::vector<SHVec3> vertexNormal;

View File

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

View File

@ -0,0 +1,72 @@
/*************************************************************************//**
* \file SHMeshCompiler.cpp
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to write data in SHMeshAsset into binary file for faster
* loading in the future
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#include "SHpch.h"
#include "SHMeshCompiler.h"
#include "Graphics/MiddleEnd/Meshes/SHMeshData.h"
#include <fstream>
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;
std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open file for writing mesh file: {}", path.string());
}
file.write(
reinterpret_cast<char const*>(&(asset.header.vertexCount)),
sizeof(uint32_t)
);
file.write(
reinterpret_cast<const char*>(&(asset.header.indexCount)),
sizeof(uint32_t)
);
auto const vertexVec3Byte {sizeof(SHVec3) * asset.header.vertexCount};
auto const vertexVec2Byte {sizeof(SHVec2) * asset.header.vertexCount};
file.write(
reinterpret_cast<char const*>(asset.vertexPosition.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexTangent.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexNormal.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.texCoords.data()),
vertexVec2Byte
);
file.write(
reinterpret_cast<char const*>(asset.indices.data()),
sizeof(uint32_t) * asset.header.indexCount
);
file.close();
return newPath;
}

View File

@ -0,0 +1,26 @@
/*************************************************************************//**
* \file SHMeshCompiler.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to write data in SHMeshAsset into binary file for faster
* loading in the future
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#include "../Asset Types/SHMeshAsset.h"
#include "../SHAssetMacros.h"
namespace SHADE
{
class SHMeshCompiler
{
private:
public:
static std::string CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept;
};
}

View File

@ -1,12 +1,25 @@
/*************************************************************************//**
* \file SHMeshLoader.cpp
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Implementation for Mesh loader. Accounts for custom binary format
* as well as GLTF file format.
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#include "SHpch.h"
#include "SHMeshLoader.h"
#include <assimp/postprocess.h>
#include <fstream>
namespace SHADE
{
Assimp::Importer SHMeshLoader::aiImporter;
void SHMeshLoader::ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes)
void SHMeshLoader::ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes) noexcept
{
for (size_t i {0}; i < node.mNumMeshes; ++i)
{
@ -20,15 +33,14 @@ namespace SHADE
}
}
SHMeshAsset SHMeshLoader::ProcessMesh(aiMesh const& mesh, aiScene const& scene)
SHMeshAsset SHMeshLoader::ProcessMesh(aiMesh const& mesh, aiScene const& scene) noexcept
{
(void)scene;
SHMeshAsset result
{
.compiled { false},
.changed { false },
.meshName { mesh.mName.C_Str() }
.changed { false }
};
for (size_t i{0}; i < mesh.mNumVertices; ++i)
@ -79,36 +91,33 @@ namespace SHADE
}
}
result.header.vertexCount = result.vertexPosition.size();
result.header.indexCount = result.indices.size();
result.header.vertexCount = static_cast<uint32_t>(result.vertexPosition.size());
result.header.indexCount = static_cast<uint32_t>(result.indices.size());
result.header.meshName = mesh.mName.C_Str();
return result;
}
bool SHMeshLoader::LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path)
void SHMeshLoader::LoadExternal(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept
{
const aiScene* scene = aiImporter.ReadFile(path.string().c_str(),
aiProcess_Triangulate
// Make sure we get triangles rather than nvert polygons
aiProcess_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_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_FindInvalidData // detect invalid model data, such as invalid normal vectors
| aiProcess_FlipUVs // flip the V to match the Vulkans way of doing UVs
);
if (!scene || !scene->HasMeshes())
{
SHLOG_ERROR("ERROR in GLTF::ASSIMP: {}\nFile: {}", aiImporter.GetErrorString(), path.string());
return false;
return;
}
//TODO MATERIALS FROM MESHES
//if (scene->HasMaterials())
//{
@ -123,7 +132,100 @@ namespace SHADE
//}
ProcessNode(*scene->mRootNode, *scene, meshes);
}
return true;
void SHMeshLoader::LoadSHMesh(SHMeshAsset& mesh, AssetPath path) noexcept
{
std::ifstream file{ path.string(), std::ios::in | std::ios::binary };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open SHMesh File: {}", path.string());
}
const std::string name{ path.stem().string() };
file.seekg(0);
uint32_t vertCount, indexCount;
std::vector<SHVec3> vertPos, vertTan, vertNorm;
std::vector<SHVec2> texCoord;
std::vector<uint32_t> indices;
file.read(reinterpret_cast<char*>(&vertCount), sizeof(uint32_t));
file.read(reinterpret_cast<char*>(&indexCount), sizeof(uint32_t));
auto const vertexVec3Byte{ sizeof(SHVec3) * vertCount };
auto const vertexVec2Byte{ sizeof(SHVec2) * vertCount };
vertPos.resize(vertCount);
vertTan.resize(vertCount);
vertNorm.resize(vertCount);
texCoord.resize(vertCount);
indices.resize(indexCount);
file.read(reinterpret_cast<char *>(vertPos.data()), vertexVec3Byte);
file.read(reinterpret_cast<char *>(vertTan.data()), vertexVec3Byte);
file.read(reinterpret_cast<char *>(vertNorm.data()), vertexVec3Byte);
file.read(reinterpret_cast<char *>(texCoord.data()), vertexVec2Byte);
file.read(reinterpret_cast<char *>(indices.data()), sizeof(uint32_t) * indexCount);
//for (auto i{ 0 }; i < vertCount; ++i)
//{
// file >> vertPos[i].x;
// file >> vertPos[i].y;
// file >> vertPos[i].z;
//}
//
//for (auto i{ 0 }; i < vertCount; ++i)
//{
// file >> vertTan[i].x;
// file >> vertTan[i].y;
// file >> vertTan[i].z;
//}
//for (auto i{ 0 }; i < vertCount; ++i)
//{
// file >> vertNorm[i].x;
// file >> vertNorm[i].y;
// file >> vertNorm[i].z;
//}
//for (auto i{ 0 }; i < vertCount; ++i)
//{
// file >> texCoord[i].x;
// file >> texCoord[i].y;
//}
//for (auto i{ 0 }; i < indexCount; ++i)
//{
// file >> indices[i];
//}
mesh.compiled = true;
mesh.changed = false;
mesh.header.indexCount = indexCount;
mesh.header.vertexCount = vertCount;
mesh.header.meshName = name;
mesh.vertexPosition = std::move(vertPos);
mesh.vertexTangent = std::move(vertTan);
mesh.vertexNormal = std::move(vertNorm);
mesh.texCoords = std::move(texCoord);
mesh.indices = std::move(indices);
file.close();
}
void SHMeshLoader::LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept
{
if (path.extension().string() == GLTF_EXTENSION)
{
LoadExternal(meshes, path);
return;
}
meshes.emplace_back();
LoadSHMesh(meshes.back(), path);
}
}

View File

@ -1,3 +1,14 @@
/*************************************************************************//**
* \file SHMeshLoader.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to load gltf mesh files and custom binary format
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
@ -12,10 +23,14 @@ namespace SHADE
private:
static Assimp::Importer aiImporter;
static void ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes);
static void ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes) noexcept;
static SHMeshAsset ProcessMesh(aiMesh const& mesh, aiScene const& scene) noexcept;
static void LoadExternal(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept;
static SHMeshAsset ProcessMesh(aiMesh const& mesh, aiScene const& scene);
public:
static bool LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path);
static void LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept;
static void LoadSHMesh(SHMeshAsset& meshes, AssetPath path) noexcept;
};
}

View File

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

View File

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

View File

@ -0,0 +1,75 @@
/*************************************************************************//**
* \file SHTextureCompiler.cpp
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to write data in SHTextureAsset into binary file for
* faster loading in the future
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#include "SHpch.h"
#include "SHTextureCompiler.h"
#include <fstream>
namespace SHADE
{
std::string SHTextureCompiler::CompileTextureBinary(SHTextureAsset const& asset, AssetPath path)
{
std::string newPath{ path.string() };
newPath = newPath.substr(0, newPath.find_last_of('.'));
newPath += TEXTURE_EXTENSION;
std::ofstream file{ newPath, std::ios::out | std::ios::binary };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open file for writing texture file: {}", path.string());
}
auto const intBytes{sizeof(uint32_t)};
uint32_t mipOffsetCount{ static_cast<uint32_t>(asset.mipOffsets.size()) };
file.write(
reinterpret_cast<char const*>(&asset.numBytes),
intBytes
);
file.write(
reinterpret_cast<char const*>(&asset.width),
intBytes
);
file.write(
reinterpret_cast<char const*>(&asset.height),
intBytes
);
file.write(
reinterpret_cast<char const*>(&asset.format),
sizeof(SHTexture::TextureFormat)
);
file.write(
reinterpret_cast<char const*>(&mipOffsetCount),
intBytes
);
file.write(
reinterpret_cast<char const*>(asset.mipOffsets.data()),
intBytes * asset.mipOffsets.size()
);
file.write(
reinterpret_cast<char const*>(asset.pixelData),
asset.numBytes
);
file.close();
return newPath;
}
}

View File

@ -0,0 +1,24 @@
/*************************************************************************//**
* \file SHTextureCompiler.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to write data in SHTextureAsset into binary file for
* faster loading in the future
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#include "Assets/Asset Types/SHTextureAsset.h"
#include "Assets/SHAssetMacros.h"
namespace SHADE
{
struct SHTextureCompiler
{
static std::string CompileTextureBinary(SHTextureAsset const& asset, AssetPath path);
};
}

View File

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

View File

@ -1,3 +1,14 @@
/*************************************************************************//**
* \file SHTextureLoader.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to load dds textures and custom binary format
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#define TINYDDSLOADER_IMPLEMENTATION
@ -13,7 +24,10 @@ namespace SHADE
static std::string TinyDDSResultToString(tinyddsloader::Result value);
static vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear);
static void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept;
public:
static void LoadImageAsset(AssetPath paths, SHTextureAsset& image);
static void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept;
};
}

View File

@ -1,3 +1,14 @@
/*************************************************************************//**
* \file SHAsset.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Struct for asset identification and meta file writing
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#include "Filesystem/SHFileSystem.h"

View File

@ -40,7 +40,7 @@ typedef FMOD::Sound* SHSound;
#define ASSET_META_VER "1.0"
// Asset type enum
enum class AssetType : uint8_t
enum class AssetType : AssetTypeMeta
{
INVALID = 0,
AUDIO = 1,
@ -57,7 +57,12 @@ enum class AssetType : uint8_t
};
//Directory
#define ASSET_ROOT "./Assets/"
#ifdef _PUBLISH
#define ASSET_ROOT "Assets"
#else
#define ASSET_ROOT "../../Assets"
#endif
// ASSET EXTENSIONS
#define META_EXTENSION ".shmeta"

View File

@ -17,6 +17,9 @@
#include "Libraries/SHMeshLoader.h"
#include "Libraries/SHTextureLoader.h"
#include "Libraries/SHMeshCompiler.h"
#include "Libraries/SHTextureCompiler.h"
namespace SHADE
{
FMOD::System* SHAssetManager::audioSystem;
@ -69,12 +72,13 @@ namespace SHADE
AssetType type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string().c_str());
std::string folder;
switch (type)
{
default:
//TODO:ASSERT UNSUPPORTED FILE TYPE
return std::filesystem::path();
}
//TODO Implement asset type generation
//switch (type)
//{
//default:
// //TODO:ASSERT UNSUPPORTED FILE TYPE
// return std::filesystem::path();
//}
return std::filesystem::path(ASSET_ROOT + folder + path.filename().string());
}
@ -105,12 +109,13 @@ namespace SHADE
meta.type = type;
std::string folder;
switch (type)
{
default:
folder = "";
break;
}
//TODO implement folder choosing
//switch (type)
//{
//default:
// folder = "";
// break;
//}
AssetPath path{ ASSET_ROOT + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) };
SHAssetMetaHandler::WriteMetaData(meta);
@ -199,7 +204,9 @@ namespace SHADE
{
AssetPath path{ p };
if (path.extension().string() == GLTF_EXTENSION)
if (path.extension().string() == FBX_EXTENSION
|| path.extension().string() == GLTF_EXTENSION
|| path.extension().string() == MESH_EXTENSION)
{
LoadGLTF(
{
@ -211,7 +218,8 @@ namespace SHADE
}
);
}
else if (path.extension().string() == DDS_EXTENSION)
else if (path.extension().string() == DDS_EXTENSION
|| path.extension().string() == TEXTURE_EXTENSION)
{
LoadDDS(
{
@ -247,6 +255,26 @@ namespace SHADE
return result;
}
SHMeshAsset const* SHAssetManager::GetMesh(AssetID id) noexcept
{
if (meshCollection.find(id) == meshCollection.end())
{
return nullptr;
}
return &meshCollection[id];
}
SHTextureAsset const* SHAssetManager::GetTexture(AssetID id) noexcept
{
if (textureCollection.find(id) == textureCollection.end())
{
return nullptr;
}
return &textureCollection[id];
}
/****************************************************************************
* \param Path for meta data file
* \param Path for asset file
@ -299,7 +327,22 @@ namespace SHADE
for (auto const& mesh : meshes)
{
meshCollection.emplace(GenerateAssetID(AssetType::MESH), mesh);
auto id{ GenerateAssetID(AssetType::MESH) };
meshCollection.emplace(id, mesh);
AssetPath path;
if (!mesh.compiled)
{
path = SHMeshCompiler::CompileMeshBinary(mesh, asset.path);
}
assetCollection.emplace_back(
mesh.header.meshName,
id,
AssetType::MESH,
path,
0
);
}
}
@ -309,7 +352,21 @@ namespace SHADE
SHTextureLoader::LoadImageAsset(asset.path, image);
textureCollection.emplace(GenerateAssetID(AssetType::DDS), image);
if (!image.compiled)
{
auto id{ GenerateAssetID(AssetType::TEXTURE) };
textureCollection.emplace(id, image);
auto path{ SHTextureCompiler::CompileTextureBinary(image, asset.path) };
assetCollection.emplace_back(
image.name,
id,
AssetType::TEXTURE,
path,
0
);
}
}
/****************************************************************************
@ -326,8 +383,24 @@ namespace SHADE
****************************************************************************/
void SHAssetManager::LoadAllData() noexcept
{
//TODO Remove when on demand loading is done
for (auto const& asset : assetCollection)
{
switch (asset.type)
{
case AssetType::MESH:
meshCollection.emplace(asset.id, SHMeshAsset());
SHMeshLoader::LoadSHMesh(meshCollection[asset.id], asset.path);
break;
case AssetType::TEXTURE:
textureCollection.emplace(asset.id, SHTextureAsset());
SHTextureLoader::LoadSHTexture(asset.path, textureCollection[asset.id]);
break;
default:
void;
}
}
}
@ -344,40 +417,51 @@ namespace SHADE
std::vector<AssetPath> metaFiles;
std::vector<AssetPath> AssetFiles;
//TODO: Write new function for file manager to loop through all files
SHFileSystem::StartupFillDirectories(ASSET_ROOT);
FolderPointer rootFolder = SHFileSystem::GetRoot();
for (auto const dir : std::filesystem::recursive_directory_iterator(ASSET_ROOT))
{
if (dir.path().extension().string() == META_EXTENSION)
{
auto meta{ SHAssetMetaHandler::RetrieveMetaData(dir.path()) };
for (auto const& meta : metaFiles)
{
for (std::vector<AssetPath>::const_iterator it{ AssetFiles.cbegin() };
it != AssetFiles.cend();
++it)
{
// Asset exists for meta file
std::string fileExtCheck{ it->filename().string() };
fileExtCheck += META_EXTENSION;
if (meta.filename().string() == fileExtCheck)
{
RegisterAsset(meta, *it);
AssetFiles.erase(it);
break;
}
assetCollection.push_back(meta);
assetRegistry.emplace(meta.id, meta);
}
}
//TODO: Write new function for file manager to loop through all files
//SHFileSystem::StartupFillDirectories(ASSET_ROOT);
//FolderPointer rootFolder = SHFileSystem::GetRoot();
//for (auto const& meta : metaFiles)
//{
// for (std::vector<AssetPath>::const_iterator it{ AssetFiles.cbegin() };
// it != AssetFiles.cend();
// ++it)
// {
// // Asset exists for meta file
// std::string fileExtCheck{ it->filename().string() };
// fileExtCheck += META_EXTENSION;
// if (meta.filename().string() == fileExtCheck)
// {
// RegisterAsset(meta, *it);
// AssetFiles.erase(it);
// break;
// }
// }
//}
//TODO: Handle if meta does not match all assets (if meta exist and asset doesnt, vice versa)
for (auto const& file : AssetFiles)
{
if (IsRecognised(file.extension().string().c_str()))
{
SHAssetMetaHandler::WriteMetaData(RegisterAssetNew(file));
}
else
{
std::cout << "Unsupported File Format: " << file.filename() << "\n";
}
}
//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

View File

@ -75,6 +75,8 @@ namespace SHADE
static std::vector<SHMeshAsset> GetAllMeshes() noexcept;
static std::vector<SHTextureAsset> GetAllTextures() noexcept;
static SHMeshAsset const* GetMesh(AssetID id) noexcept;
static SHTextureAsset const* GetTexture(AssetID id) noexcept;
private:
/****************************************************************************
* \brief Load resource data into memory

View File

@ -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;
}
@ -99,10 +108,11 @@ namespace SHADE
****************************************************************************/
void SHAssetMetaHandler::WriteMetaData(SHAsset const& meta) noexcept
{
//TODO: Write into binary eventually
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())
{
@ -110,8 +120,20 @@ namespace SHADE
return;
}
metaFile << "Name: " << meta.name << "\n";
metaFile << "ID: " << meta.id << "\n";
metaFile << "Type: " << static_cast<int>(meta.type) << std::endl;
metaFile << "Type: " << static_cast<AssetTypeMeta>(meta.type) << std::endl;
////TODO Add in information that is specific to types like mesh
//switch(meta.type)
//{
//case AssetType::MESH:
// break;
//default:
// break;
//}
metaFile.close();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,11 +6,11 @@
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "Editor/SHEditor.hpp"
#include "Editor/SHImGuiHelpers.hpp"
#include "Editor/SHEditorWidgets.hpp"
#include "SHHierarchyPanel.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Editor/SHEditor.hpp"
#include "Scene/SHSceneManager.h"
#include "Editor/DragDrop/SHDragDrop.hpp"
#include "Tools/SHException.h"
@ -21,6 +21,8 @@
//#==============================================================#
#include <imgui.h>
#include "Serialization/SHSerialization.h"
namespace SHADE
{
@ -62,11 +64,12 @@ namespace SHADE
if(ImGui::IsWindowHovered() && !SHDragDrop::hasDragDrop && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
SHEditor::selectedEntities.clear();
if(auto editor = SHSystemManager::GetSystem<SHEditor>())
editor->selectedEntities.clear();
}
ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal);
ImGui::End();
}
ImGui::End();
}
void SHHierarchyPanel::Exit()
@ -74,6 +77,11 @@ namespace SHADE
SHEditorWindow::Exit();
}
void SHHierarchyPanel::SetScrollTo(EntityID eid)
{
scrollTo = eid;
}
//#==============================================================#
//|| Private Member Functions ||
//#==============================================================#
@ -81,7 +89,20 @@ namespace SHADE
{
if (ImGui::BeginMenuBar())
{
if (ImGui::SmallButton(ICON_MD_ADD))
ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x - 35.0f);
if(ImGui::SmallButton(ICON_MD_DESELECT))
{
auto editor = SHSystemManager::GetSystem<SHEditor>();
editor->selectedEntities.clear();
}
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Clear Selections");
ImGui::EndTooltip();
}
if (ImGui::SmallButton(ICON_MD_ADD_CIRCLE))
{
SHEntityManager::CreateEntity();
}
@ -102,7 +123,16 @@ namespace SHADE
//Get node data (Children, eid, selected)
auto& children = currentNode->GetChildren();
EntityID eid = currentNode->GetEntityID();
const bool isSelected = (std::ranges::find(SHEditor::selectedEntities, eid) != SHEditor::selectedEntities.end());
if(scrollTo != MAX_EID && eid == scrollTo)
{
ImGui::SetScrollHereY();
scrollTo = MAX_EID;
}
auto editor = SHSystemManager::GetSystem<SHEditor>();
const bool isSelected = (std::ranges::find(editor->selectedEntities, eid) != editor->selectedEntities.end());
const ImGuiTreeNodeFlags nodeFlags = ((isSelected) ? ImGuiTreeNodeFlags_Selected : 0) | ((children.empty()) ? ImGuiTreeNodeFlags_Leaf : ImGuiTreeNodeFlags_OpenOnArrow);
@ -114,7 +144,7 @@ namespace SHADE
auto* entity = SHEntityManager::GetEntityByID(currentNode->GetEntityID());
//Draw Node
bool isNodeOpen = ImGui::TreeNodeEx((void*)eid, nodeFlags, "%u: %s", EntityHandleGenerator::GetIndex(eid), entity->name.c_str());
bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast<void*>(entity), nodeFlags, "%u: %s", EntityHandleGenerator::GetIndex(eid), entity->name.c_str());
const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
//Check For Begin Drag
@ -140,8 +170,12 @@ namespace SHADE
{
if(!isSelected)
{
SHEditor::selectedEntities.clear();
SHEditor::selectedEntities.push_back(eid);
editor->selectedEntities.clear();
editor->selectedEntities.push_back(eid);
}
if(ImGui::Selectable("Copy"))
{
SHLOG_INFO(SHSerialization::SerializeEntitiesToString(editor->selectedEntities))
}
if(ImGui::Selectable(std::format("{} Delete", ICON_MD_DELETE).data()))
{
@ -163,19 +197,19 @@ namespace SHADE
if (!isSelected)
{
if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
SHEditor::selectedEntities.clear();
SHEditor::selectedEntities.push_back(eid);
editor->selectedEntities.clear();
editor->selectedEntities.push_back(eid);
}//if not selected
else
{
if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
{
auto it = std::ranges::remove(SHEditor::selectedEntities, eid).begin();
auto it = std::ranges::remove(editor->selectedEntities, eid).begin();
}//if mod ctrl is not pressed
else
{
SHEditor::selectedEntities.clear();
SHEditor::selectedEntities.push_back(eid);
editor->selectedEntities.clear();
editor->selectedEntities.push_back(eid);
}
}//if selected
}//if left mouse button released

View File

@ -23,11 +23,13 @@ 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;
std::string filter;
bool isAnyNodeSelected = false;
EntityID scrollTo = MAX_EID;
};//class SHHierarchyPanel
}//namespace SHADE

View File

@ -12,12 +12,14 @@
#include "Editor/IconsMaterialDesign.h"
#include "ECS_Base/Components/SHComponent.h"
#include "Editor/SHEditorWidgets.hpp"
#include "Physics/Components/SHColliderComponent.h"
#include "Reflection/SHReflectionMetadata.h"
namespace SHADE
{
template<typename T, std::enable_if_t<std::is_base_of<SHComponent, T>::value, bool> = true>
static void DrawContextMenu(T* component)
{
if(!component)
if (!component)
return;
rttr::string_view componentName = rttr::type::get<T>().get_name();
@ -44,8 +46,8 @@ namespace SHADE
{
if (!component)
return;
auto componentType = rttr::type::get(*component);
CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; });
const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; });
ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data()))
{
@ -55,14 +57,208 @@ namespace SHADE
{
auto const& type = property.get_type();
if (type == rttr::type::get<SHVec4>())
if (type.is_enumeration())
{
DragVec4(property.get_name().data(), { "X", "Y", "Z", "W" }, [component, property]() {return property.get_value(component).template convert<SHVec4>(); }, [component, property](SHVec4 vec) {return property.set_value(component, vec); });
auto enumAlign = type.get_enumeration();
auto names = enumAlign.get_names();
std::vector<const char*> list;
for (auto const& name : names)
list.push_back(name.data());
SHEditorWidgets::ComboBox(property.get_name().data(), list, [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& idx)
{
auto enumAlign = property.get_enumeration();
auto values = enumAlign.get_values();
auto it = std::next(values.begin(), idx);
property.set_value(component, *it);
});
}
else if (type.is_arithmetic())
{
if (type == rttr::type::get<bool>())
{
SHEditorWidgets::CheckBox(property.get_name().data(), [component, property] {return property.get_value(component).to_bool(); }, [component, property](bool const& result) {property.set_value(component, result); });
}
//else if (type == rttr::type::get<char>())
//{
//
//}
else if (type == rttr::type::get<int8_t>() || type == rttr::type::get<int16_t>() || type == rttr::type::get<int32_t>() || type == rttr::type::get<int64_t>())
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
if (metaMin && metaMax)
{
SHEditorWidgets::SliderInt(property.get_name().data(), metaMin.template get_value<int>(), metaMin.template get_value<int>(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); });
}
else
{
SHEditorWidgets::DragInt(property.get_name().data(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); });
}
}
else if (type == rttr::type::get<uint8_t>())
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<uint8_t>(property.get_name().data(), ImGuiDataType_U8, metaMin.template get_value<uint8_t>(), metaMax.template get_value<uint8_t>(), [component, property] {return property.get_value(component).to_uint8(); }, [component, property](uint8_t const& result) {property.set_value(component, result); }, "%zu");
}
else
{
SHEditorWidgets::DragScalar<uint8_t>(property.get_name().data(), ImGuiDataType_U8, [component, property] {return property.get_value(component).to_uint8(); }, [component, property](uint8_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu");
}
}
else if (type == rttr::type::get<uint16_t>())
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value<uint16_t>(), metaMin.template get_value<uint16_t>(), [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, "%zu");
}
else
{
SHEditorWidgets::DragScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu");
}
}
else if (type == rttr::type::get<uint32_t>())
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value<uint32_t>(), metaMin.template get_value<uint32_t>(), [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, "%zu");
}
else
{
SHEditorWidgets::DragScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu");
}
}
else if (type == rttr::type::get<uint64_t>())
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value<uint64_t>(), metaMin.template get_value<uint64_t>(), [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, "%zu");
}
else
{
SHEditorWidgets::DragScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu");
}
}
else if (type == rttr::type::get<float>())
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderFloat(property.get_name().data(), metaMin.template get_value<float>(), metaMin.template get_value<float>(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); });
}
else
{
SHEditorWidgets::DragFloat(property.get_name().data(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); });
}
}
else if (type == rttr::type::get<double>())
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<double>(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value<double>(), metaMin.template get_value<double>(), [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); });
}
else
{
SHEditorWidgets::DragScalar<double>(property.get_name().data(), ImGuiDataType_Double, [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); }, 0.1f);
}
}
}
else if (type == rttr::type::get<SHVec4>())
{
SHEditorWidgets::DragVec4(property.get_name().data(), { "X", "Y", "Z", "W" }, [component, property]() {return property.get_value(component).template convert<SHVec4>(); }, [component, property](SHVec4 vec) {return property.set_value(component, vec); });
}
else if (type == rttr::type::get<SHVec3>())
{
DragVec3(property.get_name().data(), { "X", "Y", "Z" }, [component, property]() {return property.get_value(component).template convert<SHVec3>(); }, [component, property](SHVec3 vec) {return property.set_value(component, vec); });
SHEditorWidgets::DragVec3(property.get_name().data(), { "X", "Y", "Z" }, [component, property]() {return property.get_value(component).template convert<SHVec3>(); }, [component, property](SHVec3 vec) {return property.set_value(component, vec); });
}
else if (type == rttr::type::get<SHVec2>())
{
SHEditorWidgets::DragVec2(property.get_name().data(), { "X", "Y" }, [component, property]() {return property.get_value(component).template convert<SHVec2>(); }, [component, property](SHVec2 vec) {return property.set_value(component, vec); });
}
}
}
else DrawContextMenu(component);
}
template<>
static void DrawComponent(SHColliderComponent* component)
{
if (!component)
return;
const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; });
ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data()))
{
DrawContextMenu(component);
auto& colliders = component->GetColliders();
int const size = static_cast<int>(colliders.size());
ImGui::BeginChild("Colliders", {0.0f, colliders.empty() ? 1.0f : 250.0f}, true);
std::optional<int> 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 });
auto box = reinterpret_cast<SHBoundingBox*>(collider.GetShape());
SHEditorWidgets::DragVec3("Half Extents", { "X", "Y", "Z" }, [box] {return box->GetHalfExtents(); }, [box](SHVec3 const& vec) {box->SetHalfExtents(vec);});
}
else if (collider.GetType() == SHCollider::Type::SPHERE)
{
SHEditorWidgets::BeginPanel(std::format("{} Sphere Collider #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
auto sphere = reinterpret_cast<SHBoundingSphere*>(collider.GetShape());
SHEditorWidgets::DragFloat("Radius", [sphere] {return sphere->GetRadius(); }, [sphere](float const& value) {sphere->SetRadius(value);});
}
else if (collider.GetType() == SHCollider::Type::CAPSULE)
{
}
{
SHEditorWidgets::BeginPanel("Offset", { ImGui::GetContentRegionAvail().x, 30.0f });
SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider.GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider.SetPositionOffset(vec); });
SHEditorWidgets::EndPanel();
}
if(ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data()))
{
colliderToDelete = i;
}
SHEditorWidgets::EndPanel();
ImGui::PopID();
}
if(colliderToDelete.has_value())
{
component->RemoveCollider(colliderToDelete.value());
}
ImGui::EndChild();
if (ImGui::BeginMenu("Add Collider"))
{
if(ImGui::Selectable("Box Collider"))
{
component->AddBoundingBox();
}
if(ImGui::Selectable("Sphere Collider"))
{
component->AddBoundingSphere();
}
ImGui::EndMenu();
}
}
else DrawContextMenu(component);

View File

@ -1,5 +1,6 @@
#include "SHpch.h"
#include "Editor/SHEditor.hpp"
#include "SHEditorInspector.h"
#include "ECS_Base/SHECSMacros.h"
@ -7,21 +8,31 @@
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Editor/SHEditor.hpp"
#include "Editor/SHImGuiHelpers.hpp"
#include "Editor/SHEditorWidgets.hpp"
#include "SHEditorComponentView.hpp"
#include "ECS_Base/UnitTesting/SHTestComponents.h"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Scripting/SHScriptEngine.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "AudioSystem/SHAudioSystem.h"
#include "Physics/Components/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h"
namespace SHADE
{
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
void DrawAddComponentButton(EntityID const& eid)
bool DrawAddComponentButton(EntityID const& eid)
{
if(!SHComponentManager::HasComponent<ComponentType>(eid) && ImGui::Selectable(std::format("Add {}", rttr::type::get<ComponentType>().get_name().data()).data()))
bool selected = false;
if(!SHComponentManager::HasComponent<ComponentType>(eid))
{
if(selected = ImGui::Selectable(std::format("Add {}", rttr::type::get<ComponentType>().get_name().data()).data()); selected)
SHComponentManager::AddComponent<ComponentType>(eid);
}
return selected;
}
SHEditorInspector::SHEditorInspector()
@ -39,13 +50,14 @@ namespace SHADE
SHEditorWindow::Update();
if (Begin())
{
if (!SHEditor::selectedEntities.empty())
auto editor = SHSystemManager::GetSystem<SHEditor>();
if (editor && !editor->selectedEntities.empty())
{
EntityID const& eid = SHEditor::selectedEntities[0];
EntityID const& eid = editor->selectedEntities[0];
SHEntity* entity = SHEntityManager::GetEntityByID(eid);
ImGui::TextColored(ImGuiColors::green, "EID: %zu", eid);
CheckBox("##IsActive", [entity]()->bool {return entity->GetActive(); }, [entity](bool const& active) {entity->SetActive(active); });
SHEditorWidgets::CheckBox("##IsActive", [entity]()->bool {return entity->GetActive(); }, [entity](bool const& active) {entity->SetActive(active); });
ImGui::SameLine();
ImGui::InputText("##EntityName", &entity->name);
@ -54,17 +66,42 @@ namespace SHADE
{
DrawComponent(transformComponent);
}
if(auto renderableComponent = SHComponentManager::GetComponent_s<SHRenderable>(eid))
{
DrawComponent(renderableComponent);
}
if(auto colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(eid))
{
DrawComponent(colliderComponent);
}
if(auto rigidbodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(eid))
{
DrawComponent(rigidbodyComponent);
}
ImGui::Separator();
// Render Scripts
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->RenderScriptsInInspector(eid);
ImGui::Separator();
if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data()))
{
DrawAddComponentButton<SHTransformComponent>(eid);
DrawAddComponentButton<SHRenderable>(eid);
DrawAddComponentButton<SHColliderComponent>(eid);
if(DrawAddComponentButton<SHRigidBodyComponent>(eid))
{
if(SHComponentManager::GetComponent_s<SHTransformComponent>(eid) == nullptr)
{
SHComponentManager::AddComponent<SHTransformComponent>(eid);
}
}
ImGui::EndMenu();
}
}
}
ImGui::End();
}
}
void SHEditorInspector::Exit()
{

View File

@ -3,9 +3,12 @@
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "Editor/SHEditor.hpp"
#include "SHEditorMenuBar.h"
#include "Editor/IconsMaterialDesign.h"
#include "Editor/Command/SHCommandManager.h"
#include "Scripting/SHScriptEngine.h"
#include "ECS_Base/Managers/SHSystemManager.h"
//#==============================================================#
//|| Library Includes ||
@ -14,8 +17,7 @@
#include <imgui_internal.h>
#include <rttr/type>
#include "Editor/SHEditor.hpp"
#include "Serialization/SHSerialization.h"
namespace SHADE
{
@ -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,15 +101,56 @@ namespace SHADE
ImGui::EndDisabled();
ImGui::EndMenu();
}
if(ImGui::BeginMenu("Theme"))
if (ImGui::BeginMenu("Scripts"))
{
auto styles = rttr::type::get<SHEditor::Style>().get_enumeration();
if (ImGui::Selectable("Generate Visual Studio Project"))
{
auto* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->GenerateScriptsCsProjFile();
}
if (ImGui::Selectable("Build Scripts - Debug"))
{
auto* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->BuildScriptAssembly(true, true);
}
if (ImGui::Selectable("Build Scripts - Release"))
{
auto* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->BuildScriptAssembly(false, true);
}
ImGui::EndMenu();
}
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<SHEditor::Style>().get_enumeration();
auto values = styles.get_values();
for (auto style : values)
{
if(ImGui::Selectable(style.to_string().c_str()))
if (ImGui::Selectable(style.to_string().c_str()))
{
SHEditor::SetStyle(style.convert<SHEditor::Style>());
if (auto editor = SHSystemManager::GetSystem<SHEditor>())
editor->SetStyle(style.convert<SHEditor::Style>());
}
}
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();
@ -103,15 +158,41 @@ namespace SHADE
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<SHEditor>();
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
@ -122,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);
}

View File

@ -18,5 +18,6 @@ namespace SHADE
void DrawSecondaryBar() const noexcept;
void DrawStatusBar() const noexcept;
float menuBarHeight = 20.0f;
std::vector<std::filesystem::path> layoutPaths;
};//class SHEditorMenuBar
}//namespace SHADE

View File

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

View File

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

View File

@ -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,30 @@ namespace SHADE
//#==============================================================#
bool SHEditorWindow::Begin()
{
return ImGui::Begin(windowName.data(), &isOpen, windowFlags);
bool result = ImGui::Begin(windowName.data(), &isOpen, windowFlags);
auto wndSize = ImGui::GetWindowSize();
if(windowSize.x != wndSize.x || windowSize.y != wndSize.y)
{
windowSize = {wndSize.x, wndSize.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

View File

@ -5,6 +5,8 @@
//#==============================================================#
#include <string>
#include "Math/Vector/SHVec2.h"
//#==============================================================#
//|| Forward Declarations ||
//#==============================================================#
@ -21,11 +23,18 @@ namespace SHADE
virtual void Init();
virtual void Update();
virtual void Exit();
bool isOpen = false;
bool isOpen;
bool isWindowHovered;
std::string_view windowName;
protected:
virtual bool Begin();
virtual void OnResize();
virtual void OnPosChange();
ImGuiWindowFlags windowFlags = 0;
ImGuiIO& io;
SHVec2 windowSize;
SHVec2 windowPos;
SHVec2 viewportMousePos;
};//class SHEditorWindow
}//namespace SHADE

View File

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

View File

@ -0,0 +1,84 @@
#include "SHpch.h"
#include "SHEditorViewport.h"
#include "ECS_Base/Managers/SHSystemManager.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"
namespace SHADE
{
SHEditorViewport::SHEditorViewport()
:SHEditorWindow("Viewport", ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoScrollbar)
{
}
void SHEditorViewport::Init()
{
SHEditorWindow::Init();
}
void SHEditorViewport::Update()
{
SHEditorWindow::Update();
if(Begin())
{
DrawMenuBar();
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
auto const& descriptorSet = gfxSystem->GetPostOffscreenRenderSystem()->GetDescriptorSetGroup()->GetVkHandle()[0];
auto mousePos = ImGui::GetMousePos();
auto cursorPos = ImGui::GetCursorScreenPos();
viewportMousePos = {mousePos.x - cursorPos.x, mousePos.y - cursorPos.y};
gfxSystem->GetMousePickSystem ()->SetViewportMousePos (viewportMousePos);
//if (ImGui::IsMouseReleased(ImGuiMouseButton_Left))
//{
// auto eid = gfxSystem->GetMousePickSystem ()->GetPickedEntity();
// if(eid != MAX_EID)
// {
// auto editor = SHSystemManager::GetSystem<SHEditor>();
// editor->selectedEntities.clear();
// editor->selectedEntities.push_back(eid);
// if (const auto hierarchyPanel = SHEditorWindowManager::GetEditorWindow<SHHierarchyPanel>())
// {
// hierarchyPanel->SetScrollTo(eid);
// }
// }
//}
ImGui::Image((ImTextureID)descriptorSet, ImGui::GetWindowSize());
}
ImGui::End();
}
void SHEditorViewport::Exit()
{
SHEditorWindow::Exit();
}
void SHEditorViewport::OnResize()
{
SHEditorWindow::OnResize();
//Get graphics system to resize swapchain image
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
//auto pos = ImGui::GetCursorPos();
//windowCursorPos = {}
gfxSystem->PrepareResize(static_cast<uint32_t>(windowSize.x), static_cast<uint32_t>(windowSize.y));
}
void SHEditorViewport::OnPosChange()
{
SHEditorWindow::OnPosChange();
}
void SHEditorViewport::DrawMenuBar() const noexcept
{
if(ImGui::BeginMenuBar())
{
ImGui::EndMenuBar();
}
}
}//namespace SHADE

View File

@ -0,0 +1,29 @@
#pragma once
//#==============================================================#
//|| Library Includes ||
//#==============================================================#
#include <imgui.h>
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "imgui_internal.h"
#include "ECS_Base/SHECSMacros.h"
#include "Editor/EditorWindow/SHEditorWindow.h"
namespace SHADE
{
class SHEditorViewport final : public SHEditorWindow
{
public:
SHEditorViewport();
void Init() override;
void Update() override;
void Exit() override;
protected:
void OnResize() override;
void OnPosChange() override;
private:
void DrawMenuBar() const noexcept;
};//class SHEditorViewport
}//namespace SHADE

View File

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

View File

@ -23,6 +23,8 @@
#include "SHEditor.hpp"
#include "SHEditorWidgets.hpp"
#include "Math/Transform/SHTransformSystem.h"
//#==============================================================#
//|| Editor Window Includes ||
//#==============================================================#
@ -41,6 +43,8 @@
#include <backends/imgui_impl_sdl.h>
#include <backends/imgui_impl_vulkan.h>
#include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h"
RTTR_REGISTRATION
{
using namespace SHADE;
@ -58,19 +62,20 @@ RTTR_REGISTRATION
namespace SHADE
{
//#==============================================================#
//|| Initialise static members ||
//|| Init static members ||
//#==============================================================#
Handle<SHVkCommandPool> SHEditor::imguiCommandPool;
Handle<SHVkCommandBuffer> SHEditor::imguiCommandBuffer;
SHEditor::EditorWindowMap SHEditor::editorWindows{};
SHEditor::EditorWindowID SHEditor::windowCount{};
std::vector<EntityID> SHEditor::selectedEntities;
//Handle<SHVkCommandPool> SHEditor::imguiCommandPool;
//Handle<SHVkCommandBuffer> SHEditor::imguiCommandBuffer;
SHEditorWindowManager::EditorWindowMap SHEditorWindowManager::editorWindows{};
SHEditorWindowManager::EditorWindowID SHEditorWindowManager::windowCount{};
//std::vector<EntityID> SHEditor::selectedEntities;
//#==============================================================#
//|| Public Member Functions ||
//#==============================================================#
void SHEditor::Initialise(SDL_Window* const sdlWindow)
void SHEditor::Init()
{
IMGUI_CHECKVERSION();
if(auto context = ImGui::CreateContext())
{
@ -80,32 +85,48 @@ namespace SHADE
}
}
ImGuiIO& io = ImGui::GetIO(); (void)io;
//Add editor windows
SHEditorWindowManager::CreateEditorWindow<SHEditorMenuBar>();
SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>();
SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>();
SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>();
SHEditorWindowManager::CreateEditorWindow<SHEditorProfiler>();
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";
InitLayout();
InitFonts();
InitBackend(sdlWindow);
auto id = SHFamilyID<SHSystem>::GetID<SHGraphicsSystem>();
auto id2 = SHFamilyID<SHSystem>::GetID<SHTransformSystem>();
auto id3 = SHFamilyID<SHSystem>::GetID<SHGraphicsSystem>();
InitBackend();
SetStyle(Style::SHADE);
//Add editor windows
CreateEditorWindow<SHEditorMenuBar>();
CreateEditorWindow<SHHierarchyPanel>();
CreateEditorWindow<SHEditorInspector>();
for (const auto& window : SHEditorWindowManager::editorWindows | std::views::values)
{
window->Init();
}
SHLOG_INFO("Successfully initialised SHADE Engine Editor")
}
void SHEditor::Update(float const dt)
void SHEditor::Update(double const dt)
{
(void)dt;
NewFrame();
for (const auto& window : editorWindows | std::views::values)
for (const auto& window : SHEditorWindowManager::editorWindows | std::views::values)
{
if(window->isOpen)
window->Update();
}
@ -118,35 +139,45 @@ 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.PixelSnapH = true;
ImFont* UIFont = io.Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/MaterialIcons-Regular.ttf", 20.f, &icons_config, icon_ranges); //TODO: Change to config based assets path
constexpr 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();
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();
@ -252,7 +283,7 @@ namespace SHADE
//#==============================================================#
//|| Private Member Functions ||
//#==============================================================#
void SHEditor::InitBackend(SDL_Window* sdlWindow)
void SHEditor::InitBackend()
{
if(ImGui_ImplSDL2_InitForVulkan(sdlWindow) == false)
{
@ -273,10 +304,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)
@ -292,6 +324,8 @@ namespace SHADE
imguiCommandBuffer->EndRecording();
gfxSystem->GetQueue()->SubmitCommandBuffer({ imguiCommandBuffer }, {}, {}, vk::PipelineStageFlagBits::eNone, {});
gfxSystem->GetDevice()->WaitIdle();
ImGui_ImplVulkan_DestroyFontUploadObjects();
renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle<SHVkCommandBuffer>& cmd) {
@ -299,6 +333,29 @@ namespace SHADE
});
}
void SHEditor::PollPicking()
{
if (auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>())
{
auto viewportWindow = SHEditorWindowManager::GetEditorWindow<SHEditorViewport>();
if (viewportWindow->isWindowHovered && 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<SHHierarchyPanel>())
{
hierarchyPanel->SetScrollTo(pickedEID);
}
selectedEntities.clear();
}
selectedEntities.push_back(pickedEID);
}
}
}
void SHEditor::NewFrame()
{
SDL_Event event;
@ -312,4 +369,9 @@ namespace SHADE
}
void SHEditor::EditorRoutine::Execute(double dt) noexcept
{
reinterpret_cast<SHEditor*>(system)->Update(dt);
}
}//namespace SHADE

View File

@ -11,6 +11,8 @@
//#==============================================================#
#include "SH_API.h"
#include "ECS_Base/SHECSMacros.h"
#include "ECS_Base/System/SHSystem.h"
#include "ECS_Base/System/SHSystemRoutine.h"
#include "Resource/Handle.h"
#include "EditorWindow/SHEditorWindow.h"
#include "Tools/SHLogger.h"
@ -28,11 +30,7 @@ namespace SHADE
class SHVkCommandBuffer;
class SHVkCommandPool;
/**
* @brief SHEditor static class contains editor variables and implementation of editor functions.
*
*/
class SH_API SHEditor
class SHEditorWindowManager
{
public:
//#==============================================================#
@ -41,46 +39,6 @@ namespace SHADE
using EditorWindowID = uint8_t;
using EditorWindowPtr = std::unique_ptr<SHEditorWindow>;
using EditorWindowMap = std::unordered_map<EditorWindowID, EditorWindowPtr>;
/**
* @brief Style options
*
*/
enum class Style : uint8_t
{
SHADE,
DARK,
LIGHT,
CLASSIC
};
/**
* @brief Initialise the editor
*
* @param sdlWindow pointer to SDL_Window object created in application
*/
static void Initialise(SDL_Window* sdlWindow);
/**
* @brief Update the editor and add to ImGui DrawList
*
* @param dt Delta-time of the frame
*/
static void Update(float dt);
/**
* @brief Safely shutdown the editor
*
*/
static void Exit();
/**
* @brief Set the Style for the editor
*
* @param style Desired style
*/
static void SetStyle(Style style);
/**
* @brief Get ID for the Editor Window Type
*
@ -100,39 +58,6 @@ namespace SHADE
return id;
}
/**
* @brief Get pointer to the Editor Window
*
* @tparam T Type of editor window to retrieve
* @return T* Pointer to the editor window
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static T* GetEditorWindow()
{
return reinterpret_cast<T*>(editorWindows[GetEditorWindowID<T>()].get());
}
// List of selected entities
static std::vector<EntityID> selectedEntities;
private:
/**
* @brief Initialise Backend for ImGui (SDL and Vulkan backend)
*
* @param sdlWindow Pointer to SDL_Window
*/
static void InitBackend(SDL_Window* sdlWindow);
/**
* @brief Start new frame for editor
*
*/
static void NewFrame();
/**
* @brief Perform ImGui and ImGui Backend Render
*
*/
static void Render();
/**
* @brief Create an Editor Window
*
@ -153,16 +78,127 @@ namespace SHADE
}
}
static void InitFonts() noexcept;
// Handle to command pool used for ImGui Vulkan Backend
static Handle<SHVkCommandPool> imguiCommandPool;
// Handle to command buffer used for ImGui Vulkan Backend
static Handle<SHVkCommandBuffer> imguiCommandBuffer;
/**
* @brief Get pointer to the Editor Window
*
* @tparam T Type of editor window to retrieve
* @return T* Pointer to the editor window
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static T* GetEditorWindow()
{
return reinterpret_cast<T*>(editorWindows[GetEditorWindowID<T>()].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;
};
/**
* @brief SHEditor static class contains editor variables and implementation of editor functions.
*
*/
class SH_API SHEditor final : public SHSystem
{
public:
class SH_API EditorRoutine final : public SHSystemRoutine
{
public:
EditorRoutine():SHSystemRoutine("Editor routine", true) {};
void Execute(double dt) noexcept override final;
};
enum class State : uint8_t
{
PLAY,
PAUSE,
STOP
};
/**
* @brief Style options
*
*/
enum class Style : uint8_t
{
SHADE,
DARK,
LIGHT,
CLASSIC
};
/**
* @brief Initialise the editor
*
* @param sdlWindow pointer to SDL_Window object created in application
*/
void Init();
/**
* @brief Update the editor and add to ImGui DrawList
*
* @param dt Delta-time of the frame
*/
void Update(double dt);
/**
* @brief Safely shutdown the editor
*
*/
void Exit();
/**
* @brief Set the Style for the editor
*
* @param style Desired style
*/
void SetStyle(Style style);
/**
* @brief Initialise Backend for ImGui (SDL and Vulkan backend)
*
* @param sdlWindow Pointer to SDL_Window
*/
void InitBackend();
void SetSDLWindow(SDL_Window* inSDLWindow){sdlWindow = inSDLWindow;};
void PollPicking();
// List of selected entities
std::vector<EntityID> selectedEntities;
State editorState = State::STOP;
private:
/**
* @brief Start new frame for editor
*
*/
void NewFrame();
/**
* @brief Perform ImGui and ImGui Backend Render
*
*/
void Render();
void InitLayout() noexcept;
void InitFonts() noexcept;
// Handle to command pool used for ImGui Vulkan Backend
Handle<SHVkCommandPool> imguiCommandPool;
// Handle to command buffer used for ImGui Vulkan Backend
Handle<SHVkCommandBuffer> imguiCommandBuffer;
SDL_Window* sdlWindow {nullptr};
ImGuiIO* io{nullptr};
};//class SHEditor
}//namespace SHADE

View File

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

View File

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

View File

@ -0,0 +1,56 @@
/************************************************************************************//*!
\file SHEditorUI.hpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Sep 27, 2022
\brief Contains the implementation of editor inspector template functions.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
// Primary Header
#include "SHEditorUI.h"
// External Dependencies
#include <imgui.h>
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* ImGui Wrapper Functions - Widgets */
/*---------------------------------------------------------------------------------*/
template<typename Enum>
inline bool SHEditorUI::InputEnumCombo(const std::string& label, Enum& v, int maxVal, std::function<const char* (Enum)> toStrFn, bool* isHovered)
{
std::vector<Enum> values;
for (int i = 0; i <= maxVal; ++i)
{
values.emplace_back(static_cast<Enum>(i));
}
bool b = false;
ImGui::Text(label.c_str());
if (isHovered)
*isHovered = ImGui::IsItemHovered();
ImGui::SameLine();
if (ImGui::BeginCombo(label.c_str(), toStrFn(v), ImGuiComboFlags_None))
{
for (int i = 0; i <= maxVal; ++i)
{
const auto VALUE = values[i];
const bool IS_SELECTED = v == VALUE;
if (ImGui::Selectable(toStrFn(VALUE), IS_SELECTED))
{
v = VALUE;
b = true;
}
if (IS_SELECTED)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
return b;
}
}

View File

@ -12,6 +12,7 @@
#include "Math/SHMath.h"
#include "Command/SHCommandManager.h"
#include "SHImGuiHelpers.hpp"
#include "SH_API.h"
//#==============================================================#
//|| Library Includes ||
@ -23,9 +24,129 @@
namespace SHADE
{
class SH_API SHEditorWidgets
{
public:
//#==============================================================#
//|| Constructor ||
//#==============================================================#
SHEditorWidgets() = delete;
//#==============================================================#
//|| Custom Widgets ||
//#==============================================================#
inline static ImVector<ImRect> panelStack{};
static void BeginPanel(std::string_view const& name, const ImVec2& size)
{
ImGui::BeginGroup();
auto cursorPos = ImGui::GetCursorScreenPos();
auto itemSpacing = ImGui::GetStyle().ItemSpacing;
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
auto frameHeight = ImGui::GetFrameHeight();
ImGui::BeginGroup();
ImVec2 effectiveSize = size;
if (size.x < 0.0f)
effectiveSize.x = ImGui::GetContentRegionAvail().x;
else
effectiveSize.x = size.x;
ImGui::Dummy(ImVec2(effectiveSize.x, 0.0f));
ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
ImGui::SameLine(0.0f, 0.0f);
ImGui::BeginGroup();
ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
ImGui::SameLine(0.0f, 0.0f);
ImGui::TextUnformatted(name.data());
auto labelMin = ImGui::GetItemRectMin();
auto labelMax = ImGui::GetItemRectMax();
ImGui::SameLine(0.0f, 0.0f);
ImGui::Dummy(ImVec2(0.0, frameHeight + itemSpacing.y));
ImGui::BeginGroup();
ImGui::PopStyleVar(2);
ImGui::GetCurrentWindow()->ContentRegionRect.Max.x -= frameHeight * 0.5f;
ImGui::GetCurrentWindow()->WorkRect.Max.x -= frameHeight * 0.5f;
ImGui::GetCurrentWindow()->InnerRect.Max.x -= frameHeight * 0.5f;
ImGui::GetCurrentWindow()->Size.x -= frameHeight;
auto itemWidth = ImGui::CalcItemWidth();
ImGui::PushItemWidth(ImMax(0.0f, itemWidth - frameHeight));
panelStack.push_back(ImRect(labelMin, labelMax));
}
static void EndPanel()
{
ImGui::PopItemWidth();
auto itemSpacing = ImGui::GetStyle().ItemSpacing;
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
auto frameHeight = ImGui::GetFrameHeight();
ImGui::EndGroup();
ImGui::EndGroup();
ImGui::SameLine(0.0f, 0.0f);
ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
ImGui::Dummy(ImVec2(0.0, frameHeight - frameHeight * 0.5f - itemSpacing.y));
ImGui::EndGroup();
auto itemMin = ImGui::GetItemRectMin();
auto itemMax = ImGui::GetItemRectMax();
auto labelRect = panelStack.back();
panelStack.pop_back();
ImVec2 halfFrame = ImVec2(frameHeight * 0.25f, frameHeight) * 0.5f;
ImRect frameRect = ImRect(itemMin + halfFrame, itemMax - ImVec2(halfFrame.x, 0.0f));
labelRect.Min.x -= itemSpacing.x;
labelRect.Max.x += itemSpacing.x;
for (int i = 0; i < 4; ++i)
{
switch (i)
{
// left half-plane
case 0: ImGui::PushClipRect(ImVec2(-FLT_MAX, -FLT_MAX), ImVec2(labelRect.Min.x, FLT_MAX), true); break;
// right half-plane
case 1: ImGui::PushClipRect(ImVec2(labelRect.Max.x, -FLT_MAX), ImVec2(FLT_MAX, FLT_MAX), true); break;
// top
case 2: ImGui::PushClipRect(ImVec2(labelRect.Min.x, -FLT_MAX), ImVec2(labelRect.Max.x, labelRect.Min.y), true); break;
// bottom
case 3: ImGui::PushClipRect(ImVec2(labelRect.Min.x, labelRect.Max.y), ImVec2(labelRect.Max.x, FLT_MAX), true); break;
}
ImGui::GetWindowDrawList()->AddRect(
frameRect.Min, frameRect.Max,
ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Button)),
halfFrame.x);
ImGui::PopClipRect();
}
ImGui::PopStyleVar(2);
ImGui::GetCurrentWindow()->ContentRegionRect.Max.x += frameHeight * 0.5f;
ImGui::GetCurrentWindow()->WorkRect.Max.x += frameHeight * 0.5f;
ImGui::GetCurrentWindow()->InnerRect.Max.x += frameHeight * 0.5f;
ImGui::GetCurrentWindow()->Size.x += frameHeight;
ImGui::Dummy(ImVec2(0.0f, 0.0f));
ImGui::EndGroup();
}
static bool Splitter(bool verticalSplit, float thickness, float* size1, float* size2, float minSize1, float minSize2, float splitterAxisSize = -1.0f)
{
ImGuiWindow* window = ImGui::GetCurrentWindow();
@ -39,7 +160,7 @@ namespace SHADE
template <typename T, std::size_t N>
static bool DragN(const std::string& fieldLabel, std::vector<std::string>const& componentLabels,
std::vector<T*> values, float speed = 0.1f, const char* displayFormat = "", T valueMin = T(), T valueMax = T(),
ImGuiSliderFlags flags = 0)
ImGuiSliderFlags flags = 0, bool* isHovered = nullptr)
{
const ImGuiWindow* const window = ImGui::GetCurrentWindow();
if (window->SkipItems)
@ -53,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)
{
@ -86,7 +209,7 @@ namespace SHADE
{
SHVec2 values = get();
bool changed = false;
if (DragN<float, 2>(fieldLabel, componentLabels, {&values.x, &values.y}, speed, displayFormat, valueMin, valueMax, flags))
if (DragN<float, 2>(fieldLabel, componentLabels, { &values.x, &values.y }, speed, displayFormat, valueMin, valueMax, flags))
{
changed = true;
}
@ -95,9 +218,9 @@ namespace SHADE
{
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false);
else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left))
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), true);
else if(ImGui::IsItemDeactivatedAfterEdit())
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false);
}
@ -110,7 +233,7 @@ namespace SHADE
{
SHVec3 values = get();
bool changed = false;
if (DragN<float, 3>(fieldLabel, componentLabels, {&values.x, &values.y, &values.z}, speed, displayFormat, valueMin, valueMax, flags))
if (DragN<float, 3>(fieldLabel, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags))
{
changed = true;
}
@ -119,9 +242,9 @@ namespace SHADE
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false);
else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left))
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), true);
else if(ImGui::IsItemDeactivatedAfterEdit())
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false);
}
@ -134,7 +257,7 @@ namespace SHADE
{
SHVec4 values = get();
bool changed = false;
if (DragN<float, 4>(fieldLabel, componentLabels, {&values.x, &values.y, &values.z, &values.w}, speed, displayFormat, valueMin, valueMax, flags))
if (DragN<float, 4>(fieldLabel, componentLabels, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags))
{
changed = true;
}
@ -143,9 +266,9 @@ namespace SHADE
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), false);
else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left))
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), true);
else if(ImGui::IsItemDeactivatedAfterEdit())
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), false);
}
@ -182,6 +305,148 @@ namespace SHADE
return true;
}
static bool InputText(const std::string& label, const std::function<std::string(void)> get,
const std::function<void(std::string)> set, ImGuiInputTextFlags flag = 0,
ImGuiInputTextCallback callback = (ImGuiInputTextCallback)0, void* userData = (void*)0)
{
std::string text = get();
if (ImGui::InputText(label.c_str(), &text, flag, callback, userData))
{
if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<std::string>>(get(), text, set)), false);
return true;
}
return false;
}
template <typename T>
static bool DragScalar(const std::string& fieldLabel, ImGuiDataType data_type, std::function<T(void)> get, std::function<void(T const&)> set,
float speed = 1.0f, T p_min = T(), T p_max = T(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{
T value = get();
std::cout << value << " \n";
//bool hasChange = ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags);
if (ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags))
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
return true;
}
return false;
}
static bool DragFloat(const std::string& fieldLabel, std::function<float(void)> get, std::function<void(float const&)> set,
float speed = 0.1f, float p_min = float(), float p_max = float(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{
float value = get();
//bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags);
if (ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags))
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
return true;
}
return false;
}
static bool DragInt(const std::string& fieldLabel, std::function<int(void)> get, std::function<void(int const&)> set,
float speed = 1.0f, int p_min = int(), int p_max = int(), const char* displayFormat = "%d", ImGuiSliderFlags flags = 0)
{
int value = get();
//bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags);
if (ImGui::DragInt(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags))
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
return true;
}
return false;
}
template <typename T>
static bool SliderScalar(const std::string& fieldLabel, ImGuiDataType data_type, T min, T max, std::function<T(void)> get, std::function<void(T const&)> set,
const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{
T value = get();
if (ImGui::SliderScalar(fieldLabel.c_str(), data_type, &value, &min, &max, displayFormat, flags))
{
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), true);
return true;
}
return false;
}
static bool SliderFloat(const std::string& fieldLabel, float min, float max, std::function<float(void)> get, std::function<void(float const&)> set,
const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{
float value = get();
if (ImGui::SliderFloat(fieldLabel.c_str(), &value, min, max, displayFormat, flags))
{
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), true);
return true;
}
return false;
}
static bool SliderInt(const std::string& fieldLabel, int min, int max, std::function<int(void)> get, std::function<void(int const&)> set,
const char* displayFormat = "%d", ImGuiSliderFlags flags = 0)
{
int value = get();
if (ImGui::SliderInt(fieldLabel.c_str(), &value, min, max, displayFormat, flags))
{
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), true);
return true;
}
return false;
}
static bool ComboBox(const std::string& fieldLabel, std::vector<const char*> list, std::function<int(void)> get, std::function<void(int const&)> set)
{
bool edited = false;
int selected = get();
ImGui::PushID(fieldLabel.c_str());
ImGui::Text(fieldLabel.c_str()); ImGui::SameLine();
if (edited = ImGui::Combo("##Combo", &selected, list.data(), static_cast<int>(list.size())))
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), selected, set)), false);
}
ImGui::PopID();
return edited;
}
};
}//namespace SHADE

View File

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

View File

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

View File

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

View File

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

View File

@ -105,6 +105,17 @@ namespace SHADE
vk::Buffer GetVkBuffer (void) const noexcept;
vk::BufferUsageFlags GetUsageBits(void) const noexcept;
template <typename T>
T GetDataFromMappedPointer(uint32_t index) const noexcept
{
if (mappedPtr && index < sizeStored / sizeof (T))
{
return (static_cast<T*>(mappedPtr))[index];
}
else
return {};
};
};
}

View File

@ -24,7 +24,7 @@ namespace SHADE
/***************************************************************************/
SHVkCommandBuffer::~SHVkCommandBuffer(void) noexcept
{
if (vkCommandBuffer)
if (vkCommandBuffer && parentPool)
parentPool->GetLogicalDevice()->GetVkLogicalDevice().freeCommandBuffers(parentPool->GetVkCommandPool(), commandBufferCount, &vkCommandBuffer);
}
@ -461,6 +461,11 @@ namespace SHADE
);
}
void SHVkCommandBuffer::CopyImageToBuffer(const vk::Image& src, const vk::Buffer& dst, const std::vector<vk::BufferImageCopy>& copyInfo)
{
vkCommandBuffer.copyImageToBuffer (src, vk::ImageLayout::eTransferSrcOptimal, dst, copyInfo);
}
void SHVkCommandBuffer::PipelineBarrier(
vk::PipelineStageFlags srcStage,
vk::PipelineStageFlags dstStage,

View File

@ -121,6 +121,7 @@ namespace SHADE
// Buffer Copy
void CopyBufferToImage (const vk::Buffer& src, const vk::Image& dst, const std::vector<vk::BufferImageCopy>& copyInfo);
void CopyImageToBuffer (const vk::Image& src, const vk::Buffer& dst, const std::vector<vk::BufferImageCopy>& copyInfo);
// memory barriers
void PipelineBarrier (

View File

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

View File

@ -99,7 +99,7 @@ namespace SHADE
void SHVulkanDebugUtil::ReportVkSuccess(std::string_view message) noexcept
{
SHLOGV_INFO(message);
//SHLOGV_INFO(message);
}
/***************************************************************************/

View File

@ -40,7 +40,9 @@ namespace SHADE
{
{ vk::DescriptorType::eCombinedImageSampler, 100 },
{ vk::DescriptorType::eUniformBuffer, 100 },
{ vk::DescriptorType::eUniformBufferDynamic, 100 }
{ vk::DescriptorType::eUniformBufferDynamic, 100 },
{ vk::DescriptorType::eStorageImage, 100},
{ vk::DescriptorType::eStorageBufferDynamic, 100 }
};
/// <summary>
/// Maximum number of descriptor sets allowed

View File

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

View File

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

View File

@ -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<SHVkLogicalDevice> device, SetIndex set, const std::vector<Binding>& bindings)
SHVkDescriptorSetLayout::SHVkDescriptorSetLayout(Handle<SHVkLogicalDevice> device, SetIndex set, const std::vector<Binding>& 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<vk::DescriptorSetLayoutBinding> 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;

View File

@ -10,6 +10,7 @@ namespace SHADE
/* Forward Declarations */
/*---------------------------------------------------------------------------------*/
class SHVkLogicalDevice;
class SHVkSampler;
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
@ -74,7 +75,7 @@ namespace SHADE
/// </summary>
/// <param name="device"></param>
/// <param name="bindings"></param>
SHVkDescriptorSetLayout(Handle<SHVkLogicalDevice> device, SetIndex setIndex, const std::vector<Binding>& bindings);
SHVkDescriptorSetLayout(Handle<SHVkLogicalDevice> device, SetIndex setIndex, const std::vector<Binding>& bindings, bool genImmutableSamplers = false);
SHVkDescriptorSetLayout(const SHVkDescriptorSetLayout&) = delete;
SHVkDescriptorSetLayout(SHVkDescriptorSetLayout&& rhs) noexcept;
/// <summary>
@ -107,5 +108,6 @@ namespace SHADE
vk::DescriptorSetLayout setLayout;
std::vector<Binding> layoutDesc; // Stores description of the layout
SetIndex setIndex; // Index of the set
Handle<SHVkSampler> immutableSampler;
};
}

View File

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

View File

@ -21,7 +21,6 @@
#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
#include "Graphics/Images/SHVkImage.h"
namespace SHADE
{
/*-----------------------------------------------------------------------*/
@ -41,6 +40,8 @@ namespace SHADE
class SHShaderBlockInterface;
class SHVkDescriptorSetGroup;
class SHSubpass;
class SHVkSampler;
struct SHVkSamplerParams;
/***************************************************************************/
/*!
@ -102,6 +103,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
void InitializeVMA (void) noexcept;
void InitializeQueues (std::initializer_list<SHQueueParams> queueCreateParams) noexcept;
uint32_t ComputeAlignedBufferSize(uint32_t originalSize, size_t typeSize) const noexcept;
public:
/*-----------------------------------------------------------------------*/
@ -113,7 +115,7 @@ namespace SHADE
~SHVkLogicalDevice (void) noexcept;
SHVkLogicalDevice& operator= (SHVkLogicalDevice const& rhs) noexcept = default;
SHVkLogicalDevice& operator= (SHVkLogicalDevice&& rhs) noexcept = default;
SHVkLogicalDevice& operator= (SHVkLogicalDevice&& rhs) noexcept;
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER VARIABLES */
@ -121,7 +123,8 @@ namespace SHADE
// Miscellaneous functions
void WaitIdle (void) noexcept;
uint32_t FindMemoryType (uint32_t typeFilter, vk::MemoryPropertyFlags properties);
uint32_t PadUBOSize (uint32_t originalSize) const noexcept;
uint32_t PadUBOSize(uint32_t originalSize) const noexcept;
uint32_t PadSSBOSize(uint32_t originalSize) const noexcept;
// creation functions
Handle<SHVkSurface> CreateSurface (HWND const& windowHandle) const noexcept;
@ -178,11 +181,12 @@ namespace SHADE
Handle<SHVkRenderpass> const& renderpassHdl,
Handle<SHSubpass> subpass
) noexcept;
Handle<SHVkSampler> CreateSampler (const SHVkSamplerParams& params) noexcept;
Handle<SHVkRenderpass> CreateRenderpass (std::span<vk::AttachmentDescription> const vkDescriptions, std::vector<SHVkSubpassParams> const& subpasses) noexcept;
Handle<SHVkRenderpass> CreateRenderpass (std::span<vk::AttachmentDescription> const vkDescriptions, std::span<vk::SubpassDescription> const spDescs, std::span<vk::SubpassDependency> const spDeps) noexcept;
Handle<SHVkFramebuffer> CreateFramebuffer (Handle<SHVkRenderpass> const& renderpassHdl, std::vector<Handle<SHVkImageView>> const& attachments, uint32_t inWidth, uint32_t inHeight) noexcept;
Handle<SHVkDescriptorSetLayout> CreateDescriptorSetLayout (SetIndex setIndex, std::vector<SHVkDescriptorSetLayout::Binding> const& bindings) noexcept;
Handle<SHVkDescriptorSetLayout> CreateDescriptorSetLayout (SetIndex setIndex, std::vector<SHVkDescriptorSetLayout::Binding> const& bindings, bool genImmutableSamplers = false) noexcept;
Handle<SHVkDescriptorPool> CreateDescriptorPools (const SHVkDescriptorPool::Config& config = {}) noexcept;
Handle<SHVkDescriptorSetGroup> CreateDescriptorSetGroup(Handle<SHVkDescriptorPool> pool,
std::vector<Handle<SHVkDescriptorSetLayout>> const& layouts,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -22,8 +22,11 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/Pipeline/SHVkPipeline.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "ECS_Base/Managers/SHComponentManager.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h"
#include "Graphics/Descriptors/SHVkDescriptorPool.h"
namespace SHADE
{
@ -107,6 +110,7 @@ namespace SHADE
// Clear CPU buffers
drawData.clear();
transformData.clear();
eidData.clear();
matPropsData.reset();
matPropsDataSize = 0;
@ -116,11 +120,12 @@ namespace SHADE
{
drawDataBuffer[i].Free();
transformDataBuffer[i].Free();
eidBuffer[i].Free();
matPropsBuffer[i].Free();
}
}
void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex)
void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
@ -154,21 +159,17 @@ namespace SHADE
if (!matBufferDirty[frameIndex])
return;
// Build CPI Buffer
// Build CPU Buffer
char* propsCurrPtr = matPropsData.get();
for (auto& subBatch : subBatches)
for (const SHRenderable* renderable : subBatch.Renderables)
{
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
propsCurrPtr += singleMatPropSize;
propsCurrPtr += singleMatPropAlignedSize;
}
// Transfer to GPU
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
vk::BufferUsageFlagBits::eStorageBuffer
);
rebuildMaterialBuffers(frameIndex, descPool);
// This frame is updated
matBufferDirty[frameIndex] = false;
@ -207,7 +208,31 @@ namespace SHADE
transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix)), 0, 0);
}
void SHBatch::Build(Handle<SHVkLogicalDevice> _device, uint32_t frameIndex)
void SHBatch::UpdateEIDBuffer(uint32_t frameIndex)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to update eid buffers with an invalid frame index.");
return;
}
// Reset Transform Data
eidData.clear();
// Populate on the CPU
for (auto& subBatch : subBatches)
for (const SHRenderable* renderable : subBatch.Renderables)
{
eidData.emplace_back(renderable->GetEID());
}
// Transfer to GPU
if (eidBuffer[frameIndex])
eidBuffer[frameIndex]->WriteToMemory(eidData.data(), static_cast<EntityID>(eidData.size() * sizeof(EntityID)), 0, 0);
}
void SHBatch::Build(Handle<SHVkLogicalDevice> _device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
@ -215,6 +240,9 @@ namespace SHADE
return;
}
// Save logical device
device = _device;
// No need to build as there are no changes
if (!isDirty[frameIndex])
return;
@ -235,6 +263,11 @@ namespace SHADE
// - Transform data
transformData.reserve(numTotalElements);
transformData.clear();
// - EID data
eidData.reserve(numTotalElements);
eidData.clear();
// - Material Properties Data
const Handle<SHShaderBlockInterface> SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface
(
@ -247,7 +280,8 @@ namespace SHADE
if (!EMPTY_MAT_PROPS)
{
singleMatPropSize = SHADER_INFO->GetBytesRequired();
matPropTotalBytes = drawData.size() * singleMatPropSize;
singleMatPropAlignedSize = device->PadSSBOSize(static_cast<uint32_t>(singleMatPropSize));
matPropTotalBytes = numTotalElements * singleMatPropAlignedSize;
if (matPropsDataSize < matPropTotalBytes)
{
matPropsData.reset(new char[matPropTotalBytes]);
@ -267,14 +301,15 @@ namespace SHADE
.instanceCount = static_cast<uint32_t>(subBatch.Renderables.size()),
.firstIndex = subBatch.Mesh->FirstIndex,
.vertexOffset = subBatch.Mesh->FirstVertex,
.firstInstance = nextInstanceIndex
.firstInstance = nextInstanceIndex++
});
// Fill in buffers (CPU)
for (const SHRenderable* renderable : subBatch.Renderables)
{
// Transform
auto transform = SHComponentManager::GetComponent_s<SHTransformComponent>(renderable->GetEID());
EntityID eid = renderable->GetEID();
auto transform = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
if (!transform)
{
SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
@ -285,11 +320,13 @@ namespace SHADE
transformData.emplace_back(transform->GetTRS());
}
eidData.emplace_back(eid);
// Material Properties
if (!EMPTY_MAT_PROPS)
{
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
propsCurrPtr += singleMatPropSize;
propsCurrPtr += singleMatPropAlignedSize;
}
}
}
@ -304,30 +341,27 @@ namespace SHADE
const uint32_t DRAW_DATA_BYTES = static_cast<uint32_t>(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
_device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES,
device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES,
BuffUsage::eIndirectBuffer
);
// - Transform Buffer
const uint32_t TF_DATA_BYTES = static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
_device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
BuffUsage::eVertexBuffer
);
const uint32_t EID_DATA_BYTES = static_cast<uint32_t>(eidData.size() * sizeof(EntityID));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, eidBuffer[frameIndex], eidData.data(), EID_DATA_BYTES,
BuffUsage::eVertexBuffer
);
// - Material Properties Buffer
if (matPropsData)
{
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
_device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
BuffUsage::eStorageBuffer
);
}
rebuildMaterialBuffers(frameIndex, descPool);
// Mark this frame as no longer dirty
isDirty[frameIndex] = false;
// Save logical device
this->device = _device;
}
/*---------------------------------------------------------------------------------*/
@ -341,8 +375,21 @@ namespace SHADE
return;
}
// Bind all required objects before drawing
static std::array<uint32_t, 1> dynamicOffset { 0 };
cmdBuffer->BindPipeline(pipeline);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::EID, eidBuffer[frameIndex], 0);
if (matPropsDescSet[frameIndex])
{
cmdBuffer->BindDescriptorSet
(
matPropsDescSet[frameIndex],
vk::PipelineBindPoint::eGraphics,
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
dynamicOffset
);
}
cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
}
@ -355,4 +402,39 @@ namespace SHADE
dirt = true;
isCPUBuffersDirty = true;
}
void SHBatch::rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
if (matPropsData)
{
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
vk::BufferUsageFlagBits::eStorageBuffer
);
if (!matPropsDescSet[frameIndex])
{
matPropsDescSet[frameIndex] = descPool->Allocate
(
{ SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE] },
{ 0 }
);
}
std::array<Handle<SHVkBuffer>, 1> bufferList = { matPropsBuffer[frameIndex] };
matPropsDescSet[frameIndex]->ModifyWriteDescBuffer
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
bufferList,
0, static_cast<uint32_t>(matPropsDataSize)
);
matPropsDescSet[frameIndex]->UpdateDescriptorSetBuffer
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA
);
}
}
}

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