diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index 3471d4a7..56d65d1b 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -84,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) @@ -104,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); @@ -119,7 +119,7 @@ namespace Sandbox auto& floorRigidBody = *SHComponentManager::GetComponent_s(floor); auto& floorCollider = *SHComponentManager::GetComponent_s(floor); - floorRenderable.Mesh = CUBE_MESH; + floorRenderable.SetMesh(CUBE_MESH); floorRenderable.SetMaterial(customMat); floorRenderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(1.0f, 1.0f, 1.0f, 1.0f)); @@ -145,7 +145,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/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/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 6fbf5a76..2b8e97bc 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -680,7 +680,7 @@ namespace SHADE auto& renderables = SHComponentManager::GetDense(); for (auto& renderable : renderables) { - if (!renderable.WasMaterialChanged()) + if (!renderable.HasChanged()) continue; // Remove from old material's SuperBatch @@ -768,5 +768,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 426f0abe..4e91ca8d 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -135,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); @@ -143,6 +143,7 @@ namespace SHADE Handle AddOrGetBaseMaterialInstance(Handle material); Handle AddMaterialInstanceCopy(Handle materialInst); void RemoveMaterialInstance(Handle materialInstance); + Handle GetDefaultMaterial() { return defaultMaterial; } /*-----------------------------------------------------------------------------*/ /* Mesh Registration Functions */ @@ -286,12 +287,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 */ @@ -318,7 +324,7 @@ namespace SHADE SHTextureLibrary texLibrary; SHSamplerCache samplerCache; SHMaterialInstanceCache materialInstanceCache; - // Viewports + // Viewports #ifdef SHEDITOR Handle editorViewport; Handle editorRenderer; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.cpp index 36e30010..b6e1974f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.cpp @@ -23,7 +23,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) { @@ -59,14 +59,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..ad7da4a6 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 */ @@ -64,11 +75,6 @@ namespace SHADE Handle pipeline; std::unique_ptr propMemory; Byte propMemorySize = 0; - - /*-----------------------------------------------------------------------------*/ - /* Helper Functions */ - /*-----------------------------------------------------------------------------*/ - Handle getShaderBlockInterface() const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.hpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.hpp index 49587921..3e56bfd5 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) { @@ -36,14 +36,25 @@ namespace SHADE T* dataPtr = 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 + (*reinterpret_cast(propMemory.get() + 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,19 @@ 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)); + } } 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/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/Physics/Components/SHRigidBodyComponent.cpp b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp index b0172f64..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" diff --git a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h index 78de84e7..3c5dd4f9 100644 --- a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h +++ b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h @@ -10,7 +10,6 @@ #pragma once -#include #include // Project Headers @@ -23,6 +22,11 @@ // class SHPhysicsSystem; //} +namespace reactphysics3d +{ + class RigidBody; +} + namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -153,7 +157,7 @@ namespace SHADE uint16_t dirtyFlags; bool interpolate; - rp3d::RigidBody* rp3dBody; + reactphysics3d::RigidBody* rp3dBody; float mass; float drag; 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/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index fea59353..f0f8912b 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", + "OnColliderBoundChanged" + ); + csColliderOnRemoved = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".Collider", + "OnColliderRemoved" + ); 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..6d2c2f01 --- /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 */ + /*---------------------------------------------------------------------------------*/ + ColliderBound::ColliderBound(int arrayIdx, Entity attachedEntity) + : arrayIndex { arrayIdx } + , entity { attachedEntity } + {} + + /*---------------------------------------------------------------------------------*/ + /* ColliderBound - Setter Functions */ + /*---------------------------------------------------------------------------------*/ + void ColliderBound::updateArrayIndex(int index) + { + arrayIndex = index; + } + + /*---------------------------------------------------------------------------------*/ + /* BoxColliderBound - Constructors */ + /*---------------------------------------------------------------------------------*/ + BoxColliderBound::BoxColliderBound(int arrayIdx, Entity attachedEntity) + : ColliderBound { arrayIndex, attachedEntity } + {} + + /*---------------------------------------------------------------------------------*/ + /* BoxColliderBound - Properties */ + /*---------------------------------------------------------------------------------*/ + Vector3 BoxColliderBound::Center::get() + { + return Convert::ToCLI(getNativeBoundObject().GetCenter()); + } + void BoxColliderBound::Center::set(Vector3 value) + { + getNativeBoundObject().SetCenter(Convert::ToNative(value)); + } + Vector3 BoxColliderBound::HalfExtents::get() + { + return Convert::ToCLI(getNativeBoundObject().GetHalfExtents()); + } + void BoxColliderBound::HalfExtents::set(Vector3 value) + { + getNativeBoundObject().SetHalfExtents(Convert::ToNative(value)); + } + Vector3 BoxColliderBound::Min::get() + { + return Convert::ToCLI(getNativeBoundObject().GetMin()); + } + void BoxColliderBound::Min::set(Vector3 value) + { + getNativeBoundObject().SetMin(Convert::ToNative(value)); + } + Vector3 BoxColliderBound::Max::get() + { + return Convert::ToCLI(getNativeBoundObject().GetMax()); + } + void BoxColliderBound::Max::set(Vector3 value) + { + getNativeBoundObject().SetMax(Convert::ToNative(value)); + } + + /*---------------------------------------------------------------------------------*/ + /* BoxColliderBound - Usage Functions */ + /*---------------------------------------------------------------------------------*/ + bool BoxColliderBound::TestPoint(Vector3 point) + { + return getNativeBoundObject().TestPoint(Convert::ToNative(point)); + } + bool BoxColliderBound::Raycast(Ray ray, float maxDistance) + { + return getNativeBoundObject().Raycast(Convert::ToNative(ray), maxDistance); + } + + /*---------------------------------------------------------------------------------*/ + /* BoxColliderBound - Properties */ + /*---------------------------------------------------------------------------------*/ + Vector3 SphereColliderBound::Center::get() + { + return Convert::ToCLI(getNativeBoundObject().GetCenter()); + } + void SphereColliderBound::Center::set(Vector3 value) + { + getNativeBoundObject().SetCenter(Convert::ToNative(value)); + } + float SphereColliderBound::Radius::get() + { + return getNativeBoundObject().GetRadius(); + } + void SphereColliderBound::Radius::set(float value) + { + getNativeBoundObject().SetRadius(value); + } + + /*---------------------------------------------------------------------------------*/ + /* SphereColliderBound - Usage Functions */ + /*---------------------------------------------------------------------------------*/ + bool SphereColliderBound::TestPoint(Vector3 point) + { + return getNativeBoundObject().TestPoint(Convert::ToNative(point)); + } + bool SphereColliderBound::Raycast(Ray ray, float maxDistance) + { + return getNativeBoundObject().Raycast(Convert::ToNative(ray), maxDistance); + } + + /*---------------------------------------------------------------------------------*/ + /* SphereColliderBound - Constructors */ + /*---------------------------------------------------------------------------------*/ + SphereColliderBound::SphereColliderBound(int arrayIndex, Entity attachedEntity) + : ColliderBound{ arrayIndex, attachedEntity } + {} + + /*---------------------------------------------------------------------------------*/ + /* Collider - Constructors */ + /*---------------------------------------------------------------------------------*/ + Collider::Collider(Entity entity) + : Component(entity) + { + // Create lists if they don't exist + if (colliders == nullptr) + colliders = gcnew CollidersMap; + if (!colliders->ContainsKey(entity)) + colliders->Add(entity, gcnew WeakReferenceList()); + + // Store a weak reference + colliders[entity]->Add(gcnew System::WeakReference(this)); + } + + /*---------------------------------------------------------------------------------*/ + /* Collider - Properties */ + /*---------------------------------------------------------------------------------*/ + int Collider::ColliderBoundsCount::get() + { + return static_cast(GetNativeComponent()->GetColliders().size()); + } + + /*---------------------------------------------------------------------------------*/ + /* Collider - ColliderBound Functions */ + /*---------------------------------------------------------------------------------*/ + ColliderBound^ Collider::GetColliderBound(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::GetColliderBound(int index) + { + return safe_cast(GetColliderBound(index)); + } + + /*---------------------------------------------------------------------------------*/ + /* Event Handling Functions */ + /*---------------------------------------------------------------------------------*/ + void Collider::OnColliderRemoved(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::OnColliderBoundChanged(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()) + { + ColliderBound^ bound = nullptr; + switch (collider.first.GetType()) + { + case SHCollider::Type::BOX: + bound = gcnew BoxColliderBound(i, Owner.GetEntity()); + break; + case SHCollider::Type::SPHERE: + bound = gcnew SphereColliderBound(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..66f77e18 --- /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 + ColliderBoundType& SHADE::ColliderBound::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..f827ab71 --- /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 ColliderBound + { + 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 */ + /*-----------------------------------------------------------------------------*/ + ColliderBound(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 + ColliderBoundType& getNativeBoundObject(); + + internal: + /*-----------------------------------------------------------------------------*/ + /* Setter Functions */ + /*-----------------------------------------------------------------------------*/ + void updateArrayIndex(int index); + }; + + /// + /// Box-shaped Collider Bound. + /// + public ref class BoxColliderBound : public ColliderBound + { + 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 */ + /*-----------------------------------------------------------------------------*/ + BoxColliderBound(int arrayIndex, Entity attachedEntity); + }; + + /// + /// Sphere-shaped Collider Bound. + /// + public ref class SphereColliderBound : public ColliderBound + { + 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 */ + /*-----------------------------------------------------------------------------*/ + SphereColliderBound(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 ColliderBoundsCount + { + 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. + ColliderBound^ GetColliderBound(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:ColliderBound + T GetColliderBound(int index); + + internal: + /*-----------------------------------------------------------------------------*/ + /* Event Handling Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// To be called from native code when a collider has been removed. + /// + /// The entity which has it's collider removed. + static void OnColliderRemoved(EntityID entity); + /// + /// To be called from native code when a Collider bound has been removed. + /// + /// + /// The entity which has it's collider bounds changed. + /// + static void OnColliderBoundChanged(EntityID entity); + + private: + /*-----------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------*/ + using WeakReferenceList = System::Collections::Generic::List; + using CollidersMap = System::Collections::Generic::Dictionary; + + /*-----------------------------------------------------------------------------*/ + /* Static Data Members */ + /*-----------------------------------------------------------------------------*/ + static CollidersMap^ 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/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"