diff --git a/Assets/Cube.003.shmesh.shmeta b/Assets/Cube.003.shmesh.shmeta index 207f3999..628ecd00 100644 --- a/Assets/Cube.003.shmesh.shmeta +++ b/Assets/Cube.003.shmesh.shmeta @@ -1,3 +1,3 @@ -Name: Cube.003 -ID: 110152941 -Type: 6 +Name: Cube.003 +ID: 71245919 +Type: 4 diff --git a/Assets/Cube.012.shmesh.shmeta b/Assets/Cube.012.shmesh.shmeta index 3af04f93..56d2d0f5 100644 --- a/Assets/Cube.012.shmesh.shmeta +++ b/Assets/Cube.012.shmesh.shmeta @@ -1,3 +1,3 @@ -Name: Cube.012 -ID: 107348815 -Type: 6 +Name: Cube.012 +ID: 80365422 +Type: 4 diff --git a/Assets/RaccoonBag_Color_Ver4.shtex b/Assets/RaccoonBag_Color_Ver4.shtex new file mode 100644 index 00000000..effba95a Binary files /dev/null and b/Assets/RaccoonBag_Color_Ver4.shtex differ diff --git a/Assets/RaccoonBag_Color_Ver4.shtex.shmeta b/Assets/RaccoonBag_Color_Ver4.shtex.shmeta new file mode 100644 index 00000000..d386e9a4 --- /dev/null +++ b/Assets/RaccoonBag_Color_Ver4.shtex.shmeta @@ -0,0 +1,3 @@ +Name: RaccoonBag_Color_Ver4 +ID: 58303057 +Type: 3 diff --git a/Assets/RaccoonPreTexturedVer1_Base9.shtex.shmeta b/Assets/RaccoonPreTexturedVer1_Base9.shtex.shmeta index 3905aa4f..e1a72340 100644 --- a/Assets/RaccoonPreTexturedVer1_Base9.shtex.shmeta +++ b/Assets/RaccoonPreTexturedVer1_Base9.shtex.shmeta @@ -1,3 +1,3 @@ -Name: RaccoonPreTexturedVer1_Base9 -ID: 91918845 -Type: 4 +Name: RaccoonPreTexturedVer1_Base9 +ID: 64651793 +Type: 3 diff --git a/TempShaderFolder/KirschCs.glsl b/Assets/Shaders/Kirsch_CS.glsl similarity index 100% rename from TempShaderFolder/KirschCs.glsl rename to Assets/Shaders/Kirsch_CS.glsl diff --git a/TempShaderFolder/KirschCs.spv b/Assets/Shaders/Kirsch_CS.shshaderb similarity index 99% rename from TempShaderFolder/KirschCs.spv rename to Assets/Shaders/Kirsch_CS.shshaderb index 1ae5408b..6219d9a9 100644 Binary files a/TempShaderFolder/KirschCs.spv and b/Assets/Shaders/Kirsch_CS.shshaderb differ diff --git a/Assets/Shaders/Kirsch_CS.shshaderb.shmeta b/Assets/Shaders/Kirsch_CS.shshaderb.shmeta new file mode 100644 index 00000000..61c735f3 --- /dev/null +++ b/Assets/Shaders/Kirsch_CS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: Kirsch_CS +ID: 19931255 +Type: 2 diff --git a/TempShaderFolder/PureCopyCs.glsl b/Assets/Shaders/PureCopy_CS.glsl similarity index 100% rename from TempShaderFolder/PureCopyCs.glsl rename to Assets/Shaders/PureCopy_CS.glsl diff --git a/TempShaderFolder/PureCopyCs.spv b/Assets/Shaders/PureCopy_CS.shshaderb similarity index 94% rename from TempShaderFolder/PureCopyCs.spv rename to Assets/Shaders/PureCopy_CS.shshaderb index bf967bbf..9f1b0534 100644 Binary files a/TempShaderFolder/PureCopyCs.spv and b/Assets/Shaders/PureCopy_CS.shshaderb differ diff --git a/Assets/Shaders/PureCopy_CS.shshaderb.shmeta b/Assets/Shaders/PureCopy_CS.shshaderb.shmeta new file mode 100644 index 00000000..8cb091d7 --- /dev/null +++ b/Assets/Shaders/PureCopy_CS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: PureCopy_CS +ID: 29659779 +Type: 2 diff --git a/TempShaderFolder/TestCubeFs.glsl b/Assets/Shaders/TestCube_FS.glsl similarity index 100% rename from TempShaderFolder/TestCubeFs.glsl rename to Assets/Shaders/TestCube_FS.glsl diff --git a/TempShaderFolder/TestCubeFs.spv b/Assets/Shaders/TestCube_FS.shshaderb similarity index 97% rename from TempShaderFolder/TestCubeFs.spv rename to Assets/Shaders/TestCube_FS.shshaderb index 9955abe5..863287f6 100644 Binary files a/TempShaderFolder/TestCubeFs.spv and b/Assets/Shaders/TestCube_FS.shshaderb differ diff --git a/Assets/Shaders/TestCube_FS.shshaderb.shmeta b/Assets/Shaders/TestCube_FS.shshaderb.shmeta new file mode 100644 index 00000000..3a647313 --- /dev/null +++ b/Assets/Shaders/TestCube_FS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: TestCube_FS +ID: 18415057 +Type: 2 diff --git a/TempShaderFolder/TestCubeVs.glsl b/Assets/Shaders/TestCube_VS.glsl similarity index 100% rename from TempShaderFolder/TestCubeVs.glsl rename to Assets/Shaders/TestCube_VS.glsl diff --git a/TempShaderFolder/TestCubeVs.spv b/Assets/Shaders/TestCube_VS.shshaderb similarity index 96% rename from TempShaderFolder/TestCubeVs.spv rename to Assets/Shaders/TestCube_VS.shshaderb index 731e31d1..3d12507b 100644 Binary files a/TempShaderFolder/TestCubeVs.spv and b/Assets/Shaders/TestCube_VS.shshaderb differ diff --git a/Assets/Shaders/TestCube_VS.shshaderb.shmeta b/Assets/Shaders/TestCube_VS.shshaderb.shmeta new file mode 100644 index 00000000..23c5e30d --- /dev/null +++ b/Assets/Shaders/TestCube_VS.shshaderb.shmeta @@ -0,0 +1,3 @@ +Name: TestCube_VS +ID: 29315909 +Type: 2 diff --git a/Assets/TD_Checker_Base_Color.shtex b/Assets/TD_Checker_Base_Color.shtex new file mode 100644 index 00000000..c99ff515 Binary files /dev/null and b/Assets/TD_Checker_Base_Color.shtex differ diff --git a/Assets/TD_Checker_Base_Color.shtex.shmeta b/Assets/TD_Checker_Base_Color.shtex.shmeta new file mode 100644 index 00000000..8c0d5b77 --- /dev/null +++ b/Assets/TD_Checker_Base_Color.shtex.shmeta @@ -0,0 +1,3 @@ +Name: TD_Checker_Base_Color +ID: 51995224 +Type: 3 diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index c6750707..24d0ca00 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -110,14 +110,7 @@ namespace Sandbox SHComponentManager::CreateComponentSparseSet(); SHComponentManager::CreateComponentSparseSet(); - //TODO: REMOVE AFTER PRESENTATION - //SHAssetManager::LoadDataTemp("../../Assets/racoon.gltf"); - //SHAssetManager::LoadDataTemp("../../Assets/Cube.012.shmesh"); - //SHAssetManager::LoadDataTemp("../../Assets/RaccoonBag_Color_Ver4.dds"); - //SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.dds"); - //SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.shtex"); - //TODO: REMOVE AFTER PRESENTATION - + SHAssetManager::Load(); auto id = SHFamilyID::GetID(); auto id2 = SHFamilyID::GetID(); @@ -133,8 +126,6 @@ namespace Sandbox SHSceneManager::InitSceneManager("TestScene"); SHFrameRateController::UpdateFRC(); - - SHAssetManager::Load(); } void SBApplication::Update(void) diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index a06e68c2..4cdac9dc 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -53,7 +53,8 @@ namespace Sandbox if (asset.name == "Cube.012") handles.emplace_back(SHResourceManager::LoadOrGet(asset.id)); break; - case AssetType::IMAGE: + case AssetType::TEXTURE: + if (asset.name == "RaccoonPreTexturedVer1_Base9") texHandles.emplace_back(SHResourceManager::LoadOrGet(asset.id)); break; } @@ -83,7 +84,7 @@ namespace Sandbox auto& collider = *SHComponentManager::GetComponent_s(entity); //renderable.Mesh = handles.front(); - renderable.Mesh = CUBE_MESH; + renderable.SetMesh(CUBE_MESH); renderable.SetMaterial(customMat); if (y == 50) @@ -95,11 +96,7 @@ namespace Sandbox transform.SetWorldRotation(SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f)); transform.SetWorldScale(TEST_OBJ_SCALE); - //if (const bool IS_EVEN = (y * NUM_ROWS + x) % 2; IS_EVEN) - collider.AddBoundingBox(SHVec3::One * 0.5f, SHVec3::Zero); - //else - // collider.AddBoundingSphere(0.5f, SHVec3::Zero); - + collider.AddBoundingBox(SHVec3::One, SHVec3::Zero); stressTestObjects.emplace_back(entity); } @@ -107,7 +104,7 @@ namespace Sandbox auto& renderable = *SHComponentManager::GetComponent_s(raccoonSpin); auto& transform = *SHComponentManager::GetComponent_s(raccoonSpin); - renderable.Mesh = handles.front(); + renderable.SetMesh(handles.front()); renderable.SetMaterial(customMat); renderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f)); renderable.GetModifiableMaterial()->SetProperty("data.alpha", 1.0f); @@ -122,9 +119,8 @@ namespace Sandbox auto& floorRigidBody = *SHComponentManager::GetComponent_s(floor); auto& floorCollider = *SHComponentManager::GetComponent_s(floor); - floorRenderable.Mesh = CUBE_MESH; - floorRenderable.SetMaterial(customMat); - floorRenderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(1.0f, 1.0f, 1.0f, 1.0f)); + floorRenderable.SetMesh(CUBE_MESH); + floorRenderable.SetMaterial(graphicsSystem->GetDefaultMaterialInstance()); floorTransform.SetWorldScale({ 7.5f, 0.5f, 7.5 }); floorTransform.SetWorldPosition({ 0.0f, -3.0f, -5.0f }); @@ -148,7 +144,7 @@ namespace Sandbox auto& renderableShowcase = *SHComponentManager::GetComponent_s(raccoonShowcase); auto& transformShowcase = *SHComponentManager::GetComponent_s(raccoonShowcase); - renderableShowcase.Mesh = handles.front(); + renderableShowcase.SetMesh(handles.front()); renderableShowcase.SetMaterial(customMat); renderableShowcase.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f)); renderableShowcase.GetModifiableMaterial()->SetProperty("data.alpha", 1.0f); diff --git a/SHADE_CSharp/premake5.lua b/SHADE_CSharp/premake5.lua new file mode 100644 index 00000000..2d6c1edb --- /dev/null +++ b/SHADE_CSharp/premake5.lua @@ -0,0 +1,52 @@ +project "SHADE_CSharp" + architecture "x64" + kind "SharedLib" + language "C#" + clr "NetCore" + dotnetframework "net5.0" + namespace ("SHADE") + targetdir (outputdir) + objdir (interdir) + systemversion "latest" + + files + { + "%{prj.location}/src/**.cs", + "%{prj.location}/src/**.tt" + } + + flags + { + "MultiProcessorCompile" + } + + dependson + { + "SHADE_Engine" + } + + warnings 'Extra' + + filter "configurations:Debug" + symbols "On" + defines {"_DEBUG"} + + filter "configurations:Release" + optimize "On" + defines{"_RELEASE"} + + filter "configurations:Publish" + optimize "On" + defines{"_RELEASE"} + + require "vstudio" + + function platformsElement(cfg) + _p(2,'x64') + end + + premake.override(premake.vstudio.cs2005.elements, "projectProperties", function (oldfn, cfg) + return table.join(oldfn(cfg), { + platformsElement, + }) + end) \ No newline at end of file diff --git a/SHADE_CSharp/src/Events/CallbackAction.cs b/SHADE_CSharp/src/Events/CallbackAction.cs new file mode 100644 index 00000000..968302ed --- /dev/null +++ b/SHADE_CSharp/src/Events/CallbackAction.cs @@ -0,0 +1,852 @@ +/************************************************************************************//*! +\file CallbackAction.cs +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 23, 2022 +\brief Contains the definition of CallbackAction and related classes. + +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. +*//*************************************************************************************/ +using System; +using System.Reflection; + +namespace SHADE +{ + /// + /// Interface for a CallbackAction that all variants inherit from. + /// + public interface ICallbackAction + { + /// + /// Whether or not this CallbackAction is runtime assigned. If it is, then the + /// TargetMethodName and TargetObject properties are invalid. + /// + bool IsRuntimeAction { get; } + /// + /// Name of the method that this CallbackAction is using. + /// + string TargetMethodName { get; } + /// + /// Object which the specified target method is called on. + /// + Object TargetObject { get; } + } + + /// + /// Represents a function call that can be serialised and put togetheer with scripts. + /// This variant accepts functions with 1 parameter. + /// + public class CallbackAction : ICallbackAction + { + #region Properties ------------------------------------------------------------ + /// + public Object TargetObject { get; private set; } + /// + public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name; + /// + public bool IsRuntimeAction => targetAction != null; + #endregion + + #region Fields ------------------------------------------------------------------ + private MethodInfo targetMethod; + private Action targetAction; + private Object[] parameters; + #endregion + + #region Constructors ------------------------------------------------------------ + /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// + /// Constructs a CallbackAction that represents a call to the specified method on the + /// specified target. + /// + /// Object to call the method on. + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(Object target, MethodInfo method) + { + // Error Checks + if (method.DeclaringType != target.GetType()) + throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method."); + + // No errors, assign + TargetObject = target; + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[1]; + } + /// + /// Constructs a Callback action based on an action. + /// + /// + public CallbackAction(Action action) + { + targetAction = action; + } + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + /// Invokes the CallbackAction's stored method/action with the specified parameters. + /// + public void Invoke(T1 t1) + { + if (targetAction != null) + { + targetAction.Invoke(t1); + } + else if (TargetObject != null && targetMethod != null) + { + parameters[0] = t1; + _ = targetMethod.Invoke(TargetObject, parameters); + } + } + #endregion + } + /// + /// Represents a function call that can be serialised and put togetheer with scripts. + /// This variant accepts functions with 2 parameters. + /// + public class CallbackAction : ICallbackAction + { + #region Properties ------------------------------------------------------------ + /// + public Object TargetObject { get; private set; } + /// + public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name; + /// + public bool IsRuntimeAction => targetAction != null; + #endregion + + #region Fields ------------------------------------------------------------------ + private MethodInfo targetMethod; + private Action targetAction; + private Object[] parameters; + #endregion + + #region Constructors ------------------------------------------------------------ + /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// + /// Constructs a CallbackAction that represents a call to the specified method on the + /// specified target. + /// + /// Object to call the method on. + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(Object target, MethodInfo method) + { + // Error Checks + if (method.DeclaringType != target.GetType()) + throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method."); + + // No errors, assign + TargetObject = target; + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[1]; + } + /// + /// Constructs a Callback action based on an action. + /// + /// + public CallbackAction(Action action) + { + targetAction = action; + } + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + /// Invokes the CallbackAction's stored method/action with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2) + { + if (targetAction != null) + { + targetAction.Invoke(t1, t2); + } + else if (TargetObject != null && targetMethod != null) + { + parameters[0] = t1; + parameters[1] = t2; + _ = targetMethod.Invoke(TargetObject, parameters); + } + } + #endregion + } + /// + /// Represents a function call that can be serialised and put togetheer with scripts. + /// This variant accepts functions with 3 parameters. + /// + public class CallbackAction : ICallbackAction + { + #region Properties ------------------------------------------------------------ + /// + public Object TargetObject { get; private set; } + /// + public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name; + /// + public bool IsRuntimeAction => targetAction != null; + #endregion + + #region Fields ------------------------------------------------------------------ + private MethodInfo targetMethod; + private Action targetAction; + private Object[] parameters; + #endregion + + #region Constructors ------------------------------------------------------------ + /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// + /// Constructs a CallbackAction that represents a call to the specified method on the + /// specified target. + /// + /// Object to call the method on. + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(Object target, MethodInfo method) + { + // Error Checks + if (method.DeclaringType != target.GetType()) + throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method."); + + // No errors, assign + TargetObject = target; + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[1]; + } + /// + /// Constructs a Callback action based on an action. + /// + /// + public CallbackAction(Action action) + { + targetAction = action; + } + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + /// Invokes the CallbackAction's stored method/action with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2, T3 t3) + { + if (targetAction != null) + { + targetAction.Invoke(t1, t2, t3); + } + else if (TargetObject != null && targetMethod != null) + { + parameters[0] = t1; + parameters[1] = t2; + parameters[2] = t3; + _ = targetMethod.Invoke(TargetObject, parameters); + } + } + #endregion + } + /// + /// Represents a function call that can be serialised and put togetheer with scripts. + /// This variant accepts functions with 4 parameters. + /// + public class CallbackAction : ICallbackAction + { + #region Properties ------------------------------------------------------------ + /// + public Object TargetObject { get; private set; } + /// + public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name; + /// + public bool IsRuntimeAction => targetAction != null; + #endregion + + #region Fields ------------------------------------------------------------------ + private MethodInfo targetMethod; + private Action targetAction; + private Object[] parameters; + #endregion + + #region Constructors ------------------------------------------------------------ + /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// + /// Constructs a CallbackAction that represents a call to the specified method on the + /// specified target. + /// + /// Object to call the method on. + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(Object target, MethodInfo method) + { + // Error Checks + if (method.DeclaringType != target.GetType()) + throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method."); + + // No errors, assign + TargetObject = target; + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[1]; + } + /// + /// Constructs a Callback action based on an action. + /// + /// + public CallbackAction(Action action) + { + targetAction = action; + } + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + /// Invokes the CallbackAction's stored method/action with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4) + { + if (targetAction != null) + { + targetAction.Invoke(t1, t2, t3, t4); + } + else if (TargetObject != null && targetMethod != null) + { + parameters[0] = t1; + parameters[1] = t2; + parameters[2] = t3; + parameters[3] = t4; + _ = targetMethod.Invoke(TargetObject, parameters); + } + } + #endregion + } + /// + /// Represents a function call that can be serialised and put togetheer with scripts. + /// This variant accepts functions with 5 parameters. + /// + public class CallbackAction : ICallbackAction + { + #region Properties ------------------------------------------------------------ + /// + public Object TargetObject { get; private set; } + /// + public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name; + /// + public bool IsRuntimeAction => targetAction != null; + #endregion + + #region Fields ------------------------------------------------------------------ + private MethodInfo targetMethod; + private Action targetAction; + private Object[] parameters; + #endregion + + #region Constructors ------------------------------------------------------------ + /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// + /// Constructs a CallbackAction that represents a call to the specified method on the + /// specified target. + /// + /// Object to call the method on. + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(Object target, MethodInfo method) + { + // Error Checks + if (method.DeclaringType != target.GetType()) + throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method."); + + // No errors, assign + TargetObject = target; + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[1]; + } + /// + /// Constructs a Callback action based on an action. + /// + /// + public CallbackAction(Action action) + { + targetAction = action; + } + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + /// Invokes the CallbackAction's stored method/action with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + { + if (targetAction != null) + { + targetAction.Invoke(t1, t2, t3, t4, t5); + } + else if (TargetObject != null && targetMethod != null) + { + parameters[0] = t1; + parameters[1] = t2; + parameters[2] = t3; + parameters[3] = t4; + parameters[4] = t5; + _ = targetMethod.Invoke(TargetObject, parameters); + } + } + #endregion + } + /// + /// Represents a function call that can be serialised and put togetheer with scripts. + /// This variant accepts functions with 6 parameters. + /// + public class CallbackAction : ICallbackAction + { + #region Properties ------------------------------------------------------------ + /// + public Object TargetObject { get; private set; } + /// + public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name; + /// + public bool IsRuntimeAction => targetAction != null; + #endregion + + #region Fields ------------------------------------------------------------------ + private MethodInfo targetMethod; + private Action targetAction; + private Object[] parameters; + #endregion + + #region Constructors ------------------------------------------------------------ + /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// + /// Constructs a CallbackAction that represents a call to the specified method on the + /// specified target. + /// + /// Object to call the method on. + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(Object target, MethodInfo method) + { + // Error Checks + if (method.DeclaringType != target.GetType()) + throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method."); + + // No errors, assign + TargetObject = target; + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[1]; + } + /// + /// Constructs a Callback action based on an action. + /// + /// + public CallbackAction(Action action) + { + targetAction = action; + } + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + /// Invokes the CallbackAction's stored method/action with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) + { + if (targetAction != null) + { + targetAction.Invoke(t1, t2, t3, t4, t5, t6); + } + else if (TargetObject != null && targetMethod != null) + { + parameters[0] = t1; + parameters[1] = t2; + parameters[2] = t3; + parameters[3] = t4; + parameters[4] = t5; + parameters[5] = t6; + _ = targetMethod.Invoke(TargetObject, parameters); + } + } + #endregion + } + /// + /// Represents a function call that can be serialised and put togetheer with scripts. + /// This variant accepts functions with 7 parameters. + /// + public class CallbackAction : ICallbackAction + { + #region Properties ------------------------------------------------------------ + /// + public Object TargetObject { get; private set; } + /// + public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name; + /// + public bool IsRuntimeAction => targetAction != null; + #endregion + + #region Fields ------------------------------------------------------------------ + private MethodInfo targetMethod; + private Action targetAction; + private Object[] parameters; + #endregion + + #region Constructors ------------------------------------------------------------ + /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// + /// Constructs a CallbackAction that represents a call to the specified method on the + /// specified target. + /// + /// Object to call the method on. + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(Object target, MethodInfo method) + { + // Error Checks + if (method.DeclaringType != target.GetType()) + throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method."); + + // No errors, assign + TargetObject = target; + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[1]; + } + /// + /// Constructs a Callback action based on an action. + /// + /// + public CallbackAction(Action action) + { + targetAction = action; + } + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + /// Invokes the CallbackAction's stored method/action with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) + { + if (targetAction != null) + { + targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7); + } + else if (TargetObject != null && targetMethod != null) + { + parameters[0] = t1; + parameters[1] = t2; + parameters[2] = t3; + parameters[3] = t4; + parameters[4] = t5; + parameters[5] = t6; + parameters[6] = t7; + _ = targetMethod.Invoke(TargetObject, parameters); + } + } + #endregion + } + /// + /// Represents a function call that can be serialised and put togetheer with scripts. + /// This variant accepts functions with 8 parameters. + /// + public class CallbackAction : ICallbackAction + { + #region Properties ------------------------------------------------------------ + /// + public Object TargetObject { get; private set; } + /// + public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name; + /// + public bool IsRuntimeAction => targetAction != null; + #endregion + + #region Fields ------------------------------------------------------------------ + private MethodInfo targetMethod; + private Action targetAction; + private Object[] parameters; + #endregion + + #region Constructors ------------------------------------------------------------ + /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// + /// Constructs a CallbackAction that represents a call to the specified method on the + /// specified target. + /// + /// Object to call the method on. + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(Object target, MethodInfo method) + { + // Error Checks + if (method.DeclaringType != target.GetType()) + throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method."); + + // No errors, assign + TargetObject = target; + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[1]; + } + /// + /// Constructs a Callback action based on an action. + /// + /// + public CallbackAction(Action action) + { + targetAction = action; + } + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + /// Invokes the CallbackAction's stored method/action with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) + { + if (targetAction != null) + { + targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8); + } + else if (TargetObject != null && targetMethod != null) + { + parameters[0] = t1; + parameters[1] = t2; + parameters[2] = t3; + parameters[3] = t4; + parameters[4] = t5; + parameters[5] = t6; + parameters[6] = t7; + parameters[7] = t8; + _ = targetMethod.Invoke(TargetObject, parameters); + } + } + #endregion + } + /// + /// Represents a function call that can be serialised and put togetheer with scripts. + /// This variant accepts functions with 9 parameters. + /// + public class CallbackAction : ICallbackAction + { + #region Properties ------------------------------------------------------------ + /// + public Object TargetObject { get; private set; } + /// + public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name; + /// + public bool IsRuntimeAction => targetAction != null; + #endregion + + #region Fields ------------------------------------------------------------------ + private MethodInfo targetMethod; + private Action targetAction; + private Object[] parameters; + #endregion + + #region Constructors ------------------------------------------------------------ + /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// + /// Constructs a CallbackAction that represents a call to the specified method on the + /// specified target. + /// + /// Object to call the method on. + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(Object target, MethodInfo method) + { + // Error Checks + if (method.DeclaringType != target.GetType()) + throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method."); + + // No errors, assign + TargetObject = target; + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[1]; + } + /// + /// Constructs a Callback action based on an action. + /// + /// + public CallbackAction(Action action) + { + targetAction = action; + } + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + /// Invokes the CallbackAction's stored method/action with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) + { + if (targetAction != null) + { + targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9); + } + else if (TargetObject != null && targetMethod != null) + { + parameters[0] = t1; + parameters[1] = t2; + parameters[2] = t3; + parameters[3] = t4; + parameters[4] = t5; + parameters[5] = t6; + parameters[6] = t7; + parameters[7] = t8; + parameters[8] = t9; + _ = targetMethod.Invoke(TargetObject, parameters); + } + } + #endregion + } + /// + /// Represents a function call that can be serialised and put togetheer with scripts. + /// This variant accepts functions with 10 parameters. + /// + public class CallbackAction : ICallbackAction + { + #region Properties ------------------------------------------------------------ + /// + public Object TargetObject { get; private set; } + /// + public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name; + /// + public bool IsRuntimeAction => targetAction != null; + #endregion + + #region Fields ------------------------------------------------------------------ + private MethodInfo targetMethod; + private Action targetAction; + private Object[] parameters; + #endregion + + #region Constructors ------------------------------------------------------------ + /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// + /// Constructs a CallbackAction that represents a call to the specified method on the + /// specified target. + /// + /// Object to call the method on. + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(Object target, MethodInfo method) + { + // Error Checks + if (method.DeclaringType != target.GetType()) + throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method."); + + // No errors, assign + TargetObject = target; + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[1]; + } + /// + /// Constructs a Callback action based on an action. + /// + /// + public CallbackAction(Action action) + { + targetAction = action; + } + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + /// Invokes the CallbackAction's stored method/action with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10) + { + if (targetAction != null) + { + targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); + } + else if (TargetObject != null && targetMethod != null) + { + parameters[0] = t1; + parameters[1] = t2; + parameters[2] = t3; + parameters[3] = t4; + parameters[4] = t5; + parameters[5] = t6; + parameters[6] = t7; + parameters[7] = t8; + parameters[8] = t9; + parameters[9] = t10; + _ = targetMethod.Invoke(TargetObject, parameters); + } + } + #endregion + } +} diff --git a/SHADE_CSharp/src/Events/CallbackAction.tt b/SHADE_CSharp/src/Events/CallbackAction.tt new file mode 100644 index 00000000..fffd4251 --- /dev/null +++ b/SHADE_CSharp/src/Events/CallbackAction.tt @@ -0,0 +1,132 @@ +<# +/************************************************************************************//*! +\file CallbackAction.tt +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 23, 2022 +\brief Contains the T4 template for the definition of CallbackAction and + related classes. + +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. +*//*************************************************************************************/#> +<#@ template hostspecific="false" language="C#" #> +<#@ output extension=".cs" #> +<# var max = 10; #> +/************************************************************************************//*! +\file CallbackAction.cs +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 23, 2022 +\brief Contains the definition of CallbackAction and related classes. + +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. +*//*************************************************************************************/ +using System; +using System.Reflection; + +namespace SHADE +{ + /// + /// Interface for a CallbackAction that all variants inherit from. + /// + public interface ICallbackAction + { + /// + /// Whether or not this CallbackAction is runtime assigned. If it is, then the + /// TargetMethodName and TargetObject properties are invalid. + /// + bool IsRuntimeAction { get; } + /// + /// Name of the method that this CallbackAction is using. + /// + string TargetMethodName { get; } + /// + /// Object which the specified target method is called on. + /// + Object TargetObject { get; } + } + +<# for (int i = 1; i <= max; ++i) { #> + /// + /// Represents a function call that can be serialised and put togetheer with scripts. + /// This variant accepts functions with <#=i#> parameter<# if (i > 1) {#>s<#} #>. + /// + public class CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> : ICallbackAction + { + #region Properties ------------------------------------------------------------ + /// + public Object TargetObject { get; private set; } + /// + public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name; + /// + public bool IsRuntimeAction => targetAction != null; + #endregion + + #region Fields ------------------------------------------------------------------ + private MethodInfo targetMethod; + private Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> targetAction; + private Object[] parameters; + #endregion + + #region Constructors ------------------------------------------------------------ + /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// + /// Constructs a CallbackAction that represents a call to the specified method on the + /// specified target. + /// + /// Object to call the method on. + /// Method to call. + /// + /// Thrown if a method that is not compatible with the target is specified. The method's + /// source type must match the target's type. + /// + public CallbackAction(Object target, MethodInfo method) + { + // Error Checks + if (method.DeclaringType != target.GetType()) + throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method."); + + // No errors, assign + TargetObject = target; + targetMethod = method; + + // Create storage for parameters for calling + parameters = new Object[1]; + } + /// + /// Constructs a Callback action based on an action. + /// + /// + public CallbackAction(Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action) + { + targetAction = action; + } + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + /// Invokes the CallbackAction's stored method/action with the specified parameters. + /// + public void Invoke(<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#> t<#=t#><# if (t != i) { #>, <# } #><# } #>) + { + if (targetAction != null) + { + targetAction.Invoke(<# for (int t = 1; t < i + 1; ++t) { #>t<#=t#><# if (t != i) { #>, <# } #><# } #>); + } + else if (TargetObject != null && targetMethod != null) + { + <# for (int t = 0; t < i; ++t) {#>parameters[<#=t#>] = t<#=t+1#>; + <# } #>_ = targetMethod.Invoke(TargetObject, parameters); + } + } + #endregion + } +<# } #> +} diff --git a/SHADE_CSharp/src/Events/CallbackEvent.cs b/SHADE_CSharp/src/Events/CallbackEvent.cs new file mode 100644 index 00000000..ec464ba9 --- /dev/null +++ b/SHADE_CSharp/src/Events/CallbackEvent.cs @@ -0,0 +1,908 @@ +/************************************************************************************//*! +\file CallbackEvent.cs +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 23, 2022 +\brief Contains the definition of CallbackEvent and related classes. + +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. +*//*************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Reflection.Metadata.Ecma335; + +namespace SHADE +{ + /// + /// Interface for a CallbackEvent that all variants inherit from. + /// + public interface ICallbackEvent + { + /// + /// Registers an empty ICallbackAction. + /// + void RegisterAction(); + /// + /// Registers an ICallbackAction with the event such that it will be called in + /// future + /// + /// ICallbackAction to register with. + void RegisterAction(ICallbackAction action); + /// + /// Deregisters an ICallbackAction that was previously added. This should + /// only emit a warning if an action that was not previous added was + /// provided. + /// + /// ICallbackAction to remove. + void DeregisterAction(ICallbackAction action); + /// + /// Iterable set of ICallbackActions that were registered to this event. + /// + IEnumerable Actions { get; } + } + + /// + /// A container of CallbackActions that is correlated to a specific scenario as + /// specified by the user of this class. + /// This variant accepts CallbackEvents with 1 generic parameter. + /// + public class CallbackEvent : ICallbackEvent + { + #region Properties -------------------------------------------------------------- + /// + public IEnumerable Actions => actions; + #endregion + + #region Fields ------------------------------------------------------------------ + private List actions = new List(); + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// + public void RegisterAction(ICallbackAction action) + { + // Check if valid action + if (action.GetType() != typeof(CallbackAction)) + { + Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this); + return; + } + + actions.Add(action); + } + /// + /// Adds a CallbackAction into the event. + /// + /// CallbackAction to add. + public void RegisterAction(CallbackAction action) + { + actions.Add(action); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// System.Action to add as a CallbackAction. + public void RegisterAction(Action action) + { + actions.Add(new CallbackAction(action)); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// Object to call the method on. + /// Method to call. + public void RegisterAction(Object target, MethodInfo method) + { + actions.Add(new CallbackAction(target, method)); + } + /// + public void DeregisterAction(ICallbackAction action) + { + if (!actions.Remove(action)) + { + Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this); + } + } + /// + /// Invokes all stored CallbackActions with the specified parameters. + /// + public void Invoke(T1 t1) + { + foreach (CallbackAction action in actions) + { + try + { + action.Invoke(t1); + } + catch (Exception e) + { + Debug.LogException(e, this); + } + } + } + #endregion + } + /// + /// A container of CallbackActions that is correlated to a specific scenario as + /// specified by the user of this class. + /// This variant accepts CallbackEvents with 1 generic parameter. + /// + public class CallbackEvent : ICallbackEvent + { + #region Properties -------------------------------------------------------------- + /// + public IEnumerable Actions => actions; + #endregion + + #region Fields ------------------------------------------------------------------ + private List actions = new List(); + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// + public void RegisterAction(ICallbackAction action) + { + // Check if valid action + if (action.GetType() != typeof(CallbackAction)) + { + Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this); + return; + } + + actions.Add(action); + } + /// + /// Adds a CallbackAction into the event. + /// + /// CallbackAction to add. + public void RegisterAction(CallbackAction action) + { + actions.Add(action); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// System.Action to add as a CallbackAction. + public void RegisterAction(Action action) + { + actions.Add(new CallbackAction(action)); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// Object to call the method on. + /// Method to call. + public void RegisterAction(Object target, MethodInfo method) + { + actions.Add(new CallbackAction(target, method)); + } + /// + public void DeregisterAction(ICallbackAction action) + { + if (!actions.Remove(action)) + { + Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this); + } + } + /// + /// Invokes all stored CallbackActions with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2) + { + foreach (CallbackAction action in actions) + { + try + { + action.Invoke(t1, t2); + } + catch (Exception e) + { + Debug.LogException(e, this); + } + } + } + #endregion + } + /// + /// A container of CallbackActions that is correlated to a specific scenario as + /// specified by the user of this class. + /// This variant accepts CallbackEvents with 1 generic parameter. + /// + public class CallbackEvent : ICallbackEvent + { + #region Properties -------------------------------------------------------------- + /// + public IEnumerable Actions => actions; + #endregion + + #region Fields ------------------------------------------------------------------ + private List actions = new List(); + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// + public void RegisterAction(ICallbackAction action) + { + // Check if valid action + if (action.GetType() != typeof(CallbackAction)) + { + Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this); + return; + } + + actions.Add(action); + } + /// + /// Adds a CallbackAction into the event. + /// + /// CallbackAction to add. + public void RegisterAction(CallbackAction action) + { + actions.Add(action); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// System.Action to add as a CallbackAction. + public void RegisterAction(Action action) + { + actions.Add(new CallbackAction(action)); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// Object to call the method on. + /// Method to call. + public void RegisterAction(Object target, MethodInfo method) + { + actions.Add(new CallbackAction(target, method)); + } + /// + public void DeregisterAction(ICallbackAction action) + { + if (!actions.Remove(action)) + { + Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this); + } + } + /// + /// Invokes all stored CallbackActions with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2, T3 t3) + { + foreach (CallbackAction action in actions) + { + try + { + action.Invoke(t1, t2, t3); + } + catch (Exception e) + { + Debug.LogException(e, this); + } + } + } + #endregion + } + /// + /// A container of CallbackActions that is correlated to a specific scenario as + /// specified by the user of this class. + /// This variant accepts CallbackEvents with 1 generic parameter. + /// + public class CallbackEvent : ICallbackEvent + { + #region Properties -------------------------------------------------------------- + /// + public IEnumerable Actions => actions; + #endregion + + #region Fields ------------------------------------------------------------------ + private List actions = new List(); + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// + public void RegisterAction(ICallbackAction action) + { + // Check if valid action + if (action.GetType() != typeof(CallbackAction)) + { + Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this); + return; + } + + actions.Add(action); + } + /// + /// Adds a CallbackAction into the event. + /// + /// CallbackAction to add. + public void RegisterAction(CallbackAction action) + { + actions.Add(action); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// System.Action to add as a CallbackAction. + public void RegisterAction(Action action) + { + actions.Add(new CallbackAction(action)); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// Object to call the method on. + /// Method to call. + public void RegisterAction(Object target, MethodInfo method) + { + actions.Add(new CallbackAction(target, method)); + } + /// + public void DeregisterAction(ICallbackAction action) + { + if (!actions.Remove(action)) + { + Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this); + } + } + /// + /// Invokes all stored CallbackActions with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4) + { + foreach (CallbackAction action in actions) + { + try + { + action.Invoke(t1, t2, t3, t4); + } + catch (Exception e) + { + Debug.LogException(e, this); + } + } + } + #endregion + } + /// + /// A container of CallbackActions that is correlated to a specific scenario as + /// specified by the user of this class. + /// This variant accepts CallbackEvents with 1 generic parameter. + /// + public class CallbackEvent : ICallbackEvent + { + #region Properties -------------------------------------------------------------- + /// + public IEnumerable Actions => actions; + #endregion + + #region Fields ------------------------------------------------------------------ + private List actions = new List(); + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// + public void RegisterAction(ICallbackAction action) + { + // Check if valid action + if (action.GetType() != typeof(CallbackAction)) + { + Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this); + return; + } + + actions.Add(action); + } + /// + /// Adds a CallbackAction into the event. + /// + /// CallbackAction to add. + public void RegisterAction(CallbackAction action) + { + actions.Add(action); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// System.Action to add as a CallbackAction. + public void RegisterAction(Action action) + { + actions.Add(new CallbackAction(action)); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// Object to call the method on. + /// Method to call. + public void RegisterAction(Object target, MethodInfo method) + { + actions.Add(new CallbackAction(target, method)); + } + /// + public void DeregisterAction(ICallbackAction action) + { + if (!actions.Remove(action)) + { + Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this); + } + } + /// + /// Invokes all stored CallbackActions with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + { + foreach (CallbackAction action in actions) + { + try + { + action.Invoke(t1, t2, t3, t4, t5); + } + catch (Exception e) + { + Debug.LogException(e, this); + } + } + } + #endregion + } + /// + /// A container of CallbackActions that is correlated to a specific scenario as + /// specified by the user of this class. + /// This variant accepts CallbackEvents with 1 generic parameter. + /// + public class CallbackEvent : ICallbackEvent + { + #region Properties -------------------------------------------------------------- + /// + public IEnumerable Actions => actions; + #endregion + + #region Fields ------------------------------------------------------------------ + private List actions = new List(); + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// + public void RegisterAction(ICallbackAction action) + { + // Check if valid action + if (action.GetType() != typeof(CallbackAction)) + { + Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this); + return; + } + + actions.Add(action); + } + /// + /// Adds a CallbackAction into the event. + /// + /// CallbackAction to add. + public void RegisterAction(CallbackAction action) + { + actions.Add(action); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// System.Action to add as a CallbackAction. + public void RegisterAction(Action action) + { + actions.Add(new CallbackAction(action)); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// Object to call the method on. + /// Method to call. + public void RegisterAction(Object target, MethodInfo method) + { + actions.Add(new CallbackAction(target, method)); + } + /// + public void DeregisterAction(ICallbackAction action) + { + if (!actions.Remove(action)) + { + Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this); + } + } + /// + /// Invokes all stored CallbackActions with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) + { + foreach (CallbackAction action in actions) + { + try + { + action.Invoke(t1, t2, t3, t4, t5, t6); + } + catch (Exception e) + { + Debug.LogException(e, this); + } + } + } + #endregion + } + /// + /// A container of CallbackActions that is correlated to a specific scenario as + /// specified by the user of this class. + /// This variant accepts CallbackEvents with 1 generic parameter. + /// + public class CallbackEvent : ICallbackEvent + { + #region Properties -------------------------------------------------------------- + /// + public IEnumerable Actions => actions; + #endregion + + #region Fields ------------------------------------------------------------------ + private List actions = new List(); + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// + public void RegisterAction(ICallbackAction action) + { + // Check if valid action + if (action.GetType() != typeof(CallbackAction)) + { + Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this); + return; + } + + actions.Add(action); + } + /// + /// Adds a CallbackAction into the event. + /// + /// CallbackAction to add. + public void RegisterAction(CallbackAction action) + { + actions.Add(action); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// System.Action to add as a CallbackAction. + public void RegisterAction(Action action) + { + actions.Add(new CallbackAction(action)); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// Object to call the method on. + /// Method to call. + public void RegisterAction(Object target, MethodInfo method) + { + actions.Add(new CallbackAction(target, method)); + } + /// + public void DeregisterAction(ICallbackAction action) + { + if (!actions.Remove(action)) + { + Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this); + } + } + /// + /// Invokes all stored CallbackActions with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) + { + foreach (CallbackAction action in actions) + { + try + { + action.Invoke(t1, t2, t3, t4, t5, t6, t7); + } + catch (Exception e) + { + Debug.LogException(e, this); + } + } + } + #endregion + } + /// + /// A container of CallbackActions that is correlated to a specific scenario as + /// specified by the user of this class. + /// This variant accepts CallbackEvents with 1 generic parameter. + /// + public class CallbackEvent : ICallbackEvent + { + #region Properties -------------------------------------------------------------- + /// + public IEnumerable Actions => actions; + #endregion + + #region Fields ------------------------------------------------------------------ + private List actions = new List(); + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// + public void RegisterAction(ICallbackAction action) + { + // Check if valid action + if (action.GetType() != typeof(CallbackAction)) + { + Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this); + return; + } + + actions.Add(action); + } + /// + /// Adds a CallbackAction into the event. + /// + /// CallbackAction to add. + public void RegisterAction(CallbackAction action) + { + actions.Add(action); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// System.Action to add as a CallbackAction. + public void RegisterAction(Action action) + { + actions.Add(new CallbackAction(action)); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// Object to call the method on. + /// Method to call. + public void RegisterAction(Object target, MethodInfo method) + { + actions.Add(new CallbackAction(target, method)); + } + /// + public void DeregisterAction(ICallbackAction action) + { + if (!actions.Remove(action)) + { + Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this); + } + } + /// + /// Invokes all stored CallbackActions with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) + { + foreach (CallbackAction action in actions) + { + try + { + action.Invoke(t1, t2, t3, t4, t5, t6, t7, t8); + } + catch (Exception e) + { + Debug.LogException(e, this); + } + } + } + #endregion + } + /// + /// A container of CallbackActions that is correlated to a specific scenario as + /// specified by the user of this class. + /// This variant accepts CallbackEvents with 1 generic parameter. + /// + public class CallbackEvent : ICallbackEvent + { + #region Properties -------------------------------------------------------------- + /// + public IEnumerable Actions => actions; + #endregion + + #region Fields ------------------------------------------------------------------ + private List actions = new List(); + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// + public void RegisterAction(ICallbackAction action) + { + // Check if valid action + if (action.GetType() != typeof(CallbackAction)) + { + Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this); + return; + } + + actions.Add(action); + } + /// + /// Adds a CallbackAction into the event. + /// + /// CallbackAction to add. + public void RegisterAction(CallbackAction action) + { + actions.Add(action); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// System.Action to add as a CallbackAction. + public void RegisterAction(Action action) + { + actions.Add(new CallbackAction(action)); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// Object to call the method on. + /// Method to call. + public void RegisterAction(Object target, MethodInfo method) + { + actions.Add(new CallbackAction(target, method)); + } + /// + public void DeregisterAction(ICallbackAction action) + { + if (!actions.Remove(action)) + { + Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this); + } + } + /// + /// Invokes all stored CallbackActions with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) + { + foreach (CallbackAction action in actions) + { + try + { + action.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9); + } + catch (Exception e) + { + Debug.LogException(e, this); + } + } + } + #endregion + } + /// + /// A container of CallbackActions that is correlated to a specific scenario as + /// specified by the user of this class. + /// This variant accepts CallbackEvents with 1 generic parameter. + /// + public class CallbackEvent : ICallbackEvent + { + #region Properties -------------------------------------------------------------- + /// + public IEnumerable Actions => actions; + #endregion + + #region Fields ------------------------------------------------------------------ + private List actions = new List(); + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// + public void RegisterAction(ICallbackAction action) + { + // Check if valid action + if (action.GetType() != typeof(CallbackAction)) + { + Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this); + return; + } + + actions.Add(action); + } + /// + /// Adds a CallbackAction into the event. + /// + /// CallbackAction to add. + public void RegisterAction(CallbackAction action) + { + actions.Add(action); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// System.Action to add as a CallbackAction. + public void RegisterAction(Action action) + { + actions.Add(new CallbackAction(action)); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// Object to call the method on. + /// Method to call. + public void RegisterAction(Object target, MethodInfo method) + { + actions.Add(new CallbackAction(target, method)); + } + /// + public void DeregisterAction(ICallbackAction action) + { + if (!actions.Remove(action)) + { + Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this); + } + } + /// + /// Invokes all stored CallbackActions with the specified parameters. + /// + public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10) + { + foreach (CallbackAction action in actions) + { + try + { + action.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); + } + catch (Exception e) + { + Debug.LogException(e, this); + } + } + } + #endregion + } +} diff --git a/SHADE_CSharp/src/Events/CallbackEvent.tt b/SHADE_CSharp/src/Events/CallbackEvent.tt new file mode 100644 index 00000000..6a545601 --- /dev/null +++ b/SHADE_CSharp/src/Events/CallbackEvent.tt @@ -0,0 +1,152 @@ +<# +/************************************************************************************//*! +\file CallbackEvent.tt +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 23, 2022 +\brief Contains the T4 template for the definition of CallbackEvent and + related classes. + +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. +*//*************************************************************************************/#> +<#@ template hostspecific="false" language="C#" #> +<#@ output extension=".cs" #> +<# var max = 10; #> +/************************************************************************************//*! +\file CallbackEvent.cs +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 23, 2022 +\brief Contains the definition of CallbackEvent and related classes. + +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. +*//*************************************************************************************/ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Reflection.Metadata.Ecma335; + +namespace SHADE +{ + /// + /// Interface for a CallbackEvent that all variants inherit from. + /// + public interface ICallbackEvent + { + /// + /// Registers an empty ICallbackAction. + /// + void RegisterAction(); + /// + /// Registers an ICallbackAction with the event such that it will be called in + /// future + /// + /// ICallbackAction to register with. + void RegisterAction(ICallbackAction action); + /// + /// Deregisters an ICallbackAction that was previously added. This should + /// only emit a warning if an action that was not previous added was + /// provided. + /// + /// ICallbackAction to remove. + void DeregisterAction(ICallbackAction action); + /// + /// Iterable set of ICallbackActions that were registered to this event. + /// + IEnumerable Actions { get; } + } + +<# for (int i = 1; i <= max; ++i) { #> + /// + /// A container of CallbackActions that is correlated to a specific scenario as + /// specified by the user of this class. + /// This variant accepts CallbackEvents with 1 generic parameter. + /// + public class CallbackEvent<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> : ICallbackEvent + { + #region Properties -------------------------------------------------------------- + /// + public IEnumerable Actions => actions; + #endregion + + #region Fields ------------------------------------------------------------------ + private List actions = new List(); + #endregion + + #region Usage Functions --------------------------------------------------------- + /// + public void RegisterAction() + { + actions.Add(new CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>()); + } + /// + public void RegisterAction(ICallbackAction action) + { + // Check if valid action + if (action.GetType() != typeof(CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>)) + { + Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this); + return; + } + + actions.Add(action); + } + /// + /// Adds a CallbackAction into the event. + /// + /// CallbackAction to add. + public void RegisterAction(CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action) + { + actions.Add(action); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// System.Action to add as a CallbackAction. + public void RegisterAction(Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action) + { + actions.Add(new CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>(action)); + } + /// + /// Constructs and adds a CallbackACtion into the event. + /// + /// Object to call the method on. + /// Method to call. + public void RegisterAction(Object target, MethodInfo method) + { + actions.Add(new CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>(target, method)); + } + /// + public void DeregisterAction(ICallbackAction action) + { + if (!actions.Remove(action)) + { + Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this); + } + } + /// + /// Invokes all stored CallbackActions with the specified parameters. + /// + public void Invoke(<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#> t<#=t#><# if (t != i) { #>, <# } #><# } #>) + { + foreach (CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action in actions) + { + try + { + action.Invoke(<# for (int t = 1; t < i + 1; ++t) { #>t<#=t#><# if (t != i) { #>, <# } #><# } #>); + } + catch (Exception e) + { + Debug.LogException(e, this); + } + } + } + #endregion + } +<# } #> +} diff --git a/SHADE_CSharp/src/Utility/Debug.cs b/SHADE_CSharp/src/Utility/Debug.cs new file mode 100644 index 00000000..eb9d9b24 --- /dev/null +++ b/SHADE_CSharp/src/Utility/Debug.cs @@ -0,0 +1,37 @@ +using System; +using System.Runtime.InteropServices; + +namespace SHADE +{ + internal static class Debug + { + [DllImport("SHADE_Engine.dll", EntryPoint = "SHLog_Info")] + public static extern void LogInfo([MarshalAs(UnmanagedType.LPStr)] string str); + [DllImport("SHADE_Engine.dll", EntryPoint = "SHLog_Warning")] + public static extern void LogWarning([MarshalAs(UnmanagedType.LPStr)] string str); + [DllImport("SHADE_Engine.dll", EntryPoint = "SHLog_Error")] + public static extern void LogError([MarshalAs(UnmanagedType.LPStr)] string str); + [DllImport("SHADE_Engine.dll", EntryPoint = "SHLog_Critical")] + public static extern void LogCritical([MarshalAs(UnmanagedType.LPStr)] string str); + public static void LogInfo(string msg, Object thrower) + { + LogInfo($"[{thrower.GetType().Name}] {msg}"); + } + public static void LogWarning(string msg, Object thrower) + { + LogWarning($"[{thrower.GetType().Name}] {msg}"); + } + public static void LogError(string msg, Object thrower) + { + LogError($"[{thrower.GetType().Name}] {msg}"); + } + public static void LogCritical(string msg, Object thrower) + { + LogCritical($"[{thrower.GetType().Name}] {msg}"); + } + public static void LogException(Exception exception, Object thrower) + { + LogError($"[{ thrower.GetType().Name }] Unhandled exception: { exception.ToString() }"); + } + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Asset Types/SHShaderAsset.cpp b/SHADE_Engine/src/Assets/Asset Types/SHShaderAsset.cpp new file mode 100644 index 00000000..d0200b1f --- /dev/null +++ b/SHADE_Engine/src/Assets/Asset Types/SHShaderAsset.cpp @@ -0,0 +1,61 @@ +/*************************************************************************//** + * \file SHShaderAsset.cpp + * \author Brandon Mak + * \date 24 October 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ + +#include "SHpch.h" +#include "SHShaderAsset.h" + +namespace SHADE +{ + SHShaderAsset::SHShaderAsset() noexcept + : spirvBinary{}, + shaderType{SH_SHADER_TYPE::VERTEX}, + name{} + { + } + + SHShaderAsset::SHShaderAsset(SHShaderAsset const& rhs) noexcept + : spirvBinary{rhs.spirvBinary}, + shaderType{ rhs.shaderType }, + name{rhs.name} + { + } + + SHShaderAsset::SHShaderAsset(SHShaderAsset&& rhs) noexcept + : spirvBinary{ std::move(rhs.spirvBinary) }, + shaderType{ std::move(rhs.shaderType) }, + name{ std::move(rhs.name) } + { + } + + SHShaderAsset& SHShaderAsset::operator=(SHShaderAsset&& rhs) noexcept + { + if (this == &rhs) + { + return *this; + } + + spirvBinary = std::move(rhs.spirvBinary); + shaderType = std::move(rhs.shaderType); + name = std::move(rhs.name); + } + + SHShaderAsset& SHShaderAsset::operator=(SHShaderAsset const& rhs) noexcept + { + if (this == &rhs) + { + return *this; + } + + spirvBinary = rhs.spirvBinary; + shaderType = rhs.shaderType; + name = rhs.name; + } +} diff --git a/SHADE_Engine/src/Assets/Asset Types/SHShaderAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHShaderAsset.h new file mode 100644 index 00000000..adcd215a --- /dev/null +++ b/SHADE_Engine/src/Assets/Asset Types/SHShaderAsset.h @@ -0,0 +1,48 @@ +/*************************************************************************//** + * \file SHShaderAsset.h + * \author Brandon Mak + * \date 24 October 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ +#pragma once + +#include "SHAssetData.h" +#include "SH_API.h" +#include +#include + +namespace SHADE +{ + enum class SH_SHADER_TYPE : uint8_t + { + VERTEX, + FRAGMENT, + COMPUTE, + INAVLID_TYPE + }; + + struct SH_API SHShaderAsset : SHAssetData + { + /*-----------------------------------------------------------------------*/ + /* MEMBER VARIABLES */ + /*-----------------------------------------------------------------------*/ + //! container storing the spirv binary + std::vector spirvBinary; + + //! For the compilation of the shader. Vulkan backend will use it too + SH_SHADER_TYPE shaderType; + + //! Name of the shader file (without parent path) + std::string name; + + SHShaderAsset() noexcept; + SHShaderAsset(SHShaderAsset const& rhs) noexcept; + SHShaderAsset(SHShaderAsset&& rhs) noexcept; + SHShaderAsset& operator= (SHShaderAsset&& rhs) noexcept; + SHShaderAsset& operator= (SHShaderAsset const& rhs) noexcept; + }; +} diff --git a/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.cpp b/SHADE_Engine/src/Assets/Libraries/Compilers/SHMeshCompiler.cpp similarity index 59% rename from SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.cpp rename to SHADE_Engine/src/Assets/Libraries/Compilers/SHMeshCompiler.cpp index f4be0b68..046ba767 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.cpp +++ b/SHADE_Engine/src/Assets/Libraries/Compilers/SHMeshCompiler.cpp @@ -1,24 +1,30 @@ /*************************************************************************//** - * \file SHAssimpLibrary.cpp + * \file SHMeshCompiler.cpp * \author Loh Xiao Qi - * \date October 2022 - * \brief + * \date 30 September 2022 + * \brief Library to write data in SHMeshAsset into binary file for faster + * loading in the future + * * * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * disclosure of this file or its contents without the prior written consent * of DigiPen Institute of Technology is prohibited. *****************************************************************************/ #include "SHpch.h" -#include "SHAssimpLibrary.h" +#include "SHMeshCompiler.h" +#include "Graphics/MiddleEnd/Meshes/SHMeshData.h" #include +#include + namespace SHADE { - Assimp::Importer SHAssimpLibrary::aiImporter; - void SHAssimpLibrary::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept - { - for (size_t i {0}; i < node.mNumMeshes; ++i) + Assimp::Importer SHMeshCompiler::aiImporter; + + void SHMeshCompiler::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept + { + for (size_t i{ 0 }; i < node.mNumMeshes; ++i) { aiMesh* mesh = scene.mMeshes[node.mMeshes[i]]; meshes.push_back(ProcessMesh(*mesh)); @@ -28,16 +34,16 @@ namespace SHADE { ProcessNode(*node.mChildren[i], scene, meshes); } - } + } - void SHAssimpLibrary::ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept - { - if (scene.HasAnimations()) + void SHMeshCompiler::ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept + { + if (scene.HasAnimations()) { - std::vector anims(scene.mNumAnimations); - for (auto i{0}; i < scene.mNumAnimations; ++i) - { - auto const& anim {*scene.mAnimations[i]}; + std::vector anims(scene.mNumAnimations); + for (auto i{ 0 }; i < scene.mNumAnimations; ++i) + { + auto const& anim{ *scene.mAnimations[i] }; anims[i].name = anim.mName.C_Str(); @@ -47,17 +53,17 @@ namespace SHADE std::copy_n(anim.mChannels, anim.mNumChannels, anims[i].nodeChannels.data()); std::copy_n(anim.mMeshChannels, anim.mNumMeshChannels, anims[i].meshChannels.data()); std::copy_n(anim.mMorphMeshChannels, anim.mNumMorphMeshChannels, anims[i].morphMeshChannels.data()); - } + } } - } + } - SHMeshAsset* SHAssimpLibrary::ProcessMesh(aiMesh const& mesh) noexcept - { + SHMeshAsset* SHMeshCompiler::ProcessMesh(aiMesh const& mesh) noexcept + { SHMeshAsset* result = new SHMeshAsset(); result->compiled = false; result->changed = false; - for (size_t i{0}; i < mesh.mNumVertices; ++i) + for (size_t i{ 0 }; i < mesh.mNumVertices; ++i) { // Vertex position SHVec3 vertex; @@ -67,7 +73,7 @@ namespace SHADE result->vertexPosition.push_back(vertex); // Tex coords - SHVec2 texCoord{0.f, 0.f}; + SHVec2 texCoord{ 0.f, 0.f }; if (mesh.mTextureCoords[0]) { texCoord.x = mesh.mTextureCoords[0][i].x; @@ -76,7 +82,7 @@ namespace SHADE result->texCoords.push_back(texCoord); // Normals - SHVec3 normal{0.f, 0.f, 0.f}; + SHVec3 normal{ 0.f, 0.f, 0.f }; if (mesh.mNormals) { normal.x = mesh.mNormals[i].x; @@ -86,7 +92,7 @@ namespace SHADE result->vertexNormal.push_back(normal); // Tangent - SHVec3 tangent{0.f, 0.f, 0.f}; + SHVec3 tangent{ 0.f, 0.f, 0.f }; if (mesh.mTangents) { tangent.x = mesh.mTangents[i].x; @@ -96,10 +102,10 @@ namespace SHADE result->vertexTangent.push_back(tangent); } - for (size_t i {0}; i < mesh.mNumFaces; ++i) + for (size_t i{ 0 }; i < mesh.mNumFaces; ++i) { aiFace face = mesh.mFaces[i]; - for (size_t j{0}; j < face.mNumIndices; ++j) + for (size_t j{ 0 }; j < face.mNumIndices; ++j) { result->indices.push_back(face.mIndices[j]); } @@ -110,10 +116,10 @@ namespace SHADE result->header.name = mesh.mName.C_Str(); return result; - } + } - void SHAssimpLibrary::LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept - { + void SHMeshCompiler::LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept + { const aiScene* scene = aiImporter.ReadFile(path.string().c_str(), aiProcess_Triangulate // Make sure we get triangles rather than nvert polygons | aiProcess_GenUVCoords // Convert any type of mapping to uv mapping @@ -132,10 +138,64 @@ namespace SHADE return; } - ExtractAnimations(*scene, anims); + //ExtractAnimations(*scene, anims); ProcessNode(*scene->mRootNode, *scene, meshes); aiImporter.FreeScene(); - } + } + + std::optional SHMeshCompiler::CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept + { + std::string newPath{ path.parent_path().string() + '/' }; + newPath += asset.header.name + MESH_EXTENSION.data(); + + std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc }; + if (!file.is_open()) + { + SHLOG_ERROR("Unable to open file for writing mesh file: {}", path.string()); + } + + file.write( + reinterpret_cast(&(asset.header.vertexCount)), + sizeof(uint32_t) + ); + + file.write( + reinterpret_cast(&(asset.header.indexCount)), + sizeof(uint32_t) + ); + + auto const vertexVec3Byte{ sizeof(SHVec3) * asset.header.vertexCount }; + auto const vertexVec2Byte{ sizeof(SHVec2) * asset.header.vertexCount }; + + file.write( + reinterpret_cast(asset.vertexPosition.data()), + vertexVec3Byte + ); + + file.write( + reinterpret_cast(asset.vertexTangent.data()), + vertexVec3Byte + ); + + file.write( + reinterpret_cast(asset.vertexNormal.data()), + vertexVec3Byte + ); + + file.write( + reinterpret_cast(asset.texCoords.data()), + vertexVec2Byte + ); + + file.write( + reinterpret_cast(asset.indices.data()), + sizeof(uint32_t) * asset.header.indexCount + ); + + file.close(); + + return newPath; + } } diff --git a/SHADE_Engine/src/Assets/Libraries/Compilers/SHMeshCompiler.h b/SHADE_Engine/src/Assets/Libraries/Compilers/SHMeshCompiler.h new file mode 100644 index 00000000..1af1298b --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/Compilers/SHMeshCompiler.h @@ -0,0 +1,40 @@ +/*************************************************************************//** + * \file SHMeshCompiler.h + * \author Loh Xiao Qi + * \date 30 September 2022 + * \brief Library to write data in SHMeshAsset into binary file for faster + * loading in the future + * + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ +#pragma once + +#include +#include +#include + +#include "Assets/Asset Types/SHAnimationAsset.h" +#include "Assets/Asset Types/SHMeshAsset.h" +#include "Assets/SHAssetMacros.h" + +namespace SHADE +{ + class SHMeshCompiler + { + + using MeshVectorRef = std::vector&; + using AnimVectorRef = std::vector&; + + static Assimp::Importer aiImporter; + static void ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept; + static void ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept; + static SHMeshAsset* ProcessMesh(aiMesh const& mesh) noexcept; + + public: + static void LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept; + static std::optional CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Libraries/Compilers/SHShaderSourceCompiler.cpp b/SHADE_Engine/src/Assets/Libraries/Compilers/SHShaderSourceCompiler.cpp new file mode 100644 index 00000000..329e34e9 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/Compilers/SHShaderSourceCompiler.cpp @@ -0,0 +1,162 @@ +/*************************************************************************//** + * \file SHShaderSourceCompiler.cpp + * \author Loh Xiao Qi + * \date 23 10 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ +#include "SHpch.h" +#include "SHShaderSourceCompiler.h" +#include "shaderc/shaderc.hpp" + +#include +#include +#include +#include + +namespace SHADE +{ + std::string SHShaderSourceCompiler::CompileShaderSourceToBinary(AssetPath path, SHShaderAsset const& data) noexcept + { + std::string newPath{ path.string() }; + newPath = newPath.substr(0, newPath.find_last_of('.')); + newPath += SHADER_BUILT_IN_EXTENSION.data(); + + std::ofstream file{ newPath, std::ios::binary | std::ios::out | std::ios::trunc }; + + file.write( + reinterpret_cast(& data.shaderType), sizeof(uint8_t) + ); + + size_t const byteCount = sizeof(uint32_t) * data.spirvBinary.size(); + + file.write( + reinterpret_cast(&byteCount), sizeof(size_t) + ); + + file.write( + reinterpret_cast(data.spirvBinary.data()), byteCount + ); + + file.close(); + + return newPath; + } + + SHShaderAsset const* SHShaderSourceCompiler::CompileShaderSourceToMemory(std::string const& data, std::string const& name, SH_SHADER_TYPE type) noexcept + { + // shaderc compiler + shaderc::Compiler compiler; + shaderc::CompileOptions options; + + options.AddMacroDefinition("MY_DEFINE", "1"); + + //TODO: Check if we need optimisation levels when compiling into spirv + // Set optimization levels + //if (opLevel != shaderc_optimization_level_zero) + // options.SetOptimizationLevel(opLevel); + + // Attempt to get the shaderc equivalent shader stage + shaderc_shader_kind shaderKind; + switch (type) + { + case SH_SHADER_TYPE::VERTEX: + shaderKind = shaderc_shader_kind::shaderc_glsl_vertex_shader; + break; + case SH_SHADER_TYPE::FRAGMENT: + shaderKind = shaderc_shader_kind::shaderc_glsl_fragment_shader; + break; + case SH_SHADER_TYPE::COMPUTE: + shaderKind = shaderc_shader_kind::shaderc_glsl_compute_shader; + break; + default: + shaderKind = shaderc_shader_kind::shaderc_glsl_vertex_shader; + break; + } + + // Compile the shader and get the result + shaderc::SpvCompilationResult compileResult = compiler.CompileGlslToSpv(data, shaderKind, name.c_str(), options); + + if (compileResult.GetCompilationStatus() != shaderc_compilation_status_success) + { + SHLOG_ERROR("Shaderc failed to compile GLSL shader to binary | " + compileResult.GetErrorMessage()); + return nullptr; + } + + auto result = new SHShaderAsset(); + result->spirvBinary.resize(compileResult.end() - compileResult.begin()); + + std::ranges::copy(compileResult.begin(), compileResult.end(), result->spirvBinary.data()); + + result->name = name; + result->shaderType = type; + + return result; + } + + SH_SHADER_TYPE SHShaderSourceCompiler::GetShaderTypeFromFilename(std::string name) noexcept + { + for (auto i { 0}; i < SHADER_TYPE_MAX_COUNT; ++i) + { + if (name.find(SHADER_IDENTIFIERS[i].data()) != std::string::npos) + { + return static_cast(i); + } + } + + return SH_SHADER_TYPE::INAVLID_TYPE; + } + + std::optional SHShaderSourceCompiler::LoadAndCompileShader(AssetPath path) noexcept + { + auto type = GetShaderTypeFromFilename(path.filename().string()); + + if (type == SH_SHADER_TYPE::INAVLID_TYPE) + { + SHLOG_ERROR("Invalid filename for shaders, follow suffix in SHAssetMacros.h: {}", path.string()); + return {}; + } + + path.make_preferred(); + + std::ifstream file{ path.string(), std::ios::in }; + + if (file.is_open()) + { + std::stringstream stream; + + stream << file.rdbuf(); + + std::string const content = stream.str(); + + auto data = CompileShaderSourceToMemory(content, path.filename().string(), type); + + if (data == nullptr) + { + return{}; + } + + return CompileShaderSourceToBinary(path, *data); + } + + SHLOG_ERROR("Unable to open shader file: {}", path.string()); + + return {}; + } + + std::optional SHShaderSourceCompiler::CompileShaderFromString + (std::string const& string, AssetPath path, SH_SHADER_TYPE type) noexcept + { + auto const data = CompileShaderSourceToMemory(string, path.filename().string(), type); + + if (data == nullptr) + { + return{}; + } + + return CompileShaderSourceToBinary(path, *data); + } +} diff --git a/SHADE_Engine/src/Assets/Libraries/Compilers/SHShaderSourceCompiler.h b/SHADE_Engine/src/Assets/Libraries/Compilers/SHShaderSourceCompiler.h new file mode 100644 index 00000000..4ba87050 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/Compilers/SHShaderSourceCompiler.h @@ -0,0 +1,31 @@ +/*************************************************************************//** + * \file SHShaderSourceCompiler.h + * \author Loh Xiao Qi + * \date 23 10 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ +#pragma once + +#include "Assets/SHAssetMacros.h" +#include "Assets/Asset Types/SHShaderAsset.h" + +namespace SHADE +{ + class SHShaderSourceCompiler + { + private: + static std::string CompileShaderSourceToBinary(AssetPath path, SHShaderAsset const& data) noexcept; + static SHShaderAsset const* CompileShaderSourceToMemory(std::string const& data, std::string const& name, SH_SHADER_TYPE type) noexcept; + + static SH_SHADER_TYPE GetShaderTypeFromFilename(std::string name) noexcept; + + public: + static std::optional LoadAndCompileShader(AssetPath path) noexcept; + static std::optional CompileShaderFromString + (std::string const& string, AssetPath path, SH_SHADER_TYPE type) noexcept; + }; +} diff --git a/SHADE_Engine/src/Assets/Libraries/Compilers/SHTextureCompiler.cpp b/SHADE_Engine/src/Assets/Libraries/Compilers/SHTextureCompiler.cpp new file mode 100644 index 00000000..5093203a --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/Compilers/SHTextureCompiler.cpp @@ -0,0 +1,171 @@ +/*************************************************************************//** + * \file SHTextureCompiler.cpp + * \author Loh Xiao Qi + * \date 30 September 2022 + * \brief Library to write data in SHTextureAsset into binary file for + * faster loading in the future + * + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ +#include "SHpch.h" +#include "SHTextureCompiler.h" + +#include + +namespace SHADE +{ + + std::string SHTextureCompiler::TinyDDSResultToString(tinyddsloader::Result value) + { + switch (value) + { + case tinyddsloader::Result::ErrorFileOpen: + return "File open err"; + case tinyddsloader::Result::ErrorRead: + return "File read err"; + case tinyddsloader::Result::ErrorMagicWord: + return "File header magic word err"; + case tinyddsloader::Result::ErrorSize: + return "File size err"; + case tinyddsloader::Result::ErrorVerify: + return "Pixel format err"; + case tinyddsloader::Result::ErrorNotSupported: + return "Unsupported format"; + case tinyddsloader::Result::ErrorInvalidData: + return "Invalid data"; + default: + return "Unknown"; + } + } + + vk::Format SHTextureCompiler::ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear) + { + switch (format) + { + case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm_SRGB: + return isLinear ? vk::Format::eBc1RgbaUnormBlock : vk::Format::eBc1RgbaSrgbBlock; + case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm_SRGB: + return isLinear ? vk::Format::eBc2UnormBlock : vk::Format::eBc2SrgbBlock; + case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm_SRGB: + return isLinear ? vk::Format::eBc3UnormBlock : vk::Format::eBc3SrgbBlock; + case tinyddsloader::DDSFile::DXGIFormat::BC5_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::BC5_SNorm: + return isLinear ? vk::Format::eBc5UnormBlock : vk::Format::eBc5SnormBlock; + case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm_SRGB: + return isLinear ? vk::Format::eR8G8B8A8Unorm : vk::Format::eR8G8B8A8Srgb; + case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_SNorm: + return vk::Format::eR8G8B8A8Snorm; + case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm_SRGB: + return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8A8Srgb; + case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm: + case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm_SRGB: + return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8Srgb; + default: + throw std::runtime_error("Unsupported DDS format."); + } + } + + void SHTextureCompiler::LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept + { + tinyddsloader::Result loadResult = tinyddsloader::Result::Success; + tinyddsloader::DDSFile file; + loadResult = file.Load(path.string().c_str()); + if (loadResult != tinyddsloader::Result::Success) + { + SHLOG_ERROR("Unable to load Texture file: {} at {}", TinyDDSResultToString(loadResult), path.string()); + } + + size_t totalBytes{ 0 }; + + std::vector mipOff(file.GetMipCount()); + + for (size_t i{ 0 }; i < file.GetMipCount(); ++i) + { + mipOff[i] = static_cast(totalBytes); + totalBytes += file.GetImageData(static_cast(i), 0)->m_memSlicePitch; + } + + SHTexture::PixelChannel* pixel = new SHTexture::PixelChannel[totalBytes]; + std::memcpy(pixel, file.GetImageData()->m_mem, totalBytes); + //pixel = std::move(reinterpret_cast(file.GetDDSData())); + + asset.name = path.stem().string(); + asset.compiled = false; + asset.numBytes = static_cast(totalBytes); + asset.width = file.GetWidth(); + asset.height = file.GetHeight(); + asset.format = ddsLoaderToVkFormat(file.GetFormat(), true); + asset.mipOffsets = std::move(mipOff); + asset.pixelData = std::move(pixel); + } + + std::string SHTextureCompiler::WriteToFile(SHTextureAsset const& asset, AssetPath path) noexcept + { + std::string newPath{ path.string() }; + newPath = newPath.substr(0, newPath.find_last_of('.')); + newPath += TEXTURE_EXTENSION; + + std::ofstream file{ newPath, std::ios::out | std::ios::binary }; + if (!file.is_open()) + { + SHLOG_ERROR("Unable to open file for writing texture file: {}", path.string()); + } + + constexpr auto intBytes{ sizeof(uint32_t) }; + + uint32_t const mipOffsetCount{ static_cast(asset.mipOffsets.size()) }; + + file.write( + reinterpret_cast(&asset.numBytes), + intBytes + ); + + file.write( + reinterpret_cast(&asset.width), + intBytes + ); + + file.write( + reinterpret_cast(&asset.height), + intBytes + ); + + file.write( + reinterpret_cast(&asset.format), + sizeof(SHTexture::TextureFormat) + ); + + file.write( + reinterpret_cast(&mipOffsetCount), + intBytes + ); + + file.write( + reinterpret_cast(asset.mipOffsets.data()), + intBytes * asset.mipOffsets.size() + ); + + file.write( + reinterpret_cast(asset.pixelData), + asset.numBytes + ); + + file.close(); + return newPath; + } + + std::optional SHTextureCompiler::CompileTextureAsset(AssetPath path) + { + auto data = new SHTextureAsset(); + LoadTinyDDS(path, *data); + return WriteToFile(*data, path); + } +} diff --git a/SHADE_Engine/src/Assets/Libraries/Compilers/SHTextureCompiler.h b/SHADE_Engine/src/Assets/Libraries/Compilers/SHTextureCompiler.h new file mode 100644 index 00000000..8c4902a2 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/Compilers/SHTextureCompiler.h @@ -0,0 +1,33 @@ +/*************************************************************************//** + * \file SHTextureCompiler.h + * \author Loh Xiao Qi + * \date 30 September 2022 + * \brief Library to write data in SHTextureAsset into binary file for + * faster loading in the future + * + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ +#pragma once +#define TINYDDSLOADER_IMPLEMENTATION + +#include "Assets/Asset Types/SHTextureAsset.h" +#include "Assets/SHAssetMacros.h" +#include "tinyddsloader.h" + +namespace SHADE +{ + class SHTextureCompiler + { + private: + static std::string TinyDDSResultToString(tinyddsloader::Result value); + static vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear); + static void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept; + + static std::string WriteToFile(SHTextureAsset const& asset, AssetPath path) noexcept; + public: + static std::optional CompileTextureAsset(AssetPath path); + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Libraries/SHAssetLoader.h b/SHADE_Engine/src/Assets/Libraries/Loaders/SHAssetLoader.h similarity index 94% rename from SHADE_Engine/src/Assets/Libraries/SHAssetLoader.h rename to SHADE_Engine/src/Assets/Libraries/Loaders/SHAssetLoader.h index 41595519..63e081af 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHAssetLoader.h +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHAssetLoader.h @@ -10,6 +10,7 @@ *****************************************************************************/ #pragma once +#include "Assets/SHAssetMacros.h" #include "Assets/Asset Types/SHAssetData.h" namespace SHADE diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp b/SHADE_Engine/src/Assets/Libraries/Loaders/SHMeshLoader.cpp similarity index 100% rename from SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp rename to SHADE_Engine/src/Assets/Libraries/Loaders/SHMeshLoader.cpp diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h b/SHADE_Engine/src/Assets/Libraries/Loaders/SHMeshLoader.h similarity index 85% rename from SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h rename to SHADE_Engine/src/Assets/Libraries/Loaders/SHMeshLoader.h index 34c4e5d2..bf65851a 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHMeshLoader.h @@ -10,13 +10,13 @@ * of DigiPen Institute of Technology is prohibited. *****************************************************************************/ #pragma once -#include "../SHAssetMacros.h" -#include "../Asset Types/SHMeshAsset.h" +#include "Assets/SHAssetMacros.h" +#include "Assets/Asset Types/SHMeshAsset.h" #include "SHAssetLoader.h" namespace SHADE { - struct SHMeshLoader : public SHAssetLoader + struct SHMeshLoader : SHAssetLoader { void LoadSHMesh(AssetPath path, SHMeshAsset& meshes) noexcept; SHAssetData* Load(AssetPath path) override; diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHShaderSourceLoader.cpp b/SHADE_Engine/src/Assets/Libraries/Loaders/SHShaderSourceLoader.cpp new file mode 100644 index 00000000..824995d6 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHShaderSourceLoader.cpp @@ -0,0 +1,46 @@ +/*************************************************************************//** + * \file SHShaderSourceLoader.cpp + * \author Loh Xiao Qi + * \date 23 10 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ + +#include "SHpch.h" +#include "SHShaderSourceLoader.h" +#include "Assets/Asset Types/SHShaderAsset.h" + +#include + +namespace SHADE +{ + SHAssetData* SHShaderSourceLoader::Load(AssetPath path) + { + auto result = new SHShaderAsset(); + + result->name = path.stem().stem().string(); + + std::ifstream file{ path.string(), std::ios::in | std::ios::binary }; + if (!file.is_open()) + { + SHLOG_ERROR("Unable to open compiled shader file: {}", path.string()); + return nullptr; + } + + size_t byteCount = 0; + + file.read(reinterpret_cast(&result->shaderType), sizeof(uint8_t)); + file.read(reinterpret_cast(&byteCount), sizeof(size_t)); + + result->spirvBinary.resize(byteCount / sizeof(uint32_t)); + + file.read(reinterpret_cast(result->spirvBinary.data()), byteCount); + + file.close(); + + return result; + } +} diff --git a/SHADE_Engine/SHAnimationAsset.h b/SHADE_Engine/src/Assets/Libraries/Loaders/SHShaderSourceLoader.h similarity index 55% rename from SHADE_Engine/SHAnimationAsset.h rename to SHADE_Engine/src/Assets/Libraries/Loaders/SHShaderSourceLoader.h index d8d0ffb1..befdade5 100644 --- a/SHADE_Engine/SHAnimationAsset.h +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHShaderSourceLoader.h @@ -1,7 +1,7 @@ /*************************************************************************//** - * \file SHAnimationAsset.h + * \file SHShaderSourceLoader.h * \author Loh Xiao Qi - * \date October 2022 + * \date 23 10 2022 * \brief * * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or @@ -10,21 +10,13 @@ *****************************************************************************/ #pragma once -#include -#include -#include "SH_API.power h" +#include "Assets/Libraries/Loaders/SHAssetLoader.h" +#include "Assets/SHAssetMacros.h" namespace SHADE { - struct SH_API SHAnimationAsset + struct SHShaderSourceLoader : SHAssetLoader { - std::string name; - - std::vector nodeChannels; - std::vector meshChannels; - std::vector morphMeshChannels; - - double duration; - double ticksPerSecond; + SHAssetData* Load(AssetPath path) override; }; -} \ No newline at end of file +} diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextureLoader.cpp b/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextureLoader.cpp new file mode 100644 index 00000000..74c08230 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextureLoader.cpp @@ -0,0 +1,58 @@ +/*************************************************************************//** + * \file SHTextureLoader.cpp + * \author Loh Xiao Qi + * \date 30 September 2022 + * \brief Library to load dds textures and custom binary format + * + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ +#include "SHpch.h" +#include "SHTextureLoader.h" + +#include + +namespace SHADE +{ + + void SHTextureLoader::LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept + { + std::ifstream file{ path.string(), std::ios::in | std::ios::binary }; + if (!file.is_open()) + { + SHLOG_ERROR("Error opening SHTexture file: {}", path.string()); + } + + auto const intBytes{ sizeof(uint32_t) }; + uint32_t mipCount; + + file.read(reinterpret_cast(&asset.numBytes), intBytes); + file.read(reinterpret_cast(&asset.width), intBytes); + file.read(reinterpret_cast(&asset.height), intBytes); + file.read(reinterpret_cast(&asset.format), sizeof(SHTexture::TextureFormat)); + + file.read(reinterpret_cast(&mipCount), intBytes); + std::vector mips(mipCount); + file.read(reinterpret_cast(mips.data()), intBytes * mipCount); + + auto pixel = new SHTexture::PixelChannel[asset.numBytes]; + file.read(reinterpret_cast(pixel), asset.numBytes); + + asset.mipOffsets = std::move(mips); + asset.pixelData = std::move(pixel); + + asset.compiled = true; + file.close(); + } + + SHAssetData* SHTextureLoader::Load(AssetPath path) + { + auto result = new SHTextureAsset(); + + LoadSHTexture(path, *result); + + return result; + } +} diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.h b/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextureLoader.h similarity index 65% rename from SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.h rename to SHADE_Engine/src/Assets/Libraries/Loaders/SHTextureLoader.h index 52980084..00b060ec 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.h +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHTextureLoader.h @@ -1,9 +1,8 @@ /*************************************************************************//** - * \file SHTextureCompiler.h + * \file SHTextureLoader.h * \author Loh Xiao Qi * \date 30 September 2022 - * \brief Library to write data in SHTextureAsset into binary file for - * faster loading in the future + * \brief Library to load dds textures and custom binary format * * * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or @@ -12,13 +11,15 @@ *****************************************************************************/ #pragma once -#include "Assets/Asset Types/SHTextureAsset.h" #include "Assets/SHAssetMacros.h" +#include "Assets/Asset Types/SHTextureAsset.h" +#include "SHAssetLoader.h" namespace SHADE { - struct SHTextureCompiler + class SHTextureLoader : public SHAssetLoader { - static std::string CompileTextureBinary(SHTextureAsset const& asset, AssetPath path); + void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept; + SHAssetData* Load(AssetPath path) override; }; -} \ No newline at end of file +} diff --git a/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.h b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.h deleted file mode 100644 index 83755b4c..00000000 --- a/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.h +++ /dev/null @@ -1,36 +0,0 @@ -/*************************************************************************//** - * \file SHAssimpLibrary.h - * \author Loh Xiao Qi - * \date October 2022 - * \brief - * - * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or - * disclosure of this file or its contents without the prior written consent - * of DigiPen Institute of Technology is prohibited. - *****************************************************************************/ - -#pragma once -#include -#include -#include -#include "../SHAssetMacros.h" -#include "../Asset Types/SHMeshAsset.h" -#include "../Asset Types/SHAnimationAsset.h" - -namespace SHADE -{ - class SHAssimpLibrary - { - private: - using MeshVectorRef = std::vector&; - using AnimVectorRef = std::vector&; - - static Assimp::Importer aiImporter; - static void ProcessNode(aiNode const& node, aiScene const& scene,MeshVectorRef meshes) noexcept; - static void ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept; - static SHMeshAsset* ProcessMesh(aiMesh const& mesh) noexcept; - - public: - static void LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept; - }; -} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp b/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp deleted file mode 100644 index 2346714e..00000000 --- a/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/*************************************************************************//** - * \file SHMeshCompiler.cpp - * \author Loh Xiao Qi - * \date 30 September 2022 - * \brief Library to write data in SHMeshAsset into binary file for faster - * loading in the future - * - * - * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or - * disclosure of this file or its contents without the prior written consent - * of DigiPen Institute of Technology is prohibited. - *****************************************************************************/ -#include "SHpch.h" -#include "SHMeshCompiler.h" -#include "Graphics/MiddleEnd/Meshes/SHMeshData.h" - -#include - -std::string SHADE::SHMeshCompiler::CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept -{ - std::string newPath{ path.string() }; - newPath = newPath.substr(0, newPath.find_last_of('/') + 1); - newPath += asset.header.name + MESH_EXTENSION.data(); - - std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc }; - if (!file.is_open()) - { - SHLOG_ERROR("Unable to open file for writing mesh file: {}", path.string()); - } - - file.write( - reinterpret_cast(&(asset.header.vertexCount)), - sizeof(uint32_t) - ); - - file.write( - reinterpret_cast(&(asset.header.indexCount)), - sizeof(uint32_t) - ); - - auto const vertexVec3Byte {sizeof(SHVec3) * asset.header.vertexCount}; - auto const vertexVec2Byte {sizeof(SHVec2) * asset.header.vertexCount}; - - file.write( - reinterpret_cast(asset.vertexPosition.data()), - vertexVec3Byte - ); - - file.write( - reinterpret_cast(asset.vertexTangent.data()), - vertexVec3Byte - ); - - file.write( - reinterpret_cast(asset.vertexNormal.data()), - vertexVec3Byte - ); - - file.write( - reinterpret_cast(asset.texCoords.data()), - vertexVec2Byte - ); - - file.write( - reinterpret_cast(asset.indices.data()), - sizeof(uint32_t) * asset.header.indexCount - ); - - file.close(); - - return newPath; -} diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.h b/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.h deleted file mode 100644 index a8ce67be..00000000 --- a/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.h +++ /dev/null @@ -1,26 +0,0 @@ -/*************************************************************************//** - * \file SHMeshCompiler.h - * \author Loh Xiao Qi - * \date 30 September 2022 - * \brief Library to write data in SHMeshAsset into binary file for faster - * loading in the future - * - * - * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or - * disclosure of this file or its contents without the prior written consent - * of DigiPen Institute of Technology is prohibited. - *****************************************************************************/ -#pragma once - -#include "../Asset Types/SHMeshAsset.h" -#include "../SHAssetMacros.h" - -namespace SHADE -{ - class SHMeshCompiler - { - private: - public: - static std::string CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept; - }; -} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.cpp b/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.cpp deleted file mode 100644 index 49de6b5c..00000000 --- a/SHADE_Engine/src/Assets/Libraries/SHTextureCompiler.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/*************************************************************************//** - * \file SHTextureCompiler.cpp - * \author Loh Xiao Qi - * \date 30 September 2022 - * \brief Library to write data in SHTextureAsset into binary file for - * faster loading in the future - * - * - * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or - * disclosure of this file or its contents without the prior written consent - * of DigiPen Institute of Technology is prohibited. - *****************************************************************************/ -#include "SHpch.h" -#include "SHTextureCompiler.h" - -#include - -namespace SHADE -{ - std::string SHTextureCompiler::CompileTextureBinary(SHTextureAsset const& asset, AssetPath path) - { - std::string newPath{ path.string() }; - newPath = newPath.substr(0, newPath.find_last_of('.')); - newPath += TEXTURE_EXTENSION; - - std::ofstream file{ newPath, std::ios::out | std::ios::binary }; - if (!file.is_open()) - { - SHLOG_ERROR("Unable to open file for writing texture file: {}", path.string()); - } - - auto const intBytes{sizeof(uint32_t)}; - - uint32_t mipOffsetCount{ static_cast(asset.mipOffsets.size()) }; - - file.write( - reinterpret_cast(&asset.numBytes), - intBytes - ); - - file.write( - reinterpret_cast(&asset.width), - intBytes - ); - - file.write( - reinterpret_cast(&asset.height), - intBytes - ); - - file.write( - reinterpret_cast(&asset.format), - sizeof(SHTexture::TextureFormat) - ); - - file.write( - reinterpret_cast(&mipOffsetCount), - intBytes - ); - - file.write( - reinterpret_cast(asset.mipOffsets.data()), - intBytes * asset.mipOffsets.size() - ); - - file.write( - reinterpret_cast(asset.pixelData), - asset.numBytes - ); - - file.close(); - - return newPath; - } -} diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp deleted file mode 100644 index 8b986524..00000000 --- a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/*************************************************************************//** - * \file SHTextureLoader.cpp - * \author Loh Xiao Qi - * \date 30 September 2022 - * \brief Library to load dds textures and custom binary format - * - * - * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or - * disclosure of this file or its contents without the prior written consent - * of DigiPen Institute of Technology is prohibited. - *****************************************************************************/ -#include "SHpch.h" -#include "SHTextureLoader.h" - -namespace SHADE -{ - std::string SHTextureLoader::TinyDDSResultToString(tinyddsloader::Result value) - { - switch (value) - { - case tinyddsloader::Result::ErrorFileOpen: - return "File open err"; - case tinyddsloader::Result::ErrorRead: - return "File read err"; - case tinyddsloader::Result::ErrorMagicWord: - return "File header magic word err"; - case tinyddsloader::Result::ErrorSize: - return "File size err"; - case tinyddsloader::Result::ErrorVerify: - return "Pixel format err"; - case tinyddsloader::Result::ErrorNotSupported: - return "Unsupported format"; - case tinyddsloader::Result::ErrorInvalidData: - return "Invalid data"; - default: - return "Unknown"; - } - } - - vk::Format SHTextureLoader::ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear) - { - switch (format) - { - case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm: - case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm_SRGB: - return isLinear ? vk::Format::eBc1RgbaUnormBlock : vk::Format::eBc1RgbaSrgbBlock; - case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm: - case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm_SRGB: - return isLinear ? vk::Format::eBc2UnormBlock : vk::Format::eBc2SrgbBlock; - case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm: - case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm_SRGB: - return isLinear ? vk::Format::eBc3UnormBlock : vk::Format::eBc3SrgbBlock; - case tinyddsloader::DDSFile::DXGIFormat::BC5_UNorm: - case tinyddsloader::DDSFile::DXGIFormat::BC5_SNorm: - return isLinear ? vk::Format::eBc5UnormBlock : vk::Format::eBc5SnormBlock; - case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm: - case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm_SRGB: - return isLinear ? vk::Format::eR8G8B8A8Unorm : vk::Format::eR8G8B8A8Srgb; - case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_SNorm: - return vk::Format::eR8G8B8A8Snorm; - case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm: - case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm_SRGB: - return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8A8Srgb; - case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm: - case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm_SRGB: - return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8Srgb; - default: - throw std::runtime_error("Unsupported DDS format."); - } - } - - void SHTextureLoader::LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept - { - tinyddsloader::Result loadResult = tinyddsloader::Result::Success; - tinyddsloader::DDSFile file; - loadResult = file.Load(path.string().c_str()); - if (loadResult != tinyddsloader::Result::Success) - { - SHLOG_ERROR("Unable to load Texture file: {} at {}", TinyDDSResultToString(loadResult), path.string()); - } - - size_t totalBytes{ 0 }; - - std::vector mipOff(file.GetMipCount()); - - for (size_t i{0}; i < file.GetMipCount(); ++i) - { - mipOff[i] = static_cast(totalBytes); - totalBytes += file.GetImageData(static_cast(i), 0)->m_memSlicePitch; - } - - SHTexture::PixelChannel* pixel = new SHTexture::PixelChannel[totalBytes]; - std::memcpy(pixel, file.GetImageData()->m_mem, totalBytes); - //pixel = std::move(reinterpret_cast(file.GetDDSData())); - - asset.name = path.stem().string(); - asset.compiled = false; - asset.numBytes = static_cast(totalBytes); - asset.width = file.GetWidth(); - asset.height = file.GetHeight(); - asset.format = ddsLoaderToVkFormat(file.GetFormat(), true); - asset.mipOffsets = std::move(mipOff); - asset.pixelData = std::move(pixel); - } - - void SHTextureLoader::LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept - { - std::ifstream file{path.string(), std::ios::in | std::ios::binary}; - if (!file.is_open()) - { - SHLOG_ERROR("Error opening SHTexture file: {}", path.string()); - } - - auto const intBytes{ sizeof(uint32_t) }; - uint32_t mipCount; - - file.read(reinterpret_cast(&asset.numBytes), intBytes); - file.read(reinterpret_cast(&asset.width), intBytes); - file.read(reinterpret_cast(&asset.height), intBytes); - file.read(reinterpret_cast(&asset.format), sizeof(SHTexture::TextureFormat)); - - file.read(reinterpret_cast(&mipCount), intBytes); - std::vector mips(mipCount); - file.read(reinterpret_cast(mips.data()), intBytes * mipCount); - - auto pixel = new SHTexture::PixelChannel[asset.numBytes]; - file.read(reinterpret_cast(pixel), asset.numBytes); - - asset.mipOffsets = std::move(mips); - asset.pixelData = std::move( pixel ); - - asset.compiled = true; - file.close(); - } - - SHAssetData* SHTextureLoader::Load(AssetPath path) - { - auto result = new SHTextureAsset(); - - LoadImageAsset(path, *result); - - return result; - } - - void SHTextureLoader::LoadImageAsset(AssetPath path, SHTextureAsset& asset) - { - if (path.extension().string() == DDS_EXTENSION) - { - LoadTinyDDS(path, asset); - } - else if (path.extension().string() == TEXTURE_EXTENSION) - { - LoadSHTexture(path, asset); - } - } -} diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h deleted file mode 100644 index 8bdf91b1..00000000 --- a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************//** - * \file SHTextureLoader.h - * \author Loh Xiao Qi - * \date 30 September 2022 - * \brief Library to load dds textures and custom binary format - * - * - * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or - * disclosure of this file or its contents without the prior written consent - * of DigiPen Institute of Technology is prohibited. - *****************************************************************************/ -#pragma once -#define TINYDDSLOADER_IMPLEMENTATION - -#include "../SHAssetMacros.h" -#include "../Asset Types/SHTextureAsset.h" -#include "tinyddsloader.h" -#include "SHAssetLoader.h" - -namespace SHADE -{ - class SHTextureLoader : public SHAssetLoader - { - private: - std::string TinyDDSResultToString(tinyddsloader::Result value); - vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear); - - void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept; - public: - void LoadImageAsset(AssetPath paths, SHTextureAsset& image); - void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept; - SHAssetData* Load(AssetPath path) override; - }; -} diff --git a/SHADE_Engine/src/Assets/SHAssetMacros.h b/SHADE_Engine/src/Assets/SHAssetMacros.h index 0fdfa04e..1df4e30b 100644 --- a/SHADE_Engine/src/Assets/SHAssetMacros.h +++ b/SHADE_Engine/src/Assets/SHAssetMacros.h @@ -42,20 +42,14 @@ constexpr std::string_view ASSET_META_VER { "1.0" }; // Asset type enum enum class AssetType : AssetTypeMeta { - INVALID = 0, - AUDIO = 1, + INVALID, SHADER, - MATERIAL, - IMAGE, - TEXTURE, - MESH, - SCRIPT, - SCENE, - PREFAB, - AUDIO_WAV, - DDS, + SHADER_BUILT_IN, + TEXTURE, + MESH, MAX_COUNT }; +constexpr size_t TYPE_COUNT{ static_cast(AssetType::MAX_COUNT) }; //Directory #ifdef _PUBLISH @@ -67,37 +61,55 @@ constexpr std::string_view ASSET_ROOT {"../../Assets"}; // ASSET EXTENSIONS constexpr std::string_view META_EXTENSION {".shmeta"}; -constexpr std::string_view IMAGE_EXTENSION {".png"}; constexpr std::string_view AUDIO_EXTENSION {".ogg"}; constexpr std::string_view AUDIO_WAV_EXTENSION {".wav"}; -constexpr std::string_view SHADER_EXTENSION {".glsl"}; +constexpr std::string_view SHADER_EXTENSION{ ".shshader" }; +constexpr std::string_view SHADER_BUILT_IN_EXTENSION{".shshaderb"}; constexpr std::string_view SCRIPT_EXTENSION {".cs"}; -constexpr std::string_view SCENE_EXTENSION {".SHADE"}; -constexpr std::string_view PREFAB_EXTENSION {".SHPrefab"}; -constexpr std::string_view MATERIAL_EXTENSION {".SHMat"}; +constexpr std::string_view SCENE_EXTENSION {".shade"}; +constexpr std::string_view PREFAB_EXTENSION {".shprefab"}; +constexpr std::string_view MATERIAL_EXTENSION {".shmat"}; constexpr std::string_view TEXTURE_EXTENSION {".shtex"}; -constexpr std::string_view DDS_EXTENSION {".dds"}; -constexpr std::string_view FBX_EXTENSION {".fbx"}; -constexpr std::string_view GLTF_EXTENSION {".gltf"}; constexpr std::string_view MESH_EXTENSION {".shmesh"}; constexpr std::string_view EXTENSIONS[] = { AUDIO_EXTENSION, SHADER_EXTENSION, + SHADER_BUILT_IN_EXTENSION, MATERIAL_EXTENSION, - IMAGE_EXTENSION, TEXTURE_EXTENSION, - DDS_EXTENSION, MESH_EXTENSION, SCRIPT_EXTENSION, SCENE_EXTENSION, PREFAB_EXTENSION, AUDIO_WAV_EXTENSION, +}; + +// EXTERNAL EXTENSIONS +constexpr std::string_view GLSL_EXTENSION{ ".glsl" }; +constexpr std::string_view DDS_EXTENSION{ ".dds" }; +constexpr std::string_view FBX_EXTENSION{ ".fbx" }; +constexpr std::string_view GLTF_EXTENSION{ ".gltf" }; + +constexpr std::string_view EXTERNALS[] = { + GLSL_EXTENSION, + DDS_EXTENSION, FBX_EXTENSION, GLTF_EXTENSION }; -constexpr size_t TYPE_COUNT {static_cast(AssetType::MAX_COUNT) }; +// SHADER IDENTIFIERS +constexpr std::string_view VERTEX_SHADER{ "_VS" }; +constexpr std::string_view FRAGMENT_SHADER{ "_FS" }; +constexpr std::string_view COMPUTER_SHADER{ "_CS" }; + +constexpr std::string_view SHADER_IDENTIFIERS[] = { + VERTEX_SHADER, + FRAGMENT_SHADER, + COMPUTER_SHADER +}; + +constexpr size_t SHADER_TYPE_MAX_COUNT{ 3 }; // Error flags constexpr std::string_view FILE_NOT_FOUND_ERR {"FILE NOT FOUND"}; diff --git a/SHADE_Engine/src/Assets/SHAssetManager.cpp b/SHADE_Engine/src/Assets/SHAssetManager.cpp index 3032ba51..228f3fdc 100644 --- a/SHADE_Engine/src/Assets/SHAssetManager.cpp +++ b/SHADE_Engine/src/Assets/SHAssetManager.cpp @@ -14,12 +14,13 @@ #include "SHAssetMetaHandler.h" #include "Filesystem/SHFileSystem.h" -#include "Libraries/SHAssimpLibrary.h" -#include "Libraries/SHMeshLoader.h" -#include "Libraries/SHTextureLoader.h" +#include "Libraries/Loaders/SHMeshLoader.h" +#include "Libraries/Loaders/SHTextureLoader.h" +#include "Libraries/Loaders/SHShaderSourceLoader.h" -#include "Libraries/SHMeshCompiler.h" -#include "Libraries/SHTextureCompiler.h" +#include "Libraries/Compilers/SHMeshCompiler.h" +#include "Libraries/Compilers/SHTextureCompiler.h" +#include "Libraries/Compilers/SHShaderSourceCompiler.h" namespace SHADE { @@ -44,7 +45,13 @@ namespace SHADE result |= unique; - while (result == 0) + while (result == 0 || + std::ranges::any_of( + assetCollection.begin(), + assetCollection.end(), + [result](SHAsset const& asset) { return asset.id == result; } + ) + ) { result = GenerateAssetID(type); } @@ -64,7 +71,20 @@ namespace SHADE // TODO } - AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept + void SHAssetManager::Exit() noexcept + { + for (auto const& loader : loaders) + { + delete loader; + } + + for (auto const& data : assetData) + { + delete data.second; + } + } + + AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept { if (!IsRecognised(path.extension().string().c_str())) { @@ -91,17 +111,10 @@ namespace SHADE switch(type) { - case AssetType::SCENE: - folder = "scenes/"; - break; - - case AssetType::PREFAB: - folder = "prefabs/"; - break; - - case AssetType::MATERIAL: - folder = "materials/"; - break; + case AssetType::SHADER: + case AssetType::SHADER_BUILT_IN: + folder = "Shaders/"; + break; default: folder = "/"; @@ -206,7 +219,56 @@ namespace SHADE } - bool SHAssetManager::IsRecognised(char const* ext) noexcept + std::vector SHAssetManager::GetAllDataOfType(AssetType type) noexcept + { + auto const toRetrieve = GetAllRecordOfType(type); + std::vector result; + result.reserve(toRetrieve.size()); + for (auto const& get : toRetrieve) + { + result.push_back(LoadData(get)); + } + + return result; + } + + std::vector SHAssetManager::GetAllRecordOfType(AssetType type) noexcept + { + std::vector result; + for (auto const& asset : assetCollection) + { + if (asset.type == type) + { + result.push_back(asset); + } + } + + return result; + } + + AssetID SHAssetManager::CompileAsset(AssetPath path) noexcept + { + SHAsset newAsset + { + .name = path.stem().string(), + .location = 0 + }; + + auto const ext{ path.extension().string() }; + if (ext == GLSL_EXTENSION.data()) + { + newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value(); + newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN); + newAsset.type = AssetType::SHADER_BUILT_IN; + } + + assetCollection.push_back(newAsset); + SHAssetMetaHandler::WriteMetaData(newAsset); + + return newAsset.id; + } + + bool SHAssetManager::IsRecognised(char const* ext) noexcept { for (auto const& e : EXTENSIONS) { @@ -227,23 +289,82 @@ namespace SHADE result.type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string()); result.id = GenerateAssetID(result.type); result.path = path; + result.location = 0; return result; } - void SHAssetManager::InitLoaders() noexcept + void SHAssetManager::CompileAll() noexcept + { + std::vector paths; + + for (auto const& dir : std::filesystem::recursive_directory_iterator{ ASSET_ROOT }) + { + if (dir.is_regular_file()) + { + for (auto const& ext : EXTERNALS) + { + if (dir.path().extension().string() == ext.data()) + { + paths.push_back(dir.path()); + } + } + } + } + + for (auto const& path : paths) + { + SHAsset newAsset + { + .name = path.stem().string(), + .location = 0 + }; + + auto const ext{ path.extension().string() }; + if (ext == GLSL_EXTENSION.data()) + { + newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value(); + newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN); + newAsset.type = AssetType::SHADER_BUILT_IN; + } + else if (ext == DDS_EXTENSION.data()) + { + newAsset.path = SHTextureCompiler::CompileTextureAsset(path).value(); + newAsset.id = GenerateAssetID(AssetType::TEXTURE); + newAsset.type = AssetType::TEXTURE; + } + else if (ext == GLTF_EXTENSION.data() || ext == FBX_EXTENSION.data()) + { + std::vector meshes; + std::vector anims; + SHMeshCompiler::LoadFromFile(path, meshes, anims); + + for (auto const& mesh : meshes) + { + SHAsset meshAsset{ + .name = mesh->header.name, + .location = 0 + }; + meshAsset.path = SHMeshCompiler::CompileMeshBinary(*mesh, path).value(); + meshAsset.id = GenerateAssetID(AssetType::MESH); + meshAsset.type = AssetType::MESH; + assetCollection.push_back(meshAsset); + SHAssetMetaHandler::WriteMetaData(meshAsset); + } + continue; + } + + assetCollection.push_back(newAsset); + SHAssetMetaHandler::WriteMetaData(newAsset); + } + } + + void SHAssetManager::InitLoaders() noexcept { - loaders[static_cast(AssetType::AUDIO)] = nullptr; - loaders[static_cast(AssetType::SHADER)] = nullptr; - loaders[static_cast(AssetType::MATERIAL)] = nullptr; - loaders[static_cast(AssetType::IMAGE)] = dynamic_cast(new SHTextureLoader()); - loaders[static_cast(AssetType::TEXTURE)] = nullptr; - loaders[static_cast(AssetType::MESH)] = dynamic_cast(new SHMeshLoader()); - loaders[static_cast(AssetType::SCRIPT)] = nullptr; - loaders[static_cast(AssetType::SCENE)] = nullptr; - loaders[static_cast(AssetType::PREFAB)] = nullptr; - loaders[static_cast(AssetType::AUDIO_WAV)] = nullptr; - loaders[static_cast(AssetType::DDS)] = nullptr; + loaders[static_cast(AssetType::SHADER)] = dynamic_cast(new SHShaderSourceLoader()); + loaders[static_cast(AssetType::SHADER_BUILT_IN)] = loaders[static_cast(AssetType::SHADER)]; + loaders[static_cast(AssetType::TEXTURE)] = dynamic_cast(new SHTextureLoader()); + loaders[static_cast(AssetType::MESH)] = dynamic_cast(new SHMeshLoader()); } /**************************************************************************** @@ -251,6 +372,7 @@ namespace SHADE ****************************************************************************/ void SHAssetManager::Load() noexcept { + //CompileAll(); InitLoaders(); BuildAssetCollection(); //LoadAllData(); diff --git a/SHADE_Engine/src/Assets/SHAssetManager.h b/SHADE_Engine/src/Assets/SHAssetManager.h index 9ee7ab92..bc6f8878 100644 --- a/SHADE_Engine/src/Assets/SHAssetManager.h +++ b/SHADE_Engine/src/Assets/SHAssetManager.h @@ -12,7 +12,7 @@ #include "tinyddsloader.h" #include "SHAsset.h" #include "Asset Types/SHAssetData.h" -#include "Libraries/SHAssetLoader.h" +#include "Assets/Libraries/Loaders/SHAssetLoader.h" #include #include "SH_API.h" @@ -37,6 +37,8 @@ namespace SHADE static void Unload() noexcept; static void Unload(AssetID assetId) noexcept; + static void Exit() noexcept; + /**************************************************************************** * \brief Load all resources that are in the folder ****************************************************************************/ @@ -77,21 +79,24 @@ namespace SHADE template static std::enable_if_t, T const* const> GetData(AssetID id) noexcept; + + static std::vector GetAllDataOfType(AssetType type) noexcept; + static std::vector GetAllRecordOfType(AssetType type) noexcept; + + static AssetID CompileAsset(AssetPath path) noexcept; + private: - /**************************************************************************** - * \brief Load resource data into memory - ****************************************************************************/ + + static void InitLoaders() noexcept; static void LoadAllData() noexcept; - static SHAssetData* LoadData(SHAsset const& asset) noexcept; - inline static void BuildAssetCollection() noexcept; static bool IsRecognised(char const*) noexcept; static SHAsset CreateAssetFromPath(AssetPath path) noexcept; - static void InitLoaders() noexcept; + static void CompileAll() noexcept; static FMOD::System* audioSystem; static std::unordered_map* audioSoundList; diff --git a/SHADE_Engine/src/Camera/SHCameraComponent.cpp b/SHADE_Engine/src/Camera/SHCameraComponent.cpp index 5d49c887..31afe2ac 100644 --- a/SHADE_Engine/src/Camera/SHCameraComponent.cpp +++ b/SHADE_Engine/src/Camera/SHCameraComponent.cpp @@ -4,6 +4,7 @@ #include "SHCameraSystem.h" #include "ECS_Base/Managers/SHSystemManager.h" #include "Math/Transform/SHTransformComponent.h" +#include "Math/SHMath.h" namespace SHADE { @@ -28,7 +29,7 @@ namespace SHADE { auto transform = SHComponentManager::GetComponent(GetEID()); SHVec3 rotation = transform->GetWorldRotation(); - transform->SetWorldRotation(SHVec3{rotation.x,yaw, rotation.z}); + transform->SetWorldRotation(SHVec3{rotation.x,SHMath::DegreesToRadians(yaw), rotation.z}); } dirtyView = true; } @@ -40,7 +41,7 @@ namespace SHADE { auto transform = SHComponentManager::GetComponent(GetEID()); SHVec3 rotation = transform->GetWorldRotation(); - transform->SetWorldRotation(SHVec3{ pitch,rotation.y, rotation.z }); + transform->SetWorldRotation(SHVec3{ SHMath::DegreesToRadians(pitch),rotation.y, rotation.z }); } dirtyView = true; } @@ -52,7 +53,7 @@ namespace SHADE { auto transform = SHComponentManager::GetComponent(GetEID()); SHVec3 rotation = transform->GetWorldRotation(); - transform->SetWorldRotation(SHVec3{ rotation.x,rotation.y, roll}); + transform->SetWorldRotation(SHVec3{ rotation.x,rotation.y, SHMath::DegreesToRadians(roll)}); } dirtyView = true; } @@ -102,7 +103,7 @@ namespace SHADE } dirtyView = true; } - void SHCameraComponent::SetPosition(SHVec3& pos) noexcept + void SHCameraComponent::SetPosition(SHVec3 pos) noexcept { this->position = pos; if (SHComponentManager::HasComponent(GetEID())) @@ -145,6 +146,17 @@ namespace SHADE dirtyProj = true; } + void SHCameraComponent::SetIsPerspective(bool persp) noexcept + { + this->perspProj = persp; + dirtyProj = true; + } + + SHVec3 SHCameraComponent::GetPosition() const noexcept + { + return position; + } + float SHCameraComponent::GetYaw() const noexcept { return yaw; @@ -158,6 +170,27 @@ namespace SHADE { return roll; } + + float SHCameraComponent::GetWidth() const noexcept + { + return width; + } + + float SHCameraComponent::GetHeight() const noexcept + { + return height; + } + + float SHCameraComponent::GetNear() const noexcept + { + return zNear; + } + + float SHCameraComponent::GetFar() const noexcept + { + return zFar; + } + float SHCameraComponent::GetAspectRatio() const noexcept { return width/height; @@ -168,6 +201,11 @@ namespace SHADE return fov; } + bool SHCameraComponent::GetIsPerspective() const noexcept + { + return perspProj; + } + const SHMatrix& SHCameraComponent::GetViewMatrix() const noexcept { return viewMatrix; @@ -178,12 +216,32 @@ namespace SHADE return projMatrix; } - void SHCameraComponent::SetMainCamera(size_t directorCameraIndex) noexcept - { - auto system = SHSystemManager::GetSystem(); - system->GetDirector(directorCameraIndex)->SetMainCamera(*this); - } + //void SHCameraComponent::SetMainCamera(size_t directorCameraIndex) noexcept + //{ + // auto system = SHSystemManager::GetSystem(); + // system->GetDirector(directorCameraIndex)->SetMainCamera(*this); + //} +}//namespace SHADE + + +RTTR_REGISTRATION +{ + using namespace SHADE; + using namespace rttr; + + registration::class_("Camera Component") + .property("Position", &SHCameraComponent::GetPosition, select_overload(&SHCameraComponent::SetPosition)) + .property("Pitch", &SHCameraComponent::GetPitch, &SHCameraComponent::SetPitch) + .property("Yaw", &SHCameraComponent::GetYaw, &SHCameraComponent::SetYaw) + .property("Roll", &SHCameraComponent::GetRoll, &SHCameraComponent::SetRoll) + .property("Width", &SHCameraComponent::GetWidth, &SHCameraComponent::SetWidth) + .property("Height", &SHCameraComponent::GetHeight, &SHCameraComponent::SetHeight) + .property("Near", &SHCameraComponent::GetNear, &SHCameraComponent::SetNear) + .property("Far", &SHCameraComponent::GetFar, &SHCameraComponent::SetFar) + .property("Perspective", &SHCameraComponent::GetIsPerspective, &SHCameraComponent::SetIsPerspective); + + } diff --git a/SHADE_Engine/src/Camera/SHCameraComponent.h b/SHADE_Engine/src/Camera/SHCameraComponent.h index 1149b1e1..f5e08af4 100644 --- a/SHADE_Engine/src/Camera/SHCameraComponent.h +++ b/SHADE_Engine/src/Camera/SHCameraComponent.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "ECS_Base/Components/SHComponent.h" #include "Math/Vector/SHVec3.h" #include "Math/SHMatrix.h" @@ -50,37 +52,44 @@ namespace SHADE void SetPositionY(float y) noexcept; void SetPositionZ(float z) noexcept; void SetPosition(float x, float y, float z) noexcept; - void SetPosition(SHVec3& pos) noexcept; + void SetPosition(SHVec3 pos) noexcept; void SetWidth(float width) noexcept; void SetHeight(float height) noexcept; void SetNear(float znear) noexcept; void SetFar(float zfar) noexcept; void SetFOV(float fov) noexcept; + void SetIsPerspective(bool persp) noexcept; - + SHVec3 GetPosition() const noexcept; float GetYaw() const noexcept; float GetPitch() const noexcept; float GetRoll() const noexcept; + float GetWidth() const noexcept; + float GetHeight() const noexcept; + float GetNear() const noexcept; + float GetFar() const noexcept; + float GetAspectRatio() const noexcept; float GetFOV() const noexcept; + bool GetIsPerspective() const noexcept; const SHMatrix& GetViewMatrix() const noexcept; const SHMatrix& GetProjMatrix() const noexcept; - void SetMainCamera(size_t cameraDirectorIndex = 0) noexcept; + //void SetMainCamera(size_t cameraDirectorIndex = 0) noexcept; float movementSpeed; SHVec3 turnSpeed; - + RTTR_ENABLE() protected: - + }; diff --git a/SHADE_Engine/src/Camera/SHCameraSystem.cpp b/SHADE_Engine/src/Camera/SHCameraSystem.cpp index 0d86c17a..609805f8 100644 --- a/SHADE_Engine/src/Camera/SHCameraSystem.cpp +++ b/SHADE_Engine/src/Camera/SHCameraSystem.cpp @@ -154,7 +154,7 @@ namespace SHADE SHVec3 view, right, UP; - //ClampCameraRotation(camera); + ClampCameraRotation(camera); GetCameraAxis(camera, view, right, UP); @@ -221,8 +221,8 @@ namespace SHADE SHVec3 up = { 0.0f,1.0f,0.0f }; + target = SHVec3::RotateX(target, SHMath::DegreesToRadians(camera.pitch)); target = SHVec3::RotateY(target, SHMath::DegreesToRadians(camera.yaw)); - target =SHVec3::RotateX(target, SHMath::DegreesToRadians(camera.pitch)); target += camera.position; ////SHVec3::RotateZ(target, SHMath::DegreesToRadians(camera.roll)); diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index adabb87a..44799c17 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -207,6 +207,10 @@ namespace SHADE { if (!component) return; + + // Get transform component for extrapolating relative sizes + auto* transformComponent = SHComponentManager::GetComponent(component->GetEID()); + const auto componentType = rttr::type::get(*component); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }); ImGui::SameLine(); @@ -221,28 +225,41 @@ namespace SHADE for (int i{}; i < size; ++i) { ImGui::PushID(i); - SHCollider& collider = component->GetCollider(i); + SHCollider* collider = &component->GetCollider(i); auto cursorPos = ImGui::GetCursorPos(); - if (collider.GetType() == SHCollider::Type::BOX) + if (collider->GetType() == SHCollider::Type::BOX) { SHEditorWidgets::BeginPanel( std::format("{} Box Collider #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); - auto box = reinterpret_cast(collider.GetShape()); - SHEditorWidgets::DragVec3("Half Extents", { "X", "Y", "Z" }, [box] {return box->GetHalfExtents(); }, [box](SHVec3 const& vec) {box->SetHalfExtents(vec);}); + auto box = reinterpret_cast(collider->GetShape()); + SHEditorWidgets::DragVec3 + ( + "Half Extents", { "X", "Y", "Z" }, + [box, transformComponent] { return (transformComponent->GetWorldScale() * 2.0f) * box->GetHalfExtents(); }, + [collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); }); } - else if (collider.GetType() == SHCollider::Type::SPHERE) + else if (collider->GetType() == SHCollider::Type::SPHERE) { SHEditorWidgets::BeginPanel(std::format("{} Sphere Collider #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); - auto sphere = reinterpret_cast(collider.GetShape()); - SHEditorWidgets::DragFloat("Radius", [sphere] {return sphere->GetRadius(); }, [sphere](float const& value) {sphere->SetRadius(value);}); + auto sphere = reinterpret_cast(collider->GetShape()); + SHEditorWidgets::DragFloat + ( + "Radius", + [sphere, transformComponent] + { + const SHVec3& TF_WORLD_SCALE = transformComponent->GetWorldScale(); + const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z }); + return sphere->GetRadius() / MAX_SCALE; + }, + [collider](float const& value) { collider->SetBoundingSphere(value);}); } - else if (collider.GetType() == SHCollider::Type::CAPSULE) + else if (collider->GetType() == SHCollider::Type::CAPSULE) { } { SHEditorWidgets::BeginPanel("Offset", { ImGui::GetContentRegionAvail().x, 30.0f }); - SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider.GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider.SetPositionOffset(vec); }); + SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider->GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider->SetPositionOffset(vec); }); SHEditorWidgets::EndPanel(); } if(ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data())) diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index 511f8642..8b532b7b 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -20,6 +20,7 @@ #include "AudioSystem/SHAudioSystem.h" #include "Physics/Components/SHRigidBodyComponent.h" #include "Physics/Components/SHColliderComponent.h" +#include "Camera/SHCameraComponent.h" namespace SHADE { @@ -35,6 +36,23 @@ namespace SHADE return selected; } + template , bool> = true, std::enable_if_t, bool> = true> + bool DrawAddComponentWithEnforcedComponentButton(EntityID const& eid) + { + bool selected = false; + if (!SHComponentManager::HasComponent(eid)) + { + if(selected = ImGui::Selectable(std::format("Add {}", rttr::type::get().get_name().data()).data()); selected) + { + if(SHComponentManager::GetComponent_s(eid) == nullptr) + SHComponentManager::AddComponent(eid); + + SHComponentManager::AddComponent(eid); + } + } + return selected; + } + SHEditorInspector::SHEditorInspector() :SHEditorWindow("Inspector", ImGuiWindowFlags_MenuBar) { @@ -82,6 +100,10 @@ namespace SHADE { DrawComponent(rigidbodyComponent); } + if (auto cameraComponent = SHComponentManager::GetComponent_s(eid)) + { + DrawComponent(cameraComponent); + } ImGui::Separator(); // Render Scripts SHScriptEngine* scriptEngine = static_cast(SHSystemManager::GetSystem()); @@ -90,19 +112,15 @@ namespace SHADE if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data())) { DrawAddComponentButton(eid); - DrawAddComponentButton(eid); - DrawAddComponentButton(eid); - if (!SHComponentManager::HasComponent(eid)) - { - if (ImGui::Selectable(std::format("Add {}", rttr::type::get().get_name().data()).data())) - { - if (SHComponentManager::GetComponent_s(eid) == nullptr) - { - SHComponentManager::AddComponent(eid); - } - SHComponentManager::AddComponent(eid); - } - } + DrawAddComponentButton(eid); + + // Components that require Transforms + + DrawAddComponentWithEnforcedComponentButton(eid); + DrawAddComponentWithEnforcedComponentButton(eid); + DrawAddComponentWithEnforcedComponentButton(eid); + + ImGui::EndMenu(); } diff --git a/SHADE_Engine/src/Editor/SHEditorUI.cpp b/SHADE_Engine/src/Editor/SHEditorUI.cpp index 7107778d..0137b951 100644 --- a/SHADE_Engine/src/Editor/SHEditorUI.cpp +++ b/SHADE_Engine/src/Editor/SHEditorUI.cpp @@ -54,7 +54,7 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ bool SHEditorUI::CollapsingHeader(const std::string& title) { - return ImGui::CollapsingHeader(title.c_str()); + return ImGui::CollapsingHeader(title.c_str(), ImGuiTreeNodeFlags_DefaultOpen); } void SHEditorUI::SameLine() diff --git a/SHADE_Engine/src/Events/SHEventDefines.h b/SHADE_Engine/src/Events/SHEventDefines.h index fc9f41e1..804fbfec 100644 --- a/SHADE_Engine/src/Events/SHEventDefines.h +++ b/SHADE_Engine/src/Events/SHEventDefines.h @@ -11,3 +11,6 @@ constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT { 2 }; constexpr SHEventIdentifier SH_COMPONENT_ADDED_EVENT { 3 }; constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT { 4 }; constexpr SHEventIdentifier SH_SCENEGRAPH_CHANGE_PARENT_EVENT { 5 }; +constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_ADDED_EVENT { 6 }; +constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_REMOVED_EVENT { 7 }; + diff --git a/SHADE_Engine/src/Events/SHEventManager.hpp b/SHADE_Engine/src/Events/SHEventManager.hpp index f511518a..490c6b10 100644 --- a/SHADE_Engine/src/Events/SHEventManager.hpp +++ b/SHADE_Engine/src/Events/SHEventManager.hpp @@ -12,6 +12,7 @@ #include "SHpch.h" #include "SHEvent.h" #include "SHEventReceiver.h" +#include "SH_API.h" /****************************************************************************** INSTRUCTIONS FOR USE: @@ -67,7 +68,7 @@ namespace SHADE using EventManagerListener = std::function; - class SHEventManager + class SH_API SHEventManager { private: diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp index 09fde60f..d07e0f06 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp @@ -45,16 +45,20 @@ namespace SHADE void SHBatch::Add(const SHRenderable* renderable) { + // Ignore if null + if (!renderable->GetMesh()) + return; + // Check if we have a SubBatch with the same mesh yet auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch) - { - return batch.Mesh == renderable->Mesh; - }); + { + return batch.Mesh == renderable->GetMesh(); + }); // Create one if not found if (subBatch == subBatches.end()) { - subBatches.emplace_back(renderable->Mesh); + subBatches.emplace_back(renderable->GetMesh()); subBatch = subBatches.end() - 1; } @@ -73,7 +77,7 @@ namespace SHADE // Check if we have a SubBatch with the same mesh yet auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch) { - return batch.Mesh == renderable->Mesh; + return batch.Mesh == renderable->GetMesh(); }); // Attempt to remove if it exists @@ -84,13 +88,18 @@ namespace SHADE // Check if other renderables in subBatches contain the same material instance bool matUnused = true; + + Handle matToCheck = renderable->HasMaterialChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial(); + for (const auto& sb : subBatches) + { + // Check material usage for (const auto& rendId : sb.Renderables) { auto rend = SHComponentManager::GetComponent(rendId); if (rend) { - if (rend->GetMaterial() == renderable->GetMaterial()) + if (rend->GetMaterial() == matToCheck) { matUnused = false; break; @@ -101,10 +110,15 @@ namespace SHADE SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!"); } } + } // Material is no longer in this library, so we remove it if (matUnused) - referencedMatInstances.erase(renderable->WasMaterialChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial()); + referencedMatInstances.erase(renderable->HasChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial()); + + // Mesh is no longer in this batch, so we remove the associated sub batch + if (subBatch->Renderables.empty()) + subBatches.erase(subBatch); // Mark all as dirty setAllDirtyFlags(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index cd6a0d17..35942e7e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -118,24 +118,8 @@ namespace SHADE graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); - // TODO: This is VERY temporarily here until a more solid resource management system is implemented - shaderSourceLibrary.Init("../../TempShaderFolder/"); - - shaderSourceLibrary.LoadShader(0, "TestCubeVs.glsl", SH_SHADER_TYPE::VERTEX, true); - shaderSourceLibrary.LoadShader(1, "TestCubeFs.glsl", SH_SHADER_TYPE::FRAGMENT, true); - - shaderSourceLibrary.LoadShader(2, "KirschCs.glsl", SH_SHADER_TYPE::COMPUTE, true); - shaderSourceLibrary.LoadShader(3, "PureCopyCs.glsl", SH_SHADER_TYPE::COMPUTE, true); - - shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary); - auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl"); - auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl"); - auto greyscale = shaderModuleLibrary.GetShaderModule("KirschCs.glsl"); - auto pureCopy = shaderModuleLibrary.GetShaderModule("PureCopyCs.glsl"); - cubeVS->Reflect(); - cubeFS->Reflect(); - greyscale->Reflect(); - pureCopy->Reflect(); + shaderModuleLibrary.ImportAllShaderSource(device); + shaderModuleLibrary.ReflectAllShaderModules(); } void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept @@ -190,11 +174,11 @@ namespace SHADE gBufferSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL); //// kirsch - //auto kirschShader = shaderModuleLibrary.GetShaderModule("KirschCs.glsl"); + //auto kirschShader = shaderModuleLibrary.GetShaderModule("KirschCs"); //gBufferNode->AddNodeCompute(kirschShader, { "Scene Pre-Process", "Scene" }); // copy - auto pureCopyShader = shaderModuleLibrary.GetShaderModule("PureCopyCs.glsl"); + auto pureCopyShader = shaderModuleLibrary.GetBuiltInShaderModule("PureCopy_CS"); gBufferNode->AddNodeCompute(pureCopyShader, { "Scene Pre-Process", "Scene" }); @@ -212,11 +196,10 @@ namespace SHADE worldRenderer->SetCameraDirector(cameraSystem->CreateDirector()); - auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl"); - auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl"); + auto cubeVS = shaderModuleLibrary.GetBuiltInShaderModule("TestCube_VS"); + auto cubeFS = shaderModuleLibrary.GetBuiltInShaderModule("TestCube_FS"); defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferSubpass); - } void SHGraphicsSystem::InitMiddleEnd(void) noexcept @@ -696,7 +679,7 @@ namespace SHADE auto& renderables = SHComponentManager::GetDense(); for (auto& renderable : renderables) { - if (!renderable.WasMaterialChanged()) + if (!renderable.HasChanged()) continue; // Remove from old material's SuperBatch @@ -784,5 +767,10 @@ namespace SHADE } + Handle SHGraphicsSystem::GetPrimaryRenderpass() const noexcept + { + return worldRenderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data()); + } + #pragma endregion MISC } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index ae93bd78..f657965c 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -25,7 +25,6 @@ of DigiPen Institute of Technology is prohibited. #include "ECS_Base/System/SHSystemRoutine.h" #include "Graphics/Descriptors/SHVkDescriptorPool.h" #include "Graphics/RenderGraph/SHRenderGraph.h" -#include "Graphics/MiddleEnd/Shaders/SHShaderSourceLibrary.h" #include "Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.h" #include "SHMeshLibrary.h" #include "Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.h" @@ -136,7 +135,7 @@ namespace SHADE void RemoveViewport(Handle viewport); /*-----------------------------------------------------------------------------*/ - /* Material Creation Functions */ + /* Material Functions */ /*-----------------------------------------------------------------------------*/ Handle AddMaterial(Handle vertShader, Handle fragShader, Handle subpass); void RemoveMaterial(Handle material); @@ -144,6 +143,8 @@ namespace SHADE Handle AddOrGetBaseMaterialInstance(Handle material); Handle AddMaterialInstanceCopy(Handle materialInst); void RemoveMaterialInstance(Handle materialInstance); + Handle GetDefaultMaterial() { return defaultMaterial; } + Handle GetDefaultMaterialInstance() { return AddOrGetBaseMaterialInstance(defaultMaterial); } /*-----------------------------------------------------------------------------*/ /* Mesh Registration Functions */ @@ -287,12 +288,17 @@ namespace SHADE #endif Handle GetMousePickSystem(void) const noexcept {return mousePickSystem;}; Handle GetPostOffscreenRenderSystem(void) const noexcept {return postOffscreenRender;}; + Handle GetPrimaryRenderpass() const noexcept; //SHRenderGraph const& GetRenderGraph(void) const noexcept; //Handle GetRenderPass() const { return renderPass; } private: + /*-----------------------------------------------------------------------------*/ + /* Constants */ + /*-----------------------------------------------------------------------------*/ + static constexpr std::string_view G_BUFFER_RENDER_GRAPH_NODE_NAME = "G-Buffer"; /*-----------------------------------------------------------------------------*/ /* Data Members */ @@ -319,7 +325,7 @@ namespace SHADE SHTextureLibrary texLibrary; SHSamplerCache samplerCache; SHMaterialInstanceCache materialInstanceCache; - // Viewports + // Viewports #ifdef SHEDITOR Handle editorViewport; Handle editorRenderer; @@ -339,9 +345,7 @@ namespace SHADE // Temp Cameras Handle worldCamera; Handle screenCamera; - - // TODO: Temporary only until resource library from Xiao Qi is implemented - SHShaderSourceLibrary shaderSourceLibrary; + SHShaderModuleLibrary shaderModuleLibrary; // Temp Materials diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.cpp index 36e30010..b27f48b9 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.cpp @@ -4,6 +4,8 @@ #include "Graphics/Pipeline/SHVkPipeline.h" #include "SHGraphicsConstants.h" #include "Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h" +#include "Math/Vector/SHVec3.h" +#include "Math/Vector/SHVec4.h" namespace SHADE { @@ -23,7 +25,7 @@ namespace SHADE } // Allocate memory for properties - const Handle SHADER_INFO = getShaderBlockInterface(); + const Handle SHADER_INFO = GetShaderBlockInterface(); propMemorySize = SHADER_INFO ? SHADER_INFO->GetBytesRequired() : 0; if (propMemorySize <= 0) { @@ -49,6 +51,22 @@ namespace SHADE // Reset all the properties to default values if (propMemory) memset(propMemory.get(), 0, propMemorySize); + + // Initialize Vectors to all 1.0 by default + const Handle SHADER_INFO = GetShaderBlockInterface(); + for (int i = 0; i < SHADER_INFO->GetVariableCount(); ++i) + { + const auto& VAR = SHADER_INFO->GetVariable(i); + switch (VAR->type) + { + case SHShaderBlockInterface::Variable::Type::VECTOR3: + setPropertyUnsafe(VAR->offset, SHVec3::One); + break; + case SHShaderBlockInterface::Variable::Type::VECTOR4: + setPropertyUnsafe(VAR->offset, SHVec4::One); + break; + } + } } void SHMaterial::ExportProperties(void* dest) const noexcept @@ -59,14 +77,14 @@ namespace SHADE size_t SHMaterial::GetPropertiesMemorySize() const noexcept { - const Handle SHADER_INFO = getShaderBlockInterface(); + const Handle SHADER_INFO = GetShaderBlockInterface(); return SHADER_INFO ? SHADER_INFO->GetBytesRequired() : 0; } /*---------------------------------------------------------------------------------*/ /* Helper Functions */ /*---------------------------------------------------------------------------------*/ - Handle SHMaterial::getShaderBlockInterface() const noexcept + Handle SHMaterial::GetShaderBlockInterface() const noexcept { return pipeline->GetPipelineLayout()->GetShaderBlockInterface ( diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h index ec546fd5..964f9e34 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h @@ -50,13 +50,24 @@ namespace SHADE template void SetProperty(const std::string& key, const T& value); template + void SetProperty(uint32_t memOffset, const T& value); + template T& GetProperty(const std::string& key); template const T& GetProperty(const std::string& key) const; + template + T& GetProperty(uint32_t memOffset); + template + const T& GetProperty(uint32_t memOffset) const; void ResetProperties(); void ExportProperties(void* dest) const noexcept; Byte GetPropertiesMemorySize() const noexcept; + /*-----------------------------------------------------------------------------*/ + /* Query Functions */ + /*-----------------------------------------------------------------------------*/ + Handle GetShaderBlockInterface() const noexcept; + private: /*-----------------------------------------------------------------------------*/ /* Data Members */ @@ -68,7 +79,8 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Helper Functions */ /*-----------------------------------------------------------------------------*/ - Handle getShaderBlockInterface() const noexcept; + template + inline void setPropertyUnsafe(uint32_t memOffset, const T& value); // SetProperty() but without checks }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.hpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.hpp index 49587921..8c205570 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.hpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.hpp @@ -25,7 +25,7 @@ namespace SHADE template void SHMaterial::SetProperty(const std::string& key, const T& value) { - const auto SHADER_INFO = getShaderBlockInterface(); + const auto SHADER_INFO = GetShaderBlockInterface(); const auto PROP_INFO = SHADER_INFO->GetVariable(key); if (PROP_INFO == nullptr) { @@ -33,17 +33,28 @@ namespace SHADE } // Get offset and modify the memory directly - T* dataPtr = propMemory.get() + PROP_INFO->offset; + T* dataPtr = reinterpret_cast(propMemory.get() + PROP_INFO->offset); *dataPtr = value; } + + template + void SHMaterial::SetProperty(uint32_t memOffset, const T& value) + { + // Check if out of bounds + if (memOffset + sizeof(T) > propMemorySize) + throw std::invalid_argument("Attempted to set an invalid property!"); + // Set + setPropertyUnsafe(memOffset, value); + } + template T& SHMaterial::GetProperty(const std::string& key) { - const auto SHADER_INFO = getShaderBlockInterface(); + const auto SHADER_INFO = GetShaderBlockInterface(); const auto PROP_INFO = SHADER_INFO->GetVariable(key); if (PROP_INFO == nullptr) { - throw std::invalid_argument("Attempted to set an invalid property!"); + throw std::invalid_argument("Attempted to retrieve an invalid property!"); } // Get offset and return the memory directly @@ -55,5 +66,25 @@ namespace SHADE { return const_cast(const_cast(this)->GetProperty(key)); } + + template + const T& SHMaterial::GetProperty(uint32_t memOffset) const + { + // Check if out of bounds + if (memOffset + sizeof(T) > propMemorySize) + throw std::invalid_argument("Attempted to retrieve an invalid property!"); + return *(reinterpret_cast(propMemory.get() + memOffset)); + } + template + T& SHMaterial::GetProperty(uint32_t memOffset) + { + return const_cast(const_cast(this)->GetProperty(memOffset)); + } + + template + void SHMaterial::setPropertyUnsafe(uint32_t memOffset, const T& value) + { + (*reinterpret_cast(propMemory.get() + memOffset)) = value; + } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp index 7c4d0bb9..22de83b8 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp @@ -23,7 +23,7 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ void SHRenderable::OnCreate() { - materialChanged = true; + matChanged = true; sharedMaterial = {}; material = {}; oldMaterial = {}; @@ -55,7 +55,7 @@ namespace SHADE return; // Flag that material was changed - materialChanged = true; + matChanged = true; // Free copies of materials if any if (material) @@ -92,15 +92,41 @@ namespace SHADE return material; } - + + /*-----------------------------------------------------------------------------------*/ + /* Mesh Functions */ + /*-----------------------------------------------------------------------------------*/ + void SHRenderable::SetMesh(Handle newMesh) + { + oldMesh = mesh; + mesh = newMesh; + meshChanged = true; + } + + /*-----------------------------------------------------------------------------------*/ + /* Light Functions */ + /*-----------------------------------------------------------------------------------*/ uint8_t SHRenderable::GetLightLayer(void) const noexcept { return lightLayer; } - + + /*-----------------------------------------------------------------------------------*/ + /* Batcher Dispatcher Functions */ + /*-----------------------------------------------------------------------------------*/ void SHRenderable::ResetChangedFlag() { - materialChanged = false; - oldMaterial = {}; + matChanged = false; + meshChanged = false; + oldMaterial = {}; + oldMesh = {}; } } + +RTTR_REGISTRATION +{ + using namespace SHADE; + using namespace rttr; + + registration::class_("Renderable Component"); +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.h index 75e42d60..8893c43b 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.h @@ -11,9 +11,10 @@ of DigiPen Institute of Technology is prohibited. *//*************************************************************************************/ #pragma once +// External Dependencies +#include // Project Includes #include "Resource/SHHandle.h" -//#include "SHTransform.h" #include "ECS_Base/Components/SHComponent.h" #include "Math/SHMatrix.h" #include "SH_API.h" @@ -50,33 +51,42 @@ namespace SHADE void SetMaterial(Handle materialInstance); Handle GetMaterial() const; Handle GetModifiableMaterial(); + Handle GetPrevMaterial() const noexcept { return oldMaterial; } + bool HasMaterialChanged() const noexcept { return matChanged; } /*-------------------------------------------------------------------------------*/ - /* Getter Functions */ + /* Mesh Functions */ + /*-------------------------------------------------------------------------------*/ + void SetMesh(Handle newMesh); + Handle GetMesh() const noexcept { return mesh; } + Handle GetPrevMesh() const noexcept { return oldMesh; } + bool HasMeshChanged() const noexcept { return meshChanged; } + + /*-------------------------------------------------------------------------------*/ + /* Light Functions */ /*-------------------------------------------------------------------------------*/ - bool WasMaterialChanged() const noexcept { return materialChanged; } - Handle GetPrevMaterial() const noexcept { return oldMaterial; } uint8_t GetLightLayer (void) const noexcept; /*-------------------------------------------------------------------------------*/ /* Batcher Dispatcher Functions */ /*-------------------------------------------------------------------------------*/ + bool HasChanged() const noexcept { return matChanged || meshChanged; } // Whether or not the mesh or material has changed void ResetChangedFlag(); // TODO: Lock it so that only SHBatcherDispatcher can access this - /*-------------------------------------------------------------------------------*/ - /* Data Members */ - /*-------------------------------------------------------------------------------*/ - Handle Mesh; - private: /*-------------------------------------------------------------------------------*/ /* Data Members */ /*-------------------------------------------------------------------------------*/ + Handle mesh; + Handle oldMesh; + bool meshChanged = true; Handle sharedMaterial; Handle material; - bool materialChanged = true; + bool matChanged = true; Handle oldMaterial; uint8_t lightLayer; + + RTTR_ENABLE() }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.cpp index 23d6323c..d0b160df 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.cpp @@ -1,6 +1,7 @@ #include "SHPch.h" #include "SHShaderModuleLibrary.h" #include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Assets/SHAssetManager.h" namespace SHADE { @@ -18,33 +19,33 @@ namespace SHADE */ /***************************************************************************/ - void SHShaderModuleLibrary::ImportFromSourceLibrary(Handle& logicalDeviceHdl, SHShaderSourceLibrary const& sourceLib) noexcept - { - auto const& sources = sourceLib.GetSourceLibrary(); - for (auto const& source : sources) - { - vk::ShaderStageFlagBits shaderType{}; - switch (source.shaderType) - { - case SH_SHADER_TYPE::VERTEX: - shaderType = vk::ShaderStageFlagBits::eVertex; - break; - case SH_SHADER_TYPE::FRAGMENT: - shaderType = vk::ShaderStageFlagBits::eFragment; - break; - case SH_SHADER_TYPE::COMPUTE: - shaderType = vk::ShaderStageFlagBits::eCompute; - break; - default: - shaderType = vk::ShaderStageFlagBits::eVertex; - break; - } + //void SHShaderModuleLibrary::ImportFromSourceLibrary(Handle& logicalDeviceHdl, SHShaderSourceLibrary const& sourceLib) noexcept + //{ + // auto const& sources = sourceLib.GetSourceLibrary(); + // for (auto const& source : sources) + // { + // vk::ShaderStageFlagBits shaderType{}; + // switch (source.shaderType) + // { + // case SH_SHADER_TYPE::VERTEX: + // shaderType = vk::ShaderStageFlagBits::eVertex; + // break; + // case SH_SHADER_TYPE::FRAGMENT: + // shaderType = vk::ShaderStageFlagBits::eFragment; + // break; + // case SH_SHADER_TYPE::COMPUTE: + // shaderType = vk::ShaderStageFlagBits::eCompute; + // break; + // default: + // shaderType = vk::ShaderStageFlagBits::eVertex; + // break; + // } - Handle newShaderModule = logicalDeviceHdl->CreateShaderModule(source.spirvBinary, "main", shaderType, source.name); - shaderModules.emplace(source.id, newShaderModule); - stringToID.emplace(source.name, source.id); - } - } + // Handle newShaderModule = logicalDeviceHdl->CreateShaderModule(source.spirvBinary, "main", shaderType, source.name); + // shaderModules.emplace(source.id, newShaderModule); + // stringToID.emplace(source.name, source.id); + // } + //} /***************************************************************************/ /*! @@ -58,12 +59,81 @@ namespace SHADE */ /***************************************************************************/ - Handle SHShaderModuleLibrary::GetShaderModule(std::string shaderName) const noexcept + //Handle SHShaderModuleLibrary::GetShaderModule(std::string shaderName) const noexcept + //{ + // if (stringToID.contains(shaderName)) + // return shaderModules.at(stringToID.at(shaderName)); + // else + // return {}; + //} + + vk::ShaderStageFlagBits SHShaderModuleLibrary::GetVkShaderFlag(SH_SHADER_TYPE type) noexcept { - if (stringToID.contains(shaderName)) - return shaderModules.at(stringToID.at(shaderName)); - else - return {}; + vk::ShaderStageFlagBits shaderType{}; + switch (type) + { + case SH_SHADER_TYPE::VERTEX: + shaderType = vk::ShaderStageFlagBits::eVertex; + break; + case SH_SHADER_TYPE::FRAGMENT: + shaderType = vk::ShaderStageFlagBits::eFragment; + break; + case SH_SHADER_TYPE::COMPUTE: + shaderType = vk::ShaderStageFlagBits::eCompute; + break; + default: + shaderType = vk::ShaderStageFlagBits::eVertex; + break; + } + + return shaderType; } -} \ No newline at end of file + Handle SHShaderModuleLibrary::GetBuiltInShaderModule(std::string shaderName) const noexcept + { + if (builtInShaderModules.contains(shaderName)) + return builtInShaderModules.at(shaderName); + else + return {}; + } + + void SHShaderModuleLibrary::ImportAllShaderSource(Handle& logicalDeviceHdl) noexcept + { + uint32_t idCounter{ 0 }; + + auto const data = SHAssetManager::GetAllDataOfType(AssetType::SHADER); + for (auto const& dataPtr : data) + { + auto const shader = dynamic_cast(dataPtr); + + Handle newShaderModule = + logicalDeviceHdl->CreateShaderModule(shader->spirvBinary, "main", GetVkShaderFlag(shader->shaderType), shader->name); + + shaderModules.emplace(idCounter++, newShaderModule); + } + + auto const builtIn = SHAssetManager::GetAllDataOfType(AssetType::SHADER_BUILT_IN); + for (auto const& dataPtr : builtIn) + { + auto const shader = dynamic_cast(dataPtr); + + Handle newShaderModule = + logicalDeviceHdl->CreateShaderModule(shader->spirvBinary, "main", GetVkShaderFlag(shader->shaderType), shader->name); + + builtInShaderModules.emplace(shader->name, newShaderModule); + } + } + + void SHShaderModuleLibrary::ReflectAllShaderModules() noexcept + { + for (auto& module : shaderModules) + { + module.second->Reflect(); + } + + for (auto& module : builtInShaderModules) + { + module.second->Reflect(); + } + } +} diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.h index ed942833..9daae816 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.h @@ -2,8 +2,7 @@ #define SH_SHADER_MODULE_LIBRARY_H #include "Graphics/Shaders/SHVkShaderModule.h" -#include "SHShaderSourceLibrary.h" -#include +#include "Assets/Asset Types/SHShaderAsset.h" namespace SHADE { @@ -22,20 +21,23 @@ namespace SHADE /*-----------------------------------------------------------------------*/ //! Stored shader modules std::unordered_map> shaderModules; + std::unordered_map> builtInShaderModules; - //! We want some sort of interface with strings, instead of ints - std::map stringToID; + inline vk::ShaderStageFlagBits GetVkShaderFlag(SH_SHADER_TYPE type) noexcept; public: /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - void ImportFromSourceLibrary(Handle& logicalDeviceHdl, SHShaderSourceLibrary const& sourceLib) noexcept; + //void ImportFromSourceLibrary(Handle& logicalDeviceHdl, SHShaderSourceLibrary const& sourceLib) noexcept; /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ - Handle GetShaderModule(std::string shaderName) const noexcept; + Handle GetBuiltInShaderModule(std::string shaderName) const noexcept; + + void ImportAllShaderSource(Handle& logicalDeviceHdl) noexcept; + void ReflectAllShaderModules() noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderSourceLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderSourceLibrary.cpp deleted file mode 100644 index d9bf9ddc..00000000 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderSourceLibrary.cpp +++ /dev/null @@ -1,308 +0,0 @@ -#include "SHPch.h" -#include -#include -#include "SHShaderSourceLibrary.h" -#include "Tools/SHLogger.h" - -namespace SHADE -{ - /***************************************************************************/ - /*! - - \brief - Initializes the directory to take assets from. TODO: Only temporary until - the resource manager is implemented. - - \param directory - - \return - - */ - /***************************************************************************/ - void SHShaderSourceLibrary::Init (std::string directory) noexcept - { - shaderDirectory = directory; - if (shaderDirectory.back() != '/') - { - shaderDirectory += '/'; - } - } - - /***************************************************************************/ - /*! - - \brief - Private member function to compile a shader STRING source to binary and - returns a vector of 4 bytes. - - \param glslSource - The GLSL string source. - - \param type - Type of the shader: vertex, fragment, compute, etc. - - \param opLevel - Optimization level. - - \return - Returns a vector of the binary data. - - */ - /***************************************************************************/ - std::vector SHShaderSourceLibrary::CompileToBinary(std::string const& glslSource, char const* const spirvFilename, SH_SHADER_TYPE type, shaderc_optimization_level opLevel /*= shaderc_optimization_level_zero*/) - { - // shaderc compiler - shaderc::Compiler compiler; - shaderc::CompileOptions options; - - options.AddMacroDefinition("MY_DEFINE", "1"); - - // Set optimization levels - if (opLevel != shaderc_optimization_level_zero) - options.SetOptimizationLevel(opLevel); - - // Attempt to get the shaderc equivalent shader stage - shaderc_shader_kind shaderKind; - switch (type) - { - case SH_SHADER_TYPE::VERTEX: - shaderKind = shaderc_shader_kind::shaderc_glsl_vertex_shader; - break; - case SH_SHADER_TYPE::FRAGMENT: - shaderKind = shaderc_shader_kind::shaderc_glsl_fragment_shader; - break; - case SH_SHADER_TYPE::COMPUTE: - shaderKind = shaderc_shader_kind::shaderc_glsl_compute_shader; - break; - default: - shaderKind = shaderc_shader_kind::shaderc_glsl_vertex_shader; - break; - } - - // Compile the shader and get the result - shaderc::SpvCompilationResult compileResult = compiler.CompileGlslToSpv(glslSource, shaderKind, spirvFilename, options); - - if (compileResult.GetCompilationStatus() != shaderc_compilation_status_success) - { - SHLOG_ERROR("Shaderc failed to compile GLSL shader to binary | " + compileResult.GetErrorMessage()); - } - - return { compileResult.begin(), compileResult.end() }; - } - - /***************************************************************************/ - /*! - - \brief - TODO: Delete after file IO is implemented. Loads a shader from disk. - - \param filePath - file path to the shader in the asset directory. - - \return - Returns the data in the file in string form. - - */ - /***************************************************************************/ - std::string SHShaderSourceLibrary::GetStringFromFile(char const* filePath) noexcept - { - // Retrieve contents from filePath - // Ensure ifstream objects can throw exceptions - std::ifstream iFile; - iFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); - std::string fileContent = ""; - - try - { - // Open file - // Read file's buffer contents into streams - iFile.open(filePath); - std::stringstream fileStream; - fileStream << iFile.rdbuf(); - - fileContent = fileStream.str(); - - // Close file handler - iFile.close(); - } - catch (std::ifstream::failure e) - { - std::cerr << "File was not successfully read" << filePath << std::endl; - } - - return fileContent; - - } - - /***************************************************************************/ - /*! - - \brief - Load a shader into the library. - - \param filePath - file path to the shader in the asset directory. - - */ - /***************************************************************************/ - bool SHShaderSourceLibrary::LoadShader (uint32_t id, std::string glslFile, SH_SHADER_TYPE type, bool checkSpirvOutdated/* = true*/, bool recompileAnyway /*= false*/) noexcept - { - //if (sourceLibrary.contains(id)) - //{ - // SHLOG_ERROR("Shader with ID passed in already exists. Use a different ID"); - // return false; - //} - - std::string fullGLSLPath = shaderDirectory + glslFile; - auto path = std::filesystem::path(fullGLSLPath); - - if (path.extension() != ".glsl") - { - SHLOG_ERROR("Shader is not GLSL file, failed to load shader. "); - return false; - } - - std::string spirvFilepath = path.replace_extension("spv").string(); - - SHShaderData newShaderData{}; - newShaderData.shaderType = type; - - // spirv file - std::ifstream spirvFile(spirvFilepath, std::ios::ate | std::ios::binary); - - // If we disable spirv validation, file is not checked - if (!recompileAnyway && - spirvFile.is_open() && - (checkSpirvOutdated ? (std::filesystem::last_write_time(spirvFilepath) > std::filesystem::last_write_time(fullGLSLPath)) : true)) - { - // Get file size of binary - uint32_t fileSize = static_cast(spirvFile.tellg()); - - // resize container to store binary - newShaderData.spirvBinary.resize(fileSize / sizeof(uint32_t)); - - // Read data from binary file to container - spirvFile.seekg(0); - spirvFile.read(reinterpret_cast(newShaderData.spirvBinary.data()), fileSize); - - // close file - spirvFile.close(); - - } - else - { - // Use glslc to generate spirv file - newShaderData.spirvBinary = CompileToBinary(GetStringFromFile(fullGLSLPath.c_str()), spirvFilepath.c_str(), type); - - std::ofstream binaryFile(spirvFilepath, std::ios::binary); - - if (binaryFile.is_open()) - { - // write all data to binary file - binaryFile.write(reinterpret_cast(newShaderData.spirvBinary.data()), newShaderData.spirvBinary.size() * sizeof(uint32_t)); - } - else - { - SHLOG_ERROR("Failed to modify spirv file. "); - return false; - } - } - - newShaderData.name = glslFile; - newShaderData.id = id; - - sourceLibrary.emplace_back(std::move (newShaderData)); - return true; - } - - /***************************************************************************/ - /*! - - \brief - Gets the entire source library. - - \return - The container of binary data. - - */ - /***************************************************************************/ - std::vector const& SHShaderSourceLibrary::GetSourceLibrary(void) const noexcept - { - return sourceLibrary; - } - - /***************************************************************************/ - /*! - - \brief - Move ctor for shader data. - - \param rhs - The other shader data - - */ - /***************************************************************************/ - SHShaderData::SHShaderData(SHShaderData&& rhs) noexcept - : spirvBinary{ std::move (rhs.spirvBinary)} - , shaderType{std::move (rhs.shaderType)} - , name{ std::move (rhs.name)} - , id {std::move (rhs.id)} - { - - } - - /***************************************************************************/ - /*! - - \brief - Default ctor for shader data. Does nothing. - - */ - /***************************************************************************/ - SHShaderData::SHShaderData(void) noexcept - : spirvBinary{} - , shaderType{SH_SHADER_TYPE::VERTEX} - , name{ } - , id{ } - - { - - } - - SHShaderData::SHShaderData(SHShaderData const& rhs) noexcept - : spirvBinary{rhs.spirvBinary} - , shaderType{ rhs.shaderType} - , name{rhs.name } - , id{rhs.id } - { - - } - - SHShaderData& SHShaderData::operator=(SHShaderData const& rhs) noexcept - { - if (this == &rhs) - return *this; - - spirvBinary = rhs.spirvBinary; - shaderType = rhs.shaderType; - name = rhs.name; - id = rhs.id; - - - return *this; - } - - SHShaderData& SHShaderData::operator=(SHShaderData&& rhs) noexcept - { - if (this == &rhs) - return *this; - - spirvBinary = std::move(rhs.spirvBinary); - shaderType = std::move (rhs.shaderType); - name = std::move (rhs.name); - id = std::move (rhs.id); - - return *this; - } - -} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderSourceLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderSourceLibrary.h deleted file mode 100644 index bb346111..00000000 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderSourceLibrary.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef SH_SHADER_SOURCE_LIBRARY_H -#define SH_SHADER_SOURCE_LIBRARY_H - -#include -#include "SHShaderType.h" -#include "shaderc/shaderc.hpp" - -namespace SHADE -{ - struct SHShaderData - { - /*-----------------------------------------------------------------------*/ - /* MEMBER VARIABLES */ - /*-----------------------------------------------------------------------*/ - //! container storing the spirv binary - std::vector spirvBinary; - - //! For the compilation of the shader. Vulkan backend will use it too - SH_SHADER_TYPE shaderType; - - //! Name of the shader file (without parent path) - std::string name; - - //! id of the shader - uint32_t id; - - SHShaderData(void) noexcept; - SHShaderData(SHShaderData const& rhs) noexcept; - SHShaderData(SHShaderData&& rhs) noexcept; - SHShaderData& operator= (SHShaderData&& rhs) noexcept; - SHShaderData& operator= (SHShaderData const& rhs) noexcept; - }; - - // TODO: This class is purely temporary and will be converted/changed when XQ implements his resource manager - class SHShaderSourceLibrary - { - private: - /*-----------------------------------------------------------------------*/ - /* PRIVATE MEMBER VARIABLES */ - /*-----------------------------------------------------------------------*/ - //! Stores all the source data. Take note that the source here is GLSL source and NOT binary data. - //! Binary data gets passed to the backend to convert to spirv. - std::vector sourceLibrary; - - //! The directory where the shaders are located. - std::string shaderDirectory; - - /*-----------------------------------------------------------------------*/ - /* PRIVATE MEMBER FUNCTIONS */ - /*-----------------------------------------------------------------------*/ - std::vector CompileToBinary(std::string const& glslSource, char const* const spirvFilename, SH_SHADER_TYPE type, shaderc_optimization_level opLevel = shaderc_optimization_level_zero); - - // TODO: Delete after file IO is implemented - std::string GetStringFromFile(char const* filePath) noexcept; - - public: - /*-----------------------------------------------------------------------*/ - /* PUBLIC MEMBER FUNCTIONS */ - /*-----------------------------------------------------------------------*/ - void Init (std::string directory) noexcept; - bool LoadShader (uint32_t id, std::string glslFile, SH_SHADER_TYPE type, bool checkSpirvOutdated = true, bool recompileAnyway = false) noexcept; - - /*-----------------------------------------------------------------------*/ - /* SETTERS AND GETTERS */ - /*-----------------------------------------------------------------------*/ - std::vector const& GetSourceLibrary(void) const noexcept; - }; -} - -#endif diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderType.h b/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderType.h deleted file mode 100644 index bf4828b5..00000000 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Shaders/SHShaderType.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef SH_SHADER_TYPE_H -#define SH_SHADER_TYPE_H - -namespace SHADE -{ - enum class SH_SHADER_TYPE - { - VERTEX, - FRAGMENT, - COMPUTE - }; -} - -#endif diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index c315bffd..607c777a 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -244,7 +244,15 @@ namespace SHADE } // Add subpass to container and create mapping for it - subpasses.emplace_back(graphStorage->resourceManager->Create(graphStorage, GetHandle(), static_cast(subpasses.size()), &resourceAttachmentMapping)); + subpasses.emplace_back + ( + graphStorage->resourceManager->Create + ( + subpassName, + graphStorage, GetHandle(), static_cast(subpasses.size()), + &resourceAttachmentMapping + ) + ); subpassIndexing.try_emplace(subpassName, static_cast(subpasses.size()) - 1u); Handle subpass = subpasses.back(); subpass->Init(*graphStorage->resourceManager); diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index af6f3089..d8f4f8c2 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -30,7 +30,7 @@ namespace SHADE */ /***************************************************************************/ - SHSubpass::SHSubpass(Handle renderGraphStorage, Handle const& parent, uint32_t index, std::unordered_map const* mapping) noexcept + SHSubpass::SHSubpass(const std::string& name, Handle renderGraphStorage, Handle const& parent, uint32_t index, std::unordered_map const* mapping) noexcept : resourceAttachmentMapping{ mapping } , parentNode{ parent } , subpassIndex{ index } @@ -38,6 +38,7 @@ namespace SHADE , colorReferences{} , depthReferences{} , inputReferences{} + , name { name } , graphStorage{ renderGraphStorage } , inputImageDescriptors {SHGraphicsConstants::NUM_FRAME_BUFFERS} { @@ -411,4 +412,8 @@ namespace SHADE return parentNode->GetResource(attachmentReference)->GetResourceFormat(); } + const std::string& SHSubpass::GetName() const + { + return name; + } } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h index 166f0d76..c82ebdd0 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h @@ -77,13 +77,15 @@ namespace SHADE //! are always the last things drawn, so DO NOT USE THIS FUNCTIONALITY FOR ANYTHING //! COMPLEX. std::vector&)>> exteriorDrawCalls; + /// For identifying subpasses + std::string name; public: /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ /*-----------------------------------------------------------------------*/ - SHSubpass(Handle renderGraphStorage, Handle const& parent, uint32_t index, std::unordered_map const* mapping) noexcept; + SHSubpass(const std::string& name, Handle renderGraphStorage, Handle const& parent, uint32_t index, std::unordered_map const* mapping) noexcept; SHSubpass(SHSubpass&& rhs) noexcept; SHSubpass& operator=(SHSubpass&& rhs) noexcept; @@ -117,6 +119,7 @@ namespace SHADE Handle GetSuperBatch(void) const noexcept; std::vector const& GetColorAttachmentReferences (void) const noexcept; vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept; + const std::string& GetName() const; friend class SHRenderGraphNode; friend class SHRenderGraph; diff --git a/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.cpp b/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.cpp index 75ede865..f214c094 100644 --- a/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.cpp +++ b/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.cpp @@ -14,6 +14,7 @@ namespace SHADE return; } variables.emplace_back(std::move(newVariable)); + variableNames.emplace_back(name); variableIndexing.try_emplace(std::move(name), static_cast(variables.size() - 1)); } @@ -41,6 +42,19 @@ namespace SHADE return variableIndexing.at(variableName); } + const std::string& SHShaderBlockInterface::GetVariableName(uint32_t index) const noexcept + { + if (index < variableNames.size()) + return variableNames.at(index); + + return {}; + } + + size_t SHShaderBlockInterface::GetVariableCount() const noexcept + { + return variables.size(); + } + SHShaderBlockInterface::SHShaderBlockInterface(void) noexcept : bytesRequired{ 0 } {} diff --git a/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h b/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h index e546b452..ae75e2c8 100644 --- a/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h +++ b/SHADE_Engine/src/Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h @@ -12,13 +12,24 @@ namespace SHADE public: struct Variable { + enum class Type + { + OTHER, + FLOAT, + INT, + VECTOR2, + VECTOR3, + VECTOR4 + }; //! Offset of the variable in the block uint32_t offset; + Type type; }; private: //! containers of variable information std::vector variables; + std::vector variableNames; std::unordered_map variableIndexing; //! bytes required by the block (includes padding). This variable is required @@ -29,6 +40,8 @@ namespace SHADE Variable const* const GetVariable (std::string const& variableName) const noexcept; Variable const* const GetVariable(uint32_t index) const noexcept; uint32_t GetVariableIndex(std::string const& variableName) const; + const std::string& GetVariableName(uint32_t index) const noexcept; + size_t GetVariableCount() const noexcept; /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ diff --git a/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp b/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp index e635f763..f28561c5 100644 --- a/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp +++ b/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp @@ -97,17 +97,45 @@ namespace SHADE switch (member.type_description->op) { case SpvOp::SpvOpTypeFloat: - interfaceHdl->AddVariable(parentVarName + std::string(member.name), SHShaderBlockInterface::Variable(parentOffset + member.offset)); + interfaceHdl->AddVariable + ( + parentVarName + std::string(member.name), + SHShaderBlockInterface::Variable + ( + parentOffset + member.offset, + SHShaderBlockInterface::Variable::Type::FLOAT + ) + ); biggestAlignment = std::max (biggestAlignment, 4u); break; case SpvOp::SpvOpTypeVector: - interfaceHdl->AddVariable(parentVarName + std::string(member.name), SHShaderBlockInterface::Variable(parentOffset + member.offset)); + SHShaderBlockInterface::Variable::Type varType; + switch (dim) + { + case 2: varType = SHShaderBlockInterface::Variable::Type::VECTOR2; break; + case 3: varType = SHShaderBlockInterface::Variable::Type::VECTOR3; break; + case 4: varType = SHShaderBlockInterface::Variable::Type::VECTOR4; break; + default: varType = SHShaderBlockInterface::Variable::Type::OTHER; break; + } + interfaceHdl->AddVariable + ( + parentVarName + std::string(member.name), + SHShaderBlockInterface::Variable(parentOffset + member.offset, varType) + ); if (dim == 3) dim = 4; biggestAlignment = std::max (biggestAlignment, dim * member.type_description->traits.numeric.scalar.width / 8); break; case SpvOp::SpvOpTypeInt: - interfaceHdl->AddVariable(parentVarName + std::string(member.name), SHShaderBlockInterface::Variable(parentOffset + member.offset)); + interfaceHdl->AddVariable + ( + parentVarName + std::string(member.name), + SHShaderBlockInterface::Variable + ( + parentOffset + member.offset, + SHShaderBlockInterface::Variable::Type::INT + ) + ); biggestAlignment = std::max(biggestAlignment, 4u); break; case SpvOp::SpvOpTypeStruct: diff --git a/SHADE_Engine/src/Math/Geometry/SHShape.cpp b/SHADE_Engine/src/Math/Geometry/SHShape.cpp index 3fc5775d..2f869029 100644 --- a/SHADE_Engine/src/Math/Geometry/SHShape.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHShape.cpp @@ -27,10 +27,9 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - SHShape::Type SHShape::GetType() const + SHShape::Type SHShape::GetType() const noexcept { return type; } - } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHShape.h b/SHADE_Engine/src/Math/Geometry/SHShape.h index 18f54fe6..62198897 100644 --- a/SHADE_Engine/src/Math/Geometry/SHShape.h +++ b/SHADE_Engine/src/Math/Geometry/SHShape.h @@ -63,7 +63,7 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] Type GetType() const; + [[nodiscard]] Type GetType () const noexcept; /*---------------------------------------------------------------------------------*/ /* Function Members */ @@ -77,6 +77,6 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - Type type; + Type type; }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp index 5a540cd4..a2ab6880 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp +++ b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp @@ -61,9 +61,9 @@ namespace SHADE void SHTransformSystem::Init() { - std::shared_ptr thisReceiver { std::make_shared>(this, &SHTransformSystem::ChangeParent) }; - ReceiverPtr receiver = std::dynamic_pointer_cast(thisReceiver); - SHEventManager::SubscribeTo(SH_SCENEGRAPH_CHANGE_PARENT_EVENT, receiver); + const std::shared_ptr CHANGE_PARENT_RECEIVER { std::make_shared>(this, &SHTransformSystem::ChangeParent) }; + const ReceiverPtr CHANGE_PARENT_RECEIVER_PTR = std::dynamic_pointer_cast(CHANGE_PARENT_RECEIVER); + SHEventManager::SubscribeTo(SH_SCENEGRAPH_CHANGE_PARENT_EVENT, CHANGE_PARENT_RECEIVER_PTR); } void SHTransformSystem::Exit() @@ -75,50 +75,6 @@ namespace SHADE /* Private Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - SHEventHandle SHTransformSystem::ChangeParent(SHEventPtr changeParentEvent) - { - const auto& eventData = reinterpret_cast*>(changeParentEvent.get()); - - auto* node = eventData->data->node; - auto* tf = SHComponentManager::GetComponent_s(node->GetEntityID()); - - // Recompute local transform and store localToWorld Matrix - SHMatrix localToWorld = SHMatrix::Identity; - SHMatrix worldToLocal = SHMatrix::Identity; - - auto* newParent = eventData->data->newParent; - const auto* PARENT_TF = SHComponentManager::GetComponent_s(newParent->GetEntityID()); - if (PARENT_TF != nullptr) // Not the root - { - localToWorld = PARENT_TF->GetTRS(); - worldToLocal = SHMatrix::Inverse(localToWorld); - } - - // Maintain World Transform and recompute Local Transform - - // Compute Local Position - tf->local.position = SHVec3::Transform(tf->world.position, worldToLocal); - - - tf->localRotation = tf->worldRotation; - tf->local.scale = tf->world.scale; - - if (PARENT_TF != nullptr) - { - // Compute Local Rotation - tf->localRotation -= PARENT_TF->GetLocalRotation(); - - // Compute Local Scale - tf->local.scale /= PARENT_TF->GetLocalScale(); - } - - tf->local.trs = localToWorld; - - // Propagate maintaining world transform down the branch - UpdateChildrenLocalTransforms(node); - return eventData->handle; - } - void SHTransformSystem::UpdateChildrenLocalTransforms(SHSceneNode* node) { // Structure is similar to update entity, albeit without a queue to do being a forced update @@ -300,4 +256,49 @@ namespace SHADE tf.world.ComputeTRS(); } + SHEventHandle SHTransformSystem::ChangeParent(SHEventPtr changeParentEvent) + { + const auto& EVENT_DATA = reinterpret_cast*>(changeParentEvent.get()); + + auto* node = EVENT_DATA->data->node; + auto* tf = SHComponentManager::GetComponent_s(node->GetEntityID()); + + // Recompute local transform and store localToWorld Matrix + SHMatrix localToWorld = SHMatrix::Identity; + SHMatrix worldToLocal = SHMatrix::Identity; + + auto* newParent = EVENT_DATA->data->newParent; + const auto* PARENT_TF = SHComponentManager::GetComponent_s(newParent->GetEntityID()); + if (PARENT_TF != nullptr) // Not the root + { + localToWorld = PARENT_TF->GetTRS(); + worldToLocal = SHMatrix::Inverse(localToWorld); + } + + // Maintain World Transform and recompute Local Transform + + // Compute Local Position + tf->local.position = SHVec3::Transform(tf->world.position, worldToLocal); + + + tf->localRotation = tf->worldRotation; + tf->local.scale = tf->world.scale; + + if (PARENT_TF != nullptr) + { + // Compute Local Rotation + tf->localRotation -= PARENT_TF->GetLocalRotation(); + + // Compute Local Scale + tf->local.scale /= PARENT_TF->GetLocalScale(); + } + + tf->local.trs = localToWorld; + + // Propagate maintaining world transform down the branch + UpdateChildrenLocalTransforms(node); + + return EVENT_DATA->handle; + } + } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Transform/SHTransformSystem.h b/SHADE_Engine/src/Math/Transform/SHTransformSystem.h index e63969ce..bb373f3a 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransformSystem.h +++ b/SHADE_Engine/src/Math/Transform/SHTransformSystem.h @@ -11,9 +11,9 @@ #pragma once // Project Headers -#include "SHTransformComponent.h" -#include "Scene/SHSceneGraph.h" #include "ECS_Base/System/SHSystemRoutine.h" +#include "Scene/SHSceneGraph.h" +#include "SHTransformComponent.h" namespace SHADE { @@ -53,17 +53,6 @@ namespace SHADE /*-------------------------------------------------------------------------------*/ TransformPostLogicUpdate (); - ~TransformPostLogicUpdate () = default; - - TransformPostLogicUpdate (const TransformPostLogicUpdate&) = delete; - TransformPostLogicUpdate (TransformPostLogicUpdate&&) = delete; - - /*-------------------------------------------------------------------------------*/ - /* Operator Overloads */ - /*-------------------------------------------------------------------------------*/ - - TransformPostLogicUpdate& operator= (const TransformPostLogicUpdate&) = delete; - TransformPostLogicUpdate& operator= (TransformPostLogicUpdate&&) = delete; /*-------------------------------------------------------------------------------*/ /* Function Members */ @@ -80,17 +69,6 @@ namespace SHADE /*-------------------------------------------------------------------------------*/ TransformPostPhysicsUpdate (); - ~TransformPostPhysicsUpdate () = default; - - TransformPostPhysicsUpdate (const TransformPostPhysicsUpdate&) = delete; - TransformPostPhysicsUpdate (TransformPostPhysicsUpdate&&) = delete; - - /*-------------------------------------------------------------------------------*/ - /* Operator Overloads */ - /*-------------------------------------------------------------------------------*/ - - TransformPostPhysicsUpdate& operator= (const TransformPostPhysicsUpdate&) = delete; - TransformPostPhysicsUpdate& operator= (TransformPostPhysicsUpdate&&) = delete; /*-------------------------------------------------------------------------------*/ /* Function Members */ @@ -111,11 +89,14 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ - SHEventHandle ChangeParent (SHEventPtr changeParentEvent); static void UpdateChildrenLocalTransforms (SHSceneNode* node); static void UpdateEntity (const SHSceneNode* node, bool clearDirtyFlag); static void UpdateTransform (SHTransformComponent& tf, const SHTransformComponent* parent = nullptr); + + // Event Handlers + + SHEventHandle ChangeParent (SHEventPtr changeParentEvent); }; diff --git a/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp b/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp index 71183f00..fb999847 100644 --- a/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp +++ b/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp @@ -26,7 +26,6 @@ namespace SHADE SHColliderComponent::SHColliderComponent() noexcept : system { nullptr } - , colliders {} {} /*-----------------------------------------------------------------------------------*/ @@ -59,7 +58,7 @@ namespace SHADE if (index < 0 || static_cast(index) >= colliders.size()) throw std::invalid_argument("Out-of-range access!"); - return colliders[index].first; + return colliders[index]; } /*-----------------------------------------------------------------------------------*/ @@ -69,44 +68,29 @@ namespace SHADE void SHColliderComponent::OnCreate() { system = SHSystemManager::GetSystem(); - if (!system) - { - SHLOG_ERROR("Physics system does not exist, Collider Component not added!") - return; - } - - system->AddCollider(GetEID()); } void SHColliderComponent::OnDestroy() { - if (!system) - { - SHLOG_ERROR("Physics system does not exist, unable to remove Collider component!") - return; - } - system->RemoveCollider(GetEID()); } SHBoundingBox* SHColliderComponent::AddBoundingBox(const SHVec3& halfExtents, const SHVec3& posOffset) noexcept { - const auto TYPE = SHCollider::Type::BOX; - - auto boxPair = std::make_pair(SHCollider{TYPE}, true); - auto& collider = colliders.emplace_back(boxPair).first; - - const auto* tf = SHComponentManager::GetComponent(GetEID()); - - collider.SetPositionOffset(posOffset); - collider.SetAsBoundingBox(tf->GetWorldScale() * halfExtents); - if (!system) { SHLOG_ERROR("Physics system does not exist, unable to add Box Collider!") return nullptr; } + static constexpr auto TYPE = SHCollider::Type::BOX; + + auto& collider = colliders.emplace_back(SHCollider{ GetEID(), TYPE }); + + collider.entityID = GetEID(); + collider.SetPositionOffset(posOffset); + collider.SetBoundingBox(halfExtents); + // Notify Physics System system->AddCollisionShape(GetEID(), &collider); @@ -115,25 +99,20 @@ namespace SHADE SHBoundingSphere* SHColliderComponent::AddBoundingSphere(float radius, const SHVec3& posOffset) noexcept { - const auto TYPE = SHCollider::Type::SPHERE; - - auto spherePair = std::make_pair(SHCollider{ TYPE }, true); - auto& collider = colliders.emplace_back(spherePair).first; - - const auto* tf = SHComponentManager::GetComponent(GetEID()); - - collider.SetPositionOffset(posOffset); - - const SHVec3 TF_WORLD_SCALE = tf->GetWorldScale(); - const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z }); - collider.SetAsBoundingSphere(MAX_SCALE * 0.5f); - if (!system) { SHLOG_ERROR("Physics system does not exist, unable to add Sphere Collider!") return nullptr; } + static constexpr auto TYPE = SHCollider::Type::SPHERE; + + auto& collider = colliders.emplace_back(SHCollider{ GetEID(), TYPE }); + + collider.entityID = GetEID(); + collider.SetPositionOffset(posOffset); + collider.SetBoundingSphere(radius); + // Notify Physics System system->AddCollisionShape(GetEID(), &collider); diff --git a/SHADE_Engine/src/Physics/Components/SHColliderComponent.h b/SHADE_Engine/src/Physics/Components/SHColliderComponent.h index 22d5ceee..af726b51 100644 --- a/SHADE_Engine/src/Physics/Components/SHColliderComponent.h +++ b/SHADE_Engine/src/Physics/Components/SHColliderComponent.h @@ -43,8 +43,7 @@ namespace SHADE /* Type Definitions */ /*---------------------------------------------------------------------------------*/ - using ColliderDirtyPair = std::pair; - using Colliders = std::vector; + using Colliders = std::vector; public: @@ -81,10 +80,10 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ - void OnCreate () override; - void OnDestroy () override; + void OnCreate () override; + void OnDestroy () override; - void RemoveCollider (int index); + void RemoveCollider (int index); SHBoundingBox* AddBoundingBox (const SHVec3& halfExtents = SHVec3::One, const SHVec3& posOffset = SHVec3::Zero) noexcept; SHBoundingSphere* AddBoundingSphere (float radius = 1.0f, const SHVec3& posOffset = SHVec3::Zero) noexcept; diff --git a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp index e5938717..c1969557 100644 --- a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp +++ b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp @@ -10,6 +10,9 @@ #include +// External Dependencies +#include + // Primary Header #include "SHRigidBodyComponent.h" @@ -28,11 +31,10 @@ namespace SHADE , flags { 0 } , dirtyFlags { 0 } , interpolate { true } - , system { nullptr } + , rp3dBody { nullptr } , mass { 1.0f } , drag { 0.01f } , angularDrag { 0.01f } - { // Set default flags: Gravity & Sleeping enabled flags |= 1U << 0; @@ -161,7 +163,13 @@ namespace SHADE void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept { - constexpr int FLAG_POS = 0; + static constexpr int FLAG_POS = 0; + + if (type != Type::DYNAMIC) + { + SHLOG_WARNING("Cannot enable gravity of a non-dynamic object {}", GetEID()) + return; + } dirtyFlags |= 1U << FLAG_POS; enableGravity ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); @@ -169,7 +177,13 @@ namespace SHADE void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept { - constexpr int FLAG_POS = 1; + static constexpr int FLAG_POS = 1; + + if (type != Type::DYNAMIC) + { + SHLOG_WARNING("Cannot enable sleeping of a non-dynamic object {}", GetEID()) + return; + } dirtyFlags |= 1U << 1; isAllowedToSleep ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); @@ -177,7 +191,13 @@ namespace SHADE void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept { - constexpr int FLAG_POS = 2; + static constexpr int FLAG_POS = 2; + + if (type == Type::STATIC) + { + SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) + return; + } dirtyFlags |= 1U << 2; freezePositionX ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); @@ -185,7 +205,13 @@ namespace SHADE void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept { - constexpr int FLAG_POS = 3; + static constexpr int FLAG_POS = 3; + + if (type == Type::STATIC) + { + SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) + return; + } dirtyFlags |= 1U << 2; freezePositionY ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); @@ -193,7 +219,13 @@ namespace SHADE void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept { - constexpr int FLAG_POS = 4; + static constexpr int FLAG_POS = 4; + + if (type == Type::STATIC) + { + SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) + return; + } dirtyFlags |= 1U << 2; freezePositionZ ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); @@ -201,7 +233,13 @@ namespace SHADE void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept { - constexpr int FLAG_POS = 5; + static constexpr int FLAG_POS = 5; + + if (type == Type::STATIC) + { + SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) + return; + } dirtyFlags |= 1U << 3; freezeRotationX ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); @@ -209,7 +247,13 @@ namespace SHADE void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept { - constexpr int FLAG_POS = 6; + static constexpr int FLAG_POS = 6; + + if (type == Type::STATIC) + { + SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) + return; + } dirtyFlags |= 1U << 3; freezeRotationY ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); @@ -217,7 +261,13 @@ namespace SHADE void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept { - constexpr int FLAG_POS = 7; + static constexpr int FLAG_POS = 7; + + if (type == Type::STATIC) + { + SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) + return; + } dirtyFlags |= 1U << 3; freezeRotationZ ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); @@ -230,30 +280,60 @@ namespace SHADE void SHRigidBodyComponent::SetMass(float newMass) noexcept { + if (type != Type::DYNAMIC) + { + SHLOG_WARNING("Cannot set mass of a non-dynamic object {}", GetEID()) + return; + } + dirtyFlags |= 1U << 5; mass = newMass; } void SHRigidBodyComponent::SetDrag(float newDrag) noexcept { + if (type != Type::DYNAMIC) + { + SHLOG_WARNING("Cannot set drag of a non-dynamic object {}", GetEID()) + return; + } + dirtyFlags |= 1U << 6; drag = newDrag; } void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept { + if (type != Type::DYNAMIC) + { + SHLOG_WARNING("Cannot set angular drag of a non-dynamic object {}", GetEID()) + return; + } + dirtyFlags |= 1U << 7; angularDrag = newAngularDrag; } void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept { + if (type == Type::STATIC) + { + SHLOG_WARNING("Cannot set linear velocity of a static object {}", GetEID()) + return; + } + dirtyFlags |= 1U << 8; linearVelocity = newLinearVelocity; } void SHRigidBodyComponent::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept { + if (type == Type::STATIC) + { + SHLOG_WARNING("Cannot set angular velocity of a static object {}", GetEID()) + return; + } + dirtyFlags |= 1U << 9; angularVelocity = newAngularVelocity; } @@ -262,125 +342,92 @@ namespace SHADE /* Public Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHRigidBodyComponent::OnCreate() - { - system = SHSystemManager::GetSystem(); - if (!system) - { - SHLOG_ERROR("Physics system does not exist, Rigid Body Component not added!") - return; - } - - // Notify Physics System - system->AddRigidBody(GetEID()); - } - - void SHRigidBodyComponent::OnDestroy() - { - // Notify Physics System - if (!system) - { - SHLOG_ERROR("Physics system does not exist, unable to remove Rigid Body Component!") - return; - } - - system->RemoveRigidBody(GetEID()); - } - void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept { - if (!system) + if (rp3dBody == nullptr) { - SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") + SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID()) return; } - // Notify Physics Systems - system->AddForce(GetEID(), force); + rp3dBody->applyWorldForceAtCenterOfMass(force); } void SHRigidBodyComponent::AddForceAtLocalPos(const SHVec3& force, const SHVec3& localPos) const noexcept { - if (!system) + if (rp3dBody == nullptr) { - SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") + SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID()) return; } - // Notify Physics Systems - system->AddForceAtLocalPos(GetEID(), force, localPos); + rp3dBody->applyWorldForceAtLocalPosition(force, localPos); } void SHRigidBodyComponent::AddForceAtWorldPos(const SHVec3& force, const SHVec3& worldPos) const noexcept { - if (!system) + if (rp3dBody == nullptr) { - SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") + SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID()) return; } - // Notify Physics Systems - system->AddForceAtWorldPos(GetEID(), force, worldPos); + rp3dBody->applyWorldForceAtWorldPosition(force, worldPos); } void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept { - if (!system) + if (rp3dBody == nullptr) { - SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") + SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID()) return; } - // Notify Physics Systems - system->AddRelativeForce(GetEID(), force); + rp3dBody->applyLocalForceAtCenterOfMass(relativeForce); } void SHRigidBodyComponent::AddRelativeForceAtLocalPos(const SHVec3& relativeForce, const SHVec3& localPos) const noexcept { - if (!system) + if (rp3dBody == nullptr) { - SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") + SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID()) return; } - // Notify Physics Systems - system->AddRelativeForceAtLocalPos(GetEID(), force, localPos); + rp3dBody->applyLocalForceAtLocalPosition(relativeForce, localPos); } void SHRigidBodyComponent::AddRelativeForceAtWorldPos(const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept { - if (!system) + if (rp3dBody == nullptr) { - SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") + SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID()) return; } - // Notify Physics Systems - system->AddRelativeForceAtWorldPos(GetEID(), force, worldPos); + rp3dBody->applyLocalForceAtWorldPosition(relativeForce, worldPos); } void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept { - if (!system) + if (rp3dBody == nullptr) { - SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") + SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID()) return; } - // Notify Physics Systems - system->AddTorque(GetEID(), torque); + rp3dBody->applyWorldTorque(torque); } void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept { - if (!system) + if (rp3dBody == nullptr) { - SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") + SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID()) return; } - // Notify Physics Systems - system->AddRelativeTorque(GetEID(), relativeTorque); + rp3dBody->applyLocalTorque(relativeTorque); } } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h index 03b350e1..3c5dd4f9 100644 --- a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h +++ b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h @@ -22,6 +22,11 @@ // class SHPhysicsSystem; //} +namespace reactphysics3d +{ + class RigidBody; +} + namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -125,9 +130,6 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ - void OnCreate () override; - void OnDestroy () override; - void AddForce (const SHVec3& force) const noexcept; void AddForceAtLocalPos (const SHVec3& force, const SHVec3& localPos) const noexcept; void AddForceAtWorldPos (const SHVec3& force, const SHVec3& worldPos) const noexcept; @@ -155,7 +157,7 @@ namespace SHADE uint16_t dirtyFlags; bool interpolate; - SHPhysicsSystem* system; + reactphysics3d::RigidBody* rp3dBody; float mass; float drag; @@ -167,8 +169,6 @@ namespace SHADE SHVec3 torque; SHVec3 angularVelocity; - // TODO(Diren): Once quaternions have replaced euler angles in transforms, store it for the rigidbody. - SHVec3 position; SHQuaternion orientation; diff --git a/SHADE_Engine/src/Physics/SHCollider.cpp b/SHADE_Engine/src/Physics/SHCollider.cpp index f5899cfc..9488042d 100644 --- a/SHADE_Engine/src/Physics/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/SHCollider.cpp @@ -15,6 +15,8 @@ // Project Headers #include "Math/Geometry/SHBoundingBox.h" #include "Math/Geometry/SHBoundingSphere.h" +#include "Math/Transform/SHTransformComponent.h" +#include "Math/SHMathHelpers.h" namespace SHADE { @@ -22,22 +24,24 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHCollider::SHCollider(Type colliderType) + SHCollider::SHCollider(EntityID eid, Type colliderType, const SHPhysicsMaterial& physicsMaterial) : type { colliderType } + , entityID { eid } , isTrigger { false } , dirty { true } , shape { nullptr } + , material { physicsMaterial } { switch (type) { case Type::BOX: { - SetAsBoundingBox(SHVec3::One); + shape = new SHBoundingBox{ SHVec3::Zero, SHVec3::One }; break; } case Type::SPHERE: { - SetAsBoundingSphere(1.0f); + shape = new SHBoundingSphere{ SHVec3::Zero, 0.5f }; break; } default: break; @@ -46,19 +50,27 @@ namespace SHADE SHCollider::SHCollider(const SHCollider& rhs) noexcept : type { rhs.type} + , entityID { rhs.entityID } , isTrigger { rhs.isTrigger } , dirty { true } - , shape { rhs.shape } + , shape { nullptr } + , material { rhs.material } , positionOffset { rhs.positionOffset } - {} + { + CopyShape(rhs.shape); + } SHCollider::SHCollider(SHCollider&& rhs) noexcept : type { rhs.type} + , entityID { rhs.entityID } , isTrigger { rhs.isTrigger } , dirty { true } - , shape { rhs.shape } + , shape { nullptr } + , material { rhs.material } , positionOffset { rhs.positionOffset } - {} + { + CopyShape(rhs.shape); + } SHCollider::~SHCollider() noexcept { @@ -75,22 +87,30 @@ namespace SHADE return *this; type = rhs.type; + entityID = rhs.entityID; isTrigger = rhs.isTrigger; dirty = true; - shape = rhs.shape; + material = rhs.material; positionOffset = rhs.positionOffset; + delete shape; + CopyShape(rhs.shape); + return *this; } SHCollider& SHCollider::operator=(SHCollider&& rhs) noexcept { type = rhs.type; + entityID = rhs.entityID; isTrigger = rhs.isTrigger; dirty = true; - shape = rhs.shape; + material = rhs.material; positionOffset = rhs.positionOffset; + delete shape; + CopyShape(rhs.shape); + return *this; } @@ -115,19 +135,22 @@ namespace SHADE float SHCollider::GetFriction() const noexcept { - // TODO(Diren): Fix after implementing materials - return 0.0f; + return material.GetFriction(); } float SHCollider::GetBounciness() const noexcept { - // TODO(Diren): Fix after implementing materials - return 0.0f; + return material.GetBounciness(); } + float SHCollider::GetDensity() const noexcept { - // TODO(Diren): Fix after implementing materials - return 0.0f; + return material.GetDensity(); + } + + const SHPhysicsMaterial& SHCollider::GetMaterial() const noexcept + { + return material; } const SHVec3& SHCollider::GetPositionOffset() const noexcept @@ -145,22 +168,60 @@ namespace SHADE /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHCollider::SetAsBoundingBox(const SHVec3& halfExtents) + void SHCollider::SetBoundingBox(const SHVec3& halfExtents) { dirty = true; - type = Type::BOX; - delete shape; - shape = new SHBoundingBox{ positionOffset, halfExtents }; + // Set the half extents relative to transform + SHVec3 worldHalfExtents = halfExtents; + + const auto* transformComponent = SHComponentManager::GetComponent_s(entityID); + if (transformComponent != nullptr) + worldHalfExtents *= (transformComponent->GetWorldScale() * 0.5f); + + if (type == Type::BOX) + { + auto* box = reinterpret_cast(shape); + box->SetHalfExtents(worldHalfExtents); + } + else + { + type = Type::BOX; + + delete shape; + shape = new SHBoundingBox{ positionOffset, worldHalfExtents }; + } } - void SHCollider::SetAsBoundingSphere(float radius) + void SHCollider::SetBoundingSphere(float radius) { dirty = true; - type = Type::SPHERE; - delete shape; - shape = new SHBoundingSphere{ positionOffset, radius }; + // Set the radius relative to transform + float worldRadius = radius; + + const auto* transformComponent = SHComponentManager::GetComponent_s(entityID); + if (transformComponent != nullptr) + { + const SHVec3 TF_WORLD_SCALE = transformComponent->GetWorldScale(); + const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z }); + + worldRadius *= MAX_SCALE; + } + + if (type == Type::SPHERE) + { + auto* sphere = reinterpret_cast(shape); + sphere->SetRadius(worldRadius); + } + else + { + type = Type::SPHERE; + + delete shape; + shape = new SHBoundingSphere{ positionOffset, worldRadius }; + } + } void SHCollider::SetIsTrigger(bool trigger) noexcept @@ -172,23 +233,74 @@ namespace SHADE void SHCollider::SetFriction(float friction) noexcept { dirty = true; + material.SetFriction(friction); } void SHCollider::SetBounciness(float bounciness) noexcept { dirty = true; + material.SetBounciness(bounciness); } void SHCollider::SetDensity(float density) noexcept { dirty = true; + material.SetDensity(density); + } + + void SHCollider::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept + { + dirty = true; + material = newMaterial; } void SHCollider::SetPositionOffset(const SHVec3& posOffset) noexcept { dirty = true; positionOffset = posOffset; + + switch (type) + { + case Type::BOX: + { + reinterpret_cast(shape)->SetCenter(positionOffset); + break; + } + case Type::SPHERE: + { + reinterpret_cast(shape)->SetCenter(positionOffset); + break; + } + default: break; + } } + + /*-----------------------------------------------------------------------------------*/ + /* Private Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollider::CopyShape(const SHShape* rhs) + { + switch (type) + { + case Type::BOX: + { + const auto* RHS_BOX = reinterpret_cast(rhs); + + shape = new SHBoundingBox{ positionOffset, RHS_BOX->GetHalfExtents() }; + break; + } + case Type::SPHERE: + { + const auto* RHS_SPHERE = reinterpret_cast(rhs); + + shape = new SHBoundingSphere{ positionOffset, RHS_SPHERE->GetRadius() }; + break; + } + default: break; + } + } + } // namespace SHADE RTTR_REGISTRATION @@ -205,5 +317,4 @@ RTTR_REGISTRATION registration::class_("Collider") .property("Position Offset", &SHCollider::GetPositionOffset, &SHCollider::SetPositionOffset); - // TODO(Diren): Add Physics Materials } \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHCollider.h b/SHADE_Engine/src/Physics/SHCollider.h index 0e024f09..f760ffd0 100644 --- a/SHADE_Engine/src/Physics/SHCollider.h +++ b/SHADE_Engine/src/Physics/SHCollider.h @@ -13,8 +13,10 @@ #include // Project Headers +#include "ECS_Base/Entity/SHEntity.h" #include "Math/Geometry/SHShape.h" #include "Math/SHQuaternion.h" +#include "SHPhysicsMaterial.h" namespace SHADE { @@ -24,6 +26,15 @@ namespace SHADE class SH_API SHCollider { + private: + + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHColliderComponent; + friend class SHPhysicsObject; + public: /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -40,7 +51,7 @@ namespace SHADE /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHCollider (Type colliderType = Type::BOX); + SHCollider (EntityID eid, Type colliderType = Type::BOX, const SHPhysicsMaterial& physicsMaterial = SHPhysicsMaterial::DEFAULT); SHCollider (const SHCollider& rhs) noexcept; SHCollider (SHCollider&& rhs) noexcept; @@ -57,31 +68,33 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] bool HasChanged () const noexcept; + [[nodiscard]] bool HasChanged () const noexcept; - [[nodiscard]] bool IsTrigger () const noexcept; + [[nodiscard]] bool IsTrigger () const noexcept; - [[nodiscard]] Type GetType () const noexcept; + [[nodiscard]] Type GetType () const noexcept; - [[nodiscard]] float GetFriction () const noexcept; - [[nodiscard]] float GetBounciness () const noexcept; - [[nodiscard]] float GetDensity () const noexcept; + [[nodiscard]] float GetFriction () const noexcept; + [[nodiscard]] float GetBounciness () const noexcept; + [[nodiscard]] float GetDensity () const noexcept; + [[nodiscard]] const SHPhysicsMaterial& GetMaterial () const noexcept; - [[nodiscard]] const SHVec3& GetPositionOffset () const noexcept; + [[nodiscard]] const SHVec3& GetPositionOffset () const noexcept; - [[nodiscard]] SHShape* GetShape () noexcept; + [[nodiscard]] SHShape* GetShape () noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetAsBoundingBox (const SHVec3& halfExtents); - void SetAsBoundingSphere (float radius); + void SetBoundingBox (const SHVec3& halfExtents); + void SetBoundingSphere (float radius); - void SetIsTrigger (bool isTrigger) noexcept; - void SetFriction (float friction) noexcept; - void SetBounciness (float bounciness) noexcept; - void SetDensity (float density) noexcept; + void SetIsTrigger (bool isTrigger) noexcept; + void SetFriction (float friction) noexcept; + void SetBounciness (float bounciness) noexcept; + void SetDensity (float density) noexcept; + void SetMaterial (const SHPhysicsMaterial& newMaterial) noexcept; void SetPositionOffset (const SHVec3& positionOffset) noexcept; @@ -90,11 +103,19 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - Type type; - bool isTrigger; - bool dirty; - SHShape* shape; - SHVec3 positionOffset; + Type type; + EntityID entityID; // The entity this collider belongs to + bool isTrigger; + bool dirty; + SHShape* shape; + SHPhysicsMaterial material; + SHVec3 positionOffset; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + void CopyShape(const SHShape* rhs); RTTR_ENABLE() }; diff --git a/SHADE_Engine/src/Physics/SHPhysicsMaterial.cpp b/SHADE_Engine/src/Physics/SHPhysicsMaterial.cpp new file mode 100644 index 00000000..677e448f --- /dev/null +++ b/SHADE_Engine/src/Physics/SHPhysicsMaterial.cpp @@ -0,0 +1,104 @@ +/**************************************************************************************** + * \file SHPhysicsMaterial.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Physics Material. + * + * \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 "SHPhysicsMaterial.h" +// Project Headers +#include "Math/SHMathHelpers.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Static Data Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const SHPhysicsMaterial SHPhysicsMaterial::DEFAULT { 0.4f, 0.0f, 1.0f }; + + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsMaterial::SHPhysicsMaterial(float _friction, float _bounciness, float _density) noexcept + : friction { std::clamp(_friction, 0.0f, 1.0f) } + , bounciness{ std::clamp(_bounciness, 0.0f, 1.0f) } + , density { std::fabs(_density) } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHPhysicsMaterial::operator==(const SHPhysicsMaterial& rhs) const noexcept + { + return SHMath::CompareFloat(friction, rhs.friction) + && SHMath::CompareFloat(bounciness, rhs.bounciness) + && SHMath::CompareFloat(density, rhs.density); + } + + bool SHPhysicsMaterial::operator!=(const SHPhysicsMaterial& rhs) const noexcept + { + return !SHMath::CompareFloat(friction, rhs.friction) + || !SHMath::CompareFloat(bounciness, rhs.bounciness) + || !SHMath::CompareFloat(density, rhs.density); + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + float SHPhysicsMaterial::GetFriction() const noexcept + { + return friction; + } + + float SHPhysicsMaterial::GetBounciness() const noexcept + { + return bounciness; + } + + float SHPhysicsMaterial::GetDensity() const noexcept + { + return density; + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsMaterial::SetFriction(float newFriction) noexcept + { + if (newFriction < 0.0f || newFriction > 1.0f) + { + SHLOG_WARNING("Clamping friction of Physics Material between [0,1].") + } + friction = std::clamp(newFriction, 0.0f, 1.0f); + } + + void SHPhysicsMaterial::SetBounciness(float newBounciness) noexcept + { + if (newBounciness < 0.0f || newBounciness > 1.0f) + { + SHLOG_WARNING("Clamping bounciness of Physics Material between [0,1].") + } + bounciness = std::clamp(newBounciness, 0.0f, 1.0f); + } + + void SHPhysicsMaterial::SetDensity(float newDensity) noexcept + { + if (newDensity < 0.0f) + { + SHLOG_WARNING("Setting negative density of Physics Material to positive.") + } + density = std::fabs(newDensity); + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsMaterial.h b/SHADE_Engine/src/Physics/SHPhysicsMaterial.h new file mode 100644 index 00000000..b3db1655 --- /dev/null +++ b/SHADE_Engine/src/Physics/SHPhysicsMaterial.h @@ -0,0 +1,113 @@ +/**************************************************************************************** + * \file SHPhysicsMaterial.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Physics Material. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +// Project Headers +#include "SH_API.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SH_API SHPhysicsMaterial + { + public: + /*---------------------------------------------------------------------------------*/ + /* Static Data Members */ + /*---------------------------------------------------------------------------------*/ + + static const SHPhysicsMaterial DEFAULT; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHPhysicsMaterial (const SHPhysicsMaterial&) noexcept = default; + SHPhysicsMaterial (SHPhysicsMaterial&&) noexcept = default; + ~SHPhysicsMaterial() = default; + + /** + * @brief Default constructor for a physics material. + * @param friction The friction of the material. Clamped between [0,1]. Defaults to 0.4. + * @param bounciness The bounciness of the material. Clamped between [0,1]. + * @param density The mass density of the material. Always made positive. + */ + SHPhysicsMaterial (float friction = 0.4f, float bounciness = 0.0f, float density = 1.0f) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHPhysicsMaterial& operator= (const SHPhysicsMaterial&) noexcept = default; + SHPhysicsMaterial& operator= (SHPhysicsMaterial&&) noexcept = default; + + bool operator==(const SHPhysicsMaterial& rhs) const noexcept; + bool operator!=(const SHPhysicsMaterial& rhs) const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] float GetFriction () const noexcept; + [[nodiscard]] float GetBounciness () const noexcept; + [[nodiscard]] float GetDensity () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief Sets the friction coefficient of the physics material. + * @param newFriction The friction value to set. Clamped between [0,1]. + */ + void SetFriction (float newFriction) noexcept; + + /** + * @brief Sets the bounciness factor of the physics material. + * @param newBounciness The bounciness value to set. Clamped between [0,1]. + */ + void SetBounciness (float newBounciness) noexcept; + + /** + * @brief Sets the mass density of the physics material. + * @param newDensity The density value to set. Always made positive. + */ + void SetDensity (float newDensity) noexcept; + + private: + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief The friction coefficient of the physics object., clamped between [0,1].
+ * 0 means the object will never experience friction. + * 1 means the friction force against the object is equal to the applied force. + */ + float friction; + + /** + * @brief The bounciness factor of the physics object., clamped between [0,1].
+ * 0 means the object will never bounce. + * 1 means the object never loses energy on a bounce. + */ + float bounciness; + + /** + * @brief The density of the collider that determines the mass of the collision shape + * if it is automatically computed. Must be a positive number. + */ + float density; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/SHPhysicsObject.cpp index f9b476ef..4d4d8cd7 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsObject.cpp +++ b/SHADE_Engine/src/Physics/SHPhysicsObject.cpp @@ -26,8 +26,6 @@ namespace SHADE SHPhysicsObject::SHPhysicsObject(EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept : entityID { eid } - , isRigidBody { false } - , hasColliders{ false } , factory { physicsFactory } , world { physicsWorld } , rp3dBody { nullptr } @@ -130,42 +128,6 @@ namespace SHADE /* Public Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHPhysicsObject::CreateRigidBody(const SHTransformComponent* tf, SHRigidBodyComponent* rb, SHColliderComponent* c) - { - // If collider already exists, recreate the collision body as a rigid body - if (hasColliders) - world->destroyCollisionBody(rp3dBody); - - rp3dBody = world->createRigidBody(rp3d::Transform{ tf->GetWorldPosition(), tf->GetWorldRotation() }); - isRigidBody = true; - - rb->position = tf->GetWorldPosition(); - rb->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation()); - - if (hasColliders) - { - c->position = tf->GetWorldPosition(); - c->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation()); - // Get array of colliders and add them back into the rigidbody - for (auto& collider : c->colliders | std::views::keys) - AddCollider(&collider); - } - } - - void SHPhysicsObject::CreateCollisionBody(const SHTransformComponent* tf, SHColliderComponent* c) - { - if (rp3dBody == nullptr) - rp3dBody = world->createCollisionBody(rp3d::Transform{ tf->GetWorldPosition(), tf->GetWorldRotation() }); - - hasColliders = true; - - c->position = tf->GetWorldPosition(); - c->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation()); - - for (auto& collider : c->colliders | std::views::keys) - AddCollider(&collider); - } - int SHPhysicsObject::AddCollider(SHCollider* collider) { switch (collider->GetType()) @@ -193,31 +155,6 @@ namespace SHADE return static_cast(rp3dBody->getNbColliders()) - 1; } - void SHPhysicsObject::DestroyRigidBody(SHColliderComponent* c) noexcept - { - world->destroyRigidBody(reinterpret_cast(rp3dBody)); - - if (hasColliders) - { - // Preserve colliders as a collision body - rp3dBody = world->createCollisionBody(rp3d::Transform{ c->position, c->orientation }); - for (auto& collider : c->colliders | std::views::keys) - AddCollider(&collider); - } - - isRigidBody = false; - } - - void SHPhysicsObject::DestroyCollisionBody() noexcept - { - // Remove all colliders - for (uint32_t i = 0; i < rp3dBody->getNbColliders(); ++i) - { - auto* collider = rp3dBody->getCollider(i); - rp3dBody->removeCollider(collider); - } - } - void SHPhysicsObject::RemoveCollider(int index) { const int NUM_COLLIDERS = static_cast(rp3dBody->getNbColliders()); @@ -324,9 +261,9 @@ namespace SHADE void SHPhysicsObject::SyncColliders(SHColliderComponent* c) const noexcept { int index = 0; - for (auto& [collider, dirty] : c->colliders) + for (auto& collider : c->colliders) { - if (!dirty) + if (!collider.dirty) continue; // Update offsets @@ -356,7 +293,7 @@ namespace SHADE default: break; } - dirty = false; + collider.dirty = false; ++index; } } diff --git a/SHADE_Engine/src/Physics/SHPhysicsObject.h b/SHADE_Engine/src/Physics/SHPhysicsObject.h index 39a85421..67e5ec64 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsObject.h +++ b/SHADE_Engine/src/Physics/SHPhysicsObject.h @@ -69,13 +69,8 @@ namespace SHADE /* Function Members */ /*---------------------------------------------------------------------------------*/ - void CreateRigidBody (const SHTransformComponent* tf, SHRigidBodyComponent* rb, SHColliderComponent* c); - void CreateCollisionBody (const SHTransformComponent* tf, SHColliderComponent* c); int AddCollider (SHCollider* collider); - - void DestroyRigidBody (SHColliderComponent* c) noexcept; void RemoveCollider (int index); - void DestroyCollisionBody () noexcept; void SyncRigidBody (SHRigidBodyComponent* rb) const noexcept; void SyncColliders (SHColliderComponent* c) const noexcept; @@ -86,8 +81,6 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ EntityID entityID; - bool isRigidBody; - bool hasColliders; rp3d::PhysicsCommon* factory; rp3d::PhysicsWorld* world; diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp index a1994ad2..03241dd4 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp @@ -16,6 +16,8 @@ // Project Headers #include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHEntityManager.h" +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Editor/SHEditor.h" #include "Math/SHMathHelpers.h" #include "Scene/SHSceneManager.h" #include "Math/Transform/SHTransformComponent.h" @@ -175,11 +177,9 @@ namespace SHADE void SHPhysicsSystem::Init() { - using namespace rp3d; - // Create a physics world with the default settings - PhysicsWorld::WorldSettings settings; - settings.gravity = Vector3{ 0.0f, -9.81f, 0.0f }; + rp3d::PhysicsWorld::WorldSettings settings; + settings.gravity = SHVec3{ 0.0f, -9.81f, 0.0f }; settings.isSleepingEnabled = true; settings.defaultVelocitySolverNbIterations = 8; settings.defaultPositionSolverNbIterations = 3; @@ -190,6 +190,16 @@ namespace SHADE // Set up solvers world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::SPLIT_IMPULSES); + + // Subscribe to component events + + const std::shared_ptr ADD_COMPONENT_RECEIVER { std::make_shared>(this, &SHPhysicsSystem::AddPhysicsComponent) }; + const ReceiverPtr ADD_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast(ADD_COMPONENT_RECEIVER); + SHEventManager::SubscribeTo(SH_COMPONENT_ADDED_EVENT, ADD_COMPONENT_RECEIVER_PTR); + + const std::shared_ptr REMOVE_COMPONENT_RECEIVER { std::make_shared>(this, &SHPhysicsSystem::RemovePhysicsComponent) }; + const ReceiverPtr REMOVE_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast(REMOVE_COMPONENT_RECEIVER); + SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, REMOVE_COMPONENT_RECEIVER_PTR); } void SHPhysicsSystem::Exit() @@ -197,128 +207,83 @@ namespace SHADE factory.destroyPhysicsWorld(world); } - void SHPhysicsSystem::AddRigidBody(EntityID entityID) noexcept - { - //#ifdef _DEBUG - // SHLOG_INFO("Adding a Rigidbody to the Physics World.") - //#endif - - auto* physicsObject = CreatePhysicsObject(entityID); - - physicsObject->CreateRigidBody - ( - EnsureTransform(entityID), - SHComponentManager::GetComponent(entityID), - SHComponentManager::GetComponent_s(entityID) - ); - } - - void SHPhysicsSystem::AddCollider(EntityID entityID) noexcept - { - //#ifdef _DEBUG - // SHLOG_INFO("Adding a Collider to the Physics World.") - //#endif - - auto* physicsObject = CreatePhysicsObject(entityID); - - physicsObject->CreateCollisionBody - ( - EnsureTransform(entityID), - SHComponentManager::GetComponent(entityID) - ); - } - - void SHPhysicsSystem::RemoveRigidBody(EntityID entityID) noexcept - { - #ifdef _DEBUG - SHLOG_INFO("Removing a Rigidbody from the Physics World.") - #endif - - auto* physicsObject = GetPhysicsObject(entityID); - SHASSERT(physicsObject != nullptr, "Physics object has been lost from the world!") - - physicsObject->DestroyRigidBody(SHComponentManager::GetComponent_s(entityID)); - - if (physicsObject->rp3dBody == nullptr) - DestroyPhysicsObject(entityID); - } - - void SHPhysicsSystem::RemoveCollider(EntityID entityID) noexcept - { - #ifdef _DEBUG - SHLOG_INFO("Removing a Collider from the Physics World.") - #endif - } - - void SHPhysicsSystem::AddForce(EntityID entityID, const SHVec3& force) const noexcept - { - - } - - void SHPhysicsSystem::AddForceAtLocalPos(EntityID entityID, const SHVec3& force, const SHVec3& localPos) const noexcept - { - - } - - void SHPhysicsSystem::AddForceAtWorldPos(EntityID entityID, const SHVec3& force, const SHVec3& worldPos) const noexcept - { - - } - - void SHPhysicsSystem::AddRelativeForce(EntityID entityID, const SHVec3& relativeForce) const noexcept - { - - } - - void SHPhysicsSystem::AddRelativeForceAtLocalPos(EntityID entityID, const SHVec3& relativeForce, const SHVec3& localPos) const noexcept - { - - } - - void SHPhysicsSystem::AddRelativeForceAtWorldPos(EntityID entityID, const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept - { - - } - - void SHPhysicsSystem::AddTorque(EntityID entityID, const SHVec3& torque) const noexcept - { - - } - - void SHPhysicsSystem::AddRelativeTorque(EntityID entityID, const SHVec3& relativeTorque) const noexcept - { - - } - void SHPhysicsSystem::AddCollisionShape(EntityID entityID, SHCollider* collider) { auto* physicsObject = GetPhysicsObject(entityID); - physicsObject->AddCollider(collider); + + const SHPhysicsColliderAddedEvent COLLIDER_ADDED_EVENT_DATA + { + .entityID = entityID + , .colliderType = collider->GetType() + , .colliderIndex = physicsObject->AddCollider(collider) + }; + + SHEventManager::BroadcastEvent(COLLIDER_ADDED_EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT); } void SHPhysicsSystem::RemoveCollisionShape(EntityID entityID, int index) { - + auto* physicsObject = GetPhysicsObject(entityID); + physicsObject->RemoveCollider(index); + + const SHPhysicsColliderRemovedEvent COLLIDER_REMOVED_EVENT_DATA + { + .entityID = entityID + , .colliderIndex = index + }; + + SHEventManager::BroadcastEvent(COLLIDER_REMOVED_EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT); } void SHPhysicsSystem::PhysicsPreUpdate::Execute(double) noexcept { auto* system = reinterpret_cast(GetSystem()); + // Sync transforms + for (auto& [entityID, physicsObject] : system->map) + { + // Ensure a valid physics Object + if (physicsObject.rp3dBody == nullptr) + continue; + + const auto* transformComponent = SHComponentManager::GetComponent_s(entityID); + if (transformComponent && transformComponent->HasChanged()) + { + const auto WORLD_POS = transformComponent->GetWorldPosition(); + const auto WORLD_ROT = transformComponent->GetWorldOrientation(); + + physicsObject.SetPosition(WORLD_POS); + physicsObject.SetOrientation(WORLD_ROT); + + auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); + if (rigidBodyComponent) + { + rigidBodyComponent->position = WORLD_POS; + rigidBodyComponent->orientation = WORLD_ROT; + + // Clear all forces and velocities if editor is stopped + if (SHSystemManager::GetSystem()->editorState == SHEditor::State::STOP) + { + auto* rp3dRigidBody = reinterpret_cast(physicsObject.rp3dBody); + rp3dRigidBody->resetForce(); + rp3dRigidBody->resetTorque(); + rp3dRigidBody->setLinearVelocity(SHVec3::Zero); + rp3dRigidBody->setAngularVelocity(SHVec3::Zero); + } + } + + auto* colliderComponent = SHComponentManager::GetComponent_s(entityID); + if (colliderComponent) + { + colliderComponent->position = WORLD_POS; + colliderComponent->orientation = WORLD_ROT; + } + } + } + // Update bodies and colliders if component is dirty system->SyncRigidBodyComponents(SHComponentManager::GetDense()); system->SyncColliderComponents(SHComponentManager::GetDense()); - - // Sync transforms - for (auto& physicsObject : system->map | std::views::values) - { - const auto* TF = SHComponentManager::GetComponent(physicsObject.entityID); - if (TF->HasChanged()) - { - physicsObject.SetPosition(TF->GetWorldPosition()); - physicsObject.SetOrientation(TF->GetWorldOrientation()); - } - } } void SHPhysicsSystem::PhysicsFixedUpdate::Execute(double dt) noexcept @@ -359,7 +324,7 @@ namespace SHADE /* Private Function Member Definitions */ /*-----------------------------------------------------------------------------------*/ - SHPhysicsObject* SHPhysicsSystem::CreatePhysicsObject(EntityID entityID) noexcept + SHPhysicsObject* SHPhysicsSystem::EnsurePhysicsObject(EntityID entityID) noexcept { const auto it = map.find(entityID); if (it == map.end()) @@ -451,15 +416,18 @@ namespace SHADE const rp3d::Transform CURRENT_TF = physicsObject.rp3dBody->getTransform(); + auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); + auto* colliderComponent = SHComponentManager::GetComponent_s(entityID); + // Check if transform should be interpolated - if (physicsObject.isRigidBody) + if (rigidBodyComponent != nullptr) { - auto* rbComponent = SHComponentManager::GetComponent(entityID); - if (rbComponent->GetType() == SHRigidBodyComponent::Type::STATIC) + + if (rigidBodyComponent->GetType() == SHRigidBodyComponent::Type::STATIC) continue; - if (rbComponent->IsInterpolating()) + if (rigidBodyComponent->IsInterpolating()) { const rp3d::Transform PREV_TF = physicsObject.prevTransform; const rp3d::Transform INTERPOLATED_TF = rp3d::Transform::interpolateTransforms(PREV_TF, CURRENT_TF, static_cast(interpolationFactor)); @@ -474,12 +442,12 @@ namespace SHADE rp3dRot = CURRENT_TF.getOrientation(); } - rbComponent->position = CURRENT_TF.getPosition(); - rbComponent->orientation = CURRENT_TF.getOrientation(); + rigidBodyComponent->position = CURRENT_TF.getPosition(); + rigidBodyComponent->orientation = CURRENT_TF.getOrientation(); - if (physicsObject.hasColliders) + if (colliderComponent != nullptr) { - auto* colliderComponent = SHComponentManager::GetComponent(entityID); + colliderComponent->position = CURRENT_TF.getPosition(); colliderComponent->orientation = CURRENT_TF.getOrientation(); } @@ -491,28 +459,148 @@ namespace SHADE } // Convert RP3D Transform to SHADE - auto* tfComponent = SHComponentManager::GetComponent(entityID); - tfComponent->SetWorldPosition(rp3dPos); - tfComponent->SetWorldOrientation(SHQuaternion{ rp3dRot }); + auto* transformComponent = SHComponentManager::GetComponent(entityID); + transformComponent->SetWorldPosition(rp3dPos); + transformComponent->SetWorldOrientation(rp3dRot); // Cache transforms physicsObject.prevTransform = CURRENT_TF; } } - SHTransformComponent* SHPhysicsSystem::EnsureTransform(EntityID entityID) + SHEventHandle SHPhysicsSystem::AddPhysicsComponent(SHEventPtr addComponentEvent) { - auto* tf = SHComponentManager::GetComponent_s(entityID); + const auto& EVENT_DATA = reinterpret_cast*>(addComponentEvent.get()); - // Possibly redundant - if (!tf) + static const auto RIGID_BODY_ID = ComponentFamily::GetID(); + static const auto COLLIDER_ID = ComponentFamily::GetID(); + + const auto ADDED_ID = EVENT_DATA->data->addedComponentType; + const bool IS_PHYSICS_COMPONENT = ADDED_ID == RIGID_BODY_ID || ADDED_ID == COLLIDER_ID; + if (IS_PHYSICS_COMPONENT) { - SHComponentManager::AddComponent(entityID); - tf = SHComponentManager::GetComponent(entityID); + const EntityID ENTITY_ID = EVENT_DATA->data->eid; + auto* physicsObject = EnsurePhysicsObject(ENTITY_ID); + + auto* transformComponent = SHComponentManager::GetComponent_s(ENTITY_ID); + if (transformComponent == nullptr) + { + SHLOG_ERROR("Entity {} cannot add a Physics Component without a Transform! Component not created!", ENTITY_ID) + return EVENT_DATA->handle; + } + + auto* rigidBodyComponent = SHComponentManager::GetComponent_s(ENTITY_ID); + auto* colliderComponent = SHComponentManager::GetComponent_s(ENTITY_ID); + + if (ADDED_ID == RIGID_BODY_ID) + { + if (colliderComponent != nullptr) + { + world->destroyCollisionBody(physicsObject->rp3dBody); + physicsObject->rp3dBody = nullptr; + } + + rigidBodyComponent->position = transformComponent->GetWorldPosition(); + rigidBodyComponent->orientation = transformComponent->GetWorldOrientation(); + + physicsObject->rp3dBody = world->createRigidBody + ( + rp3d::Transform{ rigidBodyComponent->position, rigidBodyComponent->orientation } + ); + + rigidBodyComponent->rp3dBody = reinterpret_cast(physicsObject->rp3dBody); + + // Add collision shapes back into the body + if (colliderComponent != nullptr) + { + for (auto& collider : colliderComponent->colliders) + physicsObject->AddCollider(&collider); + } + } + + if (ADDED_ID == COLLIDER_ID) + { + SHASSERT(colliderComponent != nullptr, "Collider Component was not added to Entity " + std::to_string(ENTITY_ID) + "!"); + + colliderComponent->position = transformComponent->GetWorldPosition(); + colliderComponent->orientation = transformComponent->GetWorldOrientation(); + + if (physicsObject->rp3dBody == nullptr) + { + physicsObject->rp3dBody = world->createCollisionBody + ( + rp3d::Transform{ colliderComponent->position, colliderComponent->orientation } + ); + } + + // Add Collision Shapes + for (auto& collider : colliderComponent->colliders) + physicsObject->AddCollider(&collider); + } } - return tf; + return EVENT_DATA->handle; } + SHEventHandle SHPhysicsSystem::RemovePhysicsComponent(SHEventPtr removeComponentEvent) + { + const auto& EVENT_DATA = reinterpret_cast*>(removeComponentEvent.get()); + + static const auto RIGID_BODY_ID = ComponentFamily::GetID(); + static const auto COLLIDER_ID = ComponentFamily::GetID(); + + const auto REMOVED_ID = EVENT_DATA->data->removedComponentType; + const bool IS_PHYSICS_COMPONENT = REMOVED_ID == RIGID_BODY_ID || REMOVED_ID == COLLIDER_ID; + if (IS_PHYSICS_COMPONENT) + { + const EntityID ENTITY_ID = EVENT_DATA->data->eid; + auto* physicsObject = GetPhysicsObject(ENTITY_ID); + + SHASSERT(physicsObject != nullptr, "Physics object has been lost from the world!") + + if (REMOVED_ID == RIGID_BODY_ID) + { + world->destroyRigidBody(reinterpret_cast(physicsObject->rp3dBody)); + physicsObject->rp3dBody = nullptr; + + auto* colliderComponent = SHComponentManager::GetComponent_s(ENTITY_ID); + if (colliderComponent != nullptr) + { + // Preserve colliders as a collision body + physicsObject->rp3dBody = world->createCollisionBody + ( + rp3d::Transform{ colliderComponent->position, colliderComponent->orientation } + ); + + for (auto& collider : colliderComponent->colliders) + physicsObject->AddCollider(&collider); + } + + // Wake up all physics objects + for (auto& [entityID, object] : map) + { + if (SHComponentManager::HasComponent(entityID)) + reinterpret_cast(object.rp3dBody)->setIsSleeping(false); + } + } + + if (REMOVED_ID == COLLIDER_ID) + { + // Remove all colliders + const int NUM_COLLIDERS = static_cast(physicsObject->rp3dBody->getNbColliders()); + + for (int i = NUM_COLLIDERS - 1; i >= 0; --i) + { + auto* collider = physicsObject->rp3dBody->getCollider(i); + physicsObject->rp3dBody->removeCollider(collider); + } + } + + if (physicsObject->rp3dBody == nullptr) + DestroyPhysicsObject(ENTITY_ID); + } + + return EVENT_DATA->handle; + } } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/SHPhysicsSystem.h index bc6a1ba2..a3c3bea1 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/SHPhysicsSystem.h @@ -16,14 +16,14 @@ #include // Project Headers -#include "SHPhysicsObject.h" #include "Components/SHRigidBodyComponent.h" #include "Components/SHColliderComponent.h" -#include "Math/Transform/SHTransformComponent.h" - -#include "Scene/SHSceneGraph.h" #include "ECS_Base/System/SHSystemRoutine.h" #include "ECS_Base/System/SHFixedSystemRoutine.h" +#include "Math/Transform/SHTransformComponent.h" +#include "Scene/SHSceneGraph.h" +#include "SHPhysicsObject.h" + namespace SHADE @@ -32,7 +32,7 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - class SH_API SHPhysicsSystem : public SHSystem + class SH_API SHPhysicsSystem final : public SHSystem { public: /*---------------------------------------------------------------------------------*/ @@ -85,21 +85,10 @@ namespace SHADE void Init () override; void Exit () override; - void AddRigidBody (EntityID entityID) noexcept; - void AddCollider (EntityID entityID) noexcept; - void RemoveRigidBody (EntityID entityID) noexcept; - void RemoveCollider (EntityID entityID) noexcept; - - void AddForce (EntityID entityID, const SHVec3& force) const noexcept; - void AddForceAtLocalPos (EntityID entityID, const SHVec3& force, const SHVec3& localPos) const noexcept; - void AddForceAtWorldPos (EntityID entityID, const SHVec3& force, const SHVec3& worldPos) const noexcept; - - void AddRelativeForce (EntityID entityID, const SHVec3& relativeForce) const noexcept; - void AddRelativeForceAtLocalPos (EntityID entityID, const SHVec3& relativeForce, const SHVec3& localPos) const noexcept; - void AddRelativeForceAtWorldPos (EntityID entityID, const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept; - - void AddTorque (EntityID entityID, const SHVec3& torque) const noexcept; - void AddRelativeTorque (EntityID entityID, const SHVec3& relativeTorque) const noexcept; + //void AddRigidBody (EntityID entityID) noexcept; + //void AddCollider (EntityID entityID) noexcept; + //void RemoveRigidBody (EntityID entityID) noexcept; + //void RemoveCollider (EntityID entityID) noexcept; void AddCollisionShape (EntityID entityID, SHCollider* collider); void RemoveCollisionShape (EntityID entityID, int index); @@ -108,10 +97,7 @@ namespace SHADE /* System Routines */ /*---------------------------------------------------------------------------------*/ - /** - * @brief Synchronises RP3D with SHADE - */ - class SH_API PhysicsPreUpdate : public SHSystemRoutine + class SH_API PhysicsPreUpdate final : public SHSystemRoutine { public: /*-------------------------------------------------------------------------------*/ @@ -127,7 +113,7 @@ namespace SHADE void Execute(double dt) noexcept override; }; - class SH_API PhysicsFixedUpdate : public SHFixedSystemRoutine + class SH_API PhysicsFixedUpdate final : public SHFixedSystemRoutine { public: /*-------------------------------------------------------------------------------*/ @@ -143,7 +129,7 @@ namespace SHADE void Execute (double dt) noexcept override; }; - class SH_API PhysicsPostUpdate : public SHSystemRoutine + class SH_API PhysicsPostUpdate final : public SHSystemRoutine { public: /*-------------------------------------------------------------------------------*/ @@ -170,15 +156,14 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - // TODO(Diren): Store interpFactor - bool worldUpdated; double interpolationFactor; double fixedDT; - rp3d::PhysicsWorld* world; + rp3d::PhysicsWorld* world; rp3d::PhysicsCommon factory; + EntityObjectMap map; @@ -186,7 +171,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ - SHPhysicsObject* CreatePhysicsObject (EntityID entityID) noexcept; + SHPhysicsObject* EnsurePhysicsObject (EntityID entityID) noexcept; SHPhysicsObject* GetPhysicsObject (EntityID entityID) noexcept; void DestroyPhysicsObject (EntityID entityID) noexcept; @@ -194,11 +179,26 @@ namespace SHADE void SyncRigidBodyComponents (std::vector& denseArray) noexcept; void SyncColliderComponents (std::vector& denseArray) noexcept; void SyncTransforms () noexcept; - // TODO(Diren): Trigger handling - // TODO(Diren): Remove when responsibility shifted to editor - SHTransformComponent* EnsureTransform (EntityID entityID); + SHEventHandle AddPhysicsComponent (SHEventPtr addComponentEvent); + SHEventHandle RemovePhysicsComponent (SHEventPtr removeComponentEvent); }; + /*-----------------------------------------------------------------------------------*/ + /* Event Data Definitions */ + /*-----------------------------------------------------------------------------------*/ + + struct SHPhysicsColliderAddedEvent + { + EntityID entityID; + SHCollider::Type colliderType; + int colliderIndex; + }; + + struct SHPhysicsColliderRemovedEvent + { + EntityID entityID; + int colliderIndex; + }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Resource/SHHandle.hpp b/SHADE_Engine/src/Resource/SHHandle.hpp index 53061ac7..c5d14132 100644 --- a/SHADE_Engine/src/Resource/SHHandle.hpp +++ b/SHADE_Engine/src/Resource/SHHandle.hpp @@ -156,7 +156,6 @@ namespace std std::size_t hash, SHADE::Handle>>::operator()( std::pair, SHADE::Handle> const& pair) const { - return std::hash{}(pair.first.GetId().Raw) ^ std::hash{}(pair.second.GetId().Raw); } } diff --git a/SHADE_Engine/src/Resource/SHResourceManager.hpp b/SHADE_Engine/src/Resource/SHResourceManager.hpp index cff4e84b..072adaa2 100644 --- a/SHADE_Engine/src/Resource/SHResourceManager.hpp +++ b/SHADE_Engine/src/Resource/SHResourceManager.hpp @@ -136,11 +136,11 @@ namespace SHADE template std::optional SHResourceManager::GetAssetID(Handle handle) { - const Handle GENERIC_HANDLE = Handle(handle); + const Handle GENERIC_HANDLE = Handle(handle); auto [typedHandleMap, typedAssetIdMap] = getAssetHandleMap(); if (typedAssetIdMap.get().contains(GENERIC_HANDLE)) { - return typedAssetIdMap.GetId()[GENERIC_HANDLE]; + return typedAssetIdMap.get()[GENERIC_HANDLE]; } return {}; diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.cpp b/SHADE_Engine/src/Scene/SHSceneGraph.cpp index 950fd6a0..df46b3fb 100644 --- a/SHADE_Engine/src/Scene/SHSceneGraph.cpp +++ b/SHADE_Engine/src/Scene/SHSceneGraph.cpp @@ -582,9 +582,9 @@ namespace SHADE ReleaseNode(node); } - void SHSceneGraph::Traverse (const UnaryFunction& predicate) const + void SHSceneGraph::Traverse (const UnaryFunction& function) const { - TraverseAndInvokePredicate(root, predicate); + TraverseAndInvokeFunction(root, function); } /*-----------------------------------------------------------------------------------*/ @@ -621,12 +621,12 @@ namespace SHADE delete node; } - void SHSceneGraph::TraverseAndInvokePredicate(const SHSceneNode* node, const UnaryFunction& predicate) + void SHSceneGraph::TraverseAndInvokeFunction(const SHSceneNode* node, const UnaryFunction& function) { for (auto* child : node->children) { - predicate(child); - TraverseAndInvokePredicate(child, predicate); + function(child); + TraverseAndInvokeFunction(child, function); } } diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.h b/SHADE_Engine/src/Scene/SHSceneGraph.h index a4cf45eb..45ab48e5 100644 --- a/SHADE_Engine/src/Scene/SHSceneGraph.h +++ b/SHADE_Engine/src/Scene/SHSceneGraph.h @@ -142,7 +142,7 @@ namespace SHADE bool RemoveNode (SHSceneNode* nodeToRemove) noexcept; void Reset () noexcept; - void Traverse (const UnaryFunction& predicate) const; + void Traverse (const UnaryFunction& function) const; private: /*---------------------------------------------------------------------------------*/ @@ -158,9 +158,13 @@ namespace SHADE SHSceneNode* AllocateNode (EntityID entityID); void ReleaseNode (SHSceneNode* node) noexcept; - static void TraverseAndInvokePredicate (const SHSceneNode* node, const UnaryFunction& predicate); + static void TraverseAndInvokeFunction (const SHSceneNode* node, const UnaryFunction& function); }; + /*-----------------------------------------------------------------------------------*/ + /* Event Data Definitions */ + /*-----------------------------------------------------------------------------------*/ + struct SHSceneGraphChangeParentEvent { SHSceneNode* node; diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index fea59353..21ce7b82 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -24,6 +24,7 @@ of DigiPen Institute of Technology is prohibited. #include "Events/SHEvent.h" #include "Events/SHEventReceiver.h" #include "Events/SHEventManager.hpp" +#include "Physics/SHPhysicsSystem.h" namespace SHADE { @@ -60,7 +61,7 @@ namespace SHADE // Initialise the CSharp Engine csEngineInit(); - // Register entity creation events + // Register all events registerEvents(); } void SHScriptEngine::UnloadScriptAssembly() @@ -191,6 +192,12 @@ namespace SHADE // 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); + // If debug, we want to copy the PDB so that we can do script debugging + if (debug) + { + std::filesystem::copy_file("./tmp/SHADE_Scripting.pdb", "SHADE_Scripting.pdb", std::filesystem::copy_options::overwrite_existing); + } + oss << "[ScriptEngine] Successfully built Managed Script Assembly (" << MANAGED_SCRIPT_LIB_NAME << ")!"; SHLOG_INFO(oss.str()); } @@ -255,6 +262,10 @@ namespace SHADE ..\\bin\\Debug\\SHADE_Managed.dll\n\ ..\\bin\\Release\\SHADE_Managed.dll\n\ \n\ + \n\ + ..\\bin\\Debug\\SHADE_CSharp.dll\n\ + ..\\bin\\Release\\SHADE_CSharp.dll\n\ + \n\ \n\ "; @@ -280,6 +291,28 @@ namespace SHADE return eventData->handle; } + SHEventHandle SHScriptEngine::onColliderAdded(SHEventPtr eventPtr) + { + auto eventData = reinterpret_cast*>(eventPtr.get()); + csColliderOnListChanged(eventData->data->entityID); + return eventData->handle; + } + + SHEventHandle SHScriptEngine::onColliderRemoved(SHEventPtr eventPtr) + { + auto eventData = reinterpret_cast*>(eventPtr.get()); + csColliderOnListChanged(eventData->data->entityID); + return eventData->handle; + } + + SHEventHandle SHScriptEngine::onColliderComponentRemoved(SHEventPtr eventPtr) + { + auto eventData = reinterpret_cast*>(eventPtr.get()); + if (eventData->data->removedComponentType == ComponentFamily::GetID()) + csColliderOnRemoved(eventData->data->eid); + return eventData->handle; + } + /*-----------------------------------------------------------------------------------*/ /* Helper Functions */ /*-----------------------------------------------------------------------------------*/ @@ -380,6 +413,18 @@ namespace SHADE DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", "DeserialiseScripts" ); + csColliderOnListChanged = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".Collider", + "OnCollisionShapeChanged" + ); + csColliderOnRemoved = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".Collider", + "OnCollisionShapeRemoved" + ); csEditorRenderScripts = dotNet.GetFunctionPtr ( DEFAULT_CSHARP_LIB_NAME, @@ -407,8 +452,28 @@ namespace SHADE { std::make_shared>(this, &SHScriptEngine::onEntityDestroyed) }; - ReceiverPtr receiver = std::dynamic_pointer_cast(destroyedEventReceiver); - SHEventManager::SubscribeTo(SH_ENTITY_DESTROYED_EVENT, receiver); + SHEventManager::SubscribeTo(SH_ENTITY_DESTROYED_EVENT, std::dynamic_pointer_cast(destroyedEventReceiver)); + + // Register for collider added event + std::shared_ptr> addedColliderEventReceiver + { + std::make_shared>(this, &SHScriptEngine::onColliderAdded) + }; + SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_ADDED_EVENT, std::dynamic_pointer_cast(addedColliderEventReceiver)); + + // Register for collider removed event + std::shared_ptr> removedColliderEventReceiver + { + std::make_shared>(this, &SHScriptEngine::onColliderRemoved) + }; + SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_REMOVED_EVENT, std::dynamic_pointer_cast(removedColliderEventReceiver)); + + // Register for collider component removed event + std::shared_ptr> removedColliderComponentEventReceiver + { + std::make_shared>(this, &SHScriptEngine::onColliderComponentRemoved) + }; + SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, std::dynamic_pointer_cast(removedColliderComponentEventReceiver)); } void SHScriptEngine::dumpBuildLog(const std::string_view& buildLogPath) diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.h b/SHADE_Engine/src/Scripting/SHScriptEngine.h index 137d978f..c38e3618 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.h +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.h @@ -218,6 +218,7 @@ namespace SHADE using CsScriptSerialiseYamlFuncPtr = bool(*)(EntityID, void*); using CsScriptDeserialiseYamlFuncPtr = bool(*)(EntityID, const void*); using CsScriptEditorFuncPtr = void(*)(EntityID); + using CsEventRelayFuncPtr = void(*)(EntityID); /*-----------------------------------------------------------------------------*/ /* Constants */ @@ -250,6 +251,9 @@ namespace SHADE CsScriptOptionalFuncPtr csScriptsRemoveAllImmediately = nullptr; CsScriptSerialiseYamlFuncPtr csScriptsSerialiseYaml = nullptr; CsScriptDeserialiseYamlFuncPtr csScriptsDeserialiseYaml = nullptr; + // - Events + CsEventRelayFuncPtr csColliderOnListChanged = nullptr; + CsEventRelayFuncPtr csColliderOnRemoved = nullptr; // - Editor CsScriptEditorFuncPtr csEditorRenderScripts = nullptr; CsFuncPtr csEditorUndo = nullptr; @@ -259,6 +263,9 @@ namespace SHADE /* Event Handler Functions */ /*-----------------------------------------------------------------------------*/ SHEventHandle onEntityDestroyed(SHEventPtr eventPtr); + SHEventHandle onColliderAdded(SHEventPtr eventPtr); + SHEventHandle onColliderRemoved(SHEventPtr eventPtr); + SHEventHandle onColliderComponentRemoved(SHEventPtr eventPtr); /*-----------------------------------------------------------------------------*/ /* Helper Functions */ diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index 3804db95..79c8308f 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -1,8 +1,8 @@ #include "SHpch.h" -#include "SHSerializationHelper.hpp" -#include "SHSerialization.h" #include +#include "SHSerializationHelper.hpp" +#include "SHSerialization.h" #include "ECS_Base/Managers/SHEntityManager.h" #include "Scene/SHSceneManager.h" @@ -186,7 +186,7 @@ namespace SHADE } if (const auto renderable = SHComponentManager::GetComponent_s(eid)) { - components[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(renderable); + components[rttr::type::get().get_name().data()] = *renderable; } if (const auto rigidbody = SHComponentManager::GetComponent_s(eid)) { @@ -259,5 +259,6 @@ namespace SHADE if (!componentsNode) return; SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); + SHSerializationHelper::ConvertNodeToComponent(componentsNode, eid); } } diff --git a/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp b/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp index da98c885..a8e46d88 100644 --- a/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp +++ b/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp @@ -1,7 +1,7 @@ #pragma once -#include "ECS_Base/Components/SHComponent.h" #include +#include "ECS_Base/Components/SHComponent.h" #include @@ -9,6 +9,207 @@ #include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec4.h" +#include "Resource/SHResourceManager.h" +#include "Graphics/MiddleEnd/Interface/SHRenderable.h" +#include "Graphics/MiddleEnd/Interface/SHMaterial.h" +#include "SHSerializationTools.h" + +namespace YAML +{ + using namespace SHADE; + template<> + struct convert + { + static constexpr std::string_view VERT_SHADER_YAML_TAG = "VertexShader"; + static constexpr std::string_view FRAG_SHADER_YAML_TAG = "FragmentShader"; + static constexpr std::string_view SUBPASS_YAML_TAG = "SubPass"; + static constexpr std::string_view PROPS_YAML_TAG = "Properties"; + + static YAML::Node encode(SHMaterial const& rhs) + { + // Write Properties + YAML::Node propertiesNode; + Handle pipelineProperties = rhs.GetShaderBlockInterface(); + for (int i = 0; i < static_cast(pipelineProperties->GetVariableCount()); ++i) + { + const SHShaderBlockInterface::Variable* VARIABLE = pipelineProperties->GetVariable(i); + if (!VARIABLE) + break; + const std::string& VAR_NAME = pipelineProperties->GetVariableName(i); + YAML::Node propNode; + switch (VARIABLE->type) + { + case SHADE::SHShaderBlockInterface::Variable::Type::FLOAT: + propNode = rhs.GetProperty(VARIABLE->offset); + break; + case SHADE::SHShaderBlockInterface::Variable::Type::INT: + propNode = rhs.GetProperty(VARIABLE->offset); + break; + case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR2: + propNode = SHSerializationTools::ValToYAML(rhs.GetProperty(VARIABLE->offset)); + break; + case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR3: + propNode = SHSerializationTools::ValToYAML(rhs.GetProperty(VARIABLE->offset)); + break; + case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR4: + propNode = SHSerializationTools::ValToYAML(rhs.GetProperty(VARIABLE->offset)); + break; + case SHADE::SHShaderBlockInterface::Variable::Type::OTHER: + default: + continue; + break; + } + propertiesNode[VAR_NAME.data()] = propNode; + } + + // Get Shader Handles + const auto& SHADERS = rhs.GetPipeline()->GetPipelineLayout()->GetShaderModules(); + Handle vertexShader, fragShader; + for (const auto& shader : SHADERS) + { + const auto FLAG_BITS = shader->GetShaderStageFlagBits(); + if (FLAG_BITS & vk::ShaderStageFlagBits::eVertex) + vertexShader = shader; + else if (FLAG_BITS & vk::ShaderStageFlagBits::eFragment) + fragShader = shader; + } + + // Write Material + YAML::Node node; + + node[VERT_SHADER_YAML_TAG.data()] = 0; // SHResourceManager::GetAssetID(vertexShader).value_or(0); + node[FRAG_SHADER_YAML_TAG.data()] = 0; // SHResourceManager::GetAssetID(fragShader).value_or(0); + node[SUBPASS_YAML_TAG.data()] = rhs.GetPipeline()->GetPipelineState().GetSubpass()->GetName(); + node[PROPS_YAML_TAG.data()] = propertiesNode; + + return node; + } + static bool decode(YAML::Node const& node, SHMaterial& rhs) + { + /* + // Retrieve Shader Asset IDs + AssetID vertShaderId = 0; + AssetID fragShaderId = 0; + if (node[VERT_SHADER_YAML_TAG.data()]) + vertShaderId = node[VERT_SHADER_YAML_TAG.data()].as(); + if (node[FRAG_SHADER_YAML_TAG.data()]) + fragShaderId = node[FRAG_SHADER_YAML_TAG.data()].as(); + + // Ensure that both shaders are present + if (vertShaderId == 0 || fragShaderId == 0) + return false; // No pipeline + + // Get Shader Modules + Handle vertexShader, fragShader; + vertexShader = SHResourceManager::LoadOrGet(vertShaderId); + fragShader = SHResourceManager::LoadOrGet(fragShaderId); + + // Get Pipeline Library + if (node[SUBPASS_YAML_TAG.data()]) + { + auto gfxSystem = SHSystemManager::GetSystem(); + if (!gfxSystem) + return false; + + // Grab subpass from worldRenderer + auto renderPass = gfxSystem->GetPrimaryRenderpass(); + if (!renderPass) + return false; + auto subPass = renderPass->GetSubpass(node[SUBPASS_YAML_TAG.data()].as()); + if (!subPass) + return false; + + // Set Pipeline + rhs.SetPipeline(renderPass->GetOrCreatePipeline + ( + std::make_pair(vertexShader, fragShader), + subPass + )); + } + */ + + // TODO: Load Proper Material! + // Set default material + auto gfxSystem = SHSystemManager::GetSystem(); + if (!gfxSystem) + return false; + rhs.SetPipeline(gfxSystem->GetDefaultMaterial()->GetPipeline()); + + if (node[PROPS_YAML_TAG.data()]) + { + // Loop through all properties + Handle pipelineProperties = rhs.GetShaderBlockInterface(); + const YAML::Node& PROPS_NODE = node[PROPS_YAML_TAG.data()]; + for (int i = 0; i < static_cast(pipelineProperties->GetVariableCount()); ++i) + { + const std::string& PROP_NAME = pipelineProperties->GetVariableName(i); + const auto& PROP_NODE = PROPS_NODE[PROP_NAME.data()]; + if (PROP_NODE) + { + const std::string& VAR_NAME = pipelineProperties->GetVariableName(i); + const SHShaderBlockInterface::Variable* VARIABLE = pipelineProperties->GetVariable(i); + switch (VARIABLE->type) + { + case SHADE::SHShaderBlockInterface::Variable::Type::FLOAT: + rhs.SetProperty(VARIABLE->offset, PROP_NODE.as()); + break; + case SHADE::SHShaderBlockInterface::Variable::Type::INT: + rhs.SetProperty(VARIABLE->offset, PROP_NODE.as()); + break; + case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR2: + rhs.SetProperty(VARIABLE->offset, SHSerializationTools::YAMLToVec2(PROP_NODE)); + break; + case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR3: + rhs.SetProperty(VARIABLE->offset, SHSerializationTools::YAMLToVec3(PROP_NODE)); + break; + case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR4: + rhs.SetProperty(VARIABLE->offset, SHSerializationTools::YAMLToVec4(PROP_NODE)); + break; + case SHADE::SHShaderBlockInterface::Variable::Type::OTHER: + default: + continue; + break; + } + } + } + } + return true; + } + }; + + template<> + struct convert + { + static constexpr std::string_view MESH_YAML_TAG = "Mesh"; + static constexpr std::string_view MAT_YAML_TAG = "Material"; + + static YAML::Node encode(SHRenderable const& rhs) + { + YAML::Node node; + node[MESH_YAML_TAG.data()] = SHResourceManager::GetAssetID(rhs.GetMesh()).value_or(0); + node[MAT_YAML_TAG.data()] = 0; // TODO: Asset ID + return node; + } + static bool decode(YAML::Node const& node, SHRenderable& rhs) + { + if (node[MESH_YAML_TAG.data()]) + { + rhs.SetMesh(SHResourceManager::LoadOrGet(node[MESH_YAML_TAG.data()].as())); + } + if (node[MAT_YAML_TAG.data()]) + { + // TODO: Convert Asset ID To Material HAndle + // Temporarily, use default material + auto gfxSystem = SHSystemManager::GetSystem(); + if (!gfxSystem) + return false; + rhs.SetMaterial(gfxSystem->AddOrGetBaseMaterialInstance(gfxSystem->GetDefaultMaterial())); + } + return true; + } + }; +} + namespace SHADE { @@ -126,18 +327,15 @@ namespace SHADE auto propType = prop.get_type(); if (propType == rttr::type::get()) { - SHVec4 vec{ propertyNode["X"].as(), propertyNode["Y"].as(), propertyNode["Z"].as(), propertyNode["W"].as() }; - prop.set_value(component, vec); + prop.set_value(component, SHSerializationTools::YAMLToVec4(propertyNode)); } else if (propType == rttr::type::get()) { - SHVec3 vec{ propertyNode["X"].as(), propertyNode["Y"].as(), propertyNode["Z"].as() }; - prop.set_value(component, vec); + prop.set_value(component, SHSerializationTools::YAMLToVec3(propertyNode)); } else if (propType == rttr::type::get()) { - SHVec2 vec{ propertyNode["X"].as(), propertyNode["Y"].as() }; - prop.set_value(component, vec); + prop.set_value(component, SHSerializationTools::YAMLToVec2(propertyNode)); } else if (propType.is_arithmetic()) { @@ -200,5 +398,18 @@ namespace SHADE } } + template , bool> = true> + static void ConvertNodeToComponent(YAML::Node const& componentsNode, EntityID const& eid) + { + auto component = SHComponentManager::GetComponent_s(eid); + if (componentsNode.IsNull() && !component) + return; + auto rttrType = rttr::type::get(); + auto componentNode = componentsNode[rttrType.get_name().data()]; + if (componentsNode.IsNull()) + return; + YAML::convert::decode(componentNode, *component); + } + }; } diff --git a/SHADE_Engine/src/Serialization/SHSerializationTools.cpp b/SHADE_Engine/src/Serialization/SHSerializationTools.cpp new file mode 100644 index 00000000..86a74613 --- /dev/null +++ b/SHADE_Engine/src/Serialization/SHSerializationTools.cpp @@ -0,0 +1,67 @@ +/************************************************************************************//*! +\file SHSerializationTools.cpp +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 22, 2022 +\brief Contains the definition of functions of the SHSerializationTools class. + + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#include "SHpch.h" +#include "SHSerializationTools.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* YAML Serialization Functions */ + /*-----------------------------------------------------------------------------------*/ + YAML::Node SHSerializationTools::ValToYAML(const SHVec2& vec) + { + YAML::Node node; + node.SetStyle(YAML::EmitterStyle::Flow); + node["X"] = vec.x; + node["Y"] = vec.y; + return node; + } + YAML::Node SHSerializationTools::ValToYAML(const SHVec3& vec) + { + YAML::Node node; + node.SetStyle(YAML::EmitterStyle::Flow); + node["X"] = vec.x; + node["Y"] = vec.y; + node["Z"] = vec.z; + return node; + } + YAML::Node SHSerializationTools::ValToYAML(const SHVec4& vec) + { + YAML::Node node; + node.SetStyle(YAML::EmitterStyle::Flow); + node["X"] = vec.x; + node["Y"] = vec.y; + node["Z"] = vec.z; + node["W"] = vec.w; + return node; + } + + /*-----------------------------------------------------------------------------------*/ + /* YAML Deserialization Functions */ + /*-----------------------------------------------------------------------------------*/ + SHVec2 SHSerializationTools::YAMLToVec2(const YAML::Node& node) + { + return SHVec2 { node["X"].as(), node["Y"].as() }; + } + + SHVec3 SHSerializationTools::YAMLToVec3(const YAML::Node& node) + { + return SHVec3 { node["X"].as(), node["Y"].as(), node["Z"].as() }; + } + + SHVec4 SHSerializationTools::YAMLToVec4(const YAML::Node& node) + { + return SHVec4 { node["X"].as(), node["Y"].as(), node["Z"].as(), node["W"].as() }; + } + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Serialization/SHSerializationTools.h b/SHADE_Engine/src/Serialization/SHSerializationTools.h new file mode 100644 index 00000000..3a3f6645 --- /dev/null +++ b/SHADE_Engine/src/Serialization/SHSerializationTools.h @@ -0,0 +1,54 @@ +/************************************************************************************//*! +\file SHSerializationTools.h +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 22, 2022 +\brief Contains the class definition of SHSerializationTools. + + +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 + +// External Dependencies +#include +// Project Includes +#include "SH_API.h" +#include "Math/Vector/SHVec2.h" +#include "Math/Vector/SHVec3.h" +#include "Math/Vector/SHVec4.h" + +namespace SHADE +{ + /*************************************************************************************/ + /*! + \brief + Static class that contains useful functions for converting values to YAML Nodes + and vice versa. + */ + /*************************************************************************************/ + class SH_API SHSerializationTools + { + public: + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + SHSerializationTools() = delete; + + /*---------------------------------------------------------------------------------*/ + /* YAML Serialization Functions */ + /*---------------------------------------------------------------------------------*/ + static YAML::Node ValToYAML(const SHVec2& vec); + static YAML::Node ValToYAML(const SHVec3& vec); + static YAML::Node ValToYAML(const SHVec4& vec); + + /*---------------------------------------------------------------------------------*/ + /* YAML Deserialization Functions */ + /*---------------------------------------------------------------------------------*/ + static SHVec2 YAMLToVec2(const YAML::Node& node); + static SHVec3 YAMLToVec3(const YAML::Node& node); + static SHVec4 YAMLToVec4(const YAML::Node& node); + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Tools/SHLog.cpp b/SHADE_Engine/src/Tools/SHLog.cpp index 2d0b7b58..30a79338 100644 --- a/SHADE_Engine/src/Tools/SHLog.cpp +++ b/SHADE_Engine/src/Tools/SHLog.cpp @@ -51,4 +51,24 @@ namespace SHADE } #endif + void SHLog_Info(const char* msg) noexcept + { + SHLOG_INFO(msg) + } + + void SHLog_Warning(const char* msg) noexcept + { + SHLOG_WARNING(msg) + } + + void SHLog_Error(const char* msg) noexcept + { + SHLOG_ERROR(msg) + } + + void SHLog_Critical(const char* msg) noexcept + { + SHLOG_CRITICAL(msg) + } + } diff --git a/SHADE_Engine/src/Tools/SHLog.h b/SHADE_Engine/src/Tools/SHLog.h index b77042db..89dd9206 100644 --- a/SHADE_Engine/src/Tools/SHLog.h +++ b/SHADE_Engine/src/Tools/SHLog.h @@ -45,4 +45,12 @@ namespace SHADE static void Trace(const std::string& msg) noexcept; #endif }; + + extern "C" + { + static void SHLog_Info(const char* msg) noexcept; + static void SHLog_Warning(const char* msg) noexcept; + static void SHLog_Error(const char* msg) noexcept; + static void SHLog_Critical(const char* msg) noexcept; + } } diff --git a/SHADE_Managed/premake5.lua b/SHADE_Managed/premake5.lua index 6d37122c..906511c1 100644 --- a/SHADE_Managed/premake5.lua +++ b/SHADE_Managed/premake5.lua @@ -45,7 +45,8 @@ project "SHADE_Managed" { "yaml-cpp", "imgui", - "SHADE_Engine" + "SHADE_Engine", + "SHADE_CSharp" } disablewarnings diff --git a/SHADE_Managed/src/Components/Collider.cxx b/SHADE_Managed/src/Components/Collider.cxx new file mode 100644 index 00000000..f2119b43 --- /dev/null +++ b/SHADE_Managed/src/Components/Collider.cxx @@ -0,0 +1,257 @@ +/************************************************************************************//*! +\file Collider.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 20, 2022 +\brief Contains the definition of the functions of the managed Collider class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "Collider.hxx" +#include "Utility/Debug.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* ColliderBound - Constructors */ + /*---------------------------------------------------------------------------------*/ + CollisionShape::CollisionShape(int arrayIdx, Entity attachedEntity) + : arrayIndex { arrayIdx } + , entity { attachedEntity } + {} + + /*---------------------------------------------------------------------------------*/ + /* ColliderBound - Setter Functions */ + /*---------------------------------------------------------------------------------*/ + void CollisionShape::updateArrayIndex(int index) + { + arrayIndex = index; + } + + /*---------------------------------------------------------------------------------*/ + /* BoxColliderBound - Constructors */ + /*---------------------------------------------------------------------------------*/ + BoxCollider::BoxCollider(int arrayIdx, Entity attachedEntity) + : CollisionShape { arrayIndex, attachedEntity } + {} + + /*---------------------------------------------------------------------------------*/ + /* BoxColliderBound - Properties */ + /*---------------------------------------------------------------------------------*/ + Vector3 BoxCollider::Center::get() + { + return Convert::ToCLI(getNativeBoundObject().GetCenter()); + } + void BoxCollider::Center::set(Vector3 value) + { + getNativeBoundObject().SetCenter(Convert::ToNative(value)); + } + Vector3 BoxCollider::HalfExtents::get() + { + return Convert::ToCLI(getNativeBoundObject().GetHalfExtents()); + } + void BoxCollider::HalfExtents::set(Vector3 value) + { + getNativeBoundObject().SetHalfExtents(Convert::ToNative(value)); + } + Vector3 BoxCollider::Min::get() + { + return Convert::ToCLI(getNativeBoundObject().GetMin()); + } + void BoxCollider::Min::set(Vector3 value) + { + getNativeBoundObject().SetMin(Convert::ToNative(value)); + } + Vector3 BoxCollider::Max::get() + { + return Convert::ToCLI(getNativeBoundObject().GetMax()); + } + void BoxCollider::Max::set(Vector3 value) + { + getNativeBoundObject().SetMax(Convert::ToNative(value)); + } + + /*---------------------------------------------------------------------------------*/ + /* BoxColliderBound - Usage Functions */ + /*---------------------------------------------------------------------------------*/ + bool BoxCollider::TestPoint(Vector3 point) + { + return getNativeBoundObject().TestPoint(Convert::ToNative(point)); + } + bool BoxCollider::Raycast(Ray ray, float maxDistance) + { + return getNativeBoundObject().Raycast(Convert::ToNative(ray), maxDistance); + } + + /*---------------------------------------------------------------------------------*/ + /* BoxColliderBound - Properties */ + /*---------------------------------------------------------------------------------*/ + Vector3 SphereCollider::Center::get() + { + return Convert::ToCLI(getNativeBoundObject().GetCenter()); + } + void SphereCollider::Center::set(Vector3 value) + { + getNativeBoundObject().SetCenter(Convert::ToNative(value)); + } + float SphereCollider::Radius::get() + { + return getNativeBoundObject().GetRadius(); + } + void SphereCollider::Radius::set(float value) + { + getNativeBoundObject().SetRadius(value); + } + + /*---------------------------------------------------------------------------------*/ + /* SphereColliderBound - Usage Functions */ + /*---------------------------------------------------------------------------------*/ + bool SphereCollider::TestPoint(Vector3 point) + { + return getNativeBoundObject().TestPoint(Convert::ToNative(point)); + } + bool SphereCollider::Raycast(Ray ray, float maxDistance) + { + return getNativeBoundObject().Raycast(Convert::ToNative(ray), maxDistance); + } + + /*---------------------------------------------------------------------------------*/ + /* SphereColliderBound - Constructors */ + /*---------------------------------------------------------------------------------*/ + SphereCollider::SphereCollider(int arrayIndex, Entity attachedEntity) + : CollisionShape{ arrayIndex, attachedEntity } + {} + + /*---------------------------------------------------------------------------------*/ + /* Collider - Constructors */ + /*---------------------------------------------------------------------------------*/ + Collider::Collider(Entity entity) + : Component(entity) + { + // Create lists if they don't exist + if (colliders == nullptr) + colliders = gcnew ColliderMap; + if (!colliders->ContainsKey(entity)) + colliders->Add(entity, gcnew WeakReferenceList()); + + // Store a weak reference + colliders[entity]->Add(gcnew System::WeakReference(this)); + } + + /*---------------------------------------------------------------------------------*/ + /* Collider - Properties */ + /*---------------------------------------------------------------------------------*/ + int Collider::CollisionShapeCount::get() + { + return static_cast(GetNativeComponent()->GetColliders().size()); + } + + /*---------------------------------------------------------------------------------*/ + /* Collider - ColliderBound Functions */ + /*---------------------------------------------------------------------------------*/ + CollisionShape^ Collider::GetCollisionShape(int index) + { + // Populate the list if it hasn't been + if (subColliderList == nullptr) + { + updateSubColliderList(); + } + + // Check if valid + if (index < 0 || index >= subColliderList->Count) + throw gcnew System::ArgumentException("[Collider] Invalid index for Collider Bound retrieval."); + + // Return the bound + return subColliderList[index]; + } + generic + T Collider::GetCollisionShape(int index) + { + return safe_cast(GetCollisionShape(index)); + } + + /*---------------------------------------------------------------------------------*/ + /* Event Handling Functions */ + /*---------------------------------------------------------------------------------*/ + void Collider::OnCollisionShapeRemoved(EntityID entity) + { + SAFE_NATIVE_CALL_BEGIN + // Check if there are any colliders to update + if (colliders == nullptr || !colliders->ContainsKey(entity)) + return; + + // Remove the key + colliders->Remove(entity); + SAFE_NATIVE_CALL_END("Collider.OnColliderRemoved") + } + + void Collider::OnCollisionShapeChanged(EntityID entity) + { + SAFE_NATIVE_CALL_BEGIN + // Check if there are any colliders to update + if (colliders == nullptr || !colliders->ContainsKey(entity)) + return; + + // Update any colliders + System::Collections::Generic::List^ toRemove = gcnew System::Collections::Generic::List(); + WeakReferenceList^ collidersList = colliders[entity]; + for each (System::WeakReference^ wr in collidersList) + { + Collider^ collider = safe_cast(wr->Target); + // Update collider bounds + if (collider && collider->subColliderList != nullptr) + collider->updateSubColliderList(); + else + toRemove->Add(wr); + } + + // Sweep through and clear any invalid references while we're at it + for each (System::WeakReference ^ wr in toRemove) + { + collidersList->Remove(wr); + } + SAFE_NATIVE_CALL_END("Collider.OnColliderBoundChanged") + } + + void Collider::updateSubColliderList() + { + // Prepare the list + if (subColliderList) + subColliderList->Clear(); + else + subColliderList = gcnew System::Collections::Generic::List(); + + // Populate the list + int i = 0; + for (const auto& collider : GetNativeComponent()->GetColliders()) + { + CollisionShape^ bound = nullptr; + switch (collider.GetType()) + { + case SHCollider::Type::BOX: + bound = gcnew BoxCollider(i, Owner.GetEntity()); + break; + case SHCollider::Type::SPHERE: + bound = gcnew SphereCollider(i, Owner.GetEntity()); + break; + case SHCollider::Type::CAPSULE: + // TODO + break; + default: + Debug::LogWarning("[Collider] An invalid Collider Type was detected. Skipping."); + break; + } + ++i; + + // Add into list + subColliderList->Add(bound); + } + } +} diff --git a/SHADE_Managed/src/Components/Collider.h++ b/SHADE_Managed/src/Components/Collider.h++ new file mode 100644 index 00000000..1f8b43eb --- /dev/null +++ b/SHADE_Managed/src/Components/Collider.h++ @@ -0,0 +1,41 @@ +/************************************************************************************//*! +\file Collider.h++ +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 20, 2022 +\brief Contains the definition of templated functions for the managed Collider + and related classes. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Primary Include +#include "Component.hxx" +namespace SHADE +{ + template + CollisionShapeType& SHADE::CollisionShape::getNativeBoundObject() + { + SHColliderComponent* collider = SHComponentManager::GetComponent_s(entity); + if (!collider) + throw gcnew System::InvalidOperationException("Unable to retrieve Collider component!"); + + try + { + auto& bounds = collider->GetCollider(arrayIndex); + if (bounds.GetType() != SHCollider::Type::BOX) + throw gcnew System::InvalidOperationException("Attempted to retrieve invalid ColliderBound."); + + return reinterpret_cast(bounds); + } + catch (std::invalid_argument&) + { + throw gcnew System::IndexOutOfRangeException("Attempted to retrieve out of range ColliderBound!"); + } + } +} diff --git a/SHADE_Managed/src/Components/Collider.hxx b/SHADE_Managed/src/Components/Collider.hxx new file mode 100644 index 00000000..9555976f --- /dev/null +++ b/SHADE_Managed/src/Components/Collider.hxx @@ -0,0 +1,264 @@ +/************************************************************************************//*! +\file Collider.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 20, 2022 +\brief Contains the definition of the managed Collider class with the + declaration of functions for working with it. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// External Dependencies +#include "Physics/Components/SHColliderComponent.h" +// Project Includes +#include "Components/Component.hxx" +#include "Math/Vector3.hxx" +#include "Utility/Convert.hxx" +#include "Math/Ray.hxx" + +namespace SHADE +{ + /// + /// Base interface for all Collider Shapes. + /// + public ref class CollisionShape + { + public: + /*-----------------------------------------------------------------------------*/ + /* Usage Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Checks if the specified point is within this shape's bounds. + /// + /// Point to test with. + /// True if the point is in the shape's bounds. + virtual bool TestPoint(Vector3 point) = 0; + /// + /// Computes a Raycast and checks if there is a collision with any object. + /// + /// The ray to cast. + /// Maximum distance for the raycast check. + /// True if the ray intersects with an object in the scene. + virtual bool Raycast(Ray ray, float maxDistance) = 0; + + protected: + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + CollisionShape(int arrayIdx, Entity attachedEntity); + + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + int arrayIndex; // Index into the colliders vector on the native object + Entity entity; // Entity holding the collider component that this collider bounds is on + + /*-----------------------------------------------------------------------------*/ + /* Helper Functions */ + /*-----------------------------------------------------------------------------*/ + template + CollisionShapeType& getNativeBoundObject(); + + internal: + /*-----------------------------------------------------------------------------*/ + /* Setter Functions */ + /*-----------------------------------------------------------------------------*/ + void updateArrayIndex(int index); + }; + + /// + /// Box-shaped Collider Bound. + /// + public ref class BoxCollider : public CollisionShape + { + public: + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ + /// + /// Center of the Bounding Box formed by this bound. + /// + property Vector3 Center + { + Vector3 get(); + void set(Vector3 value); + } + /// + /// Half of the scale of the Bounding Box formed by this bound. + /// + property Vector3 HalfExtents + { + Vector3 get(); + void set(Vector3 value); + } + /// + /// Position of the bottom left back corner of the Bounding Box formed by this + /// bound. + /// + property Vector3 Min + { + Vector3 get(); + void set(Vector3 value); + } + /// + /// Position of the top right front corner of the Bounding Box formed by this + /// bound. + /// + property Vector3 Max + { + Vector3 get(); + void set(Vector3 value); + } + + /*-----------------------------------------------------------------------------*/ + /* ColliderBound Functions */ + /*-----------------------------------------------------------------------------*/ + /// + bool TestPoint(Vector3 point) override; + /// + bool Raycast(Ray ray, float maxDistance) override; + + internal: + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + BoxCollider(int arrayIndex, Entity attachedEntity); + }; + + /// + /// Sphere-shaped Collider Bound. + /// + public ref class SphereCollider : public CollisionShape + { + public: + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ + /// + /// Center of the Bounding Sphere formed by this bound. + /// + property Vector3 Center + { + Vector3 get(); + void set(Vector3 value); + } + /// + /// Radius of the Bounding Sphere formed by this bound. + /// + property float Radius + { + float get(); + void set(float value); + } + + /*-----------------------------------------------------------------------------*/ + /* ColliderBound Functions */ + /*-----------------------------------------------------------------------------*/ + /// + bool TestPoint(Vector3 point) override; + /// + bool Raycast(Ray ray, float maxDistance) override; + + internal: + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + SphereCollider(int arrayIndex, Entity attachedEntity); + }; + + /// + /// CLR version of the the SHADE Engine's SHColliderComponent. + /// A single Collider component can contain one or multiple Collider Bounds. + /// + public ref class Collider : public Component + { + internal: + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Constructs a Collider Component that represents a native SHColliderComponent + /// component tied to the specified Entity. + /// + /// Entity that this Component will be tied to. + Collider(Entity entity); + + public: + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ + /// + /// Total number of ColliderBounds in the Collider component. + /// + property int CollisionShapeCount + { + int get(); + } + + /*-----------------------------------------------------------------------------*/ + /* Usage Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Retrieves a ColliderBound at the specified index in the ColliderBound list. + /// + /// Index to retrieve a ColliderBound from. + /// ColliderBound for the specified index. + CollisionShape^ GetCollisionShape(int index); + /// + /// Retrieves a ColliderBound at the specified index in the ColliderBound list + /// and casts it to the appropriate type. + /// + /// Type of the ColliderBound to cast to. + /// Index to retrieve a ColliderBound from. + /// ColliderBound for the specified index. + generic where T:CollisionShape + T GetCollisionShape(int index); + + internal: + /*-----------------------------------------------------------------------------*/ + /* Event Handling Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// To be called from native code when a collision shape has been removed. + /// + /// The entity which has it's collision shape removed. + static void OnCollisionShapeRemoved(EntityID entity); + /// + /// To be called from native code when a Collision Shape has been changed. + /// + /// + /// The entity which has it's collision shape changed. + /// + static void OnCollisionShapeChanged(EntityID entity); + + private: + /*-----------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------*/ + using WeakReferenceList = System::Collections::Generic::List; + using ColliderMap = System::Collections::Generic::Dictionary; + + /*-----------------------------------------------------------------------------*/ + /* Static Data Members */ + /*-----------------------------------------------------------------------------*/ + static ColliderMap^ colliders; + + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + System::Collections::Generic::List^ subColliderList; + + /*-----------------------------------------------------------------------------*/ + /* Helper Functions */ + /*-----------------------------------------------------------------------------*/ + void updateSubColliderList(); + }; +} + +#include "Collider.h++" \ No newline at end of file diff --git a/SHADE_Managed/src/Components/RigidBody.cxx b/SHADE_Managed/src/Components/RigidBody.cxx new file mode 100644 index 00000000..172b928b --- /dev/null +++ b/SHADE_Managed/src/Components/RigidBody.cxx @@ -0,0 +1,197 @@ +/************************************************************************************//*! +\file RigidBody.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 22, 2022 +\brief Contains the definition of the functions of the managed RigidBody class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "RigidBody.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + RigidBody::RigidBody(Entity entity) + : Component(entity) + {} + + /*---------------------------------------------------------------------------------*/ + /* Properties */ + /*---------------------------------------------------------------------------------*/ + bool RigidBody::IsGravityEnabled::get() + { + return GetNativeComponent()->IsGravityEnabled(); + } + void RigidBody::IsGravityEnabled::set(bool value) + { + return GetNativeComponent()->SetGravityEnabled(value); + } + bool RigidBody::IsAllowedToSleep::get() + { + return GetNativeComponent()->IsAllowedToSleep(); + } + void RigidBody::IsAllowedToSleep::set(bool value) + { + return GetNativeComponent()->SetIsAllowedToSleep(value); + } + RigidBody::Type RigidBody::BodyType::get() + { + return static_cast(GetNativeComponent()->GetType()); + } + void RigidBody::BodyType::set(Type value) + { + return GetNativeComponent()->SetType(static_cast(value)); + } + float RigidBody::Mass::get() + { + return GetNativeComponent()->GetMass(); + } + void RigidBody::Mass::set(float value) + { + return GetNativeComponent()->SetMass(value); + } + float RigidBody::Drag::get() + { + return GetNativeComponent()->GetDrag(); + } + void RigidBody::Drag::set(float value) + { + return GetNativeComponent()->SetDrag(value); + } + float RigidBody::AngularDrag::get() + { + return GetNativeComponent()->GetAngularDrag(); + } + void RigidBody::AngularDrag::set(float value) + { + return GetNativeComponent()->SetAngularDrag(value); + } + bool RigidBody::FreezePositionX::get() + { + return GetNativeComponent()->GetFreezePositionX(); + } + void RigidBody::FreezePositionX::set(bool value) + { + return GetNativeComponent()->SetFreezePositionX(value); + } + bool RigidBody::FreezePositionY::get() + { + return GetNativeComponent()->GetFreezePositionY(); + } + void RigidBody::FreezePositionY::set(bool value) + { + return GetNativeComponent()->SetFreezePositionY(value); + } + bool RigidBody::FreezePositionZ::get() + { + return GetNativeComponent()->GetFreezePositionZ(); + } + void RigidBody::FreezePositionZ::set(bool value) + { + return GetNativeComponent()->SetFreezePositionZ(value); + } + bool RigidBody::FreezeRotationX::get() + { + return GetNativeComponent()->GetFreezeRotationX(); + } + void RigidBody::FreezeRotationX::set(bool value) + { + return GetNativeComponent()->SetFreezeRotationX(value); + } + bool RigidBody::FreezeRotationY::get() + { + return GetNativeComponent()->GetFreezeRotationY(); + } + void RigidBody::FreezeRotationY::set(bool value) + { + return GetNativeComponent()->SetFreezeRotationY(value); + } + bool RigidBody::FreezeRotationZ::get() + { + return GetNativeComponent()->GetFreezeRotationZ(); + } + void RigidBody::FreezeRotationZ::set(bool value) + { + return GetNativeComponent()->SetFreezeRotationZ(value); + } + Vector3 RigidBody::LinearVelocity::get() + { + return Convert::ToCLI(GetNativeComponent()->GetLinearVelocity()); + } + void RigidBody::LinearVelocity::set(Vector3 value) + { + return GetNativeComponent()->SetLinearVelocity(Convert::ToNative(value)); + } + Vector3 RigidBody::AngularVelocity::get() + { + return Convert::ToCLI(GetNativeComponent()->GetAngularVelocity()); + } + void RigidBody::AngularVelocity::set(Vector3 value) + { + return GetNativeComponent()->SetAngularVelocity(Convert::ToNative(value)); + } + Vector3 RigidBody::Force::get() + { + return Convert::ToCLI(GetNativeComponent()->GetForce()); + } + Vector3 RigidBody::Torque::get() + { + return Convert::ToCLI(GetNativeComponent()->GetTorque()); + } + + /*---------------------------------------------------------------------------------*/ + /* Force Functions */ + /*---------------------------------------------------------------------------------*/ + void RigidBody::AddForce(Vector3 force) + { + GetNativeComponent()->AddForce(Convert::ToNative(force)); + } + + void RigidBody::AddForceAtLocalPos(Vector3 force, Vector3 localPos) + { + GetNativeComponent()->AddForceAtLocalPos(Convert::ToNative(force), Convert::ToNative(localPos)); + } + + void RigidBody::AddForceAtWorldPos(Vector3 force, Vector3 worldPos) + { + GetNativeComponent()->AddForceAtWorldPos(Convert::ToNative(force), Convert::ToNative(worldPos)); + } + + void RigidBody::AddRelativeForce(Vector3 relativeForce) + { + GetNativeComponent()->AddRelativeForce(Convert::ToNative(relativeForce)); + } + + void RigidBody::AddRelativeForceAtLocalPos(Vector3 relativeForce, Vector3 localPos) + { + GetNativeComponent()->AddRelativeForceAtLocalPos(Convert::ToNative(relativeForce), Convert::ToNative(localPos)); + } + + void RigidBody::AddRelativeForceAtWorldPos(Vector3 relativeForce, Vector3 worldPos) + { + GetNativeComponent()->AddRelativeForceAtWorldPos(Convert::ToNative(relativeForce), Convert::ToNative(worldPos)); + } + + /*---------------------------------------------------------------------------------*/ + /* Torque Functions */ + /*---------------------------------------------------------------------------------*/ + void RigidBody::AddTorque(Vector3 torque) + { + GetNativeComponent()->AddTorque(Convert::ToNative(torque)); + } + + void RigidBody::AddRelativeTorque(Vector3 relativeTorque) + { + GetNativeComponent()->AddRelativeTorque(Convert::ToNative(relativeTorque)); + } +} \ No newline at end of file diff --git a/SHADE_Managed/src/Components/RigidBody.hxx b/SHADE_Managed/src/Components/RigidBody.hxx new file mode 100644 index 00000000..b3e031ba --- /dev/null +++ b/SHADE_Managed/src/Components/RigidBody.hxx @@ -0,0 +1,150 @@ +/************************************************************************************//*! +\file RigidBody.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 22, 2022 +\brief Contains the definition of the managed Collider class with the + declaration of functions for working with it. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// External Dependencies +#include "Physics/Components/SHRigidBodyComponent.h" +// Project Includes +#include "Components/Component.hxx" + +namespace SHADE +{ + /// + /// CLR version of the the SHADE Engine's SHRigidBodyComponent. + /// + public ref class RigidBody : public Component + { + internal: + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Constructs a RigidBody Component that represents a native + /// SHRigidBodyComponent component tied to the specified Entity. + /// + /// Entity that this Component will be tied to. + RigidBody(Entity entity); + + public: + /*-----------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------*/ + enum class Type + { + Static, + Kinematic, + Dynamic + }; + + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ + property bool IsGravityEnabled + { + bool get(); + void set(bool value); + } + property bool IsAllowedToSleep + { + bool get(); + void set(bool value); + } + property Type BodyType + { + Type get(); + void set(Type value); + } + property float Mass + { + float get(); + void set(float value); + } + property float Drag + { + float get(); + void set(float value); + } + property float AngularDrag + { + float get(); + void set(float value); + } + property bool FreezePositionX + { + bool get(); + void set(bool value); + } + property bool FreezePositionY + { + bool get(); + void set(bool value); + } + property bool FreezePositionZ + { + bool get(); + void set(bool value); + } + property bool FreezeRotationX + { + bool get(); + void set(bool value); + } + property bool FreezeRotationY + { + bool get(); + void set(bool value); + } + property bool FreezeRotationZ + { + bool get(); + void set(bool value); + } + property Vector3 LinearVelocity + { + Vector3 get(); + void set(Vector3 value); + } + property Vector3 AngularVelocity + { + Vector3 get(); + void set(Vector3 value); + } + property Vector3 Force + { + Vector3 get(); + } + property Vector3 Torque + { + Vector3 get(); + } + + /*-----------------------------------------------------------------------------*/ + /* Force Functions */ + /*-----------------------------------------------------------------------------*/ + void AddForce(Vector3 force); + void AddForceAtLocalPos(Vector3 force, Vector3 localPos); + void AddForceAtWorldPos(Vector3 force, Vector3 worldPos); + void AddRelativeForce(Vector3 relativeForce); + void AddRelativeForceAtLocalPos(Vector3 relativeForce, Vector3 localPos); + void AddRelativeForceAtWorldPos(Vector3 relativeForce, Vector3 worldPos); + + /*-----------------------------------------------------------------------------*/ + /* Torque Functions */ + /*-----------------------------------------------------------------------------*/ + void AddTorque(Vector3 force); + void AddRelativeTorque(Vector3 relativeForce); + }; + +} \ No newline at end of file diff --git a/SHADE_Managed/src/Editor/Editor.cxx b/SHADE_Managed/src/Editor/Editor.cxx index 120f0274..1097e203 100644 --- a/SHADE_Managed/src/Editor/Editor.cxx +++ b/SHADE_Managed/src/Editor/Editor.cxx @@ -68,36 +68,36 @@ using namespace System::Collections::Generic; /// The managed type of the object to edit. /// The native type of the object to edit. /// The SHEditorUI:: function to use for editing. -#define RENDER_FIELD_RANGE(MANAGED_TYPE, NATIVE_TYPE, FUNC) \ -(field->FieldType == MANAGED_TYPE::typeid) \ -{ \ - NATIVE_TYPE val = safe_cast(field->GetValue(object)); \ - NATIVE_TYPE oldVal = val; \ - \ - RangeAttribute^ rangeAttrib = hasAttribute(field); \ - const std::string FIELD_NAME = Convert::ToNative(field->Name); \ - bool changed = false; \ - if (rangeAttrib) \ - { \ - changed = SHEditorUI::InputSlider \ - ( \ - FIELD_NAME, \ - static_cast(rangeAttrib->Min), \ - static_cast(rangeAttrib->Max), \ - val, &isHovered \ - ); \ - } \ - else \ - { \ - changed = SHEditorUI::FUNC(FIELD_NAME, val, &isHovered); \ - } \ - \ - if (changed) \ - { \ - field->SetValue(object, val); \ - registerUndoAction(object, field, val, oldVal); \ - } \ -} \ +#define RENDER_FIELD_RANGE(MANAGED_TYPE, NATIVE_TYPE, FUNC) \ +(field->FieldType == MANAGED_TYPE::typeid) \ +{ \ + NATIVE_TYPE val = safe_cast(field->GetValue(object)); \ + NATIVE_TYPE oldVal = val; \ + \ + RangeAttribute^ rangeAttrib = hasAttribute(field);\ + const std::string FIELD_NAME = Convert::ToNative(field->Name); \ + bool changed = false; \ + if (rangeAttrib) \ + { \ + changed = SHEditorUI::InputSlider \ + ( \ + FIELD_NAME, \ + static_cast(rangeAttrib->Min), \ + static_cast(rangeAttrib->Max), \ + val, &isHovered \ + ); \ + } \ + else \ + { \ + changed = SHEditorUI::FUNC(FIELD_NAME, val, &isHovered); \ + } \ + \ + if (changed) \ + { \ + field->SetValue(object, val); \ + registerUndoAction(object, field, val, oldVal); \ + } \ +} \ /// /// Macro expansion that is used in renderFieldInInspector() to check the type of a field /// named "field" against the specified type and if it matches, retrieves the value of @@ -197,7 +197,7 @@ namespace SHADE void Editor::renderScriptInInspector(Entity entity, Script^ script, int index) { // Constants - const std::string LABEL = Convert::ToNative(script->GetType()->Name); + const std::string LABEL = Convert::ToNative(script->GetType()->Name); // Header SHEditorUI::PushID(index); @@ -286,6 +286,76 @@ namespace SHADE registerUndoAction(object, field, Convert::ToCLI(val), Convert::ToCLI(oldVal)); } } + else + { + array^ interfaces = field->FieldType->GetInterfaces(); + if (interfaces->Length > 0 && interfaces[0] == ICallbackEvent::typeid) + { + array^ typeArgs = field->FieldType->GenericTypeArguments; + System::String^ title = field->Name + " : CallbackEvent<"; + for (int i = 0; i < typeArgs->Length; ++i) + { + title += typeArgs[i]->Name; + if (i < typeArgs->Length - 1) + title += ", "; + } + title += ">"; + if (SHEditorUI::CollapsingHeader(Convert::ToNative(title))) + { + // Constants + const std::string LABEL = Convert::ToNative(field->Name); + SHEditorUI::PushID(LABEL); + + ICallbackEvent^ callbackEvent = safe_cast(field->GetValue(object)); + if (callbackEvent == nullptr) + { + // Construct one since it was not constructed before + callbackEvent = safe_cast(System::Activator::CreateInstance(field->FieldType)); + } + for each (ICallbackAction ^ action in callbackEvent->Actions) + { + if (action->IsRuntimeAction) + continue; + + // Attempt to get the object if any + int entityId = static_cast(-1); + if (action->TargetObject) + { + Script^ script = safe_cast(action->TargetObject); + if (script) + { + entityId = static_cast(script->Owner.GetEntity()); + } + } + SHEditorUI::InputInt("", entityId); + SHEditorUI::SameLine(); + System::String^ methodName = ""; + if (action->TargetMethodName != nullptr) + { + methodName = action->TargetMethodName; + } + std::string methodNameNative = Convert::ToNative(methodName); + SHEditorUI::InputTextField("", methodNameNative); + SHEditorUI::SameLine(); + if (SHEditorUI::Button("-")) + { + callbackEvent->DeregisterAction(action); + break; + } + } + if (SHEditorUI::Button("Add Action")) + { + callbackEvent->RegisterAction(); + } + + SHEditorUI::PopID(); + } + } + else + { + return; + } + } // Check if the field has a specific attribute TooltipAttribute^ toolTip = hasAttribute(field); diff --git a/SHADE_Managed/src/Engine/ECS.cxx b/SHADE_Managed/src/Engine/ECS.cxx index 4d62f643..df67c788 100644 --- a/SHADE_Managed/src/Engine/ECS.cxx +++ b/SHADE_Managed/src/Engine/ECS.cxx @@ -22,6 +22,8 @@ of DigiPen Institute of Technology is prohibited. // External Dependencies #include "ECS_Base/Managers/SHEntityManager.h" #include "Math/Transform/SHTransformComponent.h" +#include "Physics\Components\SHColliderComponent.h" +#include "Physics\Components\SHRigidBodyComponent.h" #include "Scene/SHSceneManager.h" #include "Scene/SHSceneGraph.h" #include "Tools/SHLog.h" @@ -29,6 +31,8 @@ of DigiPen Institute of Technology is prohibited. #include "Utility/Convert.hxx" #include "Utility/Debug.hxx" #include "Components/Transform.hxx" +#include "Components\RigidBody.hxx" +#include "Components\Collider.hxx" namespace SHADE { @@ -242,6 +246,8 @@ namespace SHADE static ECS::ECS() { componentMap.Add(createComponentSet()); + componentMap.Add(createComponentSet()); + componentMap.Add(createComponentSet()); } /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Math/Ray.cxx b/SHADE_Managed/src/Math/Ray.cxx new file mode 100644 index 00000000..ee614cbe --- /dev/null +++ b/SHADE_Managed/src/Math/Ray.cxx @@ -0,0 +1,28 @@ +/************************************************************************************//*! +\file Ray.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 20, 2022 +\brief Contains the definitions of functions of the Vector2 struct. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "Math/Ray.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + Ray::Ray(Vector3 origin, Vector3 direction) + : Origin { origin } + , Direction{ direction } + {} +} \ No newline at end of file diff --git a/SHADE_Managed/src/Math/Ray.hxx b/SHADE_Managed/src/Math/Ray.hxx new file mode 100644 index 00000000..c50191f8 --- /dev/null +++ b/SHADE_Managed/src/Math/Ray.hxx @@ -0,0 +1,50 @@ +/************************************************************************************//*! +\file Ray.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 20, 2021 +\brief Contains the definitions of Vector2 struct. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Project Includes +#include "Vector3.hxx" + +namespace SHADE +{ + /// + /// CLR version of the the SHADE Engine's Ray class that represents a ray in + /// 3-Dimensional space. + /// + public value struct Ray + { + public: + /*-----------------------------------------------------------------------------*/ + /* Public Members */ + /*-----------------------------------------------------------------------------*/ + /// + /// The start point of the ray. + /// + Vector3 Origin; + /// + /// The direction that a ray travels in. + /// + Vector3 Direction; + + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Creates a ray starting at origin along direction. + /// + /// Source of the ray. + /// Direction the ray travels in. + Ray(Vector3 origin, Vector3 direction); + }; +} diff --git a/SHADE_Managed/src/Scripts/ScriptStore.hxx b/SHADE_Managed/src/Scripts/ScriptStore.hxx index 4a9be721..9aa66fcd 100644 --- a/SHADE_Managed/src/Scripts/ScriptStore.hxx +++ b/SHADE_Managed/src/Scripts/ScriptStore.hxx @@ -132,7 +132,7 @@ namespace SHADE /// Immutable list of references to scripts of the specified type. /// generic where T : ref class, Script - static System::Collections::Generic::IEnumerable ^ GetScripts(Entity entity); + static System::Collections::Generic::IEnumerable^ GetScripts(Entity entity); /// /// Retrieves an immutable list of all scripts attached to a specified Entity. /// @@ -295,4 +295,4 @@ namespace SHADE 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/Serialisation/ReflectionUtilities.cxx b/SHADE_Managed/src/Serialisation/ReflectionUtilities.cxx index 3e963818..f114d01b 100644 --- a/SHADE_Managed/src/Serialisation/ReflectionUtilities.cxx +++ b/SHADE_Managed/src/Serialisation/ReflectionUtilities.cxx @@ -184,10 +184,6 @@ namespace SHADE void ReflectionUtilities::writeYamlIntoField(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node) { - if (fieldInfo->FieldType == System::Int16::typeid) - { - fieldInfo->SetValue(object, node.as()); - } if (fieldAssignYaml (fieldInfo, object, node) || fieldAssignYaml (fieldInfo, object, node) || fieldAssignYaml (fieldInfo, object, node) || diff --git a/SHADE_Managed/src/Utility/Convert.cxx b/SHADE_Managed/src/Utility/Convert.cxx index 4646194b..cb4815aa 100644 --- a/SHADE_Managed/src/Utility/Convert.cxx +++ b/SHADE_Managed/src/Utility/Convert.cxx @@ -37,6 +37,7 @@ namespace SHADE { return SHVec3(vec.x, vec.y, vec.z); } + Vector3 Convert::ToCLI(const SHVec3& vec) { return Vector3(vec.x, vec.y, vec.z); @@ -53,12 +54,22 @@ namespace SHADE SHQuaternion Convert::ToNative(Quaternion quat) { - return SHQuaternion{ quat.x, quat.y, quat.z, quat.w }; + return SHQuaternion{ quat.x, quat.y, quat.z, quat.w }; } Quaternion Convert::ToCLI(const SHQuaternion& quat) { - return Quaternion{ quat.x, quat.y, quat.z, quat.w }; + return Quaternion{ quat.x, quat.y, quat.z, quat.w }; + } + + SHRay Convert::ToNative(Ray vec) + { + return SHRay(ToNative(vec.Origin), ToNative(vec.Direction)); + } + + Ray Convert::ToCLI(const SHRay& vec) + { + return Ray(ToCLI(vec.position), ToCLI(vec.direction)); } /*---------------------------------------------------------------------------------*/ @@ -73,4 +84,4 @@ namespace SHADE { return msclr::interop::marshal_as(str); } -} // namespace PlushieAPI +} diff --git a/SHADE_Managed/src/Utility/Convert.hxx b/SHADE_Managed/src/Utility/Convert.hxx index d694ca6a..19faffde 100644 --- a/SHADE_Managed/src/Utility/Convert.hxx +++ b/SHADE_Managed/src/Utility/Convert.hxx @@ -19,11 +19,14 @@ of DigiPen Institute of Technology is prohibited. #include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec3.h" #include "Math/SHQuaternion.h" +#include "Math/SHRay.h" + // Project Includes #include "Engine/Entity.hxx" #include "Math/Vector2.hxx" #include "Math/Vector3.hxx" #include "Math/Quaternion.hxx" +#include "Math/Ray.hxx" namespace SHADE { @@ -88,6 +91,17 @@ namespace SHADE /// The native Quaternion to convert from. /// Managed copy of a native Quaternion. static Quaternion ToCLI(const SHQuaternion& quat); + /// Converts from a managed Vector2 to a native Vector2. + /// + /// The managed Vector2 to convert from. + /// Native copy of a managed Vector2. + static SHRay ToNative(Ray vec); + /// + /// Converts from a native Vector2 to a managed Vector2. + /// + /// The native Vector2 to convert from. + /// Managed copy of a native Vector2. + static Ray ToCLI(const SHRay& vec); /*-----------------------------------------------------------------------------*/ /* String Conversions */ diff --git a/TempScriptsFolder/PhysicsTest.cs b/TempScriptsFolder/PhysicsTest.cs new file mode 100644 index 00000000..6f9774c9 --- /dev/null +++ b/TempScriptsFolder/PhysicsTest.cs @@ -0,0 +1,43 @@ +using SHADE; +using System; +public class PhysicsTest : Script +{ + [SerializeField] + [Tooltip("Force to apply when pressing Space.")] + private Vector3 Force = new Vector3(0.0f, 200.0f, 0.0f); + private Transform Transform; + private RigidBody RigidBody; + private Collider Collider; + public PhysicsTest(GameObject gameObj) : base(gameObj) { } + + protected override void awake() + { + Transform = GetComponent(); + if (Transform == null) + { + Debug.LogError("Transform is NULL!"); + } + RigidBody = GetComponent(); + if (RigidBody == null) + { + Debug.LogError("RigidBody is NULL!"); + } + Collider = GetComponent(); + if (Collider == null) + { + Debug.LogError("Collider is NULL!"); + } + + var subColider = Collider.ColliderBoundsCount; + Debug.Log($"There are {subColider} colliders."); + } + protected override void update() + { + if (Input.GetKeyUp(Input.KeyCode.Space)) + { + RigidBody.AddForce(Force); + Debug.Log($"Jump!"); + } + Debug.Log($"{Transform.LocalPosition.y}"); + } +} \ No newline at end of file diff --git a/TempScriptsFolder/RaccoonShowcase.cs b/TempScriptsFolder/RaccoonShowcase.cs index 4191a6e5..da0b89d2 100644 --- a/TempScriptsFolder/RaccoonShowcase.cs +++ b/TempScriptsFolder/RaccoonShowcase.cs @@ -12,7 +12,7 @@ public class RaccoonShowcase : Script //private int test = 5; [SerializeField] [Tooltip("Speed of the scaling in radians per second around each axis.")] - private Vector3 ScaleSpeed = new Vector3(1.0, 1.0, 0.0); + private Vector3 ScaleSpeed = Vector3.One; private Transform Transform; private double rotation = 0.0; private Vector3 scale = Vector3.Zero; @@ -31,9 +31,9 @@ public class RaccoonShowcase : Script } protected override void update() { - rotation += RotateSpeed * 0.16; - scale += ScaleSpeed * 0.16; - Transform.LocalRotation = new Vector3(0.0f, rotation, 0.0f); - Transform.LocalScale = new Vector3(System.Math.Abs(System.Math.Sin(scale.x)) * originalScale, System.Math.Abs(System.Math.Cos(scale.y)) * originalScale, System.Math.Abs(System.Math.Sin(scale.z)) * originalScale); + //rotation += RotateSpeed * 0.16; + //scale += ScaleSpeed * 0.16; + //Transform.LocalRotation = new Vector3(0.0f, rotation, 0.0f); + //Transform.LocalScale = new Vector3(System.Math.Abs(System.Math.Sin(scale.x)) * originalScale, System.Math.Abs(System.Math.Cos(scale.y)) * originalScale, System.Math.Abs(System.Math.Sin(scale.z)) * originalScale); } } \ No newline at end of file diff --git a/TempScriptsFolder/RaccoonSpin.cs b/TempScriptsFolder/RaccoonSpin.cs index d6ee1c9f..c5420ffb 100644 --- a/TempScriptsFolder/RaccoonSpin.cs +++ b/TempScriptsFolder/RaccoonSpin.cs @@ -5,8 +5,12 @@ public class RaccoonSpin : Script { [SerializeField] [Tooltip("Speed of the rotation in radians per second.")] - private double RotateSpeed = 1.0; - private double rotation = 0.0; + private float RotateSpeed = 1.0f; + private float rotation = 0.0f; + [SerializeField] + private CallbackEvent testEvent; + [SerializeField] + private CallbackEvent testEvent3 = new CallbackEvent(); private Transform Transform; public RaccoonSpin(GameObject gameObj) : base(gameObj) { } @@ -18,9 +22,4 @@ public class RaccoonSpin : Script Debug.LogError("Transform is NULL!"); } } - protected override void update() - { - rotation += RotateSpeed * 0.16; - Transform.LocalRotation = new Vector3(0.0f, rotation, 0.0f); - } } \ No newline at end of file diff --git a/TempShaderFolder/ShaderDescriptorDefinitions.glsl b/TempShaderFolder/ShaderDescriptorDefinitions.glsl deleted file mode 100644 index c70a9f5b..00000000 --- a/TempShaderFolder/ShaderDescriptorDefinitions.glsl +++ /dev/null @@ -1,11 +0,0 @@ -#define SET_STATIC_GLOBALS 0 -#define SET_DYNAMIC_GLOBALS 1 -#define SET_HIGH_FREQUENCY_GLOBALS 2 - -#define BINDING_GENERIC_DATA 0 -#define BINDING_IMAGE_AND_SAMPLERS_DATA 1 -#define BINDING_LIGHTS_DATA 0 -#define BINDING_CAMERA_DATA 0 -#define BINDING_BATCHED_PER_INST_DATA 0 - - diff --git a/premake5.lua b/premake5.lua index cebb5544..35bff9d2 100644 --- a/premake5.lua +++ b/premake5.lua @@ -22,6 +22,7 @@ workspace "SHADE" include "SHADE_Engine" include "SHADE_Application" include "SHADE_Managed" + include "SHADE_CSharp" group "Dependencies" include "Dependencies/msdf"