diff --git a/.gitignore b/.gitignore index fba41f1e..c7fefb6e 100644 --- a/.gitignore +++ b/.gitignore @@ -353,4 +353,9 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ +# Generated Files [Dd]ependencies/ +*.vcxproj +*.vcxproj.filters +*.sln +*.csproj diff --git a/Dependencies.bat b/Dependencies.bat index bbce926b..0b1e1a54 100644 --- a/Dependencies.bat +++ b/Dependencies.bat @@ -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! diff --git a/Dependencies.lua b/Dependencies.lua index 32382cf9..9877a70e 100644 --- a/Dependencies.lua +++ b/Dependencies.lua @@ -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" diff --git a/Premake/premake5.exe b/Premake/premake5.exe index f081fe1f..c25bb3fb 100644 Binary files a/Premake/premake5.exe and b/Premake/premake5.exe differ diff --git a/SHADE.sln b/SHADE.sln deleted file mode 100644 index ff6afa61..00000000 --- a/SHADE.sln +++ /dev/null @@ -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 diff --git a/SHADE_Application/SHADE_Application.vcxproj b/SHADE_Application/SHADE_Application.vcxproj deleted file mode 100644 index c1775b8d..00000000 --- a/SHADE_Application/SHADE_Application.vcxproj +++ /dev/null @@ -1,123 +0,0 @@ - - - - - Debug - x64 - - - Release - x64 - - - - {BDC70008-29DE-FE9D-7255-8ABFDEAACF25} - true - Win32Proj - SHADE_Application - 10.0 - - - - Application - true - Unicode - v142 - - - Application - false - Unicode - v142 - - - - - - - - - - - - - true - bin\Debug_x86_64\SHADE_Application\ - bin-int\Debug_x86_64\SHADE_Application\ - SHADE_Application - .exe - ..\Dependencies\spdlog\include;$(VULKAN_SDK)\include;..\Dependencies\VMA\include;$(VULKAN_SDK)\Source\SPIRV-Reflect;$(IncludePath) - - - false - bin\Release_x86_64\SHADE_Application\ - bin-int\Release_x86_64\SHADE_Application\ - SHADE_Application - .exe - ..\Dependencies\spdlog\include;$(VULKAN_SDK)\include;..\Dependencies\VMA\include;$(VULKAN_SDK)\Source\SPIRV-Reflect;$(IncludePath) - - - - Use - SBpch.h - Level4 - NOMINMAX;_DEBUG;%(PreprocessorDefinitions) - ..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories) - EditAndContinue - Disabled - false - MultiThreadedDebug - true - stdcpplatest - - - Windows - true - wWinMainCRTStartup - - - - - Use - SBpch.h - Level4 - NOMINMAX;_RELEASE;%(PreprocessorDefinitions) - ..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories) - Full - true - true - false - true - MultiThreaded - true - stdcpplatest - - - Windows - true - true - wWinMainCRTStartup - - - - - - - - - - - Create - - - - - - - {3F92E998-2BF5-783D-D47A-B1F3C0BC44C0} - - - - - - \ No newline at end of file diff --git a/SHADE_Application/SHADE_Application.vcxproj.filters b/SHADE_Application/SHADE_Application.vcxproj.filters deleted file mode 100644 index 1234632d..00000000 --- a/SHADE_Application/SHADE_Application.vcxproj.filters +++ /dev/null @@ -1,30 +0,0 @@ - - - - - {D9DE78AF-4594-F1A4-CE88-EB7B3A3DE8A8} - - - {86EEB3D0-7290-DEA6-5B4B-F2FA478C65F7} - - - - - Application - - - - Scenes - - - - - Application - - - - Scenes - - - - \ No newline at end of file diff --git a/SHADE_Application/premake5.lua b/SHADE_Application/premake5.lua index d6efc890..50bd41b2 100644 --- a/SHADE_Application/premake5.lua +++ b/SHADE_Application/premake5.lua @@ -1,13 +1,13 @@ 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" - staticruntime "on" + staticruntime "off" entrypoint "wWinMainCRTStartup" system ("windows") @@ -15,7 +15,7 @@ project "SHADE_Application" { "%{prj.location}/src/**.h", "%{prj.location}/src/**.hpp", - "%{prj.location}/src/**.c", + "%{prj.location}/src/**.c", "%{prj.location}/src/**.cpp", "%{prj.location}/src/**.glsl", } @@ -23,7 +23,9 @@ project "SHADE_Application" includedirs { "../SHADE_Engine/src", - "src" + "src", + "%{IncludeDir.dotnet}/include", + "%{IncludeDir.SDL}/include", } externalincludedirs @@ -43,11 +45,16 @@ project "SHADE_Application" links { - "SHADE_Engine" + "SHADE_Engine", + "SHADE_Managed", + "SDL2.lib", + "SDL2main.lib" } - postbuildcommands + libdirs { + "%{IncludeDir.spdlog}/lib", + "%{IncludeDir.SDL}/lib", } defines @@ -55,6 +62,11 @@ project "SHADE_Application" "NOMINMAX" } + disablewarnings + { + "4251" + } + warnings 'Extra' filter "configurations:Debug" @@ -63,4 +75,4 @@ project "SHADE_Application" filter "configurations:Release" optimize "On" - defines{"_RELEASE"} \ No newline at end of file + defines{"_RELEASE"} diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index c47b8016..61be1ae0 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -8,9 +8,15 @@ //#include "Scenes/SBEditorScene.h" #endif // SHEDITOR +#include "Tools/SHLogger.h" +#include "Tools/SHFileUtilties.h" + #include #include #include +#include + +#include "Scripting/SHScriptEngine.h" namespace Sandbox { @@ -23,11 +29,15 @@ namespace Sandbox _In_ INT nCmdShow ) { - + // Set working directory + SHADE::SHFileUtilities::SetWorkDirToExecDir(); + + SDL_Init(SDL_INIT_VIDEO); window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow); SHADE::SHSystemManager::CreateSystem("Graphics System"); SHADE::SHGraphicsSystem* graphicsSystem = static_cast(SHADE::SHSystemManager::GetSystem("Graphics System")); graphicsSystem->SetWindow(&window); + SDL_CreateWindowFrom(window.GetHWND()); SHADE::SHSystemManager::Init(); #ifdef SHEDITOR @@ -35,6 +45,8 @@ namespace Sandbox #else #endif + // Set up scripting + SHADE::SHScriptEngine::Init(); } void SBApplication::Update(void) @@ -61,9 +73,9 @@ namespace Sandbox void SBApplication::Exit(void) { - //SHADE::SHEditor::Exit(); + SHADE::SHScriptEngine::Exit(); SHADE::SHSystemManager::Exit(); - + SDL_DestroyWindow(sdlWindow); #ifdef SHEDITOR #else #endif diff --git a/SHADE_Application/src/Application/SBApplication.h b/SHADE_Application/src/Application/SBApplication.h index 94e296b1..63626907 100644 --- a/SHADE_Application/src/Application/SBApplication.h +++ b/SHADE_Application/src/Application/SBApplication.h @@ -2,6 +2,7 @@ #define SB_APPLICATION_H #include #include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h" +#include //using namespace SHADE; namespace Sandbox @@ -10,6 +11,7 @@ namespace Sandbox { private: SHADE::SHWindow window; + SDL_Window* sdlWindow; //SHAppConfig config; public: SBApplication() = default; diff --git a/SHADE_Application/src/WinMain.cpp b/SHADE_Application/src/WinMain.cpp index ea1ac5fe..f672cead 100644 --- a/SHADE_Application/src/WinMain.cpp +++ b/SHADE_Application/src/WinMain.cpp @@ -26,15 +26,15 @@ INT WINAPI wWinMain ) { const SHADE::SHLogger::Config LOGGER_CONFIG{ .directoryPath = "./logs/" }; - SHADE::SHLogger::Initialise(LOGGER_CONFIG); + auto logger = SHADE::SHLogger::Initialise(LOGGER_CONFIG); try { #ifndef SHEDITOR //ShowWindow(::GetConsoleWindow(), SW_HIDE); - #endif + #endif - SHLOG_INFO("sup") + SHLOG_REGISTER(logger) SHADE::SHEngine::Run(hInstance, hPrevInstance, lpCmdLine, nCmdShow); _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); diff --git a/SHADE_Engine/SHADE_Engine.vcxproj b/SHADE_Engine/SHADE_Engine.vcxproj deleted file mode 100644 index 0925c31e..00000000 --- a/SHADE_Engine/SHADE_Engine.vcxproj +++ /dev/null @@ -1,280 +0,0 @@ - - - - - Debug - x64 - - - Release - x64 - - - - {3F92E998-2BF5-783D-D47A-B1F3C0BC44C0} - true - Win32Proj - SHADE_Engine - 10.0 - - - - StaticLibrary - true - Unicode - v142 - - - StaticLibrary - false - Unicode - v142 - - - - - - - - - - - - - bin\Debug_x86_64\SHADE_Engine\ - bin-int\Debug_x86_64\SHADE_Engine\ - SHADE_Engine - .lib - ..\Dependencies\assimp\include;..\Dependencies\imgui;..\Dependencies\imguizmo;..\Dependencies\imnodes;..\Dependencies\msdf;..\Dependencies\msdf\msdfgen;..\Dependencies\spdlog\include;..\Dependencies\tracy;..\Dependencies\VMA\include;..\Dependencies\yamlcpp\include;..\Dependencies\ktx\include;..\Dependencies\RTTR\include;..\Dependencies\reactphysics3d\include;$(VULKAN_SDK)\include;$(VULKAN_SDK)\Source\SPIRV-Reflect;$(IncludePath) - - - bin\Release_x86_64\SHADE_Engine\ - bin-int\Release_x86_64\SHADE_Engine\ - SHADE_Engine - .lib - ..\Dependencies\assimp\include;..\Dependencies\imgui;..\Dependencies\imguizmo;..\Dependencies\imnodes;..\Dependencies\msdf;..\Dependencies\msdf\msdfgen;..\Dependencies\spdlog\include;..\Dependencies\tracy;..\Dependencies\VMA\include;..\Dependencies\yamlcpp\include;..\Dependencies\ktx\include;..\Dependencies\RTTR\include;..\Dependencies\reactphysics3d\include;$(VULKAN_SDK)\include;$(VULKAN_SDK)\Source\SPIRV-Reflect;$(IncludePath) - - - - Use - SHpch.h - Level4 - _LIB;_GLFW_INCLUDE_NONE;MSDFGEN_USE_CPP11;NOMINMAX;_DEBUG;%(PreprocessorDefinitions) - src;%(AdditionalIncludeDirectories) - EditAndContinue - Disabled - false - MultiThreadedDebug - true - stdcpplatest - - - Windows - true - - - vulkan-1.lib;assimp-vc142-mtd.lib;ktxd.lib;librttr_core_d.lib;%(AdditionalDependencies) - libs;$(VULKAN_SDK)\Lib;..\Dependencies\assimp\lib\Debug;..\Dependencies\assimp\lib\Release;..\Dependencies\RTTR\lib;..\Dependencies\ktx\lib\Debug;..\Dependencies\ktx\lib\Release;%(AdditionalLibraryDirectories) - - - - - Use - SHpch.h - Level4 - _LIB;_GLFW_INCLUDE_NONE;MSDFGEN_USE_CPP11;NOMINMAX;_RELEASE;%(PreprocessorDefinitions) - src;%(AdditionalIncludeDirectories) - Full - true - true - false - true - MultiThreaded - true - stdcpplatest - - - Windows - true - true - - - vulkan-1.lib;assimp-vc142-mt.lib;ktx.lib;librttr_core.lib;%(AdditionalDependencies) - libs;$(VULKAN_SDK)\Lib;..\Dependencies\assimp\lib\Debug;..\Dependencies\assimp\lib\Release;..\Dependencies\RTTR\lib;..\Dependencies\ktx\lib\Debug;..\Dependencies\ktx\lib\Release;%(AdditionalLibraryDirectories) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - - - - - - - - - {88F1A057-74BE-FB62-9DD7-E90A890331F1} - - - {8900D8DD-F5DF-5679-FEF7-E14F6A56BDDA} - - - {38BD587B-248B-4C81-0D1F-BDA7F98B28E6} - - - {2ECAB41A-1A98-A820-032C-1947EF988485} - - - {C0FF640D-2C14-8DBE-F595-301E616989EF} - - - {8EAD431C-7A4F-6EF2-630A-82464F4BF542} - - - - - - \ No newline at end of file diff --git a/SHADE_Engine/SHADE_Engine.vcxproj.filters b/SHADE_Engine/SHADE_Engine.vcxproj.filters deleted file mode 100644 index 1810f10f..00000000 --- a/SHADE_Engine/SHADE_Engine.vcxproj.filters +++ /dev/null @@ -1,545 +0,0 @@ - - - - - {DBC7D3B0-C769-FE86-B024-12DB9C6585D7} - - - {7FF59BF8-EB80-09BD-F491-8CB1609C65BD} - - - {340D0110-201D-ADE0-89D6-11FF75059C79} - - - {EBFC8BDC-D7F6-B42E-C063-4B3FACFC1A9B} - - - {6CD692F2-D80D-DB89-E117-3FAD4DCE0183} - - - {B3E3FAFD-9FDD-2350-884A-BA6074E389BC} - - - {1653CE33-0220-293F-2B39-17E717655ECD} - - - {92C817CE-7EC1-3620-A7F3-1BA5934B162C} - - - {17C745C0-83DD-4356-CC54-CF7738AA14DE} - - - {51443AC7-3D28-FB1C-A688-F56F928BE59E} - - - {573A6CF2-43C9-F5BB-ECE7-09B7D8550662} - - - {08DBDC43-F4D3-FB95-1D06-E11A095EDBA1} - - - {4AD5CA42-3664-540C-DF82-6807CBF064B2} - - - {FB5EE099-67EA-4D5E-70FB-D052DC05AA5E} - - - {BA26540B-263D-52A1-6FB4-DDC2DB092329} - - - {4B204703-3704-0859-A064-02AC8C67F2DA} - - - {EBA1D3FF-D75C-C3AB-8014-3CF66CAE0D3C} - - - {8CDBA7C9-F8E8-D5AF-81CF-D19AEDDBA166} - - - {2460C057-1070-6C28-7929-D14665585BC1} - - - {FBD334F8-67EA-328E-B061-BEAF1CB70316} - - - {1DD51CAD-8960-8A71-9271-0D66FE7BE671} - - - {57DAB30C-4369-3DD6-EC87-51D1D8F54D7C} - - - {9C0DAFD9-086F-8CE7-91DC-D299FD3CC3A6} - - - {EF2D07CC-DB26-261E-0459-0BA3F0B0052A} - - - {3AEF06DD-A6D2-151D-AFD5-43591B38DC6D} - - - {245F5AB0-1085-2417-F9CA-A9E2E58F49E3} - - - {03DB39DE-EFBE-FA33-581F-F5864422E5B5} - - - {576DF841-4392-47C2-6CDD-2C52586146E0} - - - {75F29FE5-6102-4CB6-CABB-B0D4B6EA3A4F} - - - {5BAB2A92-478F-EBE7-B0EF-E53A9CF2D569} - - - {B3B14D12-9FC1-F9E2-087B-5E01F4A9E87B} - - - {AC05897C-983C-8A0D-4129-70102D3F060F} - - - {ED6CDF9B-D939-3AA7-0253-284FEE7E6F35} - - - {B3F7140E-1F0C-3DBF-E88D-E01E546139F0} - - - {16CF2D0E-82E3-55BF-4B65-F91EB73852F0} - - - - - Engine\ECS_Base\Components - - - Engine\ECS_Base\Components - - - Engine\ECS_Base\Entity - - - Engine\ECS_Base\General - - - Engine\ECS_Base\General - - - Engine\ECS_Base\General - - - Engine\ECS_Base\General - - - Engine\ECS_Base\General - - - Engine\ECS_Base - - - Engine\ECS_Base\System - - - Engine\ECS_Base\System - - - Engine\ECS_Base\System - - - Engine\ECS_Base\System - - - Engine - - - Graphics\Buffers - - - Graphics\Commands - - - Graphics\Commands - - - Graphics\Commands - - - Graphics\Debugging - - - Graphics\Debugging - - - Graphics\Debugging - - - Graphics\Descriptors - - - Graphics\Descriptors - - - Graphics\Descriptors - - - Graphics\Descriptors - - - Graphics\Descriptors - - - Graphics\Descriptors - - - Graphics\Devices - - - Graphics\Devices - - - Graphics\Devices - - - Graphics\Framebuffer - - - Graphics\Images - - - Graphics\Images - - - Graphics\Images - - - Graphics\Images - - - Graphics\Instance - - - Graphics\MiddleEnd\Interface - - - Graphics\MiddleEnd\Interface - - - Graphics\MiddleEnd\PerFrame - - - Graphics\MiddleEnd\PerFrame - - - Graphics\MiddleEnd\Shaders - - - Graphics\MiddleEnd\Shaders - - - Graphics\MiddleEnd\Shaders - - - Graphics\Pipeline - - - Graphics\Pipeline - - - Graphics\Pipeline - - - Graphics\Pipeline - - - Graphics\Pipeline - - - Graphics\Pipeline - - - Graphics\Queues - - - Graphics\RenderGraph - - - Graphics\Renderpass - - - Graphics\Renderpass - - - Graphics\Renderpass - - - Graphics\Renderpass - - - Graphics\Renderpass - - - Graphics - - - Graphics - - - Graphics - - - Graphics\Shaders\BlockInterface - - - Graphics\Shaders - - - Graphics\Shaders - - - Graphics\Shaders\spirv-reflect - - - Graphics\Swapchain - - - Graphics\Swapchain - - - Graphics\Synchronization - - - Graphics\Synchronization - - - Graphics\VertexDescriptors - - - Graphics\Windowing - - - Graphics\Windowing - - - Graphics\Windowing\Surface - - - Meta - - - Resource - - - Resource - - - Resource - - - Resource - - - Resource - - - Resource - - - - Scene - - - Scene - - - Tools - - - Tools - - - Tools - - - - - Engine\ECS_Base\Components - - - Engine\ECS_Base\Components - - - Engine\ECS_Base\Entity - - - Engine\ECS_Base\System - - - Engine\ECS_Base\System - - - Engine\ECS_Base\System - - - Engine - - - Graphics\Buffers - - - Graphics\Commands - - - Graphics\Commands - - - Graphics\Debugging - - - Graphics\Debugging - - - Graphics\Debugging - - - Graphics\Descriptors - - - Graphics\Descriptors - - - Graphics\Descriptors - - - Graphics\Descriptors - - - Graphics\Descriptors - - - Graphics\Descriptors - - - Graphics\Devices - - - Graphics\Devices - - - Graphics\Devices - - - Graphics\Framebuffer - - - Graphics\Images - - - Graphics\Images - - - Graphics\Images - - - Graphics\Instance - - - Graphics\MiddleEnd\Interface - - - Graphics\MiddleEnd\Interface - - - Graphics\MiddleEnd\PerFrame - - - Graphics\MiddleEnd\PerFrame - - - Graphics\MiddleEnd\Shaders - - - Graphics\MiddleEnd\Shaders - - - Graphics\Pipeline - - - Graphics\Pipeline - - - Graphics\Pipeline - - - Graphics\Pipeline - - - Graphics\Queues - - - Graphics\RenderGraph - - - Graphics\Renderpass - - - Graphics\Renderpass - - - Graphics\Renderpass - - - Graphics - - - Graphics - - - Graphics\Shaders\BlockInterface - - - Graphics\Shaders - - - Graphics\Shaders - - - Graphics\Shaders\spirv-reflect - - - Graphics\Swapchain - - - Graphics\Synchronization - - - Graphics\Synchronization - - - Graphics\VertexDescriptors - - - Graphics\Windowing - - - Graphics\Windowing - - - Graphics\Windowing\Surface - - - Resource - - - - Scene - - - Tools - - - Tools - - - Tools - - - \ No newline at end of file diff --git a/SHADE_Engine/premake5.lua b/SHADE_Engine/premake5.lua index c51b1ca6..74f19f96 100644 --- a/SHADE_Engine/premake5.lua +++ b/SHADE_Engine/premake5.lua @@ -1,13 +1,13 @@ 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" - staticruntime "on" + staticruntime "off" files { @@ -35,11 +35,12 @@ 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" @@ -51,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 @@ -62,8 +63,16 @@ project "SHADE_Engine" "msdf-atlas-gen", "reactphysics3d", "imgui", - "spdlog", - "vulkan-1.lib" + "vulkan-1.lib", + "SDL2.lib", + "SDL2main.lib", + "shaderc_shared.lib", + "shlwapi.lib" + } + + disablewarnings + { + "4251" } defines @@ -71,7 +80,8 @@ project "SHADE_Engine" "_LIB", "_GLFW_INCLUDE_NONE", "MSDFGEN_USE_CPP11", - "NOMINMAX" + "NOMINMAX", + "SH_API_EXPORT" } flags @@ -86,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' @@ -94,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"} \ No newline at end of file diff --git a/SHADE_Engine/src/Common/SHCommonTypes.h b/SHADE_Engine/src/Common/SHCommonTypes.h new file mode 100644 index 00000000..97ef7928 --- /dev/null +++ b/SHADE_Engine/src/Common/SHCommonTypes.h @@ -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; +} diff --git a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.cpp b/SHADE_Engine/src/ECS_Base/Components/SHComponent.cpp similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.cpp rename to SHADE_Engine/src/ECS_Base/Components/SHComponent.cpp diff --git a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.h b/SHADE_Engine/src/ECS_Base/Components/SHComponent.h similarity index 98% rename from SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.h rename to SHADE_Engine/src/ECS_Base/Components/SHComponent.h index c9c5e6f1..edd8436c 100644 --- a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.h +++ b/SHADE_Engine/src/ECS_Base/Components/SHComponent.h @@ -14,13 +14,14 @@ #include "SHpch.h" #include "../SHECSMacros.h" +#include "SH_API.h" namespace SHADE { class SHComponentManager; - class SHComponent + class SH_API SHComponent { friend SHComponentManager; diff --git a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.cpp b/SHADE_Engine/src/ECS_Base/Components/SHComponentGroup.cpp similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.cpp rename to SHADE_Engine/src/ECS_Base/Components/SHComponentGroup.cpp diff --git a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.h b/SHADE_Engine/src/ECS_Base/Components/SHComponentGroup.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.h rename to SHADE_Engine/src/ECS_Base/Components/SHComponentGroup.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.cpp b/SHADE_Engine/src/ECS_Base/Entity/SHEntity.cpp similarity index 97% rename from SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.cpp rename to SHADE_Engine/src/ECS_Base/Entity/SHEntity.cpp index 6005fb01..edf29ec7 100644 --- a/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.cpp +++ b/SHADE_Engine/src/ECS_Base/Entity/SHEntity.cpp @@ -28,7 +28,7 @@ namespace SHADE //SHEntityManager::RemoveEntity(this->entityID); } - EntityID SHEntity::GetEID() noexcept + EntityID SHEntity::GetEID() const noexcept { return this->entityID; } diff --git a/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.h b/SHADE_Engine/src/ECS_Base/Entity/SHEntity.h similarity index 98% rename from SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.h rename to SHADE_Engine/src/ECS_Base/Entity/SHEntity.h index d499042c..9077b0b9 100644 --- a/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.h +++ b/SHADE_Engine/src/ECS_Base/Entity/SHEntity.h @@ -15,6 +15,7 @@ #include "../Components/SHComponent.h" #include "../System/SHComponentManager.h" //#include "../../Scene/SHSceneNode.h" +#include "SH_API.h" @@ -23,7 +24,7 @@ namespace SHADE class SHComponentManager; class SHEntityManager; - class SHEntity + class SH_API SHEntity { public: @@ -77,7 +78,7 @@ namespace SHADE * \return uint32_t * The entityID of this Entity object. ***************************************************************************/ - EntityID GetEID() noexcept; + EntityID GetEID() const noexcept; /*!************************************************************************* * \brief Set the Active object diff --git a/SHADE_Engine/src/Engine/ECS_Base/General/SHFamily.h b/SHADE_Engine/src/ECS_Base/General/SHFamily.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/General/SHFamily.h rename to SHADE_Engine/src/ECS_Base/General/SHFamily.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/General/SHHandleGenerator.h b/SHADE_Engine/src/ECS_Base/General/SHHandleGenerator.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/General/SHHandleGenerator.h rename to SHADE_Engine/src/ECS_Base/General/SHHandleGenerator.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/General/SHSparseBase.h b/SHADE_Engine/src/ECS_Base/General/SHSparseBase.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/General/SHSparseBase.h rename to SHADE_Engine/src/ECS_Base/General/SHSparseBase.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/General/SHSparseSet.h b/SHADE_Engine/src/ECS_Base/General/SHSparseSet.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/General/SHSparseSet.h rename to SHADE_Engine/src/ECS_Base/General/SHSparseSet.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/General/SHSparseSetContainer.h b/SHADE_Engine/src/ECS_Base/General/SHSparseSetContainer.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/General/SHSparseSetContainer.h rename to SHADE_Engine/src/ECS_Base/General/SHSparseSetContainer.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/SHECSMacros.h b/SHADE_Engine/src/ECS_Base/SHECSMacros.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/SHECSMacros.h rename to SHADE_Engine/src/ECS_Base/SHECSMacros.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.cpp b/SHADE_Engine/src/ECS_Base/System/SHComponentManager.cpp similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.cpp rename to SHADE_Engine/src/ECS_Base/System/SHComponentManager.cpp diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.h b/SHADE_Engine/src/ECS_Base/System/SHComponentManager.h similarity index 99% rename from SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.h rename to SHADE_Engine/src/ECS_Base/System/SHComponentManager.h index 05a3d1ee..75db35d5 100644 --- a/SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.h +++ b/SHADE_Engine/src/ECS_Base/System/SHComponentManager.h @@ -19,13 +19,14 @@ #include "../Components/SHComponent.h" #include "../Components/SHComponentGroup.h" //#include "Scene/SHSceneNode.h" +#include "SH_API.h" #include namespace SHADE { - class SHComponentManager + class SH_API SHComponentManager { private: @@ -34,7 +35,7 @@ namespace SHADE //The Container of all Componentgroups static std::vector componentGroups; - friend class SHSceneNode; + friend struct SHSceneNode; diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.cpp b/SHADE_Engine/src/ECS_Base/System/SHEntityManager.cpp similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.cpp rename to SHADE_Engine/src/ECS_Base/System/SHEntityManager.cpp diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.h b/SHADE_Engine/src/ECS_Base/System/SHEntityManager.h similarity index 99% rename from SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.h rename to SHADE_Engine/src/ECS_Base/System/SHEntityManager.h index 11e896d5..802ef75d 100644 --- a/SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.h +++ b/SHADE_Engine/src/ECS_Base/System/SHEntityManager.h @@ -22,11 +22,12 @@ #include "../Components/SHComponent.h" #include "../General/SHHandleGenerator.h" #include "../SHECSMacros.h" +#include "SH_API.h" namespace SHADE { - class SHEntityManager + class SH_API SHEntityManager { private: static std::vector> entityVec; diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHSystem.h b/SHADE_Engine/src/ECS_Base/System/SHSystem.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/System/SHSystem.h rename to SHADE_Engine/src/ECS_Base/System/SHSystem.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.cpp b/SHADE_Engine/src/ECS_Base/System/SHSystemManager.cpp similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.cpp rename to SHADE_Engine/src/ECS_Base/System/SHSystemManager.cpp diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.h b/SHADE_Engine/src/ECS_Base/System/SHSystemManager.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.h rename to SHADE_Engine/src/ECS_Base/System/SHSystemManager.h diff --git a/SHADE_Engine/src/Events/SHEvent.h b/SHADE_Engine/src/Events/SHEvent.h new file mode 100644 index 00000000..2ca6648e --- /dev/null +++ b/SHADE_Engine/src/Events/SHEvent.h @@ -0,0 +1,22 @@ +/****************************************************************************** + * \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; + SHEventDataPtr dataPtr; + SHEventHandle handle; + }; +} diff --git a/SHADE_Engine/src/Events/SHEventDefines.h b/SHADE_Engine/src/Events/SHEventDefines.h new file mode 100644 index 00000000..76b403bd --- /dev/null +++ b/SHADE_Engine/src/Events/SHEventDefines.h @@ -0,0 +1,9 @@ +#pragma once +#include "SHpch.h" + +typedef uint32_t SHEventIdentifier; +typedef uint32_t SHEventHandle; +typedef void* SHEventDataPtr; + +//Add your event identifiers here: +constexpr SHEventIdentifier SH_EXAMPLE_EVENT{0}; \ No newline at end of file diff --git a/SHADE_Engine/src/Events/SHEventManager.cpp b/SHADE_Engine/src/Events/SHEventManager.cpp new file mode 100644 index 00000000..1cede2a0 --- /dev/null +++ b/SHADE_Engine/src/Events/SHEventManager.cpp @@ -0,0 +1,107 @@ +/****************************************************************************** + * \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 SHEventManager::packageReceiverRegistry; + std::unordered_map SHEventManager::dataEventMap; + + 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(SHEvent 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 + T* SHEventManager::BroadcastEvent(T data, SHEventIdentifier eventType) + { + SHEventDataPtr ptr = new std::byte[sizeof(data)]; + + std::memcpy(ptr, &data, sizeof(data)); + + CatchEvent( + { + eventType, + ptr, + handleCounter++ + } + ); + + return reinterpret_cast(ptr); + } + + /**************************************************************************** + * \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(SHEvent const& 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()); + //} + } +} diff --git a/SHADE_Engine/src/Events/SHEventManager.h b/SHADE_Engine/src/Events/SHEventManager.h new file mode 100644 index 00000000..f2f19fef --- /dev/null +++ b/SHADE_Engine/src/Events/SHEventManager.h @@ -0,0 +1,116 @@ +/****************************************************************************** + * \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 +#include + +/****************************************************************************** + 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, EVENT_IDENTIFIER); + + Headers required: SHEventManager.h + + On Receiver side: + 1. Create a function with the signature: + SHEventHandle FunctionName(SHEvent); + 2. In the init function of the class, copy the below in and replace the + necessary: + + std::shared_ptr> thisReceiver{ + std::make_shared>(this, &ReceiverClass::ReceiveFunction) + }; + ReceiverPtr receiver = std::dynamic_pointer_cast(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 void* + properly. + + Headers required: SHEventManager.h, SHEventReceiver.h + + If you have any questions/suggestions for improvement lmk. +******************************************************************************/ + +namespace SHADE +{ + using ResponseFunction = std::function; + using ReceiverPtr = std::shared_ptr; + using ResponseVec = std::vector; + using StaticResponseVec = std::vector; + + using EventManagerListener = std::function; + + 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(SHEvent); + + /**************************************************************************** + * \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 + static T* BroadcastEvent(T data, SHEventIdentifier eventType); + + private: + + // Registry for broadcasters and subscribers + static std::unordered_map packageReceiverRegistry; + static std::unordered_map dataEventMap; + + 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(SHEvent const&); + + /**************************************************************************** + * \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); + + }; + +} diff --git a/SHADE_Engine/src/Events/SHEventReceiver.h b/SHADE_Engine/src/Events/SHEventReceiver.h new file mode 100644 index 00000000..f968e579 --- /dev/null +++ b/SHADE_Engine/src/Events/SHEventReceiver.h @@ -0,0 +1,33 @@ +#pragma once + +#include "SHEvent.h" + +namespace SHADE +{ + class SHEventReceiver + { + private: + public: + virtual void Receive(SHEvent) = 0; + }; + + template + class SHEventReceiverSpec : public SHEventReceiver + { + private: + T* object; + SHEventHandle(T::*callback)(SHEvent); + + public: + SHEventReceiverSpec(T* obj, void(T::* cb)(SHEventDataPtr)) + :SHEventReceiver(), object{ obj }, callback{ cb } + { + + } + + void Receive(SHEvent evt) override + { + (object->*callback)(evt); + } + }; +} diff --git a/SHADE_Engine/src/FRC/SHFramerateController.cpp b/SHADE_Engine/src/FRC/SHFramerateController.cpp new file mode 100644 index 00000000..d64c6336 --- /dev/null +++ b/SHADE_Engine/src/FRC/SHFramerateController.cpp @@ -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 +#include +#include +#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 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; + } + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/FRC/SHFramerateController.h b/SHADE_Engine/src/FRC/SHFramerateController.h new file mode 100644 index 00000000..26f276d8 --- /dev/null +++ b/SHADE_Engine/src/FRC/SHFramerateController.h @@ -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 \ No newline at end of file diff --git a/SHADE_Engine/src/Filesystem/SHFileSystem.cpp b/SHADE_Engine/src/Filesystem/SHFileSystem.cpp new file mode 100644 index 00000000..5663dadd --- /dev/null +++ b/SHADE_Engine/src/Filesystem/SHFileSystem.cpp @@ -0,0 +1,135 @@ +#include "SHpch.h" +#include "SHFileSystem.h" +#include "fileapi.h" +#include +#include +#include + +namespace SHADE +{ + char const FOLDER_MAX_COUNT {15}; + + std::unordered_map> SHFileSystem::folders; + FolderPointer SHFileSystem::root {nullptr}; + + SHFolder::SHFolder(FolderHandle id, FolderName name) + :id{ id }, name{ name }, subFolders(0), folded{ false }, path{""} + { + } + + FolderLocation SHFileSystem::CreateNewFolderHere(FolderName name, FolderLocation here) noexcept + { + if (here == 0) + { + if (!folders.contains(0)) + { + folders[0] = std::make_unique(0, "root"); + } + + auto const count = static_cast(folders[here]->subFolders.size()); + + assert(count < FOLDER_MAX_COUNT, "Max subfolders reached\n"); + + auto const location = static_cast(count); + + CreateFolder(folders[0]->path, here, location, name); + + return location; + } + + assert(folders.contains(here), "Folder creation location does not exist/invalid\n"); + + auto const count = static_cast(folders[here]->subFolders.size()); + + FolderHandle location = here; + location <<= FOLDER_BIT_ALLOCATE; + location |= count; + + assert(count < FOLDER_MAX_COUNT, "Max subfolders reached\n"); + CreateFolder(folders[0]->path, here, location, name); + + return location; + } + + bool SHFileSystem::DeleteFolder(FolderPointer location) noexcept + { + assert(folders.contains(location->id), "Delete target does not exist/invalid.\n"); + + for (auto const& subFolder : folders[location->id]->subFolders) + { + DeleteFolder(subFolder); + } + + RemoveDirectoryA(folders[location->id]->path.c_str()); + return true; + } + + void SHFileSystem::StartupFillDirectories(FolderPath path) noexcept + { + std::queue folderQueue; + + folderQueue.push(RegisterFolder(path, 0, 0, "Root")); + + while (!folderQueue.empty()) + { + auto folder = folderQueue.front(); + folderQueue.pop(); + FolderCounter count = 0; + + for (auto const& dirEntry : std::filesystem::directory_iterator(folder->path)) + { + if (!dirEntry.is_directory()) + { + continue; + } + + FolderLocation location = folder->id; + location <<= FOLDER_BIT_ALLOCATE; + location |= ++count; + + std::string name = dirEntry.path().string(); + name = name.substr(name.find_last_of('/') + 1, name.length() - name.find_last_of('/')); + + FolderPointer newFolder{ RegisterFolder( + dirEntry.path().string(), + folder->id, + location, + name) + }; + + folderQueue.push(newFolder); + folder->subFolders.push_back(newFolder); + } + } + } + + FolderPointer SHFileSystem::CreateFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept + { + assert( + CreateDirectoryA(path.c_str(), nullptr), + "Failed to create folder\n" + ); + + folders[location] = std::make_unique(location, name); + folders[location]->path = path; + folders[parent]->subFolders.push_back(folders[location].get()); + + return FolderMakeHelper(path, parent, location, name); + } + + FolderPointer SHFileSystem::RegisterFolder(FolderPath path, FolderLocation parent, FolderHandle location, + FolderName name) noexcept + { + return FolderMakeHelper(path, parent, location, name); + } + + FolderPointer SHFileSystem::FolderMakeHelper(FolderPath path, FolderLocation parent, FolderHandle location, + FolderName name) noexcept + { + folders[location] = std::make_unique(location, name); + folders[location]->path = path; + folders[parent]->subFolders.push_back(folders[location].get()); + + return folders[location].get(); + } +} diff --git a/SHADE_Engine/src/Filesystem/SHFileSystem.h b/SHADE_Engine/src/Filesystem/SHFileSystem.h new file mode 100644 index 00000000..9b8b94a2 --- /dev/null +++ b/SHADE_Engine/src/Filesystem/SHFileSystem.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include +#include + +namespace SHADE +{ + class SHFolder; + + typedef unsigned char FolderCounter; + typedef unsigned char FileCounter; + typedef uint64_t FolderLocation; + typedef uint64_t FolderHandle; + typedef std::string FolderName; + typedef std::string FolderPath; + typedef SHFolder* FolderPointer; + + constexpr char FOLDER_BIT_ALLOCATE{ 4 }; + constexpr char FOLDER_MAX_DEPTH{ 16 }; + + class SHFolder + { + public: + SHFolder(FolderHandle id, FolderName name); + + FolderHandle id; + FolderName name; + std::vector subFolders; + + bool folded; + + private: + FolderPath path; + friend class SHFileSystem; + }; + + class SHFileSystem + { + public: + static FolderLocation CreateNewFolderHere(FolderName name, FolderLocation here = 0) noexcept; + + static bool DeleteFolder(FolderPointer location) noexcept; + + static void StartupFillDirectories(FolderPath path) noexcept; + + private: + static FolderPointer root; + + static std::unordered_map> folders; + + static FolderPointer CreateFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept; + static FolderPointer RegisterFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept; + static FolderPointer FolderMakeHelper(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 8c803e1d..eeaf6b12 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -21,7 +21,7 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/SHVulkanIncludes.h" #include "Graphics/MiddleEnd/PerFrame/SHRenderContext.h" #include "Graphics/RenderGraph/SHRenderGraph.h" -#include "Engine/ECS_Base/System/SHSystem.h" +#include "ECS_Base/System/SHSystem.h" #include "Graphics/Descriptors/SHVkDescriptorPool.h" namespace SHADE diff --git a/SHADE_Engine/src/Graphics/Windowing/SHWindow.h b/SHADE_Engine/src/Graphics/Windowing/SHWindow.h index a70058a1..1e08dcb0 100644 --- a/SHADE_Engine/src/Graphics/Windowing/SHWindow.h +++ b/SHADE_Engine/src/Graphics/Windowing/SHWindow.h @@ -5,6 +5,7 @@ #include #include #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; diff --git a/SHADE_Engine/src/Math/SHMath.h b/SHADE_Engine/src/Math/SHMath.h new file mode 100644 index 00000000..9763abe2 --- /dev/null +++ b/SHADE_Engine/src/Math/SHMath.h @@ -0,0 +1,9 @@ +#pragma once + +#include "SHMathHelpers.h" + +#include "Vector/SHVec2.h" +#include "Vector/SHVec3.h" +#include "Vector/SHVec4.h" + +#include "SHMatrix.h" \ No newline at end of file diff --git a/SHADE_Engine/src/Math/SHMathHelpers.cpp b/SHADE_Engine/src/Math/SHMathHelpers.cpp new file mode 100644 index 00000000..f3608778 --- /dev/null +++ b/SHADE_Engine/src/Math/SHMathHelpers.cpp @@ -0,0 +1,34 @@ +/**************************************************************************************** + * \file SHMathHelpers.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for various mathematical helper functions. + * + * \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 +#include + +// Primary Header +#include "SHMathHelpers.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Static Data Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + std::default_random_engine SHMath::rng; + + /*-----------------------------------------------------------------------------------*/ + /* Static Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHMath::Initialise() + { + const unsigned SEED = static_cast(std::chrono::system_clock::now().time_since_epoch().count()); + rng.seed(SEED); + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Math/SHMathHelpers.h b/SHADE_Engine/src/Math/SHMathHelpers.h new file mode 100644 index 00000000..9135230e --- /dev/null +++ b/SHADE_Engine/src/Math/SHMathHelpers.h @@ -0,0 +1,100 @@ +/**************************************************************************************** + * \file SHMathHelpers.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for various mathematical helper functions. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +#include +#include +#include +#include + + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Concepts */ + /*-----------------------------------------------------------------------------------*/ + + template + concept IsArithmetic = std::is_arithmetic_v; + + template + concept IsIntegral = std::is_integral_v; + + template + concept IsFloatingPoint = std::is_floating_point_v; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SHMath + { + public: + /*---------------------------------------------------------------------------------*/ + /* Static Data Members */ + /*---------------------------------------------------------------------------------*/ + + /** Standard Epsilon value for comparing Single-Precision Floating-Point values. */ + static constexpr float EPSILON = 0.001f; + + /** Single-Precision Floating-Point value of infinity */ + static constexpr float INF = std::numeric_limits::infinity(); + + static constexpr float PI = std::numbers::pi_v; + static constexpr float HALF_PI = PI * 0.5f; + static constexpr float TWO_PI = 2.0f * PI; + + /*---------------------------------------------------------------------------------*/ + /* Static Function Members */ + /*---------------------------------------------------------------------------------*/ + + static void Initialise (); + + template + [[nodiscard]] static constexpr T DegreesToRadians (T angleInDeg); + + template + [[nodiscard]] static constexpr T RadiansToDegrees (T angleInRad); + + template + [[nodiscard]] static T Lerp (T a, T b, T alpha); + + template + [[nodiscard]] static T ClampedLerp (T a, T b, T alpha, T alphaMin, T alphaMax); + + template + [[nodiscard]] static T Wrap (T value, T min, T max); + + template + [[nodiscard]] static T GenerateRandomNumber (T lowerBound = 0, T upperBound = 1); + + /** + * @brief Compares two floating-point values for equality within given tolerances. + * @tparam T A floating-point type + * @param lhs A floating-point value. + * @param rhs A floating-point value. + * @param absTolerance The absolute tolerance to compare the values for equality. + * @param relTolerance The relative tolerance for comparing large values for equality. + * @returns True if the values are equal within the specified tolerances. + */ + template + [[nodiscard]] static bool CompareFloat (T lhs, T rhs, T absTolerance = EPSILON, T relTolerance = EPSILON); + + private: + /*---------------------------------------------------------------------------------*/ + /* Static Data Members */ + /*---------------------------------------------------------------------------------*/ + static std::default_random_engine rng; + }; + +} // namespace SHADE + +#include "SHMathHelpers.hpp" \ No newline at end of file diff --git a/SHADE_Engine/src/Math/SHMathHelpers.hpp b/SHADE_Engine/src/Math/SHMathHelpers.hpp new file mode 100644 index 00000000..f0a1de12 --- /dev/null +++ b/SHADE_Engine/src/Math/SHMathHelpers.hpp @@ -0,0 +1,90 @@ +/**************************************************************************************** + * \file SHMathHelpers.hpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for various templated mathematical helper functions. + * + * \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 + +// Primary Header +#include "SHMathHelpers.h" + +#include +#include + +// TODOs (Diren): Include pch? + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Static Function Members Definitions */ + /*-----------------------------------------------------------------------------------*/ + + template + constexpr T SHMath::DegreesToRadians(T angleInDeg) + { + return angleInDeg * static_cast(PI / 180.0f); + } + + template + constexpr T SHMath::RadiansToDegrees(T angleInRad) + { + return angleInRad * static_cast(180.0f / PI); + } + + template + T SHMath::Lerp(T a, T b, T alpha) + { + return a + alpha * (b - a); + } + + template + T SHMath::ClampedLerp(T a, T b, T alpha, T alphaMin, T alphaMax) + { + const T T_ACTUAL = std::clamp(alpha, alphaMin, alphaMax); + return a + T_ACTUAL * (b - a); + } + + template + T SHMath::Wrap(T value, T min, T max) + { + while (value < min) + { + value = max - (min - value); + } + + while (value > max) + { + value = min + (value - max); + } + + return value; + } + + template + T SHMath::GenerateRandomNumber(T lowerBound, T upperBound) + { + if constexpr (IsIntegral) + { + std::uniform_int_distribution distribution(lowerBound, upperBound); + return distribution(rng); + } + if constexpr (IsFloatingPoint) + { + std::uniform_real_distribution distribution(lowerBound, upperBound); + return distribution(rng); + } + } + + + template + bool CompareFloat(T lhs, T rhs, T absTolerance, T relTolerance) + { + return std::fabs(lhs - rhs) <= std::max(absTolerance, relTolerance * std::max(abs(lhs), abs(rhs))); + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/SHMatrix.cpp b/SHADE_Engine/src/Math/SHMatrix.cpp new file mode 100644 index 00000000..8e8281d0 --- /dev/null +++ b/SHADE_Engine/src/Math/SHMatrix.cpp @@ -0,0 +1,601 @@ +/**************************************************************************************** + * \file SHMatrix.hpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Matrix. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#include + +// Primary Header +#include "SHMatrix.h" + +#include "Vector/SHVec2.h" +#include "Vector/SHVec3.h" +#include "Vector/SHVec4.h" +#include "SHQuaternion.h" + +using namespace DirectX; + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Static Data Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const SHMatrix SHMatrix::Identity + { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHMatrix::SHMatrix() noexcept + : XMFLOAT4X4 + ( + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ) + {} + + SHMatrix::SHMatrix + ( + const SHVec4& r0, const SHVec4& r1, + const SHVec4& r2, const SHVec4& r3 + ) noexcept + : XMFLOAT4X4 + ( + r0.x, r0.y, r0.z, r0.w, + r1.x, r1.y, r1.z, r1.w, + r2.x, r2.y, r2.z, r2.w, + r3.x, r3.y, r3.z, r3.w + ) + {} + + SHMatrix::SHMatrix + ( + float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33 + ) noexcept + : XMFLOAT4X4 + ( + m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33 + ) + {} + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHMatrix& SHMatrix::operator+=(const SHMatrix& rhs) noexcept + { + return *this = *this + rhs; + } + + SHMatrix& SHMatrix::operator-=(const SHMatrix& rhs) noexcept + { + return *this = *this - rhs; + } + + SHMatrix& SHMatrix::operator*=(const SHMatrix& rhs) noexcept + { + return *this = *this * rhs; + } + + SHMatrix& SHMatrix::operator*=(float rhs) noexcept + { + return *this = *this * rhs; + } + + SHMatrix& SHMatrix::operator/=(const SHMatrix& rhs) noexcept + { + return *this = *this / rhs; + } + + SHMatrix& SHMatrix::operator/=(float rhs) noexcept + { + return *this = *this / rhs; + } + + SHMatrix SHMatrix::operator+(const SHMatrix& rhs) const noexcept + { + SHMatrix result; + + const XMVECTOR L1 = XMLoadFloat4(reinterpret_cast(&_11)); + const XMVECTOR L2 = XMLoadFloat4(reinterpret_cast(&_21)); + const XMVECTOR L3 = XMLoadFloat4(reinterpret_cast(&_31)); + const XMVECTOR L4 = XMLoadFloat4(reinterpret_cast(&_41)); + + const XMVECTOR R1 = XMLoadFloat4(reinterpret_cast(&rhs._11)); + const XMVECTOR R2 = XMLoadFloat4(reinterpret_cast(&rhs._21)); + const XMVECTOR R3 = XMLoadFloat4(reinterpret_cast(&rhs._31)); + const XMVECTOR R4 = XMLoadFloat4(reinterpret_cast(&rhs._41)); + + XMStoreFloat4(reinterpret_cast(&result._11), XMVectorAdd(L1, R1)); + XMStoreFloat4(reinterpret_cast(&result._21), XMVectorAdd(L2, R2)); + XMStoreFloat4(reinterpret_cast(&result._31), XMVectorAdd(L3, R3)); + XMStoreFloat4(reinterpret_cast(&result._41), XMVectorAdd(L4, R4)); + + return result; + } + + SHMatrix SHMatrix::operator-(const SHMatrix& rhs) const noexcept + { + SHMatrix result; + + const XMVECTOR L1 = XMLoadFloat4(reinterpret_cast(&_11)); + const XMVECTOR L2 = XMLoadFloat4(reinterpret_cast(&_21)); + const XMVECTOR L3 = XMLoadFloat4(reinterpret_cast(&_31)); + const XMVECTOR L4 = XMLoadFloat4(reinterpret_cast(&_41)); + + const XMVECTOR R1 = XMLoadFloat4(reinterpret_cast(&rhs._11)); + const XMVECTOR R2 = XMLoadFloat4(reinterpret_cast(&rhs._21)); + const XMVECTOR R3 = XMLoadFloat4(reinterpret_cast(&rhs._31)); + const XMVECTOR R4 = XMLoadFloat4(reinterpret_cast(&rhs._41)); + + XMStoreFloat4(reinterpret_cast(&result._11), XMVectorSubtract(L1, R1)); + XMStoreFloat4(reinterpret_cast(&result._21), XMVectorSubtract(L2, R2)); + XMStoreFloat4(reinterpret_cast(&result._31), XMVectorSubtract(L3, R3)); + XMStoreFloat4(reinterpret_cast(&result._41), XMVectorSubtract(L4, R4)); + + return result; + } + + SHMatrix SHMatrix::operator-() const noexcept + { + SHMatrix result; + + const XMVECTOR L1 = XMLoadFloat4(reinterpret_cast(&_11)); + const XMVECTOR L2 = XMLoadFloat4(reinterpret_cast(&_21)); + const XMVECTOR L3 = XMLoadFloat4(reinterpret_cast(&_31)); + const XMVECTOR L4 = XMLoadFloat4(reinterpret_cast(&_41)); + + XMStoreFloat4(reinterpret_cast(&result._11), XMVectorNegate(L1)); + XMStoreFloat4(reinterpret_cast(&result._21), XMVectorNegate(L2)); + XMStoreFloat4(reinterpret_cast(&result._31), XMVectorNegate(L3)); + XMStoreFloat4(reinterpret_cast(&result._41), XMVectorNegate(L4)); + + return result; + } + + SHMatrix SHMatrix::operator*(const SHMatrix& rhs) const noexcept + { + SHMatrix result; + + const XMMATRIX M1 = XMLoadFloat4x4(this); + const XMMATRIX M2 = XMLoadFloat4x4(&rhs); + + XMStoreFloat4x4(&result, XMMatrixMultiply(M1, M2)); + return result; + } + + SHVec3 SHMatrix::operator*(const SHVec3& rhs) const noexcept + { + return SHVec3::Transform(rhs, *this); + } + + SHVec4 SHMatrix::operator*(const SHVec4& rhs) const noexcept + { + return SHVec4::Transform3D(rhs, *this); + } + + SHMatrix SHMatrix::operator*(float rhs) const noexcept + { + SHMatrix result; + + const XMVECTOR L1 = XMLoadFloat4(reinterpret_cast(&_11)); + const XMVECTOR L2 = XMLoadFloat4(reinterpret_cast(&_21)); + const XMVECTOR L3 = XMLoadFloat4(reinterpret_cast(&_31)); + const XMVECTOR L4 = XMLoadFloat4(reinterpret_cast(&_41)); + + XMStoreFloat4(reinterpret_cast(&result._11), XMVectorScale(L1, rhs)); + XMStoreFloat4(reinterpret_cast(&result._21), XMVectorScale(L2, rhs)); + XMStoreFloat4(reinterpret_cast(&result._31), XMVectorScale(L3, rhs)); + XMStoreFloat4(reinterpret_cast(&result._41), XMVectorScale(L4, rhs)); + + return result; + } + + SHMatrix SHMatrix::operator/(const SHMatrix& rhs) const noexcept + { + SHMatrix result; + + const XMVECTOR L1 = XMLoadFloat4(reinterpret_cast(&_11)); + const XMVECTOR L2 = XMLoadFloat4(reinterpret_cast(&_21)); + const XMVECTOR L3 = XMLoadFloat4(reinterpret_cast(&_31)); + const XMVECTOR L4 = XMLoadFloat4(reinterpret_cast(&_41)); + + const XMVECTOR R1 = XMLoadFloat4(reinterpret_cast(&rhs._11)); + const XMVECTOR R2 = XMLoadFloat4(reinterpret_cast(&rhs._21)); + const XMVECTOR R3 = XMLoadFloat4(reinterpret_cast(&rhs._31)); + const XMVECTOR R4 = XMLoadFloat4(reinterpret_cast(&rhs._41)); + + XMStoreFloat4(reinterpret_cast(&result._11), XMVectorDivide(L1, R1)); + XMStoreFloat4(reinterpret_cast(&result._21), XMVectorDivide(L2, R2)); + XMStoreFloat4(reinterpret_cast(&result._31), XMVectorDivide(L3, R3)); + XMStoreFloat4(reinterpret_cast(&result._41), XMVectorDivide(L4, R4)); + + return result; + } + + SHMatrix SHMatrix::operator/(float rhs) const noexcept + { + SHMatrix result; + + const XMVECTOR L1 = XMLoadFloat4(reinterpret_cast(&_11)); + const XMVECTOR L2 = XMLoadFloat4(reinterpret_cast(&_21)); + const XMVECTOR L3 = XMLoadFloat4(reinterpret_cast(&_31)); + const XMVECTOR L4 = XMLoadFloat4(reinterpret_cast(&_41)); + + const float INV_RHS = 1.0f / rhs; + + XMStoreFloat4(reinterpret_cast(&result._11), XMVectorScale(L1, INV_RHS)); + XMStoreFloat4(reinterpret_cast(&result._21), XMVectorScale(L2, INV_RHS)); + XMStoreFloat4(reinterpret_cast(&result._31), XMVectorScale(L3, INV_RHS)); + XMStoreFloat4(reinterpret_cast(&result._41), XMVectorScale(L4, INV_RHS)); + + return result; + } + + bool SHMatrix::operator==(const SHMatrix& rhs) const noexcept + { + const XMVECTOR L1 = XMLoadFloat4(reinterpret_cast(&_11)); + const XMVECTOR L2 = XMLoadFloat4(reinterpret_cast(&_21)); + const XMVECTOR L3 = XMLoadFloat4(reinterpret_cast(&_31)); + const XMVECTOR L4 = XMLoadFloat4(reinterpret_cast(&_41)); + + const XMVECTOR R1 = XMLoadFloat4(reinterpret_cast(&rhs._11)); + const XMVECTOR R2 = XMLoadFloat4(reinterpret_cast(&rhs._21)); + const XMVECTOR R3 = XMLoadFloat4(reinterpret_cast(&rhs._31)); + const XMVECTOR R4 = XMLoadFloat4(reinterpret_cast(&rhs._41)); + + return + ( + XMVector4Equal(L1, R1) + && XMVector4Equal(L2, R2) + && XMVector4Equal(L3, R4) + && XMVector4Equal(L4, R4) + ) != 0; + } + + + bool SHMatrix::operator!=(const SHMatrix& rhs) const noexcept + { + const XMVECTOR L1 = XMLoadFloat4(reinterpret_cast(&_11)); + const XMVECTOR L2 = XMLoadFloat4(reinterpret_cast(&_21)); + const XMVECTOR L3 = XMLoadFloat4(reinterpret_cast(&_31)); + const XMVECTOR L4 = XMLoadFloat4(reinterpret_cast(&_41)); + + const XMVECTOR R1 = XMLoadFloat4(reinterpret_cast(&rhs._11)); + const XMVECTOR R2 = XMLoadFloat4(reinterpret_cast(&rhs._21)); + const XMVECTOR R3 = XMLoadFloat4(reinterpret_cast(&rhs._31)); + const XMVECTOR R4 = XMLoadFloat4(reinterpret_cast(&rhs._41)); + + return + ( + XMVector4NotEqual(L1, R1) + || XMVector4NotEqual(L2, R2) + || XMVector4NotEqual(L3, R4) + || XMVector4NotEqual(L4, R4) + ) != 0; + } + + SHMatrix operator*(float lhs, const SHMatrix& rhs) noexcept + { + return rhs * lhs; + } + + + /*-----------------------------------------------------------------------------------*/ + /* Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHMatrix::Transpose() noexcept + { + const XMMATRIX M = XMLoadFloat4x4(this); + XMStoreFloat4x4(this, XMMatrixTranspose(M)); + } + + void SHMatrix::Invert() noexcept + { + const XMMATRIX M = XMLoadFloat4x4(this); + XMStoreFloat4x4(this, XMMatrixInverse(nullptr, M)); + } + + float SHMatrix::Determinant() const noexcept + { + const XMMATRIX M = XMLoadFloat4x4(this); + return XMVectorGetX(XMMatrixDeterminant(M)); + } + + std::string SHMatrix::ToString() const noexcept + { + std::stringstream ss; + ss << std::fixed << std::setprecision(3); + ss << "| " << _11 << ", " << _12 << ", " << _13 << ", " << _14 << " |\n"; + ss << "| " << _21 << ", " << _22 << ", " << _23 << ", " << _24 << " |\n"; + ss << "| " << _31 << ", " << _32 << ", " << _33 << ", " << _34 << " |\n"; + ss << "| " << _41 << ", " << _42 << ", " << _43 << ", " << _44 << " |"; + return ss.str(); + } + + + /*-----------------------------------------------------------------------------------*/ + /* Static Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHMatrix SHMatrix::Transpose(const SHMatrix& matrix) noexcept + { + SHMatrix result; + + const XMMATRIX M = XMLoadFloat4x4(&matrix); + XMStoreFloat4x4(&result, XMMatrixTranspose(M)); + return result; + } + + SHMatrix SHMatrix::Inverse(const SHMatrix& matrix) noexcept + { + SHMatrix result; + + const XMMATRIX M = XMLoadFloat4x4(&matrix); + XMStoreFloat4x4(&result, XMMatrixInverse(nullptr, M)); + return result; + } + + SHMatrix SHMatrix::Translate(float x, float y, float z) noexcept + { + SHMatrix result; + XMStoreFloat4x4(&result, XMMatrixTranslation(x, y, z)); + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::Translate(const SHVec3& pos) noexcept + { + SHMatrix result; + XMStoreFloat4x4(&result, XMMatrixTranslation(pos.x, pos.y, pos.z)); + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::Rotate(const SHVec3& axis, float angleInRad) noexcept + { + SHMatrix result; + + const XMVECTOR A = XMLoadFloat3(&axis); + XMStoreFloat4x4(&result, XMMatrixRotationAxis(A, angleInRad)); + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::Rotate(float yaw, float pitch, float roll) noexcept + { + SHMatrix result; + XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(pitch, yaw, roll)); + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::Rotate(const SHVec3& eulerAngles) noexcept + { + SHMatrix result; + XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(eulerAngles.x, eulerAngles.y, eulerAngles.z)); + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::Rotate(const SHQuaternion& q) noexcept + { + SHMatrix result; + + const XMVECTOR Q = XMLoadFloat4(&q); + XMStoreFloat4x4(&result, XMMatrixRotationQuaternion(Q)); + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::RotateX(float angleInRad) noexcept + { + SHMatrix result; + XMStoreFloat4x4(&result, XMMatrixRotationX(angleInRad)); + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::RotateY(float angleInRad) noexcept + { + SHMatrix result; + XMStoreFloat4x4(&result, XMMatrixRotationY(angleInRad)); + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::RotateZ(float angleInRad) noexcept + { + SHMatrix result; + XMStoreFloat4x4(&result, XMMatrixRotationZ(angleInRad)); + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::Scale(float uniformScaleFactor) noexcept + { + SHMatrix result; + XMStoreFloat4x4(&result, XMMatrixScaling(uniformScaleFactor, uniformScaleFactor, uniformScaleFactor)); + + return result; + } + + SHMatrix SHMatrix::Scale(float x, float y, float z) noexcept + { + SHMatrix result; + XMStoreFloat4x4(&result, XMMatrixScaling(x, y, z)); + + return result; + } + + SHMatrix SHMatrix::Scale(const SHVec3& scale) noexcept + { + SHMatrix result; + XMStoreFloat4x4(&result, XMMatrixScaling(scale.x, scale.y, scale.z)); + + return result; + } + + SHMatrix SHMatrix::LookAtRH(const SHVec3& eye, const SHVec3& target, const SHVec3& up) noexcept + { + SHMatrix result; + + const XMVECTOR EYE = XMLoadFloat3(&eye); + const XMVECTOR TGT = XMLoadFloat3(&target); + const XMVECTOR UP = XMLoadFloat3(&up); + + XMStoreFloat4x4(&result, XMMatrixLookAtRH(EYE, TGT, UP)); + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::LookAtLH(const SHVec3& eye, const SHVec3& target, const SHVec3& up) noexcept + { + SHMatrix result; + + const XMVECTOR EYE = XMLoadFloat3(&eye); + const XMVECTOR TGT = XMLoadFloat3(&target); + const XMVECTOR UP = XMLoadFloat3(&up); + + XMStoreFloat4x4(&result, XMMatrixLookAtLH(EYE, TGT, UP)); + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::CamToWorldRH(const SHVec3& pos, const SHVec3& forward, const SHVec3& up) noexcept + { + SHMatrix result; + + const SHVec3 FWD_HAT = SHVec3::Normalise(-forward); + + const XMVECTOR Z_HAT = XMVector3Normalize(XMLoadFloat3(&FWD_HAT)); + const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(XMLoadFloat3(&up), Z_HAT)); + const XMVECTOR Y_HAT = XMVector3Cross(Z_HAT, X_HAT); + + XMStoreFloat3(reinterpret_cast(&result._11), X_HAT); + XMStoreFloat3(reinterpret_cast(&result._21), Y_HAT); + XMStoreFloat3(reinterpret_cast(&result._31), Z_HAT); + + result._41 = pos.x; + result._42 = pos.y; + result._43 = pos.z; + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::CamToWorldLH(const SHVec3& pos, const SHVec3& forward, const SHVec3& up) noexcept + { + SHMatrix result; + + const SHVec3 FWD_HAT = SHVec3::Normalise(forward); + + const XMVECTOR Z_HAT = XMVector3Normalize(XMLoadFloat3(&FWD_HAT)); + const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(XMLoadFloat3(&up), Z_HAT)); + const XMVECTOR Y_HAT = XMVector3Cross(Z_HAT, X_HAT); + + XMStoreFloat3(reinterpret_cast(&result._11), X_HAT); + XMStoreFloat3(reinterpret_cast(&result._21), Y_HAT); + XMStoreFloat3(reinterpret_cast(&result._31), Z_HAT); + + result._41 = pos.x; + result._42 = pos.x; + result._43 = pos.x; + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::PerspectiveFovRH(float fov, float aspectRatio, float nearPlane, float farPlane) noexcept + { + SHMatrix result; + + XMStoreFloat4x4(&result, XMMatrixPerspectiveFovRH(fov, aspectRatio, nearPlane, farPlane)); + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::PerspectiveFovLH(float fov, float aspectRatio, float nearPlane, float farPlane) noexcept + { + SHMatrix result; + + XMStoreFloat4x4(&result, XMMatrixPerspectiveFovLH(fov, aspectRatio, nearPlane, farPlane)); + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::PerspectiveRH(float width, float height, float nearPlane, float farPlane) noexcept + { + SHMatrix result; + + XMStoreFloat4x4(&result, XMMatrixPerspectiveRH(width, height, nearPlane, farPlane)); + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::PerspectiveLH(float width, float height, float nearPlane, float farPlane) noexcept + { + SHMatrix result; + + XMStoreFloat4x4(&result, XMMatrixPerspectiveLH(width, height, nearPlane, farPlane)); + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::OrthographicRH(float width, float height, float nearPlane, float farPlane) noexcept + { + SHMatrix result; + + XMStoreFloat4x4(&result, XMMatrixOrthographicRH(width, height, nearPlane, farPlane)); + + result.Transpose(); + return result; + } + + SHMatrix SHMatrix::OrthographicLH(float width, float height, float nearPlane, float farPlane) noexcept + { + SHMatrix result; + + XMStoreFloat4x4(&result, XMMatrixOrthographicLH(width, height, nearPlane, farPlane)); + + result.Transpose(); + return result; + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/SHMatrix.h b/SHADE_Engine/src/Math/SHMatrix.h new file mode 100644 index 00000000..2aab05ab --- /dev/null +++ b/SHADE_Engine/src/Math/SHMatrix.h @@ -0,0 +1,144 @@ +/**************************************************************************************** + * \file SHMatrix.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Matrix. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +#include +#include + +#include "Vector/SHVec4.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + class SHVec2; + class SHVec3; + class SHVec4; + class SHQuaternion; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief Interface for a Column-Major Row Vector 4x4 Matrix. + */ + class SHMatrix : public DirectX::XMFLOAT4X4 + { + public: + /*---------------------------------------------------------------------------------*/ + /* Static Data Members */ + /*---------------------------------------------------------------------------------*/ + + static constexpr size_t SIZE = 16U; + static constexpr size_t NUM_ROWS = 4U; + static constexpr size_t NUM_COLS = 4U; + + static const SHMatrix Identity; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHMatrix (const SHMatrix& rhs) = default; + SHMatrix (SHMatrix&& rhs) = default; + ~SHMatrix () = default; + + SHMatrix () noexcept; + SHMatrix ( const SHVec4& r0, + const SHVec4& r1, + const SHVec4& r2, + const SHVec4& r3 = SHVec4::UnitW + ) noexcept; + SHMatrix ( + float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30 = 0.0f, float m31 = 0.0f, float m32 = 0.0f, float m33 = 1.0f + ) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHMatrix& operator= (const SHMatrix& rhs) = default; + SHMatrix& operator= (SHMatrix&& rhs) = default; + + SHMatrix& operator+= (const SHMatrix& rhs) noexcept; + SHMatrix& operator-= (const SHMatrix& rhs) noexcept; + SHMatrix& operator*= (const SHMatrix& rhs) noexcept; + SHMatrix& operator*= (float rhs) noexcept; + SHMatrix& operator/= (const SHMatrix& rhs) noexcept; + SHMatrix& operator/= (float rhs) noexcept; + + SHMatrix operator+ (const SHMatrix& rhs) const noexcept; + SHMatrix operator- (const SHMatrix& rhs) const noexcept; + SHMatrix operator- () const noexcept; + SHMatrix operator* (const SHMatrix& rhs) const noexcept; + SHVec3 operator* (const SHVec3& rhs) const noexcept; + SHVec4 operator* (const SHVec4& rhs) const noexcept; + SHMatrix operator* (float rhs) const noexcept; + SHMatrix operator/ (const SHMatrix& rhs) const noexcept; + SHMatrix operator/ (float rhs) const noexcept; + + bool operator== (const SHMatrix& rhs) const noexcept; + bool operator!= (const SHMatrix& rhs) const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + void Transpose () noexcept; + void Invert () noexcept; + + [[nodiscard]] float Determinant () const noexcept; + [[nodiscard]] std::string ToString () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Static Function Members */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] static SHMatrix Transpose (const SHMatrix& matrix) noexcept; + [[nodiscard]] static SHMatrix Inverse (const SHMatrix& matrix) noexcept; + + [[nodiscard]] static SHMatrix Translate (float x, float y, float z) noexcept; + [[nodiscard]] static SHMatrix Translate (const SHVec3& pos) noexcept; + + [[nodiscard]] static SHMatrix Rotate (const SHVec3& axis, float angleInRad) noexcept; + [[nodiscard]] static SHMatrix Rotate (float yaw, float pitch, float roll) noexcept; + [[nodiscard]] static SHMatrix Rotate (const SHVec3& eulerAngles) noexcept; + [[nodiscard]] static SHMatrix Rotate (const SHQuaternion& q) noexcept; + [[nodiscard]] static SHMatrix RotateX (float angleInRad) noexcept; + [[nodiscard]] static SHMatrix RotateY (float angleInRad) noexcept; + [[nodiscard]] static SHMatrix RotateZ (float angleInRad) noexcept; + + [[nodiscard]] static SHMatrix Scale (float uniformScaleFactor) noexcept; + [[nodiscard]] static SHMatrix Scale (float x, float y, float z) noexcept; + [[nodiscard]] static SHMatrix Scale (const SHVec3& scale) noexcept; + + [[nodiscard]] static SHMatrix LookAtRH (const SHVec3& eye, const SHVec3& target, const SHVec3& up) noexcept; + [[nodiscard]] static SHMatrix LookAtLH (const SHVec3& eye, const SHVec3& target, const SHVec3& up) noexcept; + [[nodiscard]] static SHMatrix CamToWorldRH (const SHVec3& pos, const SHVec3& forward, const SHVec3& up) noexcept; + [[nodiscard]] static SHMatrix CamToWorldLH (const SHVec3& pos, const SHVec3& forward, const SHVec3& up) noexcept; + [[nodiscard]] static SHMatrix PerspectiveFovRH (float fov, float aspectRatio, float nearPlane, float farPlane) noexcept; + [[nodiscard]] static SHMatrix PerspectiveFovLH (float fov, float aspectRatio, float nearPlane, float farPlane) noexcept; + [[nodiscard]] static SHMatrix PerspectiveRH (float width, float height, float nearPlane, float farPlane) noexcept; + [[nodiscard]] static SHMatrix PerspectiveLH (float width, float height, float nearPlane, float farPlane) noexcept; + [[nodiscard]] static SHMatrix OrthographicRH (float width, float height, float nearPlane, float farPlane) noexcept; + [[nodiscard]] static SHMatrix OrthographicLH (float width, float height, float nearPlane, float farPlane) noexcept; + + // TODO(Diren): Billboard, Shadow, Projection & Reflection + }; + + SHMatrix operator*(float lhs, const SHMatrix& rhs) noexcept; + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/SHQuaternion.cpp b/SHADE_Engine/src/Math/SHQuaternion.cpp new file mode 100644 index 00000000..208f131d --- /dev/null +++ b/SHADE_Engine/src/Math/SHQuaternion.cpp @@ -0,0 +1,308 @@ +/**************************************************************************************** + * \file SHQuaternion.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Quaternion. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#include + +// Primary Header +#include "SHQuaternion.h" +// Project Headers +#include "Vector/SHVec3.h" +#include "SHMatrix.h" +#include "Tools/SHLogger.h" + +using namespace DirectX; + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Static Data Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const SHQuaternion SHQuaternion::Identity{ 0.0f, 0.0f, 0.0f, 1.0f }; + + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHQuaternion::SHQuaternion() noexcept + : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) + {} + + SHQuaternion::SHQuaternion(float _x, float _y, float _z, float _w) noexcept + : XMFLOAT4( _x, _y, _z, _w ) + {} + + SHQuaternion::SHQuaternion(float yaw, float pitch, float roll) noexcept + : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) + { + XMStoreFloat4(this, XMQuaternionRotationRollPitchYaw(pitch, yaw, roll)); + } + + SHQuaternion::SHQuaternion(const SHVec3& eulerAngles) noexcept + : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) + { + const XMVECTOR V = XMLoadFloat3(&eulerAngles); + XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(V)); + } + + SHQuaternion::SHQuaternion(const SHVec3& axis, float angleInRad) noexcept + : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) + { + const XMVECTOR AXIS = XMLoadFloat3(&axis); + XMStoreFloat4(this, XMQuaternionRotationAxis(AXIS, angleInRad)); + } + + SHQuaternion::SHQuaternion(const SHMatrix& rotationMatrix) noexcept + : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) + { + const XMMATRIX M = XMLoadFloat4x4(&rotationMatrix); + XMStoreFloat4(this, XMQuaternionRotationMatrix(M)); + } + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHQuaternion& SHQuaternion::operator+=(const SHQuaternion& rhs) noexcept + { + return *this = *this + rhs; + } + + SHQuaternion& SHQuaternion::operator-=(const SHQuaternion& rhs) noexcept + { + return *this = *this - rhs; + } + + SHQuaternion& SHQuaternion::operator*=(const SHQuaternion& rhs) noexcept + { + return *this = *this * rhs; + } + + SHQuaternion& SHQuaternion::operator*=(float rhs) noexcept + { + return *this = *this * rhs; + } + + SHQuaternion& SHQuaternion::operator/=(const SHQuaternion& rhs) noexcept + { + return *this = *this / rhs; + } + + SHQuaternion SHQuaternion::operator+(const SHQuaternion& rhs) const noexcept + { + SHQuaternion result; + + const XMVECTOR Q1 = XMLoadFloat4(this); + const XMVECTOR Q2 = XMLoadFloat4(&rhs); + + XMStoreFloat4(&result, XMVectorAdd(Q1, Q2)); + return result; + } + + SHQuaternion SHQuaternion::operator-(const SHQuaternion& rhs) const noexcept + { + SHQuaternion result; + + const XMVECTOR Q1 = XMLoadFloat4(this); + const XMVECTOR Q2 = XMLoadFloat4(&rhs); + + XMStoreFloat4(&result, XMVectorSubtract(Q1, Q2)); + return result; + } + + SHQuaternion SHQuaternion::operator-() const noexcept + { + SHQuaternion result; + + const XMVECTOR Q = XMLoadFloat4(this); + + XMStoreFloat4(&result, XMVectorNegate(Q)); + return result; + } + + SHQuaternion SHQuaternion::operator*(const SHQuaternion& rhs) const noexcept + { + SHQuaternion result; + + const XMVECTOR Q1 = XMLoadFloat4(this); + const XMVECTOR Q2 = XMLoadFloat4(&rhs); + + XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q2)); + return result; + } + + SHQuaternion SHQuaternion::operator*(float rhs) const noexcept + { + SHQuaternion result; + + const XMVECTOR Q = XMLoadFloat4(this); + + XMStoreFloat4(&result, XMVectorScale(Q, rhs)); + return result; + } + + SHQuaternion SHQuaternion::operator/(const SHQuaternion& rhs) const noexcept + { + SHQuaternion result; + + const XMVECTOR Q1 = XMLoadFloat4(this); + const XMVECTOR Q2 = XMQuaternionInverse(XMLoadFloat4(&rhs)); + + XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q2)); + return result; + } + + bool SHQuaternion::operator==(const SHQuaternion& rhs) const noexcept + { + const XMVECTOR Q1 = XMLoadFloat4(this); + const XMVECTOR Q2 = XMLoadFloat4(&rhs); + + return XMQuaternionEqual(Q1, Q2); + } + + bool SHQuaternion::operator!=(const SHQuaternion& rhs) const noexcept + { + const XMVECTOR Q1 = XMLoadFloat4(this); + const XMVECTOR Q2 = XMLoadFloat4(&rhs); + + return XMQuaternionNotEqual(Q1, Q2); + } + + SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept + { + return rhs * lhs; + } + + /*-----------------------------------------------------------------------------------*/ + /* Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHQuaternion::Invert() noexcept + { + const XMVECTOR Q = XMLoadFloat4(this); + XMStoreFloat4(this, XMQuaternionInverse(Q)); + } + + float SHQuaternion::Length() const noexcept + { + const XMVECTOR Q = XMLoadFloat4(this); + return XMVectorGetX(XMQuaternionLength(Q)); + } + + float SHQuaternion::LengthSquared() const noexcept + { + const XMVECTOR Q = XMLoadFloat4(this); + return XMVectorGetX(XMQuaternionLengthSq(Q)); + } + + float SHQuaternion::Dot(const SHQuaternion& rhs) const noexcept + { + const XMVECTOR Q1 = XMLoadFloat4(this); + const XMVECTOR Q2 = XMLoadFloat4(&rhs); + + return XMVectorGetX(XMQuaternionDot(Q1, Q2)); + } + + SHQuaternion SHQuaternion::RotateTowards(const SHQuaternion&, float) const noexcept + { + SHQuaternion result; + + // TODO (Diren) + + return result; + } + + SHVec3 SHQuaternion::ToEuler() const noexcept + { + // TODO (Diren) + + return SHVec3::Zero; + } + + std::string SHQuaternion::ToString() const noexcept + { + std::stringstream ss; + ss << std::fixed << std::setprecision(3); + ss << "<" << x << ", " << y << ", " << z << ", " << w <<">"; + return ss.str(); + } + + /*-----------------------------------------------------------------------------------*/ + /* Static Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHQuaternion SHQuaternion::Normalise(const SHQuaternion& q) noexcept + { + SHQuaternion result; + + const XMVECTOR Q = XMLoadFloat4(&q); + + XMStoreFloat4(&result, XMQuaternionNormalize(Q)); + return result; + } + + SHQuaternion SHQuaternion::Conjugate(const SHQuaternion& q) noexcept + { + SHQuaternion result; + + const XMVECTOR Q = XMLoadFloat4(&q); + + XMStoreFloat4(&result, XMQuaternionConjugate(Q)); + return result; + } + + SHQuaternion SHQuaternion::Inverse(const SHQuaternion& q) noexcept + { + SHQuaternion result; + + const XMVECTOR Q = XMLoadFloat4(&q); + XMStoreFloat4(&result, XMQuaternionInverse(Q)); + + return result; + } + + + float SHQuaternion::Angle(const SHQuaternion&, const SHQuaternion&) noexcept + { + // TODO (Diren) + + return 0.0f; + } + + SHQuaternion SHQuaternion::Lerp(const SHQuaternion&, const SHQuaternion&, float) noexcept + { + SHQuaternion result; + + // TODO (Diren) + + return result; + } + + SHQuaternion SHQuaternion::Slerp(const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept + { + SHQuaternion result; + + const XMVECTOR Q1 = XMLoadFloat4(&q1); + const XMVECTOR Q2 = XMLoadFloat4(&q2); + + XMStoreFloat4(&result, XMQuaternionSlerp(Q1, Q2, t)); + return result; + } + + SHQuaternion SHQuaternion::Rotate(const SHVec3& , const SHVec3&) noexcept + { + SHQuaternion result; + + // TODO (Diren) + + return result; + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/SHQuaternion.h b/SHADE_Engine/src/Math/SHQuaternion.h new file mode 100644 index 00000000..27088284 --- /dev/null +++ b/SHADE_Engine/src/Math/SHQuaternion.h @@ -0,0 +1,106 @@ +/**************************************************************************************** + * \file SHQuaternion.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Quaternion. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +#include +#include + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + + class SHVec3; + class SHMatrix; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SHQuaternion : public DirectX::XMFLOAT4 + { + public: + /*---------------------------------------------------------------------------------*/ + /* Static Data Members */ + /*---------------------------------------------------------------------------------*/ + + static const SHQuaternion Identity; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHQuaternion (const SHQuaternion& rhs) = default; + SHQuaternion (SHQuaternion&& rhs) = default; + + SHQuaternion () noexcept; + SHQuaternion (float x, float y, float z, float w) noexcept; + SHQuaternion (float yaw, float pitch, float roll) noexcept; + SHQuaternion (const SHVec3& eulerAngles) noexcept; + SHQuaternion (const SHVec3& axis, float angleInRad) noexcept; + SHQuaternion (const SHMatrix& rotationMatrix) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] SHQuaternion& operator= (const SHQuaternion& rhs) = default; + [[nodiscard]] SHQuaternion& operator= (SHQuaternion&& rhs) = default; + + [[nodiscard]] SHQuaternion& operator+= (const SHQuaternion& rhs) noexcept; + [[nodiscard]] SHQuaternion& operator-= (const SHQuaternion& rhs) noexcept; + [[nodiscard]] SHQuaternion& operator*= (const SHQuaternion& rhs) noexcept; + [[nodiscard]] SHQuaternion& operator*= (float rhs) noexcept; + [[nodiscard]] SHQuaternion& operator/= (const SHQuaternion& rhs) noexcept; + + [[nodiscard]] SHQuaternion operator+ (const SHQuaternion& rhs) const noexcept; + [[nodiscard]] SHQuaternion operator- (const SHQuaternion& rhs) const noexcept; + [[nodiscard]] SHQuaternion operator- () const noexcept; + [[nodiscard]] SHQuaternion operator* (const SHQuaternion& rhs) const noexcept; + [[nodiscard]] SHQuaternion operator* (float rhs) const noexcept; + [[nodiscard]] SHQuaternion operator/ (const SHQuaternion& rhs) const noexcept; + + [[nodiscard]] bool operator== (const SHQuaternion& rhs) const noexcept; + [[nodiscard]] bool operator!= (const SHQuaternion& rhs) const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + void Invert () noexcept; + + [[nodiscard]] float Length () const noexcept; + [[nodiscard]] float LengthSquared () const noexcept; + [[nodiscard]] float Dot (const SHQuaternion& rhs) const noexcept; + [[nodiscard]] SHQuaternion RotateTowards (const SHQuaternion& target, float maxAngleInRad) const noexcept; + + [[nodiscard]] SHVec3 ToEuler () const noexcept; + [[nodiscard]] std::string ToString () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Static Function Members */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] static SHQuaternion Normalise (const SHQuaternion& q) noexcept; + [[nodiscard]] static SHQuaternion Conjugate (const SHQuaternion& q) noexcept; + [[nodiscard]] static SHQuaternion Inverse (const SHQuaternion& q) noexcept; + [[nodiscard]] static float Angle (const SHQuaternion& q1, const SHQuaternion& q2) noexcept; + + [[nodiscard]] static SHQuaternion Lerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept; + [[nodiscard]] static SHQuaternion Slerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept; + + [[nodiscard]] static SHQuaternion Rotate (const SHVec3& from, const SHVec3& to) noexcept; + }; + + SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept; + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Vector/SHVec2.cpp b/SHADE_Engine/src/Math/Vector/SHVec2.cpp new file mode 100644 index 00000000..72c80a50 --- /dev/null +++ b/SHADE_Engine/src/Math/Vector/SHVec2.cpp @@ -0,0 +1,460 @@ +/**************************************************************************************** + * \file SHVec2.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for 2D Vector. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#include + +// Primary Header +#include "SHVec2.h" +// Project Headers +#include "Math/SHMatrix.h" +#include "Tools/SHLogger.h" + +using namespace DirectX; + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Static Data Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + SHVec2 const SHVec2::Zero { 0.0f, 0.0f }; + SHVec2 const SHVec2::One { 1.0f, 1.0f }; + SHVec2 const SHVec2::Left { -1.0f, 0.0f }; + SHVec2 const SHVec2::Right { 1.0f, 0.0f }; + SHVec2 const SHVec2::Up { 0.0f, 1.0f }; + SHVec2 const SHVec2::Down { 0.0f, -1.0f }; + + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHVec2::SHVec2() noexcept + : XMFLOAT2( 0.0f, 0.0f ) + {} + + SHVec2::SHVec2(float _x, float _y) noexcept + : XMFLOAT2( _x, _y ) + {} + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHVec2& SHVec2::operator+=(const SHVec2& rhs) noexcept + { + return *this = *this + rhs; + } + + SHVec2& SHVec2::operator-=(const SHVec2& rhs) noexcept + { + return *this = *this - rhs; + } + + SHVec2& SHVec2::operator*=(const SHVec2& rhs) noexcept + { + return *this = *this * rhs; + } + + SHVec2& SHVec2::operator*=(float rhs) noexcept + { + return *this = *this * rhs; + } + + SHVec2& SHVec2::operator/=(const SHVec2& rhs) noexcept + { + return *this = *this / rhs; + } + + SHVec2& SHVec2::operator/=(float rhs) noexcept + { + return *this = *this / rhs; + } + + SHVec2 SHVec2::operator+(const SHVec2& rhs) const noexcept + { + SHVec2 result; + + const XMVECTOR V1 = XMLoadFloat2(this); + const XMVECTOR V2 = XMLoadFloat2(&rhs); + + XMStoreFloat2(&result, XMVectorAdd(V1, V2)); + return result; + } + + SHVec2 SHVec2::operator-(const SHVec2& rhs) const noexcept + { + SHVec2 result; + + const XMVECTOR V1 = XMLoadFloat2(this); + const XMVECTOR V2 = XMLoadFloat2(&rhs); + + XMStoreFloat2(&result, XMVectorSubtract(V1, V2)); + return result; + } + + SHVec2 SHVec2::operator-() const noexcept + { + return SHVec2{ -x, -y }; + } + + SHVec2 SHVec2::operator*(const SHVec2& rhs) const noexcept + { + SHVec2 result; + + const XMVECTOR V1 = XMLoadFloat2(this); + const XMVECTOR V2 = XMLoadFloat2(&rhs); + + XMStoreFloat2(&result, XMVectorMultiply(V1, V2)); + return result; + } + + SHVec2 SHVec2::operator*(float rhs) const noexcept + { + SHVec2 result; + + const XMVECTOR V = XMLoadFloat2(this); + + XMStoreFloat2(&result, XMVectorScale(V, rhs)); + return result; + } + + SHVec2 SHVec2::operator/(const SHVec2& rhs) const noexcept + { + SHVec2 result; + + const XMVECTOR V1 = XMLoadFloat2(this); + const XMVECTOR V2 = XMLoadFloat2(&rhs); + + XMStoreFloat2(&result, XMVectorDivide(V1, V2)); + return result; + } + + SHVec2 SHVec2::operator/(float rhs) const noexcept + { + SHVec2 result; + + const XMVECTOR V = XMLoadFloat2(this); + + XMStoreFloat2(&result, XMVectorScale(V, 1.0f / rhs)); + return result; + } + + bool SHVec2::operator==(const SHVec2& rhs) const noexcept + { + const XMVECTOR V1 = XMLoadFloat2(this); + const XMVECTOR V2 = XMLoadFloat2(&rhs); + + return XMVector2Equal(V1, V2); + } + + bool SHVec2::operator!=(const SHVec2& rhs) const noexcept + { + const XMVECTOR V1 = XMLoadFloat2(this); + const XMVECTOR V2 = XMLoadFloat2(&rhs); + + return XMVector2NotEqual(V1, V2); + } + + float SHVec2::operator[](int index) + { + if (index >= SIZE || index < 0) + throw std::invalid_argument("Index out of range!"); + + switch (index) + { + case 0: return x; + case 1: return y; + default: return 0.0f; + } + } + + float SHVec2::operator[](size_t index) + { + if (index >= SIZE) + throw std::invalid_argument("Index out of range!"); + + switch (index) + { + case 0: return x; + case 1: return y; + default: return 0.0f; + } + } + + float SHVec2::operator[](int index) const + { + if (index >= SIZE || index < 0) + throw std::invalid_argument("Index out of range!"); + + switch (index) + { + case 0: return x; + case 1: return y; + default: return 0.0f; + } + } + + float SHVec2::operator[](size_t index) const + { + if (index >= SIZE) + throw std::invalid_argument("Index out of range!"); + + switch (index) + { + case 0: return x; + case 1: return y; + default: return 0.0f; + } + } + + SHVec2 operator* (float lhs, const SHVec2& rhs) noexcept + { + SHVec2 result; + + const XMVECTOR V = XMLoadFloat2(&rhs); + + XMStoreFloat2(&result, XMVectorScale(V, lhs)); + return result; + } + + /*-----------------------------------------------------------------------------------*/ + /* Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + float SHVec2::Length() const noexcept + { + const XMVECTOR V = XMLoadFloat2(this); + + return XMVectorGetX(XMVector2Length(V)); + } + + float SHVec2::LengthSquared() const noexcept + { + const XMVECTOR V = XMLoadFloat2(this); + + return XMVectorGetX(XMVector2LengthSq(V)); + } + + std::string SHVec2::ToString() const noexcept + { + std::stringstream ss; + ss << std::fixed << std::setprecision(3); + ss << "<" << x << ", " << y << ">"; + return ss.str(); + } + + float SHVec2::Dot(const SHVec2& rhs) const noexcept + { + const XMVECTOR V1 = XMLoadFloat2(this); + const XMVECTOR V2 = XMLoadFloat2(&rhs); + + return XMVectorGetX(XMVector2Dot(V1, V2)); + } + + SHVec2 SHVec2::Cross(const SHVec2& rhs) const noexcept + { + SHVec2 result; + + const XMVECTOR V1 = XMLoadFloat2(this); + const XMVECTOR V2 = XMLoadFloat2(&rhs); + + XMStoreFloat2(&result, XMVector2Cross(V1, V2)); + return result; + } + + /*-----------------------------------------------------------------------------------*/ + /* Static Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHVec2 SHVec2::Normalise(const SHVec2& vec2) noexcept + { + SHVec2 result; + + const XMVECTOR V = XMLoadFloat2(&vec2); + + XMStoreFloat2(&result, XMVector2Normalize(V)); + return result; + } + + SHVec2 SHVec2::Abs(const SHVec2& vec2) noexcept + { + return SHVec2{ std::fabs(vec2.x), std::fabs(vec2.y) }; + } + + SHVec2 SHVec2::Min(const std::initializer_list& vec2s) noexcept + { + if (vec2s.size() == 0) + { + SHLOG_WARNING("No arguments passed in! Min value is a default SHVec2.") + return SHVec2{}; + } + + SHVec2 result; + + XMVECTOR min = XMLoadFloat2(&(*vec2s.begin())); + for (auto it = vec2s.begin() + 1; it != vec2s.end(); ++it) + { + const XMVECTOR tmp = XMLoadFloat2(&(*it)); + min = XMVectorMin(min, tmp); + } + + XMStoreFloat2(&result, min); + return result; + } + + SHVec2 SHVec2::Max(const std::initializer_list& vec2s) noexcept + { + if (vec2s.size() == 0) + { + SHLOG_WARNING("No arguments passed in! Max value is a default SHVec2.") + return SHVec2{}; + } + + SHVec2 result; + + XMVECTOR max = XMLoadFloat2(&(*vec2s.begin())); + for (auto it = vec2s.begin() + 1; it != vec2s.end(); ++it) + { + const XMVECTOR tmp = XMLoadFloat2(&(*it)); + max = XMVectorMax(max, tmp); + } + + XMStoreFloat2(&result, max); + return result; + } + + SHVec2 SHVec2::Clamp(const SHVec2& v, const SHVec2& vMin, const SHVec2& vMax) noexcept + { + SHVec2 result; + + const XMVECTOR V = XMLoadFloat2(&v); + const XMVECTOR MIN = XMLoadFloat2(&vMin); + const XMVECTOR MAX = XMLoadFloat2(&vMax); + + XMStoreFloat2(&result, XMVectorClamp(V, MIN, MAX)); + return result; + } + + SHVec2 SHVec2::Lerp(const SHVec2& a, const SHVec2& b, float t) noexcept + { + SHVec2 result; + + const XMVECTOR V1 = XMLoadFloat2(&a); + const XMVECTOR V2 = XMLoadFloat2(&b); + + XMStoreFloat2(&result, XMVectorLerp(V1, V2, t)); + return result; + } + + SHVec2 SHVec2::ClampedLerp(const SHVec2& a, const SHVec2& b, float t, float tMin, float tMax) noexcept + { + return Lerp(a, b, std::clamp(t, tMin, tMax)); + } + + float SHVec2::Distance(const SHVec2& lhs, const SHVec2& rhs) noexcept + { + return (lhs - rhs).Length(); + } + + float SHVec2::DistanceSquared(const SHVec2& lhs, const SHVec2& rhs) noexcept + { + return (lhs - rhs).LengthSquared(); + } + + float SHVec2::Angle(const SHVec2& lhs, const SHVec2& rhs) noexcept + { + const XMVECTOR V1 = XMLoadFloat2(&lhs); + const XMVECTOR V2 = XMLoadFloat2(&rhs); + + return XMVectorGetX(XMVector2AngleBetweenVectors(V1, V2)); + } + + float SHVec2::Dot(const SHVec2& lhs, const SHVec2& rhs) noexcept + { + return lhs.Dot(rhs); + } + + SHVec2 SHVec2::Project(const SHVec2& v, const SHVec2& u) noexcept + { + SHVec2 result; + + const XMVECTOR U = XMLoadFloat2(&u); + const float V_DOT_U = Dot(v, u); + const float U_LENSQ = u.LengthSquared(); + + XMStoreFloat2(&result, XMVectorScale(U, V_DOT_U / U_LENSQ)); + return result; + } + + SHVec2 SHVec2::Reflect(const SHVec2& v, const SHVec2& normal) noexcept + { + SHVec2 result; + + const XMVECTOR V = XMLoadFloat2(&v); + const XMVECTOR N = XMLoadFloat2(&normal); + + XMStoreFloat2(&result, XMVector2Reflect(V, N)); + return result; + } + + SHVec2 SHVec2::Rotate(const SHVec2& v, float angleInRad) noexcept + { + SHVec2 result; + + const XMVECTOR V = XMLoadFloat2(&v); + const XMMATRIX R = XMMatrixRotationZ(angleInRad); + + XMStoreFloat2(&result, XMVector2Transform(V, R)); + return result; + } + + SHVec2 SHVec2::Transform(const SHVec2& v, const SHMatrix& transformMtx) noexcept + { + SHVec2 result; + + const XMVECTOR V = XMLoadFloat2(&v); + const XMMATRIX TF = XMLoadFloat4x4(&transformMtx); + + XMStoreFloat2(&result, XMVector2TransformCoord(V, TF)); + return result; + } + + SHVec2 SHVec2::Cross(float lhs, const SHVec2& rhs) noexcept + { + SHVec2 result; + + const XMFLOAT3 LHS { 0.0f, 0.0f, lhs }; + const XMFLOAT3 RHS { rhs.x, rhs.y, 0.0f }; + + const XMVECTOR V1 = XMLoadFloat3(&LHS); + const XMVECTOR V2 = XMLoadFloat3(&RHS); + + XMStoreFloat2(&result, XMVector3Cross(V1, V2)); + return result; + } + + SHVec2 SHVec2::Cross(const SHVec2& lhs, float rhs) noexcept + { + SHVec2 result; + + const XMFLOAT3 LHS { lhs.x, lhs.y, 0.0f }; + const XMFLOAT3 RHS { 0.0f, 0.0f, rhs }; + + const XMVECTOR V1 = XMLoadFloat3(&LHS); + const XMVECTOR V2 = XMLoadFloat3(&RHS); + + XMStoreFloat2(&result, XMVector3Cross(V1, V2)); + return result; + } + + float SHVec2::Cross(const SHVec2& lhs, const SHVec2& rhs) noexcept + { + return (lhs.x * rhs.y) - (lhs.y * rhs.x); + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Vector/SHVec2.h b/SHADE_Engine/src/Math/Vector/SHVec2.h new file mode 100644 index 00000000..a64d4bb0 --- /dev/null +++ b/SHADE_Engine/src/Math/Vector/SHVec2.h @@ -0,0 +1,122 @@ +/**************************************************************************************** + * \file SHVec2.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for 2D Vector. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +#include +#include +#include + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + class SHMatrix; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SHVec2 : public DirectX::XMFLOAT2 + { + public: + /*---------------------------------------------------------------------------------*/ + /* Static Data Members */ + /*---------------------------------------------------------------------------------*/ + + static constexpr size_t SIZE = 2U; + + static const SHVec2 Zero; + static const SHVec2 One; + static const SHVec2 Left; + static const SHVec2 Right; + static const SHVec2 Up; + static const SHVec2 Down; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHVec2 (const SHVec2& rhs) = default; + SHVec2 (SHVec2&& rhs) = default; + ~SHVec2 () = default; + + SHVec2 () noexcept; + SHVec2 (float x, float y) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] SHVec2& operator= (const SHVec2& rhs) = default; + [[nodiscard]] SHVec2& operator= (SHVec2&& rhs) = default; + + [[nodiscard]] SHVec2& operator+= (const SHVec2& rhs) noexcept; + [[nodiscard]] SHVec2& operator-= (const SHVec2& rhs) noexcept; + [[nodiscard]] SHVec2& operator*= (const SHVec2& rhs) noexcept; + [[nodiscard]] SHVec2& operator*= (float rhs) noexcept; + [[nodiscard]] SHVec2& operator/= (const SHVec2& rhs) noexcept; + [[nodiscard]] SHVec2& operator/= (float rhs) noexcept; + + [[nodiscard]] SHVec2 operator+ (const SHVec2& rhs) const noexcept; + [[nodiscard]] SHVec2 operator- (const SHVec2& rhs) const noexcept; + [[nodiscard]] SHVec2 operator- () const noexcept; + [[nodiscard]] SHVec2 operator* (const SHVec2& rhs) const noexcept; + [[nodiscard]] SHVec2 operator* (float rhs) const noexcept; + [[nodiscard]] SHVec2 operator/ (const SHVec2& rhs) const noexcept; + [[nodiscard]] SHVec2 operator/ (float rhs) const noexcept; + + [[nodiscard]] bool operator== (const SHVec2& rhs) const noexcept; + [[nodiscard]] bool operator!= (const SHVec2& rhs) const noexcept; + + [[nodiscard]] float operator[] (int index); + [[nodiscard]] float operator[] (size_t index); + [[nodiscard]] float operator[] (int index) const; + [[nodiscard]] float operator[] (size_t index) const; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] float Length () const noexcept; + [[nodiscard]] float LengthSquared () const noexcept; + [[nodiscard]] std::string ToString () const noexcept; + + [[nodiscard]] float Dot (const SHVec2& rhs) const noexcept; + [[nodiscard]] SHVec2 Cross (const SHVec2& rhs) const noexcept; + /*---------------------------------------------------------------------------------*/ + /* Static Function Members */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] static SHVec2 Normalise (const SHVec2& vec2) noexcept; + [[nodiscard]] static SHVec2 Abs (const SHVec2& vec2) noexcept; + [[nodiscard]] static SHVec2 Min (const std::initializer_list& vec2s) noexcept; + [[nodiscard]] static SHVec2 Max (const std::initializer_list& vec2s) noexcept; + [[nodiscard]] static SHVec2 Clamp (const SHVec2& v, const SHVec2& vMin, const SHVec2& vMax) noexcept; + [[nodiscard]] static SHVec2 Lerp (const SHVec2& a, const SHVec2& b, float t) noexcept; + [[nodiscard]] static SHVec2 ClampedLerp (const SHVec2& a, const SHVec2& b, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept; + + [[nodiscard]] static float Distance (const SHVec2& lhs, const SHVec2& rhs) noexcept; + [[nodiscard]] static float DistanceSquared (const SHVec2& lhs, const SHVec2& rhs) noexcept; + [[nodiscard]] static float Angle (const SHVec2& lhs, const SHVec2& rhs) noexcept; + [[nodiscard]] static float Dot (const SHVec2& lhs, const SHVec2& rhs) noexcept; + [[nodiscard]] static SHVec2 Project (const SHVec2& v, const SHVec2& u) noexcept; + [[nodiscard]] static SHVec2 Reflect (const SHVec2& v, const SHVec2& normal) noexcept; + [[nodiscard]] static SHVec2 Rotate (const SHVec2& v, float angleInRad) noexcept; + [[nodiscard]] static SHVec2 Transform (const SHVec2& v, const SHMatrix& transformMtx) noexcept; + [[nodiscard]] static SHVec2 Cross (float lhs, const SHVec2& rhs) noexcept; + [[nodiscard]] static SHVec2 Cross (const SHVec2& lhs, float rhs) noexcept; + [[nodiscard]] static float Cross (const SHVec2& lhs, const SHVec2& rhs) noexcept; + }; + + SHVec2 operator* (float lhs, const SHVec2& rhs) noexcept; + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Vector/SHVec3.cpp b/SHADE_Engine/src/Math/Vector/SHVec3.cpp new file mode 100644 index 00000000..73030f9c --- /dev/null +++ b/SHADE_Engine/src/Math/Vector/SHVec3.cpp @@ -0,0 +1,477 @@ +/**************************************************************************************** + * \file SHVec3.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for 3D Vector. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#include + +// Primary Header +#include "SHVec3.h" +// Project Headers +#include "Math/SHMatrix.h" +#include "Tools/SHLogger.h" + +using namespace DirectX; + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Static Data Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + SHVec3 const SHVec3::Zero { 0.0f, 0.0f, 0.0f }; + SHVec3 const SHVec3::One { 1.0f, 1.0f, 1.0f }; + SHVec3 const SHVec3::Left { -1.0f, 0.0f, 0.0f }; + SHVec3 const SHVec3::Right { 1.0f, 0.0f, 0.0f }; + SHVec3 const SHVec3::Up { 0.0f, 1.0f, 0.0f }; + SHVec3 const SHVec3::Down { 0.0f, -1.0f, 0.0f }; + SHVec3 const SHVec3::Forward { 0.0f, 0.0f, 1.0f }; + SHVec3 const SHVec3::Back { 0.0f, 0.0f, -1.0f }; + SHVec3 const SHVec3::UnitX { 1.0f, 0.0f, 0.0f }; + SHVec3 const SHVec3::UnitY { 0.0f, 1.0f, 0.0f }; + SHVec3 const SHVec3::UnitZ { 0.0f, 0.0f, 1.0f }; + + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHVec3::SHVec3() noexcept + : XMFLOAT3( 0.0f, 0.0f, 0.0f ) + {} + + SHVec3::SHVec3(float _x, float _y, float _z) noexcept + : XMFLOAT3( _x, _y, _z ) + {} + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHVec3& SHVec3::operator+=(const SHVec3& rhs) noexcept + { + return *this = *this + rhs; + } + + SHVec3& SHVec3::operator-=(const SHVec3& rhs) noexcept + { + return *this = *this - rhs; + } + + SHVec3& SHVec3::operator*=(const SHVec3& rhs) noexcept + { + return *this = *this * rhs; + } + + SHVec3& SHVec3::operator*=(float rhs) noexcept + { + return *this = *this * rhs; + } + + SHVec3& SHVec3::operator/=(const SHVec3& rhs) noexcept + { + return *this = *this / rhs; + } + + SHVec3& SHVec3::operator/=(float rhs) noexcept + { + return *this = *this / rhs; + } + + SHVec3 SHVec3::operator+(const SHVec3& rhs) const noexcept + { + SHVec3 result; + + const XMVECTOR V1 = XMLoadFloat3(this); + const XMVECTOR V2 = XMLoadFloat3(&rhs); + + XMStoreFloat3(&result, XMVectorAdd(V1, V2)); + return result; + } + + SHVec3 SHVec3::operator-(const SHVec3& rhs) const noexcept + { + SHVec3 result; + + const XMVECTOR V1 = XMLoadFloat3(this); + const XMVECTOR V2 = XMLoadFloat3(&rhs); + + XMStoreFloat3(&result, XMVectorSubtract(V1, V2)); + return result; + } + + SHVec3 SHVec3::operator-() const noexcept + { + return SHVec3{ -x, -y, -z }; + } + + + SHVec3 SHVec3::operator*(const SHVec3& rhs) const noexcept + { + SHVec3 result; + + const XMVECTOR V1 = XMLoadFloat3(this); + const XMVECTOR V2 = XMLoadFloat3(&rhs); + + XMStoreFloat3(&result, XMVectorMultiply(V1, V2)); + return result; + } + + SHVec3 SHVec3::operator*(float rhs) const noexcept + { + SHVec3 result; + + const XMVECTOR V = XMLoadFloat3(this); + + XMStoreFloat3(&result, XMVectorScale(V, rhs)); + return result; + } + + SHVec3 SHVec3::operator/(const SHVec3& rhs) const noexcept + { + SHVec3 result; + + const XMVECTOR V1 = XMLoadFloat3(this); + const XMVECTOR V2 = XMLoadFloat3(&rhs); + + XMStoreFloat3(&result, XMVectorDivide(V1, V2)); + return result; + } + + SHVec3 SHVec3::operator/(float rhs) const noexcept + { + SHVec3 result; + + const XMVECTOR V = XMLoadFloat3(this); + + XMStoreFloat3(&result, XMVectorScale(V, 1.0f / rhs)); + return result; + } + + bool SHVec3::operator==(const SHVec3& rhs) const noexcept + { + const XMVECTOR V1 = XMLoadFloat3(this); + const XMVECTOR V2 = XMLoadFloat3(&rhs); + + return XMVector3Equal(V1, V2); + } + + bool SHVec3::operator!=(const SHVec3& rhs) const noexcept + { + const XMVECTOR V1 = XMLoadFloat3(this); + const XMVECTOR V2 = XMLoadFloat3(&rhs); + + return XMVector3NotEqual(V1, V2); + } + + float SHVec3::operator[](int index) + { + if (index >= SIZE || index < 0) + throw std::invalid_argument("Index out of range!"); + + switch (index) + { + case 0: return x; + case 1: return y; + case 2: return z; + default: return 0.0f; + } + } + + float SHVec3::operator[](size_t index) + { + if (index >= SIZE) + throw std::invalid_argument("Index out of range!"); + + switch (index) + { + case 0: return x; + case 1: return y; + case 2: return z; + default: return 0.0f; + } + } + + float SHVec3::operator[](int index) const + { + if (index >= SIZE || index < 0) + throw std::invalid_argument("Index out of range!"); + + switch (index) + { + case 0: return x; + case 1: return y; + case 2: return z; + default: return 0.0f; + } + } + + float SHVec3::operator[](size_t index) const + { + if (index >= SIZE) + throw std::invalid_argument("Index out of range!"); + + switch (index) + { + case 0: return x; + case 1: return y; + case 2: return z; + default: return 0.0f; + } + } + + SHVec3 operator* (float lhs, const SHVec3& rhs) noexcept + { + SHVec3 result; + + const XMVECTOR V = XMLoadFloat3(&rhs); + + XMStoreFloat3(&result, XMVectorScale(V, lhs)); + return result; + } + + /*-----------------------------------------------------------------------------------*/ + /* Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + float SHVec3::Length() const noexcept + { + const XMVECTOR V = XMLoadFloat3(this); + + return XMVectorGetX(XMVector3Length(V)); + } + + float SHVec3::LengthSquared() const noexcept + { + const XMVECTOR V = XMLoadFloat3(this); + + return XMVectorGetX(XMVector3LengthSq(V)); + } + + std::string SHVec3::ToString() const noexcept + { + std::stringstream ss; + ss << std::fixed << std::setprecision(3); + ss << "<" << x << ", " << y << ", " << z << ">"; + return ss.str(); + } + + float SHVec3::Dot(const SHVec3& rhs) const noexcept + { + const XMVECTOR V1 = XMLoadFloat3(this); + const XMVECTOR V2 = XMLoadFloat3(&rhs); + + return XMVectorGetX(XMVector3Dot(V1, V2)); + } + + SHVec3 SHVec3::Cross(const SHVec3& rhs) const noexcept + { + SHVec3 result; + + const XMVECTOR V1 = XMLoadFloat3(this); + const XMVECTOR V2 = XMLoadFloat3(&rhs); + + XMStoreFloat3(&result, XMVector3Cross(V1, V2)); + return result; + } + + /*-----------------------------------------------------------------------------------*/ + /* Static Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHVec3 SHVec3::Normalise(const SHVec3& v) noexcept + { + SHVec3 result; + + const XMVECTOR V = XMLoadFloat3(&v); + + XMStoreFloat3(&result, XMVector3Normalize(V)); + return result; + } + + SHVec3 SHVec3::Abs(const SHVec3& v) noexcept + { + return SHVec3{ std::fabs(v.x), std::fabs(v.y), std::fabs(v.z) }; + } + + SHVec3 SHVec3::Min(const std::initializer_list& vs) noexcept + { + if (vs.size() == 0) + { + SHLOG_WARNING("No arguments passed in! Min value is a default SHVec3.") + return SHVec3{}; + } + + SHVec3 result; + + XMVECTOR min = XMLoadFloat3(&(*vs.begin())); + for (auto it = vs.begin() + 1; it != vs.end(); ++it) + { + const XMVECTOR tmp = XMLoadFloat3(&(*it)); + min = XMVectorMin(min, tmp); + } + + XMStoreFloat3(&result, min); + return result; + } + + SHVec3 SHVec3::Max(const std::initializer_list& vs) noexcept + { + if (vs.size() == 0) + { + SHLOG_WARNING("No arguments passed in! Max value is a default SHVec3.") + return SHVec3{}; + } + + SHVec3 result; + + XMVECTOR max = XMLoadFloat3(&(*vs.begin())); + for (auto it = vs.begin() + 1; it != vs.end(); ++it) + { + const XMVECTOR tmp = XMLoadFloat3(&(*it)); + max = XMVectorMax(max, tmp); + } + + XMStoreFloat3(&result, max); + return result; + } + + SHVec3 SHVec3::Clamp(const SHVec3& v, const SHVec3& vMin, const SHVec3& vMax) noexcept + { + SHVec3 result; + + const XMVECTOR V = XMLoadFloat3(&v); + const XMVECTOR MIN = XMLoadFloat3(&vMin); + const XMVECTOR MAX = XMLoadFloat3(&vMax); + + XMStoreFloat3(&result, XMVectorClamp(V, MIN, MAX)); + return result; + } + + SHVec3 SHVec3::Lerp(const SHVec3& a, const SHVec3& b, float t) noexcept + { + SHVec3 result; + + const XMVECTOR V1 = XMLoadFloat3(&a); + const XMVECTOR V2 = XMLoadFloat3(&b); + + XMStoreFloat3(&result, XMVectorLerp(V1, V2, t)); + return result; + } + + SHVec3 SHVec3::ClampedLerp(const SHVec3& a, const SHVec3& b, float t, float tMin, float tMax) noexcept + { + return Lerp(a, b, std::clamp(t, tMin, tMax)); + } + + float SHVec3::Distance(const SHVec3& lhs, const SHVec3& rhs) noexcept + { + return (lhs - rhs).Length(); + } + + float SHVec3::DistanceSquared(const SHVec3& lhs, const SHVec3& rhs) noexcept + { + return (lhs - rhs).LengthSquared(); + } + + float SHVec3::Angle(const SHVec3& lhs, const SHVec3& rhs) noexcept + { + const XMVECTOR V1 = XMLoadFloat3(&lhs); + const XMVECTOR V2 = XMLoadFloat3(&rhs); + + return XMVectorGetX(XMVector3AngleBetweenVectors(V1, V2)); + } + + float SHVec3::Dot(const SHVec3& lhs, const SHVec3& rhs) noexcept + { + return lhs.Dot(rhs); + } + + SHVec3 SHVec3::Cross(const SHVec3& lhs, const SHVec3& rhs) noexcept + { + return lhs.Cross(rhs); + } + + SHVec3 SHVec3::Project(const SHVec3& v, const SHVec3& u) noexcept + { + SHVec3 result; + + const XMVECTOR U = XMLoadFloat3(&u); + const float V_DOT_U = Dot(v, u); + const float U_LENSQ = u.LengthSquared(); + + XMStoreFloat3(&result, XMVectorScale(U, V_DOT_U / U_LENSQ)); + return result; + } + + SHVec3 SHVec3::Reflect(const SHVec3& v, const SHVec3& normal) noexcept + { + SHVec3 result; + + const XMVECTOR V = XMLoadFloat3(&v); + const XMVECTOR N = XMLoadFloat3(&normal); + + XMStoreFloat3(&result, XMVector3Reflect(V, N)); + return result; + } + + SHVec3 SHVec3::Rotate(const SHVec3& v, const SHVec3& axis, float angleInRad) noexcept + { + SHVec3 result; + + const XMVECTOR V = XMLoadFloat3(&v); + + const XMVECTOR AXIS = XMLoadFloat3(&axis); + const XMVECTOR Q = XMQuaternionRotationAxis(AXIS, angleInRad); + + XMStoreFloat3(&result, XMVector3Rotate(V, Q)); + return result; + } + + SHVec3 SHVec3::RotateX(const SHVec3& v, float angleInRad) noexcept + { + SHVec3 result; + + const XMVECTOR V = XMLoadFloat3(&v); + const XMMATRIX R = XMMatrixRotationX(angleInRad); + + XMStoreFloat3(&result, XMVector3TransformCoord(V, R)); + return result; + } + + SHVec3 SHVec3::RotateY(const SHVec3& v, float angleInRad) noexcept + { + SHVec3 result; + + const XMVECTOR V = XMLoadFloat3(&v); + const XMMATRIX R = XMMatrixRotationY(angleInRad); + + XMStoreFloat3(&result, XMVector3TransformCoord(V, R)); + return result; + } + + SHVec3 SHVec3::RotateZ(const SHVec3& v, float angleInRad) noexcept + { + SHVec3 result; + + const XMVECTOR V = XMLoadFloat3(&v); + const XMMATRIX R = XMMatrixRotationZ(angleInRad); + + XMStoreFloat3(&result, XMVector3TransformCoord(V, R)); + return result; + } + + SHVec3 SHVec3::Transform(const SHVec3& v, const SHMatrix& transformMtx) noexcept + { + SHVec3 result; + + const XMVECTOR V = XMLoadFloat3(&v); + const XMMATRIX TF = XMLoadFloat4x4(&transformMtx); + + XMStoreFloat3(&result, XMVector3TransformCoord(V, TF)); + return result; + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Vector/SHVec3.h b/SHADE_Engine/src/Math/Vector/SHVec3.h new file mode 100644 index 00000000..e172e824 --- /dev/null +++ b/SHADE_Engine/src/Math/Vector/SHVec3.h @@ -0,0 +1,129 @@ +/**************************************************************************************** + * \file SHVec3.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for 3D Vector. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +#include +#include +#include + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + class SHMatrix; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SHVec3 : public DirectX::XMFLOAT3 + { + public: + /*---------------------------------------------------------------------------------*/ + /* Static Data Members */ + /*---------------------------------------------------------------------------------*/ + + static constexpr size_t SIZE = 3U; + + static const SHVec3 Zero; + static const SHVec3 One; + static const SHVec3 Left; + static const SHVec3 Right; + static const SHVec3 Up; + static const SHVec3 Down; + static const SHVec3 Forward; + static const SHVec3 Back; + static const SHVec3 UnitX; + static const SHVec3 UnitY; + static const SHVec3 UnitZ; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHVec3 (const SHVec3& rhs) = default; + SHVec3 (SHVec3&& rhs) = default; + ~SHVec3 () = default; + + SHVec3 () noexcept; + SHVec3 (float x, float y, float z) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] SHVec3& operator= (const SHVec3& rhs) = default; + [[nodiscard]] SHVec3& operator= (SHVec3&& rhs) = default; + + [[nodiscard]] SHVec3& operator+= (const SHVec3& rhs) noexcept; + [[nodiscard]] SHVec3& operator-= (const SHVec3& rhs) noexcept; + [[nodiscard]] SHVec3& operator*= (const SHVec3& rhs) noexcept; + [[nodiscard]] SHVec3& operator*= (float rhs) noexcept; + [[nodiscard]] SHVec3& operator/= (const SHVec3& rhs) noexcept; + [[nodiscard]] SHVec3& operator/= (float rhs) noexcept; + + [[nodiscard]] SHVec3 operator+ (const SHVec3& rhs) const noexcept; + [[nodiscard]] SHVec3 operator- (const SHVec3& rhs) const noexcept; + [[nodiscard]] SHVec3 operator- () const noexcept; + [[nodiscard]] SHVec3 operator* (const SHVec3& rhs) const noexcept; + [[nodiscard]] SHVec3 operator* (float rhs) const noexcept; + [[nodiscard]] SHVec3 operator/ (const SHVec3& rhs) const noexcept; + [[nodiscard]] SHVec3 operator/ (float rhs) const noexcept; + + [[nodiscard]] bool operator== (const SHVec3& rhs) const noexcept; + [[nodiscard]] bool operator!= (const SHVec3& rhs) const noexcept; + + [[nodiscard]] float operator[] (int index); + [[nodiscard]] float operator[] (size_t index); + [[nodiscard]] float operator[] (int index) const; + [[nodiscard]] float operator[] (size_t index) const; + + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] float Length () const noexcept; + [[nodiscard]] float LengthSquared () const noexcept; + [[nodiscard]] std::string ToString () const noexcept; + + [[nodiscard]] float Dot (const SHVec3& rhs) const noexcept; + [[nodiscard]] SHVec3 Cross (const SHVec3& rhs) const noexcept; + /*---------------------------------------------------------------------------------*/ + /* Static Function Members */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] static SHVec3 Normalise (const SHVec3& v) noexcept; + [[nodiscard]] static SHVec3 Abs (const SHVec3& v) noexcept; + [[nodiscard]] static SHVec3 Min (const std::initializer_list& vs) noexcept; + [[nodiscard]] static SHVec3 Max (const std::initializer_list& vs) noexcept; + [[nodiscard]] static SHVec3 Clamp (const SHVec3& v, const SHVec3& vMin, const SHVec3& vMax) noexcept; + [[nodiscard]] static SHVec3 Lerp (const SHVec3& a, const SHVec3& b, float t) noexcept; + [[nodiscard]] static SHVec3 ClampedLerp (const SHVec3& a, const SHVec3& b, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept; + + [[nodiscard]] static float Distance (const SHVec3& lhs, const SHVec3& rhs) noexcept; + [[nodiscard]] static float DistanceSquared (const SHVec3& lhs, const SHVec3& rhs) noexcept; + [[nodiscard]] static float Angle (const SHVec3& lhs, const SHVec3& rhs) noexcept; + [[nodiscard]] static float Dot (const SHVec3& lhs, const SHVec3& rhs) noexcept; + [[nodiscard]] static SHVec3 Cross (const SHVec3& lhs, const SHVec3& rhs) noexcept; + [[nodiscard]] static SHVec3 Project (const SHVec3& v, const SHVec3& u) noexcept; + [[nodiscard]] static SHVec3 Reflect (const SHVec3& v, const SHVec3& normal) noexcept; + [[nodiscard]] static SHVec3 Rotate (const SHVec3& v, const SHVec3& axis, float angleInRad) noexcept; + [[nodiscard]] static SHVec3 RotateX (const SHVec3& v, float angleInRad) noexcept; + [[nodiscard]] static SHVec3 RotateY (const SHVec3& v, float angleInRad) noexcept; + [[nodiscard]] static SHVec3 RotateZ (const SHVec3& v, float angleInRad) noexcept; + [[nodiscard]] static SHVec3 Transform (const SHVec3& v, const SHMatrix& transformMtx) noexcept; + }; + + SHVec3 operator* (float lhs, const SHVec3& rhs) noexcept; + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Vector/SHVec4.cpp b/SHADE_Engine/src/Math/Vector/SHVec4.cpp new file mode 100644 index 00000000..5d75af33 --- /dev/null +++ b/SHADE_Engine/src/Math/Vector/SHVec4.cpp @@ -0,0 +1,529 @@ +/**************************************************************************************** + * \file SHVec4.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for 4D Vector. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#include + +// Primary Header +#include "SHVec4.h" +// Project Headers +#include "Math/SHMatrix.h" +#include "Tools/SHLogger.h" + +using namespace DirectX; + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Static Data Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + SHVec4 const SHVec4::Zero { 0.0f, 0.0f, 0.0f, 0.0f }; + SHVec4 const SHVec4::One { 1.0f, 1.0f, 1.0f, 1.0f }; + SHVec4 const SHVec4::UnitX { 1.0f, 0.0f, 0.0f, 0.0f }; + SHVec4 const SHVec4::UnitY { 0.0f, 1.0f, 0.0f, 0.0f }; + SHVec4 const SHVec4::UnitZ { 0.0f, 0.0f, 1.0f, 0.0f }; + SHVec4 const SHVec4::UnitW { 0.0f, 0.0f, 0.0f, 1.0f }; + + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHVec4::SHVec4() noexcept + : XMFLOAT4( 0.0f, 0.0f, 0.0f, 0.0f ) + {} + + SHVec4::SHVec4(float _x, float _y, float _z, float _w) noexcept + : XMFLOAT4( _x, _y, _z, _w ) + {} + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHVec4& SHVec4::operator+=(const SHVec4& rhs) noexcept + { + return *this = *this + rhs; + } + + SHVec4& SHVec4::operator-=(const SHVec4& rhs) noexcept + { + return *this = *this - rhs; + } + + SHVec4& SHVec4::operator*=(const SHVec4& rhs) noexcept + { + return *this = *this * rhs; + } + + SHVec4& SHVec4::operator*=(float rhs) noexcept + { + return *this = *this * rhs; + } + + SHVec4& SHVec4::operator/=(const SHVec4& rhs) noexcept + { + return *this = *this / rhs; + } + + SHVec4& SHVec4::operator/=(float rhs) noexcept + { + return *this = *this / rhs; + } + + SHVec4 SHVec4::operator+(const SHVec4& rhs) const noexcept + { + SHVec4 result; + + const XMVECTOR V1 = XMLoadFloat4(this); + const XMVECTOR V2 = XMLoadFloat4(&rhs); + + XMStoreFloat4(&result, XMVectorAdd(V1, V2)); + return result; + } + + SHVec4 SHVec4::operator-(const SHVec4& rhs) const noexcept + { + SHVec4 result; + + const XMVECTOR V1 = XMLoadFloat4(this); + const XMVECTOR V2 = XMLoadFloat4(&rhs); + + XMStoreFloat4(&result, XMVectorSubtract(V1, V2)); + return result; + } + + SHVec4 SHVec4::operator-() const noexcept + { + return SHVec4{ -x, -y, -z, -w }; + } + + SHVec4 SHVec4::operator*(const SHVec4& rhs) const noexcept + { + SHVec4 result; + + const XMVECTOR V1 = XMLoadFloat4(this); + const XMVECTOR V2 = XMLoadFloat4(&rhs); + + XMStoreFloat4(&result, XMVectorMultiply(V1, V2)); + return result; + } + + SHVec4 SHVec4::operator*(float rhs) const noexcept + { + SHVec4 result; + + const XMVECTOR V = XMLoadFloat4(this); + + XMStoreFloat4(&result, XMVectorScale(V, rhs)); + return result; + } + + SHVec4 SHVec4::operator/(const SHVec4& rhs) const noexcept + { + SHVec4 result; + + const XMVECTOR V1 = XMLoadFloat4(this); + const XMVECTOR V2 = XMLoadFloat4(&rhs); + + XMStoreFloat4(&result, XMVectorDivide(V1, V2)); + return result; + } + + SHVec4 SHVec4::operator/(float rhs) const noexcept + { + SHVec4 result; + + const XMVECTOR V = XMLoadFloat4(this); + + XMStoreFloat4(&result, XMVectorScale(V, 1.0f / rhs)); + return result; + } + + bool SHVec4::operator==(const SHVec4& rhs) const noexcept + { + const XMVECTOR V1 = XMLoadFloat4(this); + const XMVECTOR V2 = XMLoadFloat4(&rhs); + + return XMVector4Equal(V1, V2); + } + + bool SHVec4::operator!=(const SHVec4& rhs) const noexcept + { + const XMVECTOR V1 = XMLoadFloat4(this); + const XMVECTOR V2 = XMLoadFloat4(&rhs); + + return XMVector4NotEqual(V1, V2); + } + + float SHVec4::operator[](int index) + { + if (index >= SIZE || index < 0) + throw std::invalid_argument("Index out of range!"); + + switch (index) + { + case 0: return x; + case 1: return y; + case 2: return z; + case 3: return w; + default: return 0.0f; + } + } + + float SHVec4::operator[](size_t index) + { + if (index >= SIZE) + throw std::invalid_argument("Index out of range!"); + + switch (index) + { + case 0: return x; + case 1: return y; + case 2: return z; + case 3: return w; + default: return 0.0f; + } + } + + float SHVec4::operator[](int index) const + { + if (index >= SIZE || index < 0) + throw std::invalid_argument("Index out of range!"); + + switch (index) + { + case 0: return x; + case 1: return y; + case 2: return z; + case 3: return w; + default: return 0.0f; + } + } + + float SHVec4::operator[](size_t index) const + { + if (index >= SIZE) + throw std::invalid_argument("Index out of range!"); + + switch (index) + { + case 0: return x; + case 1: return y; + case 2: return z; + case 3: return w; + default: return 0.0f; + } + } + + SHVec4 operator* (float lhs, const SHVec4& rhs) noexcept + { + SHVec4 result; + + const XMVECTOR V = XMLoadFloat4(&rhs); + + XMStoreFloat4(&result, XMVectorScale(V, lhs)); + return result; + } + + /*-----------------------------------------------------------------------------------*/ + /* Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + float SHVec4::Length() const noexcept + { + const XMVECTOR V = XMLoadFloat4(this); + + return XMVectorGetX(XMVector4Length(V)); + } + + float SHVec4::Length3D() const noexcept + { + const XMVECTOR V = XMLoadFloat4(this); + + return XMVectorGetX(XMVector3Length(V)); + } + + float SHVec4::LengthSquared() const noexcept + { + const XMVECTOR V = XMLoadFloat4(this); + + return XMVectorGetX(XMVector4LengthSq(V)); + } + + float SHVec4::LengthSquared3D() const noexcept + { + const XMVECTOR V = XMLoadFloat4(this); + + return XMVectorGetX(XMVector3LengthSq(V)); + } + + std::string SHVec4::ToString() const noexcept + { + std::stringstream ss; + ss << std::fixed << std::setprecision(3); + ss << "<" << x << ", " << y << ", " << z << ", " << w <<">"; + return ss.str(); + } + + float SHVec4::Dot(const SHVec4& rhs) const noexcept + { + const XMVECTOR V1 = XMLoadFloat4(this); + const XMVECTOR V2 = XMLoadFloat4(&rhs); + + return XMVectorGetX(XMVector4Dot(V1, V2)); + } + + float SHVec4::Dot3D(const SHVec4& rhs) const noexcept + { + const XMVECTOR V1 = XMLoadFloat4(this); + const XMVECTOR V2 = XMLoadFloat4(&rhs); + + return XMVectorGetX(XMVector3Dot(V1, V2)); + } + + SHVec4 SHVec4::Cross3D(const SHVec4& rhs) const noexcept + { + SHVec4 result; + + const XMVECTOR V1 = XMLoadFloat4(this); + const XMVECTOR V2 = XMLoadFloat4(&rhs); + + XMStoreFloat4(&result, XMVector3Cross(V1, V2)); + result.w = 1.0f; + return result; + } + + SHVec4 SHVec4::Cross(const SHVec4& v1, const SHVec4& v2) const noexcept + { + SHVec4 result; + + const XMVECTOR V3 = XMLoadFloat4(this); + const XMVECTOR V1 = XMLoadFloat4(&v1); + const XMVECTOR V2 = XMLoadFloat4(&v2); + + XMStoreFloat4(&result, XMVector4Cross(V3, V1, V2)); + return result; + } + + /*-----------------------------------------------------------------------------------*/ + /* Static Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHVec4 SHVec4::Normalise(const SHVec4& v) noexcept + { + SHVec4 result; + + const XMVECTOR V = XMLoadFloat4(&v); + + XMStoreFloat4(&result, XMVector4Normalize(V)); + return result; + } + + SHVec4 SHVec4::Normalise3D(const SHVec4& v) noexcept + { + SHVec4 result; + + const XMVECTOR V = XMLoadFloat4(&v); + + XMStoreFloat4(&result, XMVector3Normalize(V)); + result.w = 1.0f; + return result; + } + + SHVec4 SHVec4::Abs(const SHVec4& v) noexcept + { + return SHVec4{ std::fabs(v.x), std::fabs(v.y), std::fabs(v.z), std::fabs(v.w) }; + } + + SHVec4 SHVec4::Min(const std::initializer_list& vs) noexcept + { + if (vs.size() == 0) + { + SHLOG_WARNING("No arguments passed in! Min value is a default SHVec4.") + return SHVec4{}; + } + + SHVec4 result; + + XMVECTOR min = XMLoadFloat4(&(*vs.begin())); + for (auto it = vs.begin() + 1; it != vs.end(); ++it) + { + const XMVECTOR tmp = XMLoadFloat4(&(*it)); + min = XMVectorMin(min, tmp); + } + + XMStoreFloat4(&result, min); + return result; + } + + SHVec4 SHVec4::Max(const std::initializer_list& vs) noexcept + { + if (vs.size() == 0) + { + SHLOG_WARNING("No arguments passed in! Max value is a default SHVec4.") + return SHVec4{}; + } + + SHVec4 result; + + XMVECTOR max = XMLoadFloat4(&(*vs.begin())); + for (auto it = vs.begin() + 1; it != vs.end(); ++it) + { + const XMVECTOR tmp = XMLoadFloat4(&(*it)); + max = XMVectorMax(max, tmp); + } + + XMStoreFloat4(&result, max); + return result; + } + + SHVec4 SHVec4::Clamp(const SHVec4& v, const SHVec4& vMin, const SHVec4& vMax) noexcept + { + SHVec4 result; + + const XMVECTOR V = XMLoadFloat4(&v); + const XMVECTOR MIN = XMLoadFloat4(&vMin); + const XMVECTOR MAX = XMLoadFloat4(&vMax); + + XMStoreFloat4(&result, XMVectorClamp(V, MIN, MAX)); + return result; + } + + SHVec4 SHVec4::Lerp(const SHVec4& a, const SHVec4& b, float t) noexcept + { + SHVec4 result; + + const XMVECTOR V1 = XMLoadFloat4(&a); + const XMVECTOR V2 = XMLoadFloat4(&b); + + XMStoreFloat4(&result, XMVectorLerp(V1, V2, t)); + return result; + } + + SHVec4 SHVec4::ClampedLerp(const SHVec4& a, const SHVec4& b, float t, float tMin, float tMax) noexcept + { + return Lerp(a, b, std::clamp(t, tMin, tMax)); + } + + float SHVec4::Distance(const SHVec4& lhs, const SHVec4& rhs) noexcept + { + return (lhs - rhs).Length(); + } + + float SHVec4::Distance3D(const SHVec4& lhs, const SHVec4& rhs) noexcept + { + return (lhs - rhs).Length3D(); + } + + float SHVec4::DistanceSquared(const SHVec4& lhs, const SHVec4& rhs) noexcept + { + return (lhs - rhs).LengthSquared(); + } + + float SHVec4::DistanceSquared3D(const SHVec4& lhs, const SHVec4& rhs) noexcept + { + return (lhs - rhs).LengthSquared3D(); + } + + float SHVec4::Angle(const SHVec4& lhs, const SHVec4& rhs) noexcept + { + const XMVECTOR V1 = XMLoadFloat4(&lhs); + const XMVECTOR V2 = XMLoadFloat4(&rhs); + + return XMVectorGetX(XMVector4AngleBetweenVectors(V1, V2)); + } + + float SHVec4::Angle3D(const SHVec4& lhs, const SHVec4& rhs) noexcept + { + const XMVECTOR V1 = XMLoadFloat4(&lhs); + const XMVECTOR V2 = XMLoadFloat4(&rhs); + + return XMVectorGetX(XMVector3AngleBetweenVectors(V1, V2)); + } + + float SHVec4::Dot(const SHVec4& lhs, const SHVec4& rhs) noexcept + { + return lhs.Dot(rhs); + } + + float SHVec4::Dot3D(const SHVec4& lhs, const SHVec4& rhs) noexcept + { + return lhs.Dot3D(rhs); + } + + SHVec4 SHVec4::Cross3D(const SHVec4& lhs, const SHVec4& rhs) noexcept + { + return lhs.Cross3D(rhs); + } + + SHVec4 SHVec4::Cross(const SHVec4& v1, const SHVec4& v2, const SHVec4& v3) noexcept + { + return v1.Cross(v2, v3); + } + + SHVec4 SHVec4::Project(const SHVec4& v, const SHVec4& u) noexcept + { + SHVec4 result; + + const XMVECTOR U = XMLoadFloat4(&u); + const float V_DOT_U = Dot(v, u); + const float U_LENSQ = u.LengthSquared(); + + XMStoreFloat4(&result, XMVectorScale(U, V_DOT_U / U_LENSQ)); + return result; + } + + SHVec4 SHVec4::Project3D(const SHVec4& v, const SHVec4& u) noexcept + { + SHVec4 result; + + const XMVECTOR U = XMLoadFloat4(&u); + const float V_DOT_U = Dot3D(v, u); + const float U_LENSQ = u.LengthSquared3D(); + + XMStoreFloat4(&result, XMVectorScale(U, V_DOT_U / U_LENSQ)); + result.w = 1.0f; + return result; + } + + SHVec4 SHVec4::Reflect(const SHVec4& v, const SHVec4& normal) noexcept + { + SHVec4 result; + + const XMVECTOR V = XMLoadFloat4(&v); + const XMVECTOR N = XMLoadFloat4(&normal); + + XMStoreFloat4(&result, XMVector4Reflect(V, N)); + result.w = 1.0f; + return result; + } + + SHVec4 SHVec4::Reflect3D(const SHVec4& v, const SHVec4& normal) noexcept + { + SHVec4 result; + + const XMVECTOR V = XMLoadFloat4(&v); + const XMVECTOR N = XMLoadFloat4(&normal); + + XMStoreFloat4(&result, XMVector3Reflect(V, N)); + result.w = 1.0f; + return result; + } + + SHVec4 SHVec4::Transform3D(const SHVec4& v, const SHMatrix& transformMtx) noexcept + { + SHVec4 result; + + const XMVECTOR V = XMLoadFloat4(&v); + const XMMATRIX TF = XMLoadFloat4x4(&transformMtx); + + XMStoreFloat4(&result, XMVector3TransformCoord(V, TF)); + return result; + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Vector/SHVec4.h b/SHADE_Engine/src/Math/Vector/SHVec4.h new file mode 100644 index 00000000..c4caf2c8 --- /dev/null +++ b/SHADE_Engine/src/Math/Vector/SHVec4.h @@ -0,0 +1,133 @@ +/**************************************************************************************** + * \file SHVec4.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for 4D Vector. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +#include +#include +#include + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*-----------------------------------------------------------------------------------*/ + class SHMatrix; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SHVec4 : public DirectX::XMFLOAT4 + { + public: + /*---------------------------------------------------------------------------------*/ + /* Static Data Members */ + /*---------------------------------------------------------------------------------*/ + + static constexpr size_t SIZE = 4U; + + static const SHVec4 Zero; + static const SHVec4 One; + static const SHVec4 UnitX; + static const SHVec4 UnitY; + static const SHVec4 UnitZ; + static const SHVec4 UnitW; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHVec4 (const SHVec4& rhs) = default; + SHVec4 (SHVec4&& rhs) = default; + ~SHVec4 () = default; + + SHVec4 () noexcept; + SHVec4 (float x, float y, float z, float w) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] SHVec4& operator= (const SHVec4& rhs) = default; + [[nodiscard]] SHVec4& operator= (SHVec4&& rhs) = default; + + [[nodiscard]] SHVec4& operator+= (const SHVec4& rhs) noexcept; + [[nodiscard]] SHVec4& operator-= (const SHVec4& rhs) noexcept; + [[nodiscard]] SHVec4& operator*= (const SHVec4& rhs) noexcept; + [[nodiscard]] SHVec4& operator*= (float rhs) noexcept; + [[nodiscard]] SHVec4& operator/= (const SHVec4& rhs) noexcept; + [[nodiscard]] SHVec4& operator/= (float rhs) noexcept; + + [[nodiscard]] SHVec4 operator+ (const SHVec4& rhs) const noexcept; + [[nodiscard]] SHVec4 operator- (const SHVec4& rhs) const noexcept; + [[nodiscard]] SHVec4 operator- () const noexcept; + [[nodiscard]] SHVec4 operator* (const SHVec4& rhs) const noexcept; + [[nodiscard]] SHVec4 operator* (float rhs) const noexcept; + [[nodiscard]] SHVec4 operator/ (const SHVec4& rhs) const noexcept; + [[nodiscard]] SHVec4 operator/ (float rhs) const noexcept; + + [[nodiscard]] bool operator== (const SHVec4& rhs) const noexcept; + [[nodiscard]] bool operator!= (const SHVec4& rhs) const noexcept; + + [[nodiscard]] float operator[] (int index); + [[nodiscard]] float operator[] (size_t index); + [[nodiscard]] float operator[] (int index) const; + [[nodiscard]] float operator[] (size_t index) const; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] float Length () const noexcept; + [[nodiscard]] float Length3D () const noexcept; + [[nodiscard]] float LengthSquared () const noexcept; + [[nodiscard]] float LengthSquared3D () const noexcept; + [[nodiscard]] std::string ToString () const noexcept; + + [[nodiscard]] float Dot (const SHVec4& rhs) const noexcept; + [[nodiscard]] float Dot3D (const SHVec4& rhs) const noexcept; + [[nodiscard]] SHVec4 Cross3D (const SHVec4& rhs) const noexcept; + [[nodiscard]] SHVec4 Cross (const SHVec4& v1, const SHVec4& v2) const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Static Function Members */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] static SHVec4 Normalise (const SHVec4& v) noexcept; + [[nodiscard]] static SHVec4 Normalise3D (const SHVec4& v) noexcept; + [[nodiscard]] static SHVec4 Abs (const SHVec4& v) noexcept; + [[nodiscard]] static SHVec4 Min (const std::initializer_list& vs) noexcept; + [[nodiscard]] static SHVec4 Max (const std::initializer_list& vs) noexcept; + [[nodiscard]] static SHVec4 Clamp (const SHVec4& v, const SHVec4& vMin, const SHVec4& vMax) noexcept; + [[nodiscard]] static SHVec4 Lerp (const SHVec4& a, const SHVec4& b, float t) noexcept; + [[nodiscard]] static SHVec4 ClampedLerp (const SHVec4& a, const SHVec4& b, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept; + + [[nodiscard]] static float Distance (const SHVec4& lhs, const SHVec4& rhs) noexcept; + [[nodiscard]] static float Distance3D (const SHVec4& lhs, const SHVec4& rhs) noexcept; + [[nodiscard]] static float DistanceSquared (const SHVec4& lhs, const SHVec4& rhs) noexcept; + [[nodiscard]] static float DistanceSquared3D (const SHVec4& lhs, const SHVec4& rhs) noexcept; + [[nodiscard]] static float Angle (const SHVec4& lhs, const SHVec4& rhs) noexcept; + [[nodiscard]] static float Angle3D (const SHVec4& lhs, const SHVec4& rhs) noexcept; + [[nodiscard]] static float Dot (const SHVec4& lhs, const SHVec4& rhs) noexcept; + [[nodiscard]] static float Dot3D (const SHVec4& lhs, const SHVec4& rhs) noexcept; + [[nodiscard]] static SHVec4 Cross3D (const SHVec4& lhs, const SHVec4& rhs) noexcept; + [[nodiscard]] static SHVec4 Cross (const SHVec4& v1, const SHVec4& v2, const SHVec4& v3) noexcept; + [[nodiscard]] static SHVec4 Project (const SHVec4& v, const SHVec4& u) noexcept; + [[nodiscard]] static SHVec4 Project3D (const SHVec4& v, const SHVec4& u) noexcept; + [[nodiscard]] static SHVec4 Reflect (const SHVec4& v, const SHVec4& normal) noexcept; + [[nodiscard]] static SHVec4 Reflect3D (const SHVec4& v, const SHVec4& normal) noexcept; + [[nodiscard]] static SHVec4 Transform3D (const SHVec4& v, const SHMatrix& transformMtx) noexcept; + + }; + + SHVec4 operator* (float lhs, const SHVec4& rhs) noexcept; + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/SHCommonTypes.h b/SHADE_Engine/src/SHCommonTypes.h new file mode 100644 index 00000000..97ef7928 --- /dev/null +++ b/SHADE_Engine/src/SHCommonTypes.h @@ -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; +} diff --git a/SHADE_Engine/src/SH_API.h b/SHADE_Engine/src/SH_API.h new file mode 100644 index 00000000..64d1eebe --- /dev/null +++ b/SHADE_Engine/src/SH_API.h @@ -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 \ No newline at end of file diff --git a/SHADE_Engine/src/SHpch.h b/SHADE_Engine/src/SHpch.h index 281b3806..43a832f3 100644 --- a/SHADE_Engine/src/SHpch.h +++ b/SHADE_Engine/src/SHpch.h @@ -22,8 +22,14 @@ #include #include #include +#include #include #include #include #include #include +#include +#include +#include + +#include "Common/SHCommonTypes.h" diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.cpp b/SHADE_Engine/src/Scene/SHSceneGraph.cpp new file mode 100644 index 00000000..9c99fb5a --- /dev/null +++ b/SHADE_Engine/src/Scene/SHSceneGraph.cpp @@ -0,0 +1,475 @@ +/**************************************************************************************** + * \file SHSceneGraph.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Scene Graph & Scene Nodes. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#include + +// Primary Header +#include "SHSceneGraph.h" + +// Project Headers +#include "ECS_Base/System/SHEntityManager.h" +#include "Tools/SHLogger.h" +#include "Tools/SHException.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHSceneNode::SHSceneNode(EntityID eid, SHSceneNode* parent) noexcept + : isActive { true } + , entityID { eid } + , parent { parent } + {} + + + SHSceneNode::SHSceneNode(const SHSceneNode& rhs) noexcept + : isActive { rhs.isActive } + , entityID { rhs.entityID } + , parent { rhs.parent } + { + std::ranges::copy(rhs.children.begin(), rhs.children.end(), std::back_inserter(children)); + } + + SHSceneNode::SHSceneNode(SHSceneNode&& rhs) noexcept + : isActive { rhs.isActive } + , entityID { rhs.entityID } + , parent { rhs.parent } + { + std::ranges::copy(rhs.children.begin(), rhs.children.end(), std::back_inserter(children)); + } + + SHSceneNode& SHSceneNode::operator=(const SHSceneNode& rhs) noexcept + { + if (this == &rhs) + return *this; + + isActive = rhs.isActive; + entityID = rhs.entityID; + parent = rhs.parent; + + children.clear(); + std::ranges::copy(rhs.children.begin(), rhs.children.end(), std::back_inserter(children)); + + return *this; + } + + SHSceneNode& SHSceneNode::operator=(SHSceneNode&& rhs) noexcept + { + isActive = rhs.isActive; + entityID = rhs.entityID; + parent = rhs.parent; + + children.clear(); + std::ranges::copy(rhs.children.begin(), rhs.children.end(), std::back_inserter(children)); + + return *this; + } + + SHSceneGraph::SHSceneGraph() noexcept + : root { nullptr } + {} + + SHSceneGraph::~SHSceneGraph() noexcept + { + SHASSERT(root != nullptr, "Unable to destroy a Scene without a root node!") + + #ifdef _DEBUG + SHLOG_INFO("Destroying Scene Graph...") + #endif + + // Go through the map and release all the nodes + for (auto* node : entityNodeMap | std::views::values) + ReleaseNode(node); + + #ifdef _DEBUG + SHLOG_INFO("Scene Graph Destroyed Successfully!") + #endif + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHSceneNode* SHSceneNode::GetChild(EntityID childID) const noexcept + { + // Error handling + { + if (!SHEntityManager::IsValidEID(childID)) + { + SHLOG_ERROR("Child Entity {} is invalid! Unable to get child from Entity {}", childID, entityID) + return nullptr; + } + + if (children.empty()) + { + SHLOG_WARNING("Entity {} has no children!", entityID) + return nullptr; + } + } + + // Find child + const auto ENTITY_MATCH = [&](const SHSceneNode* node) { return node->GetEntityID() == childID; }; + + const auto CHILD_ITER = std::ranges::find_if(children.begin(), children.end(),ENTITY_MATCH); + if (CHILD_ITER == children.end()) + { + SHLOG_WARNING("Entity {} is not a child of Entity {}! Unable to retrieve child node!", childID, entityID) + return nullptr; + } + + return *CHILD_ITER; + } + + SHSceneNode* SHSceneGraph::GetRoot() const noexcept + { + if (root != nullptr) + return root; + + SHLOG_WARNING("Scene has no root object!") + return nullptr; + } + + SHSceneNode* SHSceneGraph::GetNode(EntityID entityID) const noexcept + { + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid! Unable to Get Scene node!", entityID) + return nullptr; + } + + const auto NODE_ITER = entityNodeMap.find(entityID); + if (NODE_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} cannot be found in the scene! Unable to Get Scene node!", entityID) + return nullptr; + } + + return NODE_ITER->second; + } + + SHSceneNode* SHSceneGraph::GetParent(EntityID entityID) const noexcept + { + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid! Unable to get Parent node!", entityID) + return nullptr; + } + + const auto NODE_ITER = entityNodeMap.find(entityID); + if (NODE_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} cannot be found in the scene! Unable to get Parent node!", entityID) + return nullptr; + } + + return NODE_ITER->second->GetParent(); + } + + SHSceneNode* SHSceneGraph::GetChild(EntityID entityID, SHSceneNode* childNode) const noexcept + { + // Error Handling + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid!", entityID) + return nullptr; + } + + const auto NODE_ITER = entityNodeMap.find(entityID); + if (NODE_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} cannot be found in the scene!", entityID) + return nullptr; + } + + const auto& children = NODE_ITER->second->GetChildren(); + if (children.empty()) + { + SHLOG_WARNING("Entity {} has no children!", entityID) + return nullptr; + } + + const auto CHILD_ITER = std::ranges::find(children.begin(), children.end(), childNode); + if (CHILD_ITER == children.end()) + { + SHLOG_WARNING("Entity {} is not a child of Entity {}!", childNode->GetEntityID(), entityID) + return nullptr; + } + + return *CHILD_ITER; + } + + SHSceneNode* SHSceneGraph::GetChild(EntityID entityID, EntityID childEntityID) const noexcept + { + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid!", entityID) + return nullptr; + } + + const auto NODE_ITER = entityNodeMap.find(entityID); + if (NODE_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} cannot be found in the scene!", entityID) + return nullptr; + } + + return NODE_ITER->second->GetChild(childEntityID); + } + + const std::vector& SHSceneGraph::GetChildren(EntityID entityID) const noexcept + { + // TODO(Diren): Discuss with team best way to handle this + + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid!", entityID) + return root->GetChildren(); + } + + const auto NODE_ITER = entityNodeMap.find(entityID); + if (NODE_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} cannot be found in the scene!", entityID) + return root->GetChildren(); + } + + return NODE_ITER->second->GetChildren(); + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHSceneNode::SetParent(SHSceneNode* parentNode) noexcept + { + if (parentNode == nullptr) + SHLOG_WARNING("Removing Entity {}'s parent", entityID) + + if (parentNode == parent) + return; + + parent = parentNode; + // Update parent's children + parent->AddChild(this); + } + + void SHSceneGraph::SetParent(EntityID entityID, SHSceneNode* parent) const noexcept + { + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid!", entityID) + return; + } + + const auto NODE_ITER = entityNodeMap.find(entityID); + if (NODE_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} cannot be found in the scene!", entityID) + return; + } + + NODE_ITER->second->SetParent(parent); + } + + void SHSceneGraph::SetParent(EntityID entityID, EntityID parent) const noexcept + { + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid! Unable to set parent of an invalid entity!", entityID) + return; + } + + if (!SHEntityManager::IsValidEID(parent)) + { + SHLOG_ERROR("Parent Entity {} is invalid! Unable to set Entity {}'s parent!", parent, entityID) + return; + } + + auto NODE_ITER = entityNodeMap.find(entityID); + if (NODE_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} cannot be found in the scene! Unable to set parent!", entityID) + return; + } + + auto PARENT_ITER = entityNodeMap.find(entityID); + if (PARENT_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} cannot be found in the scene! Unable to parent to Entity {}", parent, entityID) + return; + } + + SHSceneNode* currentNode = NODE_ITER->second; + currentNode->SetParent(PARENT_ITER->second); + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHSceneNode::AddChild(SHSceneNode* newChild) noexcept + { + if (newChild == nullptr) + { + SHLOG_WARNING("Attempting to add a non-existent child to an entity!") + return; + } + + children.emplace_back(newChild); + } + + bool SHSceneNode::RemoveChild(EntityID childID) noexcept + { + if (!SHEntityManager::IsValidEID(childID)) + { + SHLOG_ERROR("Entity {} is invalid!", childID) + return false; + } + + SHSceneNode* removedChild = nullptr; + const auto ENTITY_MATCH = [&](SHSceneNode* node) + { + if (node->GetEntityID() == childID) + { + removedChild = node; + return true; + } + + return false; + }; + + children.end() = std::remove_if(children.begin(), children.end(), ENTITY_MATCH); + removedChild->parent = nullptr; + + return removedChild == nullptr; + } + + bool SHSceneNode::RemoveChild(SHSceneNode* childToRemove) noexcept + { + if (childToRemove == nullptr) + { + SHLOG_WARNING("Attempting to remove non-existent child from Entity {}", entityID) + return false; + } + + children.end() = std::remove(children.begin(), children.end(), childToRemove); + childToRemove->parent = nullptr; + + return true; + } + + void SHSceneNode::RemoveAllChildren() noexcept + { + for (const auto child : children) + child->parent = nullptr; + + children.clear(); + } + + + SHSceneNode* SHSceneGraph::AddNode(EntityID entityID, SHSceneNode* parent) + { + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid!", entityID) + return nullptr; + } + + if (auto NODE_ITER = entityNodeMap.find(entityID); NODE_ITER != entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} already exists in the scene!", entityID) + return NODE_ITER->second; + } + + SHSceneNode* newNode = AllocateNode(entityID); + newNode->SetParent(parent); + + return newNode; + } + + bool SHSceneGraph::RemoveNode(EntityID entityID) noexcept + { + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid!", entityID) + return false; + } + + auto NODE_ITER = entityNodeMap.find(entityID); + if (NODE_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} does not exist in the scene!", entityID) + return false; + } + + // Remove reference of current node from parent + SHSceneNode* currentNode = NODE_ITER->second; + SHSceneNode* parent = currentNode->GetParent(); + if (parent != nullptr) + parent->RemoveChild(currentNode); + + ReleaseNode(currentNode); + return true; + } + + bool SHSceneGraph::RemoveNode(SHSceneNode* nodeToRemove) noexcept + { + // Remove reference of current node from parent + SHSceneNode* parent = nodeToRemove->GetParent(); + if (parent != nullptr) + parent->RemoveChild(nodeToRemove); + + ReleaseNode(nodeToRemove); + return true; + } + + void SHSceneGraph::Reset() noexcept + { + for (auto* node : entityNodeMap | std::views::values) + ReleaseNode(node); + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHSceneNode* SHSceneGraph::AllocateNode(EntityID entityID) + { + SHSceneNode* newNode = new SHSceneNode{entityID}; + + #ifdef _DEBUG + SHLOG_INFO("Allocated a new Scene Node for Entity {}!", entityID) + #endif + + entityNodeMap.emplace(entityID, newNode); + return newNode; + } + + void SHSceneGraph::ReleaseNode(SHSceneNode* node) noexcept + { + SHASSERT(node != nullptr, "Attempting to release Invalid Node!") + + // Remove parent's reference to this node if there is a parent + if (node->GetParent() != nullptr) + node->GetParent()->RemoveChild(node); + + // Remove child's references to this node. Children end up as floating nodes. + for (auto* child : node->GetChildren()) + { + child->SetParent(nullptr); + } + + entityNodeMap.erase(node->GetEntityID()); + delete node; + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.h b/SHADE_Engine/src/Scene/SHSceneGraph.h new file mode 100644 index 00000000..20830065 --- /dev/null +++ b/SHADE_Engine/src/Scene/SHSceneGraph.h @@ -0,0 +1,143 @@ +/**************************************************************************************** + * \file SHSceneGraph.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Scene Graph & Scene Nodes. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +#include + +// Project Headers +#include "ECS_Base/Entity/SHEntity.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SHSceneNode + { + public: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + bool isActive; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + ~SHSceneNode () = default; + + SHSceneNode (EntityID eid, SHSceneNode* parent = nullptr) noexcept; + SHSceneNode (const SHSceneNode& rhs) noexcept; + SHSceneNode (SHSceneNode&& rhs) noexcept; + SHSceneNode& operator= (const SHSceneNode& rhs) noexcept; + SHSceneNode& operator= (SHSceneNode&& rhs) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] EntityID GetEntityID () const noexcept { return entityID ;} + [[nodiscard]] SHSceneNode* GetParent () const noexcept { return parent; } + [[nodiscard]] std::vector& GetChildren () noexcept { return children; } + + [[nodiscard]] SHSceneNode* GetChild (EntityID childID) const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetParent (SHSceneNode* parentNode) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + void AddChild (SHSceneNode* newChild) noexcept; + + bool RemoveChild (EntityID childID) noexcept; + bool RemoveChild (SHSceneNode* childToRemove) noexcept; + + void RemoveAllChildren () noexcept; + + private: + EntityID entityID; + SHSceneNode* parent; + std::vector children; + }; + + class SHSceneGraph + { + public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + using EntityNodeMap = std::unordered_map; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHSceneGraph () noexcept; + ~SHSceneGraph () noexcept; + + SHSceneGraph (const SHSceneGraph&) = delete; + SHSceneGraph (SHSceneGraph&&) = delete; + SHSceneGraph& operator= (const SHSceneGraph&) = delete; + SHSceneGraph& operator= (SHSceneGraph&&) = delete; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] SHSceneNode* GetRoot () const noexcept; + [[nodiscard]] SHSceneNode* GetNode (EntityID entityID) const noexcept; + [[nodiscard]] SHSceneNode* GetParent (EntityID entityID) const noexcept; + [[nodiscard]] SHSceneNode* GetChild (EntityID entityID, SHSceneNode* childNode) const noexcept; + [[nodiscard]] SHSceneNode* GetChild (EntityID entityID, EntityID childEntityID) const noexcept; + [[nodiscard]] const std::vector& GetChildren (EntityID entityID) const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetParent (EntityID entityID, SHSceneNode* parent) const noexcept; + void SetParent (EntityID entityID, EntityID parent) const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + SHSceneNode* AddNode (EntityID entityID, SHSceneNode* parent = nullptr); + bool RemoveNode (EntityID entityID) noexcept; + bool RemoveNode (SHSceneNode* nodeToRemove) noexcept; + void Reset () noexcept; + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + SHSceneNode* root; + EntityNodeMap entityNodeMap; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + SHSceneNode* AllocateNode (EntityID entityID); + void ReleaseNode (SHSceneNode* node) noexcept; + }; + + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Scene/SHSceneManager.cpp b/SHADE_Engine/src/Scene/SHSceneManager.cpp index ba2eafc2..a60df922 100644 --- a/SHADE_Engine/src/Scene/SHSceneManager.cpp +++ b/SHADE_Engine/src/Scene/SHSceneManager.cpp @@ -10,11 +10,11 @@ *********************************************************************/ #include "SHpch.h" #include "SHSceneManager.h" -#include "Engine/ECS_Base/System/SHComponentManager.h" +#include "ECS_Base/System/SHComponentManager.h" //#include "Input/SHInputManager.h" -//#include "Engine/Rendering/Window/SHRenderingWindow.h" -#include "Engine/ECS_Base/System/SHEntityManager.h" -#include "Engine/ECS_Base/System/SHSystemManager.h" +//#include "Rendering/Window/SHRenderingWindow.h" +#include "ECS_Base/System/SHEntityManager.h" +#include "ECS_Base/System/SHSystemManager.h" //#include "FRC/SHFrameRateController.h" //#include "ECS_Base/System/SHApplication.h" diff --git a/SHADE_Engine/src/Scene/SHSceneManager.h b/SHADE_Engine/src/Scene/SHSceneManager.h index 6e5caa37..4139309d 100644 --- a/SHADE_Engine/src/Scene/SHSceneManager.h +++ b/SHADE_Engine/src/Scene/SHSceneManager.h @@ -13,7 +13,7 @@ #define SH_SCENE_MANAGER_H -#include "Engine/ECS_Base/General/SHFamily.h" +#include "ECS_Base/General/SHFamily.h" #include "SHScene.h" #include diff --git a/SHADE_Engine/src/Scripting/SHDotNetRuntime.cpp b/SHADE_Engine/src/Scripting/SHDotNetRuntime.cpp new file mode 100644 index 00000000..89603524 --- /dev/null +++ b/SHADE_Engine/src/Scripting/SHDotNetRuntime.cpp @@ -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 +// Primary Header +#include "SHDotNetRuntime.h" +// Standard Library +#include +// External Dependencies +#include // 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"); + createManagedDelegate = getCoreClrFunctionPtr("coreclr_create_delegate"); + shutdownCoreClr = getCoreClrFunctionPtr("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(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 6.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 6.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()); + } + } +} diff --git a/SHADE_Engine/src/Scripting/SHDotNetRuntime.h b/SHADE_Engine/src/Scripting/SHDotNetRuntime.h new file mode 100644 index 00000000..efb9e54b --- /dev/null +++ b/SHADE_Engine/src/Scripting/SHDotNetRuntime.h @@ -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 // std::setfill, std::setw +#include // std::runtime_error +#include // std::string +#include // std::ostringstream +// External Dependencies +#include // HMODULE +#include // 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 + 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 + 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" diff --git a/SHADE_Engine/src/Scripting/SHDotNetRuntime.hpp b/SHADE_Engine/src/Scripting/SHDotNetRuntime.hpp new file mode 100644 index 00000000..ae8f28e5 --- /dev/null +++ b/SHADE_Engine/src/Scripting/SHDotNetRuntime.hpp @@ -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 + 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(&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 + FunctionType SHDotNetRuntime::getCoreClrFunctionPtr(const std::string& functionName) + { + FunctionType fPtr = reinterpret_cast(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; + } +} diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp new file mode 100644 index 00000000..47c722dd --- /dev/null +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -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 +// Primary Header +#include "SHScriptEngine.h" +// Standard Library +#include // std::fstream +#include // 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 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("net6.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 = +"\n\ + \n\ + net6.0\n\ + x64\n\ + Release;Debug\n\ + \n\ + \n\ + .\\bin_Release-x64\n\ + x64\n\ + \n\ + \n\ + .\\bin_Debug-x64\n\ + x64\n\ + DEBUG;TRACE\n\ + false\n\ + full\n\ + true\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + .\\bin\\SHADE_Managed.dll\n\ + \n\ + \n\ +"; + + // 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 + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".EngineInterface", + "Init" + ); + csEngineLoadScripts = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".EngineInterface", + "LoadScriptAssembly" + ); + csEngineUnloadScripts = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".EngineInterface", + "UnloadScriptAssembly" + ); + csEngineReloadScripts = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".EngineInterface", + "ReloadScriptAssembly" + ); + csEngineExit = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".EngineInterface", + "Exit" + ); + csScriptsFrameSetUp = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", + "FrameSetUp" + ); + csScriptsExecuteFixedUpdate = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", + "ExecuteFixedUpdate" + ); + csScriptsExecuteUpdate = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", + "ExecuteUpdate" + ); + csScriptsExecuteLateUpdate = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", + "ExecuteLateUpdate" + ); + csScriptsFrameCleanUp = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", + "FrameCleanUp" + ); + csScriptsAdd = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", + "AddScriptViaName" + ); + csScriptsRemoveAll = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", + "RemoveAllScripts" + ); + csScriptsRemoveAllImmediately = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", + "RemoveAllScriptsImmediately" + ); + /*csScriptsSerialise = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", + "SerialiseScripts" + ); + csScriptsSerialiseYaml = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", + "SerialiseScriptsYaml" + ); + csScriptDeserialise = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", + "DeserialiseScript" + ); + csScriptDeserialiseYaml = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", + "SerialiseScriptsYaml" + ); + csEditorRenderScripts = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + 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; + } + } + } + +} diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.h b/SHADE_Engine/src/Scripting/SHScriptEngine.h new file mode 100644 index 00000000..442c0053 --- /dev/null +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.h @@ -0,0 +1,247 @@ +/************************************************************************************//*! +\file ScriptEngine.h +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 17, 2021 +\brief Contains the interface 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. +*//*************************************************************************************/ +#pragma once + +// STL Includes +#include + +// Project Headers +#include "SHDotNetRuntime.h" +#include "ECS_Base/SHECSMacros.h" +#include "ECS_Base/Entity/SHEntity.h" +#include "SH_API.h" + +namespace SHADE +{ + /// + /// Manages initialisation of the DotNetRuntime and interfacing with CLR code written + /// and executed on .NET. + /// + class SH_API SHScriptEngine + { + public: + /*-----------------------------------------------------------------------------*/ + /* Constructor */ + /*-----------------------------------------------------------------------------*/ + SHScriptEngine() = delete; + + /*-----------------------------------------------------------------------------*/ + /* Lifecycle Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Initialises the DotNetRuntime and retrieves function pointers to all + /// functions on the CLR used to interface with the engine. + /// + static void Init(); + /// + /// Loads the managed script assembly. Ensure this is only called after + /// UnloadScriptAssembly() has been called. + /// + static void UnloadScriptAssembly(); + /// + /// Unloads the managed script assembly. + /// Take note that this will clear all existing scripts, ensure that the scene + /// is saved before doing so. + /// + static void LoadScriptAssembly(); + /// + /// Reloads the managed script assembly. + /// Take note that this will clear all existing scripts, ensure that the scene + /// is saved before doing so. + /// + static void ReloadScriptAssembly(); + /// + /// Executes the FixedUpdate()s of the Scripts that are attached to + /// Entities. + /// + static void ExecuteFixedUpdates(); + /// + /// Shuts down the DotNetRuntime. + /// + static void Exit(); + + /*-----------------------------------------------------------------------------*/ + /* Script Manipulation Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Adds a Script to a specified Entity. Note that while you can call this + /// multiple times on a specified Entity, it will work for all intents and + /// purposes but GetScript<T>() (C# only) currently only + /// gives you the first Script added of the specified type. + /// + /// The entity to add a script to. + /// Type name of the script to add. + /// + /// True if successfully added. False otherwise with the error logged to the + /// console. + /// + static bool AddScript(const SHEntity& entity, const std::string_view& scriptName); + /// + /// Removes all Scripts attached to the specified Entity. Does not do anything + /// if the specified Entity is invalid or does not have any Scripts + /// attached. + /// + /// The entity to remove the scripts from. + static void RemoveAllScripts(const SHEntity& entity); + /// + /// Removes all Scripts attached to the specified Entity. Unlike + /// RemoveAllScripts(), this removes all the scripts immediately. + /// Does not do anything if the specified Entity is invalid or does not have any + /// Scripts attached. + /// + /// The entity to remove the scripts from. + /// + /// Whether or not to call OnDestroy on the scripts. This is ignored if not in + /// play mode. + /// + static void RemoveAllScriptsImmediately(const SHEntity& entity, bool callOnDestroy); + + /*-----------------------------------------------------------------------------*/ + /* Script Serialisation Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Generates a JSON string that represents the set of Scripts attached to the + /// specified Entity. + /// + /// The Entity to Serialise. + /// + /// String that represents the set of scripts attached to the specified Entity. + /// + static std::string SerialiseScripts(const SHEntity& entity); + /// + /// Loads the specified JSON string and creates a Script for the specified Entity + /// based on the specified JSON string. + /// + /// The Entity to deserialise a Script on to. + /// + /// The YAML string that represents the Script to load into the Entity. + /// + static void DeserialiseScript(const SHEntity& entity, const std::string& yaml); + + /*-----------------------------------------------------------------------------*/ + /* Script Editor Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Renders the set of attached Scripts for the specified Entity into the + /// inspector. + ///
+ /// This function is meant for consumption from native code in the inspector + /// rendering code. + ///
+ /// The Entity to render the Scripts of. + static void RenderScriptsInInspector(const SHEntity& entity); + + /*-----------------------------------------------------------------------------*/ + /* Static Utility Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Utilises execution of a external batch file for invoking the dotnet build + /// tool to compile C# scripts in the Assets folder into the SHADE_Scripting + /// C# assembly DLL. + /// + /// + /// Whether or not a debug build will be built. Only debug built C# assemblies + /// can be debugged. + /// + /// Whether or not the build succeeded. + static bool BuildScriptAssembly(bool debug = false); + /// + /// Generates a .csproj file for editing and compiling the C# scripts. + /// + /// File path to the generated file. + static void GenerateScriptsCsProjFile(const std::filesystem::path& path); + + private: + /*-----------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------*/ + using CsFuncPtr = void(*)(void); + using CsScriptManipFuncPtr = bool(*)(EntityID, const char*); + using CsScriptBasicFuncPtr = void(*)(EntityID); + using CsScriptOptionalFuncPtr = void(*)(EntityID, bool); + using CsScriptSerialiseFuncPtr = bool(*)(EntityID, char*, int); + using CsScriptDeserialiseFuncPtr = bool(*)(EntityID, const char*); + using CsScriptSerialiseYamlFuncPtr = bool(*)(EntityID, void*); + using CsScriptEditorFuncPtr = void(*)(EntityID); + + /*-----------------------------------------------------------------------------*/ + /* Constants */ + /*-----------------------------------------------------------------------------*/ + static constexpr std::string_view DEFAULT_CSHARP_LIB_NAME = "SHADE_Managed"; + static constexpr std::string_view MANAGED_SCRIPT_LIB_NAME = "SHADE_Scripting"; + static const std::string DEFAULT_CSHARP_NAMESPACE; + + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + static SHDotNetRuntime dotNet; + // Function Pointers to CLR Code + // - Engine Lifecycle + static CsFuncPtr csEngineInit; + static CsFuncPtr csEngineLoadScripts; + static CsFuncPtr csEngineUnloadScripts; + static CsFuncPtr csEngineReloadScripts; + static CsFuncPtr csEngineExit; + // - Scripts Store + static CsFuncPtr csScriptsFrameSetUp; + static CsFuncPtr csScriptsExecuteFixedUpdate; + static CsFuncPtr csScriptsExecuteUpdate; + static CsFuncPtr csScriptsExecuteLateUpdate; + static CsFuncPtr csScriptsFrameCleanUp; + static CsScriptManipFuncPtr csScriptsAdd; + static CsScriptBasicFuncPtr csScriptsRemoveAll; + static CsScriptOptionalFuncPtr csScriptsRemoveAllImmediately; + static CsScriptSerialiseFuncPtr csScriptsSerialise; + static CsScriptDeserialiseFuncPtr csScriptDeserialise; + static CsScriptSerialiseYamlFuncPtr csScriptsSerialiseYaml; + static CsScriptSerialiseYamlFuncPtr csScriptDeserialiseYaml; + // - Editor + static CsScriptEditorFuncPtr csEditorRenderScripts; + // Delegates + /*ECS::EntityEvent::Delegate onEntityCreate; + ECS::EntityEvent::Delegate onEntityDestroy;*/ + + /*-----------------------------------------------------------------------------*/ + /* Helper Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Loads all the function pointers to CLR code that we need to execute. + /// + static void loadFunctions(); + /// + /// Reads the file via the specified path that represents a build log of error + /// and warning messages. + /// + /// + /// File path to the build log of script builds done by BuildScriptAssembly() to + /// dump and process. + /// + static void dumpBuildLog(const std::string_view& buildLogPath); + /// + /// Deletes the file as specified by the file path. + /// + /// File path to the file to delete. + static void deleteFile(const std::string_view& filePath); + /// + /// Deletes the folder and all files in it as specified by the file path. + /// + /// File path to the file to delete. + static void deleteFolder(const std::string_view& filePath); + /// + /// Checks if a specified file exists. + /// + /// File path to the file to check. + /// True if the file exists + static bool fileExists(const std::string_view& filePath); + static DWORD execProcess(const std::wstring& path, const std::wstring& args); + }; +} diff --git a/SHADE_Engine/src/Tools/SHExceptionHandler.h b/SHADE_Engine/src/Tools/SHExceptionHandler.h index dd1d7596..32cda608 100644 --- a/SHADE_Engine/src/Tools/SHExceptionHandler.h +++ b/SHADE_Engine/src/Tools/SHExceptionHandler.h @@ -12,13 +12,15 @@ #include +#include "SH_API.h" + namespace SHADE { /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - class SHExceptionHandler + class SH_API SHExceptionHandler { public: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Tools/SHFileUtilties.cpp b/SHADE_Engine/src/Tools/SHFileUtilties.cpp new file mode 100644 index 00000000..0e75b16a --- /dev/null +++ b/SHADE_Engine/src/Tools/SHFileUtilties.cpp @@ -0,0 +1,30 @@ +/************************************************************************************//*! +\file SHFileUtilities.cpp +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 15, 2022 +\brief Contains the definition of functions of the SHFileUtilities static class. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Header +#include "SHpch.h" +// Primary Header +#include "SHFileUtilties.h" +// Standard Libraries +#include +// External Dependencies +#include // GetModuleFileName, PathRemoveFileSpec + +namespace SHADE +{ + void SHFileUtilities::SetWorkDirToExecDir() + { + TCHAR currentExecFilePath[MAX_PATH] = { '\0' }; + GetModuleFileName(nullptr, currentExecFilePath, MAX_PATH); + PathRemoveFileSpec(currentExecFilePath); + std::filesystem::current_path(currentExecFilePath); + } +} diff --git a/SHADE_Engine/src/Tools/SHFileUtilties.h b/SHADE_Engine/src/Tools/SHFileUtilties.h new file mode 100644 index 00000000..b9ba164b --- /dev/null +++ b/SHADE_Engine/src/Tools/SHFileUtilties.h @@ -0,0 +1,38 @@ +/************************************************************************************//*! +\file SHFileUtilities.h +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 15, 2022 +\brief Contains the SHFileUtilities static class. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ + +// Project Headers +#include "SH_API.h" + +namespace SHADE +{ + /*!************************************************************************************ + + \class SHFileUtilities + + \brief + Static class that contains functions for working with files and directories. + + **************************************************************************************/ + class SH_API SHFileUtilities + { + public: + /*!********************************************************************************** + + \brief + Sets the application's current working directory to the application executable's + directory. + + ************************************************************************************/ + static void SetWorkDirToExecDir(); + }; +} diff --git a/SHADE_Engine/src/Tools/SHLogger.cpp b/SHADE_Engine/src/Tools/SHLogger.cpp index 7b39e979..9c1e76fc 100644 --- a/SHADE_Engine/src/Tools/SHLogger.cpp +++ b/SHADE_Engine/src/Tools/SHLogger.cpp @@ -30,8 +30,9 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ /* Static Data Member Definitions */ /*-----------------------------------------------------------------------------------*/ - unsigned char SHLogger::configFlags = DEFAULT_CONFIG_FLAG; - SHLogger::DateFormat SHLogger::dateFormat = SHLogger::DateFormat::DD_MM_YY; + unsigned char SHLogger::configFlags = DEFAULT_CONFIG_FLAG; + SHLogger::DateFormat SHLogger::dateFormat = SHLogger::DateFormat::DD_MM_YY; + SHLogger::Logger SHLogger::logger = nullptr; std::string SHLogger::trivialPattern; std::string SHLogger::verbosePattern; @@ -142,7 +143,7 @@ namespace SHADE /* Public Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHLogger::Initialise(const Config& config) + SHLogger::Logger SHLogger::Initialise(const Config& config) { SetConfig(config); @@ -176,10 +177,10 @@ namespace SHADE FILE_SINK->set_pattern(trivialPattern + "%v"); // Create and register logger with spdlog - const auto LOGGER = std::make_shared(SHLOGGER_NAME, sinks.begin(), sinks.end()); - LOGGER->set_level(spdlog::level::trace); - LOGGER->flush_on(spdlog::level::trace); - register_logger(LOGGER); + logger = std::make_shared(SHLOGGER_NAME, sinks.begin(), sinks.end()); + logger->set_level(spdlog::level::trace); + logger->flush_on(spdlog::level::trace); + spdlog::register_logger(logger); // Flush every 3 seconds spdlog::flush_every(std::chrono::seconds(config.flushTime)); @@ -190,6 +191,8 @@ namespace SHADE { std::cout << "Log initialisation failed: " << e.what() << std::endl; } + + return logger; } void SHLogger::Shutdown() noexcept @@ -211,6 +214,143 @@ namespace SHADE sinks[1]->set_pattern(verbosePattern + "%v"); // File Sink } + void SHLogger::LogInfo(const std::string& msg) noexcept + { + SHLOG_INFO(msg) + } + + void SHLogger::LogVerboseInfo(const std::string& msg, const std::source_location& src) noexcept + { + const bool SHOW_SRC_FILE = configFlags & (1U << 3); + const bool SHOW_SRC_LINE = configFlags & (1U << 4); + + std::stringstream ss; + ss << "["; + if (SHOW_SRC_FILE) + { + ss << std::filesystem::path(src.file_name()).filename().string() << ", "; + if (SHOW_SRC_LINE) + { + ss << src.line() << ", "; + } + } + + ss << src.function_name() << "] " << msg; + + SHLOG_INFO(ss.str()) + } + + void SHLogger::LogWarning(const std::string& msg) noexcept + { + SHLOG_WARNING(msg) + } + + void SHLogger::LogVerboseWarning(const std::string& msg, const std::source_location& src) noexcept + { + const bool SHOW_SRC_FILE = configFlags & (1U << 3); + const bool SHOW_SRC_LINE = configFlags & (1U << 4); + + std::stringstream ss; + ss << "["; + if (SHOW_SRC_FILE) + { + ss << std::filesystem::path(src.file_name()).filename().string() << ", "; + if (SHOW_SRC_LINE) + { + ss << src.line() << ", "; + } + } + + ss << src.function_name() << "] " << msg; + + SHLOG_WARNING(ss.str()) + } + + void SHLogger::LogError(const std::string& msg) noexcept + { + SHLOG_ERROR(msg) + } + + void SHLogger::LogVerboseError(const std::string& msg, const std::source_location& src) noexcept + { + const bool SHOW_SRC_FILE = configFlags & (1U << 3); + const bool SHOW_SRC_LINE = configFlags & (1U << 4); + + std::stringstream ss; + ss << "["; + if (SHOW_SRC_FILE) + { + ss << std::filesystem::path(src.file_name()).filename().string() << ", "; + if (SHOW_SRC_LINE) + { + ss << src.line() << ", "; + } + } + + ss << src.function_name() << "] " << msg; + + SHLOG_ERROR(ss.str()) + } + + void SHLogger::LogCritical(const std::string& msg) noexcept + { + SHLOG_CRITICAL(msg) + } + + void SHLogger::LogVerboseCritical(const std::string& msg, const std::source_location& src) noexcept + { + const bool SHOW_SRC_FILE = configFlags & (1U << 3); + const bool SHOW_SRC_LINE = configFlags & (1U << 4); + + std::stringstream ss; + ss << "["; + if (SHOW_SRC_FILE) + { + ss << std::filesystem::path(src.file_name()).filename().string() << ", "; + if (SHOW_SRC_LINE) + { + ss << src.line() << ", "; + } + } + + ss << src.function_name() << "] " << msg; + + SHLOG_CRITICAL(ss.str()) + } + + void SHLogger::LogFloor() noexcept + { + SHLOG_FLOOR() + } + + #ifdef _DEBUG + void SHLogger::LogTrace(const std::string& msg) noexcept + { + SHLOG_TRACE(msg) + } + + void SHLogger::LogVerboseTrace(const std::string& msg, const std::source_location& src) noexcept + { + const bool SHOW_SRC_FILE = configFlags & (1U << 3); + const bool SHOW_SRC_LINE = configFlags & (1U << 4); + + std::stringstream ss; + ss << "["; + if (SHOW_SRC_FILE) + { + ss << std::filesystem::path(src.file_name()).filename().string() << ", "; + if (SHOW_SRC_LINE) + { + ss << src.line() << ", "; + } + } + + ss << src.function_name() << "] " << msg; + + SHLOG_TRACE(ss.str()) + } + #endif + /*-----------------------------------------------------------------------------------*/ /* Private Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Tools/SHLogger.h b/SHADE_Engine/src/Tools/SHLogger.h index ac5f9308..b2c01b73 100644 --- a/SHADE_Engine/src/Tools/SHLogger.h +++ b/SHADE_Engine/src/Tools/SHLogger.h @@ -12,9 +12,11 @@ #include #include +#include #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE #include +#include "SH_API.h" /*-------------------------------------------------------------------------------------*/ /* Macros */ @@ -27,13 +29,15 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - class SHLogger + class SH_API SHLogger { public: /*---------------------------------------------------------------------------------*/ /* Type Definitions */ /*---------------------------------------------------------------------------------*/ + using Logger = std::shared_ptr; + enum class ClockFormat { _12HR, _24HR }; enum class DateFormat @@ -70,33 +74,33 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] static const std::string& GetTrivialPattern () noexcept { return trivialPattern; } - [[nodiscard]] static const std::string& GetVerbosePattern () noexcept { return verbosePattern; } + [[nodiscard]] static const std::string& GetTrivialPattern () noexcept { return trivialPattern; } + [[nodiscard]] static const std::string& GetVerbosePattern () noexcept { return verbosePattern; } /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - static void SetTrivialPattern (const std::string& pattern) noexcept { trivialPattern = pattern; } - static void SetVerbosePattern (const std::string& pattern) noexcept { verbosePattern = pattern; } + static void SetTrivialPattern (const std::string& pattern) noexcept { trivialPattern = pattern; } + static void SetVerbosePattern (const std::string& pattern) noexcept { verbosePattern = pattern; } - static void SetConfig (const Config& config) noexcept; + static void SetConfig (const Config& config) noexcept; - static void SetShowTime (bool showTime) noexcept; - static void SetShowDate (bool showDate) noexcept; - static void SetShowFunctionFileName (bool showFunctionFileName) noexcept; - static void SetShowFunctionLineNumber (bool showFunctionLineNumber) noexcept; + static void SetShowTime (bool showTime) noexcept; + static void SetShowDate (bool showDate) noexcept; + static void SetShowFunctionFileName (bool showFunctionFileName) noexcept; + static void SetShowFunctionLineNumber (bool showFunctionLineNumber) noexcept; - static void SetClockFormat (ClockFormat newClockFormat) noexcept; - static void SetDateFormat (DateFormat newDateFormat) noexcept; + static void SetClockFormat (ClockFormat newClockFormat) noexcept; + static void SetDateFormat (DateFormat newDateFormat) noexcept; - static void SetFileName (const std::string& logFileName) noexcept; - static void SetDirectoryPath (const std::filesystem::path& logDirectoryPath) noexcept; + static void SetFileName (const std::string& logFileName) noexcept; + static void SetDirectoryPath (const std::filesystem::path& logDirectoryPath) noexcept; - static void SetFlushTime (int seconds) noexcept; - static void SetFlushTime (size_t seconds) noexcept { spdlog::flush_every(std::chrono::seconds(seconds)); } + static void SetFlushTime (int seconds) noexcept; + static void SetFlushTime (size_t seconds) noexcept { spdlog::flush_every(std::chrono::seconds(seconds)); } /*---------------------------------------------------------------------------------*/ /* Function Members */ @@ -106,17 +110,34 @@ namespace SHADE * @brief Creates a console and a file to log to. * @param[in] config The configuration parameters for the logger. */ - static void Initialise (const Config& config = Config{}); + static Logger Initialise (const Config& config = Config{}); static void Shutdown () noexcept; /** * @brief The next message logged by the logger will be set to follow the trivial pattern. */ - static void UseTrivialPattern () noexcept; + static void UseTrivialPattern () noexcept; /** * @brief The next message logged by the logger will be set to follow the verbose pattern. */ - static void UseVerbosePattern () noexcept; + static void UseVerbosePattern () noexcept; + + /// Logging Functions to interface with C++/CLI. + + static void LogInfo (const std::string& msg) noexcept; + static void LogVerboseInfo (const std::string& msg, const std::source_location& src= std::source_location::current()) noexcept; + static void LogWarning (const std::string& msg) noexcept; + static void LogVerboseWarning (const std::string& msg, const std::source_location& src = std::source_location::current()) noexcept; + static void LogError (const std::string& msg) noexcept; + static void LogVerboseError (const std::string& msg, const std::source_location& src = std::source_location::current()) noexcept; + static void LogCritical (const std::string& msg) noexcept; + static void LogVerboseCritical (const std::string& msg, const std::source_location& src = std::source_location::current()) noexcept; + static void LogFloor () noexcept; + + #ifdef _DEBUG + static void LogTrace (const std::string& msg) noexcept; + static void LogVerboseTrace (const std::string& msg, const std::source_location& src = std::source_location::current()) noexcept; + #endif private: /*---------------------------------------------------------------------------------*/ @@ -126,7 +147,9 @@ namespace SHADE static constexpr short DEFAULT_CONSOLE_LEN = 1024; static unsigned char configFlags; // Initialised 0 0 FuncLine# FuncFileName Date TimeFormat Time - static DateFormat dateFormat; + static DateFormat dateFormat; + + static Logger logger; static std::string trivialPattern; static std::string verbosePattern; @@ -171,4 +194,7 @@ namespace SHADE #define SHLOGV_CRITICAL(format, ...) SHADE::SHLogger::UseVerbosePattern(); SPDLOG_LOGGER_CRITICAL(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__); // Misc Logging Macros -#define SHLOG_FLOOR() SHADE::SHLogger::UseTrivialPattern(); SPDLOG_LOGGER_INFO(spdlog::get(SHLOGGER_NAME), "--------------------------------"); \ No newline at end of file +#define SHLOG_FLOOR() SHADE::SHLogger::UseTrivialPattern(); SPDLOG_LOGGER_INFO(spdlog::get(SHLOGGER_NAME), "--------------------------------"); + +// For use outside the library to register the logger +#define SHLOG_REGISTER(logger) spdlog::register_logger(logger); spdlog::set_level(spdlog::level::level_enum::trace); diff --git a/SHADE_Engine/src/Tools/SHStringUtils.cpp b/SHADE_Engine/src/Tools/SHStringUtils.cpp new file mode 100644 index 00000000..a2594888 --- /dev/null +++ b/SHADE_Engine/src/Tools/SHStringUtils.cpp @@ -0,0 +1,52 @@ +/************************************************************************************//*! +\file StringUtilities.cpp +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Nov 29, 2021 +\brief Contains the definition of functions for working with strings. + +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 +// Primary Header +#include "SHStringUtils.h" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Utility Functions */ + /*---------------------------------------------------------------------------------*/ + std::vector SHStringUtils::Split(const std::string& str, const char& delim) + { + return Split(str, delim); + } + std::vector SHStringUtils::Split(const std::wstring& str, const wchar_t& delim) + { + return Split(str, delim); + } + std::string SHStringUtils::WstrToStr(const std::wstring& wstr) + { + static std::vector buffer; + const int STR_SIZE = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast(wstr.size()), nullptr, 0, nullptr, nullptr) + 1 /* Null Terminator */; + buffer.resize(STR_SIZE); + WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast(wstr.size()), buffer.data(), MAX_PATH, nullptr, nullptr); + return std::string(buffer.data()); + } + std::wstring SHStringUtils::StrToWstr(const std::string& str) + { + static std::vector buffer; + const int WSTR_SIZE = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.size()), nullptr, 0) + 1 /* Null Terminator */; + buffer.resize(WSTR_SIZE); + MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.size()), buffer.data(), WSTR_SIZE); + return std::wstring(buffer.data()); + } + + std::string SHStringUtils::GetWin32ErrorMessage(unsigned long errorCode) + { + return std::system_category().message(errorCode); + } + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Tools/SHStringUtils.h b/SHADE_Engine/src/Tools/SHStringUtils.h new file mode 100644 index 00000000..1c895b99 --- /dev/null +++ b/SHADE_Engine/src/Tools/SHStringUtils.h @@ -0,0 +1,81 @@ +/************************************************************************************//*! +\file StringUtilities.h +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Nov 29, 2021 +\brief Contains the declaration of functions for working with files and folders. + +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 // std::basic_string +#include // std::vector + +namespace SHADE +{ + /// + /// Contains useful functions for operating on strings. + /// + class SHStringUtils + { + public: + /*-----------------------------------------------------------------------------*/ + /* Utility Functions */ + /*-----------------------------------------------------------------------------*/ + + /// + /// Splits a string separated by a specified delimiter into a vector of strings. + /// + /// Internal type of each element in the string. + /// Read only reference to the string to split. + /// Read only reference to the delimiter. + /// Vector of strings that have been split. + template + static std::vector> Split(const std::basic_string& str, const T& delim); + /// + /// Splits a string separated by a specified delimiter into a vector of strings. + /// Overload of Split() to allow for string literals to be accepted. + /// + /// Read only reference to the string to split. + /// Read only reference to the delimiter. + /// Vector of strings that have been split. + static std::vector Split(const std::string& str, const char& delim); + /// + /// Splits a string separated by a specified delimiter into a vector of strings. + /// Overload of Split() to allow for wide string literals to be accepted. + /// + /// Read only reference to the string to split. + /// Read only reference to the delimiter. + /// Vector of strings that have been split. + static std::vector Split(const std::wstring& str, const wchar_t& delim); + /// + /// Converts a wstring to a string. + /// + /// wstring to convert. + /// The converted wstring in string form. + static std::string WstrToStr(const std::wstring& wstr); + /// + /// Converts a string to a wstring. + /// + /// string to convert. + /// The converted string in wstring form. + static std::wstring StrToWstr(const std::string& str); + /// + /// Retrieves the error message associated with a Win32 error code. + /// + /// Win32 error code to decode. + /// String that represents the Win32 error. + static std::string GetWin32ErrorMessage(unsigned long errorCode); + + private: + /*-------------------------------------------------------------------------------*/ + /* Constructors/Destructors */ + /*-------------------------------------------------------------------------------*/ + SHStringUtils() = delete; + }; +} + +#include "SHStringUtils.hpp" diff --git a/SHADE_Engine/src/Tools/SHStringUtils.hpp b/SHADE_Engine/src/Tools/SHStringUtils.hpp new file mode 100644 index 00000000..8b83187a --- /dev/null +++ b/SHADE_Engine/src/Tools/SHStringUtils.hpp @@ -0,0 +1,46 @@ +/************************************************************************************//*! +\file StringUtilities.hpp +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Nov 29, 2021 +\brief Contains the implementation of template functions for working with files + and folders. + +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 Header +#include "SHStringUtils.h" + +namespace SHADE +{ + /*-------------------------------------------------------------------------------*/ + /* Template Function Definitions */ + /*-------------------------------------------------------------------------------*/ + template + inline std::vector> SHStringUtils::Split(const std::basic_string& str, const T& delim) + { + std::vector> results; + std::basic_string remaining = str; + + // Go through looking for delimiters + while (true) + { + const size_t DELIM_POS = remaining.find_first_of(delim); + results.emplace_back(remaining.substr(0, DELIM_POS)); + + // Check if we hit the end of the string + if (DELIM_POS == remaining.npos) + { + break; + } + + // Otherwise, cut the remainder + remaining = remaining.substr(DELIM_POS + 1); + } + + return results; + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Tools/SHUtilities.h b/SHADE_Engine/src/Tools/SHUtilities.h new file mode 100644 index 00000000..543c771c --- /dev/null +++ b/SHADE_Engine/src/Tools/SHUtilities.h @@ -0,0 +1,50 @@ +/**************************************************************************************** + * \file SHutilities.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for various utility functions. + * + * \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 "Math/SHMathHelpers.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Concepts */ + /*-----------------------------------------------------------------------------------*/ + + template + concept IsEnum = std::is_enum_v; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SHUtilities + { + public: + /*---------------------------------------------------------------------------------*/ + /* Static Function Members */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief Converts an enum class member from it's type to any other type. + * @tparam InputType Restricted to an enum class + * @tparam OutputType The type to convert the enum class member to. Defaults to int. + * @param[in] enumClassMember A member of the specified enum class. + * @returns The value of the enum class member in the output type. + */ + template + static constexpr OutputType ConvertEnum(InputType enumClassMember) noexcept; + + }; + +} // namespace SHADE + +#include "SHUtilities.hpp" + diff --git a/SHADE_Engine/src/Tools/SHUtilities.hpp b/SHADE_Engine/src/Tools/SHUtilities.hpp new file mode 100644 index 00000000..0e21a9d0 --- /dev/null +++ b/SHADE_Engine/src/Tools/SHUtilities.hpp @@ -0,0 +1,28 @@ +/**************************************************************************************** + * \file SHutilities.hpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for various templated utility functions. + * + * \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 + +// Primary Header +#include "SHUtilities.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Static Function Members Definitions */ + /*-----------------------------------------------------------------------------------*/ + + template + constexpr OutputType SHUtilities::ConvertEnum (InputType enumClassMember) noexcept + { + return static_cast(enumClassMember); + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Managed/premake5.lua b/SHADE_Managed/premake5.lua new file mode 100644 index 00000000..092e92af --- /dev/null +++ b/SHADE_Managed/premake5.lua @@ -0,0 +1,74 @@ +project "SHADE_Managed" + kind "SharedLib" + language "C++" + clr "NetCore" + dotnetframework "net6.0" + cppdialect "C++17" + targetdir (outputdir) + objdir (interdir) + systemversion "latest" + pchheader "SHpch.h" + pchsource "%{prj.location}/src/SHpch.cpp" + staticruntime "off" + + files + { + "%{prj.location}/src/**.hxx", + "%{prj.location}/src/**.h++", + "%{prj.location}/src/**.cxx", + "%{prj.location}/src/**.h", + "%{prj.location}/src/**.hpp", + "%{prj.location}/src/**.c", + "%{prj.location}/src/**.cpp", + } + + includedirs + { + "%{prj.location}/src", + "%{IncludeDir.spdlog}/include", + "%{IncludeDir.imgui}", + "%{IncludeDir.imguizmo}", + "%{IncludeDir.imnodes}", + "%{IncludeDir.yamlcpp}", + "%{IncludeDir.RTTR}/include", + "%{wks.location}/SHADE_Engine/src" + } + + links + { + "yaml-cpp", + "imgui", + "SHADE_Engine" + } + + disablewarnings + { + "4251" + } + + defines + { + "NOMINMAX" + } + + flags + { + "MultiProcessorCompile" + } + + dependson + { + "yaml-cpp", + "imgui", + "SHADE_Engine" + } + + warnings 'Extra' + + filter "configurations:Debug" + symbols "On" + defines {"_DEBUG"} + + filter "configurations:Release" + optimize "On" + defines{"_RELEASE"} diff --git a/SHADE_Managed/src/AssemblyInfo.cxx b/SHADE_Managed/src/AssemblyInfo.cxx new file mode 100644 index 00000000..234bda73 --- /dev/null +++ b/SHADE_Managed/src/AssemblyInfo.cxx @@ -0,0 +1,39 @@ +/************************************************************************************//*! +\file AssemblyInfo.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 24, 2021 +\brief Defines the properties of this managed .NET Assembly. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#include "SHpch.h" + +/*-------------------------------------------------------------------------------------*/ +/* Using Declarations */ +/*-------------------------------------------------------------------------------------*/ +using namespace System; +using namespace System::Reflection; +using namespace System::Runtime::CompilerServices; +using namespace System::Runtime::InteropServices; +using namespace System::Security::Permissions; + +/*-------------------------------------------------------------------------------------*/ +/* Assembly Properties */ +/*-------------------------------------------------------------------------------------*/ +[assembly:AssemblyTitleAttribute(L"SHADE_Managed")]; +[assembly:AssemblyDescriptionAttribute(L"")]; +[assembly:AssemblyConfigurationAttribute(L"")]; +[assembly:AssemblyCompanyAttribute(L"")]; +[assembly:AssemblyProductAttribute(L"SHADE_Managed")]; +[assembly:AssemblyCopyrightAttribute(L"Copyright (C) 2022 DigiPen Institute of Technology")]; +[assembly:AssemblyTrademarkAttribute(L"")]; +[assembly:AssemblyCultureAttribute(L"")]; + +[assembly:AssemblyVersionAttribute("1.0.*")]; + +[assembly:ComVisible(false)]; diff --git a/SHADE_Managed/src/Components/Component.cxx b/SHADE_Managed/src/Components/Component.cxx new file mode 100644 index 00000000..a6afc5cc --- /dev/null +++ b/SHADE_Managed/src/Components/Component.cxx @@ -0,0 +1,107 @@ +/************************************************************************************//*! +\file Component.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 27, 2021 +\brief Contains the definition of the functions for the Component class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "Components/Component.hxx" +// External Dependencies +#include "Engine/ECS.hxx" +// Project Headers +#include "Scripts/ScriptStore.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Component Access Functions */ + /*---------------------------------------------------------------------------------*/ + generic + T BaseComponent::AddComponent() + { + return ECS::AddComponent(owner.GetEntity()); + } + generic + T BaseComponent::GetComponent() + { + return ECS::GetComponent(owner.GetEntity()); + } + generic + void BaseComponent::RemoveComponent() + { + ECS::RemoveComponent(owner.GetEntity()); + } + + /*---------------------------------------------------------------------------------*/ + /* Script Access Functions */ + /*---------------------------------------------------------------------------------*/ + generic + T BaseComponent::AddScript() + { + return ScriptStore::AddScript(owner.GetEntity()); + } + generic + T BaseComponent::GetScript() + { + return ScriptStore::GetScript(owner.GetEntity()); + } + + generic + System::Collections::Generic::IEnumerable^ BaseComponent::GetScripts() + { + return ScriptStore::GetScripts(owner.GetEntity()); + } + + generic + void BaseComponent::RemoveScript() + { + ScriptStore::RemoveScript(owner.GetEntity()); + } + + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + BaseComponent::BaseComponent(Entity entity) + : owner { entity } + {} + + /*---------------------------------------------------------------------------------*/ + /* IEquatable */ + /*---------------------------------------------------------------------------------*/ + bool BaseComponent::Equals(BaseComponent^ other) + { + if (other == nullptr) + return false; + return owner == other->owner; + } + + /*---------------------------------------------------------------------------------*/ + /* Object */ + /*---------------------------------------------------------------------------------*/ + bool BaseComponent::Equals(Object^ o) + { + try + { + BaseComponent^ cmp = safe_cast(o); + return Equals(cmp); + } + catch (System::InvalidCastException^) + { + return false; + } + } + + int BaseComponent::GetHashCode() + { + return owner.GetHashCode(); + } +} diff --git a/SHADE_Managed/src/Components/Component.h++ b/SHADE_Managed/src/Components/Component.h++ new file mode 100644 index 00000000..e2a20998 --- /dev/null +++ b/SHADE_Managed/src/Components/Component.h++ @@ -0,0 +1,41 @@ +/************************************************************************************//*! +\file Component.h++ +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 27, 2021 +\brief Contains the definition of templated functions for the managed Component + classes. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Primary Include +#include "Component.hxx" +// Project includes +#include "Utility/Convert.hxx" +#include "Engine/ECS.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + template + Component::Component(Entity entity) + : BaseComponent { entity } + {} + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + template + typename Component::NativeComponent* Component::GetNativeComponent() + { + return ECS::GetNativeComponent(owner.GetEntity()); + } +} diff --git a/SHADE_Managed/src/Components/Component.hxx b/SHADE_Managed/src/Components/Component.hxx new file mode 100644 index 00000000..670e4e21 --- /dev/null +++ b/SHADE_Managed/src/Components/Component.hxx @@ -0,0 +1,200 @@ +/************************************************************************************//*! +\file Component.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 27, 2021 +\brief Contains the definition of the managed Component classes with the + declaration of functions for working with it. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// External Dependencies +#include "ECS_Base/Components/SHComponent.h" +// Project Includes +#include "Engine/Entity.hxx" +#include "Scripts/Script.hxx" + +namespace SHADE +{ + /// + /// Class that serves as the base for a wrapper class to Components in native code. + /// + public ref class BaseComponent : public System::IEquatable + { + public: + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ + /// + /// Retrieves the GameObject that this Component belongs to. + /// + property GameObject Owner + { + GameObject get() { return owner; } + } + + /*-----------------------------------------------------------------------------*/ + /* Component Access Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Adds a Component to this GameObject. + /// + /// Type of the Component to add. + /// Reference to the Component that was added. + generic where T : BaseComponent + T AddComponent(); + /// + /// Gets a Component from this GameObject. + /// + /// Type of the Component to get. + /// + /// Reference to the Component or null if this GameObject does not have the + /// specified Component. + /// + generic where T : BaseComponent + T GetComponent(); + /// + /// Removes a Component from this GameObject. If no Component exists to begin + /// with, nothing happens. + /// + /// Type of the Component to get. + generic where T : BaseComponent + void RemoveComponent(); + + /*-----------------------------------------------------------------------------*/ + /* Script Access Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Adds a Script of the specified type to this GameObject. + /// + /// Type of Script to add. + /// Reference to the created Script. + generic where T : ref class, Script + T AddScript(); + /// + /// Retrieves a Script of the specified type from this GameObject. + /// If multiple Scripts of the same specified type are added on the same + /// GameObject, this will retrieve the first one added. + /// + /// Type of Script to add. + /// Reference to the Script to retrieve. + generic where T : ref class, Script + T GetScript(); + /// + /// Retrieves a immutable list of Scripts of the specified type from this + /// GameObject. + /// + /// Type of Scripts to Get. + /// Immutable list of Scripts of the specified type. + generic where T : ref class, Script + System::Collections::Generic::IEnumerable^ GetScripts(); + /// + /// Removes all Scripts of the specified type from this GameObject. + /// + /// Type of PLushieScripts to remove. + generic where T : ref class, Script + void RemoveScript(); + + protected: + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Constructor for BaseComponent to tie it to a specific Entity. + /// Constructors of derived Components should call this Constructor. + /// + /// Entity that this Component will be tied to. + BaseComponent(Entity entity); + + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + /// + /// Entity that this Component belongs to. + /// + GameObject owner; + + public: + /*-----------------------------------------------------------------------------*/ + /* IEquatable */ + /*-----------------------------------------------------------------------------*/ + /// + /// Compares equality with an object of the same type. + /// + /// The object to compare with. + /// True if both objects are the same. + virtual bool Equals(BaseComponent^ other); + + /*-----------------------------------------------------------------------------*/ + /* Object */ + /*-----------------------------------------------------------------------------*/ + /// + /// Compares equality with another unboxed object. + /// + /// The unboxed object to compare with. + /// True if both objects are the same. + bool Equals(Object^ o) override; + /// + /// Gets a unique hash for this object. + /// + /// Unique hash for this object. + int GetHashCode() override; + }; + + /// + /// C++ template for the BaseComponent class used to generate common template-able + /// functions and types. + /// + /// + /// Type of the native component that this Component wraps. + /// + template + public ref class Component : public BaseComponent + { + internal: + /*-----------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Type of the native component that this Component wraps. + /// + using NativeComponent = NativeType; + + /*-----------------------------------------------------------------------------*/ + /* Helper Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Retrieves a pointer to the native unmanaged component that is tied to the + /// Entity described by the owner value. + /// + /// + /// Pointer to the native component. Will be nullptr if it does not exist. + /// + /// + /// Thrown if the internal ID stored by this native component is invalid. + /// + /// + /// Thrown if an attempt to retrieve the native component fails. + /// + NativeComponent* GetNativeComponent(); + + protected: + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Constructor for Component to tie it to a specific Entity. + /// Constructors of derived Components should call this Constructor. + /// + /// Entity that this Component will be tied to. + Component(Entity entity); + }; +} + +#include "Component.h++" diff --git a/SHADE_Managed/src/Engine/ECS.cxx b/SHADE_Managed/src/Engine/ECS.cxx new file mode 100644 index 00000000..5aceceee --- /dev/null +++ b/SHADE_Managed/src/Engine/ECS.cxx @@ -0,0 +1,255 @@ +/************************************************************************************//*! +\file ECS.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definition of the functions for the ECS managed static + class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "ECS.hxx" +// Standard Library +#include +#include +// External Dependencies +#include "ECS_Base/System/SHEntityManager.h" +// Project Headers +#include "Utility/Convert.hxx" +#include "Utility/Debug.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Component Manipulation Functions */ + /*---------------------------------------------------------------------------------*/ + generic + T ECS::AddComponent(EntityID entity) + { + System::Type^ componentType = T::typeid; + + // Check if entity is correct + if (!SHEntityManager::IsValidEID(entity)) + { + std::ostringstream oss; + oss << "[ECS] Attempted to add Component \"" + << msclr::interop::marshal_as(componentType->Name) + << "\" to invalid Entity."; + Debug::LogError(oss.str()); + return T(); + } + + // Add based on the correct component + for each(ComponentSet^ type in componentMap) + { + if (componentType == type->Type) + { + // Attempt to add + type->AddFunction(entity); + + // Return the managed component + return createManagedComponent(entity); + } + } + + std::ostringstream oss; + oss << "[ECS] Failed to add unsupported Component \"" + << Convert::ToNative(componentType->Name) + << "\" to Entity #" + << entity; + Debug::LogError(oss.str()); + return T(); + } + generic + T ECS::GetComponent(EntityID entity) + { + System::Type^ componentType = T::typeid; + + // Check if entity is correct + if (!SHEntityManager::IsValidEID(entity)) + { + std::ostringstream oss; + oss << "[ECS] Attempted to retrieve Component \"" + << Convert::ToNative(componentType->Name) + << "\" from invalid Entity."; + Debug::LogError(oss.str()); + return T(); + } + + // Get based on the correct component + for each(ComponentSet^ type in componentMap) + { + if (componentType == type->Type) + { + if (type->HasFunction(entity)) + { + return createManagedComponent(entity); + } + else + { + return T(); + } + } + } + + std::ostringstream oss; + oss << "[ECS] Failed to retrieve unsupported Component \"" + << Convert::ToNative(componentType->Name) + << "\" to Entity #" + << entity; + Debug::LogError(oss.str()); + return T(); + } + + generic + T ECS::GetComponentInChildren(EntityID entity) + { + System::Type^ componentType = T::typeid; + + // Check if entity is correct + if (!SHEntityManager::IsValidEID(entity)) + { + std::ostringstream oss; + oss << "[ECS] Attempted to retrieve Component \"" + << Convert::ToNative(componentType->Name) + << "\" from invalid Entity."; + Debug::LogError(oss.str()); + return T(); + } + + // Get Transform component and get the children list + throw gcnew System::NotImplementedException; + //Pls::Transform* tf = Pls::ECS::GetComponent(entity); + //if (tf == nullptr) + // return T(); + + //// Search direct children first + //for (const auto& child : tf->GetChildren()) + //{ + // T component = GetComponent(child); + // if (component != nullptr) + // return component; + //} + + //// Search their children + //for (const auto& child : tf->GetChildren()) + //{ + // T script = GetComponentInChildren(child); + // if (script != nullptr) + // return script; + //} + + // None here + return T(); + } + + generic + T ECS::EnsureComponent(EntityID entity) + { + if (HasComponent(entity)) + { + AddComponent(entity); + } + + return GetComponent(entity); + } + generic + bool ECS::HasComponent(EntityID entity) + { + System::Type^ componentType = T::typeid; + + // Check if entity is correct + if (!SHEntityManager::IsValidEID(entity)) + { + std::ostringstream oss; + oss << "[ECS] Attempted to check existence of Component \"" + << Convert::ToNative(componentType->Name) + << "\" from invalid Entity."; + Debug::LogError(oss.str()); + return false; + } + + // Add based on the correct component + for each(ComponentSet^ type in componentMap) + { + if (componentType == type->Type) + { + return type->HasFunction(entity); + } + } + + std::ostringstream oss; + oss << "[ECS] Attempted to check existence of unsupported Component \"" + << msclr::interop::marshal_as(componentType->Name) + << "\" from Entity #" + << entity; + Debug::LogError(oss.str()); + + return false; + } + generic + void ECS::RemoveComponent(EntityID entity) + { + System::Type^ componentType = T::typeid; + + // Check if entity is correct + if (!SHEntityManager::IsValidEID(entity)) + { + std::ostringstream oss; + oss << "[ECS] Attempted to remove Component \"" + << Convert::ToNative(componentType->Name) + << "\" from invalid Entity."; + Debug::LogError(oss.str()); + } + + // Add based on the correct component + for each(ComponentSet^ type in componentMap) + { + if (componentType == type->Type) + { + type->RemoveFunction(entity); + return; + } + } + + std::ostringstream oss; + oss << "[ECS] Attempted to remove unsupported Component \"" + << msclr::interop::marshal_as(componentType->Name) + << "\" from Entity #" + << entity; + Debug::LogError(oss.str()); + } + + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + static ECS::ECS() + { + // TODO + // componentMap.Add(createComponentSet()); + } + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + generic + T ECS::createManagedComponent(EntityID entity) + { + using namespace System::Reflection; + + array^ params = gcnew array{ static_cast(entity) }; + return safe_cast(System::Activator::CreateInstance + ( + T::typeid, + BindingFlags::Instance | BindingFlags::NonPublic | BindingFlags::CreateInstance, + nullptr, params, nullptr) + ); + } +} diff --git a/SHADE_Managed/src/Engine/ECS.h++ b/SHADE_Managed/src/Engine/ECS.h++ new file mode 100644 index 00000000..e5ede5f2 --- /dev/null +++ b/SHADE_Managed/src/Engine/ECS.h++ @@ -0,0 +1,60 @@ +/************************************************************************************//*! +\file ECS.h++ +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 27, 2021 +\brief Contains the definition of templated functions for the managed Component + classes. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Primary Include +#include "ECS.hxx" +// External Dependencies +#include "ECS_Base/System/SHComponentManager.h" +#include "ECS_Base/System/SHEntityManager.h" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Static Functions */ + /*---------------------------------------------------------------------------------*/ + template + NativeComponent* ECS::GetNativeComponent(Entity entity) + { + // Get native Entity + SHEntity* nativeEntity = SHEntityManager::GetEntityByID(entity); + + // Entity Validity Check + if (nativeEntity == nullptr) + throw gcnew System::InvalidOperationException("Attempted to get native Component to an invalid Entity."); + + // Null Check + NativeComponent* component = SHComponentManager::GetComponent_s(nativeEntity); + if (component == nullptr) + throw gcnew System::NullReferenceException("Attempted to get a native Component that does not exist."); + + return component; + } + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + template + ECS::ComponentSet ECS::createComponentSet() + { + return ComponentSet + { + ManagedType::typeid, + SHComponentManager::AddComponent, + SHComponentManager::EnsureComponent, + SHComponentManager::HasComponent, + SHComponentManager::RemoveComponent + }; + } +} diff --git a/SHADE_Managed/src/Engine/ECS.hxx b/SHADE_Managed/src/Engine/ECS.hxx new file mode 100644 index 00000000..72c88e11 --- /dev/null +++ b/SHADE_Managed/src/Engine/ECS.hxx @@ -0,0 +1,174 @@ +/************************************************************************************//*! +\file ECS.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definitions of the GameObject managed class which define an + abstraction for working with Entities in managed code. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// External Dependencies +#include "ECS_Base/System/SHComponentManager.h" +// Project Includes +#include "Components/Component.hxx" + +namespace SHADE +{ + /// + /// Static class which contains functions that map Pls::ECS's Component manipulation + /// functions to managed generic functions. + /// + private ref class ECS abstract sealed + { + public: + /*-----------------------------------------------------------------------------*/ + /* Component Manipulation Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Adds a Component to the specified Entity. + /// + /// Type of the Component to add. + /// + /// Entity object that should have the specified Component added to. + /// + /// Reference to the Component that was added. + generic where T : BaseComponent + static T AddComponent(EntityID entity); + /// + /// Gets a Component from the specified Entity. + /// + /// Type of the Component to get. + /// Entity object to get the Component from. + /// + /// Reference to the Component or null if the Entity does not have the + /// specified Component. + /// + generic where T : BaseComponent + static T GetComponent(EntityID entity); + /// + /// Retrieves the first Component from the specified GameObjectt's children that + /// matches the specified type. + /// + /// Type of the Component to get. + /// Entity object to get the Component from. + /// + /// Reference to the Component or null if the Entity does not have the + /// specified Component. + /// + generic where T : BaseComponent + static T GetComponentInChildren(EntityID entity); + /// + /// Ensures a Component on the specified Entity. + /// + /// Type of the Component to ensure. + /// Entity object to ensure the Component on. + /// Reference to the Component. + generic where T : BaseComponent + static T EnsureComponent(EntityID entity); + /// + /// Checks if the specified Entity has the specified Component. + /// + /// Type of the Component to check for. + /// Entity object to check for the Component. + /// + /// True if the specified Entity has the specified Component. False otherwise. + /// + generic where T : BaseComponent + static bool HasComponent(EntityID entity); + /// + /// Removes a Component from the specified Entity. + /// + /// Type of the Component to remove. + /// + /// Entity object that should have the specified Component removed from/ + /// + generic where T : BaseComponent + static void RemoveComponent(EntityID entity); + + internal: + /*-----------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Pointer to a function for Component manipulation operations. + /// + using ComponentFunc = void(*)(const EntityID&); + using ComponentHasFunc = bool(*)(const EntityID&); + /// + /// Contains a set of Component related data used for resolving operations for + /// each Component. + /// + value struct ComponentSet + { + public: + System::Type^ Type; + ComponentFunc AddFunction; + ComponentHasFunc HasFunction; + ComponentFunc RemoveFunction; + + }; + + /*-----------------------------------------------------------------------------*/ + /* Static Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Retrieves a pointer to the native unmanaged component of the specified + /// Entity. + /// + /// + /// Pointer to the native component. Will be nullptr if it does not exist. + /// + /// + /// Thrown if the Entity specified is invalid. + /// + /// + /// Thrown if an attempt to retrieve the native component fails. + /// + template + static NativeComponent* GetNativeComponent(Entity entity); + + private: + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Static constructor to initialize static data + /// + static ECS(); + + /*-----------------------------------------------------------------------------*/ + /* Static Data Members */ + /*-----------------------------------------------------------------------------*/ + static System::Collections::Generic::List componentMap; + + /*-----------------------------------------------------------------------------*/ + /* Helper Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Creates a ComponentSet for a pair of Native and Managed Components. + /// + /// Type of the Native Component. + /// Type of the Managed Component. + /// ComponentSet for the parameters specified. + template + static ComponentSet createComponentSet(); + /// + /// Creates an instance of the Managed representation of a Component with a + /// native Entity. + /// + /// Type of Component to create. + /// Native Entity that this Component is tied to. + /// The created Managed representation of the Component. + generic where T : BaseComponent + static T createManagedComponent(EntityID entity); + }; +} + +#include "ECS.h++" diff --git a/SHADE_Managed/src/Engine/EngineInterface.cxx b/SHADE_Managed/src/Engine/EngineInterface.cxx new file mode 100644 index 00000000..2009b2e5 --- /dev/null +++ b/SHADE_Managed/src/Engine/EngineInterface.cxx @@ -0,0 +1,138 @@ +/************************************************************************************//*! +\file EngineInterface.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the implementation of the managed EngineInterface static class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "EngineInterface.hxx" +// Standard Libraries +#include +// Project Headers +#include "Utility/Convert.hxx" +#include "Utility/Debug.hxx" +#include "Scripts/ScriptStore.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Interop Static Functions */ + /*---------------------------------------------------------------------------------*/ + void EngineInterface::Init() + { + SAFE_NATIVE_CALL_BEGIN + // Set up exception handler + System::AppDomain::CurrentDomain->UnhandledException += exceptionHandler; + LoadScriptAssembly(); + Debug::Log("[EngineInterface] Successfully initialized managed runtime."); + SAFE_NATIVE_CALL_END_N("SHADE_Managed.EngineInterface") + } + void EngineInterface::UnloadScriptAssembly() + { + SAFE_NATIVE_CALL_BEGIN + std::ostringstream oss; + oss << "[EngineInterface] Unloading " << Convert::ToNative(ManagedLibraryName) << ".dll"; + ScriptStore::Exit(); + + // Unload the script + scriptContext->Unload(); + scriptContext = nullptr; + System::GC::Collect(); + System::GC::WaitForPendingFinalizers(); + + // Unload the assembly File + if (managedLibFile != nullptr) + { + managedLibFile->Close(); + managedLibFile = nullptr; + } + + oss.str(""); + oss << "[EngineInterface] Successfully unloaded " << Convert::ToNative(ManagedLibraryName) << ".dll"; + Debug::Log(oss.str()); + SAFE_NATIVE_CALL_END_N("SHADE_Managed.EngineInterface") + } + void EngineInterface::LoadScriptAssembly() + { + SAFE_NATIVE_CALL_BEGIN + scriptContext = gcnew DisposableAssemblyLoadContext(); + loadManagedLibrary(); + ScriptStore::Init(); + SAFE_NATIVE_CALL_END_N("SHADE_Managed.EngineInterface") + } + void EngineInterface::ReloadScriptAssembly() + { + SAFE_NATIVE_CALL_BEGIN + // Stop scripts + UnloadScriptAssembly(); + // Reload assembly and restart scripts runtime + LoadScriptAssembly(); + SAFE_NATIVE_CALL_END_N("SHADE_Managed.EngineInterface") + } + void EngineInterface::Exit() + { + SAFE_NATIVE_CALL_BEGIN + // Clean up ScriptStore + ScriptStore::Exit(); + scriptContext->Unload(); + + // Release exception handler + System::AppDomain::CurrentDomain->UnhandledException -= exceptionHandler; + SAFE_NATIVE_CALL_END_N("SHADE_Managed.EngineInterface") + } + + /*---------------------------------------------------------------------------------*/ + /* Constructor */ + /*---------------------------------------------------------------------------------*/ + static EngineInterface::EngineInterface() + { + exceptionHandler = gcnew System::UnhandledExceptionEventHandler(unhandledExceptionHandler); + managedLibPath = System::Reflection::Assembly::GetExecutingAssembly()->Location->Replace("SHADE_Managed.dll", ManagedLibraryName + ".dll"); + } + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + void EngineInterface::loadManagedLibrary() + { + using namespace System::IO; + + std::ostringstream oss; + try + { + oss << "[EngineInterface] Loading " << Convert::ToNative(ManagedLibraryName) << ".dll"; + managedLibFile = File::Open(managedLibPath, FileMode::Open, FileAccess::Read); + scriptContext->LoadFromStream(managedLibFile); + oss.str(""); + oss << "[EngineInterface] Successfully loaded " << Convert::ToNative(ManagedLibraryName) << ".dll"; + Debug::Log(oss.str()); + } + catch (System::Exception^ e) + { + oss << "[EngineInterface] Unable to load " << Convert::ToNative(ManagedLibraryName) << ".dll!" + << "(" << Convert::ToNative(e->ToString()) << ")"; + Debug::LogError(oss.str()); + } + } + + /*---------------------------------------------------------------------------------*/ + /* Exception Handler Functions */ + /*---------------------------------------------------------------------------------*/ + void EngineInterface::unhandledExceptionHandler(System::Object^, System::UnhandledExceptionEventArgs^ e) + { + std::ostringstream oss; + oss << "[EngineInterface] Unhandled managed exception: " + << Convert::ToNative(e->ExceptionObject->GetType()->ToString()) << ": " + << Convert::ToNative(e->ExceptionObject->ToString()); + Debug::LogError(oss.str()); + } +} diff --git a/SHADE_Managed/src/Engine/EngineInterface.hxx b/SHADE_Managed/src/Engine/EngineInterface.hxx new file mode 100644 index 00000000..4fd8f7b3 --- /dev/null +++ b/SHADE_Managed/src/Engine/EngineInterface.hxx @@ -0,0 +1,90 @@ +/************************************************************************************//*! +\file EngineInterface.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definitions of the managed EngineInterface static class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Project Includes +#include "Utility/DisposableAssemblyLoadContext.hxx" + +namespace SHADE +{ + /// + /// Static class that contains the functions for interfacing with the core + /// PlushieEngine written in C++ for managing the lifecycle of managed code. + /// + private ref class EngineInterface abstract sealed + { + public: + /*-----------------------------------------------------------------------------*/ + /* Constants */ + /*-----------------------------------------------------------------------------*/ + /// + /// Name of the Managed Library that contains the C# scripts written externally. + /// + literal System::String^ ManagedLibraryName = "SHADE_Scripting"; + + /*-----------------------------------------------------------------------------*/ + /* Interop Static Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Initialises all required components for managed code. + /// + static void Init(); + /// + /// Unloads the managed script assembly. + /// Take note that this will clear all existing scripts, ensure that the scene + /// is saved before doing so. + /// + static void UnloadScriptAssembly(); + /// + /// Loads the managed script assembly. Ensure this is only called after + /// UnloadScriptAssembly() has been called. + /// + static void LoadScriptAssembly(); + /// + /// Reloads the managed script assembly. + /// Take note that this will clear all existing scripts, ensure that the scene + /// is saved before doing so. + /// Equivalent to calling UnloadScriptAssembly() and then LoadScriptAssembly(). + /// + static void ReloadScriptAssembly(); + /// + /// Cleans up all required components for managed code. + /// + static void Exit(); + + private: + /*-----------------------------------------------------------------------------*/ + /* Constructor */ + /*-----------------------------------------------------------------------------*/ + static EngineInterface(); + + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + static DisposableAssemblyLoadContext^ scriptContext; + static System::UnhandledExceptionEventHandler^ exceptionHandler; + static System::String^ managedLibPath; + static System::IO::FileStream^ managedLibFile; + + /*-----------------------------------------------------------------------------*/ + /* Helper Functions */ + /*-----------------------------------------------------------------------------*/ + static void loadManagedLibrary(); + + /*-----------------------------------------------------------------------------*/ + /* Exception Handler Functions */ + /*-----------------------------------------------------------------------------*/ + static void unhandledExceptionHandler(System::Object^ sender, System::UnhandledExceptionEventArgs^ e); + }; +} \ No newline at end of file diff --git a/SHADE_Managed/src/Engine/Entity.cxx b/SHADE_Managed/src/Engine/Entity.cxx new file mode 100644 index 00000000..ba1a31c6 --- /dev/null +++ b/SHADE_Managed/src/Engine/Entity.cxx @@ -0,0 +1,28 @@ +/************************************************************************************//*! +\file Entity.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definition of the functions for the EntityUtils managed + static class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "Entity.hxx" +// External Dependencies +#include "ECS_Base/System/SHEntityManager.h" + +namespace SHADE +{ + bool EntityUtils::IsValid(Entity^ entity) + { + return SHEntityManager::IsValidEID(static_cast(entity)); + } +} diff --git a/SHADE_Managed/src/Engine/Entity.hxx b/SHADE_Managed/src/Engine/Entity.hxx new file mode 100644 index 00000000..7be9340b --- /dev/null +++ b/SHADE_Managed/src/Engine/Entity.hxx @@ -0,0 +1,41 @@ +/************************************************************************************//*! +\file Entity.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definitions of a managed Entity identifier and declarations + of useful utility functions for working with Entity identifiers. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// External Dependencies +#include "ECS_Base/Entity/SHEntity.h" + +namespace SHADE +{ + /// + /// Managed representation of a native ECS Entity. + /// + using Entity = System::UInt32; + + /// + /// Static class that contains useful utility functions for working with Entity. + /// + private ref class EntityUtils abstract sealed + { + public: + /// + /// Checks if the specified entity is valid. This is done by checking if it + /// matches Pls::Entity::INVALID. + /// + /// The Entity to check. + /// True if the specified Entity is valid. + static bool IsValid(Entity^ entity); + }; +} diff --git a/SHADE_Managed/src/Engine/GameObject.cxx b/SHADE_Managed/src/Engine/GameObject.cxx new file mode 100644 index 00000000..3896fac5 --- /dev/null +++ b/SHADE_Managed/src/Engine/GameObject.cxx @@ -0,0 +1,201 @@ +/************************************************************************************//*! +\file GameObject.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definition of the functions for the GameObject managed class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "GameObject.hxx" +// External Dependencies +#include "ECS_Base/System/SHEntityManager.h" +// Project Headers +#include "ECS.hxx" +#include "Scripts/ScriptStore.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Static Functions */ + /*---------------------------------------------------------------------------------*/ + GameObject GameObject::Create() + { + return GameObject(SHEntityManager::CreateEntity()); + } + + void GameObject::Destroy(GameObject obj) + { + SHEntityManager::DestroyEntity(static_cast(obj.GetEntity())); + } + + System::Nullable GameObject::Find(System::String ^ name) + { + // Search the GameObjectLibrary for an Entity with the specified name + throw gcnew System::NotImplementedException(); + } + + /*---------------------------------------------------------------------------------*/ + /* Properties */ + /*---------------------------------------------------------------------------------*/ + System::String^ GameObject::Name::get() + { + return Convert::ToCLI(GetNativeEntity().name); + + } + bool GameObject::IsActiveSelf::get() + { + return GetNativeEntity().isActive; + } + bool GameObject::IsActiveInHierarchy::get() + { + throw gcnew System::NotImplementedException(); + } + + /*---------------------------------------------------------------------------------*/ + /* GameObject Property Functions */ + /*---------------------------------------------------------------------------------*/ + void GameObject::SetName(System::String^ name) + { + GetNativeEntity().name = Convert::ToNative(name); + } + void GameObject::SetActive(bool active) + { + GetNativeEntity().isActive = active; + } + + /*---------------------------------------------------------------------------------*/ + /* Component Functions */ + /*---------------------------------------------------------------------------------*/ + generic + T GameObject::AddComponent() + { + return ECS::AddComponent(entity); + } + + generic + T GameObject::GetComponent() + { + return ECS::GetComponent(entity); + } + + generic + T GameObject::GetComponentInChildren() + { + return ECS::GetComponentInChildren(entity); + } + + generic + T GameObject::EnsureComponent() + { + return ECS::EnsureComponent(entity); + } + + generic + void GameObject::RemoveComponent() + { + ECS::RemoveComponent(entity); + } + + /*---------------------------------------------------------------------------------*/ + /* Script Access Functions */ + /*---------------------------------------------------------------------------------*/ + generic + T GameObject::AddScript() + { + return ScriptStore::AddScript(entity); + } + + generic + T GameObject::GetScript() + { + return ScriptStore::GetScript(entity); + } + + generic + T GameObject::GetScriptInChildren() + { + return ScriptStore::GetScriptInChildren(entity); + } + + generic + System::Collections::Generic::IEnumerable^ GameObject::GetScripts() + { + return ScriptStore::GetScripts(entity); + } + + generic + void GameObject::RemoveScript() + { + ScriptStore::RemoveScript(entity); + } + + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + GameObject::GameObject(const SHEntity& entity) + : entity { entity.GetEID() } + {} + + GameObject::GameObject(Entity entity) + : entity { entity } + {} + + /*---------------------------------------------------------------------------------*/ + /* Getters */ + /*---------------------------------------------------------------------------------*/ + SHEntity& GameObject::GetNativeEntity() + { + SHEntity* nativeEntity = SHEntityManager::GetEntityByID(entity); + if (nativeEntity == nullptr) + throw gcnew System::InvalidOperationException("[GameObject] Unable to obtain native Entity for GameObject."); + + return *nativeEntity; + } + + /*---------------------------------------------------------------------------------*/ + /* IEquatable */ + /*---------------------------------------------------------------------------------*/ + bool GameObject::Equals(GameObject other) + { + return entity == other.entity; + } + + /*---------------------------------------------------------------------------------*/ + /* Object */ + /*---------------------------------------------------------------------------------*/ + bool GameObject::Equals(Object^ o) + { + try + { + GameObject^ cmp = safe_cast(o); + return Equals(cmp); + } + catch (System::InvalidCastException^) + { + return false; + } + } + + int GameObject::GetHashCode() + { + return entity.GetHashCode(); + } + + bool GameObject::operator==(GameObject lhs, GameObject rhs) + { + return lhs.Equals(rhs); + } + + bool GameObject::operator!=(GameObject lhs, GameObject rhs) + { + return !(lhs == rhs); + } +} diff --git a/SHADE_Managed/src/Engine/GameObject.hxx b/SHADE_Managed/src/Engine/GameObject.hxx new file mode 100644 index 00000000..723d9cec --- /dev/null +++ b/SHADE_Managed/src/Engine/GameObject.hxx @@ -0,0 +1,282 @@ +/************************************************************************************//*! +\file GameObject.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definitions of the GameObject managed class which define an + abstraction for working with Entities in managed code. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Project Includes +#include "Entity.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*---------------------------------------------------------------------------------*/ + ref class Script; + ref class BaseComponent; + + /*---------------------------------------------------------------------------------*/ + /* Class Definitions */ + /*---------------------------------------------------------------------------------*/ + /// + /// Lightweight object for an PlushieEngine Entity that allows for easy access + /// to Component and Script operations. + /// + public value class GameObject : public System::IEquatable + { + public: + /*-----------------------------------------------------------------------------*/ + /* Static Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Creates a new GameObject in the current Scene. If multiple Scenes are loaded, + /// and you would like to create an object in a specific Scene, call the Scene's + /// CreateGameObject(). + /// + /// GameObject that represents the newly created GameObject. + static GameObject Create(); + /// + /// Destroys the specified GameObject. Note that the specified GameObject will no + /// longer be a valid GameObject after this function is called. + /// + /// The GameObject to be destroyed. + static void Destroy(GameObject obj); + /// + /// Retrieves a GameObject with the specified name. If there are multiple + /// GameObjects with the same name, the first found GameObject will be retrieved. + /// There is no guaranteed order of which GameObject is considered "first". + /// + /// Name of the GameObject to find. + /// GameObject that has the specified name. Null if not found. + static System::Nullable Find(System::String^ name); + + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ + /// + /// Name of the object that this Entity represents. + /// + property System::String^ Name + { + System::String^ get(); + } + /// + /// Whether or not this Entity alone, is active. This does not mean that this + /// object is active in the scene. For example, if this Entity's parent is not + /// active, then this Entity would also be not active. + /// + property bool IsActiveSelf + { + bool get(); + } + /// + /// Whether or not this Entity is active in the Scene hierarchy. + /// + property bool IsActiveInHierarchy + { + bool get(); + } + + /*-----------------------------------------------------------------------------*/ + /* GameObject Property Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Sets the name of this GameObject. + /// + /// The name to set. + void SetName(System::String^ name); + /// + /// Sets the active state of this GameObject. + ///
+ /// The actual "activeness" of this GameObject is still dependent on the parents' + /// active states. + ///
+ /// + /// Whether to activate or deactivate this GameObject. + /// + void SetActive(bool active); + + /*-----------------------------------------------------------------------------*/ + /* Component Access Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Adds a Component to this GameObject. + /// + /// Type of the Component to add. + /// Reference to the Component that was added. + generic where T : BaseComponent + T AddComponent(); + /// + /// Gets a Component from this GameObject. + /// + /// Type of the Component to get. + /// + /// Reference to the Component or null if this GameObject does not have the + /// specified Component. + /// + generic where T : BaseComponent + T GetComponent(); + /// + /// Retrieves the first Component from this GameObject's children that matches + /// the specified type. + /// + /// Type of the Component to get. + /// + /// Reference to the Component or null if neither of this GameObject's children + /// does not have the specified Component. + /// + generic where T : BaseComponent + T GetComponentInChildren(); + /// + /// Ensures a Component on this GameObject. + /// + /// Type of the Component to ensure. + /// + /// Reference to the Component. + /// + generic where T : BaseComponent + T EnsureComponent(); + /// + /// Removes a Component from this GameObject. If no Component exists to begin + /// with, nothing happens. + /// + /// Type of the Component to get. + generic where T : BaseComponent + void RemoveComponent(); + + /*-----------------------------------------------------------------------------*/ + /* Script Access Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Adds a Script of the specified type to this GameObject. + /// + /// Type of Script to add. + /// Reference to the created Script. + generic where T : ref class, Script + T AddScript(); + /// + /// Retrieves a Script of the specified type from this GameObject. + /// If multiple Scripts of the same specified type are added on the same + /// GameObject, this will retrieve the first one added. + /// + /// Type of Script to retrieve. + /// Reference to the Script to retrieve. + generic where T : ref class, Script + T GetScript(); + /// + /// Retrieves a Script of the specified type from child GameObjects. + /// If multiple Scripts of the same specified type are added on the same + /// child GameObject, this will retrieve the first one added. + /// + /// Type of Script to retrieve. + /// Reference to the Script to retrieve. + generic where T : ref class, Script + T GetScriptInChildren(); + /// + /// Retrieves a immutable list of Scripts of the specified type from this + /// GameObject. + /// + /// Type of Scripts to retrieve. + /// Immutable list of Scripts of the specified type. + generic where T : ref class, Script + System::Collections::Generic::IEnumerable^ GetScripts(); + /// + /// Removes all Scripts of the specified type from this GameObject. + /// + /// Type of PLushieScripts to remove. + generic where T : ref class, Script + void RemoveScript(); + + internal: + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Constructor for the GameObject. + /// + /// + /// The ECS Entity that this GameObject should represent. + /// + GameObject(const SHEntity& entity); + /// + /// Constructor for the GameObject. + /// + /// + /// Managed numerical representation of the ECS Entity that this GameObject + /// should represent. + /// + GameObject(Entity entity); + + /*-----------------------------------------------------------------------------*/ + /* Getters */ + /*-----------------------------------------------------------------------------*/ + /// + /// Retrieves the CLR Entity object that this GameObject represents. + /// + /// Entity object that this GameObject represents. + inline Entity GetEntity() { return entity; } + /// + /// Retrieves the native Entity object that this GameObject represents. + /// + /// Native Entity object that this GameObject represents. + SHEntity& GetNativeEntity(); + + private: + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + Entity entity; + + public: + /*-----------------------------------------------------------------------------*/ + /* IEquatable */ + /*-----------------------------------------------------------------------------*/ + /// + /// Compares equality with an object of the same type. + /// + /// The object to compare with. + /// True if both objects are the same. + virtual bool Equals(GameObject other); + + /*-----------------------------------------------------------------------------*/ + /* Object */ + /*-----------------------------------------------------------------------------*/ + /// + /// Compares equality with another unboxed object. + /// + /// The unboxed object to compare with. + /// True if both objects are the same. + bool Equals(Object^ o) override; + /// + /// Gets a unique hash for this object. + /// + /// Unique hash for this object. + int GetHashCode() override; + /// + /// Checks if two GameObject references are the same. + /// + /// GameObject to check. + /// Another GameObject to check with. + /// True if both Components are the same. + static bool operator==(GameObject lhs, GameObject rhs); + /// + /// Checks if two GameObject references are different. + /// + /// GameObject to check. + /// Another GameObject to check with. + /// True if both Components are different. + static bool operator!=(GameObject lhs, GameObject rhs); + }; + +} + diff --git a/SHADE_Managed/src/Math/Math.cxx b/SHADE_Managed/src/Math/Math.cxx new file mode 100644 index 00000000..5ec850a1 --- /dev/null +++ b/SHADE_Managed/src/Math/Math.cxx @@ -0,0 +1,57 @@ +/************************************************************************************//*! +\file Math.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Nov 11, 2021 +\brief Contains the implementation of the functions of the managed Math struct. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "Math/Math.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Utility Functions */ + /*---------------------------------------------------------------------------------*/ + double Math::Wrap(double value, double min, double max) + { + while (value < min) + { + value = max - (min - value); + } + while (value > max) + { + value = min + (value - max); + } + return value; + } + double Math::DegreesToRadians(double degrees) + { + return degrees * Deg2Rad; + } + double Math::RadiansToDegrees(double radians) + { + return radians * Rad2Deg; + } + double Math::Lerp(double a, double b, double t) + { + return LerpUnclamped(a, b, System::Math::Clamp(t, 0.0, 1.0)); + } + double Math::LerpUnclamped(double a, double b, double t) + { + return a + t * (b - a); + } + + double Math::InverseLerp(double a, double b, double value) + { + return (value - a) / (b - a); + } +} diff --git a/SHADE_Managed/src/Math/Math.hxx b/SHADE_Managed/src/Math/Math.hxx new file mode 100644 index 00000000..3ddc5149 --- /dev/null +++ b/SHADE_Managed/src/Math/Math.hxx @@ -0,0 +1,92 @@ +/************************************************************************************//*! +\file Math.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Nov 11, 2021 +\brief Contains the definition of the managed Math static class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +namespace SHADE +{ + /// + /// Contains utility Math functions. + /// + public ref class Math abstract sealed + { + public: + /*-----------------------------------------------------------------------------*/ + /* Static Constants */ + /*-----------------------------------------------------------------------------*/ + /// + /// Degrees-to-radians conversion constant + /// + static constexpr double Deg2Rad = System::Math::PI / 180.0; + /// + /// Radians-to-degrees conversion constant + /// + static constexpr double Rad2Deg = 180.0 / System::Math::PI; + /// + /// Small value used for single precision floating point comparisons. + /// + static constexpr float Epsilon = 0.001f; + + /*-----------------------------------------------------------------------------*/ + /* Utility Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Wraps a value if they get to low or too high. + /// + /// Value to wrap. + /// Minimum value to wrap at. + /// Maximum value to wrap at. + /// Wrapped value. + static double Wrap(double value, double min, double max); + /// + /// Converts an angle from degree representation to radian representation. + /// + /// Degree-based angle to convert. + /// The specified angle in radians. + static double DegreesToRadians(double degrees); + /// + /// Converts an angle from radian representation to degree representation. + /// + /// Radian-based angle to convert. + /// The specified angle in degrees. + static double RadiansToDegrees(double radians); + /// + /// Linearly interpolates between a and b by t. + /// The parameter t is clamped to the range [0, 1]. + /// + /// The start value. + /// The end value. + /// The interpolation value between the two double. + /// The interpolated double result between the two double values. + static double Lerp(double a, double b, double t); + /// + /// Linearly interpolates between a and b by t. + /// The parameter t is not clamped and a value based on a and b is supported. + /// If t is less than zero, or greater than one, then LerpUnclamped will result + /// in a return value outside the range a to b. + /// + /// The start value. + /// The end value. + /// The interpolation value between the two double. + /// The interpolated double result between the two double values. + static double LerpUnclamped(double a, double b, double t); + /// + /// Calculates the linear parameter t that produces the interpolant value within the range [a, b]. + /// + /// Start value. + /// End value. + /// Value between start and end. + /// Percentage of value between start and end. + static double InverseLerp(double a, double b, double value); + }; +} diff --git a/SHADE_Managed/src/Math/Vector2.cxx b/SHADE_Managed/src/Math/Vector2.cxx new file mode 100644 index 00000000..d40e2323 --- /dev/null +++ b/SHADE_Managed/src/Math/Vector2.cxx @@ -0,0 +1,263 @@ +/************************************************************************************//*! +\file Vector2.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Nov 2, 2021 +\brief Contains the definitions of functions of the Vector2 struct. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "Math/Vector2.hxx" +// Standard Libraries +#include +#include +// Project Headers +#include "Math.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + Vector2::Vector2(double _x) + : Vector2 { _x, 0.0 } + {} + Vector2::Vector2(double _x, double _y) + : x { _x } + , y { _y } + {} + + /*---------------------------------------------------------------------------------*/ + /* Usage Functions */ + /*---------------------------------------------------------------------------------*/ + void Vector2::Normalise() + { + *this = GetNormalised(); + } + + Vector2 Vector2::GetNormalised() + { + return *this / GetMagnitude(); + } + + double Vector2::GetMagnitude() + { + return sqrt(x * x + y * y); + } + + double Vector2::GetSqrMagnitude() + { + return x * x + y * y; + } + + double Vector2::AngleFromRightRadians() + { + return atan2(y, x); + } + + double Vector2::AngleFromRightDegrees() + { + return Math::RadiansToDegrees(AngleFromRightRadians()); + } + + bool Vector2::IsNearPoint(Vector2 point) + { + return IsNearPoint(point, Math::Epsilon); + } + + bool Vector2::IsNearPoint(Vector2 point, double tolerance) + { + return (*this - point).GetSqrMagnitude() < (tolerance * tolerance); + } + + /*---------------------------------------------------------------------------------*/ + /* IEquatable */ + /*---------------------------------------------------------------------------------*/ + bool Vector2::Equals(Object^ o) + { + try + { + Vector2 vec = safe_cast(o); + return Equals(vec); + } + catch (System::InvalidCastException^) + { + return false; + } + } + + /*---------------------------------------------------------------------------------*/ + /* Object Overrides */ + /*---------------------------------------------------------------------------------*/ + bool Vector2::Equals(Vector2 other) + { + return IsNear(*this, other); + } + int Vector2::GetHashCode() + { + const int HASH = 19; + return x.GetHashCode() * HASH + y.GetHashCode(); + } + + /*---------------------------------------------------------------------------------*/ + /* Static Functions */ + /*---------------------------------------------------------------------------------*/ + bool Vector2::IsNear(Vector2 lhs, Vector2 rhs) + { + return IsNear(lhs, rhs, Math::Epsilon); + } + bool Vector2::IsNear(Vector2 lhs, Vector2 rhs, double tolerance) + { + return (std::abs(lhs.x) - std::abs(rhs.x)) < tolerance + && + (std::abs(lhs.y) - std::abs(rhs.y)) < tolerance; + } + double Vector2::Dot(Vector2 lhs, Vector2 rhs) + { + return lhs.x * rhs.x + lhs.y * rhs.y; + } + + Vector2 Vector2::Perpendicular(Vector2 lhs) + { + return Perpendicular(lhs, true); + } + + Vector2 Vector2::Perpendicular(Vector2 lhs, bool inward) + { + if (inward) + { + return Vector2 + ( + -lhs.y, lhs.x + ); + } + else + { + return Vector2 + ( + lhs.y, -lhs.x + ); + } + } + + Vector2 Vector2::Project(Vector2 vec, Vector2 direction) + { + return direction.GetNormalised() * vec.GetMagnitude(); + } + Vector2 Vector2::Reflect(Vector2 vec, Vector2 normal) + { + return vec - (Project(vec, normal.GetNormalised()) * 2.0); + } + Vector2 Vector2::RotateRadians(Vector2 vec, double radians) + { + const double SINE = sin(radians); + const double COSINE = cos(radians); + + return Vector2 + ( + vec.x * COSINE - vec.y * SINE, + vec.x * SINE + vec.y * COSINE + ); + } + Vector2 Vector2::RotateDegrees(Vector2 vec, double degrees) + { + return RotateRadians(vec, Math::DegreesToRadians(degrees)); + } + Vector2 Vector2::Min(Vector2 lhs, Vector2 rhs) + { + double lx = lhs.x, rx = rhs.x; + double ly = lhs.y, ry = rhs.y; + + return Vector2(std::min(lx, rx), + std::min(ly, ry)); + } + Vector2 Vector2::Max(Vector2 lhs, Vector2 rhs) + { + double lx = lhs.x, rx = rhs.x; + double ly = lhs.y, ry = rhs.y; + + return Vector2(std::max(lx, rx), + std::max(ly, ry)); + } + Vector2 Vector2::Lerp(Vector2 a, Vector2 b, double t) + { + return LerpUnclamped(a, b, std::clamp(t, 0.0, 1.0)); + } + Vector2 Vector2::LerpUnclamped(Vector2 a, Vector2 b, double t) + { + return a + ((b - a) * t); + } + Vector2 Vector2::MoveTowards(Vector2 current, Vector2 target, double maxDistanceDelta) + { + // Ignore if it is exactly on the same point + if (current == target) + return target; + + // Calculate new position + Vector2 DELTA = (target - current).GetNormalised() * maxDistanceDelta; + Vector2 newPos = current + DELTA; + + // Check if check if is behind or ahead of target + Vector2 DIFF = target - newPos; + if (Dot(DELTA, DIFF) < 0.0) + { + newPos = target; + } + return newPos; + } + Vector2 Vector2::operator+(Vector2 lhs, Vector2 rhs) + { + return Vector2 + ( + lhs.x + rhs.x, + lhs.y + rhs.y + ); + } + Vector2 Vector2::operator-(Vector2 lhs, Vector2 rhs) + { + return Vector2 + ( + lhs.x - rhs.x, + lhs.y - rhs.y + ); + } + Vector2 Vector2::operator*(Vector2 lhs, Vector2 rhs) + { + return Vector2 + ( + lhs.x * rhs.x, + lhs.y * rhs.y + ); + } + Vector2 Vector2::operator*(Vector2 lhs, double rhs) + { + return Vector2 + ( + lhs.x * rhs, + lhs.y * rhs + ); + } + Vector2 Vector2::operator/(Vector2 lhs, double rhs) + { + return Vector2 + ( + lhs.x / rhs, + lhs.y / rhs + ); + } + bool Vector2::operator==(Vector2 lhs, Vector2 rhs) + { + return lhs.Equals(rhs); + } + bool Vector2::operator!=(Vector2 lhs, Vector2 rhs) + { + return !(lhs == rhs); + } +} // namespace PlushieAPI::Mathematics \ No newline at end of file diff --git a/SHADE_Managed/src/Math/Vector2.hxx b/SHADE_Managed/src/Math/Vector2.hxx new file mode 100644 index 00000000..69a6110f --- /dev/null +++ b/SHADE_Managed/src/Math/Vector2.hxx @@ -0,0 +1,396 @@ +/************************************************************************************//*! +\file Vector2.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Nov 2, 2021 +\brief Contains the definitions of Vector2 struct. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Standard Libraries +#include + +namespace SHADE +{ + /// + /// CLR version of the the PlushieEngine's Vector2 class that represents a + /// 2-Dimensional Vector. Designed to closely match Unity's Vector2 struct. + /// + [System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)] + public value struct Vector2 : public System::IEquatable + { + public: + /*-----------------------------------------------------------------------------*/ + /* Constants */ + /*-----------------------------------------------------------------------------*/ + #pragma region Constants + /// + /// Shorthand for writing Vector2(0, -1). + /// + static initonly Vector2 Down = Vector2(0.0, -1.0); + /// + /// Shorthand for writing Vector2(-1, 0). + /// + static initonly Vector2 Left = Vector2(-1.0, 0.0); + /// + /// Shorthand for writing Vector2(double.NegativeInfinity, + /// double.NegativeInfinity). + /// + static initonly Vector2 NegativeInfinity = Vector2(std::numeric_limits::lowest(), std::numeric_limits::lowest()); + /// + /// Shorthand for writing Vector2(1, 1). + /// + static initonly Vector2 One = Vector2(1.0, 1.0); + /// + /// Shorthand for writing Vector2(double.PositiveInfinity, + /// double.PositiveInfinity). + /// + static initonly Vector2 PositiveInfinity = Vector2(std::numeric_limits::max(), std::numeric_limits::max()); + /// + /// Shorthand for writing Vector2(1, 0). + /// + static initonly Vector2 Right = Vector2(1.0, 0.0); + /// + /// Shorthand for writing Vector2(0, 1). + /// + static initonly Vector2 Up = Vector2(0.0, 1.0); + /// + /// Shorthand for writing Vector2(0, 0). + /// + static initonly Vector2 Zero = Vector2(0.0, 0.0); + #pragma endregion + + /*-----------------------------------------------------------------------------*/ + /* Public Members */ + /*-----------------------------------------------------------------------------*/ + /// + /// X-component of the Vector2. + /// + double x; + /// + /// Y-component of the Vector2. + /// + double y; + + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Constructor to construct a Vector2 with the specified components with the + /// Y-component set to 0.0. + /// + /// X-coordinate to set. + Vector2(double _x); + /// + /// Constructor to construct a Vector2 with the specified components.. + /// + /// X-coordinate to set. + /// Y-coordinate to set. + Vector2(double _x, double _y); + + /*-----------------------------------------------------------------------------*/ + /* Usage Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Normalises this current Vector2. This changes the data of this Vector2. + /// If you would like to get a copy, use GetNormalised() instead. + /// This function does nothing to a zero vector. + /// + void Normalise(); + /// + /// Creates a copy of this Vector2 and returns a normalized version. + /// + /// + /// Returns a normalised copy of this Vector2. + /// If this Vector2 is a zero vector, a zero vector will be returned. + /// + Vector2 GetNormalised(); + /// + /// Calculates and returns the magnitude of this Vector2. Note that this function + /// incurs a performance cost from the square root calculation. If you do not + /// need the precise magnitude, consider using GetSqrMagnitude() instead. + /// + /// Returns the length of this Vector2. + double GetMagnitude(); + /// + /// Calculates and returns the squared magnitude of this Vector2. + /// + /// Returns the squared length of this Vector2. + double GetSqrMagnitude(); + /// + /// Calculates and returns the angle of this vector from the right vector. This + /// function returns values between -Math.PI and Math.PI. + /// + /// Returns the angle of this vector from the right vector in radians. + double AngleFromRightRadians(); + /// + /// Calculates and returns the angle of this vector from the right vector. This + /// function returns values between -180.0 and 180.0. + /// + /// Returns the angle of this vector from the right vector in degrees. + double AngleFromRightDegrees(); + /// + /// Checks if a specified point is near this Vector2 that represents a point with + /// a tolerance value of PLS_EPSILON. + /// + /// The other point to check if we are near. + /// + /// True if this Vector2 representing a point and the specified point are within + /// the range of the specified tolerance. False otherwise. + /// + bool IsNearPoint(Vector2 point); + /// + /// Checks if a specified point is near this Vector2 that represents a point. + /// + /// The other point to check if we are near. + /// + /// The amount of tolerance before we consider these points as "near". + /// + /// + /// True if this Vector2 representing a point and the specified point are within + /// the range of the specified tolerance. False otherwise. + /// + bool IsNearPoint(Vector2 point, double tolerance); + + /*-----------------------------------------------------------------------------*/ + /* IEquatable */ + /*-----------------------------------------------------------------------------*/ + /// + /// Compares equality with an object of the same type. + /// + /// The object to compare with. + /// True if both objects are the same. + virtual bool Equals(Vector2 other); + + /*-----------------------------------------------------------------------------*/ + /* Object */ + /*-----------------------------------------------------------------------------*/ + /// + /// Compares equality with another unboxed object. + /// + /// The unboxed object to compare with. + /// True if both objects are the same. + bool Equals(Object^ o) override; + /// + /// Gets a unique hash for this object. + /// + /// Unique hash for this object. + int GetHashCode() override; + + /*-----------------------------------------------------------------------------*/ + /* Static Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Checks if two specified Vector2s are near in value. + /// + /// Vector2 to check if is near in value. + /// Another Vector2 to check if is near in value. + /// + /// True if the two Vector2s are within the tolerance value specified + /// + static bool IsNear(Vector2 lhs, Vector2 rhs); + /// + /// Checks if two specified Vector2s are near in value. + /// + /// Vector2 to check if is near in value. + /// Another Vector2 to check if is near in value. + /// + /// Amount of tolerance to do the comparison with. + /// + /// + /// True if the two Vector2s are within the tolerance value specified + /// + static bool IsNear(Vector2 lhs, Vector2 rhs, double tolerance); + /// + /// Computes and returns the dot product of 2 specified Vector2s. + /// + /// Vector2 to calculate dot product with. + /// Another Vector2 to calculate dot product with. + /// + /// Scalar value representing the dot product of the two Vector2s. + /// + static double Dot(Vector2 lhs, Vector2 rhs); + /// + /// Computes the inward perpendicular Vector2 to the specified Vector2. + /// Equivalent to calling Perpendicular(lhs, true). This means, the + /// resultant Vector2 is rotated 90-degrees in a counter-clockwise. + /// + /// Vector2 to find a perpendicular of. + /// + /// The perpendicular Vector2 relative to the specified Vector2. + /// + static Vector2 Perpendicular(Vector2 lhs); + /// + /// Computes a perpendicular Vector2 to the specified Vector2. + /// + /// Vector2 to find a perpendicular of. + /// + /// Whether the inward perpendicular Vector is retrieved. If true, the + /// resultant vector is rotated 90-degrees in a counter-clockwise. + /// + /// The perpendicular Vector2 relative to the specified Vector2. + /// + static Vector2 Perpendicular(Vector2 lhs, bool inward); + /// + /// Computes and returns a Vector2 projection. + /// + /// Vector2 to project. + /// Vector2 to project onto. + /// The Vector2 that represents the projected vec onto direction. + static Vector2 Project(Vector2 vec, Vector2 direction); + /// + /// Reflects a Vector2 across another Vector2. + /// + /// A Vector2 to reflect. + /// A normal to reflect the Vector2 across. + /// The Vector2 that represents vec reflected across normal. + static Vector2 Reflect(Vector2 vec, Vector2 normal); + /// + /// Rotates a Vector2 on the Z-axis by a specified angle in an anti-clockwise + /// direction. + /// + /// A Vector2 to rotate. + /// + /// Angle to rotate the vector by in an anti-clockwise direction in radians. + /// + /// The Vector2 that represents the rotated vector. + static Vector2 RotateRadians(Vector2 vec, double radians); + /// + /// Rotates a Vector2 on the Z-axis by a specified angle in an anti-clockwise + /// direction. + /// + /// A Vector2 to rotate. + /// + /// Angle to rotate the vector by in an anti-clockwise direction in degrees. + /// + /// The Vector2 that represents the rotated vector. + static Vector2 RotateDegrees(Vector2 vec, double degrees); + /// + /// Computes and returns a Vector2 that is made from the smallest components of + /// the two specified Vector2s. + /// + /// Vector2 to calculate minimum Vector2 with. + /// Another Vector2 to calculate minimum Vector2 with. + /// + /// The Vector2 that contains the smallest components of the two specified + /// Vector2s. + /// + static Vector2 Min(Vector2 lhs, Vector2 rhs); + /// + /// Computes and returns a Vector2 that is made from the largest components of + /// the two specified Vector2s. + /// + /// Vector2 to calculate maximum Vector2 with. + /// Another Vector2 to calculate maximum Vector2 with. + /// + /// The Vector2 that contains the largest components of the two specified + /// Vector2s. + /// + static Vector2 Max(Vector2 lhs, Vector2 rhs); + /// + /// Linearly interpolates between two specified points. + /// This is most commonly used to find a point some fraction of the way along a + /// line between two endpoints. + /// + /// The start Vector2, returned when t = 0.0. + /// The end Vector2, returned when t = 1.0. + /// + /// Value used to interpolate between a and b which is clamped to + /// the range[0, 1]. + /// + /// The interpolated Vector2. + static Vector2 Lerp(Vector2 a, Vector2 b, double t); + /// + /// Linearly interpolates between two specified points. + /// This is most commonly used to find a point some fraction of the way along a + /// line between two endpoints. + /// Unlike Lerp(), t is not clamped to a range at all. + /// + /// The start Vector2, returned when t = 0.0. + /// The end Vector2, returned when t = 1.0. + /// Value used to interpolate between a and b. + /// The interpolated Vector2. + static Vector2 LerpUnclamped(Vector2 a, Vector2 b, double t); + /// + /// Moves a point current towards target. + /// Similar to Lerp(), however, the function will ensure that the distance never + /// exceeds maxDistanceDelta. Negative values of maxDistanceDelta pushes the + /// vector away from target + /// + /// The current position of the point. + /// The target position to move to. + /// Maximum distance moved per call. + /// Vector representing the moved point. + static Vector2 MoveTowards(Vector2 current, Vector2 target, double maxDistanceDelta); + + /*-----------------------------------------------------------------------------*/ + /* Overloaded Operators */ + /*-----------------------------------------------------------------------------*/ + /// + /// Adds two Vector2s together and returns the result. + /// + /// Vector2 to add. + /// Another Vector2 to add. + /// The result of lhs added to rhs + static Vector2 operator+(Vector2 lhs, Vector2 rhs); + /// + /// Subtracts a Vector2 from another Vector2 and returns the result. + /// + /// Vector2 to subtract from. + /// Another Vector2 to subtract. + /// The result of rhs subtracted from lhs. + static Vector2 operator-(Vector2 lhs, Vector2 rhs); + /// + /// Calculates the component-wise multiplication of two Vector2s and returns the + /// result. + /// + /// Vector2 to multiply with. + /// Another Vector2 to multiply with. + /// The result of rhs subtracted from lhs. + static Vector2 operator*(Vector2 lhs, Vector2 rhs); + /// + /// Calculates the multiplication of a Vector2 with a scalar value and returns + /// the result. + /// + /// Vector2 to multiply with. + /// Scalar to multiply with. + /// The result of the scalar multiplication. + static Vector2 operator*(Vector2 lhs, double rhs); + /// + /// Calculates the division of a Vector2 with a scalar value and returns + /// the result. + /// + /// Scalar to divide with. + /// Vector2 to divide with. + /// The result of the scalar division. + static Vector2 operator/(Vector2 lhs, double rhs); + /// + /// Checks if two Vector2s are approximately equal. This is equivalent to + /// calling Vector2.IsNear() with default tolerance values. + /// + /// Vector2 to compare. + /// Another Vector2 to compare. + /// + /// True if all components are approximately equal within the default + /// tolerance value. + /// + static bool operator==(Vector2 lhs, Vector2 rhs); + /// + /// Checks if two Vector2s are not approximately equal. This is equivalent to + /// calling !Vector2.IsNear() with default tolerance values. + /// + /// Vector2 to compare. + /// Another Vector2 to compare. + /// + /// True if all components are not approximately equal within the default + /// tolerance value. + /// + static bool operator!=(Vector2 lhs, Vector2 rhs); + }; +} diff --git a/SHADE_Managed/src/Math/Vector3.cxx b/SHADE_Managed/src/Math/Vector3.cxx new file mode 100644 index 00000000..26ff5a72 --- /dev/null +++ b/SHADE_Managed/src/Math/Vector3.cxx @@ -0,0 +1,278 @@ +/************************************************************************************//*! +\file Vector3.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 24, 2021 +\brief Contains the definitions of functions of the Vector3 struct. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "Vector3.hxx" +// Standard Libraries +#include +#include +// Project Headers +#include "Math.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + Vector3::Vector3(double _x) + : Vector3 {_x, 0.0, 0.0} + {} + Vector3::Vector3(double _x, double _y) + : Vector3 {_x, _y, 0.0} + {} + Vector3::Vector3(double _x, double _y, double _z) + : x { _x } + , y { _y } + , z { _z } + {} + Vector3::Vector3(Vector2 vec) + : Vector3(vec.x, vec.y) + {} + + /*---------------------------------------------------------------------------------*/ + /* Usage Functions */ + /*---------------------------------------------------------------------------------*/ + void Vector3::Normalise() + { + *this = GetNormalised(); + } + + Vector3 Vector3::GetNormalised() + { + return *this / GetSqrMagnitude(); + } + + double Vector3::GetMagnitude() + { + return sqrt(x * x + y * y + z * z); + } + + double Vector3::GetSqrMagnitude() + { + return x * x + y * y + z * z; + } + + double Vector3::Angle2DFromRightRadians() + { + return atan2(y, x); + } + + double Vector3::Angle2DFromRightDegrees() + { + return Math::RadiansToDegrees(Angle2DFromRightRadians()); + } + + bool Vector3::IsNearPoint(Vector3 point) + { + return IsNearPoint(point, Math::Epsilon); + } + + bool Vector3::IsNearPoint(Vector3 point, double tolerance) + { + return (*this - point).GetSqrMagnitude() < (tolerance * tolerance); + } + + /*---------------------------------------------------------------------------------*/ + /* IEquatable */ + /*---------------------------------------------------------------------------------*/ + bool Vector3::Equals(Object^ o) + { + try + { + Vector3 vec = safe_cast(o); + return Equals(vec); + } + catch (System::InvalidCastException^) + { + return false; + } + } + + /*---------------------------------------------------------------------------------*/ + /* Object Overrides */ + /*---------------------------------------------------------------------------------*/ + bool Vector3::Equals(Vector3 other) + { + return IsNear(*this, other); + } + int Vector3::GetHashCode() + { + const int HASH = 19; + const int HASH2 = 23; + return x.GetHashCode() * HASH + y.GetHashCode() * HASH2 + z.GetHashCode(); + } + + /*---------------------------------------------------------------------------------*/ + /* Static Functions */ + /*---------------------------------------------------------------------------------*/ + bool Vector3::IsNear(Vector3 lhs, Vector3 rhs) + { + return IsNear(lhs, rhs, Math::Epsilon); + } + bool Vector3::IsNear(Vector3 lhs, Vector3 rhs, double tolerance) + { + return (std::abs(lhs.x) - std::abs(rhs.x)) < tolerance + && + (std::abs(lhs.y) - std::abs(rhs.y)) < tolerance + && + (std::abs(lhs.z) - std::abs(rhs.z)) < tolerance; + } + double Vector3::Dot(Vector3 lhs, Vector3 rhs) + { + return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z; + } + Vector3 Vector3::Cross(Vector3 lhs, Vector3 rhs) + { + return Vector3(lhs.y * rhs.z - lhs.z * rhs.y, + lhs.z * rhs.x - lhs.x * rhs.z, + lhs.x * rhs.y - lhs.y * rhs.x); + } + Vector3 Vector3::Project(Vector3 vec, Vector3 direction) + { + return direction.GetNormalised() * vec.GetMagnitude(); + } + Vector3 Vector3::Reflect(Vector3 vec, Vector3 normal) + { + return vec - (Project(vec, normal.GetNormalised()) * 2.0); + } + Vector3 Vector3::RotateRadians(Vector3 vec, double radians) + { + const double SINE = sin(radians); + const double COSINE = cos(radians); + + return Vector3 + ( + vec.x * COSINE - vec.y * SINE, + vec.x * SINE + vec.y * COSINE, + vec.z + ); + } + Vector3 Vector3::RotateDegrees(Vector3 vec, double degrees) + { + return RotateRadians(vec, Math::DegreesToRadians(degrees)); + } + Vector3 Vector3::Min(Vector3 lhs, Vector3 rhs) + { + double lx = lhs.x, rx = rhs.x; + double ly = lhs.y, ry = rhs.y; + double lz = lhs.z, rz = rhs.z; + + return Vector3(std::min(lx, rx), + std::min(ly, ry), + std::min(lz, rz)); + } + Vector3 Vector3::Max(Vector3 lhs, Vector3 rhs) + { + double lx = lhs.x, rx = rhs.x; + double ly = lhs.y, ry = rhs.y; + double lz = lhs.z, rz = rhs.z; + + return Vector3(std::max(lx, rx), + std::max(ly, ry), + std::max(lz, rz)); + } + Vector3 Vector3::Lerp(Vector3 a, Vector3 b, double t) + { + return LerpUnclamped(a, b, std::clamp(t, 0.0, 1.0)); + } + Vector3 Vector3::LerpUnclamped(Vector3 a, Vector3 b, double t) + { + return a + ((b - a) * t); + } + Vector3 Vector3::MoveTowards(Vector3 current, Vector3 target, double maxDistanceDelta) + { + // Ignore if it is exactly on the same point + if (current == target) + return target; + + // Calculate new position + Vector3 DELTA = (target - current).GetNormalised() * maxDistanceDelta; + Vector3 newPos = current + DELTA; + + // Check if check if is behind or ahead of target + Vector3 DIFF = target - newPos; + if (Dot(DELTA, DIFF) < 0.0) + { + newPos = target; + } + return newPos; + } + Vector3 Vector3::operator+(Vector3 lhs, Vector3 rhs) + { + return Vector3 + ( + lhs.x + rhs.x, + lhs.y + rhs.y, + lhs.z + rhs.z + ); + } + Vector3 Vector3::operator-(Vector3 lhs, Vector3 rhs) + { + return Vector3 + ( + lhs.x - rhs.x, + lhs.y - rhs.y, + lhs.z - rhs.z + ); + } + Vector3 Vector3::operator*(Vector3 lhs, Vector3 rhs) + { + return Vector3 + ( + lhs.x * rhs.x, + lhs.y * rhs.y, + lhs.z * rhs.z + ); + } + Vector3 Vector3::operator*(Vector3 lhs, double rhs) + { + return Vector3 + ( + lhs.x * rhs, + lhs.y * rhs, + lhs.z * rhs + ); + } + Vector3 Vector3::operator/(Vector3 lhs, double rhs) + { + return Vector3 + ( + lhs.x / rhs, + lhs.y / rhs, + lhs.z / rhs + ); + } + bool Vector3::operator==(Vector3 lhs, Vector3 rhs) + { + return lhs.Equals(rhs); + } + bool Vector3::operator!=(Vector3 lhs, Vector3 rhs) + { + return !(lhs == rhs); + } + + /*---------------------------------------------------------------------------------*/ + /* Conversion Operators */ + /*---------------------------------------------------------------------------------*/ + Vector3::operator Vector2(Vector3 vec) + { + return Vector2(vec.x, vec.y); + } + + Vector3::operator Vector3(Vector2 vec) + { + return Vector3(vec); + } +} // namespace PlushieAPI::Mathematics \ No newline at end of file diff --git a/SHADE_Managed/src/Math/Vector3.hxx b/SHADE_Managed/src/Math/Vector3.hxx new file mode 100644 index 00000000..e6cdc7d4 --- /dev/null +++ b/SHADE_Managed/src/Math/Vector3.hxx @@ -0,0 +1,425 @@ +/************************************************************************************//*! +\file Vector3.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 24, 2021 +\brief Contains the definitions of Vector3 struct. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Standard Libraries +#include +// Project Includes +#include "Vector2.hxx" + +namespace SHADE +{ + /// + /// CLR version of the the PlushieEngine's Vector3 class that represents a + /// 3-Dimensional Vector. Designed to closely match Unity's Vector3 struct. + /// + [System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)] + public value struct Vector3 : public System::IEquatable + { + public: + /*-----------------------------------------------------------------------------*/ + /* Constants */ + /*-----------------------------------------------------------------------------*/ + #pragma region Constants + /// + /// Shorthand for writing Vector3(0, 0, -1). + /// + static initonly Vector3 Back = Vector3(0.0, 0.0, -1.0); + /// + /// Shorthand for writing Vector3(0, -1, 0). + /// + static initonly Vector3 Down = Vector3(0.0, -1.0, 0.0); + /// + /// Shorthand for writing Vector3(0, 0, 1). + /// + static initonly Vector3 Forward = Vector3(0.0, 0.0, 1.0); + /// + /// Shorthand for writing Vector3(-1, 0, 0). + /// + static initonly Vector3 Left = Vector3(-1.0, 0.0, 0.0); + /// + /// Shorthand for writing Vector3(double.NegativeInfinity, + /// double.NegativeInfinity, double.NegativeInfinity). + /// + static initonly Vector3 NegativeInfinity = Vector3(std::numeric_limits::lowest(), + std::numeric_limits::lowest(), + std::numeric_limits::lowest()); + /// + /// Shorthand for writing Vector3(1, 1, 1). + /// + static initonly Vector3 One = Vector3(1.0, 1.0, 1.0); + /// + /// Shorthand for writing Vector3(double.PositiveInfinity, + /// double.PositiveInfinity, double.PositiveInfinity). + /// + static initonly Vector3 PositiveInfinity = Vector3(std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max()); + /// + /// Shorthand for writing Vector3(1, 0, 0). + /// + static initonly Vector3 Right = Vector3(1.0, 0.0, 0.0); + /// + /// Shorthand for writing Vector3(0, 1, 0). + /// + static initonly Vector3 Up = Vector3(0.0, 1.0, 0.0); + /// + /// Shorthand for writing Vector3(0, 0, 0). + /// + static initonly Vector3 Zero = Vector3(0.0, 0.0, 0.0); + #pragma endregion + + /*-----------------------------------------------------------------------------*/ + /* Public Members */ + /*-----------------------------------------------------------------------------*/ + /// + /// X-component of the Vector3. + /// + double x; + /// + /// Y-component of the Vector3. + /// + double y; + /// + /// Z-component of the Vector3. + /// + double z; + + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Constructor to construct a Vector3 with the specified components with the + /// Y and Z-component set to 0.0. + /// + /// X-coordinate to set. + Vector3(double _x); + /// + /// Constructor to construct a Vector3 with the specified components with the + /// Z-component set to 0.0. + /// + /// X-coordinate to set. + /// Y-coordinate to set. + Vector3(double _x, double _y); + /// + /// Constructor to construct a Vector3 with the specified components. + /// + /// X-coordinate to set. + /// Y-coordinate to set. + /// Z-coordinate to set. + Vector3(double _x, double _y, double _z); + /// + /// Conversion constructor to construct a Vector3 using a Vector2. + /// + /// + Vector3(Vector2 vec); + + /*-----------------------------------------------------------------------------*/ + /* Usage Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Normalises this current Vector3. This changes the data of this Vector3. + /// If you would like to get a copy, use GetNormalised() instead. + /// This function does nothing to a zero vector. + /// + void Normalise(); + /// + /// Creates a copy of this Vector3 and returns a normalized version. + /// + /// + /// Returns a normalised copy of this Vector3. + /// If this Vector3 is a zero vector, a zero vector will be returned. + /// + Vector3 GetNormalised(); + /// + /// Calculates and returns the magnitude of this Vector3. Note that this function + /// incurs a performance cost from the square root calculation. If you do not + /// need the precise magnitude, consider using GetSqrMagnitude() instead. + /// + /// Returns the length of this Vector3. + double GetMagnitude(); + /// + /// Calculates and returns the squared magnitude of this Vector3. + /// + /// Returns the squared length of this Vector3. + double GetSqrMagnitude(); + /// + /// Calculates and returns the angle of this vector from the right vector. This + /// function returns values between -Math.PI and Math.PI. + /// + /// Returns the angle of this vector from the right vector in radians. + double Angle2DFromRightRadians(); + /// + /// Calculates and returns the angle of this vector from the right vector. This + /// function returns values between -180.0 and 180.0. + /// + /// Returns the angle of this vector from the right vector in degrees. + double Angle2DFromRightDegrees(); + /// + /// Checks if a specified point is near this Vector3 that represents a point with + /// a tolerance value of PLS_EPSILON. + /// + /// The other point to check if we are near. + /// + /// True if this Vector3 representing a point and the specified point are within + /// the range of the specified tolerance. False otherwise. + /// + bool IsNearPoint(Vector3 point); + /// + /// Checks if a specified point is near this Vector3 that represents a point. + /// + /// The other point to check if we are near. + /// + /// The amount of tolerance before we consider these points as "near". + /// + /// + /// True if this Vector3 representing a point and the specified point are within + /// the range of the specified tolerance. False otherwise. + /// + bool IsNearPoint(Vector3 point, double tolerance); + + /*-----------------------------------------------------------------------------*/ + /* IEquatable */ + /*-----------------------------------------------------------------------------*/ + /// + /// Compares equality with an object of the same type. + /// + /// The object to compare with. + /// True if both objects are the same. + virtual bool Equals(Vector3 other); + + /*-----------------------------------------------------------------------------*/ + /* Object */ + /*-----------------------------------------------------------------------------*/ + /// + /// Compares equality with another unboxed object. + /// + /// The unboxed object to compare with. + /// True if both objects are the same. + bool Equals(Object^ o) override; + /// + /// Gets a unique hash for this object. + /// + /// Unique hash for this object. + int GetHashCode() override; + + /*-----------------------------------------------------------------------------*/ + /* Static Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Checks if two specified Vector3s are near in value. + /// + /// Vector3 to check if is near in value. + /// Another Vector3 to check if is near in value. + /// + /// True if the two Vector3s are within the tolerance value specified + /// + static bool IsNear(Vector3 lhs, Vector3 rhs); + /// + /// Checks if two specified Vector3s are near in value. + /// + /// Vector3 to check if is near in value. + /// Another Vector3 to check if is near in value. + /// Amount of tolerance to do the comparison with. + /// + /// True if the two Vector3s are within the tolerance value specified + /// + static bool IsNear(Vector3 lhs, Vector3 rhs, double tolerance); + /// + /// Computes and returns the dot product of 2 specified Vector3s. + /// + /// Vector3 to calculate dot product with. + /// Another Vector3 to calculate dot product with. + /// Scalar value representing the dot product of the two Vector3s. + static double Dot(Vector3 lhs, Vector3 rhs); + /// + /// Computes and returns the cross product of 2 specified Vector3s. + /// + /// Vector3 to calculate cross product with. + /// Another Vector3 to calculate cross product with. + /// The cross product of the two Vector3s. + static Vector3 Cross(Vector3 lhs, Vector3 rhs); + /// + /// Computes and returns a Vector3 projection. + /// + /// Vector3 to project. + /// Vector3 to project onto. + /// The Vector3 that represents the projected vec onto direction. + static Vector3 Project(Vector3 vec, Vector3 direction); + /// + /// Reflects a Vector3 across another Vector3. + /// + /// A Vector3 to reflect. + /// A normal to reflect the Vector3 across. + /// The Vector3 that represents vec reflected across normal. + static Vector3 Reflect(Vector3 vec, Vector3 normal); + /// + /// Rotates a Vector3 on the Z-axis by a specified angle in an anti-clockwise + /// direction. + /// + /// A Vector3 to rotate. + /// + /// Angle to rotate the vector by in an anti-clockwise direction in radians. + /// + /// The Vector3 that represents the rotated vector. + static Vector3 RotateRadians(Vector3 vec, double radians); + /// + /// Rotates a Vector3 on the Z-axis by a specified angle in an anti-clockwise + /// direction. + /// + /// A Vector3 to rotate. + /// + /// Angle to rotate the vector by in an anti-clockwise direction in degrees. + /// + /// The Vector3 that represents the rotated vector. + static Vector3 RotateDegrees(Vector3 vec, double degrees); + /// + /// Computes and returns a Vector3 that is made from the smallest components of + /// the two specified Vector3s. + /// + /// Vector3 to calculate minimum Vector3 with. + /// Another Vector3 to calculate minimum Vector3 with. + /// + /// The Vector3 that contains the smallest components of the two specified + /// Vector3s. + /// + static Vector3 Min(Vector3 lhs, Vector3 rhs); + /// + /// Computes and returns a Vector3 that is made from the largest components of + /// the two specified Vector3s. + /// + /// Vector3 to calculate maximum Vector3 with. + /// Another Vector3 to calculate maximum Vector3 with. + /// + /// The Vector3 that contains the largest components of the two specified + /// Vector3s. + /// + static Vector3 Max(Vector3 lhs, Vector3 rhs); + /// + /// Linearly interpolates between two specified points. + /// This is most commonly used to find a point some fraction of the way along a + /// line between two endpoints. + /// + /// The start Vector3, returned when t = 0.0. + /// The end Vector3, returned when t = 1.0. + /// + /// Value used to interpolate between a and b which is clamped to + /// the range[0, 1]. + /// + /// The interpolated Vector3. + static Vector3 Lerp(Vector3 a, Vector3 b, double t); + /// + /// Linearly interpolates between two specified points. + /// This is most commonly used to find a point some fraction of the way along a + /// line between two endpoints. + /// Unlike Lerp(), t is not clamped to a range at all. + /// + /// The start Vector3, returned when t = 0.0. + /// The end Vector3, returned when t = 1.0. + /// Value used to interpolate between a and b. + /// The interpolated Vector3. + static Vector3 LerpUnclamped(Vector3 a, Vector3 b, double t); + /// + /// Moves a point current towards target. + /// Similar to Lerp(), however, the function will ensure that the distance never + /// exceeds maxDistanceDelta. Negative values of maxDistanceDelta pushes the + /// vector away from target + /// + /// The current position of the point. + /// The target position to move to. + /// Maximum distance moved per call. + /// Vector representing the moved point. + static Vector3 MoveTowards(Vector3 current, Vector3 target, double maxDistanceDelta); + + /*-----------------------------------------------------------------------------*/ + /* Overloaded Operators */ + /*-----------------------------------------------------------------------------*/ + /// + /// Adds two Vector3s together and returns the result. + /// + /// Vector3 to add. + /// Another Vector3 to add. + /// The result of lhs added to rhs + static Vector3 operator+(Vector3 lhs, Vector3 rhs); + /// + /// Subtracts a Vector3 from another Vector3 and returns the result. + /// + /// Vector3 to subtract from. + /// Another Vector3 to subtract. + /// The result of rhs subtracted from lhs. + static Vector3 operator-(Vector3 lhs, Vector3 rhs); + /// + /// Calculates the component-wise multiplication of two Vector3s and returns the + /// result. + /// + /// Vector3 to multiply with. + /// Another Vector3 to multiply with. + /// The result of rhs subtracted from lhs. + static Vector3 operator*(Vector3 lhs, Vector3 rhs); + /// + /// Calculates the multiplication of a Vector3 with a scalar value and returns + /// the result. + /// + /// Vector3 to multiply with. + /// Scalar to multiply with. + /// The result of the scalar multiplication. + static Vector3 operator*(Vector3 lhs, double rhs); + /// + /// Calculates the division of a Vector3 with a scalar value and returns + /// the result. + /// + /// Scalar to divide with. + /// Vector3 to divide with. + /// The result of the scalar division. + static Vector3 operator/(Vector3 lhs, double rhs); + /// + /// Checks if two Vector3s are approximately equal. This is equivalent to + /// calling Vector3.IsNear() with default tolerance values. + /// + /// Vector3 to compare. + /// Another Vector3 to compare. + /// + /// True if all components are approximately equal within the default + /// tolerance value. + /// + static bool operator==(Vector3 lhs, Vector3 rhs); + /// + /// Checks if two Vector3s are not approximately equal. This is equivalent to + /// calling !Vector3.IsNear() with default tolerance values. + /// + /// Vector3 to compare. + /// Another Vector3 to compare. + /// + /// True if all components are not approximately equal within the default + /// tolerance value. + /// + static bool operator!=(Vector3 lhs, Vector3 rhs); + + /*-----------------------------------------------------------------------------*/ + /* Conversion Operators */ + /*-----------------------------------------------------------------------------*/ + /// + /// Explicit conversion operator to enable explicit casting from a Vector3 to a + /// Vector2. + /// + /// Vector3 to convert from. + static explicit operator Vector2(Vector3 vec); + /// + /// Explicit conversion operator to enable explicit casting from a Vector2 to a + /// Vector3. + /// + /// Vector2 to convert from. + static explicit operator Vector3(Vector2 vec); + }; +} // namespace PlushieAPI::Mathematics diff --git a/SHADE_Managed/src/SHpch.cpp b/SHADE_Managed/src/SHpch.cpp new file mode 100644 index 00000000..2a36c693 --- /dev/null +++ b/SHADE_Managed/src/SHpch.cpp @@ -0,0 +1,10 @@ +/**************************************************************************************** + * \file SHpch.h + * \brief Empty source file for generating SHADE Engine's precompiled header. + * + * \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 "SHpch.h" \ No newline at end of file diff --git a/SHADE_Managed/src/SHpch.h b/SHADE_Managed/src/SHpch.h new file mode 100644 index 00000000..b54a8a5b --- /dev/null +++ b/SHADE_Managed/src/SHpch.h @@ -0,0 +1,31 @@ +/**************************************************************************************** + * \file SHpch.h + * \brief Precompiled header file for SHADE Engine. + * + * \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 + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files +#include +// C RunTime Header Files +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/SHADE_Managed/src/Scripts/Script.cxx b/SHADE_Managed/src/Scripts/Script.cxx new file mode 100644 index 00000000..ecd27325 --- /dev/null +++ b/SHADE_Managed/src/Scripts/Script.cxx @@ -0,0 +1,171 @@ +/************************************************************************************//*! +\file Script.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definition of the functions for the PlushieScript managed + class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "Script.hxx" +// Project Headers +#include "Utility/Debug.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Component Access Functions */ + /*---------------------------------------------------------------------------------*/ + generic + T Script::AddComponent() + { + return owner.AddComponent(); + } + generic + T Script::GetComponent() + { + return owner.GetComponent(); + } + + generic + T Script::GetComponentInChildren() + { + return owner.GetComponentInChildren(); + } + + generic + T Script::EnsureComponent() + { + return owner.EnsureComponent(); + } + generic + void Script::RemoveComponent() + { + throw gcnew System::NotImplementedException; + //ECS::RemoveComponent(owner.GetNativeEntity()); + } + + /*---------------------------------------------------------------------------------*/ + /* Script Access Functions */ + /*---------------------------------------------------------------------------------*/ + generic + T Script::AddScript() + { + throw gcnew System::NotImplementedException; + //return ScriptStore::AddScript(owner.GetEntity()); + } + generic + T Script::GetScript() + { + throw gcnew System::NotImplementedException; + //return ScriptStore::GetScript(owner.GetEntity()); + } + + generic + T Script::GetScriptInChildren() + { + throw gcnew System::NotImplementedException; + //return ScriptStore::GetScriptInChildren(owner.GetEntity()); + } + + generic + System::Collections::Generic::IEnumerable^ Script::GetScripts() + { + throw gcnew System::NotImplementedException; + //return ScriptStore::GetScripts(owner.GetEntity()); + } + + generic + void Script::RemoveScript() + { + throw gcnew System::NotImplementedException; + //ScriptStore::RemoveScript(owner.GetEntity()); + } + + /*---------------------------------------------------------------------------------*/ + /* "All-time" Lifecycle Functions */ + /*---------------------------------------------------------------------------------*/ + void Script::OnAttached() + { + SAFE_NATIVE_CALL_BEGIN + onAttached(); + SAFE_NATIVE_CALL_END(this) + } + void Script::OnDetached() + { + SAFE_NATIVE_CALL_BEGIN + onDetatched(); + SAFE_NATIVE_CALL_END(this) + } + + /*---------------------------------------------------------------------------------*/ + /* Lifecycle Functions */ + /*---------------------------------------------------------------------------------*/ + void Script::Awake() + { + SAFE_NATIVE_CALL_BEGIN + awake(); + SAFE_NATIVE_CALL_END(this) + } + void Script::Start() + { + SAFE_NATIVE_CALL_BEGIN + start(); + SAFE_NATIVE_CALL_END(this) + } + void Script::FixedUpdate() + { + SAFE_NATIVE_CALL_BEGIN + fixedUpdate(); + SAFE_NATIVE_CALL_END(this) + } + void Script::Update() + { + SAFE_NATIVE_CALL_BEGIN + update(); + SAFE_NATIVE_CALL_END(this) + } + void Script::LateUpdate() + { + SAFE_NATIVE_CALL_BEGIN + lateUpdate(); + SAFE_NATIVE_CALL_END(this) + } + void Script::OnDestroy() + { + SAFE_NATIVE_CALL_BEGIN + onDestroy(); + SAFE_NATIVE_CALL_END(this) + } + + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + Script::Script(GameObject gameObj) + : owner { gameObj } + {} + + /*---------------------------------------------------------------------------------*/ + /* Virtual "All-Time" Lifecycle Functions */ + /*---------------------------------------------------------------------------------*/ + void Script::onAttached() {} + void Script::onDetatched() {} + + /*---------------------------------------------------------------------------------*/ + /* Virtual Lifecycle Functions */ + /*---------------------------------------------------------------------------------*/ + void Script::awake() {} + void Script::start() {} + void Script::fixedUpdate() {} + void Script::update() {} + void Script::lateUpdate() {} + void Script::onDestroy() {} +}// namespace PlushieAPI diff --git a/SHADE_Managed/src/Scripts/Script.hxx b/SHADE_Managed/src/Scripts/Script.hxx new file mode 100644 index 00000000..cef9f4cd --- /dev/null +++ b/SHADE_Managed/src/Scripts/Script.hxx @@ -0,0 +1,274 @@ +/************************************************************************************//*! +\file Script.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definition of the Script class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Project Includes +#include "Engine/GameObject.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Forward Declarations */ + /*---------------------------------------------------------------------------------*/ + ref class BaseComponent; + + /*---------------------------------------------------------------------------------*/ + /* Class Definitions */ + /*---------------------------------------------------------------------------------*/ + /// + /// Class that forms the basis of all "script"-objects that can be attached to + /// Entities to update each Entity's Components via C# code. + /// + public ref class Script + { + public: + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ + /// + /// GameObject that this Script belongs to. + /// + property GameObject Owner + { + GameObject get() { return owner; } + } + + /*-----------------------------------------------------------------------------*/ + /* Component Access Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Adds a Component to the GameObject that this Script belongs to. + /// + /// + /// Type of the Component to add. Must be derived from BaseComponent. + /// + /// Reference to the Component that was added. + generic where T : BaseComponent + T AddComponent(); + /// + /// Gets a Component from the GameObject that this Script belongs to. + /// + /// + /// Type of the Component to get. Must be derived from BaseComponent. + /// + /// Reference to the Component that was retrieved. + generic where T : BaseComponent + T GetComponent(); + /// + /// Retrieves the first Component from this GameObject's children that matches + /// the specified type. + /// + /// + /// Type of the Component to get. Must be derived from BaseComponent. + /// + /// Reference to the Component that was retrieved. + generic where T : BaseComponent + T GetComponentInChildren(); + /// + /// Ensures a Component on the GameObject that this Script belongs to. + /// + /// + /// Type of the Component to ensure. Must be derived from BaseComponent. + /// + /// Reference to the Component. + generic where T : BaseComponent + T EnsureComponent(); + /// + /// Removes a Component from the GameObject that this Script belongs to. + /// + /// + /// Type of the Component to remove. Must be derived from BaseComponent. + /// + generic where T : BaseComponent + void RemoveComponent(); + + /*-----------------------------------------------------------------------------*/ + /* Script Access Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Adds a Script to this GameObject. + /// + /// + /// Type of script to add. + /// This needs to be a default constructable Script. + /// + /// Reference to the script added + generic where T : ref class, Script + T AddScript(); + /// + /// Retrieves the first Script from this GameObject that matches the specified + /// type. + /// + /// + /// Type of script to get. + /// This needs to be a default constructable Script. + /// + /// Reference to the script added + generic where T : ref class, Script + T GetScript(); + /// + /// Retrieves the first Script from this GameObject's children that matches the + /// specified type. + /// + /// + /// Type of script to get. + /// This needs to be a default constructable Script. + /// + /// Reference to the script added + generic where T : ref class, Script + T GetScriptInChildren(); + /// + /// Retrieves a immutable list of scripts from the specified Entity that + /// matches the specified type. + ///
+ /// Note that this function allocates. It should be used sparingly. + ///
+ /// + /// Type of scripts to get. + /// This needs to be a default constructable Script. + /// + /// + /// Immutable list of references to scripts of the specified type. + /// + generic where T : ref class, Script + System::Collections::Generic::IEnumerable^ GetScripts(); + /// + /// Removes all Scripts of the specified type from this GameObject. + /// + /// + /// Type of script to remove. + /// This needs to be a default constructable Script. + /// + generic where T : ref class, Script + void RemoveScript(); + + internal: + /*-----------------------------------------------------------------------------*/ + /* "All-Time" Lifecycle Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Used to call onAttached(). This is called immediately when this script is + /// attached to a GameObject. + /// + void OnAttached(); + /// + /// Used to call onDetached(). This is called immediately when this script is + /// detached from a GameObject. + /// + void OnDetached(); + + /*-----------------------------------------------------------------------------*/ + /* Lifecycle Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Used to call awake(). This should be called on the first frame that the + /// attached GameObject is active if they are a part of the scene. + /// + void Awake(); + /// + /// Used to call start(). This should be called on the first frame that the + /// attached GameObject is active but always after Awake(). + /// + void Start(); + /// + /// Used to call fixedUpdate(). This should be called in sync with Physics + /// update steps and thus in most cases will execute more than Update() will. + /// This will be called immediately before a Physics update step. + /// + void FixedUpdate(); + /// + /// Used to call update(). This should be called every frame before physics and + /// collision resolution. + /// + void Update(); + /// + /// Used to call lateUpdate(). This should be called every frame after physics + /// and collision resolution but before rendering. + /// + void LateUpdate(); + /// + /// Used to call onDestroy(). This should be called at the end of the frame + /// where the attached GameObject or this script is destroyed directly or + /// indirectly due to destruction of the owner. + /// + void OnDestroy(); + + protected: + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Constructor for Script to tie it to a specific GameObject. + /// Constructors of derived Scripts should call this Constructor. + /// + /// + /// GameObject that this Script will be tied to. + /// + Script(GameObject gameObj); + + /*-----------------------------------------------------------------------------*/ + /* Virtual "All-Time" Lifecycle Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Called immediately once this script is attached to a GameObject. + /// + virtual void onAttached(); + /// + /// Called immediately once this script is detached from a GameObject. + /// + virtual void onDetatched(); + + /*-----------------------------------------------------------------------------*/ + /* Virtual Lifecycle Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Called on the first frame that the attached GameObject is active if they are + /// a part of the scene. + /// + virtual void awake(); + /// + /// Called on the first frame that the attached GameObject is active but always + /// after Awake(). + /// + virtual void start(); + /// + /// Called every frame in sync with Physics update steps and thus in most cases + /// will execute more than update() will. This will be called immediately before + /// a Physics update step. + /// + virtual void fixedUpdate(); + /// + /// Called every frame before physics and collision resolution. + /// + virtual void update(); + /// + /// Called every frame after physics and collision resolution but before + /// rendering. + /// + virtual void lateUpdate(); + /// + /// Called just before the end of the frame where the attached GameObject or + /// this script is destroyed directly or indirectly due to destruction of the + /// owner. + /// + virtual void onDestroy(); + + private: + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + GameObject owner; + }; + +} // namespace PlushieAPI diff --git a/SHADE_Managed/src/Scripts/ScriptStore.cxx b/SHADE_Managed/src/Scripts/ScriptStore.cxx new file mode 100644 index 00000000..9a9eff54 --- /dev/null +++ b/SHADE_Managed/src/Scripts/ScriptStore.cxx @@ -0,0 +1,673 @@ +/************************************************************************************//*! +\file ScriptStore.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definition of the functions for the ScriptStore managed + static class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "ScriptStore.hxx" +// Standard Libraries +#include +// External Dependencies +#include "ECS_Base/System/SHEntityManager.h" +// Project Headers +#include "Utility/Debug.hxx" +#include "Utility/Convert.hxx" +#include "Script.hxx" +#include "Engine/Entity.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Scripts Manipulation Functions */ + /*---------------------------------------------------------------------------------*/ + generic + T ScriptStore::AddScript(Entity entity) + { + // Check if entity exists + if (!EntityUtils::IsValid(entity)) + throw gcnew System::ArgumentException("Invalid Entity provided to add a Script to."); + + System::Collections::Generic::List ^ entityScriptList; + + // Check if storage for scripts of this entity exists + if (!scripts.ContainsKey(entity)) + { + // Create a new list for this set of scripts + entityScriptList = gcnew System::Collections::Generic::List(); + scripts.Add(entity, entityScriptList); + } + else + { + entityScriptList = scripts[entity]; + } + + // Create the script and add it in + array^ params = gcnew array{GameObject(entity)}; + Script^ script = safe_cast(System::Activator::CreateInstance(T::typeid, params)); + entityScriptList->Add(script); + awakeList.Add(script); + startList.Add(script); + script->OnAttached(); + + return safe_cast(script); + } + + bool ScriptStore::AddScriptViaName(Entity entity, System::String^ scriptName) + { + SAFE_NATIVE_CALL_BEGIN + Script^ script; + return AddScriptViaNameWithRef(entity, scriptName, script); + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + return false; + } + + bool ScriptStore::AddScriptViaNameWithRef(Entity entity, System::String^ scriptName, Script^% createdScript) + { + // Check if we are set up to get scripts + if (addScriptMethod == nullptr) + { + Debug::LogError("[ScriptStore] Native AddScript() was not loaded. Unable to add scripts."); + return false; + } + + // Get the script if it exists + System::Type^ scriptType = getScriptType(scriptName); + if (scriptType == nullptr) + { + std::ostringstream oss; + oss << "[ScriptStore] No Script named " + << Convert::ToNative(scriptName) + << " found!"; + Debug::LogError(oss.str()); + return false; + } + + // Otherwise, add the script + System::Reflection::MethodInfo^ method = addScriptMethod->MakeGenericMethod(scriptType); + try + { + array^ params = gcnew array{entity}; + createdScript = safe_cast(method->Invoke(nullptr, params)); + } + catch (System::Exception^ e) + { + std::ostringstream oss; + oss << "[ScriptStore] Failed to add Script named \"" << Convert::ToNative(scriptName) + << "\" to Entity #" << entity << "! (" << Convert::ToNative(e->GetType()->Name) << ")"; + Debug::LogError(oss.str()); + return false; + } + return true; + } + + generic + T ScriptStore::GetScript(Entity entity) + { + // Check if entity exists + if (!EntityUtils::IsValid(entity)) + throw gcnew System::ArgumentException("Invalid Entity provided to get a Script from."); + + // Check if entity exists in the script storage + if (!scripts.ContainsKey(entity)) + { + return T(); + } + + // Search for and obtain + for each (Script^ script in scripts[entity]) + { + try + { + T actualScript = safe_cast(script); + return actualScript; + } + catch (System::InvalidCastException^) + { + continue; + } + } + + return T(); + } + + generic + T ScriptStore::GetScriptInChildren(Entity entity) + { + // Check if entity exists and is a valid GameObject + if (!EntityUtils::IsValid(entity)) + throw gcnew System::ArgumentException("Invalid Entity provided to get a Script from."); + + + // Check if entity exists in the script storage + if (!scripts.ContainsKey(entity)) + { + return T(); + } + + // Get Transform component and get the children list + throw gcnew System::NotImplementedException; + //Pls::Transform* tf = Pls::ECS::GetComponent(Convert::ToNative(entity)); + //if (tf == nullptr) + // return T(); + + //// Search direct children first + //for (const auto& child : tf->GetChildren()) + //{ + // T script = GetScript(Convert::ToCLI(child)); + // if (script != nullptr) + // return script; + //} + + //// Search their children + //for (const auto& child : tf->GetChildren()) + //{ + // T script = GetScriptInChildren(Convert::ToCLI(child)); + // if (script != nullptr) + // return script; + //} + + // None here + return T(); + } + + generic + System::Collections::Generic::IEnumerable^ ScriptStore::GetScripts(Entity entity) + { + // Check if entity exists and is a valid GameObject + if (!EntityUtils::IsValid(entity)) + throw gcnew System::ArgumentException("Invalid Entity provided to get a Script from."); + + // Create a list to store entries + System::Collections::Generic::List^ foundScripts = gcnew System::Collections::Generic::List(); + + // Check if entity exists in the script storage + if (!scripts.ContainsKey(entity)) + { + return foundScripts; + } + + // Search for and obtain + for each (Script^ script in scripts[entity]) + { + try + { + T actualScript = safe_cast(script); + foundScripts->Add(actualScript); + } + catch (System::InvalidCastException^) + { + continue; + } + } + + return foundScripts; + } + System::Collections::Generic::IEnumerable^ ScriptStore::GetAllScripts(Entity entity) + { + // Check if entity exists + if (!EntityUtils::IsValid(entity)) + return nullptr; + + // Check if entity exists in the script storage + if (scripts.ContainsKey(entity)) + { + return scripts[entity]; + } + return nullptr; + } + generic + void ScriptStore::RemoveScript(Entity entity) + { + // Check if entity exists + if (!EntityUtils::IsValid(entity)) + throw gcnew System::ArgumentException("Invalid Entity provided to remove a Script from."); + + + // Check if entity exists in the script storage + if (!scripts.ContainsKey(entity)) + { + Debug::LogError("[ScriptStore] Attempted to remove a Script that does not belong to the specified Entity!"); + return; + } + + // Search for and obtain + for each (Script^ script in scripts[entity]) + { + try + { + safe_cast(script); + removeScript(script); + } + catch (System::InvalidCastException^) + { + continue; + } + } + } + bool ScriptStore::RemoveScript(Entity entity, Script^ script) + { + // Check if entity exists + if (!EntityUtils::IsValid(entity)) + { + Debug::LogError("[ScriptStore] Attempted to remove a Script from an invalid Entity!"); + return false; + } + + + // Check if entity exists in the script storage + if (!scripts.ContainsKey(entity)) + { + Debug::LogError("[ScriptStore] Attempted to remove a Script that does not belong to the specified Entity!"); + return false; + } + + // Check if the script exists to begin with + if (!scripts[entity]->Contains(script)) + { + Debug::LogError("[ScriptStore] Attempted to remove a Script that does not belong to the specified Entity!"); + return false; + } + + // Script found, queue it for deletion + removeScript(script); + return true; + } + void ScriptStore::RemoveAllScripts(Entity entity) + { + SAFE_NATIVE_CALL_BEGIN + // Check if entity exists + if (!EntityUtils::IsValid(entity)) + { + Debug::LogError("[ScriptStore] Attempted to remove Scripts from an invalid Entity!"); + return; + } + + // Check if entity exists in the script storage + if (!scripts.ContainsKey(entity)) + return; + + // Search for and clear + System::Collections::Generic::List^ scriptList = scripts[entity]; + for each (Script^ script in scriptList) + { + removeScript(script); + } + scriptList->Clear(); + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + } + void ScriptStore::RemoveAllScriptsImmediately(Entity entity, bool callOnDestroy) + { + SAFE_NATIVE_CALL_BEGIN + // Check if entity exists + if (!EntityUtils::IsValid(entity)) + { + Debug::LogError("[ScriptStore] Attempted to remove Scripts from an invalid Entity!"); + return; + } + + // Check if entity exists in the script storage + if (!scripts.ContainsKey(entity)) + return; + + // Clear all + System::Collections::Generic::List^ scriptList = scripts[entity]; + for each (Script ^ script in scriptList) + { + // Call OnDestroy only if indicated and also in play mode + if (callOnDestroy) + { + script->OnDestroy(); + } + script->OnDetached(); + + // Remove scripts from awakening if they were not woken up to begin with + awakeList.Remove(script); + startList.Remove(script); + } + scriptList->Clear(); + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + } + + /*---------------------------------------------------------------------------------*/ + /* Lifecycle Functions */ + /*---------------------------------------------------------------------------------*/ + void ScriptStore::Init() + { + // Create an enumerable list of script types + refreshScriptTypeList(); + // Get stored methods for interop variants of functions + getGenericMethods(); + } + void ScriptStore::FrameSetUp() + { + SAFE_NATIVE_CALL_BEGIN + // Clear the awake queue + for each (Script^ script in awakeList) + { + script->Awake(); + } + awakeList.Clear(); + + // Clear the start queue + for each (Script^ script in startList) + { + if (script->Owner.IsActiveInHierarchy) + { + script->Start(); + } + else + { + inactiveStartList.Add(script); + } + } + startList.Clear(); + startList.AddRange(%inactiveStartList); + inactiveStartList.Clear(); + + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + } + void ScriptStore::FrameCleanUp() + { + SAFE_NATIVE_CALL_BEGIN + // Clear the queue + while (disposalQueue.Count > 0) + { + Script^ script = disposalQueue.Dequeue(); + /*if (Application::IsPlaying) + { + script->OnDestroy(); + }*/ + auto entity = script->Owner.GetEntity(); + auto scriptList = scripts[script->Owner.GetEntity()]; + scriptList->Remove(script); + if (scriptList->Count <= 0) + { + scripts.Remove(entity); + } + } + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + } + void ScriptStore::Exit() + { + SAFE_NATIVE_CALL_BEGIN + // Run the deinit all scripts if needed + //if (Application::IsPlaying) + { + Debug::Log("Running OnDestroy() for scripts."); + for each (System::Collections::Generic::KeyValuePair entity in scripts) + { + for each (Script^ script in entity.Value) + { + script->OnDestroy(); + } + } + } + + // Clear Script Storage + scripts.Clear(); + awakeList.Clear(); + startList.Clear(); + disposalQueue.Clear(); + scriptTypeList = nullptr; + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + } + + /*---------------------------------------------------------------------------------*/ + /* Script Information Functions */ + /*---------------------------------------------------------------------------------*/ + System::Collections::Generic::IEnumerable^ ScriptStore::GetAvailableScriptList() + { + return scriptTypeList; + } + + /*---------------------------------------------------------------------------------*/ + /* Script Execution Functions */ + /*---------------------------------------------------------------------------------*/ + void ScriptStore::ExecuteFixedUpdate() + { + SAFE_NATIVE_CALL_BEGIN + for each (System::Collections::Generic::KeyValuePair entity in scripts) + { + // Check active state + if (!isEntityActive(entity.Key)) + continue; + + // Update each script + for each (Script^ script in entity.Value) + { + script->FixedUpdate(); + } + } + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + } + void ScriptStore::ExecuteUpdate() + { + SAFE_NATIVE_CALL_BEGIN + for each (System::Collections::Generic::KeyValuePair entity in scripts) + { + // Check active state + if (!isEntityActive(entity.Key)) + continue; + + // Update each script + for each (Script^ script in entity.Value) + { + script->Update(); + } + } + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + } + void ScriptStore::ExecuteLateUpdate() + { + SAFE_NATIVE_CALL_BEGIN + for each (System::Collections::Generic::KeyValuePair entity in scripts) + { + // Check active state + if (!isEntityActive(entity.Key)) + continue; + + // Update each script + for each (Script^ script in entity.Value) + { + script->LateUpdate(); + } + } + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + } + bool ScriptStore::SerialiseScripts(Entity entity, System::Text::StringBuilder^ buffer, int bufferSize) + { + SAFE_NATIVE_CALL_BEGIN + // Create a buffer that we can work with temporarily + System::Text::StringBuilder^ jsonString = gcnew System::Text::StringBuilder(); + + // Check if entity exists, otherwise nothing + if (!EntityUtils::IsValid(entity)) + return true; + + + // Check if entity exists in the script storage + if (!scripts.ContainsKey(entity)) + return true; + + // Serialise each script + System::Collections::Generic::List^ scriptList = scripts[entity]; + for (int i = 0; i < scriptList->Count; ++i) + { + throw gcnew System::NotImplementedException; + //jsonString->Append(ReflectionUtilities::Serialise(scriptList[i])); + + // Only add separator if is not last script + if (i != scriptList->Count - 1) + { + jsonString->Append(",\r\n"); + } + } + + // Check if the size is too big + if (jsonString->Length > bufferSize) + return false; + + // Otherwise we copy it over + buffer->Clear(); + buffer->Append(jsonString->ToString()); + return true; + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + return false; + } + + bool ScriptStore::DeserialiseScript(Entity entity, System::String^ yaml) + { + SAFE_NATIVE_CALL_BEGIN + // Check if entity exists, otherwise nothing + if (!EntityUtils::IsValid(entity)) + return false; + + // Get the name of the script + const int FIRST_QUOTE = yaml->IndexOf('\"'); + const int FIRST_COLON = yaml->IndexOf(':'); + if (FIRST_QUOTE < 0 || FIRST_COLON < 0) // No script name, it's invalid + return false; + const int SCRIPT_NAME_START = FIRST_QUOTE + 1; + const int SCRIPT_NAME_END = FIRST_COLON - 1; + System::String^ typeName = yaml->Substring(SCRIPT_NAME_START, SCRIPT_NAME_END - SCRIPT_NAME_START); + + // Create the script + Script^ script; + if (AddScriptViaNameWithRef(entity, typeName, script)) + { + // Copy the data in + throw gcnew System::NotImplementedException; + //ReflectionUtilities::Deserialise(json, script); + return true; + } + + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + return false; + } + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + void ScriptStore::removeScript(Script^ script) + { + // Prepare for disposal + disposalQueue.Enqueue(script); + + // Also remove it fromm awake and start queues if they were created but not initialised + awakeList.Remove(script); + startList.Remove(script); + script->OnDetached(); + } + + namespace + { + /* Select Many */ + ref struct Pair + { + System::Reflection::Assembly^ assembly; + System::Type^ type; + }; + + System::Collections::Generic::IEnumerable^ selectorFunc(System::Reflection::Assembly^ assembly) + { + return assembly->GetExportedTypes(); + } + Pair^ resultSelectorFunc(System::Reflection::Assembly^ assembly, System::Type^ type) + { + Pair^ p = gcnew Pair(); + p->assembly = assembly; + p->type = type; + return p; + } + + /* Where */ + bool predicateFunc(Pair^ pair) + { + return pair->type->IsSubclassOf(Script::typeid) && !pair->type->IsAbstract; + } + + /* Select */ + System::Type^ selectorFunc(Pair^ pair) + { + return pair->type; + } + } + + void ScriptStore::refreshScriptTypeList() + { + using namespace System; + using namespace System::Reflection; + using namespace System::Linq; + using namespace System::Collections::Generic; + + /* Select Many: Types in Loaded Assemblies */ + IEnumerable^ assemblies = AppDomain::CurrentDomain->GetAssemblies(); + Func^>^ collectionSelector = gcnew Func^>(selectorFunc); + Func^ resultSelector = gcnew Func(resultSelectorFunc); + IEnumerable^ selectManyResult = Enumerable::SelectMany(assemblies, collectionSelector, resultSelector); + + /* Where: Are concrete Scripts */ + Func^ predicate = gcnew Func(predicateFunc); + IEnumerable^ whereResult = Enumerable::Where(selectManyResult, predicate); + + /* Select: Select them all */ + Func^ selector = gcnew Func(selectorFunc); + scriptTypeList = Enumerable::Select(whereResult, selector); + + // Log + std::ostringstream oss; + oss << "[ScriptStore] Successfully retrieved references to " << Enumerable::Count(scriptTypeList) + << " Script(s) from currently loaded assemblies."; + Debug::Log(oss.str()); + } + + void ScriptStore::getGenericMethods() + { + addScriptMethod = ScriptStore::typeid->GetMethod("AddScript"); + if (addScriptMethod == nullptr) + { + Debug::LogError("[ScriptStore] Failed to get MethodInfo of \"AddScript()\". Adding of scripts from native code will fail."); + } + } + + System::Type^ ScriptStore::getScriptType(System::String^ scriptName) + { + // Remove any whitespaces just in case + scriptName = scriptName->Trim(); + + // Look for the correct script + for each (System::Type^ type in scriptTypeList) + { + if (type->FullName == scriptName || type->Name == scriptName) + { + return type; + } + } + + return nullptr; + } + + bool ScriptStore::isEntityActive(Entity entity) + { + // Get native Entity + SHEntity* nativeEntity = SHEntityManager::GetEntityByID(entity); + + // Entity Validity Check + if (nativeEntity == nullptr) + throw gcnew System::InvalidOperationException("Attempted to get native Component to an invalid Entity."); + + // Check active state + return nativeEntity->isActive; + } +} diff --git a/SHADE_Managed/src/Scripts/ScriptStore.hxx b/SHADE_Managed/src/Scripts/ScriptStore.hxx new file mode 100644 index 00000000..cc0c1db5 --- /dev/null +++ b/SHADE_Managed/src/Scripts/ScriptStore.hxx @@ -0,0 +1,301 @@ +/************************************************************************************//*! +\file ScriptStore.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definitions of the GameObject managed class which define an + abstraction for working with Entities in managed code. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Project Includes +#include "Engine/Entity.hxx" +#include "Script.hxx" + +namespace SHADE +{ + /// + /// Responsible for managing all scripts attached to Entities as well as executing + /// all lifecycle functions of scripts. + /// + public ref class ScriptStore abstract sealed + { + public: + /*-----------------------------------------------------------------------------*/ + /* Scripts Manipulation Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Adds a Script to a specified Entity. + /// + /// + /// Type of script to add. + /// This needs to be a default constructable PlushieScript. + /// + /// The entity to add a script to. + /// Reference to the script added. + /// + /// If the specified Entity is invalid. + /// + generic where T : ref class, Script + static T AddScript(Entity entity); + /// + /// Adds a Script to a specified Entity. + ///
+ /// This function is meant for consumption from native code. If you are writing + /// in C# or C++/CLI, use AddScript<T>() instead as it is faster. + ///
+ /// The entity to add a script to. + /// The entity to add a script to. + /// + /// True if successfully added. False otherwise with the error logged to the + /// console. + /// + static bool AddScriptViaName(Entity entity, System::String^ scriptName); + /// + /// Adds a Script to a specified Entity. + ///
+ /// This function is meant for consumption from native code or for serialisation + /// purposes. If you are writing in C# or C++/CLI and not doing serialisation, + /// use AddScript<T>() instead as it is faster. + ///
+ /// The entity to add a script to. + /// The entity to add a script to. + /// + /// Out parameter handle to the Script that was created. + /// + /// + /// True if successfully added. False otherwise with the error logged to the + /// console. + /// + static bool AddScriptViaNameWithRef(Entity entity, System::String^ scriptName, [System::Runtime::InteropServices::Out] Script^% createdScript); + /// + /// Retrieves the first Script from the specified Entity that matches the + /// specified type. + /// + /// + /// Type of script to get. + /// This needs to be a default constructable Script. + /// + /// + /// The entity which the script to retrieve is attached. + /// + /// + /// Reference to the script. This can be null if no script of the specified + /// type is attached. + /// + /// + /// If the specified Entity is invalid. + /// + generic where T : ref class, Script + static T GetScript(Entity entity); + /// + /// Retrieves the first Script from the specified Entity's children that matches + /// the specified type. + /// + /// + /// Type of script to get. + /// This needs to be a default constructable Script. + /// + /// + /// The entity which the script to retrieve is attached. + /// + /// + /// Reference to the script. This can be null if no script of the specified + /// type is attached. + /// + /// + /// If the specified Entity is invalid. + /// + generic where T : ref class, Script + static T GetScriptInChildren(Entity entity); + /// + /// Retrieves a immutable list of scripts from the specified Entity that + /// matches the specified type. + ///
+ /// Note that this function allocates. It should be used sparingly. + ///
+ /// + /// Type of scripts to get. + /// This needs to be a default constructable Script. + /// + /// + /// The entity which the scripts to retrieve are attached. + /// + /// + /// Immutable list of references to scripts of the specified type. + /// + generic where T : ref class, Script + static System::Collections::Generic::IEnumerable ^ GetScripts(Entity entity); + /// + /// Retrieves an immutable list of all scripts attached to a specified Entity. + /// + /// + /// The entity which the scripts to retrieve are attached. + /// + /// + /// Immutable list of references to scripts attached to the specified Entity. + /// This can also be null if there are no scripts at all or an invalid Entity + /// was specified. + /// + static System::Collections::Generic::IEnumerable^ GetAllScripts(Entity entity); + /// + /// Removes all Scripts of the specified type from the specified Entity. + /// + /// + /// Type of script to remove. + /// This needs to be a default constructable Script. + /// + /// The entity to remove the script from. + /// + /// If the specified Entity is invalid. + /// + generic where T : ref class, Script + static void RemoveScript(Entity entity); + /// + /// Removes a specific script from the + /// + /// The entity to remove the script from. + /// The script to remove. + /// True if successfully removed. False otherwise. + static bool RemoveScript(Entity entity, Script^ script); + /// + /// Removes all Scripts attached to the specified Entity. Does not do anything + /// if the specified Entity is invalid or does not have any Scripts + /// attached. + /// + /// The entity to remove the scripts from. + static void RemoveAllScripts(Entity entity); + /// + /// Removes all Scripts attached to the specified Entity. Unlike + /// RemoveAllScripts(), this removes all the scripts immediately. + /// Does not do anything if the specified Entity is invalid or does not have any + /// Scripts attached. + /// + /// The entity to remove the scripts from. + /// + /// Whether or not to call OnDestroy on the scripts.This is ignored if not in + /// play mode. + /// + static void RemoveAllScriptsImmediately(Entity entity, bool callOnDestroy); + + internal: + /*-----------------------------------------------------------------------------*/ + /* Lifecycle Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Initializes the ScriptStore to allocate and pre-populate reflection data. + /// + static void Init(); + /// + /// Sets up scripts that were marked for initialization. This calls the Awake() + /// and Start() for Scripts that have yet to have done so. + /// + static void FrameSetUp(); + /// + /// Cleans up scripts that were marked for deletion. This calls the OnDestroy() + /// for these Scripts. + /// + static void FrameCleanUp(); + /// + /// Cleans up data stored in the ScriptStore to free up memory for garbage + /// collection. + /// + static void Exit(); + + /*-----------------------------------------------------------------------------*/ + /* Script Information Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Retrieves a immutable list of available scripts that can be added. + /// + /// Immutable list of available scripts that can be added. + static System::Collections::Generic::IEnumerable^ GetAvailableScriptList(); + + /*-----------------------------------------------------------------------------*/ + /* Script Execution Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Executes FixedUpdate() for all scripts. + /// + static void ExecuteFixedUpdate(); + /// + /// Executes Update() for all scripts. + /// + static void ExecuteUpdate(); + /// + /// Executes LateUpdate() for all scripts. + /// + static void ExecuteLateUpdate(); + + /*-----------------------------------------------------------------------------*/ + /* Serialisation Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Generates a JSON string that represents the set of Scripts attached + /// to the specified Entity. + ///

+ /// This function should only be called from native unmanaged code. + ///
+ /// The Entity to Serialise. + /// + /// StringBuilder handle that maps to a native char array that will contain the + /// serialised string. + /// + /// + /// The size of the char array. + /// + /// + /// True if serialisation is successful. False if the buffer is too small for + /// the serialised output. + /// + static bool SerialiseScripts(Entity entity, System::Text::StringBuilder^ buffer, int bufferSize); + /// + /// Processes a JSON string that represents a single Script and attaches + /// it onto the specified Entity. + ///

+ /// This function should only be called from native unmanaged code. + ///
+ /// + /// The Entity to attach the deserialised Scripts to. + /// + /// + /// JSON string that describes the Script to serialise. + /// + /// + static bool DeserialiseScript(Entity entity, System::String^ yaml); + + private: + /*-----------------------------------------------------------------------------*/ + /* Type Definition */ + /*-----------------------------------------------------------------------------*/ + using ScriptList = System::Collections::Generic::List; + using ScriptDictionary = System::Collections::Generic::Dictionary; + using ScriptQueue = System::Collections::Generic::Queue; + + /*-----------------------------------------------------------------------------*/ + /* Static Data Members */ + /*-----------------------------------------------------------------------------*/ + static ScriptDictionary scripts; + static ScriptList awakeList; + static ScriptList startList; + static ScriptList inactiveStartList; + static ScriptQueue disposalQueue; + static System::Collections::Generic::IEnumerable^ scriptTypeList; + static System::Reflection::MethodInfo^ addScriptMethod; + + /*-----------------------------------------------------------------------------*/ + /* Helper Functions */ + /*-----------------------------------------------------------------------------*/ + static void removeScript(Script^ script); + static void refreshScriptTypeList(); + static void getGenericMethods(); + static System::Type^ getScriptType(System::String^ scriptName); + static bool isEntityActive(Entity entity); + }; +} // namespace PlushieAPI \ No newline at end of file diff --git a/SHADE_Managed/src/Utility/Convert.cxx b/SHADE_Managed/src/Utility/Convert.cxx new file mode 100644 index 00000000..8a8aff70 --- /dev/null +++ b/SHADE_Managed/src/Utility/Convert.cxx @@ -0,0 +1,45 @@ +/************************************************************************************//*! +\file Convert.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definition of the functions for the Convert managed static + class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "Convert.hxx" +// External Dependencies +#include "ECS_Base/System//SHEntityManager.h" +#include + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* ECS Conversions */ + /*---------------------------------------------------------------------------------*/ + Entity Convert::ToCLI(SHEntity entity) + { + return static_cast(entity.GetEID()); + } + + /*---------------------------------------------------------------------------------*/ + /* String Conversions */ + /*---------------------------------------------------------------------------------*/ + std::string Convert::ToNative(System::String^ str) + { + return msclr::interop::marshal_as(str); + } + + System::String^ Convert::ToCLI(const std::string& str) + { + return msclr::interop::marshal_as(str); + } +} // namespace PlushieAPI diff --git a/SHADE_Managed/src/Utility/Convert.hxx b/SHADE_Managed/src/Utility/Convert.hxx new file mode 100644 index 00000000..241e5863 --- /dev/null +++ b/SHADE_Managed/src/Utility/Convert.hxx @@ -0,0 +1,62 @@ +/************************************************************************************//*! +\file Convert.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definition of the Convert static class and the + declaration of its functions. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// External Dependencies +#include "ECS_Base/Entity/SHEntity.h" +// Project Includes +#include "Engine/Entity.hxx" + +namespace SHADE +{ + /// + /// Provides functions easy and consistent syntax for converting between custom + /// managed and native types that are aligned. + /// + class Convert + { + public: + /*-----------------------------------------------------------------------------*/ + /* Deleted Destructors (Static Class) */ + /*-----------------------------------------------------------------------------*/ + Convert() = delete; + + /*-----------------------------------------------------------------------------*/ + /* ECS Conversions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Converts from a native Entity to a managed Entity (UInt32). + /// + /// Native Entity to convert from. + /// Managed representation of the specified Entity. + static Entity ToCLI(SHEntity entity); + + /*-----------------------------------------------------------------------------*/ + /* String Conversions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Converts from a managed String to a native std::string. + /// + /// The managed String to convert from. + /// Native copy of a managed String. + static std::string ToNative(System::String^ str); + /// + /// Converts from a native std::Stringto a managed String. + /// + /// The native std::string to convert from. + /// Managed copy of a native std::string. + static System::String^ ToCLI(const std::string& str); + }; +} diff --git a/SHADE_Managed/src/Utility/Debug.cxx b/SHADE_Managed/src/Utility/Debug.cxx new file mode 100644 index 00000000..330375b0 --- /dev/null +++ b/SHADE_Managed/src/Utility/Debug.cxx @@ -0,0 +1,122 @@ +/************************************************************************************//*! +\file Debug.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definition of the functions for the Debug managed static + class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "Debug.hxx" +// Standard Libraries +#include +// Project Headers +#include "Convert.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Logging Functions */ + /*---------------------------------------------------------------------------------*/ + void Debug::Log(const std::string& str) + { + std::cout << str << std::endl; + } + void Debug::Log(System::String^ str) + { + System::Console::WriteLine(str); + } + + void Debug::Log(System::String^ str, Object^ owner) + { + Log(str, owner->GetType()->Name); + } + void Debug::Log(System::String^ str, System::String^ throwerName) + { + Log("[" + throwerName + "] " + str); + } + void Debug::Log(System::String^ str, const std::string& throwerName) + { + std::ostringstream oss; + oss << "[" << throwerName << "] " << Convert::ToNative(str); + std::cout << oss.str() << std::endl; + } + void Debug::LogWarning(const std::string& str) + { + std::cout << str << std::endl; + } + void Debug::LogWarning(System::String^ str) + { + System::Console::WriteLine(str); + } + void Debug::LogWarning(System::String^ str, Object^ thrower) + { + LogWarning(str, thrower->GetType()->Name); + } + void Debug::LogWarning(System::String^ str, System::String^ throwerName) + { + LogWarning("[" + throwerName + "] " + str); + } + + void Debug::LogWarning(System::String^ str, const std::string& throwerName) + { + std::ostringstream oss; + oss << "[" << throwerName << "] " << Convert::ToNative(str); + std::cout << oss.str() << std::endl; + } + void Debug::LogError(const std::string& str) + { + std::cout << str << std::endl; + } + void Debug::LogError(System::String^ str) + { + System::Console::WriteLine(str); + } + void Debug::LogError(System::String^ str, Object^ thrower) + { + LogError(str, thrower->GetType()->Name); + } + void Debug::LogErrorNative(System::String^ str, const std::string& throwerName) + { + std::ostringstream oss; + oss << "[" << throwerName << "] -> " << Convert::ToNative(str); + std::cout << oss.str() << std::endl; + } + void Debug::LogError(System::String^ str, System::String^ throwerName) + { + LogError("[" + throwerName + "] " + str); + } + void Debug::LogException(System::Exception^ exception) + { + LogError("Unhandled exception: " + exception->ToString(), exception->Source); + } + + void Debug::LogException(System::Exception^ exception, Object^ thrower) + { + LogError("Unhandled exception: " + exception->ToString(), thrower->GetType()->Name); + } + void Debug::LogException(const std::exception& exception, Object^ thrower) + { + LogExceptionNative(exception, Convert::ToNative(thrower->GetType()->Name)); + } + void Debug::LogExceptionNative(System::Exception^ exception, const std::string& throwerName) + { + std::ostringstream oss; + oss << "[" << throwerName << "] Unhandled exception: " << Convert::ToNative(exception->ToString()); + std::cout << oss.str() << std::endl; + } + void Debug::LogExceptionNative(const std::exception& exception, const std::string& throwerName) + { + std::ostringstream oss; + oss << "[" << throwerName << "] Unhandled exception: " << exception.what(); + std::cout << oss.str() << std::endl; + } +} diff --git a/SHADE_Managed/src/Utility/Debug.hxx b/SHADE_Managed/src/Utility/Debug.hxx new file mode 100644 index 00000000..28f2bc88 --- /dev/null +++ b/SHADE_Managed/src/Utility/Debug.hxx @@ -0,0 +1,255 @@ +/************************************************************************************//*! +\file Debug.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 30, 2021 +\brief Contains the definition of the Debug static class and the declaration of + its functions. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Standard Library +#include +#include + +/*-------------------------------------------------------------------------------------*/ +/* Macro Functions */ +/*-------------------------------------------------------------------------------------*/ +/// +/// Macro expansion that is used together with SAFE_NATIVE_CALL_END or +/// SAFE_NATIVE_CALL_END_N to wrap the body of a function with a try and catch that +/// catches native and managed exceptions. This is needed to prevent crashes when calling +/// managed code from native code. +/// + +#define SAFE_NATIVE_CALL_BEGIN try { +/// +/// Macro expansion that is used together with SAFE_NATIVE_CALL_BEGIN or to wrap the body +/// of a function with a try and catch that catches native and managed exceptions. This +/// is needed to prevent crashes when calling managed code from native code. +///
+/// Use this instead of SAFE_NATIVE_CALL_END_N if passing in managed types as the owner. +///
+/// +/// The managed object that owns the function that this macro encapsulates. +/// +#define SAFE_NATIVE_CALL_END(OWNER) \ +} \ +catch (System::Exception^ e) \ +{ \ + Debug::LogException(e); \ +} \ +catch (const std::exception& e) \ +{ \ + Debug::LogException(e, OWNER); \ +} \ +catch (...) \ +{ \ + Debug::LogError("Unsupported native exception.", OWNER); \ +} \ +/// +/// Macro expansion that is used together with SAFE_NATIVE_CALL_BEGIN or to wrap the body +/// of a function with a try and catch that catches native and managed exceptions. This +/// is needed to prevent crashes when calling managed code from native code. +///
+/// Use this instead of SAFE_NATIVE_CALL_END if passing in a native string that specifies +/// the owner. +///
+/// +/// The managed object that owns the function that this macro encapsulates. +/// + +#define SAFE_NATIVE_CALL_END_N(OWNER) \ +} \ +catch (System::Exception^ e) \ +{ \ + Debug::LogExceptionNative(e, OWNER); \ +} \ +catch (const std::exception& e) \ +{ \ + Debug::LogExceptionNative(e, OWNER); \ +} \ +catch (...) \ +{ \ + Debug::LogErrorNative("Unsupported native exception.", OWNER); \ +} \ + +/*-------------------------------------------------------------------------------------*/ +/* Type Definitions */ +/*-------------------------------------------------------------------------------------*/ +namespace SHADE +{ + /// + /// Static class that contains the functions for working with time. + /// + public ref class Debug abstract sealed + { + public: + /*-----------------------------------------------------------------------------*/ + /* Logging Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Logs a message to the output. + /// + /// The string to output. + static void Log(const std::string& str); + /// + /// Logs a message to the output. + /// + /// The string to output. + static void Log(System::String^ str); + /// + /// Logs a message to the output with a label such that it looks like this: + /// "[Label] Message" + /// + /// The string to output. + /// + /// Object that sent the message to label the message. + /// The name of the object will be used. + /// + static void Log(System::String^ str, Object^ owner); + /// + /// Logs a message to the output with a label such that it looks like this: + /// "[Label] Message" + /// + /// The string to output. + /// + /// Name of the object that sent the message to label the message. + /// The name of the object will be used. + /// + static void Log(System::String^ str, System::String^ throwerName); + /// + /// Logs a message to the output with a label such that it looks like this: + /// "[Label] Message" + /// + /// The string to output. + /// + /// Name of the object that sent the message to label the message. + /// The name of the object will be used. + /// + static void Log(System::String^ str, const std::string& throwerName); + /// + /// Logs a warning message to the output. + /// + /// The string to output. + static void LogWarning(const std::string& str); + /// + /// Logs a warning message to the output. + /// + /// The string to output. + static void LogWarning(System::String^ str); + /// + /// Logs a warning message to the output with a label such that it looks like this: + /// "[Label] Message" + /// + /// The string to output. + /// + /// Object that threw the warning to label the warning message. + /// The name of the object will be used. + /// + static void LogWarning(System::String^ str, Object^ thrower); + /// + /// Logs a warning message to the output with a label such that it looks like this: + /// "[Label] Message" + /// + /// The string to output. + /// + /// Name of the object that threw the warning to label the warning message. + /// The name of the object will be used. + /// + static void LogWarning(System::String^ str, System::String^ throwerName); + /// + /// Logs a warning message to the output with a label such that it looks like this: + /// "[Label] Message" + /// + /// The string to output. + /// + /// Name of the object that threw the warning to label the warning message. + /// The name of the object will be used. + /// + static void LogWarning(System::String^ str, const std::string& throwerName); + /// + /// Logs a error message to the output. + /// + /// The string to output. + static void LogError(const std::string& str); + /// + /// Logs a error message to the output. + /// + /// The string to output. + static void LogError(System::String^ str); + /// + /// Logs a error message to the output with a label such that it looks like this: + /// "[Label] Message" + /// + /// The string to output. + /// + /// Object that threw the error to label the error message. + /// The name of the object will be used. + /// + static void LogError(System::String^ str, Object^ thrower); + /// + /// Logs a error message to the output with a label such that it looks like this: + /// "[Label] Message" + /// + /// The string to output. + /// + /// Name of the object that threw the error to label the error message. + /// The name of the object will be used. + /// + static void LogErrorNative(System::String^ str, const std::string& throwerName); + /// + /// Logs a error message to the output with a label such that it looks like this: + /// "[Label] Message" + /// + /// The string to output. + /// + /// Name of the object that threw the error to label the error message. + /// The name of the object will be used. + /// + static void LogError(System::String^ str, System::String^ throwerName); + /// + /// Logs an exception that is formatted nicely to the output. + /// + /// Exception to log. + static void LogException(System::Exception^ exception); + /// + /// Logs an exception that is formatted nicely to the output. + /// + /// Exception to log. + /// + /// Object that threw the exception to label the exception message. + /// The name of the object will be used. + /// + static void LogException(System::Exception^ exception, Object^ thrower); + /// + /// Logs a native exception that is formatted nicely to the output. + /// Equivalent to calling + /// LogException(exception, Convert::ToNative(thrower->GetType()->Name)); + /// + /// Native exception to log. + /// + /// Object that threw the exception to label the exception message. + /// The name of the object will be used. + /// + static void LogException(const std::exception& exception, Object^ thrower); + /// + /// Logs an exception that is formatted nicely to the output. + /// + /// Name of the one responsible for the exception. + /// Exception to log. + static void LogExceptionNative(System::Exception^ exception, const std::string& throwerName); + /// + /// Logs a native exception that is formatted nicely to the output. + /// + /// Native exception to log. + /// Name of the one responsible for the exception. + static void LogExceptionNative(const std::exception& exception, const std::string& throwerName); + }; +} diff --git a/SHADE_Managed/src/Utility/DisposableAssemblyLoadContext.cxx b/SHADE_Managed/src/Utility/DisposableAssemblyLoadContext.cxx new file mode 100644 index 00000000..ebf2e987 --- /dev/null +++ b/SHADE_Managed/src/Utility/DisposableAssemblyLoadContext.cxx @@ -0,0 +1,36 @@ +/************************************************************************************//*! +\file DisposableAssemblyLoadContext.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Jan 20, 2022 +\brief Contains the implementation of the managed DisposableAssemblyLoadContext + class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "DisposableAssemblyLoadContext.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Constructor */ + /*---------------------------------------------------------------------------------*/ + DisposableAssemblyLoadContext::DisposableAssemblyLoadContext() + : AssemblyLoadContext { true } + {} + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + System::Reflection::Assembly^ DisposableAssemblyLoadContext::Load(System::Reflection::AssemblyName^) + { + return nullptr; + } +} // namespace PlushieAPI \ No newline at end of file diff --git a/SHADE_Managed/src/Utility/DisposableAssemblyLoadContext.hxx b/SHADE_Managed/src/Utility/DisposableAssemblyLoadContext.hxx new file mode 100644 index 00000000..433dd85e --- /dev/null +++ b/SHADE_Managed/src/Utility/DisposableAssemblyLoadContext.hxx @@ -0,0 +1,39 @@ +/************************************************************************************//*! +\file DisposableAssemblyLoadContext.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Jan 20, 2022 +\brief Contains the definitions of the managed DisposableAssemblyLoadContext + class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +namespace SHADE +{ + /// + /// Custom AssemblyLoadContext marked as collectible so that it can be unloaded. + /// + private ref class DisposableAssemblyLoadContext : public System::Runtime::Loader::AssemblyLoadContext + { + public: + /*-----------------------------------------------------------------------------*/ + /* Constructor */ + /*-----------------------------------------------------------------------------*/ + /// + /// Default Constructor + /// + DisposableAssemblyLoadContext(); + + protected: + /*-----------------------------------------------------------------------------*/ + /* Helper Functions */ + /*-----------------------------------------------------------------------------*/ + System::Reflection::Assembly^ Load(System::Reflection::AssemblyName^ assemblyName) override; + }; +} // namespace PlushieAPI \ No newline at end of file diff --git a/premake5.lua b/premake5.lua index d54f8e40..450be7d7 100644 --- a/premake5.lua +++ b/premake5.lua @@ -14,16 +14,17 @@ workspace "SHADE" { "MultiProcessorCompile" } - - outputdir = "%{cfg.buildcfg}_%{cfg.architecture}" - include "SHADE_Application" + outputdir = "%{wks.location}/bin/%{cfg.buildcfg}" + interdir = "%{wks.location}/bin_int" + include "SHADE_Engine" + include "SHADE_Application" + include "SHADE_Managed" group "Dependencies" include "Dependencies/msdf" include "Dependencies/imgui" - include "Dependencies/spdlog" --include "Dependencies/tracy" include "Dependencies/yamlcpp" include "Dependencies/reactphysics3d"