Merge remote-tracking branch 'origin/main' into SP3-2-Physics

This commit is contained in:
Diren D Bharwani 2022-10-28 14:08:18 +08:00
commit d4f775843c
52 changed files with 3982 additions and 119 deletions

View File

@ -84,7 +84,7 @@ namespace Sandbox
auto& collider = *SHComponentManager::GetComponent_s<SHColliderComponent>(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<SHRenderable>(raccoonSpin);
auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(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<SHRigidBodyComponent>(floor);
auto& floorCollider = *SHComponentManager::GetComponent_s<SHColliderComponent>(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<SHRenderable>(raccoonShowcase);
auto& transformShowcase = *SHComponentManager::GetComponent_s<SHTransformComponent>(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);

52
SHADE_CSharp/premake5.lua Normal file
View File

@ -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,'<Platforms>x64</Platforms>')
end
premake.override(premake.vstudio.cs2005.elements, "projectProperties", function (oldfn, cfg)
return table.join(oldfn(cfg), {
platformsElement,
})
end)

View File

@ -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
{
/// <summary>
/// Interface for a CallbackAction that all variants inherit from.
/// </summary>
public interface ICallbackAction
{
/// <summary>
/// Whether or not this CallbackAction is runtime assigned. If it is, then the
/// TargetMethodName and TargetObject properties are invalid.
/// </summary>
bool IsRuntimeAction { get; }
/// <summary>
/// Name of the method that this CallbackAction is using.
/// </summary>
string TargetMethodName { get; }
/// <summary>
/// Object which the specified target method is called on.
/// </summary>
Object TargetObject { get; }
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 1 parameter.
/// </summary>
public class CallbackAction<T1> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
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];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
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
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 2 parameters.
/// </summary>
public class CallbackAction<T1, T2> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
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];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
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
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 3 parameters.
/// </summary>
public class CallbackAction<T1, T2, T3> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2, T3> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
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];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2, T3> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
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
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 4 parameters.
/// </summary>
public class CallbackAction<T1, T2, T3, T4> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2, T3, T4> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
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];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2, T3, T4> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
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
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 5 parameters.
/// </summary>
public class CallbackAction<T1, T2, T3, T4, T5> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2, T3, T4, T5> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
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];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2, T3, T4, T5> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
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
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 6 parameters.
/// </summary>
public class CallbackAction<T1, T2, T3, T4, T5, T6> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2, T3, T4, T5, T6> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
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];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
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
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 7 parameters.
/// </summary>
public class CallbackAction<T1, T2, T3, T4, T5, T6, T7> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2, T3, T4, T5, T6, T7> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
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];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
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
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 8 parameters.
/// </summary>
public class CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2, T3, T4, T5, T6, T7, T8> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
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];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
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
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 9 parameters.
/// </summary>
public class CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2, T3, T4, T5, T6, T7, T8, T9> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
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];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
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
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 10 parameters.
/// </summary>
public class CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
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];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
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
}
}

View File

@ -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
{
/// <summary>
/// Interface for a CallbackAction that all variants inherit from.
/// </summary>
public interface ICallbackAction
{
/// <summary>
/// Whether or not this CallbackAction is runtime assigned. If it is, then the
/// TargetMethodName and TargetObject properties are invalid.
/// </summary>
bool IsRuntimeAction { get; }
/// <summary>
/// Name of the method that this CallbackAction is using.
/// </summary>
string TargetMethodName { get; }
/// <summary>
/// Object which the specified target method is called on.
/// </summary>
Object TargetObject { get; }
}
<# for (int i = 1; i <= max; ++i) { #>
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with <#=i#> parameter<# if (i > 1) {#>s<#} #>.
/// </summary>
public class CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
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 ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
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];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
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
}
<# } #>
}

View File

@ -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
{
/// <summary>
/// Interface for a CallbackEvent that all variants inherit from.
/// </summary>
public interface ICallbackEvent
{
/// <summary>
/// Registers an empty ICallbackAction.
/// </summary>
void RegisterAction();
/// <summary>
/// Registers an ICallbackAction with the event such that it will be called in
/// future
/// </summary>
/// <param name="action">ICallbackAction to register with.</param>
void RegisterAction(ICallbackAction action);
/// <summary>
/// Deregisters an ICallbackAction that was previously added. This should
/// only emit a warning if an action that was not previous added was
/// provided.
/// </summary>
/// <param name="action">ICallbackAction to remove.</param>
void DeregisterAction(ICallbackAction action);
/// <summary>
/// Iterable set of ICallbackActions that were registered to this event.
/// </summary>
IEnumerable<ICallbackAction> Actions { get; }
}
/// <summary>
/// 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.
/// </summary>
public class CallbackEvent<T1> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1> action)
{
actions.Add(new CallbackAction<T1>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1)
{
foreach (CallbackAction<T1> action in actions)
{
try
{
action.Invoke(t1);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// 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.
/// </summary>
public class CallbackEvent<T1, T2> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2> action)
{
actions.Add(new CallbackAction<T1, T2>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2)
{
foreach (CallbackAction<T1, T2> action in actions)
{
try
{
action.Invoke(t1, t2);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// 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.
/// </summary>
public class CallbackEvent<T1, T2, T3> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3> action)
{
actions.Add(new CallbackAction<T1, T2, T3>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3)
{
foreach (CallbackAction<T1, T2, T3> action in actions)
{
try
{
action.Invoke(t1, t2, t3);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// 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.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4)
{
foreach (CallbackAction<T1, T2, T3, T4> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// 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.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
{
foreach (CallbackAction<T1, T2, T3, T4, T5> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// 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.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5, T6> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5, T6>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5, T6> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5, T6> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
{
foreach (CallbackAction<T1, T2, T3, T4, T5, T6> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5, t6);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// 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.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5, T6, T7> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5, T6, T7>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5, T6, T7> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5, T6, T7> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
{
foreach (CallbackAction<T1, T2, T3, T4, T5, T6, T7> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5, t6, t7);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// 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.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5, T6, T7, T8> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5, T6, T7, T8> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
{
foreach (CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5, t6, t7, t8);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// 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.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5, T6, T7, T8, T9> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9)
{
foreach (CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// 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.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
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<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
}

View File

@ -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
{
/// <summary>
/// Interface for a CallbackEvent that all variants inherit from.
/// </summary>
public interface ICallbackEvent
{
/// <summary>
/// Registers an empty ICallbackAction.
/// </summary>
void RegisterAction();
/// <summary>
/// Registers an ICallbackAction with the event such that it will be called in
/// future
/// </summary>
/// <param name="action">ICallbackAction to register with.</param>
void RegisterAction(ICallbackAction action);
/// <summary>
/// Deregisters an ICallbackAction that was previously added. This should
/// only emit a warning if an action that was not previous added was
/// provided.
/// </summary>
/// <param name="action">ICallbackAction to remove.</param>
void DeregisterAction(ICallbackAction action);
/// <summary>
/// Iterable set of ICallbackActions that were registered to this event.
/// </summary>
IEnumerable<ICallbackAction> Actions { get; }
}
<# for (int i = 1; i <= max; ++i) { #>
/// <summary>
/// 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.
/// </summary>
public class CallbackEvent<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>());
}
/// <inheritdoc/>
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);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
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));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
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));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
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
}
<# } #>
}

View File

@ -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() }");
}
}
}

View File

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

View File

@ -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<SHMaterialInstance> 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<SHRenderable>(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();

View File

@ -680,7 +680,7 @@ namespace SHADE
auto& renderables = SHComponentManager::GetDense<SHRenderable>();
for (auto& renderable : renderables)
{
if (!renderable.WasMaterialChanged())
if (!renderable.HasChanged())
continue;
// Remove from old material's SuperBatch
@ -768,5 +768,10 @@ namespace SHADE
}
Handle<SHRenderGraphNode> SHGraphicsSystem::GetPrimaryRenderpass() const noexcept
{
return worldRenderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data());
}
#pragma endregion MISC
}

View File

@ -135,7 +135,7 @@ namespace SHADE
void RemoveViewport(Handle<SHViewport> viewport);
/*-----------------------------------------------------------------------------*/
/* Material Creation Functions */
/* Material Functions */
/*-----------------------------------------------------------------------------*/
Handle<SHMaterial> AddMaterial(Handle<SHVkShaderModule> vertShader, Handle<SHVkShaderModule> fragShader, Handle<SHSubpass> subpass);
void RemoveMaterial(Handle<SHMaterial> material);
@ -143,6 +143,7 @@ namespace SHADE
Handle<SHMaterialInstance> AddOrGetBaseMaterialInstance(Handle<SHMaterial> material);
Handle<SHMaterialInstance> AddMaterialInstanceCopy(Handle<SHMaterialInstance> materialInst);
void RemoveMaterialInstance(Handle<SHMaterialInstance> materialInstance);
Handle<SHMaterial> GetDefaultMaterial() { return defaultMaterial; }
/*-----------------------------------------------------------------------------*/
/* Mesh Registration Functions */
@ -286,12 +287,17 @@ namespace SHADE
#endif
Handle<SHMousePickSystem> GetMousePickSystem(void) const noexcept {return mousePickSystem;};
Handle<SHPostOffscreenRenderSystem> GetPostOffscreenRenderSystem(void) const noexcept {return postOffscreenRender;};
Handle<SHRenderGraphNode> GetPrimaryRenderpass() const noexcept;
//SHRenderGraph const& GetRenderGraph(void) const noexcept;
//Handle<SHVkRenderpass> GetRenderPass() const { return renderPass; }
private:
/*-----------------------------------------------------------------------------*/
/* Constants */
/*-----------------------------------------------------------------------------*/
static constexpr std::string_view G_BUFFER_RENDER_GRAPH_NODE_NAME = "G-Buffer";
/*-----------------------------------------------------------------------------*/
/* Data Members */

View File

@ -23,7 +23,7 @@ namespace SHADE
}
// Allocate memory for properties
const Handle<SHShaderBlockInterface> SHADER_INFO = getShaderBlockInterface();
const Handle<SHShaderBlockInterface> 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<SHShaderBlockInterface> SHADER_INFO = getShaderBlockInterface();
const Handle<SHShaderBlockInterface> SHADER_INFO = GetShaderBlockInterface();
return SHADER_INFO ? SHADER_INFO->GetBytesRequired() : 0;
}
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
Handle<SHShaderBlockInterface> SHMaterial::getShaderBlockInterface() const noexcept
Handle<SHShaderBlockInterface> SHMaterial::GetShaderBlockInterface() const noexcept
{
return pipeline->GetPipelineLayout()->GetShaderBlockInterface
(

View File

@ -50,13 +50,24 @@ namespace SHADE
template<typename T>
void SetProperty(const std::string& key, const T& value);
template<typename T>
void SetProperty(uint32_t memOffset, const T& value);
template<typename T>
T& GetProperty(const std::string& key);
template<typename T>
const T& GetProperty(const std::string& key) const;
template<typename T>
T& GetProperty(uint32_t memOffset);
template<typename T>
const T& GetProperty(uint32_t memOffset) const;
void ResetProperties();
void ExportProperties(void* dest) const noexcept;
Byte GetPropertiesMemorySize() const noexcept;
/*-----------------------------------------------------------------------------*/
/* Query Functions */
/*-----------------------------------------------------------------------------*/
Handle<SHShaderBlockInterface> GetShaderBlockInterface() const noexcept;
private:
/*-----------------------------------------------------------------------------*/
/* Data Members */
@ -64,11 +75,6 @@ namespace SHADE
Handle<SHVkPipeline> pipeline;
std::unique_ptr<char> propMemory;
Byte propMemorySize = 0;
/*-----------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
Handle<SHShaderBlockInterface> getShaderBlockInterface() const noexcept;
};
}

View File

@ -25,7 +25,7 @@ namespace SHADE
template<typename T>
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<typename T>
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<T*>(propMemory.get() + memOffset)) = value;
}
template<typename T>
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
@ -56,4 +67,18 @@ namespace SHADE
return const_cast<const T&>(const_cast<SHMaterial*>(this)->GetProperty(key));
}
template<typename T>
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<T*>(propMemory.get() + memOffset));
}
template<typename T>
T& SHMaterial::GetProperty(uint32_t memOffset)
{
return const_cast<const T&>(const_cast<SHMaterial*>(this)->GetProperty(memOffset));
}
}

View File

@ -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)
@ -93,14 +93,40 @@ namespace SHADE
return material;
}
/*-----------------------------------------------------------------------------------*/
/* Mesh Functions */
/*-----------------------------------------------------------------------------------*/
void SHRenderable::SetMesh(Handle<SHMesh> 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_<SHRenderable>("Renderable Component");
}

View File

@ -11,9 +11,10 @@ of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
// External Dependencies
#include <rttr/registration>
// 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<SHMaterialInstance> materialInstance);
Handle<SHMaterialInstance> GetMaterial() const;
Handle<SHMaterialInstance> GetModifiableMaterial();
Handle<SHMaterialInstance> GetPrevMaterial() const noexcept { return oldMaterial; }
bool HasMaterialChanged() const noexcept { return matChanged; }
/*-------------------------------------------------------------------------------*/
/* Getter Functions */
/* Mesh Functions */
/*-------------------------------------------------------------------------------*/
void SetMesh(Handle<SHMesh> newMesh);
Handle<SHMesh> GetMesh() const noexcept { return mesh; }
Handle<SHMesh> GetPrevMesh() const noexcept { return oldMesh; }
bool HasMeshChanged() const noexcept { return meshChanged; }
/*-------------------------------------------------------------------------------*/
/* Light Functions */
/*-------------------------------------------------------------------------------*/
bool WasMaterialChanged() const noexcept { return materialChanged; }
Handle<SHMaterialInstance> 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<SHMesh> Mesh;
private:
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
Handle<SHMesh> mesh;
Handle<SHMesh> oldMesh;
bool meshChanged = true;
Handle<SHMaterialInstance> sharedMaterial;
Handle<SHMaterialInstance> material;
bool materialChanged = true;
bool matChanged = true;
Handle<SHMaterialInstance> oldMaterial;
uint8_t lightLayer;
RTTR_ENABLE()
};
}

View File

@ -244,7 +244,15 @@ namespace SHADE
}
// Add subpass to container and create mapping for it
subpasses.emplace_back(graphStorage->resourceManager->Create<SHSubpass>(graphStorage, GetHandle(), static_cast<uint32_t>(subpasses.size()), &resourceAttachmentMapping));
subpasses.emplace_back
(
graphStorage->resourceManager->Create<SHSubpass>
(
subpassName,
graphStorage, GetHandle(), static_cast<uint32_t>(subpasses.size()),
&resourceAttachmentMapping
)
);
subpassIndexing.try_emplace(subpassName, static_cast<uint32_t>(subpasses.size()) - 1u);
Handle<SHSubpass> subpass = subpasses.back();
subpass->Init(*graphStorage->resourceManager);

View File

@ -30,7 +30,7 @@ namespace SHADE
*/
/***************************************************************************/
SHSubpass::SHSubpass(Handle<SHRenderGraphStorage> renderGraphStorage, Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping) noexcept
SHSubpass::SHSubpass(const std::string& name, Handle<SHRenderGraphStorage> renderGraphStorage, Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> 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;
}
}

View File

@ -77,13 +77,15 @@ namespace SHADE
//! are always the last things drawn, so DO NOT USE THIS FUNCTIONALITY FOR ANYTHING
//! COMPLEX.
std::vector<std::function<void(Handle<SHVkCommandBuffer>&)>> exteriorDrawCalls;
/// For identifying subpasses
std::string name;
public:
/*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */
/*-----------------------------------------------------------------------*/
SHSubpass(Handle<SHRenderGraphStorage> renderGraphStorage, Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping) noexcept;
SHSubpass(const std::string& name, Handle<SHRenderGraphStorage> renderGraphStorage, Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping) noexcept;
SHSubpass(SHSubpass&& rhs) noexcept;
SHSubpass& operator=(SHSubpass&& rhs) noexcept;
@ -117,6 +119,7 @@ namespace SHADE
Handle<SHSuperBatch> GetSuperBatch(void) const noexcept;
std::vector<vk::AttachmentReference> const& GetColorAttachmentReferences (void) const noexcept;
vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept;
const std::string& GetName() const;
friend class SHRenderGraphNode;
friend class SHRenderGraph;

View File

@ -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<uint32_t>(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 }
{}

View File

@ -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<Variable> variables;
std::vector<std::string> variableNames;
std::unordered_map<std::string, uint32_t> 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 */

View File

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

View File

@ -10,6 +10,9 @@
#include <SHpch.h>
// External Dependencies
#include <reactphysics3d/reactphysics3d.h>
// Primary Header
#include "SHRigidBodyComponent.h"

View File

@ -10,7 +10,6 @@
#pragma once
#include <reactphysics3d/reactphysics3d.h>
#include <rttr/registration>
// 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;

View File

@ -156,7 +156,6 @@ namespace std
std::size_t hash<pair<SHADE::Handle<T1>, SHADE::Handle<T2>>>::operator()(
std::pair<SHADE::Handle<T1>, SHADE::Handle<T2>> const& pair) const
{
return std::hash<uint64_t>{}(pair.first.GetId().Raw) ^ std::hash<uint64_t>{}(pair.second.GetId().Raw);
}
}

View File

@ -136,11 +136,11 @@ namespace SHADE
template<typename T>
std::optional<AssetID> SHResourceManager::GetAssetID(Handle<T> handle)
{
const Handle GENERIC_HANDLE = Handle(handle);
const Handle<void> GENERIC_HANDLE = Handle<void>(handle);
auto [typedHandleMap, typedAssetIdMap] = getAssetHandleMap<T>();
if (typedAssetIdMap.get().contains(GENERIC_HANDLE))
{
return typedAssetIdMap.GetId()[GENERIC_HANDLE];
return typedAssetIdMap.get()[GENERIC_HANDLE];
}
return {};

View File

@ -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
<HintPath Condition=\"Exists('..\\bin\\Debug\\SHADE_Managed.dll')\">..\\bin\\Debug\\SHADE_Managed.dll</HintPath>\n\
<HintPath Condition=\"Exists('..\\bin\\Release\\SHADE_Managed.dll')\">..\\bin\\Release\\SHADE_Managed.dll</HintPath>\n\
</Reference>\n\
<Reference Include=\"SHADE_CSharp\">\n\
<HintPath Condition=\"Exists('..\\bin\\Debug\\SHADE_Managed.dll')\">..\\bin\\Debug\\SHADE_CSharp.dll</HintPath>\n\
<HintPath Condition=\"Exists('..\\bin\\Release\\SHADE_Managed.dll')\">..\\bin\\Release\\SHADE_CSharp.dll</HintPath>\n\
</Reference>\n\
</ItemGroup>\n\
</Project>";
@ -280,6 +291,28 @@ namespace SHADE
return eventData->handle;
}
SHEventHandle SHScriptEngine::onColliderAdded(SHEventPtr eventPtr)
{
auto eventData = reinterpret_cast<const SHEventSpec<SHPhysicsColliderAddedEvent>*>(eventPtr.get());
csColliderOnListChanged(eventData->data->entityID);
return eventData->handle;
}
SHEventHandle SHScriptEngine::onColliderRemoved(SHEventPtr eventPtr)
{
auto eventData = reinterpret_cast<const SHEventSpec<SHPhysicsColliderRemovedEvent>*>(eventPtr.get());
csColliderOnListChanged(eventData->data->entityID);
return eventData->handle;
}
SHEventHandle SHScriptEngine::onColliderComponentRemoved(SHEventPtr eventPtr)
{
auto eventData = reinterpret_cast<const SHEventSpec<SHComponentRemovedEvent>*>(eventPtr.get());
if (eventData->data->removedComponentType == ComponentFamily::GetID<SHColliderComponent>())
csColliderOnRemoved(eventData->data->eid);
return eventData->handle;
}
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/
@ -380,6 +413,18 @@ namespace SHADE
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"DeserialiseScripts"
);
csColliderOnListChanged = dotNet.GetFunctionPtr<CsEventRelayFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".Collider",
"OnColliderBoundChanged"
);
csColliderOnRemoved = dotNet.GetFunctionPtr<CsEventRelayFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".Collider",
"OnColliderRemoved"
);
csEditorRenderScripts = dotNet.GetFunctionPtr<CsScriptEditorFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
@ -407,8 +452,28 @@ namespace SHADE
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onEntityDestroyed)
};
ReceiverPtr receiver = std::dynamic_pointer_cast<SHEventReceiver>(destroyedEventReceiver);
SHEventManager::SubscribeTo(SH_ENTITY_DESTROYED_EVENT, receiver);
SHEventManager::SubscribeTo(SH_ENTITY_DESTROYED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(destroyedEventReceiver));
// Register for collider added event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> addedColliderEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onColliderAdded)
};
SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_ADDED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(addedColliderEventReceiver));
// Register for collider removed event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> removedColliderEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onColliderRemoved)
};
SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_REMOVED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(removedColliderEventReceiver));
// Register for collider component removed event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> removedColliderComponentEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onColliderComponentRemoved)
};
SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(removedColliderComponentEventReceiver));
}
void SHScriptEngine::dumpBuildLog(const std::string_view& buildLogPath)

View File

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

View File

@ -1,8 +1,8 @@
#include "SHpch.h"
#include "SHSerializationHelper.hpp"
#include "SHSerialization.h"
#include <yaml-cpp/yaml.h>
#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<SHRenderable>(eid))
{
components[rttr::type::get<SHRenderable>().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(renderable);
components[rttr::type::get<SHRenderable>().get_name().data()] = *renderable;
}
if (const auto rigidbody = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(eid))
{
@ -259,5 +259,6 @@ namespace SHADE
if (!componentsNode)
return;
SHSerializationHelper::InitializeComponentFromNode<SHTransformComponent>(componentsNode, eid);
SHSerializationHelper::ConvertNodeToComponent<SHRenderable>(componentsNode, eid);
}
}

View File

@ -1,7 +1,7 @@
#pragma once
#include "ECS_Base/Components/SHComponent.h"
#include <yaml-cpp/yaml.h>
#include "ECS_Base/Components/SHComponent.h"
#include <rttr/registration>
@ -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<SHMaterial>
{
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<SHShaderBlockInterface> pipelineProperties = rhs.GetShaderBlockInterface();
for (int i = 0; i < static_cast<int>(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<float>(VARIABLE->offset);
break;
case SHADE::SHShaderBlockInterface::Variable::Type::INT:
propNode = rhs.GetProperty<int>(VARIABLE->offset);
break;
case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR2:
propNode = SHSerializationTools::ValToYAML(rhs.GetProperty<SHVec2>(VARIABLE->offset));
break;
case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR3:
propNode = SHSerializationTools::ValToYAML(rhs.GetProperty<SHVec3>(VARIABLE->offset));
break;
case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR4:
propNode = SHSerializationTools::ValToYAML(rhs.GetProperty<SHVec4>(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<SHVkShaderModule> 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<SHVkShaderModule>(vertexShader).value_or(0);
node[FRAG_SHADER_YAML_TAG.data()] = 0; // SHResourceManager::GetAssetID<SHVkShaderModule>(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<AssetID>();
if (node[FRAG_SHADER_YAML_TAG.data()])
fragShaderId = node[FRAG_SHADER_YAML_TAG.data()].as<AssetID>();
// Ensure that both shaders are present
if (vertShaderId == 0 || fragShaderId == 0)
return false; // No pipeline
// Get Shader Modules
Handle<SHVkShaderModule> vertexShader, fragShader;
vertexShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(vertShaderId);
fragShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(fragShaderId);
// Get Pipeline Library
if (node[SUBPASS_YAML_TAG.data()])
{
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
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<std::string>());
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<SHGraphicsSystem>();
if (!gfxSystem)
return false;
rhs.SetPipeline(gfxSystem->GetDefaultMaterial()->GetPipeline());
if (node[PROPS_YAML_TAG.data()])
{
// Loop through all properties
Handle<SHShaderBlockInterface> pipelineProperties = rhs.GetShaderBlockInterface();
const YAML::Node& PROPS_NODE = node[PROPS_YAML_TAG.data()];
for (int i = 0; i < static_cast<int>(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<float>());
break;
case SHADE::SHShaderBlockInterface::Variable::Type::INT:
rhs.SetProperty(VARIABLE->offset, PROP_NODE.as<int>());
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<SHRenderable>
{
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<SHMesh>(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<SHMesh>(node[MESH_YAML_TAG.data()].as<AssetID>()));
}
if (node[MAT_YAML_TAG.data()])
{
// TODO: Convert Asset ID To Material HAndle
// Temporarily, use default material
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
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>())
{
SHVec4 vec{ propertyNode["X"].as<float>(), propertyNode["Y"].as<float>(), propertyNode["Z"].as<float>(), propertyNode["W"].as<float>() };
prop.set_value(component, vec);
prop.set_value(component, SHSerializationTools::YAMLToVec4(propertyNode));
}
else if (propType == rttr::type::get<SHVec3>())
{
SHVec3 vec{ propertyNode["X"].as<float>(), propertyNode["Y"].as<float>(), propertyNode["Z"].as<float>() };
prop.set_value(component, vec);
prop.set_value(component, SHSerializationTools::YAMLToVec3(propertyNode));
}
else if (propType == rttr::type::get<SHVec2>())
{
SHVec2 vec{ propertyNode["X"].as<float>(), propertyNode["Y"].as<float>() };
prop.set_value(component, vec);
prop.set_value(component, SHSerializationTools::YAMLToVec2(propertyNode));
}
else if (propType.is_arithmetic())
{
@ -200,5 +398,18 @@ namespace SHADE
}
}
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static void ConvertNodeToComponent(YAML::Node const& componentsNode, EntityID const& eid)
{
auto component = SHComponentManager::GetComponent_s<ComponentType>(eid);
if (componentsNode.IsNull() && !component)
return;
auto rttrType = rttr::type::get<ComponentType>();
auto componentNode = componentsNode[rttrType.get_name().data()];
if (componentsNode.IsNull())
return;
YAML::convert<ComponentType>::decode(componentNode, *component);
}
};
}

View File

@ -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<float>(), node["Y"].as<float>() };
}
SHVec3 SHSerializationTools::YAMLToVec3(const YAML::Node& node)
{
return SHVec3 { node["X"].as<float>(), node["Y"].as<float>(), node["Z"].as<float>() };
}
SHVec4 SHSerializationTools::YAMLToVec4(const YAML::Node& node)
{
return SHVec4 { node["X"].as<float>(), node["Y"].as<float>(), node["Z"].as<float>(), node["W"].as<float>() };
}
}

View File

@ -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 <yaml-cpp/yaml.h>
// 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);
};
}

View File

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

View File

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

View File

@ -45,7 +45,8 @@ project "SHADE_Managed"
{
"yaml-cpp",
"imgui",
"SHADE_Engine"
"SHADE_Engine",
"SHADE_CSharp"
}
disablewarnings

View File

@ -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<SHBoundingBox>().GetCenter());
}
void BoxColliderBound::Center::set(Vector3 value)
{
getNativeBoundObject<SHBoundingBox>().SetCenter(Convert::ToNative(value));
}
Vector3 BoxColliderBound::HalfExtents::get()
{
return Convert::ToCLI(getNativeBoundObject<SHBoundingBox>().GetHalfExtents());
}
void BoxColliderBound::HalfExtents::set(Vector3 value)
{
getNativeBoundObject<SHBoundingBox>().SetHalfExtents(Convert::ToNative(value));
}
Vector3 BoxColliderBound::Min::get()
{
return Convert::ToCLI(getNativeBoundObject<SHBoundingBox>().GetMin());
}
void BoxColliderBound::Min::set(Vector3 value)
{
getNativeBoundObject<SHBoundingBox>().SetMin(Convert::ToNative(value));
}
Vector3 BoxColliderBound::Max::get()
{
return Convert::ToCLI(getNativeBoundObject<SHBoundingBox>().GetMax());
}
void BoxColliderBound::Max::set(Vector3 value)
{
getNativeBoundObject<SHBoundingBox>().SetMax(Convert::ToNative(value));
}
/*---------------------------------------------------------------------------------*/
/* BoxColliderBound - Usage Functions */
/*---------------------------------------------------------------------------------*/
bool BoxColliderBound::TestPoint(Vector3 point)
{
return getNativeBoundObject<SHBoundingBox>().TestPoint(Convert::ToNative(point));
}
bool BoxColliderBound::Raycast(Ray ray, float maxDistance)
{
return getNativeBoundObject<SHBoundingBox>().Raycast(Convert::ToNative(ray), maxDistance);
}
/*---------------------------------------------------------------------------------*/
/* BoxColliderBound - Properties */
/*---------------------------------------------------------------------------------*/
Vector3 SphereColliderBound::Center::get()
{
return Convert::ToCLI(getNativeBoundObject<SHBoundingSphere>().GetCenter());
}
void SphereColliderBound::Center::set(Vector3 value)
{
getNativeBoundObject<SHBoundingSphere>().SetCenter(Convert::ToNative(value));
}
float SphereColliderBound::Radius::get()
{
return getNativeBoundObject<SHBoundingSphere>().GetRadius();
}
void SphereColliderBound::Radius::set(float value)
{
getNativeBoundObject<SHBoundingSphere>().SetRadius(value);
}
/*---------------------------------------------------------------------------------*/
/* SphereColliderBound - Usage Functions */
/*---------------------------------------------------------------------------------*/
bool SphereColliderBound::TestPoint(Vector3 point)
{
return getNativeBoundObject<SHBoundingBox>().TestPoint(Convert::ToNative(point));
}
bool SphereColliderBound::Raycast(Ray ray, float maxDistance)
{
return getNativeBoundObject<SHBoundingBox>().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<int>(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<typename T>
T Collider::GetColliderBound(int index)
{
return safe_cast<T>(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<System::WeakReference^>^ toRemove = gcnew System::Collections::Generic::List<System::WeakReference ^>();
WeakReferenceList^ collidersList = colliders[entity];
for each (System::WeakReference^ wr in collidersList)
{
Collider^ collider = safe_cast<Collider^>(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<ColliderBound^>();
// 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);
}
}
}

View File

@ -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<typename ColliderBoundType>
ColliderBoundType& SHADE::ColliderBound::getNativeBoundObject()
{
SHColliderComponent* collider = SHComponentManager::GetComponent_s<SHColliderComponent>(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<ColliderBoundType&>(bounds);
}
catch (std::invalid_argument&)
{
throw gcnew System::IndexOutOfRangeException("Attempted to retrieve out of range ColliderBound!");
}
}
}

View File

@ -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
{
/// <summary>
/// Base interface for all Collider Shapes.
/// </summary>
public ref class ColliderBound
{
public:
/*-----------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Checks if the specified point is within this shape's bounds.
/// </summary>
/// <param name="point">Point to test with.</param>
/// <returns>True if the point is in the shape's bounds.</returns>
virtual bool TestPoint(Vector3 point) = 0;
/// <summary>
/// Computes a Raycast and checks if there is a collision with any object.
/// </summary>
/// <param name="ray">The ray to cast.</param>
/// <param name="maxDistance">Maximum distance for the raycast check.</param>
/// <returns>True if the ray intersects with an object in the scene.</returns>
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<typename ColliderBoundType>
ColliderBoundType& getNativeBoundObject();
internal:
/*-----------------------------------------------------------------------------*/
/* Setter Functions */
/*-----------------------------------------------------------------------------*/
void updateArrayIndex(int index);
};
/// <summary>
/// Box-shaped Collider Bound.
/// </summary>
public ref class BoxColliderBound : public ColliderBound
{
public:
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Center of the Bounding Box formed by this bound.
/// </summary>
property Vector3 Center
{
Vector3 get();
void set(Vector3 value);
}
/// <summary>
/// Half of the scale of the Bounding Box formed by this bound.
/// </summary>
property Vector3 HalfExtents
{
Vector3 get();
void set(Vector3 value);
}
/// <summary>
/// Position of the bottom left back corner of the Bounding Box formed by this
/// bound.
/// </summary>
property Vector3 Min
{
Vector3 get();
void set(Vector3 value);
}
/// <summary>
/// Position of the top right front corner of the Bounding Box formed by this
/// bound.
/// </summary>
property Vector3 Max
{
Vector3 get();
void set(Vector3 value);
}
/*-----------------------------------------------------------------------------*/
/* ColliderBound Functions */
/*-----------------------------------------------------------------------------*/
/// <inheritdoc/>
bool TestPoint(Vector3 point) override;
/// <inheritdoc/>
bool Raycast(Ray ray, float maxDistance) override;
internal:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
BoxColliderBound(int arrayIndex, Entity attachedEntity);
};
/// <summary>
/// Sphere-shaped Collider Bound.
/// </summary>
public ref class SphereColliderBound : public ColliderBound
{
public:
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Center of the Bounding Sphere formed by this bound.
/// </summary>
property Vector3 Center
{
Vector3 get();
void set(Vector3 value);
}
/// <summary>
/// Radius of the Bounding Sphere formed by this bound.
/// </summary>
property float Radius
{
float get();
void set(float value);
}
/*-----------------------------------------------------------------------------*/
/* ColliderBound Functions */
/*-----------------------------------------------------------------------------*/
/// <inheritdoc/>
bool TestPoint(Vector3 point) override;
/// <inheritdoc/>
bool Raycast(Ray ray, float maxDistance) override;
internal:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
SphereColliderBound(int arrayIndex, Entity attachedEntity);
};
/// <summary>
/// CLR version of the the SHADE Engine's SHColliderComponent.
/// A single Collider component can contain one or multiple Collider Bounds.
/// </summary>
public ref class Collider : public Component<SHColliderComponent>
{
internal:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructs a Collider Component that represents a native SHColliderComponent
/// component tied to the specified Entity.
/// </summary>
/// <param name="entity">Entity that this Component will be tied to.</param>
Collider(Entity entity);
public:
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Total number of ColliderBounds in the Collider component.
/// </summary>
property int ColliderBoundsCount
{
int get();
}
/*-----------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Retrieves a ColliderBound at the specified index in the ColliderBound list.
/// </summary>
/// <param name="index">Index to retrieve a ColliderBound from.</param>
/// <returns>ColliderBound for the specified index.</returns>
ColliderBound^ GetColliderBound(int index);
/// <summary>
/// Retrieves a ColliderBound at the specified index in the ColliderBound list
/// and casts it to the appropriate type.
/// </summary>
/// <typeparam name="T">Type of the ColliderBound to cast to.</typeparam>
/// <param name="index">Index to retrieve a ColliderBound from.</param>
/// <returns>ColliderBound for the specified index.</returns>
generic<typename T> where T:ColliderBound
T GetColliderBound(int index);
internal:
/*-----------------------------------------------------------------------------*/
/* Event Handling Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// To be called from native code when a collider has been removed.
/// </summary>
/// <param name="entity">The entity which has it's collider removed.</param>
static void OnColliderRemoved(EntityID entity);
/// <summary>
/// To be called from native code when a Collider bound has been removed.
/// </summary>
/// <param name="entity">
/// The entity which has it's collider bounds changed.
/// </param>
static void OnColliderBoundChanged(EntityID entity);
private:
/*-----------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------*/
using WeakReferenceList = System::Collections::Generic::List<System::WeakReference^>;
using CollidersMap = System::Collections::Generic::Dictionary<EntityID, WeakReferenceList^>;
/*-----------------------------------------------------------------------------*/
/* Static Data Members */
/*-----------------------------------------------------------------------------*/
static CollidersMap^ colliders;
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
System::Collections::Generic::List<ColliderBound^>^ subColliderList;
/*-----------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
void updateSubColliderList();
};
}
#include "Collider.h++"

View File

@ -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<Type>(GetNativeComponent()->GetType());
}
void RigidBody::BodyType::set(Type value)
{
return GetNativeComponent()->SetType(static_cast<SHRigidBodyComponent::Type>(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));
}
}

View File

@ -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
{
/// <summary>
/// CLR version of the the SHADE Engine's SHRigidBodyComponent.
/// </summary>
public ref class RigidBody : public Component<SHRigidBodyComponent>
{
internal:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructs a RigidBody Component that represents a native
/// SHRigidBodyComponent component tied to the specified Entity.
/// </summary>
/// <param name="entity">Entity that this Component will be tied to.</param>
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);
};
}

View File

@ -68,36 +68,36 @@ using namespace System::Collections::Generic;
/// <param name="MANAGED_TYPE">The managed type of the object to edit.</param>
/// <param name="NATIVE_TYPE">The native type of the object to edit.</param>
/// <param name="FUNC">The SHEditorUI:: function to use for editing.</param>
#define RENDER_FIELD_RANGE(MANAGED_TYPE, NATIVE_TYPE, FUNC) \
(field->FieldType == MANAGED_TYPE::typeid) \
{ \
NATIVE_TYPE val = safe_cast<NATIVE_TYPE>(field->GetValue(object)); \
NATIVE_TYPE oldVal = val; \
\
RangeAttribute^ rangeAttrib = hasAttribute<RangeAttribute^>(field); \
const std::string FIELD_NAME = Convert::ToNative(field->Name); \
bool changed = false; \
if (rangeAttrib) \
{ \
changed = SHEditorUI::InputSlider \
( \
FIELD_NAME, \
static_cast<NATIVE_TYPE>(rangeAttrib->Min), \
static_cast<NATIVE_TYPE>(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<NATIVE_TYPE>(field->GetValue(object)); \
NATIVE_TYPE oldVal = val; \
\
RangeAttribute^ rangeAttrib = hasAttribute<RangeAttribute^>(field);\
const std::string FIELD_NAME = Convert::ToNative(field->Name); \
bool changed = false; \
if (rangeAttrib) \
{ \
changed = SHEditorUI::InputSlider \
( \
FIELD_NAME, \
static_cast<NATIVE_TYPE>(rangeAttrib->Min), \
static_cast<NATIVE_TYPE>(rangeAttrib->Max), \
val, &isHovered \
); \
} \
else \
{ \
changed = SHEditorUI::FUNC(FIELD_NAME, val, &isHovered); \
} \
\
if (changed) \
{ \
field->SetValue(object, val); \
registerUndoAction(object, field, val, oldVal); \
} \
} \
/// <summary>
/// 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<System::Type^>^ interfaces = field->FieldType->GetInterfaces();
if (interfaces->Length > 0 && interfaces[0] == ICallbackEvent::typeid)
{
array<System::Type^>^ 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<ICallbackEvent^>(field->GetValue(object));
if (callbackEvent == nullptr)
{
// Construct one since it was not constructed before
callbackEvent = safe_cast<ICallbackEvent^>(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<int>(-1);
if (action->TargetObject)
{
Script^ script = safe_cast<Script^>(action->TargetObject);
if (script)
{
entityId = static_cast<int>(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<TooltipAttribute^>(field);

View File

@ -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<SHTransformComponent, Transform>());
componentMap.Add(createComponentSet<SHColliderComponent, Collider>());
componentMap.Add(createComponentSet<SHRigidBodyComponent, RigidBody>());
}
/*---------------------------------------------------------------------------------*/

View File

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

View File

@ -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
{
///<summary>
/// CLR version of the the SHADE Engine's Ray class that represents a ray in
/// 3-Dimensional space.
/// </summary>
public value struct Ray
{
public:
/*-----------------------------------------------------------------------------*/
/* Public Members */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// The start point of the ray.
/// </summary>
Vector3 Origin;
/// <summary>
/// The direction that a ray travels in.
/// </summary>
Vector3 Direction;
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Creates a ray starting at origin along direction.
/// </summary>
/// <param name="origin">Source of the ray.</param>
/// <param name="direction">Direction the ray travels in.</param>
Ray(Vector3 origin, Vector3 direction);
};
}

View File

@ -132,7 +132,7 @@ namespace SHADE
/// Immutable list of references to scripts of the specified type.
/// </returns>
generic<typename T> where T : ref class, Script
static System::Collections::Generic::IEnumerable<T> ^ GetScripts(Entity entity);
static System::Collections::Generic::IEnumerable<T>^ GetScripts(Entity entity);
/// <summary>
/// Retrieves an immutable list of all scripts attached to a specified Entity.
/// </summary>
@ -295,4 +295,4 @@ namespace SHADE
static System::Type^ getScriptType(System::String^ scriptName);
static bool isEntityActive(Entity entity);
};
} // namespace PlushieAPI
}

View File

@ -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<int>());
}
if (fieldAssignYaml<System::Int16> (fieldInfo, object, node) ||
fieldAssignYaml<System::Int32> (fieldInfo, object, node) ||
fieldAssignYaml<System::Int64> (fieldInfo, object, node) ||

View File

@ -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<System::String^>(str);
}
} // namespace PlushieAPI
}

View File

@ -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
/// <param name="quat">The native Quaternion to convert from.</param>
/// <returns>Managed copy of a native Quaternion.</returns>
static Quaternion ToCLI(const SHQuaternion& quat);
/// Converts from a managed Vector2 to a native Vector2.
/// </summary>
/// <param name="vec">The managed Vector2 to convert from.</param>
/// <returns>Native copy of a managed Vector2.</returns>
static SHRay ToNative(Ray vec);
/// <summary>
/// Converts from a native Vector2 to a managed Vector2.
/// </summary>
/// <param name="vec">The native Vector2 to convert from.</param>
/// <returns>Managed copy of a native Vector2.</returns>
static Ray ToCLI(const SHRay& vec);
/*-----------------------------------------------------------------------------*/
/* String Conversions */

View File

@ -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<Transform>();
if (Transform == null)
{
Debug.LogError("Transform is NULL!");
}
RigidBody = GetComponent<RigidBody>();
if (RigidBody == null)
{
Debug.LogError("RigidBody is NULL!");
}
Collider = GetComponent<Collider>();
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}");
}
}

View File

@ -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);
}
}

View File

@ -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<int> testEvent;
[SerializeField]
private CallbackEvent<int, double, Vector3> testEvent3 = new CallbackEvent<int, double, Vector3>();
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);
}
}

View File

@ -22,6 +22,7 @@ workspace "SHADE"
include "SHADE_Engine"
include "SHADE_Application"
include "SHADE_Managed"
include "SHADE_CSharp"
group "Dependencies"
include "Dependencies/msdf"