Merge branch 'main' into SP3-16-Math

This commit is contained in:
Cocoa 2022-09-19 17:08:16 +08:00
commit ec3470c443
142 changed files with 9660 additions and 844 deletions

5
.gitignore vendored
View File

@ -353,4 +353,9 @@ MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Generated Files
[Dd]ependencies/
*.vcxproj
*.vcxproj.filters
*.sln
*.csproj

View File

@ -8,34 +8,36 @@ echo "A - All"
echo "B - VMA"
echo "C - msdf"
echo "D - assimp"
echo "E - ktx"
echo "F - spdlog"
echo "G - reactphysics3d"
echo "H - imgui"
echo "I - imguizmo"
echo "J - imnodes"
echo "K - tracy"
echo "L - RTTR"
echo "M - yamlcpp"
echo "E - spdlog"
echo "F - reactphysics3d"
echo "G - imgui"
echo "H - imguizmo"
echo "I - imnodes"
echo "J - tracy"
echo "K - RTTR"
echo "L - yamlcpp"
echo "M - SDL"
echo "N - dotnet"
echo ---------------------------------------------------
echo.
choice /C ABCDEFGHIJKLM /T 10 /D A
choice /C ABCDEFGHIJKLMN /T 10 /D A
set _e=%ERRORLEVEL%
if %_e%==1 goto VMA
if %_e%==2 goto VMA
if %_e%==3 goto MSDF
if %_e%==4 goto assimp
if %_e%==5 goto ktx
if %_e%==6 goto spdlog
if %_e%==7 goto reactphysics3d
if %_e%==8 goto imgui
if %_e%==9 goto imguizmo
if %_e%==10 goto imnodes
if %_e%==11 goto tracy
if %_e%==12 goto RTTR
if %_e%==13 goto yamlcpp
if %_e%==5 goto spdlog
if %_e%==6 goto reactphysics3d
if %_e%==7 goto imgui
if %_e%==8 goto imguizmo
if %_e%==9 goto imnodes
if %_e%==10 goto tracy
if %_e%==11 goto RTTR
if %_e%==12 goto yamlcpp
if %_e%==13 goto SDL
if %_e%==14 goto dotnet
:VMA
echo -----------------------VMA----------------------------
@ -53,60 +55,87 @@ if %_e%==3 (goto :done) else (goto :assimp)
echo -----------------------assimp----------------------------
rmdir "Dependencies/assimp" /S /Q
git clone https://github.com/SHADE-DP/assimp.git "Dependencies/assimp"
if %_e%==4 (goto :done) else (goto :ktx)
if %_e%==4 (goto :done) else (goto :spdlog)
:ktx
rmdir "Dependencies/ktx" /S /Q
echo -----------------------ktx----------------------------
git clone https://github.com/SHADE-DP/ktx.git "Dependencies/ktx"
if %_e%==5 (goto :done) else (goto :spdlog)
@REM :ktx
@REM rmdir "Dependencies/ktx" /S /Q
@REM echo -----------------------ktx----------------------------
@REM git clone https://github.com/SHADE-DP/ktx.git "Dependencies/ktx"
@REM if %_e%==5 (goto :done) else (goto :spdlog)
:spdlog
echo -----------------------spdlog----------------------------
rmdir "Dependencies/spdlog" /S /Q
git clone https://github.com/SHADE-DP/spdlog.git "Dependencies/spdlog"
if %_e%==6 (goto :done) else (goto :reactphysics3d)
if %_e%==5 (goto :done) else (goto :reactphysics3d)
:reactphysics3d
echo -----------------------reactphysics3d----------------------------
rmdir "Dependencies/reactphysics3d" /S /Q
git clone https://github.com/SHADE-DP/reactphysics3d.git "Dependencies/reactphysics3d"
if %_e%==7 (goto :done) else (goto :imgui)
if %_e%==6 (goto :done) else (goto :imgui)
:imgui
echo -----------------------imgui----------------------------
rmdir "Dependencies/imgui" /S /Q
git clone https://github.com/SHADE-DP/imgui.git "Dependencies/imgui"
if %_e%==8 (goto :done) else (goto :imguizmo)
if %_e%==7 (goto :done) else (goto :imguizmo)
:imguizmo
echo -----------------------imguizmo----------------------------
rmdir "Dependencies/imguizmo" /S /Q
git clone https://github.com/SHADE-DP/ImGuizmo.git "Dependencies/imguizmo"
if %_e%==9 (goto :done) else (goto :imnodes)
if %_e%==8 (goto :done) else (goto :imnodes)
:imnodes
echo -----------------------imnodes----------------------------
rmdir "Dependencies/imnodes" /S /Q
git clone https://github.com/SHADE-DP/imnodes.git "Dependencies/imnodes"
if %_e%==10 (goto :done) else (goto :tracy)
if %_e%==9 (goto :done) else (goto :tracy)
:tracy
echo -----------------------tracy----------------------------
rmdir "Dependencies/tracy" /S /Q
git clone https://github.com/SHADE-DP/tracy.git "Dependencies/tracy"
if %_e%==11 (goto :done) else (goto :RTTR)
if %_e%==10 (goto :done) else (goto :RTTR)
:RTTR
echo -----------------------RTTR----------------------------
rmdir "Dependencies/RTTR" /S /Q
git clone https://github.com/SHADE-DP/RTTR.git "Dependencies/RTTR"
if %_e%==12 (goto :done) else (goto :yamlcpp)
if %_e%==11 (goto :done) else (goto :yamlcpp)
:yamlcpp
echo -----------------------yamlcpp----------------------------
rmdir "Dependencies/yamlcpp" /S /Q
git clone https://github.com/SHADE-DP/yaml-cpp.git "Dependencies/yamlcpp"
if %_e%==12 (goto :done) else (goto :SDL)
:SDL
echo -----------------------SDL----------------------------
rmdir "Dependencies/SDL" /S /Q
mkdir "Dependencies/SDL/include"
mkdir "Dependencies/SDL/lib"
powershell -Command "& {wget https://github.com/libsdl-org/SDL/releases/download/release-2.24.0/SDL2-devel-2.24.0-VC.zip -OutFile "Dependencies/SDL/SDL.zip"}"
powershell -Command "& {Expand-Archive -LiteralPath Dependencies/SDL/SDL.zip -DestinationPath Dependencies/SDL/tmp}"
robocopy "Dependencies/SDL/tmp/SDL2-2.24.0/lib/x64" "Dependencies/SDL/lib/" /ns /nfl /ndl /nc /njh
robocopy "Dependencies/SDL/tmp/SDL2-2.24.0/include/" "Dependencies/SDL/include/" /ns /nfl /ndl /nc /njh
rmdir "Dependencies/SDL/tmp/" /s /q
powershell -Command "& {Remove-Item "Dependencies/SDL/SDL.zip"}"
if %_e%==13 (goto :done) else (goto :dotnet)
:dotnet
echo -----------------------dotnet----------------------------
rmdir "Dependencies/dotnet" /S /Q
mkdir "Dependencies/dotnet/include"
mkdir "Dependencies/dotnet/bin"
powershell -Command "& {wget https://raw.githubusercontent.com/dotnet/runtime/main/src/coreclr/hosts/inc/coreclrhost.h -OutFile "Dependencies/dotnet/include/coreclrhost.h"}"
powershell -Command "& {wget https://download.visualstudio.microsoft.com/download/pr/8686fa48-b378-424e-908b-afbd66d6e120/2d75d5c3574fb5d917c5a3cd3f624287/dotnet-sdk-6.0.400-win-x64.zip -OutFile "Dependencies/dotnet/dotnet.zip"}"
powershell -Command "& {Expand-Archive -LiteralPath Dependencies/dotnet/dotnet.zip -DestinationPath Dependencies/dotnet/tmp}"
robocopy "Dependencies/dotnet/tmp/shared/Microsoft.NETCore.App/6.0.8/" "Dependencies/dotnet/bin/" *.dll /ns /nfl /ndl /nc /njh
rmdir "Dependencies/dotnet/tmp/" /s /q
del "Dependencies/dotnet/dotnet.zip"
powershell -Command "& {Remove-Item "Dependencies/dotnet/dotnet.zip"}"
:done
echo DONE!

View File

@ -10,6 +10,7 @@ IncludeDir["tracy"] = "%{wks.location}/Dependencies/tracy"
IncludeDir["VMA"] = "%{wks.location}/Dependencies/VMA"
IncludeDir["yamlcpp"] = "%{wks.location}/Dependencies/yamlcpp/include"
IncludeDir["RTTR"] = "%{wks.location}/Dependencies/RTTR"
IncludeDir["ktx"] = "%{wks.location}/Dependencies/ktx"
IncludeDir["reactphysics3d"] = "%{wks.location}/Dependencies/reactphysics3d"
IncludeDir["SDL"] = "%{wks.location}/Dependencies/SDL"
IncludeDir["VULKAN"] = "$(VULKAN_SDK)"
IncludeDir["dotnet"] = "%{wks.location}/Dependencies/dotnet"

Binary file not shown.

View File

@ -1,87 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SHADE_Application", "SHADE_Application\SHADE_Application.vcxproj", "{BDC70008-29DE-FE9D-7255-8ABFDEAACF25}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dependencies", "Dependencies", "{53E47842-3FC8-3998-A828-34EB942B241A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImGui", "Dependencies\imgui\ImGui.vcxproj", "{C0FF640D-2C14-8DBE-F595-301E616989EF}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "freetype", "Dependencies\msdf\msdfgen\freetype\freetype.vcxproj", "{89895BD8-7556-B6E3-9E6F-A48B8A9BEB71}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msdf-atlas-gen", "Dependencies\msdf\msdf-atlas-gen.vcxproj", "{38BD587B-248B-4C81-0D1F-BDA7F98B28E6}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msdfgen", "Dependencies\msdf\msdfgen\msdfgen.vcxproj", "{8900D8DD-F5DF-5679-FEF7-E14F6A56BDDA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reactphysics3d", "Dependencies\reactphysics3d\reactphysics3d.vcxproj", "{2ECAB41A-1A98-A820-032C-1947EF988485}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spdlog", "Dependencies\spdlog\spdlog.vcxproj", "{8EAD431C-7A4F-6EF2-630A-82464F4BF542}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml-cpp", "Dependencies\yamlcpp\yaml-cpp.vcxproj", "{88F1A057-74BE-FB62-9DD7-E90A890331F1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SHADE_Engine", "SHADE_Engine\SHADE_Engine.vcxproj", "{3F92E998-2BF5-783D-D47A-B1F3C0BC44C0}"
ProjectSection(ProjectDependencies) = postProject
{88F1A057-74BE-FB62-9DD7-E90A890331F1} = {88F1A057-74BE-FB62-9DD7-E90A890331F1}
{8900D8DD-F5DF-5679-FEF7-E14F6A56BDDA} = {8900D8DD-F5DF-5679-FEF7-E14F6A56BDDA}
{38BD587B-248B-4C81-0D1F-BDA7F98B28E6} = {38BD587B-248B-4C81-0D1F-BDA7F98B28E6}
{2ECAB41A-1A98-A820-032C-1947EF988485} = {2ECAB41A-1A98-A820-032C-1947EF988485}
{C0FF640D-2C14-8DBE-F595-301E616989EF} = {C0FF640D-2C14-8DBE-F595-301E616989EF}
{8EAD431C-7A4F-6EF2-630A-82464F4BF542} = {8EAD431C-7A4F-6EF2-630A-82464F4BF542}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BDC70008-29DE-FE9D-7255-8ABFDEAACF25}.Debug|x64.ActiveCfg = Debug|x64
{BDC70008-29DE-FE9D-7255-8ABFDEAACF25}.Debug|x64.Build.0 = Debug|x64
{BDC70008-29DE-FE9D-7255-8ABFDEAACF25}.Release|x64.ActiveCfg = Release|x64
{BDC70008-29DE-FE9D-7255-8ABFDEAACF25}.Release|x64.Build.0 = Release|x64
{C0FF640D-2C14-8DBE-F595-301E616989EF}.Debug|x64.ActiveCfg = Debug|x64
{C0FF640D-2C14-8DBE-F595-301E616989EF}.Debug|x64.Build.0 = Debug|x64
{C0FF640D-2C14-8DBE-F595-301E616989EF}.Release|x64.ActiveCfg = Release|x64
{C0FF640D-2C14-8DBE-F595-301E616989EF}.Release|x64.Build.0 = Release|x64
{89895BD8-7556-B6E3-9E6F-A48B8A9BEB71}.Debug|x64.ActiveCfg = Debug|x64
{89895BD8-7556-B6E3-9E6F-A48B8A9BEB71}.Debug|x64.Build.0 = Debug|x64
{89895BD8-7556-B6E3-9E6F-A48B8A9BEB71}.Release|x64.ActiveCfg = Release|x64
{89895BD8-7556-B6E3-9E6F-A48B8A9BEB71}.Release|x64.Build.0 = Release|x64
{38BD587B-248B-4C81-0D1F-BDA7F98B28E6}.Debug|x64.ActiveCfg = Debug|x64
{38BD587B-248B-4C81-0D1F-BDA7F98B28E6}.Debug|x64.Build.0 = Debug|x64
{38BD587B-248B-4C81-0D1F-BDA7F98B28E6}.Release|x64.ActiveCfg = Release|x64
{38BD587B-248B-4C81-0D1F-BDA7F98B28E6}.Release|x64.Build.0 = Release|x64
{8900D8DD-F5DF-5679-FEF7-E14F6A56BDDA}.Debug|x64.ActiveCfg = Debug|x64
{8900D8DD-F5DF-5679-FEF7-E14F6A56BDDA}.Debug|x64.Build.0 = Debug|x64
{8900D8DD-F5DF-5679-FEF7-E14F6A56BDDA}.Release|x64.ActiveCfg = Release|x64
{8900D8DD-F5DF-5679-FEF7-E14F6A56BDDA}.Release|x64.Build.0 = Release|x64
{2ECAB41A-1A98-A820-032C-1947EF988485}.Debug|x64.ActiveCfg = Debug|x64
{2ECAB41A-1A98-A820-032C-1947EF988485}.Debug|x64.Build.0 = Debug|x64
{2ECAB41A-1A98-A820-032C-1947EF988485}.Release|x64.ActiveCfg = Release|x64
{2ECAB41A-1A98-A820-032C-1947EF988485}.Release|x64.Build.0 = Release|x64
{8EAD431C-7A4F-6EF2-630A-82464F4BF542}.Debug|x64.ActiveCfg = Debug|x64
{8EAD431C-7A4F-6EF2-630A-82464F4BF542}.Debug|x64.Build.0 = Debug|x64
{8EAD431C-7A4F-6EF2-630A-82464F4BF542}.Release|x64.ActiveCfg = Release|x64
{8EAD431C-7A4F-6EF2-630A-82464F4BF542}.Release|x64.Build.0 = Release|x64
{88F1A057-74BE-FB62-9DD7-E90A890331F1}.Debug|x64.ActiveCfg = Debug|x64
{88F1A057-74BE-FB62-9DD7-E90A890331F1}.Debug|x64.Build.0 = Debug|x64
{88F1A057-74BE-FB62-9DD7-E90A890331F1}.Release|x64.ActiveCfg = Release|x64
{88F1A057-74BE-FB62-9DD7-E90A890331F1}.Release|x64.Build.0 = Release|x64
{3F92E998-2BF5-783D-D47A-B1F3C0BC44C0}.Debug|x64.ActiveCfg = Debug|x64
{3F92E998-2BF5-783D-D47A-B1F3C0BC44C0}.Debug|x64.Build.0 = Debug|x64
{3F92E998-2BF5-783D-D47A-B1F3C0BC44C0}.Release|x64.ActiveCfg = Release|x64
{3F92E998-2BF5-783D-D47A-B1F3C0BC44C0}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{C0FF640D-2C14-8DBE-F595-301E616989EF} = {53E47842-3FC8-3998-A828-34EB942B241A}
{89895BD8-7556-B6E3-9E6F-A48B8A9BEB71} = {53E47842-3FC8-3998-A828-34EB942B241A}
{38BD587B-248B-4C81-0D1F-BDA7F98B28E6} = {53E47842-3FC8-3998-A828-34EB942B241A}
{8900D8DD-F5DF-5679-FEF7-E14F6A56BDDA} = {53E47842-3FC8-3998-A828-34EB942B241A}
{2ECAB41A-1A98-A820-032C-1947EF988485} = {53E47842-3FC8-3998-A828-34EB942B241A}
{8EAD431C-7A4F-6EF2-630A-82464F4BF542} = {53E47842-3FC8-3998-A828-34EB942B241A}
{88F1A057-74BE-FB62-9DD7-E90A890331F1} = {53E47842-3FC8-3998-A828-34EB942B241A}
EndGlobalSection
EndGlobal

View File

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Application">
<UniqueIdentifier>{D9DE78AF-4594-F1A4-CE88-EB7B3A3DE8A8}</UniqueIdentifier>
</Filter>
<Filter Include="Scenes">
<UniqueIdentifier>{86EEB3D0-7290-DEA6-5B4B-F2FA478C65F7}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\Application\SBApplication.h">
<Filter>Application</Filter>
</ClInclude>
<ClInclude Include="src\SBpch.h" />
<ClInclude Include="src\Scenes\SBTestScene.h">
<Filter>Scenes</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\Application\SBApplication.cpp">
<Filter>Application</Filter>
</ClCompile>
<ClCompile Include="src\SBpch.cpp" />
<ClCompile Include="src\Scenes\SBTestScene.cpp">
<Filter>Scenes</Filter>
</ClCompile>
<ClCompile Include="src\WinMain.cpp" />
</ItemGroup>
</Project>

View File

@ -1,9 +1,9 @@
project "SHADE_Application"
kind "WindowedApp"
language "C++"
cppdialect "C++latest"
targetdir ("bin/" .. outputdir .. "/%{prj.name}")
objdir ("bin-int/" .. outputdir .. "/%{prj.name}")
cppdialect "C++20"
targetdir (outputdir)
objdir (interdir)
systemversion "latest"
pchheader "SBpch.h"
pchsource "%{prj.location}/src/SBpch.cpp"
@ -14,6 +14,7 @@ project "SHADE_Application"
files
{
"%{prj.location}/src/**.h",
"%{prj.location}/src/**.hpp",
"%{prj.location}/src/**.c",
"%{prj.location}/src/**.cpp",
"%{prj.location}/src/**.glsl",
@ -21,11 +22,22 @@ project "SHADE_Application"
includedirs
{
"%{IncludeDir.spdlog}/include",
"../SHADE_Engine/src",
"src"
"src",
"%{IncludeDir.dotnet}/include",
"%{IncludeDir.SDL}/include",
}
externalincludedirs
{
"%{IncludeDir.spdlog}/include",
"%{IncludeDir.VULKAN}/include",
"%{IncludeDir.VMA}/include",
"%{IncludeDir.VULKAN}/Source/SPIRV-Reflect"
}
externalwarnings "Off"
flags
{
"MultiProcessorCompile"
@ -33,11 +45,26 @@ project "SHADE_Application"
links
{
"SHADE_Engine"
"SHADE_Engine",
"SHADE_Managed",
"SDL2.lib",
"SDL2main.lib"
}
postbuildcommands
libdirs
{
"%{IncludeDir.spdlog}/lib",
"%{IncludeDir.SDL}/lib",
}
defines
{
"NOMINMAX"
}
disablewarnings
{
"4251"
}
warnings 'Extra'

View File

@ -1,17 +1,22 @@
#include "SBpch.h"
#include "SBApplication.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#define SHEDITOR
#ifdef SHEDITOR
#include "Editor/SHEditor.h"
#include "Scenes/SBEditorScene.h"
//#include "Editor/SHEditor.h"
//#include "Scenes/SBEditorScene.h"
#endif // SHEDITOR
#include "Math/SHMath.h"
#include "Tools/SHLogger.h"
#include "Tools/SHFileUtilties.h"
#include <chrono>
#include <ratio>
#include <ctime>
#include <SDL.h>
#include "Scripting/SHScriptEngine.h"
namespace Sandbox
{
@ -24,32 +29,56 @@ namespace Sandbox
_In_ INT nCmdShow
)
{
// Set working directory
SHADE::SHFileUtilities::SetWorkDirToExecDir();
SHADE::SHQuaternion aroundZ20{ SHADE::SHVec3::UnitZ, SHADE::SHMath::DegreesToRadians(20.0f) };
SHLOG_INFO("Angle is {}", SHADE::SHMath::RadiansToDegrees(aroundZ20.GetAngle()))
SDL_Init(SDL_INIT_VIDEO);
window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
SHADE::SHSystemManager::CreateSystem<SHADE::SHGraphicsSystem>();
SHADE::SHGraphicsSystem* graphicsSystem = static_cast<SHADE::SHGraphicsSystem*>(SHADE::SHSystemManager::GetSystem<SHADE::SHGraphicsSystem>());
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHGraphicsSystem, SHADE::SHGraphicsSystem::SHGraphicsSystemRoutine>(1);
graphicsSystem->SetWindow(&window);
SDL_CreateWindowFrom(window.GetHWND());
SHADE::SHSystemManager::Init();
#ifdef SHEDITOR
//SHADE::SHEditor::Initialize(window.GetHWND());
#else
#endif
// Set up scripting
SHADE::SHScriptEngine::Init();
}
void SBApplication::Update(void)
{
SHADE::SHGraphicsSystem* graphicsSystem = static_cast<SHADE::SHGraphicsSystem*>(SHADE::SHSystemManager::GetSystem<SHADE::SHGraphicsSystem>());
//TODO: Change true to window is open
while (!window.WindowShouldClose())
{
#ifdef SHEDITOR
#else
#endif
//#ifdef SHEDITOR
//SHADE::SHEditor::PreRender();
//#endif
graphicsSystem->BeginRender();
graphicsSystem->Run(1.0f);
//#ifdef SHEDITOR
//SHADE::SHEditor::PreRender();
//SHADE::SHEditor::Update();
//SHADE::SHEditor::Render();
//#endif
graphicsSystem->EndRender();
}
}
void SBApplication::Exit(void)
{
SHADE::SHScriptEngine::Exit();
SHADE::SHSystemManager::Exit();
SDL_DestroyWindow(sdlWindow);
#ifdef SHEDITOR
#else
#endif

View File

@ -1,6 +1,8 @@
#ifndef SB_APPLICATION_H
#define SB_APPLICATION_H
#include <Graphics/Windowing/SHWindow.h>
#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h"
#include <SDL_video.h>
//using namespace SHADE;
namespace Sandbox
@ -9,6 +11,7 @@ namespace Sandbox
{
private:
SHADE::SHWindow window;
SDL_Window* sdlWindow;
//SHAppConfig config;
public:
SBApplication() = default;

View File

@ -26,7 +26,7 @@ INT WINAPI wWinMain
)
{
const SHADE::SHLogger::Config LOGGER_CONFIG{ .directoryPath = "./logs/" };
SHADE::SHLogger::Initialise(LOGGER_CONFIG);
auto logger = SHADE::SHLogger::Initialise(LOGGER_CONFIG);
try
{
@ -34,7 +34,7 @@ INT WINAPI wWinMain
//ShowWindow(::GetConsoleWindow(), SW_HIDE);
#endif
SHLOG_INFO("sup")
SHLOG_REGISTER(logger)
SHADE::SHEngine::Run<Sandbox::SBApplication>(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

View File

@ -1,9 +1,9 @@
project "SHADE_Engine"
kind "StaticLib"
kind "SharedLib"
language "C++"
cppdialect "C++latest"
targetdir ("bin/" .. outputdir .. "/%{prj.name}")
objdir ("bin-int/" .. outputdir .. "/%{prj.name}")
cppdialect "C++20"
targetdir (outputdir)
objdir (interdir)
systemversion "latest"
pchheader "SHpch.h"
pchsource "%{prj.location}/src/SHpch.cpp"
@ -12,15 +12,19 @@ project "SHADE_Engine"
files
{
"%{prj.location}/src/**.h",
"%{prj.location}/src/**.hpp",
"%{prj.location}/src/**.c",
"%{prj.location}/src/**.cpp",
"%{prj.location}/src/**.glsl",
"%{wks.location}/Dependencies/stb_image/**.cpp"
"%{prj.location}/src/**.glsl"
}
includedirs
{
"%{prj.location}/src",
}
externalincludedirs
{
"%{IncludeDir.assimp}/include",
"%{IncludeDir.imgui}",
"%{IncludeDir.imguizmo}",
@ -31,13 +35,16 @@ project "SHADE_Engine"
"%{IncludeDir.tracy}",
"%{IncludeDir.VMA}/include",
"%{IncludeDir.yamlcpp}",
"%{IncludeDir.ktx}/include",
"%{IncludeDir.SDL}/include",
"%{IncludeDir.RTTR}/include",
"%{IncludeDir.reactphysics3d}/include",
"%{IncludeDir.VULKAN}/include",
"%{IncludeDir.VULKAN}/Source/SPIRV-Reflect"
"%{IncludeDir.VULKAN}/Source/SPIRV-Reflect",
"%{IncludeDir.dotnet}/include",
}
externalwarnings "Off"
libdirs
{
"%{prj.location}/libs",
@ -45,8 +52,8 @@ project "SHADE_Engine"
"%{IncludeDir.assimp}/lib/Debug",
"%{IncludeDir.assimp}/lib/Release",
"%{IncludeDir.RTTR}/lib",
"%{IncludeDir.ktx}/lib/Debug",
"%{IncludeDir.ktx}/lib/Release",
"%{IncludeDir.SDL}/lib",
"%{IncludeDir.spdlog}/lib"
}
links
@ -56,9 +63,16 @@ project "SHADE_Engine"
"msdf-atlas-gen",
"reactphysics3d",
"imgui",
"spdlog",
"vulkan-1.lib",
"shaderc_shared.lib"
"SDL2.lib",
"SDL2main.lib",
"shaderc_shared.lib",
"shlwapi.lib"
}
disablewarnings
{
"4251"
}
defines
@ -66,7 +80,8 @@ project "SHADE_Engine"
"_LIB",
"_GLFW_INCLUDE_NONE",
"MSDFGEN_USE_CPP11",
"NOMINMAX"
"NOMINMAX",
"SH_API_EXPORT"
}
flags
@ -81,7 +96,13 @@ project "SHADE_Engine"
"msdf-atlas-gen",
"reactphysics3d",
"imgui",
"spdlog",
}
postbuildcommands
{
"xcopy /s /r /y /q \"%{IncludeDir.spdlog}/bin\" \"$(OutDir)\"",
"xcopy /r /y /q \"%{IncludeDir.SDL}/lib/SDL2.dll\" \"$(OutDir)\"",
"xcopy /s /r /y /q \"%{IncludeDir.dotnet}/bin\" \"$(OutDir)\""
}
warnings 'Extra'
@ -89,11 +110,11 @@ project "SHADE_Engine"
filter "configurations:Debug"
symbols "On"
defines {"_DEBUG"}
links{"assimp-vc142-mtd.lib", "ktxd.lib", "librttr_core_d.lib"}
links{"assimp-vc142-mtd.lib", "librttr_core_d.lib", "spdlogd.lib"}
--links{"fmodstudioL_vc.lib", "fmodL_vc.lib"}
filter "configurations:Release"
optimize "On"
defines{"_RELEASE"}
links{"assimp-vc142-mt.lib", "ktx.lib", "librttr_core.lib"}
links{"assimp-vc142-mt.lib", "librttr_core.lib", "spdlog.lib"}
--links{"fmodstudio_vc.lib", "fmod_vc.lib"}

View File

@ -0,0 +1,28 @@
/************************************************************************************//*!
\file SHCommonTypes.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Sep 8, 2022
\brief Contains the definitions of type alias for commonly used units for
clarity and convenience.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
/***********************************************************************************/
/*!
\brief
Type used to mark a value that is supposed to represent a size in bytes.
*/
/***********************************************************************************/
using Byte = size_t;
}

View File

@ -9,18 +9,18 @@
*********************************************************************/
#ifndef SH_COMPONENT_H
#define SH_COMPONENT_H
#pragma once
#include "SHpch.h"
#include "../SHECSMacros.h"
#include "SH_API.h"
namespace SHADE
{
class SHComponentManager;
class SHComponent
class SH_API SHComponent
{
friend SHComponentManager;
@ -118,4 +118,3 @@ namespace SHADE
};
}
#endif

View File

@ -14,7 +14,7 @@
#include "SHpch.h"
#include "SHComponentGroup.h"
#include "../System/SHComponentManager.h"
#include "../Managers/SHComponentManager.h"
namespace SHADE

View File

@ -12,9 +12,7 @@
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#ifndef SH_COMPONENT_GROUP
#define SH_COMPONENT_GROUP
#pragma once
#include "../SHECSMacros.h"
#include "../General/SHFamily.h"
@ -180,6 +178,3 @@ namespace SHADE
};
}
#endif

View File

@ -9,9 +9,9 @@
*********************************************************************/
#include "SHpch.h"
#include "SHEntity.h"
#include "../System/SHEntityManager.h"
#include "../Managers/SHEntityManager.h"
//#include "Scene/SHSceneGraph.h"
#include "../System/SHComponentManager.h"
#include "../Managers/SHComponentManager.h"
namespace SHADE
{
@ -28,7 +28,7 @@ namespace SHADE
//SHEntityManager::RemoveEntity(this->entityID);
}
EntityID SHEntity::GetEID() noexcept
EntityID SHEntity::GetEID() const noexcept
{
return this->entityID;
}
@ -39,6 +39,10 @@ namespace SHADE
SHComponentManager::SetActive(entityID, active);
}
bool SHEntity::GetActive(void) const noexcept
{
return isActive;
}
void SHEntity::SetParent(SHEntity* newParent) noexcept
@ -53,20 +57,20 @@ namespace SHADE
//TODO
}
SHEntity* SHEntity::GetParent() noexcept
SHEntity* SHEntity::GetParent()const noexcept
{
//TODO
return nullptr;
}
std::vector<SHEntity*>const& SHEntity::GetChildren() noexcept
std::vector<SHEntity*>const& SHEntity::GetChildren()const noexcept
{
//TODO
return std::vector<SHEntity*>{};
}
std::vector<EntityID>const& SHEntity::GetChildrenID() noexcept
std::vector<EntityID>const& SHEntity::GetChildrenID()const noexcept
{
return std::vector<EntityID>{};
}

View File

@ -8,13 +8,13 @@
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#ifndef SH_ENTITY_H
#define SH_ENTITY_H
#pragma once
#include "../SHECSMacros.h"
#include "../Components/SHComponent.h"
#include "../System/SHComponentManager.h"
#include "../Managers/SHComponentManager.h"
//#include "../../Scene/SHSceneNode.h"
#include "SH_API.h"
@ -23,7 +23,7 @@ namespace SHADE
class SHComponentManager;
class SHEntityManager;
class SHEntity
class SH_API SHEntity
{
public:
@ -63,7 +63,7 @@ namespace SHADE
* Returns nullptr if the entity does not have such Component.
***************************************************************************/
template<typename T>
std::enable_if_t<std::is_base_of_v<SHComponent, T>, T*> GetComponent() noexcept
std::enable_if_t<std::is_base_of_v<SHComponent, T>, T*> GetComponent()const noexcept
{
return SHComponentManager::GetComponent_s<T>(entityID);
@ -77,7 +77,7 @@ namespace SHADE
* \return uint32_t
* The entityID of this Entity object.
***************************************************************************/
EntityID GetEID() noexcept;
EntityID GetEID() const noexcept;
/*!*************************************************************************
* \brief Set the Active object
@ -91,6 +91,7 @@ namespace SHADE
***************************************************************************/
virtual void SetActive(bool active) noexcept;
bool GetActive(void)const noexcept;
/**************************************************************************
@ -124,7 +125,7 @@ namespace SHADE
* Returns a pointer to the parent entity.
* Returns a nullptr if the parent node is the root node.
***************************************************************************/
SHEntity* GetParent() noexcept;
SHEntity* GetParent()const noexcept;
/**************************************************************************
@ -133,7 +134,7 @@ namespace SHADE
* \return
* Return a vector of SHEntity pointers of the children belonging to this entity.
***************************************************************************/
std::vector<SHEntity*>const& GetChildren() noexcept;
std::vector<SHEntity*>const& GetChildren()const noexcept;
/**************************************************************************
* \brief
@ -141,11 +142,13 @@ namespace SHADE
* \return
* return a vector of EntityID of the children belonging to this entity.
***************************************************************************/
std::vector<EntityID>const& GetChildrenID() noexcept;
std::vector<EntityID>const& GetChildrenID()const noexcept;
//Name of the entity. This name is non-unique and only used for the editor.
std::string name;
bool isActive;
private:
@ -156,8 +159,10 @@ namespace SHADE
EntityID entityID;
//Entity active state. This should only be set using the SetActive function which will
//set the active state of all components of this entity.
bool isActive;
};
}
#endif

View File

@ -0,0 +1,12 @@
#pragma once
#include "ECS_Base/Entity/SHEntity.h"
namespace SHADE
{
struct SHEntityCreationEvent
{
EntityID eid;
std::vector<ComponentTypeID> componentTypeIDs;
};
}

View File

@ -0,0 +1,11 @@
#pragma once
#include "ECS_Base/Entity/SHEntity.h"
namespace SHADE
{
struct SHEntityDestroyedEvent
{
EntityID eid;
};
}

View File

@ -11,8 +11,7 @@
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#ifndef SH_FAMILY_H
#define SH_FAMILY_H
#pragma once
#include "../SHECSMacros.h"
@ -82,7 +81,3 @@ namespace SHADE
ComponentTypeID SHFamilyID<BaseClass>::currentID = 0;
}
#endif

View File

@ -11,8 +11,7 @@
or disclosure of this file or its contents without the prior written
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#ifndef SH_HANDLE_GENERATOR_H
#define SH_HANDLE_GENERATOR_H
#pragma once
#include <vector>
#include <iostream>
@ -300,6 +299,3 @@ namespace SHADE
typedef SHHandleGenerator<EntityID, EntityIndex> EntityHandleGenerator;
}
#endif

View File

@ -10,8 +10,7 @@
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#ifndef SH_SPARSE_BASE_H
#define SH_SPARSE_BASE_H
#pragma once
#include "../SHECSMacros.h"
@ -45,6 +44,3 @@ namespace SHADE
};
}
#endif

View File

@ -9,8 +9,7 @@
or disclosure of this file or its contents without the prior written
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#ifndef SH_SPARSE_SET_H
#define SH_SPARSE_SET_H
#pragma once
#include "../SHECSMacros.h"
#include "../General/SHSparseBase.h"
@ -352,5 +351,3 @@ namespace SHADE
};
}
#endif

View File

@ -10,8 +10,7 @@
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#ifndef SH_SPARSE_SET_CONTAINER_H
#define SH_SPARSE_SET_CONTAINER_H
#pragma once
#include "SHSparseSet.h"
#include "SHFamily.h"
@ -243,6 +242,3 @@ namespace SHADE
};
}
#endif

View File

@ -12,20 +12,22 @@
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#ifndef SH_ENGINE_H
#define SH_ENGINE_H
#pragma once
#include "../General/SHSparseSetContainer.h"
#include "../Components/SHComponent.h"
#include "../Components/SHComponentGroup.h"
//#include "Scene/SHSceneNode.h"
#include "SH_API.h"
#include <cassert>
namespace SHADE
{
class SHComponentManager
typedef SHFamilyID<SHComponent> ComponentFamily;
class SH_API SHComponentManager
{
private:
@ -38,6 +40,8 @@ namespace SHADE
/**************************************************************************
* \brief
* This is called by the SHSceneNode friend class to change the parent
@ -225,7 +229,7 @@ namespace SHADE
* \return
* none
***************************************************************************/
static void AddComponent(EntityID entityID, uint32_t componentTypeID) noexcept
static void AddComponent(EntityID entityID, ComponentTypeID componentTypeID) noexcept
{
componentSet.GetSparseSet_ID(componentTypeID)->Add(EntityHandleGenerator::GetIndex(entityID));
@ -277,7 +281,7 @@ namespace SHADE
* \return bool
* True if the entity has a component of specified type.
***************************************************************************/
static bool HasComponent_ID(EntityID entityID, uint32_t componentTypeID) noexcept;
static bool HasComponent_ID(EntityID entityID, ComponentTypeID componentTypeID) noexcept;
/*!*************************************************************************
@ -362,7 +366,7 @@ namespace SHADE
* \return
*
***************************************************************************/
static void SwapInDenseByIndexHash_ID(EntityIndex index, EntityID hash, uint32_t componentTypeID) noexcept;
static void SwapInDenseByIndexHash_ID(EntityIndex index, EntityID hash, ComponentTypeID componentTypeID) noexcept;
@ -385,7 +389,7 @@ namespace SHADE
* \return
* The number of components in the component sparse set.
***************************************************************************/
static EntityIndex ComponentCount_ID(uint32_t componentTypeID)
static EntityIndex ComponentCount_ID(ComponentTypeID componentTypeID)
{
return componentSet.GetSparseSet_ID(componentTypeID)->Count();
}
@ -402,9 +406,9 @@ namespace SHADE
static void SetActive(EntityID entityID, bool active) noexcept;
template<typename... T>
static std::enable_if_t<(... && std::is_base_of_v<SHComponent, T>), uint32_t> CreateComponentGroup(uint32_t numOwningComponents)
static std::enable_if_t<(... && std::is_base_of_v<SHComponent, T>), uint32_t> CreateComponentGroup(ComponentTypeID numOwningComponents)
{
std::vector<uint32_t> templateIDs{ (SHFamilyID<SHComponent>::GetID<T>())... };
std::vector<ComponentTypeID> templateIDs{ (ComponentFamily::GetID<T>())... };
for (auto& g : componentGroups)
{
@ -421,11 +425,11 @@ namespace SHADE
}
SHComponentGroup grp;
for (uint32_t i = 0; i < numOwningComponents; ++i)
for (ComponentTypeID i = 0; i < numOwningComponents; ++i)
{
grp.ownedComponentTypes.push_back(templateIDs[i]);
}
for (uint32_t i = 0; i < templateIDs.size(); ++i)
for (ComponentTypeID i = 0; i < templateIDs.size(); ++i)
{
grp.componentTypeIDs.push_back(templateIDs[i]);
}
@ -472,6 +476,3 @@ namespace SHADE
}
#endif

View File

@ -52,63 +52,20 @@ namespace SHADE
return entityHandle.GetIndex(entityID);
}
EntityID SHEntityManager::CreateEntity(std::vector<uint32_t>const& componentTypeIDs, std::string const& name,EntityID parentEID)
{
EntityID eID = entityHandle.GetNewHandle();
EntityIndex eIndex = entityHandle.GetIndex(eID);
if (eIndex > entityVec.size())
{
assert("FATAL ERROR: EntityIndex out of range in Entity Creation");
}
else if (eIndex == entityVec.size())
{
entityVec.emplace_back(std::make_unique<SHEntity>());
}
else
{
if (!entityVec[eIndex])
{
//There is still an entity stored there.Something went wrong
assert("FATAL ERROR: Entity Creation error. Entity Index Conflict");
}
//Reset it to a newly constructed entity
entityVec[eIndex].reset(new SHEntity());
}
entityVec[eIndex]->entityID = eID;
entityVec[eIndex]->name = name;
for (auto& id : componentTypeIDs)
{
SHComponentManager::AddComponent(eID, id);
}
//(SHComponentManager::AddComponent<ComponentTypes>(eID), ...);
/*if (entityHandle.IsValid(parentEID) == false)
{
entityVec[eIndex]->sceneNode.ConnectToRoot();
}
else
{
entityVec[eIndex]->SetParent(parentEID);
}*/
//TODO Link to Scene graph.
return eID;
}
EntityID SHEntityManager::CreateEntity(std::vector<uint32_t>const& componentTypeIDs, EntityID desiredEID, std::string const& name, EntityID parentEID)
{
EntityID eID ;
EntityID eID;
if (desiredEID == MAX_EID)
{
eID = entityHandle.GetNewHandle();
}
else
{
if (entityHandle.ClaimHandle(desiredEID) == true)
eID = desiredEID;
else
eID = entityHandle.GetNewHandle();
}
EntityIndex eIndex = entityHandle.GetIndex(eID);
@ -146,6 +103,10 @@ namespace SHADE
SHComponentManager::AddComponent(eID, id);
}
//set up event stuff
SHEntityCreationEvent event{ eID,componentTypeIDs };
SHEventManager::BroadcastEvent<SHEntityCreationEvent>(event, SH_ENTITY_CREATION_EVENT);
//(SHComponentManager::AddComponent<ComponentTypes>(eID), ...);
//if (entityHandle.IsValid(parentEID) == false)
@ -196,6 +157,12 @@ namespace SHADE
entityHandle.RemoveHandle(eID);
entityVec[eIndex].reset(nullptr);
SHEntityDestroyedEvent event{eID};
SHEventManager::BroadcastEvent<SHEntityDestroyedEvent>(event, SH_ENTITY_DESTROYED_EVENT);
}
}

View File

@ -12,9 +12,7 @@
or disclosure of this file or its contents without the prior written
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#ifndef SH_ENTITY_MANAGER_H
#define SH_ENTITY_MANAGER_H
#pragma once
#include <vector>
#include <memory>
@ -22,11 +20,15 @@
#include "../Components/SHComponent.h"
#include "../General/SHHandleGenerator.h"
#include "../SHECSMacros.h"
#include "ECS_Base/Events/SHEntityCreationEvent.h"
#include "ECS_Base/Events/SHEntityDestroyedEvent.h"
#include "Events/SHEventManager.h"
#include "SH_API.h"
namespace SHADE
{
class SHEntityManager
class SH_API SHEntityManager
{
private:
static std::vector<std::unique_ptr<SHEntity>> entityVec;
@ -81,55 +83,21 @@ namespace SHADE
* EntityID of the new Entity
***************************************************************************/
template<typename ...ComponentTypes>
static std::enable_if_t<(... && std::is_base_of_v<SHComponent, ComponentTypes>), EntityID> CreateEntity(std::string const& name = "Default", EntityID parentEID = MAX_EID)
{
EntityID eID = entityHandle.GetNewHandle();
EntityIndex eIndex = entityHandle.GetIndex(eID);
if (eIndex > entityVec.size())
{
assert("FATAL ERROR: EntityIndex out of range in Entity Creation");
}
else if (eIndex == entityVec.size())
{
entityVec.emplace_back(std::make_unique<SHEntity>());
}
else
{
if (!entityVec[eIndex])
{
//There is still an entity stored there.Something went wrong
assert("FATAL ERROR: Entity Creation error. Entity Index Conflict");
}
//Reset it to a newly constructed entity
entityVec[eIndex].reset(new SHEntity());
}
entityVec[eIndex]->entityID = eID;
entityVec[eIndex]->name = name;
(SHComponentManager::AddComponent<ComponentTypes>(eID),...);
/*if (entityHandle.IsValid(parentEID) == false)
{
entityVec[eIndex]->sceneNode.ConnectToRoot();
}
else
{
entityVec[eIndex]->SetParent(parentEID);
}*/
//TODO Link up with Scene graph
return eID;
}
template<typename ...ComponentTypes>
static std::enable_if_t<(... && std::is_base_of_v<SHComponent, ComponentTypes>), EntityID> CreateEntity(EntityID desiredEID, std::string const& name = "Default", EntityID parentEID = MAX_EID)
static std::enable_if_t<(... && std::is_base_of_v<SHComponent, ComponentTypes>), EntityID> CreateEntity(EntityID desiredEID = MAX_EID, std::string const& name = "Default", EntityID parentEID = MAX_EID)
{
EntityID eID;
if (desiredEID == MAX_EID)
{
eID = entityHandle.GetNewHandle();
}
else
{
if (entityHandle.ClaimHandle(desiredEID) == true)
eID = desiredEID;
else
eID = entityHandle.GetNewHandle();
}
EntityIndex eIndex = entityHandle.GetIndex(eID);
if (eIndex > entityVec.size())
{
@ -160,6 +128,14 @@ namespace SHADE
entityVec[eIndex]->name = name;
(SHComponentManager::AddComponent<ComponentTypes>(eID), ...);
//set up event stuff
std::vector<ComponentTypeID> typeIDVec;
(typeIDVec.push_back(ComponentFamily::GetID<ComponentTypes>()), ...);
SHEntityCreationEvent event{ eID,typeIDVec };
SHEventManager::BroadcastEvent<SHEntityCreationEvent>(event, SH_ENTITY_CREATION_EVENT);
/*if (entityHandle.IsValid(parentEID) == false)
{
entityVec[eIndex]->sceneNode.ConnectToRoot();
@ -179,21 +155,6 @@ namespace SHADE
/**************************************************************************
* \brief
* Create Entity using a vector of ComponentTypeIDs.
* \param componentTypeIDs
* Vector of ComponentTypeIDs. This assumes that CreateSparseSet is called
* for these ComponentTypes.
* \param name
* Name of the Entity (this is not unique)
* \param parentEID
* The entity ID of the parent. This does not call UpdateHierarchy hence
* the parent of the entity is not updated until UpdateHierarchy is called.
* \return
* EntityID of the new Entity
***************************************************************************/
static EntityID CreateEntity(std::vector<ComponentTypeID>const& componentTypeIDs,std::string const& name = "Default", EntityID parentEID = MAX_EID);
/**************************************************************************
* \brief
@ -209,7 +170,7 @@ namespace SHADE
* \return
* EntityID of the new Entity
***************************************************************************/
static EntityID CreateEntity(std::vector<ComponentTypeID>const& componentTypeIDs, EntityID desiredEID, std::string const& name = "Default", EntityID parentEID = MAX_EID);
static EntityID CreateEntity(std::vector<ComponentTypeID>const& componentTypeIDs, EntityID desiredEID = MAX_EID, std::string const& name = "Default", EntityID parentEID = MAX_EID);
/**************************************************************************
* \brief
@ -247,7 +208,3 @@ namespace SHADE
}
#endif

View File

@ -0,0 +1,77 @@
/*********************************************************************
* \file SHSystemManager.cpp
* \author Daniel Chua Yee Chen
* \brief Implementation for the SHSystemManager class.
* SHSystemManager is the interface class where users of the engine create
* the systems that gives the components their functionality. This also
* ensures that the Init and Exit functions are ran at the appropriate time
*
* \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 "SHSystemManager.h"
#include <iostream>
#include <chrono>
#include <ratio>
#include <ctime>
namespace SHADE
{
SHSystemManager::SystemContainer SHSystemManager::systemContainer;
SHSystemManager::SystemRoutineContainer SHSystemManager::systemRoutineContainer;
void SHSystemManager::Init() noexcept
{
for (auto& system : systemContainer)
{
system.second->Init();
#ifdef _DEBUG
std::cout << system.first << " Init" << std::endl;
#endif
}
}
void SHSystemManager::RunRoutines(bool editorPause, double deltaTime) noexcept
{
for (auto& routine : systemRoutineContainer)
{
if (editorPause == true)
{
if (routine.get()->IsRunInEditorPause)
{
std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
routine.get()->Execute(deltaTime);
std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
routine.get()->stats.executionTime = std::chrono::duration<double, std::milli>(end - start).count();
}
}
else
{
std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
routine.get()->Execute(deltaTime);
std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
routine.get()->stats.executionTime = std::chrono::duration<double, std::milli>(end - start).count();
}
}
}
void SHSystemManager::Exit() noexcept
{
systemRoutineContainer.clear();
for (SystemContainer::reverse_iterator it = systemContainer.rbegin(); it != systemContainer.rend(); ++it)
{
(*it).second->Exit();
//delete system.second;
}
systemContainer.clear();
}
}

View File

@ -10,29 +10,33 @@
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#ifndef SH_SYSTEM_MANAGER_H
#define SH_SYSTEM_MANAGER_H
#pragma once
#include <unordered_map>
#include <map>
#include <memory>
#include <string>
#include <cassert>
#include <climits>
#include "../System/SHSystem.h"
#include "../General/SHFamily.h"
#include "../System/SHSystemRoutine.h"
#include "SH_API.h"
namespace SHADE
{
class SHSystemManager
typedef SHFamilyID<SHSystem> SystemFamily;
class SH_API SHSystemManager
{
//type definition for the container we use to store our system
using SystemContainer = std::unordered_map<std::string, std::unique_ptr<SHSystem>>;
using SystemContainer = std::map<SystemID, std::unique_ptr<SHSystem>>;
using SystemRoutineContainer = std::vector<std::unique_ptr<SHSystemRoutine>>;
private:
static SystemContainer systemContainer;
static SystemRoutineContainer systemRoutineContainer;
public:
/*!*************************************************************************
@ -52,15 +56,21 @@ namespace SHADE
* none
***************************************************************************/
template<typename T>
static std::enable_if_t<std::is_base_of_v<SHSystem, T>, void> CreateSystem(std::string const& name)
static std::enable_if_t<std::is_base_of_v<SHSystem, T>, SystemID> CreateSystem()
{
if (systemContainer.find(name) != systemContainer.end())
SystemTypeID typeID = SystemFamily::GetID<T>();
SystemVersionID version = 0;
SystemID id = ((SystemID)version << sizeof(SystemVersionID) * CHAR_BIT) + typeID;
while (systemContainer.find(id) != systemContainer.end())
{
assert("System Creation Error: System with the same name already exist.");
++version;
id = ((SystemID)version << sizeof(SystemVersionID) * CHAR_BIT) + typeID;
}
systemContainer.emplace(id, std::make_unique<T>());
systemContainer[id].get()->systemID = id;
systemContainer.emplace(name, std::make_unique<T>());
return id;
}
@ -72,7 +82,21 @@ namespace SHADE
* \return
* Base System pointer.
***************************************************************************/
static SHSystem* GetSystem(std::string name);
template<typename T>
static std::enable_if_t<std::is_base_of_v<SHSystem, T>, T*> GetSystem(SystemVersionID version = 0)
{
SystemTypeID typeID = SystemFamily::GetID<T>();
SystemID id = ((SystemID)version << sizeof(SystemVersionID) * CHAR_BIT) + typeID;
if (systemContainer.find(id) == systemContainer.end())
{
std::cout << "System Manager error: System Version " << version << " does not exit." << std::endl;
return nullptr;
}
return (T*)systemContainer.find(id)->second.get();
}
/**************************************************************************
* \brief
@ -82,6 +106,20 @@ namespace SHADE
***************************************************************************/
static void Init() noexcept;
static void RunRoutines(bool editorPause, double deltaTime) noexcept;
template<typename SystemType, typename RoutineType>
static void RegisterRoutine(SystemVersionID version = 0) noexcept
{
SHSystem* system = GetSystem<SystemType>(version);
if (system == nullptr)
return;
systemRoutineContainer.emplace_back(std::make_unique<RoutineType>());
systemRoutineContainer.back().get()->system = system;
}
/**************************************************************************
* \brief
* Call the Exit function of all systems.
@ -96,7 +134,3 @@ namespace SHADE
};
}
#endif

View File

@ -9,6 +9,10 @@
typedef uint32_t EntityID;
typedef uint16_t EntityIndex;
typedef uint32_t ComponentTypeID;
typedef uint32_t SystemTypeID;
typedef uint32_t SystemVersionID;
typedef uint64_t SystemID;
const EntityIndex MAX_EID = 51000;

View File

@ -0,0 +1,21 @@
#include "SHpch.h"
#include "SHFixedSystemRoutine.h"
#include "../SHECSMacros.h"
namespace SHADE
{
void SHFixedSystemRoutine::Execute(double dt) noexcept
{
accumulatedTime += dt;
int counter = 0;
while (accumulatedTime >= fixedTimeStep)
{
++counter;
accumulatedTime -= fixedTimeStep;
FixedExecute(fixedTimeStep);
}
stats.numSteps = counter;
}
}

View File

@ -0,0 +1,31 @@
#pragma once
#include "SHSystemRoutine.h"
#define DEFAULT_FIXED_STEP 1.0/60.0
namespace SHADE
{
class SHFixedSystemRoutine: public SHSystemRoutine
{
private:
double accumulatedTime;
double fixedTimeStep;
protected:
SHFixedSystemRoutine(double timeStep = DEFAULT_FIXED_STEP, std::string routineName = "Default Fixed Routine Name", bool editorPause = false)
:SHSystemRoutine(routineName, editorPause), accumulatedTime(0.0), fixedTimeStep(timeStep){}
public:
~SHFixedSystemRoutine() = default;
virtual void Execute(double dt) noexcept;
virtual void FixedExecute(double dt) noexcept {};
};
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <string>
#include <iostream>
namespace SHADE
{
struct SHRoutineStats
{
SHRoutineStats(std::string name)
:name(name)
{
}
std::string name;
double executionTime;
int numSteps{1};
//friend std::ostream& operator<<(std::ostream& os, const SHRoutineStats& stats);
};
//std::ostream& operator<<(std::ostream& os, const SHRoutineStats& stats)
//{
// os << stats.name << ": Execution Time: " << stats.executionTime << " Number of steps: " << stats.numSteps << std::endl;
// return os;
//}
}

View File

@ -8,13 +8,20 @@
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#ifndef SH_SYSTEM_H
#define SH_SYSTEM_H
#pragma once
#include "../SHECSMacros.h"
namespace SHADE
{
class SHSystemManager;
class SHSystem
{
private:
SystemID systemID;
protected:
/*!*************************************************************************
* \brief
@ -22,6 +29,9 @@ namespace SHADE
***************************************************************************/
SHSystem()= default;
public:
/*!*************************************************************************
* \brief
@ -35,13 +45,13 @@ namespace SHADE
***************************************************************************/
virtual void Init() = 0;
/*!*************************************************************************
* \brief
* Pure virtual Run function. Derived class must implement this
* \param dt
* Delta time
***************************************************************************/
virtual void Run(float dt) = 0;
///*!*************************************************************************
// * \brief
// * Pure virtual Run function. Derived class must implement this
// * \param dt
// * Delta time
//***************************************************************************/
//virtual void Run(float dt) = 0;
/*!*************************************************************************
* \brief
@ -49,7 +59,14 @@ namespace SHADE
***************************************************************************/
virtual void Exit() = 0;
};
}
friend class SHSystemManager;
#endif
inline SystemID GetSystemID(void) const noexcept { return systemID; }
inline SystemVersionID GetSystemVersion(void) const noexcept { return static_cast<SystemVersionID>(systemID >> sizeof(SystemVersionID) * CHAR_BIT); }
};
}

View File

@ -1,57 +0,0 @@
/*********************************************************************
* \file SHSystemManager.cpp
* \author Daniel Chua Yee Chen
* \brief Implementation for the SHSystemManager class.
* SHSystemManager is the interface class where users of the engine create
* the systems that gives the components their functionality. This also
* ensures that the Init and Exit functions are ran at the appropriate time
*
* \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 "SHSystemManager.h"
#include <iostream>
namespace SHADE
{
SHSystemManager::SystemContainer SHSystemManager::systemContainer;
SHSystem* SHSystemManager::GetSystem(std::string name)
{
if (systemContainer.find(name) == systemContainer.end())
{
assert("Get System Error: No system with such name exist.");
return nullptr;
}
return systemContainer.find(name)->second.get();
}
void SHSystemManager::Init() noexcept
{
for (auto& system : systemContainer)
{
system.second->Init();
#ifdef _DEBUG
std::cout << system.first << " Init" << std::endl;
#endif
}
}
void SHSystemManager::Exit() noexcept
{
for (auto& system : systemContainer)
{
system.second->Exit();
//delete system.second;
}
systemContainer.clear();
}
}

View File

@ -0,0 +1,23 @@
#include "SHpch.h"
#include "SHSystemRoutine.h"
namespace SHADE
{
SHSystem* SHSystemRoutine::GetSystem() const noexcept
{
return system;
}
std::string const SHSystemRoutine::GetName()const noexcept
{
return name;
}
SHRoutineStats const& SHSystemRoutine::GetStats()const noexcept
{
return stats;
}
}

View File

@ -0,0 +1,53 @@
#pragma once
#include "../SHECSMacros.h"
#include "SHRoutineStats.h"
#include "SHSystem.h"
#include <string>
namespace SHADE
{
class SHSystemManager;
class SHSystemRoutine
{
friend class SHSystemManager;
protected:
SHSystemRoutine(std::string routineName = "Default Routine Name", bool editorPause = false)
:system(nullptr), name(routineName), stats(routineName),IsRunInEditorPause(editorPause){};
SHSystem* system;
std::string name;
SHRoutineStats stats;
//Whether or not this routine should run when the editor is still in pause
bool IsRunInEditorPause;
public:
~SHSystemRoutine() = default;
SHSystem* GetSystem()const noexcept;
std::string const GetName() const noexcept;
SHRoutineStats const& GetStats()const noexcept;
virtual void Execute(double dt) noexcept {};
};
}

View File

@ -0,0 +1,181 @@
#include "SHpch.h"
#include "SHECSUnitTest.h"
#include "../Managers/SHComponentManager.h"
#include "../Managers/SHEntityManager.h"
#include "../Managers/SHSystemManager.h"
#include "SHTestComponents.h"
#include "SHTestSystems.h"
#include "Tools/SHLogger.h"
namespace SHADE
{
void SHECSUnitTest::TestAll(void) noexcept
{
TestBasicEntityCreate();
TestEntityCreateTemplate();
TestEntityDestroy();
TestSystemRoutine();
}
void SHECSUnitTest::TestBasicEntityCreate(void) noexcept
{
SHComponentManager::CreateComponentSparseSet<SHComponent_A>();
SHComponentManager::CreateComponentSparseSet<SHComponent_B>();
SHComponentManager::CreateComponentSparseSet<SHComponent_C>();
SHLOG_INFO("Test for add and remove component")
EntityID id1 = SHEntityManager::CreateEntity();
EntityID id2 = SHEntityManager::CreateEntity();
EntityID id3 = SHEntityManager::CreateEntity();
SHComponentManager::AddComponent<SHComponent_A>(id1);
}
void SHECSUnitTest::TestEntityCreateTemplate(void) noexcept
{
std::cout << "\nTest2" << std::endl;
//Test entity Creation.
SHComponentManager::CreateComponentSparseSet<SHComponent_A>();
SHComponentManager::CreateComponentSparseSet<SHComponent_B>();
SHComponentManager::CreateComponentSparseSet<SHComponent_C>();
for (size_t i = 0; i < 10000; ++i)
{
switch (i % 3)
{
case 0:
{
SHEntityManager::CreateEntity<SHComponent_A, SHComponent_B>();
}break;
case 1:
{
SHEntityManager::CreateEntity<SHComponent_A, SHComponent_C>();
}break;
case 2:
{
SHEntityManager::CreateEntity<SHComponent_A>();
}break;
default:
break;
}
}
auto& denseA = SHComponentManager::GetDense<SHComponent_A>();
auto& denseB = SHComponentManager::GetDense<SHComponent_B>();
auto& denseC = SHComponentManager::GetDense<SHComponent_C>();
std::cout << "Test Entity Creation" << std::endl;
std::cout << "dense A size: " << denseA.size() << ((denseA.size() == 10000) ? " Success" : " Failure") << std::endl;
std::cout << "dense B size: " << denseB.size() << ((denseB.size() == 3334) ? " Success" : " Failure") << std::endl;
std::cout << "dense C size: " << denseC.size() << ((denseC.size() == 3333) ? " Success" : " Failure") << std::endl;
std::cout << "Number of entities: " << SHEntityManager::GetEntityCount() << (SHEntityManager::GetEntityCount() == 10000 ? " Success" : " Failure") << std::endl;
SHEntityManager::DestroyAllEntity();
std::cout << std::endl << "Test Destroy All Entity" << std::endl;
std::cout << "dense A size: " << denseA.size() << ((denseA.size() == 0) ? " Success" : " Failure") << std::endl;
std::cout << "dense B size: " << denseB.size() << ((denseB.size() == 0) ? " Success" : " Failure") << std::endl;
std::cout << "dense C size: " << denseC.size() << ((denseC.size() == 0) ? " Success" : " Failure") << std::endl;
std::cout << "Number of entities: " << SHEntityManager::GetEntityCount() << (SHEntityManager::GetEntityCount() == 0 ? " Success" : " Failure") << std::endl;
}
void SHECSUnitTest::TestEntityDestroy(void) noexcept
{
std::cout << "\nTest3" << std::endl;
SHComponentManager::CreateComponentSparseSet<SHComponent_A>();
SHComponentManager::CreateComponentSparseSet<SHComponent_B>();
SHComponentManager::CreateComponentSparseSet<SHComponent_C>();
for (size_t i = 0; i < 10000; ++i)
{
switch (i % 3)
{
case 0:
{
SHEntityManager::CreateEntity<SHComponent_A, SHComponent_B>();
}break;
case 1:
{
SHEntityManager::CreateEntity<SHComponent_A, SHComponent_C>();
}break;
case 2:
{
SHEntityManager::CreateEntity<SHComponent_A>();
}break;
default:
break;
}
}
SHEntityManager::DestroyEntity(5000);
SHEntityManager::DestroyEntity(5001);
auto& denseA = SHComponentManager::GetDense<SHComponent_A>();
auto& denseB = SHComponentManager::GetDense<SHComponent_B>();
auto& denseC = SHComponentManager::GetDense<SHComponent_C>();
std::cout << "Test Entity Deletion" << std::endl;
std::cout << "dense A size: " << denseA.size() << ((denseA.size() == 9998) ? " Success" : " Failure") << std::endl;
std::cout << "dense B size: " << denseB.size() << ((denseB.size() == 3333) ? " Success" : " Failure") << std::endl;
std::cout << "dense C size: " << denseC.size() << ((denseC.size() == 3333) ? " Success" : " Failure") << std::endl;
std::cout << "Number of entities: " << SHEntityManager::GetEntityCount() << (SHEntityManager::GetEntityCount() == 9998 ? " Success" : " Failure") << std::endl;
std::cout << std::endl << "Test Entity Recreation" << std::endl;
EntityID id = SHEntityManager::CreateEntity<SHComponent_C>();
std::cout << "dense A size: " << denseA.size() << ((denseA.size() == 9998) ? " Success" : " Failure") << std::endl;
std::cout << "dense B size: " << denseB.size() << ((denseB.size() == 3333) ? " Success" : " Failure") << std::endl;
std::cout << "dense C size: " << denseC.size() << ((denseC.size() == 3334) ? " Success" : " Failure") << std::endl;
std::cout << "Entity ID: " << id << " EntityIndex: " << EntityHandleGenerator::GetIndex(id) << (EntityHandleGenerator::GetIndex(id) == 5001 ? " Success" : " Failure") << std::endl;
std::cout << "Number of entities: " << SHEntityManager::GetEntityCount() << (SHEntityManager::GetEntityCount() == 9999 ? " Success" : " Failure") << std::endl;
SHEntityManager::DestroyAllEntity();
std::cout << std::endl << "Check Destroy All Entity" << std::endl;
std::cout << "dense A size: " << denseA.size() << ((denseA.size() == 0) ? " Success" : " Failure") << std::endl;
std::cout << "dense B size: " << denseB.size() << ((denseB.size() == 0) ? " Success" : " Failure") << std::endl;
std::cout << "dense C size: " << denseC.size() << ((denseC.size() == 0) ? " Success" : " Failure") << std::endl;
std::cout << "Number of entities: " << SHEntityManager::GetEntityCount() << (SHEntityManager::GetEntityCount() == 0 ? " Success" : " Failure") << std::endl;
}
void SHECSUnitTest::TestSystemRoutine(void) noexcept
{
SHSystemManager::CreateSystem<SHTestSystem>();
SHSystemManager::CreateSystem<SHTestSystem>();
SHSystemManager::RegisterRoutine<SHTestSystem, SHTestSystem::SHTestRoutine>(1);
SHSystemManager::RunRoutines(false, 1.0 / 120.0);
SHSystemManager::Exit();
}
}

View File

@ -0,0 +1,22 @@
#pragma once
namespace SHADE
{
class SHECSUnitTest
{
public:
SHECSUnitTest() = delete;
~SHECSUnitTest() = delete;
static void TestBasicEntityCreate(void) noexcept;
static void TestEntityCreateTemplate(void) noexcept;
static void TestEntityDestroy(void) noexcept;
static void TestSystemRoutine(void) noexcept;
static void TestAll(void) noexcept;
};
}

View File

@ -0,0 +1,30 @@
#pragma once
#include "../Components/SHComponent.h"
namespace SHADE
{
class SHComponent_A :public SHComponent
{
public:
int value{};
};
class SHComponent_B :public SHComponent
{
public:
float x{};
float y{};
float z{};
};
class SHComponent_C :public SHComponent
{
public:
std::string value{};
};
}

View File

@ -0,0 +1,40 @@
#pragma once
#include <string>
#include "../System/SHSystem.h"
#include "../System/SHSystemRoutine.h"
namespace SHADE
{
class SHTestSystem : public SHSystem
{
public:
SHTestSystem() {};
~SHTestSystem() {};
std::string test{ "Test system" };
void Init() {};
void Exit() {};
class SHTestRoutine : public SHSystemRoutine
{
public:
SHTestRoutine()
:SHSystemRoutine("Test System Routine", false) {}
virtual void Execute(double dt) noexcept
{
std::cout << GetName() << " System Version: " << GetSystem()->GetSystemVersion() << std::endl;
}
};
};
}

View File

@ -0,0 +1,32 @@
/******************************************************************************
* \file SHEvent.h
* \author Loh Xiao Qi
* \brief Event class declaration
*
* \copyright Copyright (c) 2022 Digipen Institute of Technology. Reproduction
* or disclosure of this file or its contents without the prior written consent
* of Digipen Institute of Technology is prohibited.
******************************************************************************/
#pragma once
#include "SHEventDefines.h"
namespace SHADE
{
struct SHEvent
{
SHEventIdentifier type;
SHEventHandle handle;
};
template<typename T>
struct SHEventSpec : SHEvent
{
SHEventSpec(SHEventIdentifier t, SHEventHandle e, T* dp)
:SHEvent{ t, e }, data{ dp } {}
std::shared_ptr<const T> data;
};
using SHEventPtr = std::shared_ptr<SHEvent>;
}

View File

@ -0,0 +1,10 @@
#pragma once
#include "SHpch.h"
typedef uint32_t SHEventIdentifier;
typedef uint32_t SHEventHandle;
//Add your event identifiers here:
constexpr SHEventIdentifier SH_EXAMPLE_EVENT{0};
constexpr SHEventIdentifier SH_ENTITY_DESTROYED_EVENT{ 1 };
constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT{ 2 };

View File

@ -0,0 +1,101 @@
/******************************************************************************
* \file SHEventManager.cpp
* \author Loh Xiao Qi
* \brief Function Implmentations for SHEventManager
*
* \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 "SHEventManager.h"
namespace SHADE
{
std::unordered_map<SHEventIdentifier, ResponseVec> SHEventManager::packageReceiverRegistry;
SHEventHandle SHEventManager::handleCounter{ 0 };
/****************************************************************************
* \param ListenerConstPtr - Const pointer to listener that sent event.
* \param EventType - Templated type for every type of event
* \brief Receives event from the listeners.
****************************************************************************/
void SHEventManager::CatchEvent(SHEventPtr event)
{
// Do something with the event
Broadcast(event);
}
/****************************************************************************
* \param ResponseFunction - function pointer from receiver to be passed
* into event manager to be called when events are broadcasted.
* \param SHEventIdentifier - package type that corresponding subscriber is
* subscribing to.
* \brief Links a function pointer from a subscriber to a particular
* package type
****************************************************************************/
void SHEventManager::SubscribeTo(SHEventIdentifier pkgType, ReceiverPtr receiver)
{
RegisterReceiverToType(pkgType, receiver);
}
template<typename T>
void SHEventManager::BroadcastEvent(T data, SHEventIdentifier eventType)
{
std::shared_ptr<const T> data = std::make_shared<T>(data);
CatchEvent(
reinterpret_cast<SHEventPtr>
(
std::make_shared<SHEventSpec<T>>(eventType, handleCounter++, data)
)
);
}
/****************************************************************************
* \param ReceiverPtr - Pointer to receiver
* \param ListenerConstPtr - Const pointer to listener that receiver is
* subscribing to.
* \brief Registers receiver as a subscriber to listener in the registry.
****************************************************************************/
void SHEventManager::RegisterReceiverToType(
SHEventIdentifier pkgType, ReceiverPtr receiver)
{
if (packageReceiverRegistry.contains(pkgType))
{
packageReceiverRegistry[pkgType].emplace_back(receiver);
}
else
{
packageReceiverRegistry.emplace(pkgType, std::vector{ receiver });
}
}
/****************************************************************************
* \param ListenerConstPtr - Const pointer to listener that sent event.
* \param EventType - Event data
* \brief Broadcast event to all receivers that are subscribed to this
* listener.
****************************************************************************/
void SHEventManager::Broadcast(SHEventPtr event)
{
ResponseVec& receivers{ packageReceiverRegistry[event->type] };
for (auto& receiver : receivers)
{
receiver->Receive(event);
}
//auto& funcs{ ackageReceiverRegistry[event.GetType()] };
//for (auto func : funcs)
//{
// func(event.GetData());
//}
}
}

View File

@ -0,0 +1,124 @@
/******************************************************************************
* \file SHEventManager.h
* \author Loh Xiao Qi
* \brief Class declaration for event manager.
*
* \copyright Copyright (c) 2022 Digipen Institute of Technology. Reproduction
* or disclosure of this file or its contents without the prior written consent
* of Digipen Institute of Technology is prohibited.
******************************************************************************/
#pragma once
#include "SHEvent.h"
#include "SHEventReceiver.h"
#include <unordered_map>
#include <functional>
/******************************************************************************
INSTRUCTIONS FOR USE:
On broadcaster side:
1. Create a struct/class to contain the data that you would need to send
in the event.
2. Create unique event identifier in SHEventDefines.h, follow the example
provided.
3. When ready to send the event, call
SHEventManager::BroadcastEvent<ExampleClass>(exampleClass, EVENT_IDENTIFIER);
NOTE: If your custom struct to contain data requires a deep copy, please
overload the assignment operator accordingly. It is fine to send
a single object of a basic type such as int/float.
Headers required: SHEventManager.h
On Receiver side:
1. Create a function with the signature:
SHEventHandle FunctionName(SHEventPtr);
2. In the init function of the class, copy the below in and replace the
necessary:
std::shared_ptr<SHEventReceiverSpec<ReceiverClass>> thisReceiver{
std::make_shared<SHEventReceiverSpec<ReceiverClass>>(this, &ReceiverClass::ReceiveFunction)
};
ReceiverPtr receiver = std::dynamic_pointer_cast<SHEventReceiver>(thisReceiver);
SHEventManager::SubscribeTo(EVENT_IDENTIFIER, receiver);
ReceiverClass is the class that the receiver is in. E.g., SHPhysicsSystem
3. Note: The EventIdentifier should match all that is defined in
SHEventDefines.h so check there. When the receiver catches the event, it
needs to know the struct that the broadcaster is using to cast the event
ptr as such:
reinterpret_cast<std::shared_ptr<SHEventSpec<CustomClass>>>(event)
4. Inside the new ptr should be a shared pointer of const CustomClass type.
Headers required: SHEventManager.h, SHEventReceiver.h
If you have any questions/suggestions for improvement lmk.
******************************************************************************/
namespace SHADE
{
//using ResponseFunction = std::function<SHEventHandle(SHEventPtr)>;
using ReceiverPtr = std::shared_ptr<SHEventReceiver>;
using ResponseVec = std::vector<ReceiverPtr>;
using EventManagerListener = std::function<void(SHEvent)>;
class SHEventManager
{
public:
/****************************************************************************
* \param ListenerConstPtr - Const pointer to listener that sent event.
* \param EventType - Templated type for every type of event
* \brief Receives event from the listeners.
****************************************************************************/
static void CatchEvent(SHEventPtr);
/****************************************************************************
* \param ResponseFunction - function pointer from receiver to be passed
* into event manager to be called when events are broadcasted.
* \param SHPackageType - package type that corresponding subscriber is
* subscribing to.
* \brief Links a function pointer from a subscriber to a particular
* package type
****************************************************************************/
static void SubscribeTo(SHEventIdentifier, ReceiverPtr);
template<typename T>
static void BroadcastEvent(T data, SHEventIdentifier eventType);
private:
// Registry for broadcasters and subscribers
static std::unordered_map<SHEventIdentifier, ResponseVec> packageReceiverRegistry;
static SHEventHandle handleCounter;
/****************************************************************************
* \param ListenerConstPtr - Const pointer to listener that sent event.
* \param EventType - Event data
* \brief Broadcast event to all receivers that are subscribed to this
* listener.
****************************************************************************/
static void Broadcast(SHEventPtr event);
/****************************************************************************
* \param ReceiverPtr - Pointer to receiver
* \param ListenerConstPtr - Const pointer to listener that receiver is
* subscribing to.
* \brief Registers receiver as a subscriber to listener in the registry.
****************************************************************************/
static void RegisterReceiverToType(SHEventIdentifier, ReceiverPtr);
};
}

View File

@ -0,0 +1,33 @@
#pragma once
#include "SHEvent.h"
namespace SHADE
{
class SHEventReceiver
{
private:
public:
virtual void Receive(SHEventPtr) = 0;
};
template<typename T>
class SHEventReceiverSpec : public SHEventReceiver
{
private:
T* object;
SHEventHandle(T::*callback)(SHEventPtr);
public:
SHEventReceiverSpec(T* obj, void(T::* cb)(SHEventPtr))
:SHEventReceiver(), object{ obj }, callback{ cb }
{
}
void Receive(SHEventPtr evt) override
{
(object->*callback)(evt);
}
};
}

View File

@ -0,0 +1,134 @@
/*********************************************************************
* \file SHFramerateController.cpp
* \author Ryan Wang Nian Jing
* \brief Definition for functions of the framerate controller
* Handles changing of scenes and manages loop (timestep, etc.)
*
* \copyright Copyright (c) 2022 DigiPen Institute of Technology. Reproduction
or disclosure of this file or its contents without the prior written
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#include <chrono>
#include <cassert>
#include <SHpch.h>
#include "SHFramerateController.h"
#include "../Tools/SHLogger.h"
namespace SHADE
{
//Init statics
double SHFramerateController::fixedTimestep = 0.01;
SHScene* SHFramerateController::previousScene = nullptr;
SHScene* SHFramerateController::currentScene = nullptr;
SHScene* SHFramerateController::nextScene = nullptr;
bool SHFramerateController::toRestart = false;
bool SHFramerateController::toQuit = false;
//Scene manager loop
void SHFramerateController::Run(SHScene* firstScene)
{
if (firstScene == nullptr)
{
SHLOG_ERROR("Do not pass a nullptr as the firstScene");
return;
}
//Set quit and restart flags to false
toQuit = false;
toRestart = false;
//Set the first scene to run
previousScene = firstScene;
currentScene = firstScene;
nextScene = firstScene;
while (!toQuit)
{
if (toRestart)
{
//Restart current scene
currentScene = previousScene;
nextScene = previousScene;
toRestart = false;
}
else
{
//Move to a new scene
currentScene->Load();
}
//Call init function of current scene
currentScene->Init();
//Have an initial value
//This frame time will fluctuate
//SHOULD be larger than the fixed timestep
//TODO this might need to be changed
double variableLastFrameTime = fixedTimestep;
//Time accumulator for meshing between fixed and variable timesteps
double accumulator = 0.0;
//Start state loop
while (currentScene == nextScene && !toQuit && !toRestart)
{
//Use of new STL timing functions
//https://en.cppreference.com/w/cpp/chrono
std::chrono::duration<double> deltaTime;
auto startTime = std::chrono::high_resolution_clock::now();
//Whittle down the accumulator by continuously simulating
for (; accumulator > fixedTimestep; accumulator -= fixedTimestep)
{
MSG msg;
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//TODO change to double
currentScene->Update((float)fixedTimestep);
}
//Interpolation
//Manage the alpha value well
//https://randomascii.wordpress.com/2012/02/13/dont-store-that-in-a-float/
//Key points:
//1) Any time you add or subtract floats of widely varying
// magnitudes, you need to watch for loss of precision
//2) Sometimes using double instead of float is the correct
// solution, but often a more stable algorithm is more important
//3) calcT() should probably use double (to give sufficient
// precision after many hours of gameplay)
//TODO awaiting approval to use this
//double alpha = accumulator / fixedTimestep;
//assert alpha does not go out of range
currentScene->Render();
auto endTime = std::chrono::high_resolution_clock::now();
deltaTime = endTime - startTime;
variableLastFrameTime = deltaTime.count();
//Increase accumulator
accumulator += variableLastFrameTime;
}
//Free once out of scene loop
currentScene->Free();
//Check if not to restart state
//If so, unload
if (!toRestart) currentScene->Unload();
//Shift forward scenes
previousScene = currentScene;
currentScene = nextScene;
}
}
}

View File

@ -0,0 +1,62 @@
/*********************************************************************
* \file SHFramerateController.h
* \author Ryan Wang Nian Jing
* \brief Declaration for the framerate controller
* Handles changing of scenes and manages loop (timestep, etc.)
*
* \copyright Copyright (c) 2022 DigiPen Institute of Technology. Reproduction
or disclosure of this file or its contents without the prior written
consent of DigiPen Institute of Technology is prohibited.
*********************************************************************/
#ifndef SH_FRAMERATECONTROLLER_H
#define SH_FRAMERATECONTROLLER_H
#pragma once
#include "../Scene/SHScene.h"
namespace SHADE
{
class SHFramerateController
{
private:
//scene pointers
static SHScene* previousScene;
static SHScene* currentScene;
static SHScene* nextScene;
//Flags
//Whether the flag has been raised for the game to be quit
static bool toQuit;
//Whether the flag has been raised for the current scene to restart
static bool toRestart;
public:
//Fixed timestep value for physics. Default at 1/100th of a second.
//Should be lower than the variable refresh rate
static double fixedTimestep;
//Scene Manager Loop
//This loop is vital to the game because it runs for as long as the game
//runs. Before entering, initialise vital systems for game. After exiting,
//free these vital systems before finishing the main() function and
//terminating the game
//Parameter of firstScene is what scene the game should start with
static void Run(SHScene* firstScene);
//Set the flag to restart the current game scene
static inline void RestartScene() { toRestart = true; }
//Set the flag to halt running of the scene manager and quit the game
static inline void QuitGame() { toQuit = true; }
//Set the next scene to be excuted
//This will tell the scene manager to
//halt execution of the current scene and prepare
//execution of the next
static inline void SetNextScene(SHScene* const next) { nextScene = next; }
};
}
#endif

View File

@ -33,6 +33,8 @@ namespace SHADE
};
cmdBufferHdl->GetVkCommandBuffer().copyBuffer(stagingBuffer, vkBuffer, 1, &copyRegion);
}
// TODO: Need to destroy staging buffer. Obviously not here but after the command has finished executing.
}
vk::Buffer SHVkBuffer::GetVkBuffer(void) const noexcept

View File

@ -48,7 +48,6 @@ namespace SHADE
vk::BufferUsageFlags bufferUsageFlags;
//! Reference to the allocator
//VmaAllocator const& vmaAllocator;
std::reference_wrapper<VmaAllocator const> vmaAllocator;
/*-----------------------------------------------------------------------*/

View File

@ -76,7 +76,10 @@ namespace SHADE
// Check if command buffer is ready to record.
if (cmdBufferState != SH_CMD_BUFFER_STATE::INITIAL)
{
SHLOG_ERROR("Command buffer not in initial state, cannot begin recording. ");
SHLOG_ERROR("Command buffer not in initial state, cannot begin recording. Command buffer could be: \n"
"- corrupted and in invalid state\n"
"- in executable state\n"
"- in pending state\n");
return;
}
@ -182,7 +185,9 @@ namespace SHADE
// Check if render area is optimal
if (!IsRenderAreaOptimal(renderpassHdl, framebufferExtent, renderPassInfo.renderArea))
{
SHLOG_ERROR("Render area in renderpass begin info is not optimal. See Vulkan vkGetRenderAreaGranularity for details.");
}
// Begin the render pass
vkCommandBuffer.beginRenderPass (&renderPassInfo, vk::SubpassContents::eInline);
@ -202,6 +207,11 @@ namespace SHADE
vkCommandBuffer.endRenderPass();
}
void SHVkCommandBuffer::NextSubpass(void) noexcept
{
vkCommandBuffer.nextSubpass(commandBufferType == SH_CMD_BUFFER_TYPE::PRIMARY ? vk::SubpassContents::eInline : vk::SubpassContents::eSecondaryCommandBuffers);
}
/***************************************************************************/
/*!
@ -406,6 +416,41 @@ namespace SHADE
}
void SHVkCommandBuffer::PipelineBarrier (
vk::PipelineStageFlags srcStage,
vk::PipelineStageFlags dstStage,
vk::DependencyFlags deps,
std::vector<vk::MemoryBarrier> const& memoryBarriers,
std::vector<vk::BufferMemoryBarrier> const& bufferMemoryBarriers,
std::vector<vk::ImageMemoryBarrier> const& imageMemoryBarriers
) const noexcept
{
vkCommandBuffer.pipelineBarrier (
srcStage,
dstStage,
deps,
memoryBarriers,
bufferMemoryBarriers,
imageMemoryBarriers
);
}
bool SHVkCommandBuffer::IsReadyToSubmit(void) const noexcept
{
return cmdBufferState == SH_CMD_BUFFER_STATE::EXECUTABLE;
}
void SHVkCommandBuffer::HandlePostSubmit(void) noexcept
{
SetState(SH_CMD_BUFFER_STATE::PENDING);
}
//void SHVkCommandBuffer::PipelineBarrier(vk::PipelineStageFlags ) const noexcept
//{
// //vkCommandBuffer.pipelineBarrier()
//}
/***************************************************************************/
/*!
@ -463,9 +508,7 @@ namespace SHADE
{
vk::Extent2D granularity = parentPool->GetLogicalDevice()->GetVkLogicalDevice().getRenderAreaGranularity(renderpassHdl->GetVkRenderpass());
return (renderArea.offset.x % granularity.width == 0 && renderArea.offset.y % granularity.height == 0 &&
(renderArea.extent.width % granularity.width || renderArea.offset.x + renderArea.extent.width == framebufferExtent.width) &&
(renderArea.extent.height % granularity.height || renderArea.offset.y + renderArea.extent.height == framebufferExtent.height));
return (renderArea.offset.x % granularity.width == 0 && renderArea.offset.y % granularity.height == 0 && (renderArea.extent.width % granularity.width || renderArea.offset.x + renderArea.extent.width == framebufferExtent.width) && (renderArea.extent.height % granularity.height || renderArea.offset.y + renderArea.extent.height == framebufferExtent.height));
}
/***************************************************************************/
@ -529,6 +572,7 @@ namespace SHADE
, usageFlags{}
, commandBufferCount{ 0 }
, parentPool{commandPool}
, pushConstantData{}
{
vk::CommandBufferAllocateInfo allocateInfo{};

View File

@ -96,11 +96,12 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
void Reset(void);
// Begins and Ends
// Begins, Ends and Nexts
void BeginRecording (void) noexcept;
void EndRecording (void) noexcept;
void BeginRenderpass (Handle<SHVkRenderpass> const& renderpassHdl, Handle<SHVkFramebuffer> const& framebufferHdl, vk::Offset2D offset = {0, 0}, vk::Extent2D extent = {0, 0}) noexcept;
void EndRenderpass (void) noexcept;
void NextSubpass (void) noexcept;
// Dynamic State
void SetviewportScissor (float vpWidth, float vpHeight, uint32_t sWidth, uint32_t sHeight, float vpX = 0.0f, float vpY = 0.0f, int32_t sX = 0.0f, int32_t sY = 0.0f, float vpMinDepth = 0.0f, float vpMaxDepth = 1.0f) noexcept;
@ -114,6 +115,19 @@ namespace SHADE
void DrawArrays (uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept;
void DrawIndexed (uint32_t indexCount, uint32_t firstIndex, uint32_t vertexOffset) const noexcept;
// memory barriers
void PipelineBarrier (
vk::PipelineStageFlags srcStage,
vk::PipelineStageFlags dstStage,
vk::DependencyFlags deps,
std::vector<vk::MemoryBarrier> const& memoryBarriers,
std::vector<vk::BufferMemoryBarrier> const& bufferMemoryBarriers,
std::vector<vk::ImageMemoryBarrier> const& imageMemoryBarriers
) const noexcept;
bool IsReadyToSubmit (void) const noexcept;
void HandlePostSubmit (void) noexcept;
// Push Constant variable setting
template <typename T>
void SetPushConstantVariable(std::string variableName, T const& data) noexcept

View File

@ -150,20 +150,19 @@ namespace SHADE
logicalDeviceHdl->GetVkLogicalDevice().resetCommandPool(vkCommandPool, vk::CommandPoolResetFlagBits::eReleaseResources);
for (auto& primary : primaries)
{
if (primary->GetState() != SH_CMD_BUFFER_STATE::PENDING)
// #NoteToSelf: Since there is no way to set the state of a command buffer back to initial, we just hard set it to initial. Ditto for secondaries.
//if (primary->GetState() != SH_CMD_BUFFER_STATE::PENDING)
primary->SetState(SH_CMD_BUFFER_STATE::INITIAL);
else
SHLOG_ERROR("Primary command buffer in pending state, could not reset. ");
// From the spec: Any primary command buffer allocated from another VkCommandPool that is in the recording or
// executable state and has a secondary command buffer allocated from commandPool recorded into it,
// becomes invalid. TODO: Might want to check and throw exception for these conditions after making sure this actually happens using validation layers.
}
for (auto& secondary : secondaries)
{
if (secondary->GetState() != SH_CMD_BUFFER_STATE::PENDING)
//if (secondary->GetState() != SH_CMD_BUFFER_STATE::PENDING)
secondary->SetState(SH_CMD_BUFFER_STATE::INITIAL);
else
SHLOG_ERROR("Secondary command buffer in pending state, could not reset. ");
// TODO: Ditto from TODO in primary check
}

View File

@ -59,7 +59,7 @@ namespace SHADE
*/
/***************************************************************************/
void SHVulkanDebugUtil::ReportVkWarning(vk::Result vkResult, std::string_view message, std::source_location const& location /*= std::source_location::current()*/) noexcept
void SHVulkanDebugUtil::ReportVkWarning(vk::Result vkResult, std::string_view message) noexcept
{
//std::cout << location.file_name() << ": " << location.function_name() << "|" << location.line() << "|" <<
// location.column() << "|: Warning: " << SHDebugUtil::VkResultToString(vkResult) << " | " << message << std::endl;
@ -88,7 +88,7 @@ namespace SHADE
*/
/***************************************************************************/
void SHVulkanDebugUtil::ReportVkError(vk::Result vkResult, std::string_view message, std::source_location const& location /*= std::source_location::current()*/) noexcept
void SHVulkanDebugUtil::ReportVkError(vk::Result vkResult, std::string_view message) noexcept
{
std::string toLogger = "Vulkan Warning: " + std::string(SHVulkanDebugUtil::VkResultToString(vkResult)) + " | " + std::string(message);
@ -96,7 +96,7 @@ namespace SHADE
}
void SHVulkanDebugUtil::ReportVkSuccess(std::string_view message, std::source_location const& location /*= std::source_location::current()*/) noexcept
void SHVulkanDebugUtil::ReportVkSuccess(std::string_view message) noexcept
{
SHLOGV_INFO(message);
}

View File

@ -15,9 +15,9 @@ namespace SHADE
public:
static VKAPI_ATTR VkBool32 VKAPI_CALL GenericDebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageSeverityFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData);
static void ReportVkWarning(vk::Result vkResult, std::string_view message, std::source_location const& location = std::source_location::current()) noexcept;
static void ReportVkError(vk::Result vkResult, std::string_view message, std::source_location const& location = std::source_location::current()) noexcept;
static void ReportVkSuccess(std::string_view message, std::source_location const& location = std::source_location::current()) noexcept;
static void ReportVkWarning(vk::Result vkResult, std::string_view message) noexcept;
static void ReportVkError(vk::Result vkResult, std::string_view message) noexcept;
static void ReportVkSuccess(std::string_view message) noexcept;
};

View File

@ -0,0 +1,84 @@
#include "SHpch.h"
#include "SHDescriptorSetUpdater.h"
namespace SHADE
{
SHDescriptorWriteInfo::SHDescriptorWriteInfo(SHDescriptorWriteInfo&& rhs) noexcept
: descImageInfos{ std::move(rhs.descImageInfos) }
, descBufferInfos{ std::move(rhs.descBufferInfos) }
, descTexelBufferInfos{std::move (rhs.descTexelBufferInfos)}
{
}
SHDescriptorWriteInfo::SHDescriptorWriteInfo(void) noexcept
: descImageInfos{}
, descBufferInfos{}
, descTexelBufferInfos{}
{
}
/***************************************************************************/
/*!
\brief
Links the write infos to the vulkan write descriptor sets.
*/
/***************************************************************************/
void SHDescriptorSetUpdater::LinkInfoToWriteDescSet(void) noexcept
{
for (uint32_t i = 0; i < writeInfos.size(); ++i)
{
writeDescSets[i].pImageInfo = writeInfos[i].descImageInfos.data();
writeDescSets[i].pBufferInfo = writeInfos[i].descBufferInfos.data();
writeDescSets[i].pTexelBufferView = writeInfos[i].descTexelBufferInfos.data();
}
}
SHDescriptorWriteInfo& SHDescriptorWriteInfo::operator=(SHDescriptorWriteInfo&& rhs) noexcept
{
if (&rhs == this)
return *this;
descImageInfos = std::move(rhs.descImageInfos);
descBufferInfos = std::move(rhs.descBufferInfos);
descTexelBufferInfos = std::move(rhs.descTexelBufferInfos);
return *this;
}
SHDescriptorSetUpdater::SHDescriptorSetUpdater(SHDescriptorSetUpdater&& rhs) noexcept
: writeInfos{ std::move(rhs.writeInfos) }
, writeHashMap {std::move (rhs.writeHashMap)}
{
}
SHDescriptorSetUpdater::SHDescriptorSetUpdater(void) noexcept
: writeInfos{}
, writeHashMap{}
{
}
std::vector<vk::WriteDescriptorSet> const& SHDescriptorSetUpdater::GetWriteDescriptorSets(void) const noexcept
{
return writeDescSets;
}
SHDescriptorSetUpdater& SHDescriptorSetUpdater::operator=(SHDescriptorSetUpdater&& rhs) noexcept
{
if (&rhs == this)
return *this;
writeInfos = std::move (rhs.writeInfos);
writeHashMap = std::move (rhs.writeHashMap);
return *this;
}
}

View File

@ -0,0 +1,60 @@
#pragma once
#include <vector>
#include <unordered_map>
#include "Graphics/SHVulkanIncludes.h"
#include "Graphics/Shaders/SHShaderReflected.h"
namespace SHADE
{
// Vulkan doesn't use all of the information when looking at a writeDescriptorSet. It all
// depends on the descriptor type. This struct plays it safe by having members that would
// accommodate all types of descriptors.
class SHDescriptorWriteInfo
{
//! When we want to update a descriptor that is an image, it goes in here
std::vector<vk::DescriptorImageInfo> descImageInfos;
//! When we want to update a descriptor that is a buffer, it goes in here
std::vector<vk::DescriptorBufferInfo> descBufferInfos;
//! When we want to update a descriptor that is an texel buffer, it goes in here
std::vector<vk::BufferView> descTexelBufferInfos;
public:
SHDescriptorWriteInfo (void) noexcept;
SHDescriptorWriteInfo (SHDescriptorWriteInfo&& rhs) noexcept;
SHDescriptorWriteInfo& operator= (SHDescriptorWriteInfo&& rhs) noexcept;
friend class SHVkDescriptorSetGroup;
friend class SHDescriptorSetUpdater;
};
class SHDescriptorSetUpdater
{
private:
//! When we want to update descriptor sets, this will get passed into vkUpdateDescriptorSets.
//! Each write will correspond to a binding from a set. If the binding is a variable
//! sized binding, pImageInfo (e.g.) will point to an array of vk::DescriptorImageInfo.
std::vector<SHDescriptorWriteInfo> writeInfos;
//! When we want to update a write, we need to use this to identify the index of the write.
std::unordered_map<BindingAndSetHash, uint32_t> writeHashMap;
//! We keep this here because we want this to be immediately passable to vkUpdateDescriptorSets
std::vector<vk::WriteDescriptorSet> writeDescSets;
void LinkInfoToWriteDescSet(void) noexcept;
public:
SHDescriptorSetUpdater (void) noexcept;
SHDescriptorSetUpdater(SHDescriptorSetUpdater&& rhs) noexcept;
SHDescriptorSetUpdater& operator= (SHDescriptorSetUpdater&& rhs) noexcept;
public:
std::vector<vk::WriteDescriptorSet> const& GetWriteDescriptorSets (void) const noexcept;
friend class SHVkDescriptorSetGroup;
};
}

View File

@ -11,7 +11,7 @@ namespace SHADE
/* Constructor/Destructor */
/*---------------------------------------------------------------------------------*/
SHVkDescriptorPool::SHVkDescriptorPool(Handle<SHVkLogicalDevice> device, const Config& config)
: device { device }
: device{ device }
{
// Create the Pool
const vk::DescriptorPoolCreateInfo POOL_CREATE_INFO
@ -24,12 +24,32 @@ namespace SHADE
pool = device->GetVkLogicalDevice().createDescriptorPool(POOL_CREATE_INFO);
}
SHVkDescriptorPool::SHVkDescriptorPool(SHVkDescriptorPool&& rhs) noexcept
: device{ rhs.device }
, pool{ rhs.pool }
{
rhs.pool = VK_NULL_HANDLE;
}
SHVkDescriptorPool::~SHVkDescriptorPool() noexcept
{
if (pool)
device->GetVkLogicalDevice().destroyDescriptorPool(pool);
}
SHVkDescriptorPool& SHVkDescriptorPool::operator=(SHVkDescriptorPool&& rhs) noexcept
{
if (&rhs == this)
return *this;
device = rhs.device;
pool = rhs.pool;
rhs.pool = VK_NULL_HANDLE;
return *this;
}
std::vector<Handle<SHVkDescriptorSetGroup>> SHVkDescriptorPool::Allocate(const std::vector<Handle<SHVkDescriptorSetLayout>>& layouts, std::vector<uint32_t> const& variableDescCounts)
{
SHVkInstance::GetResourceManager().Create<SHVkDescriptorSetGroup>(device, GetHandle(), layouts, variableDescCounts);

View File

@ -65,7 +65,7 @@ namespace SHADE
/// </param>
SHVkDescriptorPool(Handle<SHVkLogicalDevice> device, const Config& config = {});
SHVkDescriptorPool(const SHVkDescriptorPool&) = delete;
SHVkDescriptorPool(SHVkDescriptorPool&& rhs) noexcept = default;
SHVkDescriptorPool(SHVkDescriptorPool&& rhs) noexcept;
/// <summary>
/// Destructor which will unload and deallocate all resources for this Pool.
/// </summary>
@ -75,7 +75,7 @@ namespace SHADE
/* Overloaded Operators */
/*-----------------------------------------------------------------------------*/
SHVkDescriptorPool& operator=(const SHVkDescriptorPool&) = delete;
SHVkDescriptorPool& operator=(SHVkDescriptorPool&& rhs) noexcept = default;
SHVkDescriptorPool& operator=(SHVkDescriptorPool&& rhs) noexcept;
/*-----------------------------------------------------------------------------*/
/* Getter Functions */

View File

@ -42,9 +42,11 @@ namespace SHADE
{
// Create the layout for each concurrent frame
std::vector<vk::DescriptorSetLayout> vkLayouts{ layouts.size() };
for (auto& layout : layouts)
//for (auto& layout : layouts)
for (uint32_t i = 0; i < layouts.size(); ++i)
{
vkLayouts.push_back(layout->GetVkHandle());
vkLayouts.push_back(layouts[i]->GetVkHandle());
}
// Check for variable descriptor count
@ -67,6 +69,66 @@ namespace SHADE
// allocate descriptor sets
descSets = device->GetVkLogicalDevice().allocateDescriptorSets(DESC_SET_LAYOUT_CREATE_INFO);
// Now we want to prepare the write descriptor sets for writing later.
for (uint32_t i = 0; i < layouts.size(); ++i)
{
auto const& bindings = layouts[i]->GetBindings();
for (auto& binding : bindings)
{
BindingAndSetHash writeHash = binding.BindPoint;
writeHash |= static_cast<uint64_t>(i) << 32;
// new write for the binding
updater.writeInfos.emplace_back();
updater.writeHashMap.try_emplace(writeHash, updater.writeInfos.size() - 1);
auto& writeInfo = updater.writeInfos.back();
updater.writeDescSets.emplace_back();
auto& writeDescSet = updater.writeDescSets.back();
// Initialize info for write
writeDescSet.descriptorType = binding.Type;
writeDescSet.dstArrayElement = 0;
writeDescSet.dstSet = descSets[i];
writeDescSet.dstBinding = binding.BindPoint;
// Descriptor count for the write descriptor set. Usually this is set to 1, but if binding is variable sized, set to info passed in
uint32_t descriptorCount = (binding.flags & vk::DescriptorBindingFlagBits::eVariableDescriptorCount) ? variableDescCounts[i] : 1;
writeDescSet.descriptorCount = descriptorCount;
switch (binding.Type)
{
//case vk::DescriptorType::eSampler:
//case vk::DescriptorType::eSampledImage:
case vk::DescriptorType::eCombinedImageSampler:
writeInfo.descImageInfos.resize(descriptorCount);
break;
//case vk::DescriptorType::eStorageImage:
// break;
case vk::DescriptorType::eUniformTexelBuffer:
case vk::DescriptorType::eStorageTexelBuffer:
case vk::DescriptorType::eUniformBuffer:
case vk::DescriptorType::eStorageBuffer:
writeInfo.descImageInfos.resize (descriptorCount);
break;
//case vk::DescriptorType::eUniformBufferDynamic:
// break;
//case vk::DescriptorType::eStorageBufferDynamic:
// break;
//case vk::DescriptorType::eInputAttachment:
// break;
//case vk::DescriptorType::eInlineUniformBlock:
// break;
default:
break;
}
}
}
// Link all the writeDescSet data for vkUpdateDescriptorSets to write to the linked descriptors
updater.LinkInfoToWriteDescSet();
}
/***************************************************************************/
@ -82,4 +144,45 @@ namespace SHADE
if (!descSets.empty())
device->GetVkLogicalDevice().freeDescriptorSets(descPool->GetVkHandle(), descSets);
}
/***************************************************************************/
/*!
\brief
Modifies a descriptor write info. #NoteToSelf: This function does NOT
need to modify the writeDescSets. Those are already linked before.
\param imageViewsAndSamplers
Image and view samplers
*/
/***************************************************************************/
void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::vector<std::pair<vk::ImageView, vk::Sampler>> const& imageViewsAndSamplers) noexcept
{
// Find the target writeDescSet
BindingAndSetHash writeHash = binding;
writeHash |= static_cast<uint64_t>(set) << 32;
auto& writeInfo = updater.writeInfos[updater.writeHashMap.at(writeHash)];
if (imageViewsAndSamplers.size() > writeInfo.descImageInfos.size())
{
SHLOG_ERROR("Attempting write too many descriptors into descriptor set. Failed to write to vk::WriteDescriptorSet. ");
}
for (uint32_t i = 0; i < imageViewsAndSamplers.size(); ++i)
{
// write sampler and image view
auto& ivs = imageViewsAndSamplers[i];
writeInfo.descImageInfos[i].imageView = ivs.first;
writeInfo.descImageInfos[i].sampler = ivs.second;
}
}
void SHVkDescriptorSetGroup::UpdateDescriptorSet(void) noexcept
{
device->UpdateDescriptorSets(updater.GetWriteDescriptorSets());
}
}

View File

@ -1,8 +1,10 @@
#pragma once
#pragma once
// Project Includes
#include "Graphics/SHVulkanIncludes.h"
#include "Resource/Handle.h"
#include "Graphics/Shaders/SHShaderReflected.h"
#include "SHDescriptorSetUpdater.h"
namespace SHADE
{
@ -13,6 +15,7 @@ namespace SHADE
class SHVkDescriptorPool;
class SHVkDescriptorSetLayout;
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
@ -50,6 +53,12 @@ namespace SHADE
SHVkDescriptorSetGroup& operator=(const SHVkDescriptorSetGroup&) = delete;
SHVkDescriptorSetGroup& operator=(SHVkDescriptorSetGroup&& rhs) noexcept = default;
/*-----------------------------------------------------------------------------*/
/* Descriptor set writing */
/*-----------------------------------------------------------------------------*/
void ModifyWriteDescImage (uint32_t set, uint32_t binding, std::vector<std::pair<vk::ImageView, vk::Sampler>> const& imageViewsAndSamplers) noexcept;
void UpdateDescriptorSet (void) noexcept;
/*-----------------------------------------------------------------------------*/
/* Getter Functions */
/*-----------------------------------------------------------------------------*/
@ -59,13 +68,22 @@ namespace SHADE
/// <returns>Handle to the Vulkan Descriptor Set.</returns>
[[nodiscard]]
inline const std::vector<vk::DescriptorSet>& GetVkHandle() { return descSets; }
private:
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
//! Device required to allocate descriptor sets
Handle<SHVkLogicalDevice> device;
//! Descriptor pool to allocate descriptor sets
Handle<SHVkDescriptorPool> descPool;
//! Descriptor sets
std::vector<vk::DescriptorSet> descSets;
//! for updating descriptor sets. We want to cache this so that we don't create the
//! write structs at runtime.
SHDescriptorSetUpdater updater;
};
}

View File

@ -85,6 +85,11 @@ namespace SHADE
device->GetVkLogicalDevice().destroyDescriptorSetLayout(setLayout);
}
std::vector<SHVkDescriptorSetLayout::Binding> const& SHVkDescriptorSetLayout::GetBindings(void) const noexcept
{
return layoutDesc;
}
SHVkDescriptorSetLayout& SHVkDescriptorSetLayout::operator=(SHVkDescriptorSetLayout&& rhs) noexcept
{
if (&rhs == this)

View File

@ -96,6 +96,7 @@ namespace SHADE
/// </summary>
/// <returns>Handle to the Vulkan Descriptor Set Layout handle.</returns>
inline const vk::DescriptorSetLayout& GetVkHandle() const { return setLayout; }
std::vector<Binding> const& GetBindings (void) const noexcept;
private:
/*-----------------------------------------------------------------------------*/

View File

@ -418,7 +418,12 @@ namespace SHADE
/***************************************************************************/
Handle<SHVkImage> SHVkLogicalDevice::CreateImage(uint32_t w, uint32_t h, uint8_t levels, vk::Format format, vk::ImageUsageFlags usage, vk::ImageCreateFlags create) const noexcept
{
return SHVkInstance::GetResourceManager().Create<SHVkImage>(std::cref(vmaAllocator), w, h, levels, format, usage, create);
return SHVkInstance::GetResourceManager().Create<SHVkImage>(&vmaAllocator, w, h, levels, format, usage, create);
}
Handle<SHVkImage> SHVkLogicalDevice::CreateImage(SHImageCreateParams const& imageDetails, unsigned char* data, uint32_t dataSize, std::span<uint32_t> inMipOffsets, VmaMemoryUsage memUsage, VmaAllocationCreateFlags allocFlags) noexcept
{
return SHVkInstance::GetResourceManager().Create<SHVkImage>(&vmaAllocator, imageDetails, data, dataSize, inMipOffsets, memUsage, allocFlags);
}
/***************************************************************************/
@ -509,6 +514,12 @@ namespace SHADE
}
Handle<SHVkDescriptorPool> SHVkLogicalDevice::CreateDescriptorPools(const SHVkDescriptorPool::Config& config /*= {}*/) noexcept
{
return SHVkInstance::GetResourceManager().Create <SHVkDescriptorPool>(GetHandle(), config);
}
/***************************************************************************/
/*!
@ -541,6 +552,22 @@ namespace SHADE
return SHVkInstance::GetResourceManager().Create<SHVkSemaphore>(GetHandle());
}
/***************************************************************************/
/*!
\brief
Writes to descriptor sets.
\param writeDescSets
Descriptor sets to write to.
*/
/***************************************************************************/
void SHVkLogicalDevice::UpdateDescriptorSets(std::vector<vk::WriteDescriptorSet> const& writeDescSets) noexcept
{
vkLogicalDevice.updateDescriptorSets(writeDescSets, {});
}
/***************************************************************************/
/*!

View File

@ -17,8 +17,9 @@
#include "Graphics/Pipeline/SHPipelineState.h"
#include "Graphics/Pipeline/SHPipelineType.h"
#include "vk_mem_alloc.h"
//#include "Graphics/DescriptorSets/SHDescriptorPool.h"
#include "Graphics/Descriptors/SHVkDescriptorPool.h"
#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
#include "Graphics/Images/SHVkImage.h"
namespace SHADE
{
@ -29,7 +30,6 @@ namespace SHADE
class SHVkSurface;
class SHVkSwapchain;
class SHVkBuffer;
class SHVkImage;
class SHVkFence;
class SHVkSemaphore;
class SHVkShaderModule;
@ -38,6 +38,7 @@ namespace SHADE
class SHVkFramebuffer;
class SHVkImageView;
class SHShaderBlockInterface;
class SHVkDescriptorSetGroup;
/***************************************************************************/
/*!
@ -146,6 +147,15 @@ namespace SHADE
vk::ImageCreateFlags create
) const noexcept;
Handle<SHVkImage> CreateImage (
SHImageCreateParams const& imageDetails,
unsigned char* data,
uint32_t dataSize,
std::span<uint32_t> inMipOffsets,
VmaMemoryUsage memUsage,
VmaAllocationCreateFlags allocFlags
) noexcept;
Handle<SHVkShaderModule> CreateShaderModule (
std::vector<uint32_t> const& binaryData,
std::string entryPoint,
@ -165,10 +175,13 @@ namespace SHADE
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 (std::vector<SHVkDescriptorSetLayout::Binding> const& bindings) noexcept;
Handle<SHVkDescriptorPool> CreateDescriptorPools (const SHVkDescriptorPool::Config& config = {}) noexcept;
Handle<SHVkPipelineLayout> CreatePipelineLayout (SHPipelineLayoutParams& pipelineLayoutParams) noexcept;
Handle<SHVkFence> CreateFence (void) const noexcept;
Handle<SHVkSemaphore> CreateSemaphore (void) const noexcept;
void UpdateDescriptorSets (std::vector<vk::WriteDescriptorSet> const& writeDescSets) noexcept;
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/

View File

@ -180,10 +180,10 @@ namespace SHADE
return;
}
SHLOG_ERROR("Successfully queried Physical Devices:");
SHLOG_TRACE("Successfully queried Physical Devices:");
for (auto const& device : physicalDevices)
{
SHLOG_ERROR(std::string_view (std::string("\t-") + GetDeviceTypeName(device.getProperties().deviceType) + device.getProperties().deviceName.operator std::string()));
SHLOG_TRACE(std::string_view (std::string("\t-") + GetDeviceTypeName(device.getProperties().deviceType) + device.getProperties().deviceName.operator std::string()));
}
}
}

View File

@ -5,12 +5,86 @@
#include "Tools/SHLogger.h"
#include "SHVkImageView.h"
#include "Graphics/Instance/SHVkInstance.h"
#include "Graphics/Buffers/SHVkBuffer.h"
namespace SHADE
{
/***************************************************************************/
/*!
\brief
If an image is a GPU only resource, we need to prep a staging buffer
to use for transferring data to the GPU. #NoteToSelf: I don't really
like this because its duplicate code. Should try to find a way to utilize
the logical device for this.
\param data
Data to transfer.
\param srcSize
Size in bytes of the data.
*/
/***************************************************************************/
void SHVkImage::PrepStagingBuffer(void* data, uint32_t srcSize) noexcept
{
// For creation of buffer
vk::BufferCreateInfo bufferInfo{};
// size stored same as GPU buffer
bufferInfo.size = srcSize;
// We just want to set the transfer bit
bufferInfo.usage = vk::BufferUsageFlagBits::eTransferSrc;
// sharing mode exclusive
bufferInfo.sharingMode = vk::SharingMode::eExclusive;
// Set to auto detect bits
VmaAllocationCreateInfo allocCreateInfo{};
allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
// We want to just write all at once. Using random access bit could make this slow
allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
// parameters of a vmaAllocation retrieved via vmaGetAllocationInfo
VmaAllocationInfo allocInfo;
// results of allocation
VmaAllocation stagingAlloc;
// To get around VMA's usage for C version of vulkan, create a temp first...,
VkBuffer tempBuffer{};
// Create the buffer...
vmaCreateBuffer(*vmaAllocator,
&bufferInfo.operator VkBufferCreateInfo & (), // TODO: Verify if this works (can use renderdoc to check buffer variables?)
&allocCreateInfo,
&tempBuffer, &stagingAlloc, &allocInfo);
// then assign it to the hpp version
stagingBuffer = tempBuffer;
// Just map, copy then unmap
void* stagingBufferMappedPtr = nullptr;
vmaMapMemory(*vmaAllocator, stagingAlloc, &stagingBufferMappedPtr);
if (stagingBufferMappedPtr)
std::memcpy(static_cast<uint8_t*>(stagingBufferMappedPtr), static_cast<uint8_t*>(data), srcSize);
const VkDeviceSize offsets = 0;
const VkDeviceSize sizes = srcSize;
vmaFlushAllocations(*vmaAllocator, 1, &stagingAlloc, &offsets, &sizes);
vmaUnmapMemory(*vmaAllocator, stagingAlloc);
}
SHVkImage::SHVkImage(
VmaAllocator const& vmaAllocator,
VmaAllocator const* allocator,
SHImageCreateParams const& imageDetails,
unsigned char* data,
uint32_t dataSize,
std::span<uint32_t> inMipOffsets,
VmaMemoryUsage memUsage,
VmaAllocationCreateFlags allocFlags
) noexcept
@ -23,12 +97,14 @@ namespace SHADE
, imageFormat{ imageDetails.imageFormat }
, usageFlags{}
, createFlags{}
, vmaAllocator{allocator}
, mipOffsets { inMipOffsets }
, boundToCoherent{false}
, randomAccessOptimized {false}
, mappedPtr{nullptr}
{
for (auto& bit : imageDetails.usageBits)
usageFlags |= bit;
for (auto& bit : imageDetails.createBits)
createFlags |= bit;
usageFlags = imageDetails.usageFlags;
createFlags = imageDetails.createFlags;
// If marked as 2D array compatible, image type MUST be 3D
if (createFlags & vk::ImageCreateFlagBits::e2DArrayCompatible)
@ -64,58 +140,52 @@ namespace SHADE
VmaAllocationInfo allocInfo{};
VkImage tempImage;
vmaCreateImage(vmaAllocator, &imageCreateInfo.operator VkImageCreateInfo&(), &allocCreateInfo, &tempImage, &alloc, &allocInfo);
auto result = vmaCreateImage(*vmaAllocator, &imageCreateInfo.operator VkImageCreateInfo&(), &allocCreateInfo, &tempImage, &alloc, &allocInfo);
if (result != VK_SUCCESS)
SHVulkanDebugUtil::ReportVkError(vk::Result(result), "Failed to create vulkan image. ");
else
SHVulkanDebugUtil::ReportVkSuccess("Successfully created image. ");
vkImage = tempImage;
//if (allocFlags & )
// At this point the image and device memory have been created.
if (allocFlags & VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)
randomAccessOptimized = true;
// TODO: This constructor can only create a GPU only resource for now. Due to time constraint, I was trying to create a ctor
// fast to finish up the ImGUI backend. In the future, there definitely needs to be more versatility to the constructor.
// Get the memory property flags
VkMemoryPropertyFlags memPropFlags;
vmaGetAllocationMemoryProperties(*vmaAllocator, alloc, &memPropFlags);
// mainly host visible. Can be cached (need to flush/invalidate), uncached (always coherent) and coherent (virtual).
//if (memPropFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
//{
// // If memory is marked to be coherent between CPU and GPU (no need flush/invalidate) (TODO: Verify if VMA_ALLOCATION_CREATE_MAPPED_BIT is used when VMA_MEMORY_USAGE_AUTO is set)
// // TODO: also verify that coherent bit = pointer is already mapped
// if (memPropFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
// {
// boundToCoherent = true;
// mappedPtr = allocInfo.pMappedData;
// }
// else
// mappedPtr = nullptr;
// if (data)
// MapWriteUnmap(data, srcSize, 0, 0);
//}
//else
//{
// We can prep first so that we can do transfers later via 1 cmd buffer recording
PrepStagingBuffer(data, dataSize);
//}
}
/***************************************************************************/
/*!
\brief
This is mainly used for images that aren't created internally because
they cannot be created in the traditional way (e.g. swapchain images).
\param inVkImage
Image already created outside
\param width
Width of the image
\param height
Height of the image
\param depth
Depth of the image
\param levels
Number of levels in the image
\param arrayLayers
if the image is an array, this value will be > 1.
\param imageFormat
Format of the image
*/
/***************************************************************************/
SHVkImage::SHVkImage(vk::Image inVkImage, vk::ImageType type, uint32_t inWidth, uint32_t inHeight, uint32_t inDepth, uint32_t arrayLayers, uint8_t levels, vk::Format format, vk::ImageUsageFlags flags) noexcept
: vkImage (inVkImage)
, width{ inWidth }
, height{ inHeight }
, depth{ inDepth }
, mipLevelCount{ levels }
, layerCount{ arrayLayers }
, imageFormat{ format }
, usageFlags{flags}
, alloc{}
, imageType{type}
, createFlags{}
{
}
SHVkImage::SHVkImage(VmaAllocator const& vmaAllocator, uint32_t w, uint32_t h, uint8_t levels, vk::Format format, vk::ImageUsageFlags usage, vk::ImageCreateFlags create) noexcept
SHVkImage::SHVkImage(VmaAllocator const* allocator, uint32_t w, uint32_t h, uint8_t levels, vk::Format format, vk::ImageUsageFlags usage, vk::ImageCreateFlags create) noexcept
: width {w}
, height{h}
, depth {1}
@ -124,6 +194,7 @@ namespace SHADE
, imageFormat{format}
, usageFlags{usage}
, createFlags {create}
, vmaAllocator {allocator}
{
vk::ImageCreateInfo imageCreateInfo{};
imageCreateInfo.imageType = vk::ImageType::e2D;
@ -149,7 +220,7 @@ namespace SHADE
VmaAllocationInfo allocInfo{};
VkImage tempImage;
auto result = vmaCreateImage(vmaAllocator, &imageCreateInfo.operator VkImageCreateInfo & (), &allocCreateInfo, &tempImage, &alloc, &allocInfo);
auto result = vmaCreateImage(*vmaAllocator, &imageCreateInfo.operator VkImageCreateInfo & (), &allocCreateInfo, &tempImage, &alloc, &allocInfo);
vkImage = tempImage;
if (result != VK_SUCCESS)
@ -163,6 +234,86 @@ namespace SHADE
return SHVkInstance::GetResourceManager().Create<SHVkImageView>(inLogicalDeviceHdl, parent, createParams);
}
void SHVkImage::TransferToDeviceResource(Handle<SHVkCommandBuffer> const& cmdBufferHdl) noexcept
{
// prepare copy regions
std::vector<vk::BufferImageCopy> copyRegions{mipOffsets.size()};
for (uint32_t i = 0; i < mipOffsets.size(); ++i)
{
copyRegions[i].bufferOffset = mipOffsets[i];
copyRegions[i].bufferRowLength = 0; // for padding
copyRegions[i].bufferImageHeight = 0; // for padding
copyRegions[i].imageSubresource.aspectMask = vk::ImageAspectFlagBits::eColor; // TODO: Need to change this to base it off image format.
copyRegions[i].imageSubresource.mipLevel = i;
copyRegions[i].imageSubresource.baseArrayLayer = 0; // TODO: Array textures not supported yet
copyRegions[i].imageSubresource.layerCount = layerCount;
copyRegions[i].imageOffset = vk::Offset3D{ 0,0,0 };
copyRegions[i].imageExtent = vk::Extent3D{ width >> i, height >> i, 1 };
}
}
/***************************************************************************/
/*!
\brief
Does not perform any image transitions but prepares a barrier for image
transitioning. Pipeline barrier will be issued outside this call after
this preparation function, or at least, it should be.
\param oldLayout
Old layout of the image.
\param newLayout
new layout of the image to transition to.
\param barrier
Barrier to modify to prepare the image for transitioning.
*/
/***************************************************************************/
void SHVkImage::PrepareImageTransition(vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::ImageMemoryBarrier& barrier) noexcept
{
barrier.oldLayout = oldLayout;
barrier.newLayout = newLayout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = vkImage;
barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; // TODO: Need to change this to base it off image format.
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = mipLevelCount;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = layerCount;
vk::PipelineStageFlagBits srcStage = vk::PipelineStageFlagBits::eTopOfPipe;
vk::PipelineStageFlagBits dstStage = vk::PipelineStageFlagBits::eTopOfPipe;
if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal)
{
srcStage = vk::PipelineStageFlagBits::eTopOfPipe;
dstStage = vk::PipelineStageFlagBits::eTransfer;
barrier.srcAccessMask = vk::AccessFlagBits::eNone;
barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite;
}
else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal)
{
srcStage = vk::PipelineStageFlagBits::eTransfer;
// TODO, what if we want to access in compute shader
dstStage = vk::PipelineStageFlagBits::eFragmentShader;
barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
}
else
{
SHLOG_ERROR("Image layouts are invalid. ");
}
}
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

@ -10,6 +10,7 @@ namespace SHADE
{
class SHVkLogicalDevice;
class SHVkImageView;
class SHVkCommandBuffer;
struct SHImageCreateParams
{
@ -35,10 +36,10 @@ namespace SHADE
vk::Format imageFormat;
//! Image usage bits
std::span<vk::ImageUsageFlagBits> usageBits;
vk::ImageUsageFlags usageFlags;
//! Image create flags
std::span<vk::ImageCreateFlagBits> createBits;
vk::ImageCreateFlags createFlags;
};
class SHVkImage
@ -47,6 +48,12 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
//! Pointer to the vma allocator. #NoteToSelf: Not super proud of this being a pointer.
//! The only reason why this is a pointer is because a reference_wrapper cannot be default constructed.
//! And the reason why we want a default constructor is because sometimes we don't want to create images
//! but merely link them from outside (swapchain images)
VmaAllocator const* vmaAllocator;
//! 1D, 2D or 3D
vk::ImageType imageType = vk::ImageType::e2D;
@ -80,22 +87,46 @@ namespace SHADE
//! allocation object containing details of an allocation
VmaAllocation alloc{};
//! Whether or not this image is HOST_VISIBLE and random access optimized
bool randomAccessOptimized;
//! Whether or not the memory the image is bound to is memory coherent (updates on CPU can be seen on GPU without flushing cache)
bool boundToCoherent;
//! Persistently mapped pointer if applicable (will be void if image is
//! not created with the correct flags). Note that this is only used for
//! persistent mapping. One time updates do not use this pointer.
void* mappedPtr;
//! Staging buffer for images purely in the GPU
vk::Buffer stagingBuffer;
//! Mipmap offsets for initializing the vk::BufferImageCopy during transfer to GPU resource
std::span<uint32_t> mipOffsets;
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void PrepStagingBuffer(void* data, uint32_t srcSize) noexcept;
public:
/*-----------------------------------------------------------------------*/
/* CTOR AND DTOR */
/*-----------------------------------------------------------------------*/
SHVkImage(void) noexcept = default;
// TODO: Might need to add flags to parameters
SHVkImage(
VmaAllocator const& vmaAllocator,
VmaAllocator const* allocator,
SHImageCreateParams const& imageDetails,
unsigned char* data,
uint32_t dataSize,
std::span<uint32_t> inMipOffsets,
VmaMemoryUsage memUsage,
VmaAllocationCreateFlags allocFlags
) noexcept;
SHVkImage(vk::Image inVkImage, vk::ImageType type, uint32_t inWidth, uint32_t inHeight, uint32_t inDepth, uint32_t arrayLayers, uint8_t levels, vk::Format format, vk::ImageUsageFlags flags) noexcept;
SHVkImage(VmaAllocator const& vmaAllocator, uint32_t w, uint32_t h, uint8_t levels, vk::Format format, vk::ImageUsageFlags usage, vk::ImageCreateFlags create) noexcept;
SHVkImage(VmaAllocator const* allocator, uint32_t w, uint32_t h, uint8_t levels, vk::Format format, vk::ImageUsageFlags usage, vk::ImageCreateFlags create) noexcept;
SHVkImage(SHVkImage&& rhs) noexcept = default;
SHVkImage& operator=(SHVkImage && rhs) noexcept = default;
@ -103,7 +134,9 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
Handle<SHVkImageView> CreateImageView(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, Handle<SHVkImage> const& parent, SHImageViewDetails const& createParams) const noexcept;
Handle<SHVkImageView> CreateImageView (Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, Handle<SHVkImage> const& parent, SHImageViewDetails const& createParams) const noexcept;
void TransferToDeviceResource (Handle<SHVkCommandBuffer> const& cmdBufferHdl) noexcept;
void PrepareImageTransition (vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::ImageMemoryBarrier& barrier) noexcept;
/*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */

View File

@ -0,0 +1,7 @@
#include "SHpch.h"
#include "SHVkSampler.h"
namespace SHADE
{
}

View File

@ -0,0 +1,27 @@
#pragma once
#include "Graphics/SHVulkanIncludes.h"
namespace SHADE
{
struct SHVkSamplerParams
{
vk::Filter minFilter;
vk::Filter maxFilter;
//vk::Filter maxFilter;
};
class SHVkSampler
{
private:
//! The vulkan sampler handler
vk::Sampler vkSampler;
public:
SHVkSampler () noexcept;
SHVkSampler (SHVkSampler&& rhs) noexcept;
SHVkSampler&& operator=(SHVkSampler&& rhs) noexcept;
};
}

View File

@ -22,14 +22,12 @@ of DigiPen Institute of Technology is prohibited.
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Constructor/Destructors */
/*---------------------------------------------------------------------------------*/
SHGraphicsSystem::SHGraphicsSystem(SHWindow& window)
void SHGraphicsSystem::Init(void)
{
// Save the SHWindow
this->window = &window;
// Set Up Instance
SHVkInstance::Init(true, true, true);
@ -39,10 +37,10 @@ namespace SHADE
device = SHVkInstance::CreateLogicalDevice({ SHQueueParams(SH_Q_FAM::GRAPHICS, SH_QUEUE_SELECT::DEDICATED), SHQueueParams(SH_Q_FAM::TRANSFER, SH_QUEUE_SELECT::DEDICATED) }, physicalDevice);
// Construct surface
surface = device->CreateSurface(window.GetHWND());
surface = device->CreateSurface(window->GetHWND());
// Construct Swapchain
auto windowDims = window.GetWindowSize();
auto windowDims = window->GetWindowSize();
swapchain = device->CreateSwapchain(surface, windowDims.first, windowDims.second, SHSwapchainParams
{
.surfaceImageFormats {vk::Format::eB8G8R8A8Unorm, vk::Format::eR8G8B8A8Unorm, vk::Format::eB8G8R8Unorm, vk::Format::eR8G8B8Unorm},
@ -51,13 +49,13 @@ namespace SHADE
.vsyncOn = false, // TODO: Set to true when shipping game
});
window.RegisterWindowSizeCallback([&]([[maybe_unused]] uint32_t width, [[maybe_unused]] uint32_t height)
window->RegisterWindowSizeCallback([&]([[maybe_unused]] uint32_t width, [[maybe_unused]] uint32_t height)
{
renderContext.SetIsResized(true);
});
// Create graphics queue
queue = device->GetQueue(SH_Q_FAM::GRAPHICS, 0);
graphicsQueue = device->GetQueue(SH_Q_FAM::GRAPHICS, 0);
// Create Render Context
@ -87,7 +85,7 @@ namespace SHADE
//commandBuffers[i] = commandPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); // works
}
descPool = device->CreateDescriptorPools();
@ -101,12 +99,12 @@ namespace SHADE
renderGraph.AddResource("Composite", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat);
renderGraph.AddResource("Downscale", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat);
renderGraph.AddResource("Present", SH_ATT_DESC_TYPE::COLOR_PRESENT, windowDims.first, windowDims.second);
auto node = renderGraph.AddNode("G-Buffer", { "Position", "Normals", "Composite" }, {}); // no predecessors
auto node = renderGraph.AddNode("G-Buffer", { "Composite", "Position", "Normals", "Present" }, {}); // no predecessors
// First subpass to write to G-Buffer
auto writeSubpass = node->AddSubpass("G-Buffer Write");
writeSubpass->AddColorOutput("Position");
writeSubpass->AddColorOutput("Normals");
writeSubpass->AddColorOutput("Present");
// Second subpass to read from G-Buffer
auto compositeSubpass = node->AddSubpass("G-Buffer Composite");
@ -114,11 +112,11 @@ namespace SHADE
compositeSubpass->AddInput("Normals");
compositeSubpass->AddInput("Position");
auto compositeNode = renderGraph.AddNode("Bloom", { "Composite", "Downscale", "Present"}, {"G-Buffer"});
auto bloomSubpass = compositeNode->AddSubpass("Downsample");
bloomSubpass->AddInput("Composite");
bloomSubpass->AddColorOutput("Downscale");
bloomSubpass->AddColorOutput("Present");
//auto compositeNode = renderGraph.AddNode("Bloom", { "Composite", "Downscale", "Present" }, { "G-Buffer" });
//auto bloomSubpass = compositeNode->AddSubpass("Downsample");
//bloomSubpass->AddInput("Composite");
//bloomSubpass->AddColorOutput("Downscale");
//bloomSubpass->AddColorOutput("Present");
renderGraph.Generate();
@ -127,11 +125,25 @@ namespace SHADE
/* RENDERGRAPH END TESTING */
/*-----------------------------------------------------------------------*/
}
SHGraphicsSystem::~SHGraphicsSystem()
void SHGraphicsSystem::Run(float dt) noexcept
{
auto const& frameData = renderContext.GetCurrentFrameData();
renderGraph.Execute(renderContext.GetCurrentFrame());
graphicsQueue->SubmitCommandBuffer({ renderGraph.GetCommandBuffer(renderContext.GetCurrentFrame()) },
{ frameData.semRenderFinishHdl },
{ frameData.semImgAvailableHdl },
vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests);
}
void SHGraphicsSystem::Exit(void)
{
//renderPass.Free();
renderContext.Destroy();
queue.Free();
graphicsQueue.Free();
swapchain.Free();
surface.Free();
device.Free();
@ -205,7 +217,7 @@ namespace SHADE
presentInfo.pImageIndices = &CURR_FRAME_IDX;
// #BackEndTest: queues an image for presentation
if (auto result = device->GetQueue(SH_Q_FAM::GRAPHICS, 0)->GetVkQueue().presentKHR(&presentInfo); result != vk::Result::eSuccess)
if (auto result = graphicsQueue->Present(swapchain, {currFrameData.semRenderFinishHdl}, CURR_FRAME_IDX); result != vk::Result::eSuccess)
{
// If swapchain is incompatible/outdated
if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR)
@ -235,4 +247,19 @@ namespace SHADE
void SHGraphicsSystem::RemoveSegment(Handle<SHScreenSegment> segment)
{
}
void SHGraphicsSystem::SetWindow(SHWindow* wind) noexcept
{
window = wind;
}
SHRenderGraph const& SHGraphicsSystem::GetRenderGraph(void) const noexcept
{
return renderGraph;
}
void SHGraphicsSystem::SHGraphicsSystemRoutine::Execute(double dt) noexcept
{
}
}

View File

@ -21,9 +21,14 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/SHVulkanIncludes.h"
#include "Graphics/MiddleEnd/PerFrame/SHRenderContext.h"
#include "Graphics/RenderGraph/SHRenderGraph.h"
#include "ECS_Base/System/SHSystem.h"
#include "ECS_Base/System/SHSystemRoutine.h"
#include "Graphics/Descriptors/SHVkDescriptorPool.h"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Forward Declarations */
/*---------------------------------------------------------------------------------*/
@ -61,8 +66,15 @@ namespace SHADE
portions of the screen.
*/
/***********************************************************************************/
class SHGraphicsSystem
class SH_API SHGraphicsSystem : public SHSystem
{
public:
class SH_API SHGraphicsSystemRoutine : public SHSystemRoutine
{
public:
virtual void Execute(double dt) noexcept override;
};
public:
/*-----------------------------------------------------------------------------*/
/* Constants */
@ -72,8 +84,15 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
/* Constructor/Destructors */
/*-----------------------------------------------------------------------------*/
SHGraphicsSystem(SHWindow& window);
~SHGraphicsSystem();
SHGraphicsSystem (void) = default;
~SHGraphicsSystem(void) noexcept = default;
/*-----------------------------------------------------------------------------*/
/* SHSystem overrides */
/*-----------------------------------------------------------------------------*/
virtual void Init(void) override;
void Run (float dt) noexcept;
virtual void Exit(void) override;
/*-----------------------------------------------------------------------------*/
/* Lifecycle Functions */
@ -93,12 +112,22 @@ namespace SHADE
Handle<SHScreenSegment> AddSegment(const VkViewport& viewport, Handle<SHVkImage> imageToUse);
void RemoveSegment(Handle<SHScreenSegment> segment);
/*-----------------------------------------------------------------------------*/
/* Setters */
/*-----------------------------------------------------------------------------*/
void SetWindow (SHWindow* wind) noexcept;
/*-----------------------------------------------------------------------------*/
/* Getters (Temporary) */
/*-----------------------------------------------------------------------------*/
Handle<SHVkLogicalDevice> GetDevice() const { return device; }
Handle<SHVkSwapchain> GetSwapchain() const { return swapchain; }
Handle<SHVkSurface> GetSurface() const { return surface; }
Handle<SHVkPhysicalDevice> GetPhysicalDevice() const {return physicalDevice;}
Handle<SHVkQueue> GetQueue() const { return graphicsQueue; }
Handle<SHVkDescriptorPool> GetDescriptorPool() const { return descPool; }
SHRenderGraph const& GetRenderGraph (void) const noexcept;
//Handle<SHVkRenderpass> GetRenderPass() const { return renderPass; }
@ -111,7 +140,8 @@ namespace SHADE
Handle<SHVkLogicalDevice> device;
Handle<SHVkSurface> surface;
Handle<SHVkSwapchain> swapchain;
Handle<SHVkQueue> queue;
Handle<SHVkQueue> graphicsQueue;
Handle<SHVkDescriptorPool> descPool;
//Handle<SHVkRenderpass> renderPass; // Potentially bring out?
std::vector<SHScreenSegment> screenSegments;
SHRenderContext renderContext;
@ -125,5 +155,6 @@ namespace SHADE
//std::vector<SHRenderer> renderers;
SHRenderGraph renderGraph;
friend SHGraphicsSystemRoutine;
};
}

View File

@ -3,6 +3,7 @@
#include <vector>
#include "SHPerFrameData.h"
#include "SH_API.h"
namespace SHADE
{
@ -16,7 +17,7 @@ namespace SHADE
//! render context in SHADE engine has is that it requires users to call these explicitly in the middle end. While there
//! is little reason the flow of the render context should deviate from its intended usage, we want to leave it up to
//! users to explicitly call functions from here so we don't risk losing opportunities for different usage.
class SHRenderContext
class SH_API SHRenderContext
{
private:
//! container of frame data. Note that the manager owns the data, but the frame data themselves do not own anything.

View File

@ -117,7 +117,7 @@ namespace SHADE
dirty = isDirty;
}
std::tuple<uint32_t, uint32_t, vk::Format> SHVertexInputState::GetInfoFromAttribFormat(SHAttribFormat attribFormat) const noexcept
std::tuple<SHVertexInputState::numAttribSlots, SHVertexInputState::bytesRequired, vk::Format> SHVertexInputState::GetInfoFromAttribFormat(SHAttribFormat attribFormat) const noexcept
{
switch (attribFormat)
{
@ -138,6 +138,9 @@ namespace SHADE
case SHAttribFormat::MAT_4D:
return std::make_tuple(4, 16, vk::Format::eR32G32B32A32Sfloat);
break;
case SHAttribFormat::UINT32_1D:
return std::make_tuple(1, 4, vk::Format::eR32Uint);
}
return std::make_tuple(0, 0, vk::Format::eR32Sfloat);
}

View File

@ -5,6 +5,7 @@
#include "Graphics/Synchronization/SHVkSemaphore.h"
#include "Graphics/Synchronization/SHVkFence.h"
#include "Graphics/Commands/SHVkCommandBuffer.h"
#include "Graphics/Swapchain/SHVkSwapchain.h"
namespace SHADE
@ -31,14 +32,10 @@ namespace SHADE
}
vk::Queue SHVkQueue::GetVkQueue(void) const noexcept
void SHVkQueue::SubmitCommandBuffer(std::initializer_list<Handle<SHVkCommandBuffer>> cmdBuffers, std::initializer_list<Handle<SHVkSemaphore>> signalSems /*= {}*/, std::initializer_list<Handle<SHVkSemaphore>> waitSems /*= {}*/, vk::PipelineStageFlags waitDstStageMask /*= {}*/, Handle<SHVkFence> const& optionalFence /*= {}*/) noexcept
{
return vkQueue;
}
void SHVkQueue::SubmitCommandBuffer(std::initializer_list<Handle<SHVkCommandBuffer>> cmdBuffers, std::initializer_list<Handle<SHVkSemaphore>> signalSems /*= {}*/, std::initializer_list<Handle<SHVkSemaphore>> waitSems /*= {}*/, vk::PipelineStageFlagBits waitDstStageMask /*= {}*/, Handle<SHVkFence> const& optionalFence /*= {}*/) noexcept
{
std::vector<vk::Semaphore> vkWaitSems{ waitSems.size() };
// prepare wait sems
std::array<vk::Semaphore, 5> vkWaitSems{ };
uint32_t i = 0;
for (auto& sem : waitSems)
{
@ -46,7 +43,8 @@ namespace SHADE
++i;
}
std::vector<vk::Semaphore> vkSignalSems{ signalSems.size() };
// prepare signal sems
std::array<vk::Semaphore, 5> vkSignalSems{ };
i = 0;
for (auto& sem : signalSems)
{
@ -54,33 +52,76 @@ namespace SHADE
++i;
}
std::vector<vk::CommandBuffer> vkCmdBuffers{ cmdBuffers.size() };
// prepare cmd buffers
std::array<vk::CommandBuffer, 5> vkCmdBuffers{ };
i = 0;
for (auto& cmdBuffer : cmdBuffers)
{
// Check if command buffer is in executable state
if (!cmdBuffer->IsReadyToSubmit())
{
SHLOG_ERROR("Command buffer is not in executable state. Cannot submit command buffer. ");
return;
}
vkCmdBuffers[i] = cmdBuffer->GetVkCommandBuffer();
++i;
}
vk::PipelineStageFlags mask = waitDstStageMask;
// Prepare submit info
vk::SubmitInfo submitInfo
{
.waitSemaphoreCount = static_cast<uint32_t>(vkWaitSems.size()),
.waitSemaphoreCount = static_cast<uint32_t>(waitSems.size()),
.pWaitSemaphores = vkWaitSems.data(),
.pWaitDstStageMask = &mask,
.commandBufferCount = static_cast<uint32_t>(vkCmdBuffers.size()),
.pWaitDstStageMask = &waitDstStageMask,
.commandBufferCount = static_cast<uint32_t>(cmdBuffers.size()),
.pCommandBuffers = vkCmdBuffers.data(),
.signalSemaphoreCount = static_cast<uint32_t>(vkSignalSems.size()),
.signalSemaphoreCount = static_cast<uint32_t>(signalSems.size()),
.pSignalSemaphores = vkSignalSems.data(),
};
// #BackEndTest: Submit the queue
// Submit the queue
if (auto result = vkQueue.submit(1, &submitInfo, (optionalFence) ? optionalFence->GetVkFence() : nullptr); result != vk::Result::eSuccess)
{
SHVulkanDebugUtil::ReportVkError(result, "Failed to submit command buffer. ");
}
else // if success
{
// Change all command buffers to pending state
for (Handle<SHVkCommandBuffer> cmdBuffer : cmdBuffers)
{
cmdBuffer->HandlePostSubmit();
}
}
}
vk::Result SHVkQueue::Present(Handle<SHVkSwapchain> const& swapchain, std::initializer_list<Handle<SHVkSemaphore>> waitSems, uint32_t frameIndex) noexcept
{
vk::PresentInfoKHR presentInfo{};
// prepare wait sems
std::array<vk::Semaphore, 5> vkWaitSems{ };
uint32_t i = 0;
for (auto& sem : waitSems)
{
vkWaitSems[i] = sem->GetVkSem();
++i;
}
// prepare presentation information
presentInfo.waitSemaphoreCount = static_cast<uint32_t>(waitSems.size());
presentInfo.pWaitSemaphores = vkWaitSems.data();
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = &swapchain->GetVkSwapchain();
presentInfo.pImageIndices = &frameIndex;
// Present swapchain image.
auto result = vkQueue.presentKHR(&presentInfo);
if (result != vk::Result::eSuccess)
{
SHLOGV_ERROR ("Failed to present swapchain image. ");
}
return result;
}
}

View File

@ -11,6 +11,7 @@ namespace SHADE
class SHVkCommandBuffer;
class SHVkFence;
class SHVkSemaphore;
class SHVkSwapchain;
enum class SH_QUEUE_FAMILY_ARRAY_INDEX : std::size_t
{
@ -45,9 +46,9 @@ namespace SHADE
public:
SHVkQueue(vk::Queue inVkQueue, SHQueueFamilyIndex parent, Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl) noexcept;
vk::Queue GetVkQueue(void) const noexcept;
void SubmitCommandBuffer(std::initializer_list<Handle<SHVkCommandBuffer>> cmdBuffers, std::initializer_list<Handle<SHVkSemaphore>> signalSems = {}, std::initializer_list<Handle<SHVkSemaphore>> waitSems = {}, vk::PipelineStageFlagBits waitDstStageMask = {}, Handle<SHVkFence> const& fence = {}) noexcept;
void SubmitCommandBuffer (std::initializer_list<Handle<SHVkCommandBuffer>> cmdBuffers, std::initializer_list<Handle<SHVkSemaphore>> signalSems = {}, std::initializer_list<Handle<SHVkSemaphore>> waitSems = {}, vk::PipelineStageFlags waitDstStageMask = {}, Handle<SHVkFence> const& fence = {}) noexcept;
vk::Result Present (Handle<SHVkSwapchain> const& swapchain, std::initializer_list<Handle<SHVkSemaphore>> waitSems, uint32_t frameIndex) noexcept;
};
}

View File

@ -209,9 +209,10 @@ namespace SHADE
*/
/***************************************************************************/
SHRenderGraphNode::SHSubpass::SHSubpass(std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources) noexcept
SHRenderGraphNode::SHSubpass::SHSubpass(Handle<SHRenderGraphNode> const& parent, std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources) noexcept
: resourceAttachmentMapping{ mapping }
, ptrToResources{ resources }
, parentNode{ parent }
{
}
@ -333,6 +334,38 @@ namespace SHADE
inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal });
}
void SHRenderGraphNode::SHSubpass::Execute(Handle<SHVkCommandBuffer>& commandBuffer) noexcept
{
// Draw all the batches
// Draw all the exterior draw calls
for (auto& drawCall : exteriorDrawCalls)
{
drawCall(commandBuffer);
}
}
void SHRenderGraphNode::SHSubpass::AddExteriorDrawCalls(std::function<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept
{
exteriorDrawCalls.push_back(newDrawCall);
}
/***************************************************************************/
/*!
\brief
Getter for parent renderpass.
\return
Returns the parent renderpass the subpass belongs to.
*/
/***************************************************************************/
Handle<SHRenderGraphNode> const& SHRenderGraphNode::SHSubpass::GetParentNode(void) const noexcept
{
return parentNode;
}
/***************************************************************************/
/*!
@ -426,10 +459,10 @@ namespace SHADE
// We set this to clear first. If later we find out that some predecessor is writing to the same attachment,
// we set the pred's storeOp to eStore and "this" loadOp to eLoad.
newDesc.loadOp = vk::AttachmentLoadOp::eClear;
newDesc.storeOp = vk::AttachmentStoreOp::eDontCare;
newDesc.storeOp = vk::AttachmentStoreOp::eStore;
newDesc.stencilLoadOp = vk::AttachmentLoadOp::eClear;
newDesc.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
newDesc.stencilStoreOp = vk::AttachmentStoreOp::eStore;
newDesc.format = attResources[i]->resourceFormat;
@ -512,11 +545,44 @@ namespace SHADE
}
// Add subpass to container and create mapping for it
subpasses.emplace_back(resourceManager.Create<SHSubpass>(&resourceAttachmentMapping, ptrToResources));
subpassIndexing.try_emplace(subpassName, subpasses.size() - 1);
subpasses.emplace_back(resourceManager.Create<SHSubpass>(GetHandle(), &resourceAttachmentMapping, ptrToResources));
subpassIndexing.try_emplace(subpassName, static_cast<uint32_t>(subpasses.size()) - 1u);
return subpasses.at(subpassIndexing[subpassName]);
}
void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer>& commandBuffer, uint32_t frameIndex) noexcept
{
frameIndex = (framebuffers.size() > 1) ? frameIndex : 0;
commandBuffer->BeginRenderpass(renderpass, framebuffers[frameIndex]);
for (uint32_t i = 0; i < subpasses.size(); ++i)
{
subpasses[i]->Execute(commandBuffer);
// Go to next subpass if not last subpass
if (i != subpasses.size() - 1)
commandBuffer->NextSubpass();
}
commandBuffer->EndRenderpass();
}
/***************************************************************************/
/*!
\brief
Get the renderpass from the node.
\return
Handle to the renderpass.
*/
/***************************************************************************/
Handle<SHVkRenderpass> SHRenderGraphNode::GetRenderpass(void) const noexcept
{
return renderpass;
}
/***************************************************************************/
/*!
@ -544,7 +610,7 @@ namespace SHADE
*/
/***************************************************************************/
void SHRenderGraph::AddResource(std::string resourceName, SH_ATT_DESC_TYPE type, uint32_t w /*= static_cast<uint32_t>(-1)*/, uint32_t h /*= static_cast<uint32_t>(-1)*/, vk::Format format/* = vk::Format::eB8G8R8A8Unorm*/, uint32_t levels /*= 1*/, vk::ImageCreateFlagBits createFlags /*= {}*/)
void SHRenderGraph::AddResource(std::string resourceName, SH_ATT_DESC_TYPE type, uint32_t w /*= static_cast<uint32_t>(-1)*/, uint32_t h /*= static_cast<uint32_t>(-1)*/, vk::Format format/* = vk::Format::eB8G8R8A8Unorm*/, uint8_t levels /*= 1*/, vk::ImageCreateFlagBits createFlags /*= {}*/)
{
// If we set to
if (w == static_cast<uint32_t>(-1) && h == static_cast<uint32_t>(-1))
@ -816,6 +882,24 @@ namespace SHADE
}
}
/***************************************************************************/
/*!
\brief
Configures command pools and command buffers.
*/
/***************************************************************************/
void SHRenderGraph::ConfigureCommands(void) noexcept
{
commandPool = logicalDeviceHdl->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true);
commandBuffers.resize(static_cast<std::size_t>(swapchainHdl->GetNumImages()));
for (auto& cmdBuffer : commandBuffers)
{
cmdBuffer = commandPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
}
}
/***************************************************************************/
/*!
@ -913,7 +997,7 @@ namespace SHADE
}
nodes.emplace_back(resourceManager.Create<SHRenderGraphNode>(resourceManager, logicalDeviceHdl, swapchainHdl, std::move(resources), std::move(predecessors), &graphResources));
nodeIndexing.emplace(nodeName, nodes.size() - 1);
nodeIndexing.emplace(nodeName, static_cast<uint32_t>(nodes.size()) - 1u);
return nodes.at(nodeIndexing[nodeName]);
}
@ -936,6 +1020,37 @@ namespace SHADE
ConfigureSubpasses();
ConfigureRenderpasses();
ConfigureFramebuffers();
ConfigureCommands();
}
void SHRenderGraph::Execute(uint32_t frameIndex) noexcept
{
commandPool->Reset();
auto& cmdBuffer = commandBuffers[frameIndex];
cmdBuffer->BeginRecording();
cmdBuffer->SetviewportScissor(1920.0f, 1080.0f, 1920, 1080);
for (auto& node : nodes)
{
node->Execute(commandBuffers[frameIndex], frameIndex);
}
cmdBuffer->EndRecording();
}
Handle<SHRenderGraphNode> SHRenderGraph::GetNode(std::string const& nodeName) const noexcept
{
if (nodeIndexing.contains(nodeName))
return nodes[nodeIndexing.at(nodeName)];
return {};
}
Handle<SHVkCommandBuffer> const& SHRenderGraph::GetCommandBuffer(uint32_t frameIndex) const noexcept
{
return commandBuffers[frameIndex];
}
}

View File

@ -3,6 +3,7 @@
#include "Graphics/Renderpass/SHVkRenderpass.h"
#include "Resource/ResourceLibrary.h"
#include "SH_API.h"
#include <string>
#include <map>
@ -15,6 +16,8 @@ namespace SHADE
class SHVkImage;
class SHVkImageView;
class SHVkFramebuffer;
class SHVkCommandPool;
class SHVkCommandBuffer;
// Used for attachment description creation for renderpass node
enum class SH_ATT_DESC_TYPE
@ -26,7 +29,7 @@ namespace SHADE
DEPTH_STENCIL,
};
class SHRenderGraphResource
class SH_API SHRenderGraphResource
{
private:
/*-----------------------------------------------------------------------*/
@ -72,25 +75,44 @@ namespace SHADE
friend class SHRenderGraph;
};
class SHRenderGraphNode
class SH_API SHRenderGraphNode : public ISelfHandle<SHRenderGraphNode>
{
public:
class SHSubpass
class SH_API SHSubpass
{
public:
SHSubpass(std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources) noexcept;
/*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */
/*-----------------------------------------------------------------------*/
SHSubpass(Handle<SHRenderGraphNode> const& parent, std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources) noexcept;
SHSubpass(SHSubpass&& rhs) noexcept;
SHSubpass& operator=(SHSubpass&& rhs) noexcept;
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
// Preparation functions
void AddColorOutput (std::string resourceToReference) noexcept;
void AddDepthOutput (std::string resourceToReference, SH_ATT_DESC_TYPE attachmentDescriptionType = SH_ATT_DESC_TYPE::DEPTH_STENCIL) noexcept;
void AddInput (std::string resourceToReference) noexcept;
// Runtime functions
void Execute (Handle<SHVkCommandBuffer>& commandBuffer) noexcept;
void AddExteriorDrawCalls (std::function<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept;
/*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */
/*-----------------------------------------------------------------------*/
Handle<SHRenderGraphNode> const& GetParentNode (void) const noexcept;
private:
/*---------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
/*---------------------------------------------------------------------*/
//! The parent renderpass that this subpass belongs to
Handle<SHRenderGraphNode> parentNode;
//! Color attachments
std::vector<vk::AttachmentReference> colorReferences;
@ -106,6 +128,14 @@ namespace SHADE
//! Pointer to resources in the render graph (for getting handle IDs)
std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources;
//! Sometimes there exists entities that we want to render onto a render target
//! but don't want it to come from the batching system. An example would be ImGUI.
//! For these entities we want to link a function from the outside and draw them
//! after we draw everything from the batch. Because of this, these draw calls
//! are always the last things drawn, so DO NOT USE THIS FUNCTIONALITY FOR ANYTHING
//! COMPLEX.
std::vector<std::function<void(Handle<SHVkCommandBuffer>&)>> exteriorDrawCalls;
friend class SHRenderGraphNode;
friend class SHRenderGraph;
};
@ -179,11 +209,17 @@ namespace SHADE
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
Handle<SHSubpass> AddSubpass (std::string subpassName) noexcept;
void Execute (Handle<SHVkCommandBuffer>& commandBuffer, uint32_t frameIndex) noexcept;
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
Handle<SHVkRenderpass> GetRenderpass (void) const noexcept;
friend class SHRenderGraph;
};
class SHRenderGraph
class SH_API SHRenderGraph
{
private:
/*-----------------------------------------------------------------------*/
@ -193,6 +229,7 @@ namespace SHADE
void ConfigureSubpasses (void) noexcept;
void ConfigureRenderpasses (void) noexcept;
void ConfigureFramebuffers (void) noexcept;
void ConfigureCommands (void) noexcept;
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
@ -214,6 +251,13 @@ namespace SHADE
//! Resource library for graph handles
ResourceManager resourceManager;
//! Command pool for the render graph
Handle<SHVkCommandPool> commandPool;
//! Command buffers for the render graph
std::vector<Handle<SHVkCommandBuffer>> commandBuffers;
public:
/*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */
@ -224,9 +268,16 @@ namespace SHADE
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void Init (Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain) noexcept;
void AddResource(std::string resourceName, SH_ATT_DESC_TYPE type, uint32_t w = static_cast<uint32_t>(-1), uint32_t h = static_cast<uint32_t>(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, uint32_t levels = 1, vk::ImageCreateFlagBits createFlags = {});
void AddResource (std::string resourceName, SH_ATT_DESC_TYPE type, uint32_t w = static_cast<uint32_t>(-1), uint32_t h = static_cast<uint32_t>(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, uint8_t levels = 1, vk::ImageCreateFlagBits createFlags = {});
Handle<SHRenderGraphNode> AddNode (std::string nodeName, std::initializer_list<std::string> resourceNames, std::initializer_list<std::string> predecessorNodes) noexcept;
void Generate (void) noexcept;
void Execute (uint32_t frameIndex) noexcept;
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
Handle<SHRenderGraphNode> GetNode (std::string const& nodeName) const noexcept;
Handle<SHVkCommandBuffer> const& GetCommandBuffer (uint32_t frameIndex) const noexcept;
};
}

View File

@ -29,11 +29,17 @@ namespace SHADE
/***************************************************************************/
SHVkRenderpass::SHVkRenderpass(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, std::span<vk::AttachmentDescription> const vkDescriptions, std::vector<SHVkSubpassParams> const& subpasses) noexcept
: logicalDeviceHdl {inLogicalDeviceHdl}
, numAttDescs {static_cast<uint32_t>(vkDescriptions.size())}
, clearColors{}
{
// TODO: temporary only
clearColors[0].color = { {{0.0f, 0.0f, 0.0f, 1.0f}} };
clearColors[1].depthStencil = vk::ClearDepthStencilValue(1.0f, 0);
for (uint32_t i = 0; i < vkDescriptions.size(); ++i)
{
if (SHVkUtil::IsDepthStencilAttachment(vkDescriptions[i].format))
clearColors[i].depthStencil = vk::ClearDepthStencilValue(1.0f, 0);
else
clearColors[i].color = { {{0.0f, 0.0f, 0.0f, 1.0f}} };
}
vk::RenderPassCreateInfo renderPassCreateInfo{};
std::vector<vk::SubpassDependency> subpassDeps;
@ -164,11 +170,16 @@ namespace SHADE
SHVkRenderpass::SHVkRenderpass(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, std::span<vk::AttachmentDescription> const vkDescriptions, std::span<vk::SubpassDescription> const spDescs, std::span<vk::SubpassDependency> const spDeps) noexcept
: logicalDeviceHdl{ inLogicalDeviceHdl }
, numAttDescs{ static_cast<uint32_t>(vkDescriptions.size()) }
, clearColors{}
{
// TODO: temporary only
clearColors[0].color = { {{0.0f, 0.0f, 0.0f, 1.0f}} };
clearColors[1].depthStencil = vk::ClearDepthStencilValue(1.0f, 0);
for (uint32_t i = 0; i < vkDescriptions.size(); ++i)
{
if (SHVkUtil::IsDepthStencilAttachment(vkDescriptions[i].format))
clearColors[i].depthStencil = vk::ClearDepthStencilValue(1.0f, 0);
else
clearColors[i].color = { {{0.0f, 0.0f, 0.0f, 1.0f}} };
}
subpassDescriptions.resize (spDescs.size());
for (uint32_t i = 0; i < subpassDescriptions.size(); ++i)

View File

@ -17,7 +17,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* STATIC CONSTEXPR VALUES */
/*-----------------------------------------------------------------------*/
static constexpr uint32_t NUM_CLEAR_COLORS = 2;
static constexpr uint32_t NUM_CLEAR_COLORS = 10;
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
@ -34,6 +34,9 @@ namespace SHADE
//! Clear colors for the color and depth
std::array<vk::ClearValue, NUM_CLEAR_COLORS> clearColors;
// number of attachment descriptions
uint32_t numAttDescs;
public:
/*-----------------------------------------------------------------------*/
/* CTOR AND DTOR */

View File

@ -189,7 +189,7 @@ namespace SHADE
Handle<SHShaderBlockInterface> SHShaderDescriptorBindingInfo::GetShaderBlockInterface(uint32_t set, uint32_t binding) const noexcept
{
SHShaderDescriptorBindingInfo::BindingAndSetHash hash = binding;
BindingAndSetHash hash = binding;
hash |= static_cast<uint64_t>(set) << 32;
if (blockInterfaces.contains(hash))
return blockInterfaces.at(hash);

View File

@ -9,11 +9,10 @@
namespace SHADE
{
struct SHShaderDescriptorBindingInfo
{
public:
using BindingAndSetHash = uint64_t;
struct SHShaderDescriptorBindingInfo
{
private:
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */

View File

@ -19,11 +19,15 @@ namespace SHADE
vkPresentModes = physicalDeviceHdl->GetVkPhysicalDevice().getSurfacePresentModesKHR(surfaceHdl->GetVkSurface());
if (vkSurfaceFormats.size() == 0)
{
SHLOG_ERROR("Failed to get surface formats from the physical device. ");
}
if (vkPresentModes.size() == 0)
{
SHLOG_ERROR("Failed to get present modes from the physical device. ");
}
}
vk::SurfaceFormatKHR SHVkSwapchain::ChooseSwapSurfaceFormat(std::vector<vk::SurfaceFormatKHR> const& surfaceFormats) const noexcept
{

View File

@ -18,7 +18,10 @@ namespace SHADE
// that a mat2 can be interpreted as (x, y, x, y), (o, o, o, o) instead of (x, y, o, o), (o, o, o, o)?
MAT_2D,
MAT_3D,
MAT_4D
MAT_4D,
// integer formats
UINT32_1D,
};
struct SHVertexAttribute

View File

@ -222,7 +222,7 @@ namespace SHADE
return true;
{
MSG Message;
while (PeekMessageW(&Message, NULL, 0, 0, PM_REMOVE))
while (PeekMessageW(&Message, wndHWND, 0, 0, PM_REMOVE))
{
if (WM_QUIT == Message.message)
{

View File

@ -5,6 +5,7 @@
#include <functional>
#include <unordered_map>
#include "SHWindowMap.h"
#include "SH_API.h"
namespace SHADE
{
@ -67,7 +68,7 @@ namespace SHADE
std::string icoPath = "";
};
class SHWindow
class SH_API SHWindow
{
public:
using SHVec2 = std::pair<uint32_t, uint32_t>;

View File

@ -139,7 +139,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
ResourceLibrary<T>* library;
ResourceLibrary<T>* library = nullptr;
/*-----------------------------------------------------------------------------*/
/* Friend Declarations */

View File

@ -69,7 +69,7 @@ namespace SHADE
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
void assertHandleValid(Handle<T> handle) const;
int getAvailableFreeIndex();
uint32_t getAvailableFreeIndex();
};
/// <summary>

View File

@ -35,13 +35,13 @@ namespace SHADE
}
else
{
handle.id.Data.Version = 0;
versionCounts.insert(handle.id.Data.Index, handle.id.Data.Version);
handle.id.Data.Version = 0U;
versionCounts.insert(static_cast<uint32_t>(handle.id.Data.Index), handle.id.Data.Version);
}
handle.library = this;
// Create the resource
[[maybe_unused]] T& obj = objects.insert(handle.id.Data.Index, std::forward<Args>(args) ...);
[[maybe_unused]] T& obj = objects.insert(static_cast<uint32_t>(handle.id.Data.Index), std::forward<Args>(args) ...);
// Handling SelfHandle assignment
if constexpr (std::is_base_of_v<ISelfHandle<T>, T>)
@ -89,7 +89,7 @@ namespace SHADE
}
template<typename T>
inline int ResourceLibrary<T>::getAvailableFreeIndex()
inline uint32_t ResourceLibrary<T>::getAvailableFreeIndex()
{
// Get from the free list if present
if (!freeList.empty())

View File

@ -56,7 +56,7 @@ namespace SHADE
throw std::invalid_argument("An element at this index does not exist!");
// Swap with the last element
const int BACK_IDX = denseArray.size() - 1;
const auto BACK_IDX = denseArray.size() - 1;
std::swap(denseArray[sparseArray[idx]], denseArray.back());
denseArray.pop_back();
// Update the sparse set by swapping the indices
@ -110,7 +110,7 @@ namespace SHADE
// We need to resize the array
if (idx >= sparseArray.size())
{
const int NEW_SIZE = idx + 1;
const auto NEW_SIZE = idx + 1;
sparseArray.resize(NEW_SIZE, INVALID);
inverseSparseArray.resize(NEW_SIZE, INVALID);
}
@ -123,7 +123,7 @@ namespace SHADE
auto& insertedElem = denseArray.emplace_back(std::forward<Args>(args) ...);
// Update sparse and inverse sparse arrays
const index_type DENSE_IDX = denseArray.size() - 1;
const auto DENSE_IDX = static_cast<index_type>(denseArray.size()) - 1;
sparseArray[idx] = DENSE_IDX;
inverseSparseArray[DENSE_IDX] = idx;

View File

@ -0,0 +1,28 @@
/************************************************************************************//*!
\file SHCommonTypes.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Sep 8, 2022
\brief Contains the definitions of type alias for commonly used units for
clarity and convenience.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
/***********************************************************************************/
/*!
\brief
Type used to mark a value that is supposed to represent a size in bytes.
*/
/***********************************************************************************/
using Byte = size_t;
}

36
SHADE_Engine/src/SH_API.h Normal file
View File

@ -0,0 +1,36 @@
/************************************************************************************//*!
\file SH_API.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Sep 13, 2022
\brief Contains dllexport and dllimport macros for the SHADE Engine.
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
// Select the correct export system based on the compiler
#if defined SH_LIB
# define SH_API
#else
# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER
# define SH_EXPORT __declspec(dllexport)
# define SH_IMPORT __declspec(dllimport)
# elif defined __GNUC__ && __GNUC__ >= 4
# define SH_EXPORT __attribute__((visibility("default")))
# define SH_IMPORT __attribute__((visibility("default")))
# else /* Unsupported compiler */
# define SH_EXPORT
# define SH_IMPORT
# endif
// Define the correct
# ifndef SH_API
# if defined SH_API_EXPORT
# define SH_API SH_EXPORT
# else
# define SH_API SH_IMPORT
# endif
# endif
#endif

View File

@ -33,5 +33,7 @@
#include <functional>
#include <sstream>
#include <iomanip>
#include <cstddef>
#include "Common/SHCommonTypes.h"
#include "Tools/SHLogger.h"

View File

@ -14,7 +14,7 @@
#include "SHSceneGraph.h"
// Project Headers
#include "ECS_Base/System/SHEntityManager.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Tools/SHLogger.h"
#include "Tools/SHException.h"

View File

@ -10,11 +10,11 @@
*********************************************************************/
#include "SHpch.h"
#include "SHSceneManager.h"
#include "ECS_Base/System/SHComponentManager.h"
#include "ECS_Base/Managers/SHComponentManager.h"
//#include "Input/SHInputManager.h"
//#include "Rendering/Window/SHRenderingWindow.h"
#include "ECS_Base/System/SHEntityManager.h"
#include "ECS_Base/System/SHSystemManager.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
//#include "FRC/SHFrameRateController.h"
//#include "ECS_Base/System/SHApplication.h"

View File

@ -0,0 +1,198 @@
/*************************************************************************************//*!
\file SHDotNetRuntime.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 2, 2021
\brief Contains the definition of the SHDotNetRuntime class.
Implementation of code to set up code for SHDotNetRuntime is based on the
following repository:
https://github.com/mjrousos/SampleCoreCLRHost
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 "SHDotNetRuntime.h"
// Standard Library
#include <array>
// External Dependencies
#include <shlwapi.h> // PathRemoveFileSpecA
#include "Tools/SHLogger.h"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Constructors/Destructor */
/*---------------------------------------------------------------------------------*/
SHDotNetRuntime::SHDotNetRuntime(bool autoInit)
{
if (autoInit)
{
Init();
}
}
SHDotNetRuntime::~SHDotNetRuntime()
{
if (IsLoaded())
{
try
{
Exit();
}
catch (std::runtime_error& e)
{
SHLOG_ERROR(e.what());
}
}
}
/*---------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*---------------------------------------------------------------------------------*/
void SHDotNetRuntime::Init()
{
// State checking, in case there was an unload before, we must ensure that the state is valid
if (initialised)
throw std::runtime_error("[DotNetRuntime] Failed to initialise as it was already initialised or was deinitialised into an invalid state.");
// Get the current executable directory
std::string runtimePath(MAX_PATH, '\0');
GetModuleFileNameA(nullptr, runtimePath.data(), MAX_PATH);
PathRemoveFileSpecA(runtimePath.data());
// Since PathRemoveFileSpecA() removes from data(), the size is not updated, so we must manually update it
runtimePath.resize(std::strlen(runtimePath.data()));
// Do not need to load the library if it was previously loaded
if (coreClr == nullptr)
{
// Construct the CoreCLR path
std::string coreClrPath(runtimePath); // Works
coreClrPath += "\\coreclr.dll";
// Load the CoreCLR DLL
coreClr = LoadLibraryExA(coreClrPath.c_str(), nullptr, 0);
if (!coreClr)
{
std::ostringstream oss;
oss << "[DotNetRuntime] Error #" << GetLastError() << " Failed to load CoreCLR from \"" << coreClrPath << "\"\n";
throw std::runtime_error(oss.str());
}
// Step 2: Get CoreCLR hosting functions
initializeCoreClr = getCoreClrFunctionPtr<coreclr_initialize_ptr>("coreclr_initialize");
createManagedDelegate = getCoreClrFunctionPtr<coreclr_create_delegate_ptr>("coreclr_create_delegate");
shutdownCoreClr = getCoreClrFunctionPtr<coreclr_shutdown_ptr>("coreclr_shutdown");
}
// Step 3: Construct AppDomain properties used when starting the runtime
// Construct the trusted platform assemblies (TPA) list
// This is the list of assemblies that .NET Core can load as
// trusted system assemblies (similar to the .NET Framework GAC).
// For this host (as with most), assemblies next to CoreCLR will
// be included in the TPA list
std::string tpaList = buildTpaList(runtimePath);
// Define CoreCLR properties
std::array propertyKeys =
{
"TRUSTED_PLATFORM_ASSEMBLIES", // Trusted assemblies (like the GAC)
"APP_PATHS", // Directories to probe for application assemblies
// "APP_NI_PATHS", // Directories to probe for application native images (not used in this sample)
// "NATIVE_DLL_SEARCH_DIRECTORIES", // Directories to probe for native dlls (not used in this sample)
};
std::array propertyValues =
{
tpaList.c_str(),
runtimePath.c_str()
};
// Step 4: Start the CoreCLR runtime
int result = initializeCoreClr
(
runtimePath.c_str(), // AppDomain base path
"SHADEHost", // AppDomain friendly name
static_cast<int>(propertyKeys.size()), // Property count
propertyKeys.data(), // Property names
propertyValues.data(), // Property values
&hostHandle, // Host handle
&domainId // AppDomain ID
);
// Check if intiialization of CoreCLR failed
throwIfFailed("[DotNetRuntime] Failed to initialize CoreCLR.", result);
initialised = true;
SHLOG_INFO("[DotNetRuntime] Successfully loaded the .NET 5.0 Runtime.");
}
void SHDotNetRuntime::Exit()
{
// State checking, in case there was an unload before, we must ensure that the state is valid
if (!initialised)
throw std::runtime_error("[DotNetRuntime] Failed to deinitialise as it was not initialised before.");
// Shutdown CoreCLR
int result = shutdownCoreClr(hostHandle, domainId);
throwIfFailed("[DotNetRuntime] Failed to shut down CoreCLR.", result);
// Unset pointers
hostHandle = nullptr;
domainId = 0;
initialised = false;
SHLOG_INFO("[DotNetRuntime] Successfully shut down the .NET 5.0 Runtime.");
}
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
std::string SHDotNetRuntime::buildTpaList(const std::string& directory)
{
// Constants
static const std::string SEARCH_PATH = directory + "\\*.dll";
static constexpr char PATH_DELIMITER = ';';
// Create a osstream object to compile the string
std::ostringstream tpaList;
// Search the current directory for the TPAs (.DLLs)
WIN32_FIND_DATAA findData;
HANDLE fileHandle = FindFirstFileA(SEARCH_PATH.c_str(), &findData);
if (fileHandle != INVALID_HANDLE_VALUE)
{
do
{
// Append the assembly to the list
tpaList << directory << '\\' << findData.cFileName << PATH_DELIMITER;
// Note that the CLR does not guarantee which assembly will be loaded if an assembly
// is in the TPA list multiple times (perhaps from different paths or perhaps with different NI/NI.dll
// extensions. Therefore, a real host should probably add items to the list in priority order and only
// add a file if it's not already present on the list.
//
// For this simple sample, though, and because we're only loading TPA assemblies from a single path,
// and have no native images, we can ignore that complication.
}
while (FindNextFileA(fileHandle, &findData));
FindClose(fileHandle);
}
return tpaList.str();
}
void SHDotNetRuntime::throwIfFailed(const std::string& errMsg, int resultCode)
{
if (resultCode < 0)
{
std::ostringstream oss;
oss << std::hex << std::setfill('0') << std::setw(8)
<< errMsg
<< " Error 0x" << resultCode << "\n";
throw std::runtime_error(oss.str());
}
}
}

View File

@ -0,0 +1,207 @@
/*************************************************************************************//*!
\file SHDotNetRuntime.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 2, 2021
\brief Contains the interface of a wrapper class for interfacing with the
.NET 5 Runtime.
Copyright (C) 2021 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//**************************************************************************************/
#pragma once
// Standard Libraries
#include <iomanip> // std::setfill, std::setw
#include <stdexcept> // std::runtime_error
#include <string> // std::string
#include <sstream> // std::ostringstream
// External Dependencies
#include <Windows.h> // HMODULE
#include <coreclrhost.h> // coreclr_*
namespace SHADE
{
/*************************************************************************************/
/*!
class SHDotNetRuntime
\brief
Class that encapsulates the state of the .NET Core Runtime lifecycle.
*/
/*************************************************************************************/
class SHDotNetRuntime
{
public:
/*---------------------------------------------------------------------------------*/
/* Constructors/Destructor */
/*---------------------------------------------------------------------------------*/
/***********************************************************************************/
/*!
\brief
Default constructor that immediately initializes the CoreCLR.
\param autoInit
If true, loads the CoreCLR by calling Init().
*/
/***********************************************************************************/
SHDotNetRuntime(bool autoInit = true);
/***********************************************************************************/
/*!
\brief
Destructor that unloads the CoreCLR if it has not been unloaded yet.
*/
/***********************************************************************************/
~SHDotNetRuntime();
// Disallow copy and moving
SHDotNetRuntime(const SHDotNetRuntime&) = delete;
SHDotNetRuntime(SHDotNetRuntime&&) = delete;
/*----------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*----------------------------------------------------------------------------------*/
/***********************************************************************************/
/*!
\brief
Loads the CoreCLR and grabs pointers to bootstrapping functions and kickstarts the
CoreCLR.
\throws std::runtime_error
Thrown if there is a failure in loading the CLR and related functions.
*/
/***********************************************************************************/
void Init();
/***********************************************************************************/
/*!
\brief
Unloads the CoreCLR.
\throws std::runtime_error
Thrown if there is a failure in unloading the CLR.
*/
/***********************************************************************************/
void Exit();
/*----------------------------------------------------------------------------------*/
/* Usage Functions */
/*----------------------------------------------------------------------------------*/
/***********************************************************************************/
/*!
\brief
Checks if the DotNetRuntime has successfully been initialised.
\return
True if this DotNetRuntime has been initialised.
*/
/***********************************************************************************/
inline bool IsLoaded() const noexcept { return initialised; }
/***********************************************************************************/
/*!
\brief
Retrieves a function pointer from the a CLR assembly based on the specified
assembly, type and function names.
\tparam FunctionType
Type of the function pointer that the specified function name will provide.
\param assemblyName
Name of the CoreCLR assembly that contains the function.
\param typeName
Name of the CoreCLR type in the assembly that contains the function. Nested types
are separated by a period(.).
\param functionName
Name of the CoreCLR function to get a pointer to.
\return
Pointer to the function in the assembly that was specified.
*/
/***********************************************************************************/
template<typename FunctionType>
FunctionType GetFunctionPtr(const std::string_view& assemblyName,
const std::string_view& typeName,
const std::string_view& functionName) const;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
bool initialised = false;
// References to CoreCLR key components
HMODULE coreClr = nullptr;
void* hostHandle = nullptr;
unsigned int domainId = 0;
// Function Pointers to CoreCLR functions
coreclr_initialize_ptr initializeCoreClr = nullptr;
coreclr_create_delegate_ptr createManagedDelegate = nullptr;
coreclr_shutdown_ptr shutdownCoreClr = nullptr;
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
/***********************************************************************************/
/*!
\brief
Retrieves a function pointer from the CoreCLR based on the specified
function name.
\tparam FunctionType
Type of the function pointer that the specified function name will provide.
\param functionName
Name of the CoreCLR function to get a pointer to.
\return
Pointer to the function in the CoreCLR that was specified.
*/
/***********************************************************************************/
template<typename FunctionType>
FunctionType getCoreClrFunctionPtr(const std::string& functionName);
/***********************************************************************************/
/*!
\brief
Compiles a semicolon separated string of trusted platform assemblies by
searching the specified directory.
\param directory
Path to the directory where the trusted platform assemblies reside.
\return
Semicolon separated string of trusted platform assemblies.
*/
/***********************************************************************************/
static std::string buildTpaList(const std::string& directory);
/***********************************************************************************/
/*!
\brief
Takes in a Win32 result code and throws an exception it if there is an error.
\param errMsg
Error message to display if the resultCode is a failure code.
\param resultCode
Result code of the function to check.
*/
/***********************************************************************************/
static void throwIfFailed(const std::string& errMsg, int resultCode);
};
}
#include "SHDotNetRuntime.hpp"

View File

@ -0,0 +1,61 @@
/*************************************************************************************//*!
\file SHDotNetRuntime.hpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 2, 2021
\brief Contains the implementation of the template functions of the
DotNetRuntime 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.
*//**************************************************************************************/
#pragma once
// Primary Include
#include "SHDotNetRuntime.h"
namespace SHADE
{
template<typename FunctionType>
FunctionType SHDotNetRuntime::GetFunctionPtr(const std::string_view & assemblyName,
const std::string_view & typeName,
const std::string_view & functionName) const
{
FunctionType managedDelegate = nullptr;
int result = createManagedDelegate
(
hostHandle,
domainId,
assemblyName.data(),
typeName.data(),
functionName.data(),
reinterpret_cast<void**>(&managedDelegate)
);
// Check if it failed
if (result < 0)
{
std::ostringstream oss;
oss << std::hex << std::setfill('0') << std::setw(8)
<< "[DotNetRuntime] Failed to get pointer to function \""
<< typeName << "." << functionName << "\" in assembly (" << assemblyName << "). "
<< "Error 0x" << result << "\n";
throw std::runtime_error(oss.str());
}
return managedDelegate;
}
template<typename FunctionType>
FunctionType SHDotNetRuntime::getCoreClrFunctionPtr(const std::string& functionName)
{
FunctionType fPtr = reinterpret_cast<FunctionType>(GetProcAddress(coreClr, functionName.c_str()));
if (!fPtr)
{
std::ostringstream oss;
oss << "[DotNetRuntime] Unable to get pointer to function: \"" << functionName << "\"";
throw std::runtime_error(oss.str());
}
return fPtr;
}
}

View File

@ -0,0 +1,506 @@
/************************************************************************************//*!
\file SHScriptEngine.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Sep 17, 2021
\brief Contains the implementation for ScriptEngine 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 Headers
#include <SHpch.h>
// Primary Header
#include "SHScriptEngine.h"
// Standard Library
#include <fstream> // std::fstream
#include <filesystem> // std::filesystem::canonical, std::filesystem::remove
// Project Headers
#include "Tools/SHLogger.h"
#include "Tools/SHStringUtils.h"
namespace SHADE
{
/*--------------------------------------------------------------------------------*/
/* Static Definitions */
/*--------------------------------------------------------------------------------*/
const std::string SHScriptEngine::DEFAULT_CSHARP_NAMESPACE = std::string("SHADE");
SHDotNetRuntime SHScriptEngine::dotNet { false };
SHScriptEngine::CsFuncPtr SHScriptEngine::csEngineInit = nullptr;
SHScriptEngine::CsFuncPtr SHScriptEngine::csEngineLoadScripts = nullptr;
SHScriptEngine::CsFuncPtr SHScriptEngine::csEngineUnloadScripts = nullptr;
SHScriptEngine::CsFuncPtr SHScriptEngine::csEngineReloadScripts = nullptr;
SHScriptEngine::CsFuncPtr SHScriptEngine::csEngineExit = nullptr;
SHScriptEngine::CsFuncPtr SHScriptEngine::csScriptsFrameSetUp = nullptr;
SHScriptEngine::CsFuncPtr SHScriptEngine::csScriptsExecuteFixedUpdate = nullptr;
SHScriptEngine::CsFuncPtr SHScriptEngine::csScriptsExecuteUpdate = nullptr;
SHScriptEngine::CsFuncPtr SHScriptEngine::csScriptsExecuteLateUpdate = nullptr;
SHScriptEngine::CsFuncPtr SHScriptEngine::csScriptsFrameCleanUp = nullptr;
SHScriptEngine::CsScriptManipFuncPtr SHScriptEngine::csScriptsAdd = nullptr;
SHScriptEngine::CsScriptBasicFuncPtr SHScriptEngine::csScriptsRemoveAll = nullptr;
SHScriptEngine::CsScriptOptionalFuncPtr SHScriptEngine::csScriptsRemoveAllImmediately = nullptr;
SHScriptEngine::CsScriptSerialiseFuncPtr SHScriptEngine::csScriptsSerialise = nullptr;
SHScriptEngine::CsScriptDeserialiseFuncPtr SHScriptEngine::csScriptDeserialise = nullptr;
SHScriptEngine::CsScriptSerialiseYamlFuncPtr SHScriptEngine::csScriptsSerialiseYaml = nullptr;
SHScriptEngine::CsScriptSerialiseYamlFuncPtr SHScriptEngine::csScriptDeserialiseYaml = nullptr;
SHScriptEngine::CsScriptEditorFuncPtr SHScriptEngine::csEditorRenderScripts = nullptr;
/*---------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*---------------------------------------------------------------------------------*/
void SHScriptEngine::Init()
{
// Do not allow initialization if already initialised
if (dotNet.IsLoaded())
{
SHLOG_ERROR("[ScriptEngine] Attempted to initialise an already loaded DotNetRuntime.");
return;
}
dotNet.Init();
// Load all the helpers
loadFunctions();
// Generate script assembly if it hasn't been before
if (!fileExists(std::string(MANAGED_SCRIPT_LIB_NAME) + ".dll"))
{
BuildScriptAssembly();
}
// Initialise the CSharp Engine
csEngineInit();
// Link events
// - Entity Destruction
/*onEntityDestroy = [this](const SHEntity& e)
{
csScriptsRemoveAll(e.GetEID());
csGOLibNotifyDestroyEntity(e.GetEID());
};
ECS::OnEntityDestroy += onEntityDestroy;*/
}
void SHScriptEngine::UnloadScriptAssembly()
{
csEngineUnloadScripts();
}
void SHScriptEngine::LoadScriptAssembly()
{
csEngineLoadScripts();
}
void SHScriptEngine::ReloadScriptAssembly()
{
csEngineReloadScripts();
}
void SHScriptEngine::ExecuteFixedUpdates()
{
csScriptsExecuteFixedUpdate();
}
void SHScriptEngine::Exit()
{
// Do not allow deinitialization if not initialised
if (!dotNet.IsLoaded())
{
SHLOG_ERROR("[ScriptEngine] Attempted to clean up an unloaded DotNetRuntime.");
return;
}
// Unlink events
/*ECS::OnEntityCreated -= onEntityCreate;
ECS::OnEntityDestroy -= onEntityDestroy;*/
// Clean up the CSharp Engine
csEngineExit();
// Shut down the CLR
dotNet.Exit();
}
/*---------------------------------------------------------------------------------*/
/* Script Manipulation Functions */
/*---------------------------------------------------------------------------------*/
bool SHScriptEngine::AddScript(const SHEntity& entity, const std::string_view& scriptName)
{
return csScriptsAdd(entity.GetEID(), scriptName.data());
}
void SHScriptEngine::RemoveAllScripts(const SHEntity& entity)
{
csScriptsRemoveAll(entity.GetEID());
}
void SHScriptEngine::RemoveAllScriptsImmediately(const SHEntity& entity, bool callOnDestroy)
{
csScriptsRemoveAllImmediately(entity.GetEID(), callOnDestroy);
}
/*---------------------------------------------------------------------------------*/
/* Script Serialisation Functions */
/*---------------------------------------------------------------------------------*/
std::string SHScriptEngine::SerialiseScripts(const SHEntity& entity)
{
// Create buffer needed to store serialised script data
constexpr int BUFFER_SIZE = 10240;
std::unique_ptr<char> buffer { new char[BUFFER_SIZE] };
std::memset(buffer.get(), 0, BUFFER_SIZE);
// Attempt to serialise the script
std::string result;
if (csScriptsSerialise(entity.GetEID(), buffer.get(), BUFFER_SIZE))
{
result = std::string(buffer.get());
}
else
{
SHLOG_ERROR("[ScriptEngine] Failed to serialise scripts as string buffer is too small!");
}
// Return an empty string since we failed to serialise
return result;
}
/*---------------------------------------------------------------------------------*/
/* Script Serialisation Functions */
/*---------------------------------------------------------------------------------*/
void SHScriptEngine::DeserialiseScript(const SHEntity& entity, const std::string& yaml)
{
csScriptDeserialise(entity.GetEID(), yaml.c_str());
}
/*---------------------------------------------------------------------------------*/
/* Script Editor Functions */
/*---------------------------------------------------------------------------------*/
void SHScriptEngine::RenderScriptsInInspector(const SHEntity& entity)
{
csEditorRenderScripts(entity.GetEID());
}
/*---------------------------------------------------------------------------------*/
/* Static Utility Functions */
/*---------------------------------------------------------------------------------*/
bool SHScriptEngine::BuildScriptAssembly(bool debug)
{
constexpr std::string_view BUILD_LOG_PATH = "../Build.log";
// Generate csproj file if it doesn't exist
static const std::filesystem::path CSPROJ_PATH = "../SHADE_Scripting.csproj";
if (!std::filesystem::exists(CSPROJ_PATH))
{
GenerateScriptsCsProjFile(CSPROJ_PATH);
}
// Prepare directory (delete useless files)
deleteFolder("net5.0");
deleteFolder("ref");
deleteFolder("../SHADE_Scripting");
deleteFolder("../obj");
// Attempt to build the assembly
std::ostringstream oss;
oss << "[ScriptEngine] Building " << (debug ? " debug " : "") << "Managed Script Assembly (" << MANAGED_SCRIPT_LIB_NAME << ")!";
SHLOG_INFO(oss.str());
oss.str("");
const bool BUILD_SUCCESS = execProcess
(
L"C:\\Windows\\system32\\cmd.exe",
L"/K \"dotnet build \"../SHADE_Scripting.csproj\" -c Debug -o \"./tmp/\" -fl -flp:LogFile=build.log;Verbosity=quiet & exit\""
) == 0;
if (BUILD_SUCCESS)
{
// Copy to built dll to the working directory and replace
std::filesystem::copy_file("./tmp/SHADE_Scripting.dll", "SHADE_Scripting.dll", std::filesystem::copy_options::overwrite_existing);
oss << "[ScriptEngine] Successfully built Managed Script Assembly (" << MANAGED_SCRIPT_LIB_NAME << ")!";
SHLOG_INFO(oss.str());
}
else
{
oss << "[ScriptEngine] Failed to build Managed Script Assembly (" << MANAGED_SCRIPT_LIB_NAME << ")!";
SHLOG_ERROR(oss.str());
}
// Clean up built files
deleteFolder("./tmp");
// Read the build log and output to the console
dumpBuildLog(BUILD_LOG_PATH);
// Delete the build log file since we no longer need it
deleteFile(BUILD_LOG_PATH);
return BUILD_SUCCESS;
}
void SHScriptEngine::GenerateScriptsCsProjFile(const std::filesystem::path& path)
{
// Sample
static std::string_view FILE_CONTENTS =
"<Project Sdk=\"Microsoft.NET.Sdk\">\n\
<PropertyGroup>\n\
<TargetFramework>net5.0</TargetFramework>\n\
<Platforms>x64</Platforms>\n\
<Configurations>Release;Debug</Configurations>\n\
</PropertyGroup>\n\
<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n\
<OutputPath>.\\bin_Release-x64</OutputPath>\n\
<PlatformTarget>x64</PlatformTarget>\n\
</PropertyGroup>\n\
<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\"> \n\
<OutputPath>.\\bin_Debug-x64</OutputPath>\n\
<PlatformTarget>x64</PlatformTarget>\n\
<DefineConstants>DEBUG;TRACE</DefineConstants>\n\
<Optimize>false</Optimize>\n\
<DebugType>full</DebugType>\n\
<DebugSymbols>true</DebugSymbols>\n\
</PropertyGroup>\n\
<ItemGroup>\n\
<Compile Remove=\"bin\\**\" />\n\
<EmbeddedResource Remove=\"Assets\\**\" />\n\
<EmbeddedResource Remove=\"bin\\**\" />\n\
<None Remove=\"bin\\**\" />\n\
</ItemGroup>\n\
<ItemGroup>\n\
<None Remove=\".gitignore\" />\n\
<None Remove=\".gitmodules\" />\n\
</ItemGroup>\n\
<ItemGroup>\n\
<Reference Include=\"SHADE_Managed\">\n\
<HintPath>.\\bin\\SHADE_Managed.dll</HintPath>\n\
</Reference>\n\
</ItemGroup>\n\
</Project>";
// Attempt to create the file
std::ofstream file(path);
if (!file.is_open())
throw std::runtime_error("Unable to create CsProj file!");
// Fill the file
file << FILE_CONTENTS;
// Close
file.close();
}
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
void SHScriptEngine::loadFunctions()
{
std::ostringstream oss;
oss << "[ScriptEngine] Loading \"" << DEFAULT_CSHARP_LIB_NAME << "\" CLR library.";
SHLOG_INFO(oss.str());
// Load functions
csEngineInit = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
"Init"
);
csEngineLoadScripts = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
"LoadScriptAssembly"
);
csEngineUnloadScripts = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
"UnloadScriptAssembly"
);
csEngineReloadScripts = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
"ReloadScriptAssembly"
);
csEngineExit = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
"Exit"
);
csScriptsFrameSetUp = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"FrameSetUp"
);
csScriptsExecuteFixedUpdate = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"ExecuteFixedUpdate"
);
csScriptsExecuteUpdate = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"ExecuteUpdate"
);
csScriptsExecuteLateUpdate = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"ExecuteLateUpdate"
);
csScriptsFrameCleanUp = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"FrameCleanUp"
);
csScriptsAdd = dotNet.GetFunctionPtr<CsScriptManipFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"AddScriptViaName"
);
csScriptsRemoveAll = dotNet.GetFunctionPtr<CsScriptBasicFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"RemoveAllScripts"
);
csScriptsRemoveAllImmediately = dotNet.GetFunctionPtr<CsScriptOptionalFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"RemoveAllScriptsImmediately"
);
/*csScriptsSerialise = dotNet.GetFunctionPtr<CsScriptSerialiseFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"SerialiseScripts"
);
csScriptsSerialiseYaml = dotNet.GetFunctionPtr<CsScriptSerialiseYamlFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"SerialiseScriptsYaml"
);
csScriptDeserialise = dotNet.GetFunctionPtr<CsScriptDeserialiseFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"DeserialiseScript"
);
csScriptDeserialiseYaml = dotNet.GetFunctionPtr<CsScriptSerialiseYamlFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"SerialiseScriptsYaml"
);
csEditorRenderScripts = dotNet.GetFunctionPtr<CsScriptEditorFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".Editor",
"RenderScriptsInInspector"
);*/
}
void SHScriptEngine::dumpBuildLog(const std::string_view& buildLogPath)
{
std::ifstream buildLog(buildLogPath);
// Fail to open
if (!buildLog.is_open())
return;
// Process line by line
std::string line;
while (std::getline(buildLog, line))
{
if (line.find("error") != line.npos)
{
SHLOG_ERROR(line);
}
else
{
SHLOG_WARNING(line);
}
}
}
void SHScriptEngine::deleteFile(const std::string_view& filePath)
{
try
{
std::filesystem::remove(std::filesystem::canonical(filePath));
}
catch (...) {} // Ignore deletion failures
}
void SHScriptEngine::deleteFolder(const std::string_view& filePath)
{
try
{
std::filesystem::remove_all(std::filesystem::canonical(filePath));
}
catch (...) {} // Ignore deletion failures
}
bool SHScriptEngine::fileExists(const std::string_view& filePath)
{
std::error_code error;
if (std::filesystem::exists(filePath, error))
{
return true;
}
return false;
}
DWORD SHScriptEngine::execProcess(const std::wstring& path, const std::wstring& args)
{
STARTUPINFOW startInfo;
PROCESS_INFORMATION procInfo;
ZeroMemory(&startInfo, sizeof(startInfo));
ZeroMemory(&procInfo, sizeof(procInfo));
startInfo.cb = sizeof(startInfo);
std::wstring argsWstr = args;
// Start Process
const auto SUCCESS = CreateProcess
(
path.data(), argsWstr.data(),
nullptr, nullptr, false, NULL, nullptr, nullptr,
&startInfo, &procInfo
);
// Error Check
if (!SUCCESS)
{
auto err = GetLastError();
std::ostringstream oss;
oss << "[ScriptEngine] Failed to launch process. Error code: " << std::hex << err
<< " (" << SHStringUtils::GetWin32ErrorMessage(err) << ")";
throw std::runtime_error(oss.str());
}
// Wait for execution to end
DWORD status;
while (true)
{
const auto SUCCESS = GetExitCodeProcess(procInfo.hProcess, &status);
if (!SUCCESS)
{
auto err = GetLastError();
std::ostringstream oss;
oss << "[ScriptEngine] Failed to query process. Error code: " << std::hex << err
<< " (" << SHStringUtils::GetWin32ErrorMessage(err) << ")";
throw std::runtime_error(oss.str());
}
// Break only if process ends
if (status != STILL_ACTIVE)
{
CloseHandle(procInfo.hProcess);
CloseHandle(procInfo.hThread);
return status;
}
}
}
}

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