Merge remote-tracking branch 'origin/main' into SP3-1-Rendering

This commit is contained in:
Brandon Mak 2022-10-30 00:00:17 +08:00
commit 7c5a24b8e1
149 changed files with 7394 additions and 1719 deletions

View File

@ -1,3 +1,3 @@
Name: Cube.003 Name: Cube.003
ID: 110152941 ID: 77135977
Type: 6 Type: 4

View File

@ -1,3 +1,3 @@
Name: Cube.012 Name: Cube.012
ID: 107348815 ID: 81876417
Type: 6 Type: 4

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: RaccoonBag_Color_Ver4
ID: 66703095
Type: 3

View File

@ -1,3 +1,3 @@
Name: RaccoonPreTexturedVer1_Base9 Name: RaccoonPreTexturedVer1_Base9
ID: 91918845 ID: 60820650
Type: 4 Type: 3

View File

@ -0,0 +1,83 @@
#version 450
struct DirectionalLightStruct
{
vec3 direction;
uint isActive;
uint cullingMask;
vec4 diffuseColor;
};
struct AmbientLightStruct
{
vec4 ambientColor;
float strength;
uint isActive;
uint cullingMask;
};
layout(local_size_x = 16, local_size_y = 16) in;
layout(set = 4, binding = 0, rgba32f) uniform image2D positions;
layout(set = 4, binding = 1, rgba32f) uniform image2D normals;
layout(set = 4, binding = 2, rgba8) uniform image2D albedo;
layout(set = 4, binding = 3, r32ui) uniform uimage2D lightLayerData;
layout(set = 4, binding = 4, rgba8) uniform image2D targetImage;
layout(set = 1, binding = 0) uniform LightCounts
{
uint directionalLights;
uint pointLights;
uint spotLights;
uint ambientLights;
} lightCounts;
layout(std430, set = 1, binding = 1) buffer DirectionalLightData
{
DirectionalLightStruct dLightData[];
} DirLightData;
layout(std430, set = 1, binding = 4) buffer AmbientLightData
{
AmbientLightStruct aLightData[];
} AmbLightData;
void main()
{
// convenient variables
ivec2 globalThread = ivec2(gl_GlobalInvocationID);
// Get the diffuse color of the pixel
vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb;
// Get position of fragment in world space
vec3 positionWorld = imageLoad (positions, globalThread).rgb;
// normal of fragment
vec3 normalWorld = imageLoad(normals, globalThread).rgb;
vec3 fragColor = vec3 (0.0f);
for (int i = 0; i < lightCounts.directionalLights; ++i)
{
// get normalized direction of light
vec3 dLightNormalized = normalize (DirLightData.dLightData[i].direction);
// Get diffuse strength
float diffuseStrength = max (0, dot (dLightNormalized, normalWorld));
// Calculate the fragment color
fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse;
}
for (int i = 0; i < lightCounts.ambientLights; ++i)
{
// Just do some add
//fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f);
fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength);
}
// store result into result image
imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor, 1.0f));
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: DeferredComposite_CS
ID: 42814284
Type: 2

View File

@ -0,0 +1,3 @@
Name: Kirsch_CS
ID: 41371706
Type: 2

View File

@ -0,0 +1,3 @@
Name: PureCopy_CS
ID: 35841916
Type: 2

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: TestCube_FS
ID: 47024851
Type: 2

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: TestCube_VS
ID: 40523220
Type: 2

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: TD_Checker_Base_Color
ID: 55706287
Type: 3

View File

@ -110,14 +110,7 @@ namespace Sandbox
SHComponentManager::CreateComponentSparseSet<SHRenderable>(); SHComponentManager::CreateComponentSparseSet<SHRenderable>();
SHComponentManager::CreateComponentSparseSet<SHCameraComponent>(); SHComponentManager::CreateComponentSparseSet<SHCameraComponent>();
//TODO: REMOVE AFTER PRESENTATION SHAssetManager::Load();
//SHAssetManager::LoadDataTemp("../../Assets/racoon.gltf");
//SHAssetManager::LoadDataTemp("../../Assets/Cube.012.shmesh");
//SHAssetManager::LoadDataTemp("../../Assets/RaccoonBag_Color_Ver4.dds");
//SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.dds");
//SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.shtex");
//TODO: REMOVE AFTER PRESENTATION
auto id = SHFamilyID<SHSystem>::GetID<SHGraphicsSystem>(); auto id = SHFamilyID<SHSystem>::GetID<SHGraphicsSystem>();
auto id2 = SHFamilyID<SHSystem>::GetID<SHGraphicsSystem>(); auto id2 = SHFamilyID<SHSystem>::GetID<SHGraphicsSystem>();
@ -133,8 +126,6 @@ namespace Sandbox
SHSceneManager::InitSceneManager<SBTestScene>("TestScene"); SHSceneManager::InitSceneManager<SBTestScene>("TestScene");
SHFrameRateController::UpdateFRC(); SHFrameRateController::UpdateFRC();
SHAssetManager::Load();
} }
void SBApplication::Update(void) void SBApplication::Update(void)

View File

@ -53,7 +53,8 @@ namespace Sandbox
if (asset.name == "Cube.012") if (asset.name == "Cube.012")
handles.emplace_back(SHResourceManager::LoadOrGet<SHMesh>(asset.id)); handles.emplace_back(SHResourceManager::LoadOrGet<SHMesh>(asset.id));
break; break;
case AssetType::IMAGE: case AssetType::TEXTURE:
if (asset.name == "RaccoonPreTexturedVer1_Base9")
texHandles.emplace_back(SHResourceManager::LoadOrGet<SHTexture>(asset.id)); texHandles.emplace_back(SHResourceManager::LoadOrGet<SHTexture>(asset.id));
break; break;
} }
@ -83,7 +84,7 @@ namespace Sandbox
auto& collider = *SHComponentManager::GetComponent_s<SHColliderComponent>(entity); auto& collider = *SHComponentManager::GetComponent_s<SHColliderComponent>(entity);
//renderable.Mesh = handles.front(); //renderable.Mesh = handles.front();
renderable.Mesh = CUBE_MESH; renderable.SetMesh(CUBE_MESH);
renderable.SetMaterial(customMat); renderable.SetMaterial(customMat);
if (y == 50) if (y == 50)
@ -95,11 +96,7 @@ namespace Sandbox
transform.SetWorldRotation(SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f)); transform.SetWorldRotation(SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f));
transform.SetWorldScale(TEST_OBJ_SCALE); transform.SetWorldScale(TEST_OBJ_SCALE);
//if (const bool IS_EVEN = (y * NUM_ROWS + x) % 2; IS_EVEN) collider.AddBoundingBox(SHVec3::One, SHVec3::Zero);
collider.AddBoundingBox(SHVec3::One * 0.5f, SHVec3::Zero);
//else
// collider.AddBoundingSphere(0.5f, SHVec3::Zero);
stressTestObjects.emplace_back(entity); stressTestObjects.emplace_back(entity);
} }
@ -107,7 +104,7 @@ namespace Sandbox
auto& renderable = *SHComponentManager::GetComponent_s<SHRenderable>(raccoonSpin); auto& renderable = *SHComponentManager::GetComponent_s<SHRenderable>(raccoonSpin);
auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(raccoonSpin); auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(raccoonSpin);
renderable.Mesh = handles.front(); renderable.SetMesh(handles.front());
renderable.SetMaterial(customMat); renderable.SetMaterial(customMat);
renderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f)); renderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f));
renderable.GetModifiableMaterial()->SetProperty("data.alpha", 1.0f); renderable.GetModifiableMaterial()->SetProperty("data.alpha", 1.0f);
@ -122,9 +119,8 @@ namespace Sandbox
auto& floorRigidBody = *SHComponentManager::GetComponent_s<SHRigidBodyComponent>(floor); auto& floorRigidBody = *SHComponentManager::GetComponent_s<SHRigidBodyComponent>(floor);
auto& floorCollider = *SHComponentManager::GetComponent_s<SHColliderComponent>(floor); auto& floorCollider = *SHComponentManager::GetComponent_s<SHColliderComponent>(floor);
floorRenderable.Mesh = CUBE_MESH; floorRenderable.SetMesh(CUBE_MESH);
floorRenderable.SetMaterial(customMat); floorRenderable.SetMaterial(graphicsSystem->GetDefaultMaterialInstance());
floorRenderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(1.0f, 1.0f, 1.0f, 1.0f));
floorTransform.SetWorldScale({ 7.5f, 0.5f, 7.5 }); floorTransform.SetWorldScale({ 7.5f, 0.5f, 7.5 });
floorTransform.SetWorldPosition({ 0.0f, -3.0f, -5.0f }); floorTransform.SetWorldPosition({ 0.0f, -3.0f, -5.0f });
@ -148,7 +144,7 @@ namespace Sandbox
auto& renderableShowcase = *SHComponentManager::GetComponent_s<SHRenderable>(raccoonShowcase); auto& renderableShowcase = *SHComponentManager::GetComponent_s<SHRenderable>(raccoonShowcase);
auto& transformShowcase = *SHComponentManager::GetComponent_s<SHTransformComponent>(raccoonShowcase); auto& transformShowcase = *SHComponentManager::GetComponent_s<SHTransformComponent>(raccoonShowcase);
renderableShowcase.Mesh = handles.front(); renderableShowcase.SetMesh(handles.front());
renderableShowcase.SetMaterial(customMat); renderableShowcase.SetMaterial(customMat);
renderableShowcase.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f)); renderableShowcase.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f));
renderableShowcase.GetModifiableMaterial()->SetProperty("data.alpha", 1.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

@ -0,0 +1,61 @@
/*************************************************************************//**
* \file SHShaderAsset.cpp
* \author Brandon Mak
* \date 24 October 2022
* \brief
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#include "SHpch.h"
#include "SHShaderAsset.h"
namespace SHADE
{
SHShaderAsset::SHShaderAsset() noexcept
: spirvBinary{},
shaderType{SH_SHADER_TYPE::VERTEX},
name{}
{
}
SHShaderAsset::SHShaderAsset(SHShaderAsset const& rhs) noexcept
: spirvBinary{rhs.spirvBinary},
shaderType{ rhs.shaderType },
name{rhs.name}
{
}
SHShaderAsset::SHShaderAsset(SHShaderAsset&& rhs) noexcept
: spirvBinary{ std::move(rhs.spirvBinary) },
shaderType{ std::move(rhs.shaderType) },
name{ std::move(rhs.name) }
{
}
SHShaderAsset& SHShaderAsset::operator=(SHShaderAsset&& rhs) noexcept
{
if (this == &rhs)
{
return *this;
}
spirvBinary = std::move(rhs.spirvBinary);
shaderType = std::move(rhs.shaderType);
name = std::move(rhs.name);
}
SHShaderAsset& SHShaderAsset::operator=(SHShaderAsset const& rhs) noexcept
{
if (this == &rhs)
{
return *this;
}
spirvBinary = rhs.spirvBinary;
shaderType = rhs.shaderType;
name = rhs.name;
}
}

View File

@ -0,0 +1,48 @@
/*************************************************************************//**
* \file SHShaderAsset.h
* \author Brandon Mak
* \date 24 October 2022
* \brief
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#include "SHAssetData.h"
#include "SH_API.h"
#include <vector>
#include <string>
namespace SHADE
{
enum class SH_SHADER_TYPE : uint8_t
{
VERTEX,
FRAGMENT,
COMPUTE,
INAVLID_TYPE
};
struct SH_API SHShaderAsset : SHAssetData
{
/*-----------------------------------------------------------------------*/
/* MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
//! container storing the spirv binary
std::vector<uint32_t> spirvBinary;
//! For the compilation of the shader. Vulkan backend will use it too
SH_SHADER_TYPE shaderType;
//! Name of the shader file (without parent path)
std::string name;
SHShaderAsset() noexcept;
SHShaderAsset(SHShaderAsset const& rhs) noexcept;
SHShaderAsset(SHShaderAsset&& rhs) noexcept;
SHShaderAsset& operator= (SHShaderAsset&& rhs) noexcept;
SHShaderAsset& operator= (SHShaderAsset const& rhs) noexcept;
};
}

View File

@ -1,22 +1,28 @@
/*************************************************************************//** /*************************************************************************//**
* \file SHAssimpLibrary.cpp * \file SHMeshCompiler.cpp
* \author Loh Xiao Qi * \author Loh Xiao Qi
* \date October 2022 * \date 30 September 2022
* \brief * \brief Library to write data in SHMeshAsset into binary file for faster
* loading in the future
*
* *
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent * disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited. * of DigiPen Institute of Technology is prohibited.
*****************************************************************************/ *****************************************************************************/
#include "SHpch.h" #include "SHpch.h"
#include "SHAssimpLibrary.h" #include "SHMeshCompiler.h"
#include "Graphics/MiddleEnd/Meshes/SHMeshData.h"
#include <assimp/postprocess.h> #include <assimp/postprocess.h>
#include <fstream>
namespace SHADE namespace SHADE
{ {
Assimp::Importer SHAssimpLibrary::aiImporter;
void SHAssimpLibrary::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept Assimp::Importer SHMeshCompiler::aiImporter;
void SHMeshCompiler::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept
{ {
for (size_t i{ 0 }; i < node.mNumMeshes; ++i) for (size_t i{ 0 }; i < node.mNumMeshes; ++i)
{ {
@ -30,7 +36,7 @@ namespace SHADE
} }
} }
void SHAssimpLibrary::ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept void SHMeshCompiler::ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept
{ {
if (scene.HasAnimations()) if (scene.HasAnimations())
{ {
@ -51,7 +57,7 @@ namespace SHADE
} }
} }
SHMeshAsset* SHAssimpLibrary::ProcessMesh(aiMesh const& mesh) noexcept SHMeshAsset* SHMeshCompiler::ProcessMesh(aiMesh const& mesh) noexcept
{ {
SHMeshAsset* result = new SHMeshAsset(); SHMeshAsset* result = new SHMeshAsset();
result->compiled = false; result->compiled = false;
@ -112,7 +118,7 @@ namespace SHADE
return result; return result;
} }
void SHAssimpLibrary::LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept void SHMeshCompiler::LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept
{ {
const aiScene* scene = aiImporter.ReadFile(path.string().c_str(), const aiScene* scene = aiImporter.ReadFile(path.string().c_str(),
aiProcess_Triangulate // Make sure we get triangles rather than nvert polygons aiProcess_Triangulate // Make sure we get triangles rather than nvert polygons
@ -132,10 +138,64 @@ namespace SHADE
return; return;
} }
ExtractAnimations(*scene, anims); //ExtractAnimations(*scene, anims);
ProcessNode(*scene->mRootNode, *scene, meshes); ProcessNode(*scene->mRootNode, *scene, meshes);
aiImporter.FreeScene(); aiImporter.FreeScene();
} }
std::optional<AssetPath> SHMeshCompiler::CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept
{
std::string newPath{ path.parent_path().string() + '/' };
newPath += asset.header.name + MESH_EXTENSION.data();
std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open file for writing mesh file: {}", path.string());
}
file.write(
reinterpret_cast<char const*>(&(asset.header.vertexCount)),
sizeof(uint32_t)
);
file.write(
reinterpret_cast<const char*>(&(asset.header.indexCount)),
sizeof(uint32_t)
);
auto const vertexVec3Byte{ sizeof(SHVec3) * asset.header.vertexCount };
auto const vertexVec2Byte{ sizeof(SHVec2) * asset.header.vertexCount };
file.write(
reinterpret_cast<char const*>(asset.vertexPosition.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexTangent.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexNormal.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.texCoords.data()),
vertexVec2Byte
);
file.write(
reinterpret_cast<char const*>(asset.indices.data()),
sizeof(uint32_t) * asset.header.indexCount
);
file.close();
return newPath;
}
} }

View File

@ -0,0 +1,40 @@
/*************************************************************************//**
* \file SHMeshCompiler.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to write data in SHMeshAsset into binary file for faster
* loading in the future
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <vector>
#include "Assets/Asset Types/SHAnimationAsset.h"
#include "Assets/Asset Types/SHMeshAsset.h"
#include "Assets/SHAssetMacros.h"
namespace SHADE
{
class SHMeshCompiler
{
using MeshVectorRef = std::vector<SHMeshAsset*>&;
using AnimVectorRef = std::vector<SHAnimationAsset*>&;
static Assimp::Importer aiImporter;
static void ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept;
static void ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept;
static SHMeshAsset* ProcessMesh(aiMesh const& mesh) noexcept;
public:
static void LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept;
static std::optional<AssetPath> CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept;
};
}

View File

@ -0,0 +1,162 @@
/*************************************************************************//**
* \file SHShaderSourceCompiler.cpp
* \author Loh Xiao Qi
* \date 23 10 2022
* \brief
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#include "SHpch.h"
#include "SHShaderSourceCompiler.h"
#include "shaderc/shaderc.hpp"
#include <fstream>
#include <sstream>
#include <string>
#include <algorithm>
namespace SHADE
{
std::string SHShaderSourceCompiler::CompileShaderSourceToBinary(AssetPath path, SHShaderAsset const& data) noexcept
{
std::string newPath{ path.string() };
newPath = newPath.substr(0, newPath.find_last_of('.'));
newPath += SHADER_BUILT_IN_EXTENSION.data();
std::ofstream file{ newPath, std::ios::binary | std::ios::out | std::ios::trunc };
file.write(
reinterpret_cast<char const*>(& data.shaderType), sizeof(uint8_t)
);
size_t const byteCount = sizeof(uint32_t) * data.spirvBinary.size();
file.write(
reinterpret_cast<char const*>(&byteCount), sizeof(size_t)
);
file.write(
reinterpret_cast<char const*>(data.spirvBinary.data()), byteCount
);
file.close();
return newPath;
}
SHShaderAsset const* SHShaderSourceCompiler::CompileShaderSourceToMemory(std::string const& data, std::string const& name, SH_SHADER_TYPE type) noexcept
{
// shaderc compiler
shaderc::Compiler compiler;
shaderc::CompileOptions options;
options.AddMacroDefinition("MY_DEFINE", "1");
//TODO: Check if we need optimisation levels when compiling into spirv
// Set optimization levels
//if (opLevel != shaderc_optimization_level_zero)
// options.SetOptimizationLevel(opLevel);
// Attempt to get the shaderc equivalent shader stage
shaderc_shader_kind shaderKind;
switch (type)
{
case SH_SHADER_TYPE::VERTEX:
shaderKind = shaderc_shader_kind::shaderc_glsl_vertex_shader;
break;
case SH_SHADER_TYPE::FRAGMENT:
shaderKind = shaderc_shader_kind::shaderc_glsl_fragment_shader;
break;
case SH_SHADER_TYPE::COMPUTE:
shaderKind = shaderc_shader_kind::shaderc_glsl_compute_shader;
break;
default:
shaderKind = shaderc_shader_kind::shaderc_glsl_vertex_shader;
break;
}
// Compile the shader and get the result
shaderc::SpvCompilationResult compileResult = compiler.CompileGlslToSpv(data, shaderKind, name.c_str(), options);
if (compileResult.GetCompilationStatus() != shaderc_compilation_status_success)
{
SHLOG_ERROR("Shaderc failed to compile GLSL shader to binary | " + compileResult.GetErrorMessage());
return nullptr;
}
auto result = new SHShaderAsset();
result->spirvBinary.resize(compileResult.end() - compileResult.begin());
std::ranges::copy(compileResult.begin(), compileResult.end(), result->spirvBinary.data());
result->name = name;
result->shaderType = type;
return result;
}
SH_SHADER_TYPE SHShaderSourceCompiler::GetShaderTypeFromFilename(std::string name) noexcept
{
for (auto i { 0}; i < SHADER_TYPE_MAX_COUNT; ++i)
{
if (name.find(SHADER_IDENTIFIERS[i].data()) != std::string::npos)
{
return static_cast<SH_SHADER_TYPE>(i);
}
}
return SH_SHADER_TYPE::INAVLID_TYPE;
}
std::optional<AssetPath> SHShaderSourceCompiler::LoadAndCompileShader(AssetPath path) noexcept
{
auto type = GetShaderTypeFromFilename(path.filename().string());
if (type == SH_SHADER_TYPE::INAVLID_TYPE)
{
SHLOG_ERROR("Invalid filename for shaders, follow suffix in SHAssetMacros.h: {}", path.string());
return {};
}
path.make_preferred();
std::ifstream file{ path.string(), std::ios::in };
if (file.is_open())
{
std::stringstream stream;
stream << file.rdbuf();
std::string const content = stream.str();
auto data = CompileShaderSourceToMemory(content, path.filename().string(), type);
if (data == nullptr)
{
return{};
}
return CompileShaderSourceToBinary(path, *data);
}
SHLOG_ERROR("Unable to open shader file: {}", path.string());
return {};
}
std::optional<AssetPath> SHShaderSourceCompiler::CompileShaderFromString
(std::string const& string, AssetPath path, SH_SHADER_TYPE type) noexcept
{
auto const data = CompileShaderSourceToMemory(string, path.filename().string(), type);
if (data == nullptr)
{
return{};
}
return CompileShaderSourceToBinary(path, *data);
}
}

View File

@ -0,0 +1,31 @@
/*************************************************************************//**
* \file SHShaderSourceCompiler.h
* \author Loh Xiao Qi
* \date 23 10 2022
* \brief
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#include "Assets/SHAssetMacros.h"
#include "Assets/Asset Types/SHShaderAsset.h"
namespace SHADE
{
class SHShaderSourceCompiler
{
private:
static std::string CompileShaderSourceToBinary(AssetPath path, SHShaderAsset const& data) noexcept;
static SHShaderAsset const* CompileShaderSourceToMemory(std::string const& data, std::string const& name, SH_SHADER_TYPE type) noexcept;
static SH_SHADER_TYPE GetShaderTypeFromFilename(std::string name) noexcept;
public:
static std::optional<AssetPath> LoadAndCompileShader(AssetPath path) noexcept;
static std::optional<AssetPath> CompileShaderFromString
(std::string const& string, AssetPath path, SH_SHADER_TYPE type) noexcept;
};
}

View File

@ -0,0 +1,171 @@
/*************************************************************************//**
* \file SHTextureCompiler.cpp
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to write data in SHTextureAsset into binary file for
* faster loading in the future
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#include "SHpch.h"
#include "SHTextureCompiler.h"
#include <fstream>
namespace SHADE
{
std::string SHTextureCompiler::TinyDDSResultToString(tinyddsloader::Result value)
{
switch (value)
{
case tinyddsloader::Result::ErrorFileOpen:
return "File open err";
case tinyddsloader::Result::ErrorRead:
return "File read err";
case tinyddsloader::Result::ErrorMagicWord:
return "File header magic word err";
case tinyddsloader::Result::ErrorSize:
return "File size err";
case tinyddsloader::Result::ErrorVerify:
return "Pixel format err";
case tinyddsloader::Result::ErrorNotSupported:
return "Unsupported format";
case tinyddsloader::Result::ErrorInvalidData:
return "Invalid data";
default:
return "Unknown";
}
}
vk::Format SHTextureCompiler::ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear)
{
switch (format)
{
case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm_SRGB:
return isLinear ? vk::Format::eBc1RgbaUnormBlock : vk::Format::eBc1RgbaSrgbBlock;
case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm_SRGB:
return isLinear ? vk::Format::eBc2UnormBlock : vk::Format::eBc2SrgbBlock;
case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm_SRGB:
return isLinear ? vk::Format::eBc3UnormBlock : vk::Format::eBc3SrgbBlock;
case tinyddsloader::DDSFile::DXGIFormat::BC5_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::BC5_SNorm:
return isLinear ? vk::Format::eBc5UnormBlock : vk::Format::eBc5SnormBlock;
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm_SRGB:
return isLinear ? vk::Format::eR8G8B8A8Unorm : vk::Format::eR8G8B8A8Srgb;
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_SNorm:
return vk::Format::eR8G8B8A8Snorm;
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm_SRGB:
return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8A8Srgb;
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm_SRGB:
return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8Srgb;
default:
throw std::runtime_error("Unsupported DDS format.");
}
}
void SHTextureCompiler::LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept
{
tinyddsloader::Result loadResult = tinyddsloader::Result::Success;
tinyddsloader::DDSFile file;
loadResult = file.Load(path.string().c_str());
if (loadResult != tinyddsloader::Result::Success)
{
SHLOG_ERROR("Unable to load Texture file: {} at {}", TinyDDSResultToString(loadResult), path.string());
}
size_t totalBytes{ 0 };
std::vector<uint32_t> mipOff(file.GetMipCount());
for (size_t i{ 0 }; i < file.GetMipCount(); ++i)
{
mipOff[i] = static_cast<uint32_t>(totalBytes);
totalBytes += file.GetImageData(static_cast<uint32_t>(i), 0)->m_memSlicePitch;
}
SHTexture::PixelChannel* pixel = new SHTexture::PixelChannel[totalBytes];
std::memcpy(pixel, file.GetImageData()->m_mem, totalBytes);
//pixel = std::move(reinterpret_cast<SHTexture::PixelChannel const*>(file.GetDDSData()));
asset.name = path.stem().string();
asset.compiled = false;
asset.numBytes = static_cast<uint32_t>(totalBytes);
asset.width = file.GetWidth();
asset.height = file.GetHeight();
asset.format = ddsLoaderToVkFormat(file.GetFormat(), true);
asset.mipOffsets = std::move(mipOff);
asset.pixelData = std::move(pixel);
}
std::string SHTextureCompiler::WriteToFile(SHTextureAsset const& asset, AssetPath path) noexcept
{
std::string newPath{ path.string() };
newPath = newPath.substr(0, newPath.find_last_of('.'));
newPath += TEXTURE_EXTENSION;
std::ofstream file{ newPath, std::ios::out | std::ios::binary };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open file for writing texture file: {}", path.string());
}
constexpr auto intBytes{ sizeof(uint32_t) };
uint32_t const mipOffsetCount{ static_cast<uint32_t>(asset.mipOffsets.size()) };
file.write(
reinterpret_cast<char const*>(&asset.numBytes),
intBytes
);
file.write(
reinterpret_cast<char const*>(&asset.width),
intBytes
);
file.write(
reinterpret_cast<char const*>(&asset.height),
intBytes
);
file.write(
reinterpret_cast<char const*>(&asset.format),
sizeof(SHTexture::TextureFormat)
);
file.write(
reinterpret_cast<char const*>(&mipOffsetCount),
intBytes
);
file.write(
reinterpret_cast<char const*>(asset.mipOffsets.data()),
intBytes * asset.mipOffsets.size()
);
file.write(
reinterpret_cast<char const*>(asset.pixelData),
asset.numBytes
);
file.close();
return newPath;
}
std::optional<AssetPath> SHTextureCompiler::CompileTextureAsset(AssetPath path)
{
auto data = new SHTextureAsset();
LoadTinyDDS(path, *data);
return WriteToFile(*data, path);
}
}

View File

@ -0,0 +1,33 @@
/*************************************************************************//**
* \file SHTextureCompiler.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to write data in SHTextureAsset into binary file for
* faster loading in the future
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#define TINYDDSLOADER_IMPLEMENTATION
#include "Assets/Asset Types/SHTextureAsset.h"
#include "Assets/SHAssetMacros.h"
#include "tinyddsloader.h"
namespace SHADE
{
class SHTextureCompiler
{
private:
static std::string TinyDDSResultToString(tinyddsloader::Result value);
static vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear);
static void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept;
static std::string WriteToFile(SHTextureAsset const& asset, AssetPath path) noexcept;
public:
static std::optional<AssetPath> CompileTextureAsset(AssetPath path);
};
}

View File

@ -10,6 +10,7 @@
*****************************************************************************/ *****************************************************************************/
#pragma once #pragma once
#include "Assets/SHAssetMacros.h"
#include "Assets/Asset Types/SHAssetData.h" #include "Assets/Asset Types/SHAssetData.h"
namespace SHADE namespace SHADE

View File

@ -10,13 +10,13 @@
* of DigiPen Institute of Technology is prohibited. * of DigiPen Institute of Technology is prohibited.
*****************************************************************************/ *****************************************************************************/
#pragma once #pragma once
#include "../SHAssetMacros.h" #include "Assets/SHAssetMacros.h"
#include "../Asset Types/SHMeshAsset.h" #include "Assets/Asset Types/SHMeshAsset.h"
#include "SHAssetLoader.h" #include "SHAssetLoader.h"
namespace SHADE namespace SHADE
{ {
struct SHMeshLoader : public SHAssetLoader struct SHMeshLoader : SHAssetLoader
{ {
void LoadSHMesh(AssetPath path, SHMeshAsset& meshes) noexcept; void LoadSHMesh(AssetPath path, SHMeshAsset& meshes) noexcept;
SHAssetData* Load(AssetPath path) override; SHAssetData* Load(AssetPath path) override;

View File

@ -0,0 +1,46 @@
/*************************************************************************//**
* \file SHShaderSourceLoader.cpp
* \author Loh Xiao Qi
* \date 23 10 2022
* \brief
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#include "SHpch.h"
#include "SHShaderSourceLoader.h"
#include "Assets/Asset Types/SHShaderAsset.h"
#include <fstream>
namespace SHADE
{
SHAssetData* SHShaderSourceLoader::Load(AssetPath path)
{
auto result = new SHShaderAsset();
result->name = path.stem().stem().string();
std::ifstream file{ path.string(), std::ios::in | std::ios::binary };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open compiled shader file: {}", path.string());
return nullptr;
}
size_t byteCount = 0;
file.read(reinterpret_cast<char*>(&result->shaderType), sizeof(uint8_t));
file.read(reinterpret_cast<char*>(&byteCount), sizeof(size_t));
result->spirvBinary.resize(byteCount / sizeof(uint32_t));
file.read(reinterpret_cast<char*>(result->spirvBinary.data()), byteCount);
file.close();
return result;
}
}

View File

@ -1,7 +1,7 @@
/*************************************************************************//** /*************************************************************************//**
* \file SHAnimationAsset.h * \file SHShaderSourceLoader.h
* \author Loh Xiao Qi * \author Loh Xiao Qi
* \date October 2022 * \date 23 10 2022
* \brief * \brief
* *
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
@ -10,21 +10,13 @@
*****************************************************************************/ *****************************************************************************/
#pragma once #pragma once
#include <vector> #include "Assets/Libraries/Loaders/SHAssetLoader.h"
#include <assimp/anim.h> #include "Assets/SHAssetMacros.h"
#include "SH_API.power h"
namespace SHADE namespace SHADE
{ {
struct SH_API SHAnimationAsset struct SHShaderSourceLoader : SHAssetLoader
{ {
std::string name; SHAssetData* Load(AssetPath path) override;
std::vector<aiNodeAnim*> nodeChannels;
std::vector<aiMeshAnim*> meshChannels;
std::vector<aiMeshMorphAnim*> morphMeshChannels;
double duration;
double ticksPerSecond;
}; };
} }

View File

@ -0,0 +1,58 @@
/*************************************************************************//**
* \file SHTextureLoader.cpp
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to load dds textures and custom binary format
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#include "SHpch.h"
#include "SHTextureLoader.h"
#include <fstream>
namespace SHADE
{
void SHTextureLoader::LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept
{
std::ifstream file{ path.string(), std::ios::in | std::ios::binary };
if (!file.is_open())
{
SHLOG_ERROR("Error opening SHTexture file: {}", path.string());
}
auto const intBytes{ sizeof(uint32_t) };
uint32_t mipCount;
file.read(reinterpret_cast<char*>(&asset.numBytes), intBytes);
file.read(reinterpret_cast<char*>(&asset.width), intBytes);
file.read(reinterpret_cast<char*>(&asset.height), intBytes);
file.read(reinterpret_cast<char*>(&asset.format), sizeof(SHTexture::TextureFormat));
file.read(reinterpret_cast<char*>(&mipCount), intBytes);
std::vector<uint32_t> mips(mipCount);
file.read(reinterpret_cast<char*>(mips.data()), intBytes * mipCount);
auto pixel = new SHTexture::PixelChannel[asset.numBytes];
file.read(reinterpret_cast<char*>(pixel), asset.numBytes);
asset.mipOffsets = std::move(mips);
asset.pixelData = std::move(pixel);
asset.compiled = true;
file.close();
}
SHAssetData* SHTextureLoader::Load(AssetPath path)
{
auto result = new SHTextureAsset();
LoadSHTexture(path, *result);
return result;
}
}

View File

@ -1,9 +1,8 @@
/*************************************************************************//** /*************************************************************************//**
* \file SHTextureCompiler.h * \file SHTextureLoader.h
* \author Loh Xiao Qi * \author Loh Xiao Qi
* \date 30 September 2022 * \date 30 September 2022
* \brief Library to write data in SHTextureAsset into binary file for * \brief Library to load dds textures and custom binary format
* faster loading in the future
* *
* *
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
@ -12,13 +11,15 @@
*****************************************************************************/ *****************************************************************************/
#pragma once #pragma once
#include "Assets/Asset Types/SHTextureAsset.h"
#include "Assets/SHAssetMacros.h" #include "Assets/SHAssetMacros.h"
#include "Assets/Asset Types/SHTextureAsset.h"
#include "SHAssetLoader.h"
namespace SHADE namespace SHADE
{ {
struct SHTextureCompiler class SHTextureLoader : public SHAssetLoader
{ {
static std::string CompileTextureBinary(SHTextureAsset const& asset, AssetPath path); void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept;
SHAssetData* Load(AssetPath path) override;
}; };
} }

View File

@ -1,36 +0,0 @@
/*************************************************************************//**
* \file SHAssimpLibrary.h
* \author Loh Xiao Qi
* \date October 2022
* \brief
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <vector>
#include "../SHAssetMacros.h"
#include "../Asset Types/SHMeshAsset.h"
#include "../Asset Types/SHAnimationAsset.h"
namespace SHADE
{
class SHAssimpLibrary
{
private:
using MeshVectorRef = std::vector<SHMeshAsset*>&;
using AnimVectorRef = std::vector<SHAnimationAsset*>&;
static Assimp::Importer aiImporter;
static void ProcessNode(aiNode const& node, aiScene const& scene,MeshVectorRef meshes) noexcept;
static void ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept;
static SHMeshAsset* ProcessMesh(aiMesh const& mesh) noexcept;
public:
static void LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept;
};
}

View File

@ -1,72 +0,0 @@
/*************************************************************************//**
* \file SHMeshCompiler.cpp
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to write data in SHMeshAsset into binary file for faster
* loading in the future
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#include "SHpch.h"
#include "SHMeshCompiler.h"
#include "Graphics/MiddleEnd/Meshes/SHMeshData.h"
#include <fstream>
std::string SHADE::SHMeshCompiler::CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept
{
std::string newPath{ path.string() };
newPath = newPath.substr(0, newPath.find_last_of('/') + 1);
newPath += asset.header.name + MESH_EXTENSION.data();
std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open file for writing mesh file: {}", path.string());
}
file.write(
reinterpret_cast<char const*>(&(asset.header.vertexCount)),
sizeof(uint32_t)
);
file.write(
reinterpret_cast<const char*>(&(asset.header.indexCount)),
sizeof(uint32_t)
);
auto const vertexVec3Byte {sizeof(SHVec3) * asset.header.vertexCount};
auto const vertexVec2Byte {sizeof(SHVec2) * asset.header.vertexCount};
file.write(
reinterpret_cast<char const*>(asset.vertexPosition.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexTangent.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexNormal.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.texCoords.data()),
vertexVec2Byte
);
file.write(
reinterpret_cast<char const*>(asset.indices.data()),
sizeof(uint32_t) * asset.header.indexCount
);
file.close();
return newPath;
}

View File

@ -1,26 +0,0 @@
/*************************************************************************//**
* \file SHMeshCompiler.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to write data in SHMeshAsset into binary file for faster
* loading in the future
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#include "../Asset Types/SHMeshAsset.h"
#include "../SHAssetMacros.h"
namespace SHADE
{
class SHMeshCompiler
{
private:
public:
static std::string CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept;
};
}

View File

@ -1,75 +0,0 @@
/*************************************************************************//**
* \file SHTextureCompiler.cpp
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to write data in SHTextureAsset into binary file for
* faster loading in the future
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#include "SHpch.h"
#include "SHTextureCompiler.h"
#include <fstream>
namespace SHADE
{
std::string SHTextureCompiler::CompileTextureBinary(SHTextureAsset const& asset, AssetPath path)
{
std::string newPath{ path.string() };
newPath = newPath.substr(0, newPath.find_last_of('.'));
newPath += TEXTURE_EXTENSION;
std::ofstream file{ newPath, std::ios::out | std::ios::binary };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open file for writing texture file: {}", path.string());
}
auto const intBytes{sizeof(uint32_t)};
uint32_t mipOffsetCount{ static_cast<uint32_t>(asset.mipOffsets.size()) };
file.write(
reinterpret_cast<char const*>(&asset.numBytes),
intBytes
);
file.write(
reinterpret_cast<char const*>(&asset.width),
intBytes
);
file.write(
reinterpret_cast<char const*>(&asset.height),
intBytes
);
file.write(
reinterpret_cast<char const*>(&asset.format),
sizeof(SHTexture::TextureFormat)
);
file.write(
reinterpret_cast<char const*>(&mipOffsetCount),
intBytes
);
file.write(
reinterpret_cast<char const*>(asset.mipOffsets.data()),
intBytes * asset.mipOffsets.size()
);
file.write(
reinterpret_cast<char const*>(asset.pixelData),
asset.numBytes
);
file.close();
return newPath;
}
}

View File

@ -1,156 +0,0 @@
/*************************************************************************//**
* \file SHTextureLoader.cpp
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to load dds textures and custom binary format
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#include "SHpch.h"
#include "SHTextureLoader.h"
namespace SHADE
{
std::string SHTextureLoader::TinyDDSResultToString(tinyddsloader::Result value)
{
switch (value)
{
case tinyddsloader::Result::ErrorFileOpen:
return "File open err";
case tinyddsloader::Result::ErrorRead:
return "File read err";
case tinyddsloader::Result::ErrorMagicWord:
return "File header magic word err";
case tinyddsloader::Result::ErrorSize:
return "File size err";
case tinyddsloader::Result::ErrorVerify:
return "Pixel format err";
case tinyddsloader::Result::ErrorNotSupported:
return "Unsupported format";
case tinyddsloader::Result::ErrorInvalidData:
return "Invalid data";
default:
return "Unknown";
}
}
vk::Format SHTextureLoader::ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear)
{
switch (format)
{
case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm_SRGB:
return isLinear ? vk::Format::eBc1RgbaUnormBlock : vk::Format::eBc1RgbaSrgbBlock;
case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm_SRGB:
return isLinear ? vk::Format::eBc2UnormBlock : vk::Format::eBc2SrgbBlock;
case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm_SRGB:
return isLinear ? vk::Format::eBc3UnormBlock : vk::Format::eBc3SrgbBlock;
case tinyddsloader::DDSFile::DXGIFormat::BC5_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::BC5_SNorm:
return isLinear ? vk::Format::eBc5UnormBlock : vk::Format::eBc5SnormBlock;
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm_SRGB:
return isLinear ? vk::Format::eR8G8B8A8Unorm : vk::Format::eR8G8B8A8Srgb;
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_SNorm:
return vk::Format::eR8G8B8A8Snorm;
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm_SRGB:
return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8A8Srgb;
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm_SRGB:
return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8Srgb;
default:
throw std::runtime_error("Unsupported DDS format.");
}
}
void SHTextureLoader::LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept
{
tinyddsloader::Result loadResult = tinyddsloader::Result::Success;
tinyddsloader::DDSFile file;
loadResult = file.Load(path.string().c_str());
if (loadResult != tinyddsloader::Result::Success)
{
SHLOG_ERROR("Unable to load Texture file: {} at {}", TinyDDSResultToString(loadResult), path.string());
}
size_t totalBytes{ 0 };
std::vector<uint32_t> mipOff(file.GetMipCount());
for (size_t i{0}; i < file.GetMipCount(); ++i)
{
mipOff[i] = static_cast<uint32_t>(totalBytes);
totalBytes += file.GetImageData(static_cast<uint32_t>(i), 0)->m_memSlicePitch;
}
SHTexture::PixelChannel* pixel = new SHTexture::PixelChannel[totalBytes];
std::memcpy(pixel, file.GetImageData()->m_mem, totalBytes);
//pixel = std::move(reinterpret_cast<SHTexture::PixelChannel const*>(file.GetDDSData()));
asset.name = path.stem().string();
asset.compiled = false;
asset.numBytes = static_cast<uint32_t>(totalBytes);
asset.width = file.GetWidth();
asset.height = file.GetHeight();
asset.format = ddsLoaderToVkFormat(file.GetFormat(), true);
asset.mipOffsets = std::move(mipOff);
asset.pixelData = std::move(pixel);
}
void SHTextureLoader::LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept
{
std::ifstream file{path.string(), std::ios::in | std::ios::binary};
if (!file.is_open())
{
SHLOG_ERROR("Error opening SHTexture file: {}", path.string());
}
auto const intBytes{ sizeof(uint32_t) };
uint32_t mipCount;
file.read(reinterpret_cast<char*>(&asset.numBytes), intBytes);
file.read(reinterpret_cast<char*>(&asset.width), intBytes);
file.read(reinterpret_cast<char*>(&asset.height), intBytes);
file.read(reinterpret_cast<char*>(&asset.format), sizeof(SHTexture::TextureFormat));
file.read(reinterpret_cast<char*>(&mipCount), intBytes);
std::vector<uint32_t> mips(mipCount);
file.read(reinterpret_cast<char*>(mips.data()), intBytes * mipCount);
auto pixel = new SHTexture::PixelChannel[asset.numBytes];
file.read(reinterpret_cast<char*>(pixel), asset.numBytes);
asset.mipOffsets = std::move(mips);
asset.pixelData = std::move( pixel );
asset.compiled = true;
file.close();
}
SHAssetData* SHTextureLoader::Load(AssetPath path)
{
auto result = new SHTextureAsset();
LoadImageAsset(path, *result);
return result;
}
void SHTextureLoader::LoadImageAsset(AssetPath path, SHTextureAsset& asset)
{
if (path.extension().string() == DDS_EXTENSION)
{
LoadTinyDDS(path, asset);
}
else if (path.extension().string() == TEXTURE_EXTENSION)
{
LoadSHTexture(path, asset);
}
}
}

View File

@ -1,34 +0,0 @@
/*************************************************************************//**
* \file SHTextureLoader.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to load dds textures and custom binary format
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#define TINYDDSLOADER_IMPLEMENTATION
#include "../SHAssetMacros.h"
#include "../Asset Types/SHTextureAsset.h"
#include "tinyddsloader.h"
#include "SHAssetLoader.h"
namespace SHADE
{
class SHTextureLoader : public SHAssetLoader
{
private:
std::string TinyDDSResultToString(tinyddsloader::Result value);
vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear);
void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept;
public:
void LoadImageAsset(AssetPath paths, SHTextureAsset& image);
void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept;
SHAssetData* Load(AssetPath path) override;
};
}

View File

@ -42,20 +42,14 @@ constexpr std::string_view ASSET_META_VER { "1.0" };
// Asset type enum // Asset type enum
enum class AssetType : AssetTypeMeta enum class AssetType : AssetTypeMeta
{ {
INVALID = 0, INVALID,
AUDIO = 1,
SHADER, SHADER,
MATERIAL, SHADER_BUILT_IN,
IMAGE,
TEXTURE, TEXTURE,
MESH, MESH,
SCRIPT,
SCENE,
PREFAB,
AUDIO_WAV,
DDS,
MAX_COUNT MAX_COUNT
}; };
constexpr size_t TYPE_COUNT{ static_cast<size_t>(AssetType::MAX_COUNT) };
//Directory //Directory
#ifdef _PUBLISH #ifdef _PUBLISH
@ -67,37 +61,55 @@ constexpr std::string_view ASSET_ROOT {"../../Assets"};
// ASSET EXTENSIONS // ASSET EXTENSIONS
constexpr std::string_view META_EXTENSION {".shmeta"}; constexpr std::string_view META_EXTENSION {".shmeta"};
constexpr std::string_view IMAGE_EXTENSION {".png"};
constexpr std::string_view AUDIO_EXTENSION {".ogg"}; constexpr std::string_view AUDIO_EXTENSION {".ogg"};
constexpr std::string_view AUDIO_WAV_EXTENSION {".wav"}; constexpr std::string_view AUDIO_WAV_EXTENSION {".wav"};
constexpr std::string_view SHADER_EXTENSION {".glsl"}; constexpr std::string_view SHADER_EXTENSION{ ".shshader" };
constexpr std::string_view SHADER_BUILT_IN_EXTENSION{".shshaderb"};
constexpr std::string_view SCRIPT_EXTENSION {".cs"}; constexpr std::string_view SCRIPT_EXTENSION {".cs"};
constexpr std::string_view SCENE_EXTENSION {".SHADE"}; constexpr std::string_view SCENE_EXTENSION {".shade"};
constexpr std::string_view PREFAB_EXTENSION {".SHPrefab"}; constexpr std::string_view PREFAB_EXTENSION {".shprefab"};
constexpr std::string_view MATERIAL_EXTENSION {".SHMat"}; constexpr std::string_view MATERIAL_EXTENSION {".shmat"};
constexpr std::string_view TEXTURE_EXTENSION {".shtex"}; constexpr std::string_view TEXTURE_EXTENSION {".shtex"};
constexpr std::string_view DDS_EXTENSION {".dds"};
constexpr std::string_view FBX_EXTENSION {".fbx"};
constexpr std::string_view GLTF_EXTENSION {".gltf"};
constexpr std::string_view MESH_EXTENSION {".shmesh"}; constexpr std::string_view MESH_EXTENSION {".shmesh"};
constexpr std::string_view EXTENSIONS[] = { constexpr std::string_view EXTENSIONS[] = {
AUDIO_EXTENSION, AUDIO_EXTENSION,
SHADER_EXTENSION, SHADER_EXTENSION,
SHADER_BUILT_IN_EXTENSION,
MATERIAL_EXTENSION, MATERIAL_EXTENSION,
IMAGE_EXTENSION,
TEXTURE_EXTENSION, TEXTURE_EXTENSION,
DDS_EXTENSION,
MESH_EXTENSION, MESH_EXTENSION,
SCRIPT_EXTENSION, SCRIPT_EXTENSION,
SCENE_EXTENSION, SCENE_EXTENSION,
PREFAB_EXTENSION, PREFAB_EXTENSION,
AUDIO_WAV_EXTENSION, AUDIO_WAV_EXTENSION,
};
// EXTERNAL EXTENSIONS
constexpr std::string_view GLSL_EXTENSION{ ".glsl" };
constexpr std::string_view DDS_EXTENSION{ ".dds" };
constexpr std::string_view FBX_EXTENSION{ ".fbx" };
constexpr std::string_view GLTF_EXTENSION{ ".gltf" };
constexpr std::string_view EXTERNALS[] = {
GLSL_EXTENSION,
DDS_EXTENSION,
FBX_EXTENSION, FBX_EXTENSION,
GLTF_EXTENSION GLTF_EXTENSION
}; };
constexpr size_t TYPE_COUNT {static_cast<size_t>(AssetType::MAX_COUNT) }; // SHADER IDENTIFIERS
constexpr std::string_view VERTEX_SHADER{ "_VS" };
constexpr std::string_view FRAGMENT_SHADER{ "_FS" };
constexpr std::string_view COMPUTER_SHADER{ "_CS" };
constexpr std::string_view SHADER_IDENTIFIERS[] = {
VERTEX_SHADER,
FRAGMENT_SHADER,
COMPUTER_SHADER
};
constexpr size_t SHADER_TYPE_MAX_COUNT{ 3 };
// Error flags // Error flags
constexpr std::string_view FILE_NOT_FOUND_ERR {"FILE NOT FOUND"}; constexpr std::string_view FILE_NOT_FOUND_ERR {"FILE NOT FOUND"};

View File

@ -14,12 +14,13 @@
#include "SHAssetMetaHandler.h" #include "SHAssetMetaHandler.h"
#include "Filesystem/SHFileSystem.h" #include "Filesystem/SHFileSystem.h"
#include "Libraries/SHAssimpLibrary.h" #include "Libraries/Loaders/SHMeshLoader.h"
#include "Libraries/SHMeshLoader.h" #include "Libraries/Loaders/SHTextureLoader.h"
#include "Libraries/SHTextureLoader.h" #include "Libraries/Loaders/SHShaderSourceLoader.h"
#include "Libraries/SHMeshCompiler.h" #include "Libraries/Compilers/SHMeshCompiler.h"
#include "Libraries/SHTextureCompiler.h" #include "Libraries/Compilers/SHTextureCompiler.h"
#include "Libraries/Compilers/SHShaderSourceCompiler.h"
namespace SHADE namespace SHADE
{ {
@ -44,7 +45,13 @@ namespace SHADE
result |= unique; result |= unique;
while (result == 0) while (result == 0 ||
std::ranges::any_of(
assetCollection.begin(),
assetCollection.end(),
[result](SHAsset const& asset) { return asset.id == result; }
)
)
{ {
result = GenerateAssetID(type); result = GenerateAssetID(type);
} }
@ -64,6 +71,19 @@ namespace SHADE
// TODO // TODO
} }
void SHAssetManager::Exit() noexcept
{
for (auto const& loader : loaders)
{
delete loader;
}
for (auto const& data : assetData)
{
delete data.second;
}
}
AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept
{ {
if (!IsRecognised(path.extension().string().c_str())) if (!IsRecognised(path.extension().string().c_str()))
@ -91,16 +111,9 @@ namespace SHADE
switch(type) switch(type)
{ {
case AssetType::SCENE: case AssetType::SHADER:
folder = "scenes/"; case AssetType::SHADER_BUILT_IN:
break; folder = "Shaders/";
case AssetType::PREFAB:
folder = "prefabs/";
break;
case AssetType::MATERIAL:
folder = "materials/";
break; break;
default: default:
@ -206,6 +219,55 @@ namespace SHADE
} }
std::vector<SHAssetData const*> SHAssetManager::GetAllDataOfType(AssetType type) noexcept
{
auto const toRetrieve = GetAllRecordOfType(type);
std::vector<SHAssetData const*> result;
result.reserve(toRetrieve.size());
for (auto const& get : toRetrieve)
{
result.push_back(LoadData(get));
}
return result;
}
std::vector<SHAsset> SHAssetManager::GetAllRecordOfType(AssetType type) noexcept
{
std::vector<SHAsset> result;
for (auto const& asset : assetCollection)
{
if (asset.type == type)
{
result.push_back(asset);
}
}
return result;
}
AssetID SHAssetManager::CompileAsset(AssetPath path) noexcept
{
SHAsset newAsset
{
.name = path.stem().string(),
.location = 0
};
auto const ext{ path.extension().string() };
if (ext == GLSL_EXTENSION.data())
{
newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value();
newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN);
newAsset.type = AssetType::SHADER_BUILT_IN;
}
assetCollection.push_back(newAsset);
SHAssetMetaHandler::WriteMetaData(newAsset);
return newAsset.id;
}
bool SHAssetManager::IsRecognised(char const* ext) noexcept bool SHAssetManager::IsRecognised(char const* ext) noexcept
{ {
for (auto const& e : EXTENSIONS) for (auto const& e : EXTENSIONS)
@ -227,23 +289,82 @@ namespace SHADE
result.type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string()); result.type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string());
result.id = GenerateAssetID(result.type); result.id = GenerateAssetID(result.type);
result.path = path; result.path = path;
result.location = 0;
return result; return result;
} }
void SHAssetManager::CompileAll() noexcept
{
std::vector<AssetPath> paths;
for (auto const& dir : std::filesystem::recursive_directory_iterator{ ASSET_ROOT })
{
if (dir.is_regular_file())
{
for (auto const& ext : EXTERNALS)
{
if (dir.path().extension().string() == ext.data())
{
paths.push_back(dir.path());
}
}
}
}
for (auto const& path : paths)
{
SHAsset newAsset
{
.name = path.stem().string(),
.location = 0
};
auto const ext{ path.extension().string() };
if (ext == GLSL_EXTENSION.data())
{
newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value();
newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN);
newAsset.type = AssetType::SHADER_BUILT_IN;
}
else if (ext == DDS_EXTENSION.data())
{
newAsset.path = SHTextureCompiler::CompileTextureAsset(path).value();
newAsset.id = GenerateAssetID(AssetType::TEXTURE);
newAsset.type = AssetType::TEXTURE;
}
else if (ext == GLTF_EXTENSION.data() || ext == FBX_EXTENSION.data())
{
std::vector<SHMeshAsset*> meshes;
std::vector<SHAnimationAsset*> anims;
SHMeshCompiler::LoadFromFile(path, meshes, anims);
for (auto const& mesh : meshes)
{
SHAsset meshAsset{
.name = mesh->header.name,
.location = 0
};
meshAsset.path = SHMeshCompiler::CompileMeshBinary(*mesh, path).value();
meshAsset.id = GenerateAssetID(AssetType::MESH);
meshAsset.type = AssetType::MESH;
assetCollection.push_back(meshAsset);
SHAssetMetaHandler::WriteMetaData(meshAsset);
}
continue;
}
assetCollection.push_back(newAsset);
SHAssetMetaHandler::WriteMetaData(newAsset);
}
}
void SHAssetManager::InitLoaders() noexcept void SHAssetManager::InitLoaders() noexcept
{ {
loaders[static_cast<size_t>(AssetType::AUDIO)] = nullptr; loaders[static_cast<size_t>(AssetType::SHADER)] = dynamic_cast<SHAssetLoader*>(new SHShaderSourceLoader());
loaders[static_cast<size_t>(AssetType::SHADER)] = nullptr; loaders[static_cast<size_t>(AssetType::SHADER_BUILT_IN)] = loaders[static_cast<size_t>(AssetType::SHADER)];
loaders[static_cast<size_t>(AssetType::MATERIAL)] = nullptr; loaders[static_cast<size_t>(AssetType::TEXTURE)] = dynamic_cast<SHAssetLoader*>(new SHTextureLoader());
loaders[static_cast<size_t>(AssetType::IMAGE)] = dynamic_cast<SHAssetLoader*>(new SHTextureLoader());
loaders[static_cast<size_t>(AssetType::TEXTURE)] = nullptr;
loaders[static_cast<size_t>(AssetType::MESH)] = dynamic_cast<SHAssetLoader*>(new SHMeshLoader()); loaders[static_cast<size_t>(AssetType::MESH)] = dynamic_cast<SHAssetLoader*>(new SHMeshLoader());
loaders[static_cast<size_t>(AssetType::SCRIPT)] = nullptr;
loaders[static_cast<size_t>(AssetType::SCENE)] = nullptr;
loaders[static_cast<size_t>(AssetType::PREFAB)] = nullptr;
loaders[static_cast<size_t>(AssetType::AUDIO_WAV)] = nullptr;
loaders[static_cast<size_t>(AssetType::DDS)] = nullptr;
} }
/**************************************************************************** /****************************************************************************
@ -251,6 +372,7 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
void SHAssetManager::Load() noexcept void SHAssetManager::Load() noexcept
{ {
//CompileAll();
InitLoaders(); InitLoaders();
BuildAssetCollection(); BuildAssetCollection();
//LoadAllData(); //LoadAllData();

View File

@ -12,7 +12,7 @@
#include "tinyddsloader.h" #include "tinyddsloader.h"
#include "SHAsset.h" #include "SHAsset.h"
#include "Asset Types/SHAssetData.h" #include "Asset Types/SHAssetData.h"
#include "Libraries/SHAssetLoader.h" #include "Assets/Libraries/Loaders/SHAssetLoader.h"
#include <memory> #include <memory>
#include "SH_API.h" #include "SH_API.h"
@ -37,6 +37,8 @@ namespace SHADE
static void Unload() noexcept; static void Unload() noexcept;
static void Unload(AssetID assetId) noexcept; static void Unload(AssetID assetId) noexcept;
static void Exit() noexcept;
/**************************************************************************** /****************************************************************************
* \brief Load all resources that are in the folder * \brief Load all resources that are in the folder
****************************************************************************/ ****************************************************************************/
@ -77,21 +79,24 @@ namespace SHADE
template<typename T> template<typename T>
static std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> GetData(AssetID id) noexcept; static std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> GetData(AssetID id) noexcept;
static std::vector<SHAssetData const*> GetAllDataOfType(AssetType type) noexcept;
static std::vector<SHAsset> GetAllRecordOfType(AssetType type) noexcept;
static AssetID CompileAsset(AssetPath path) noexcept;
private: private:
/****************************************************************************
* \brief Load resource data into memory static void InitLoaders() noexcept;
****************************************************************************/
static void LoadAllData() noexcept; static void LoadAllData() noexcept;
static SHAssetData* LoadData(SHAsset const& asset) noexcept; static SHAssetData* LoadData(SHAsset const& asset) noexcept;
inline static void BuildAssetCollection() noexcept; inline static void BuildAssetCollection() noexcept;
static bool IsRecognised(char const*) noexcept; static bool IsRecognised(char const*) noexcept;
static SHAsset CreateAssetFromPath(AssetPath path) noexcept; static SHAsset CreateAssetFromPath(AssetPath path) noexcept;
static void InitLoaders() noexcept; static void CompileAll() noexcept;
static FMOD::System* audioSystem; static FMOD::System* audioSystem;
static std::unordered_map<AssetID,SHSound>* audioSoundList; static std::unordered_map<AssetID,SHSound>* audioSoundList;

View File

@ -4,6 +4,7 @@
#include "SHCameraSystem.h" #include "SHCameraSystem.h"
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Math/SHMath.h"
namespace SHADE namespace SHADE
{ {
@ -28,7 +29,7 @@ namespace SHADE
{ {
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(GetEID()); auto transform = SHComponentManager::GetComponent<SHTransformComponent>(GetEID());
SHVec3 rotation = transform->GetWorldRotation(); SHVec3 rotation = transform->GetWorldRotation();
transform->SetWorldRotation(SHVec3{rotation.x,yaw, rotation.z}); transform->SetWorldRotation(SHVec3{rotation.x,SHMath::DegreesToRadians(yaw), rotation.z});
} }
dirtyView = true; dirtyView = true;
} }
@ -40,7 +41,7 @@ namespace SHADE
{ {
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(GetEID()); auto transform = SHComponentManager::GetComponent<SHTransformComponent>(GetEID());
SHVec3 rotation = transform->GetWorldRotation(); SHVec3 rotation = transform->GetWorldRotation();
transform->SetWorldRotation(SHVec3{ pitch,rotation.y, rotation.z }); transform->SetWorldRotation(SHVec3{ SHMath::DegreesToRadians(pitch),rotation.y, rotation.z });
} }
dirtyView = true; dirtyView = true;
} }
@ -52,7 +53,7 @@ namespace SHADE
{ {
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(GetEID()); auto transform = SHComponentManager::GetComponent<SHTransformComponent>(GetEID());
SHVec3 rotation = transform->GetWorldRotation(); SHVec3 rotation = transform->GetWorldRotation();
transform->SetWorldRotation(SHVec3{ rotation.x,rotation.y, roll}); transform->SetWorldRotation(SHVec3{ rotation.x,rotation.y, SHMath::DegreesToRadians(roll)});
} }
dirtyView = true; dirtyView = true;
} }
@ -102,7 +103,7 @@ namespace SHADE
} }
dirtyView = true; dirtyView = true;
} }
void SHCameraComponent::SetPosition(SHVec3& pos) noexcept void SHCameraComponent::SetPosition(SHVec3 pos) noexcept
{ {
this->position = pos; this->position = pos;
if (SHComponentManager::HasComponent<SHTransformComponent>(GetEID())) if (SHComponentManager::HasComponent<SHTransformComponent>(GetEID()))
@ -145,6 +146,17 @@ namespace SHADE
dirtyProj = true; dirtyProj = true;
} }
void SHCameraComponent::SetIsPerspective(bool persp) noexcept
{
this->perspProj = persp;
dirtyProj = true;
}
SHVec3 SHCameraComponent::GetPosition() const noexcept
{
return position;
}
float SHCameraComponent::GetYaw() const noexcept float SHCameraComponent::GetYaw() const noexcept
{ {
return yaw; return yaw;
@ -158,6 +170,27 @@ namespace SHADE
{ {
return roll; return roll;
} }
float SHCameraComponent::GetWidth() const noexcept
{
return width;
}
float SHCameraComponent::GetHeight() const noexcept
{
return height;
}
float SHCameraComponent::GetNear() const noexcept
{
return zNear;
}
float SHCameraComponent::GetFar() const noexcept
{
return zFar;
}
float SHCameraComponent::GetAspectRatio() const noexcept float SHCameraComponent::GetAspectRatio() const noexcept
{ {
return width/height; return width/height;
@ -168,6 +201,11 @@ namespace SHADE
return fov; return fov;
} }
bool SHCameraComponent::GetIsPerspective() const noexcept
{
return perspProj;
}
const SHMatrix& SHCameraComponent::GetViewMatrix() const noexcept const SHMatrix& SHCameraComponent::GetViewMatrix() const noexcept
{ {
return viewMatrix; return viewMatrix;
@ -178,12 +216,32 @@ namespace SHADE
return projMatrix; return projMatrix;
} }
void SHCameraComponent::SetMainCamera(size_t directorCameraIndex) noexcept //void SHCameraComponent::SetMainCamera(size_t directorCameraIndex) noexcept
//{
// auto system = SHSystemManager::GetSystem<SHCameraSystem>();
// system->GetDirector(directorCameraIndex)->SetMainCamera(*this);
//}
}//namespace SHADE
RTTR_REGISTRATION
{ {
auto system = SHSystemManager::GetSystem<SHCameraSystem>(); using namespace SHADE;
system->GetDirector(directorCameraIndex)->SetMainCamera(*this); using namespace rttr;
}
registration::class_<SHCameraComponent>("Camera Component")
.property("Position", &SHCameraComponent::GetPosition, select_overload<void(SHVec3)>(&SHCameraComponent::SetPosition))
.property("Pitch", &SHCameraComponent::GetPitch, &SHCameraComponent::SetPitch)
.property("Yaw", &SHCameraComponent::GetYaw, &SHCameraComponent::SetYaw)
.property("Roll", &SHCameraComponent::GetRoll, &SHCameraComponent::SetRoll)
.property("Width", &SHCameraComponent::GetWidth, &SHCameraComponent::SetWidth)
.property("Height", &SHCameraComponent::GetHeight, &SHCameraComponent::SetHeight)
.property("Near", &SHCameraComponent::GetNear, &SHCameraComponent::SetNear)
.property("Far", &SHCameraComponent::GetFar, &SHCameraComponent::SetFar)
.property("Perspective", &SHCameraComponent::GetIsPerspective, &SHCameraComponent::SetIsPerspective);
} }

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <rttr/registration>
#include "ECS_Base/Components/SHComponent.h" #include "ECS_Base/Components/SHComponent.h"
#include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec3.h"
#include "Math/SHMatrix.h" #include "Math/SHMatrix.h"
@ -50,32 +52,39 @@ namespace SHADE
void SetPositionY(float y) noexcept; void SetPositionY(float y) noexcept;
void SetPositionZ(float z) noexcept; void SetPositionZ(float z) noexcept;
void SetPosition(float x, float y, float z) noexcept; void SetPosition(float x, float y, float z) noexcept;
void SetPosition(SHVec3& pos) noexcept; void SetPosition(SHVec3 pos) noexcept;
void SetWidth(float width) noexcept; void SetWidth(float width) noexcept;
void SetHeight(float height) noexcept; void SetHeight(float height) noexcept;
void SetNear(float znear) noexcept; void SetNear(float znear) noexcept;
void SetFar(float zfar) noexcept; void SetFar(float zfar) noexcept;
void SetFOV(float fov) noexcept; void SetFOV(float fov) noexcept;
void SetIsPerspective(bool persp) noexcept;
SHVec3 GetPosition() const noexcept;
float GetYaw() const noexcept; float GetYaw() const noexcept;
float GetPitch() const noexcept; float GetPitch() const noexcept;
float GetRoll() const noexcept; float GetRoll() const noexcept;
float GetWidth() const noexcept;
float GetHeight() const noexcept;
float GetNear() const noexcept;
float GetFar() const noexcept;
float GetAspectRatio() const noexcept; float GetAspectRatio() const noexcept;
float GetFOV() const noexcept; float GetFOV() const noexcept;
bool GetIsPerspective() const noexcept;
const SHMatrix& GetViewMatrix() const noexcept; const SHMatrix& GetViewMatrix() const noexcept;
const SHMatrix& GetProjMatrix() const noexcept; const SHMatrix& GetProjMatrix() const noexcept;
void SetMainCamera(size_t cameraDirectorIndex = 0) noexcept; //void SetMainCamera(size_t cameraDirectorIndex = 0) noexcept;
float movementSpeed; float movementSpeed;
SHVec3 turnSpeed; SHVec3 turnSpeed;
RTTR_ENABLE()
protected: protected:

View File

@ -154,7 +154,7 @@ namespace SHADE
SHVec3 view, right, UP; SHVec3 view, right, UP;
//ClampCameraRotation(camera); ClampCameraRotation(camera);
GetCameraAxis(camera, view, right, UP); GetCameraAxis(camera, view, right, UP);
@ -221,8 +221,8 @@ namespace SHADE
SHVec3 up = { 0.0f,1.0f,0.0f }; SHVec3 up = { 0.0f,1.0f,0.0f };
target = SHVec3::RotateY(target, SHMath::DegreesToRadians(camera.yaw));
target = SHVec3::RotateX(target, SHMath::DegreesToRadians(camera.pitch)); target = SHVec3::RotateX(target, SHMath::DegreesToRadians(camera.pitch));
target = SHVec3::RotateY(target, SHMath::DegreesToRadians(camera.yaw));
target += camera.position; target += camera.position;
////SHVec3::RotateZ(target, SHMath::DegreesToRadians(camera.roll)); ////SHVec3::RotateZ(target, SHMath::DegreesToRadians(camera.roll));

View File

@ -221,6 +221,10 @@ namespace SHADE
{ {
if (!component) if (!component)
return; return;
// Get transform component for extrapolating relative sizes
auto* transformComponent = SHComponentManager::GetComponent<SHTransformComponent>(component->GetEID());
const auto componentType = rttr::type::get(*component); const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; });
ImGui::SameLine(); ImGui::SameLine();
@ -235,28 +239,41 @@ namespace SHADE
for (int i{}; i < size; ++i) for (int i{}; i < size; ++i)
{ {
ImGui::PushID(i); ImGui::PushID(i);
SHCollider& collider = component->GetCollider(i); SHCollider* collider = &component->GetCollider(i);
auto cursorPos = ImGui::GetCursorPos(); auto cursorPos = ImGui::GetCursorPos();
if (collider.GetType() == SHCollider::Type::BOX) if (collider->GetType() == SHCollider::Type::BOX)
{ {
SHEditorWidgets::BeginPanel( std::format("{} Box Collider #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); SHEditorWidgets::BeginPanel( std::format("{} Box Collider #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
auto box = reinterpret_cast<SHBoundingBox*>(collider.GetShape()); auto box = reinterpret_cast<SHBoundingBox*>(collider->GetShape());
SHEditorWidgets::DragVec3("Half Extents", { "X", "Y", "Z" }, [box] {return box->GetHalfExtents(); }, [box](SHVec3 const& vec) {box->SetHalfExtents(vec);}); SHEditorWidgets::DragVec3
(
"Half Extents", { "X", "Y", "Z" },
[box, transformComponent] { return (transformComponent->GetWorldScale() * 2.0f) * box->GetHalfExtents(); },
[collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); });
} }
else if (collider.GetType() == SHCollider::Type::SPHERE) else if (collider->GetType() == SHCollider::Type::SPHERE)
{ {
SHEditorWidgets::BeginPanel(std::format("{} Sphere Collider #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); SHEditorWidgets::BeginPanel(std::format("{} Sphere Collider #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
auto sphere = reinterpret_cast<SHBoundingSphere*>(collider.GetShape()); auto sphere = reinterpret_cast<SHBoundingSphere*>(collider->GetShape());
SHEditorWidgets::DragFloat("Radius", [sphere] {return sphere->GetRadius(); }, [sphere](float const& value) {sphere->SetRadius(value);}); SHEditorWidgets::DragFloat
(
"Radius",
[sphere, transformComponent]
{
const SHVec3& TF_WORLD_SCALE = transformComponent->GetWorldScale();
const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z });
return sphere->GetRadius() / MAX_SCALE;
},
[collider](float const& value) { collider->SetBoundingSphere(value);});
} }
else if (collider.GetType() == SHCollider::Type::CAPSULE) else if (collider->GetType() == SHCollider::Type::CAPSULE)
{ {
} }
{ {
SHEditorWidgets::BeginPanel("Offset", { ImGui::GetContentRegionAvail().x, 30.0f }); SHEditorWidgets::BeginPanel("Offset", { ImGui::GetContentRegionAvail().x, 30.0f });
SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider.GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider.SetPositionOffset(vec); }); SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider->GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider->SetPositionOffset(vec); });
SHEditorWidgets::EndPanel(); SHEditorWidgets::EndPanel();
} }
if(ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data())) if(ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data()))

View File

@ -20,6 +20,7 @@
#include "AudioSystem/SHAudioSystem.h" #include "AudioSystem/SHAudioSystem.h"
#include "Physics/Components/SHRigidBodyComponent.h" #include "Physics/Components/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Components/SHColliderComponent.h"
#include "Camera/SHCameraComponent.h"
namespace SHADE namespace SHADE
{ {
@ -35,6 +36,23 @@ namespace SHADE
return selected; return selected;
} }
template <typename ComponentType, typename EnforcedComponent, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true, std::enable_if_t<std::is_base_of_v<SHComponent, EnforcedComponent>, bool> = true>
bool DrawAddComponentWithEnforcedComponentButton(EntityID const& eid)
{
bool selected = false;
if (!SHComponentManager::HasComponent<ComponentType>(eid))
{
if(selected = ImGui::Selectable(std::format("Add {}", rttr::type::get<ComponentType>().get_name().data()).data()); selected)
{
if(SHComponentManager::GetComponent_s<EnforcedComponent>(eid) == nullptr)
SHComponentManager::AddComponent<EnforcedComponent>(eid);
SHComponentManager::AddComponent<ComponentType>(eid);
}
}
return selected;
}
SHEditorInspector::SHEditorInspector() SHEditorInspector::SHEditorInspector()
:SHEditorWindow("Inspector", ImGuiWindowFlags_MenuBar) :SHEditorWindow("Inspector", ImGuiWindowFlags_MenuBar)
{ {
@ -86,6 +104,10 @@ namespace SHADE
{ {
DrawComponent(lightComponent); DrawComponent(lightComponent);
} }
if (auto cameraComponent = SHComponentManager::GetComponent_s<SHCameraComponent>(eid))
{
DrawComponent(cameraComponent);
}
ImGui::Separator(); ImGui::Separator();
// Render Scripts // Render Scripts
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>()); SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
@ -94,16 +116,15 @@ namespace SHADE
if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data())) if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data()))
{ {
DrawAddComponentButton<SHTransformComponent>(eid); DrawAddComponentButton<SHTransformComponent>(eid);
DrawAddComponentButton<SHRenderable>(eid); DrawAddComponentButton<SHCameraComponent>(eid);
DrawAddComponentButton<SHColliderComponent>(eid);
DrawAddComponentButton<SHLightComponent>(eid); // Components that require Transforms
if(DrawAddComponentButton<SHRigidBodyComponent>(eid))
{ DrawAddComponentWithEnforcedComponentButton<SHRenderable, SHTransformComponent>(eid);
if(SHComponentManager::GetComponent_s<SHTransformComponent>(eid) == nullptr) DrawAddComponentWithEnforcedComponentButton<SHRigidBodyComponent, SHTransformComponent>(eid);
{ DrawAddComponentWithEnforcedComponentButton<SHColliderComponent, SHTransformComponent>(eid);
SHComponentManager::AddComponent<SHTransformComponent>(eid);
}
}
ImGui::EndMenu(); ImGui::EndMenu();
} }

View File

@ -54,7 +54,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
bool SHEditorUI::CollapsingHeader(const std::string& title) bool SHEditorUI::CollapsingHeader(const std::string& title)
{ {
return ImGui::CollapsingHeader(title.c_str()); return ImGui::CollapsingHeader(title.c_str(), ImGuiTreeNodeFlags_DefaultOpen);
} }
void SHEditorUI::SameLine() void SHEditorUI::SameLine()

View File

@ -11,3 +11,6 @@ constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT { 2 };
constexpr SHEventIdentifier SH_COMPONENT_ADDED_EVENT { 3 }; constexpr SHEventIdentifier SH_COMPONENT_ADDED_EVENT { 3 };
constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT { 4 }; constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT { 4 };
constexpr SHEventIdentifier SH_SCENEGRAPH_CHANGE_PARENT_EVENT { 5 }; constexpr SHEventIdentifier SH_SCENEGRAPH_CHANGE_PARENT_EVENT { 5 };
constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_ADDED_EVENT { 6 };
constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_REMOVED_EVENT { 7 };

View File

@ -12,6 +12,7 @@
#include "SHpch.h" #include "SHpch.h"
#include "SHEvent.h" #include "SHEvent.h"
#include "SHEventReceiver.h" #include "SHEventReceiver.h"
#include "SH_API.h"
/****************************************************************************** /******************************************************************************
INSTRUCTIONS FOR USE: INSTRUCTIONS FOR USE:
@ -67,7 +68,7 @@ namespace SHADE
using EventManagerListener = std::function<void(SHEvent)>; using EventManagerListener = std::function<void(SHEvent)>;
class SHEventManager class SH_API SHEventManager
{ {
private: private:

View File

@ -45,16 +45,20 @@ namespace SHADE
void SHBatch::Add(const SHRenderable* renderable) void SHBatch::Add(const SHRenderable* renderable)
{ {
// Ignore if null
if (!renderable->GetMesh())
return;
// Check if we have a SubBatch with the same mesh yet // Check if we have a SubBatch with the same mesh yet
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch) 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 // Create one if not found
if (subBatch == subBatches.end()) if (subBatch == subBatches.end())
{ {
subBatches.emplace_back(renderable->Mesh); subBatches.emplace_back(renderable->GetMesh());
subBatch = subBatches.end() - 1; subBatch = subBatches.end() - 1;
} }
@ -73,7 +77,7 @@ namespace SHADE
// Check if we have a SubBatch with the same mesh yet // Check if we have a SubBatch with the same mesh yet
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch) 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 // Attempt to remove if it exists
@ -84,13 +88,18 @@ namespace SHADE
// Check if other renderables in subBatches contain the same material instance // Check if other renderables in subBatches contain the same material instance
bool matUnused = true; bool matUnused = true;
Handle<SHMaterialInstance> matToCheck = renderable->HasMaterialChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial();
for (const auto& sb : subBatches) for (const auto& sb : subBatches)
{
// Check material usage
for (const auto& rendId : sb.Renderables) for (const auto& rendId : sb.Renderables)
{ {
auto rend = SHComponentManager::GetComponent<SHRenderable>(rendId); auto rend = SHComponentManager::GetComponent<SHRenderable>(rendId);
if (rend) if (rend)
{ {
if (rend->GetMaterial() == renderable->GetMaterial()) if (rend->GetMaterial() == matToCheck)
{ {
matUnused = false; matUnused = false;
break; break;
@ -101,10 +110,15 @@ namespace SHADE
SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!"); SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
} }
} }
}
// Material is no longer in this library, so we remove it // Material is no longer in this library, so we remove it
if (matUnused) 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 // Mark all as dirty
setAllDirtyFlags(); setAllDirtyFlags();

View File

@ -110,29 +110,8 @@ namespace SHADE
graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
// TODO: This is VERY temporarily here until a more solid resource management system is implemented shaderModuleLibrary.ImportAllShaderSource(device);
shaderSourceLibrary.Init("../../TempShaderFolder/"); shaderModuleLibrary.ReflectAllShaderModules();
shaderSourceLibrary.LoadShader(0, "TestCubeVs.glsl", SH_SHADER_TYPE::VERTEX, true);
shaderSourceLibrary.LoadShader(1, "TestCubeFs.glsl", SH_SHADER_TYPE::FRAGMENT, true);
shaderSourceLibrary.LoadShader(2, "KirschCs.glsl", SH_SHADER_TYPE::COMPUTE, true);
shaderSourceLibrary.LoadShader(3, "PureCopyCs.glsl", SH_SHADER_TYPE::COMPUTE, true);
shaderSourceLibrary.LoadShader(4, "DeferredCompositeCs.glsl", SH_SHADER_TYPE::COMPUTE, true);
shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary);
auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl");
auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl");
auto greyscale = shaderModuleLibrary.GetShaderModule("KirschCs.glsl");
auto pureCopy = shaderModuleLibrary.GetShaderModule("PureCopyCs.glsl");
auto deferredComposite = shaderModuleLibrary.GetShaderModule("DeferredCompositeCs.glsl");
cubeVS->Reflect();
cubeFS->Reflect();
greyscale->Reflect();
pureCopy->Reflect();
deferredComposite->Reflect();
} }
void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept
@ -210,7 +189,7 @@ namespace SHADE
//gBufferNode->AddNodeCompute(pureCopyShader, { "Position", "Scene" }); //gBufferNode->AddNodeCompute(pureCopyShader, { "Position", "Scene" });
// deferred composite // deferred composite
auto deferredCompositeShader = shaderModuleLibrary.GetShaderModule("DeferredCompositeCs.glsl"); auto deferredCompositeShader = shaderModuleLibrary.GetBuiltInShaderModule("DeferredComposite_CS");
gBufferNode->AddNodeCompute(deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "Scene" }); gBufferNode->AddNodeCompute(deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "Scene" });
@ -228,11 +207,10 @@ namespace SHADE
worldRenderer->SetCameraDirector(cameraSystem->CreateDirector()); worldRenderer->SetCameraDirector(cameraSystem->CreateDirector());
auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl"); auto cubeVS = shaderModuleLibrary.GetBuiltInShaderModule("TestCube_VS");
auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl"); auto cubeFS = shaderModuleLibrary.GetBuiltInShaderModule("TestCube_FS");
defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferSubpass); defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferSubpass);
} }
void SHGraphicsSystem::InitMiddleEnd(void) noexcept void SHGraphicsSystem::InitMiddleEnd(void) noexcept
@ -737,7 +715,7 @@ namespace SHADE
auto& renderables = SHComponentManager::GetDense<SHRenderable>(); auto& renderables = SHComponentManager::GetDense<SHRenderable>();
for (auto& renderable : renderables) for (auto& renderable : renderables)
{ {
if (!renderable.WasMaterialChanged()) if (!renderable.HasChanged())
continue; continue;
// Remove from old material's SuperBatch // Remove from old material's SuperBatch
@ -825,5 +803,10 @@ namespace SHADE
} }
Handle<SHRenderGraphNode> SHGraphicsSystem::GetPrimaryRenderpass() const noexcept
{
return worldRenderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data());
}
#pragma endregion MISC #pragma endregion MISC
} }

View File

@ -25,7 +25,6 @@ of DigiPen Institute of Technology is prohibited.
#include "ECS_Base/System/SHSystemRoutine.h" #include "ECS_Base/System/SHSystemRoutine.h"
#include "Graphics/Descriptors/SHVkDescriptorPool.h" #include "Graphics/Descriptors/SHVkDescriptorPool.h"
#include "Graphics/RenderGraph/SHRenderGraph.h" #include "Graphics/RenderGraph/SHRenderGraph.h"
#include "Graphics/MiddleEnd/Shaders/SHShaderSourceLibrary.h"
#include "Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.h" #include "Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.h"
#include "SHMeshLibrary.h" #include "SHMeshLibrary.h"
#include "Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.h" #include "Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.h"
@ -136,7 +135,7 @@ namespace SHADE
void RemoveViewport(Handle<SHViewport> viewport); void RemoveViewport(Handle<SHViewport> viewport);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Material Creation Functions */ /* Material Functions */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
Handle<SHMaterial> AddMaterial(Handle<SHVkShaderModule> vertShader, Handle<SHVkShaderModule> fragShader, Handle<SHSubpass> subpass); Handle<SHMaterial> AddMaterial(Handle<SHVkShaderModule> vertShader, Handle<SHVkShaderModule> fragShader, Handle<SHSubpass> subpass);
void RemoveMaterial(Handle<SHMaterial> material); void RemoveMaterial(Handle<SHMaterial> material);
@ -144,6 +143,8 @@ namespace SHADE
Handle<SHMaterialInstance> AddOrGetBaseMaterialInstance(Handle<SHMaterial> material); Handle<SHMaterialInstance> AddOrGetBaseMaterialInstance(Handle<SHMaterial> material);
Handle<SHMaterialInstance> AddMaterialInstanceCopy(Handle<SHMaterialInstance> materialInst); Handle<SHMaterialInstance> AddMaterialInstanceCopy(Handle<SHMaterialInstance> materialInst);
void RemoveMaterialInstance(Handle<SHMaterialInstance> materialInstance); void RemoveMaterialInstance(Handle<SHMaterialInstance> materialInstance);
Handle<SHMaterial> GetDefaultMaterial() { return defaultMaterial; }
Handle<SHMaterialInstance> GetDefaultMaterialInstance() { return AddOrGetBaseMaterialInstance(defaultMaterial); }
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Mesh Registration Functions */ /* Mesh Registration Functions */
@ -287,12 +288,17 @@ namespace SHADE
#endif #endif
Handle<SHMousePickSystem> GetMousePickSystem(void) const noexcept {return mousePickSystem;}; Handle<SHMousePickSystem> GetMousePickSystem(void) const noexcept {return mousePickSystem;};
Handle<SHPostOffscreenRenderSystem> GetPostOffscreenRenderSystem(void) const noexcept {return postOffscreenRender;}; Handle<SHPostOffscreenRenderSystem> GetPostOffscreenRenderSystem(void) const noexcept {return postOffscreenRender;};
Handle<SHRenderGraphNode> GetPrimaryRenderpass() const noexcept;
//SHRenderGraph const& GetRenderGraph(void) const noexcept; //SHRenderGraph const& GetRenderGraph(void) const noexcept;
//Handle<SHVkRenderpass> GetRenderPass() const { return renderPass; } //Handle<SHVkRenderpass> GetRenderPass() const { return renderPass; }
private: private:
/*-----------------------------------------------------------------------------*/
/* Constants */
/*-----------------------------------------------------------------------------*/
static constexpr std::string_view G_BUFFER_RENDER_GRAPH_NODE_NAME = "G-Buffer";
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
@ -340,8 +346,6 @@ namespace SHADE
Handle<SHCamera> worldCamera; Handle<SHCamera> worldCamera;
Handle<SHCamera> screenCamera; Handle<SHCamera> screenCamera;
// TODO: Temporary only until resource library from Xiao Qi is implemented
SHShaderSourceLibrary shaderSourceLibrary;
SHShaderModuleLibrary shaderModuleLibrary; SHShaderModuleLibrary shaderModuleLibrary;
// Temp Materials // Temp Materials

View File

@ -4,6 +4,8 @@
#include "Graphics/Pipeline/SHVkPipeline.h" #include "Graphics/Pipeline/SHVkPipeline.h"
#include "SHGraphicsConstants.h" #include "SHGraphicsConstants.h"
#include "Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h" #include "Graphics/Shaders/BlockInterface/SHShaderBlockInterface.h"
#include "Math/Vector/SHVec3.h"
#include "Math/Vector/SHVec4.h"
namespace SHADE namespace SHADE
{ {
@ -23,7 +25,7 @@ namespace SHADE
} }
// Allocate memory for properties // Allocate memory for properties
const Handle<SHShaderBlockInterface> SHADER_INFO = getShaderBlockInterface(); const Handle<SHShaderBlockInterface> SHADER_INFO = GetShaderBlockInterface();
propMemorySize = SHADER_INFO ? SHADER_INFO->GetBytesRequired() : 0; propMemorySize = SHADER_INFO ? SHADER_INFO->GetBytesRequired() : 0;
if (propMemorySize <= 0) if (propMemorySize <= 0)
{ {
@ -49,6 +51,22 @@ namespace SHADE
// Reset all the properties to default values // Reset all the properties to default values
if (propMemory) if (propMemory)
memset(propMemory.get(), 0, propMemorySize); memset(propMemory.get(), 0, propMemorySize);
// Initialize Vectors to all 1.0 by default
const Handle<SHShaderBlockInterface> SHADER_INFO = GetShaderBlockInterface();
for (int i = 0; i < SHADER_INFO->GetVariableCount(); ++i)
{
const auto& VAR = SHADER_INFO->GetVariable(i);
switch (VAR->type)
{
case SHShaderBlockInterface::Variable::Type::VECTOR3:
setPropertyUnsafe(VAR->offset, SHVec3::One);
break;
case SHShaderBlockInterface::Variable::Type::VECTOR4:
setPropertyUnsafe(VAR->offset, SHVec4::One);
break;
}
}
} }
void SHMaterial::ExportProperties(void* dest) const noexcept void SHMaterial::ExportProperties(void* dest) const noexcept
@ -59,14 +77,14 @@ namespace SHADE
size_t SHMaterial::GetPropertiesMemorySize() const noexcept 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; return SHADER_INFO ? SHADER_INFO->GetBytesRequired() : 0;
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Helper Functions */ /* Helper Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
Handle<SHShaderBlockInterface> SHMaterial::getShaderBlockInterface() const noexcept Handle<SHShaderBlockInterface> SHMaterial::GetShaderBlockInterface() const noexcept
{ {
return pipeline->GetPipelineLayout()->GetShaderBlockInterface return pipeline->GetPipelineLayout()->GetShaderBlockInterface
( (

View File

@ -50,13 +50,24 @@ namespace SHADE
template<typename T> template<typename T>
void SetProperty(const std::string& key, const T& value); void SetProperty(const std::string& key, const T& value);
template<typename T> template<typename T>
void SetProperty(uint32_t memOffset, const T& value);
template<typename T>
T& GetProperty(const std::string& key); T& GetProperty(const std::string& key);
template<typename T> template<typename T>
const T& GetProperty(const std::string& key) const; 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 ResetProperties();
void ExportProperties(void* dest) const noexcept; void ExportProperties(void* dest) const noexcept;
Byte GetPropertiesMemorySize() const noexcept; Byte GetPropertiesMemorySize() const noexcept;
/*-----------------------------------------------------------------------------*/
/* Query Functions */
/*-----------------------------------------------------------------------------*/
Handle<SHShaderBlockInterface> GetShaderBlockInterface() const noexcept;
private: private:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
@ -68,7 +79,8 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Helper Functions */ /* Helper Functions */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
Handle<SHShaderBlockInterface> getShaderBlockInterface() const noexcept; template<typename T>
inline void setPropertyUnsafe(uint32_t memOffset, const T& value); // SetProperty() but without checks
}; };
} }

View File

@ -25,7 +25,7 @@ namespace SHADE
template<typename T> template<typename T>
void SHMaterial::SetProperty(const std::string& key, const T& value) 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); const auto PROP_INFO = SHADER_INFO->GetVariable(key);
if (PROP_INFO == nullptr) if (PROP_INFO == nullptr)
{ {
@ -33,21 +33,32 @@ namespace SHADE
} }
// Get offset and modify the memory directly // Get offset and modify the memory directly
T* dataPtr = propMemory.get() + PROP_INFO->offset; T* dataPtr = reinterpret_cast<T*>(propMemory.get() + PROP_INFO->offset);
*dataPtr = value; *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
setPropertyUnsafe(memOffset, value);
}
template<typename T> template<typename T>
T& SHMaterial::GetProperty(const std::string& key) 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); const auto PROP_INFO = SHADER_INFO->GetVariable(key);
if (PROP_INFO == nullptr) 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 // Get offset and return the memory directly
T* dataPtr = propMemory.get() + PROP_INFO->offset; T* dataPtr = reinterpret_cast<T*>(propMemory.get() + PROP_INFO->offset);
return *dataPtr; return *dataPtr;
} }
template<typename T> template<typename T>
@ -56,4 +67,24 @@ namespace SHADE
return const_cast<const T&>(const_cast<SHMaterial*>(this)->GetProperty(key)); 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));
}
template<typename T>
void SHMaterial::setPropertyUnsafe(uint32_t memOffset, const T& value)
{
(*reinterpret_cast<T*>(propMemory.get() + memOffset)) = value;
}
} }

View File

@ -69,7 +69,7 @@ namespace SHADE
// Search Override Data for the property // Search Override Data for the property
uint32_t PROP_IDX = SHADER_INFO->GetVariableIndex(key); uint32_t PROP_IDX = SHADER_INFO->GetVariableIndex(key);
auto prop = std::find(overrideData.begin(), overrideData.end(), [&](const OverrideData& data) auto prop = std::find_if(overrideData.begin(), overrideData.end(), [&](const OverrideData& data)
{ {
return PROP_IDX == data.Index; return PROP_IDX == data.Index;
}); });
@ -77,7 +77,7 @@ namespace SHADE
throw std::invalid_argument("Attempted to get an property that was not set previously!"); throw std::invalid_argument("Attempted to get an property that was not set previously!");
// Get offset and return the memory directly // Get offset and return the memory directly
T* dataPtr = dataStore.get() + prop->StoredDataOffset; T* dataPtr = reinterpret_cast<T*>(dataStore.get() + prop->StoredDataOffset);
return *dataPtr; return *dataPtr;
} }
template<typename T> template<typename T>

View File

@ -17,7 +17,8 @@ of DigiPen Institute of Technology is prohibited.
// Project Includes // Project Includes
#include "Resource/SHHandle.h" #include "Resource/SHHandle.h"
#include "Resource/SHResourceLibrary.h" #include "Resource/SHResourceLibrary.h"
#include "Math/SHMath.h" #include "Math/Vector/SHVec2.h"
#include "Math/Vector/SHVec3.h"
namespace SHADE namespace SHADE
{ {

View File

@ -23,7 +23,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHRenderable::OnCreate() void SHRenderable::OnCreate()
{ {
materialChanged = true; matChanged = true;
sharedMaterial = {}; sharedMaterial = {};
material = {}; material = {};
oldMaterial = {}; oldMaterial = {};
@ -55,7 +55,7 @@ namespace SHADE
return; return;
// Flag that material was changed // Flag that material was changed
materialChanged = true; matChanged = true;
// Free copies of materials if any // Free copies of materials if any
if (material) if (material)
@ -93,14 +93,40 @@ namespace SHADE
return material; 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 uint8_t SHRenderable::GetLightLayer(void) const noexcept
{ {
return lightLayer; return lightLayer;
} }
/*-----------------------------------------------------------------------------------*/
/* Batcher Dispatcher Functions */
/*-----------------------------------------------------------------------------------*/
void SHRenderable::ResetChangedFlag() void SHRenderable::ResetChangedFlag()
{ {
materialChanged = false; matChanged = false;
meshChanged = false;
oldMaterial = {}; 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 #pragma once
// External Dependencies
#include <rttr/registration>
// Project Includes // Project Includes
#include "Resource/SHHandle.h" #include "Resource/SHHandle.h"
//#include "SHTransform.h"
#include "ECS_Base/Components/SHComponent.h" #include "ECS_Base/Components/SHComponent.h"
#include "Math/SHMatrix.h" #include "Math/SHMatrix.h"
#include "SH_API.h" #include "SH_API.h"
@ -50,33 +51,42 @@ namespace SHADE
void SetMaterial(Handle<SHMaterialInstance> materialInstance); void SetMaterial(Handle<SHMaterialInstance> materialInstance);
Handle<SHMaterialInstance> GetMaterial() const; Handle<SHMaterialInstance> GetMaterial() const;
Handle<SHMaterialInstance> GetModifiableMaterial(); 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; uint8_t GetLightLayer (void) const noexcept;
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
/* Batcher Dispatcher Functions */ /* 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 void ResetChangedFlag(); // TODO: Lock it so that only SHBatcherDispatcher can access this
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
Handle<SHMesh> Mesh;
private: private:
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
Handle<SHMesh> mesh;
Handle<SHMesh> oldMesh;
bool meshChanged = true;
Handle<SHMaterialInstance> sharedMaterial; Handle<SHMaterialInstance> sharedMaterial;
Handle<SHMaterialInstance> material; Handle<SHMaterialInstance> material;
bool materialChanged = true; bool matChanged = true;
Handle<SHMaterialInstance> oldMaterial; Handle<SHMaterialInstance> oldMaterial;
uint8_t lightLayer; uint8_t lightLayer;
RTTR_ENABLE()
}; };
} }

View File

@ -1,6 +1,7 @@
#include "SHPch.h" #include "SHPch.h"
#include "SHShaderModuleLibrary.h" #include "SHShaderModuleLibrary.h"
#include "Graphics/Devices/SHVkLogicalDevice.h" #include "Graphics/Devices/SHVkLogicalDevice.h"
#include "Assets/SHAssetManager.h"
namespace SHADE namespace SHADE
{ {
@ -18,13 +19,58 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
void SHShaderModuleLibrary::ImportFromSourceLibrary(Handle<SHVkLogicalDevice>& logicalDeviceHdl, SHShaderSourceLibrary const& sourceLib) noexcept //void SHShaderModuleLibrary::ImportFromSourceLibrary(Handle<SHVkLogicalDevice>& logicalDeviceHdl, SHShaderSourceLibrary const& sourceLib) noexcept
{ //{
auto const& sources = sourceLib.GetSourceLibrary(); // auto const& sources = sourceLib.GetSourceLibrary();
for (auto const& source : sources) // for (auto const& source : sources)
// {
// vk::ShaderStageFlagBits shaderType{};
// switch (source.shaderType)
// {
// case SH_SHADER_TYPE::VERTEX:
// shaderType = vk::ShaderStageFlagBits::eVertex;
// break;
// case SH_SHADER_TYPE::FRAGMENT:
// shaderType = vk::ShaderStageFlagBits::eFragment;
// break;
// case SH_SHADER_TYPE::COMPUTE:
// shaderType = vk::ShaderStageFlagBits::eCompute;
// break;
// default:
// shaderType = vk::ShaderStageFlagBits::eVertex;
// break;
// }
// Handle<SHVkShaderModule> newShaderModule = logicalDeviceHdl->CreateShaderModule(source.spirvBinary, "main", shaderType, source.name);
// shaderModules.emplace(source.id, newShaderModule);
// stringToID.emplace(source.name, source.id);
// }
//}
/***************************************************************************/
/*!
\brief
Gets the shader module based on module name.
\param shaderName
\return
*/
/***************************************************************************/
//Handle<SHVkShaderModule> SHShaderModuleLibrary::GetShaderModule(std::string shaderName) const noexcept
//{
// if (stringToID.contains(shaderName))
// return shaderModules.at(stringToID.at(shaderName));
// else
// return {};
//}
vk::ShaderStageFlagBits SHShaderModuleLibrary::GetVkShaderFlag(SH_SHADER_TYPE type) noexcept
{ {
vk::ShaderStageFlagBits shaderType{}; vk::ShaderStageFlagBits shaderType{};
switch (source.shaderType) switch (type)
{ {
case SH_SHADER_TYPE::VERTEX: case SH_SHADER_TYPE::VERTEX:
shaderType = vk::ShaderStageFlagBits::eVertex; shaderType = vk::ShaderStageFlagBits::eVertex;
@ -40,30 +86,54 @@ namespace SHADE
break; break;
} }
Handle<SHVkShaderModule> newShaderModule = logicalDeviceHdl->CreateShaderModule(source.spirvBinary, "main", shaderType, source.name); return shaderType;
shaderModules.emplace(source.id, newShaderModule);
stringToID.emplace(source.name, source.id);
}
} }
/***************************************************************************/ Handle<SHVkShaderModule> SHShaderModuleLibrary::GetBuiltInShaderModule(std::string shaderName) const noexcept
/*!
\brief
Gets the shader module based on module name.
\param shaderName
\return
*/
/***************************************************************************/
Handle<SHVkShaderModule> SHShaderModuleLibrary::GetShaderModule(std::string shaderName) const noexcept
{ {
if (stringToID.contains(shaderName)) if (builtInShaderModules.contains(shaderName))
return shaderModules.at(stringToID.at(shaderName)); return builtInShaderModules.at(shaderName);
else else
return {}; return {};
} }
void SHShaderModuleLibrary::ImportAllShaderSource(Handle<SHVkLogicalDevice>& logicalDeviceHdl) noexcept
{
uint32_t idCounter{ 0 };
auto const data = SHAssetManager::GetAllDataOfType(AssetType::SHADER);
for (auto const& dataPtr : data)
{
auto const shader = dynamic_cast<SHShaderAsset const*>(dataPtr);
Handle<SHVkShaderModule> newShaderModule =
logicalDeviceHdl->CreateShaderModule(shader->spirvBinary, "main", GetVkShaderFlag(shader->shaderType), shader->name);
shaderModules.emplace(idCounter++, newShaderModule);
}
auto const builtIn = SHAssetManager::GetAllDataOfType(AssetType::SHADER_BUILT_IN);
for (auto const& dataPtr : builtIn)
{
auto const shader = dynamic_cast<SHShaderAsset const*>(dataPtr);
Handle<SHVkShaderModule> newShaderModule =
logicalDeviceHdl->CreateShaderModule(shader->spirvBinary, "main", GetVkShaderFlag(shader->shaderType), shader->name);
builtInShaderModules.emplace(shader->name, newShaderModule);
}
}
void SHShaderModuleLibrary::ReflectAllShaderModules() noexcept
{
for (auto& module : shaderModules)
{
module.second->Reflect();
}
for (auto& module : builtInShaderModules)
{
module.second->Reflect();
}
}
} }

View File

@ -2,8 +2,7 @@
#define SH_SHADER_MODULE_LIBRARY_H #define SH_SHADER_MODULE_LIBRARY_H
#include "Graphics/Shaders/SHVkShaderModule.h" #include "Graphics/Shaders/SHVkShaderModule.h"
#include "SHShaderSourceLibrary.h" #include "Assets/Asset Types/SHShaderAsset.h"
#include <map>
namespace SHADE namespace SHADE
{ {
@ -22,20 +21,23 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
//! Stored shader modules //! Stored shader modules
std::unordered_map<uint32_t, Handle<SHVkShaderModule>> shaderModules; std::unordered_map<uint32_t, Handle<SHVkShaderModule>> shaderModules;
std::unordered_map<std::string, Handle<SHVkShaderModule>> builtInShaderModules;
//! We want some sort of interface with strings, instead of ints inline vk::ShaderStageFlagBits GetVkShaderFlag(SH_SHADER_TYPE type) noexcept;
std::map<std::string, uint32_t> stringToID;
public: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */ /* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void ImportFromSourceLibrary(Handle<SHVkLogicalDevice>& logicalDeviceHdl, SHShaderSourceLibrary const& sourceLib) noexcept; //void ImportFromSourceLibrary(Handle<SHVkLogicalDevice>& logicalDeviceHdl, SHShaderSourceLibrary const& sourceLib) noexcept;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */ /* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
Handle<SHVkShaderModule> GetShaderModule(std::string shaderName) const noexcept; Handle<SHVkShaderModule> GetBuiltInShaderModule(std::string shaderName) const noexcept;
void ImportAllShaderSource(Handle<SHVkLogicalDevice>& logicalDeviceHdl) noexcept;
void ReflectAllShaderModules() noexcept;
}; };
} }

View File

@ -1,308 +0,0 @@
#include "SHPch.h"
#include <filesystem>
#include <fstream>
#include "SHShaderSourceLibrary.h"
#include "Tools/SHLogger.h"
namespace SHADE
{
/***************************************************************************/
/*!
\brief
Initializes the directory to take assets from. TODO: Only temporary until
the resource manager is implemented.
\param directory
\return
*/
/***************************************************************************/
void SHShaderSourceLibrary::Init (std::string directory) noexcept
{
shaderDirectory = directory;
if (shaderDirectory.back() != '/')
{
shaderDirectory += '/';
}
}
/***************************************************************************/
/*!
\brief
Private member function to compile a shader STRING source to binary and
returns a vector of 4 bytes.
\param glslSource
The GLSL string source.
\param type
Type of the shader: vertex, fragment, compute, etc.
\param opLevel
Optimization level.
\return
Returns a vector of the binary data.
*/
/***************************************************************************/
std::vector<uint32_t> SHShaderSourceLibrary::CompileToBinary(std::string const& glslSource, char const* const spirvFilename, SH_SHADER_TYPE type, shaderc_optimization_level opLevel /*= shaderc_optimization_level_zero*/)
{
// shaderc compiler
shaderc::Compiler compiler;
shaderc::CompileOptions options;
options.AddMacroDefinition("MY_DEFINE", "1");
// Set optimization levels
if (opLevel != shaderc_optimization_level_zero)
options.SetOptimizationLevel(opLevel);
// Attempt to get the shaderc equivalent shader stage
shaderc_shader_kind shaderKind;
switch (type)
{
case SH_SHADER_TYPE::VERTEX:
shaderKind = shaderc_shader_kind::shaderc_glsl_vertex_shader;
break;
case SH_SHADER_TYPE::FRAGMENT:
shaderKind = shaderc_shader_kind::shaderc_glsl_fragment_shader;
break;
case SH_SHADER_TYPE::COMPUTE:
shaderKind = shaderc_shader_kind::shaderc_glsl_compute_shader;
break;
default:
shaderKind = shaderc_shader_kind::shaderc_glsl_vertex_shader;
break;
}
// Compile the shader and get the result
shaderc::SpvCompilationResult compileResult = compiler.CompileGlslToSpv(glslSource, shaderKind, spirvFilename, options);
if (compileResult.GetCompilationStatus() != shaderc_compilation_status_success)
{
SHLOG_ERROR("Shaderc failed to compile GLSL shader to binary | " + compileResult.GetErrorMessage());
}
return { compileResult.begin(), compileResult.end() };
}
/***************************************************************************/
/*!
\brief
TODO: Delete after file IO is implemented. Loads a shader from disk.
\param filePath
file path to the shader in the asset directory.
\return
Returns the data in the file in string form.
*/
/***************************************************************************/
std::string SHShaderSourceLibrary::GetStringFromFile(char const* filePath) noexcept
{
// Retrieve contents from filePath
// Ensure ifstream objects can throw exceptions
std::ifstream iFile;
iFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
std::string fileContent = "";
try
{
// Open file
// Read file's buffer contents into streams
iFile.open(filePath);
std::stringstream fileStream;
fileStream << iFile.rdbuf();
fileContent = fileStream.str();
// Close file handler
iFile.close();
}
catch (std::ifstream::failure e)
{
std::cerr << "File was not successfully read" << filePath << std::endl;
}
return fileContent;
}
/***************************************************************************/
/*!
\brief
Load a shader into the library.
\param filePath
file path to the shader in the asset directory.
*/
/***************************************************************************/
bool SHShaderSourceLibrary::LoadShader (uint32_t id, std::string glslFile, SH_SHADER_TYPE type, bool checkSpirvOutdated/* = true*/, bool recompileAnyway /*= false*/) noexcept
{
//if (sourceLibrary.contains(id))
//{
// SHLOG_ERROR("Shader with ID passed in already exists. Use a different ID");
// return false;
//}
std::string fullGLSLPath = shaderDirectory + glslFile;
auto path = std::filesystem::path(fullGLSLPath);
if (path.extension() != ".glsl")
{
SHLOG_ERROR("Shader is not GLSL file, failed to load shader. ");
return false;
}
std::string spirvFilepath = path.replace_extension("spv").string();
SHShaderData newShaderData{};
newShaderData.shaderType = type;
// spirv file
std::ifstream spirvFile(spirvFilepath, std::ios::ate | std::ios::binary);
// If we disable spirv validation, file is not checked
if (!recompileAnyway &&
spirvFile.is_open() &&
(checkSpirvOutdated ? (std::filesystem::last_write_time(spirvFilepath) > std::filesystem::last_write_time(fullGLSLPath)) : true))
{
// Get file size of binary
uint32_t fileSize = static_cast<uint32_t>(spirvFile.tellg());
// resize container to store binary
newShaderData.spirvBinary.resize(fileSize / sizeof(uint32_t));
// Read data from binary file to container
spirvFile.seekg(0);
spirvFile.read(reinterpret_cast<char*>(newShaderData.spirvBinary.data()), fileSize);
// close file
spirvFile.close();
}
else
{
// Use glslc to generate spirv file
newShaderData.spirvBinary = CompileToBinary(GetStringFromFile(fullGLSLPath.c_str()), spirvFilepath.c_str(), type);
std::ofstream binaryFile(spirvFilepath, std::ios::binary);
if (binaryFile.is_open())
{
// write all data to binary file
binaryFile.write(reinterpret_cast<const char*>(newShaderData.spirvBinary.data()), newShaderData.spirvBinary.size() * sizeof(uint32_t));
}
else
{
SHLOG_ERROR("Failed to modify spirv file. ");
return false;
}
}
newShaderData.name = glslFile;
newShaderData.id = id;
sourceLibrary.emplace_back(std::move (newShaderData));
return true;
}
/***************************************************************************/
/*!
\brief
Gets the entire source library.
\return
The container of binary data.
*/
/***************************************************************************/
std::vector<SHShaderData> const& SHShaderSourceLibrary::GetSourceLibrary(void) const noexcept
{
return sourceLibrary;
}
/***************************************************************************/
/*!
\brief
Move ctor for shader data.
\param rhs
The other shader data
*/
/***************************************************************************/
SHShaderData::SHShaderData(SHShaderData&& rhs) noexcept
: spirvBinary{ std::move (rhs.spirvBinary)}
, shaderType{std::move (rhs.shaderType)}
, name{ std::move (rhs.name)}
, id {std::move (rhs.id)}
{
}
/***************************************************************************/
/*!
\brief
Default ctor for shader data. Does nothing.
*/
/***************************************************************************/
SHShaderData::SHShaderData(void) noexcept
: spirvBinary{}
, shaderType{SH_SHADER_TYPE::VERTEX}
, name{ }
, id{ }
{
}
SHShaderData::SHShaderData(SHShaderData const& rhs) noexcept
: spirvBinary{rhs.spirvBinary}
, shaderType{ rhs.shaderType}
, name{rhs.name }
, id{rhs.id }
{
}
SHShaderData& SHShaderData::operator=(SHShaderData const& rhs) noexcept
{
if (this == &rhs)
return *this;
spirvBinary = rhs.spirvBinary;
shaderType = rhs.shaderType;
name = rhs.name;
id = rhs.id;
return *this;
}
SHShaderData& SHShaderData::operator=(SHShaderData&& rhs) noexcept
{
if (this == &rhs)
return *this;
spirvBinary = std::move(rhs.spirvBinary);
shaderType = std::move (rhs.shaderType);
name = std::move (rhs.name);
id = std::move (rhs.id);
return *this;
}
}

View File

@ -1,70 +0,0 @@
#ifndef SH_SHADER_SOURCE_LIBRARY_H
#define SH_SHADER_SOURCE_LIBRARY_H
#include <map>
#include "SHShaderType.h"
#include "shaderc/shaderc.hpp"
namespace SHADE
{
struct SHShaderData
{
/*-----------------------------------------------------------------------*/
/* MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
//! container storing the spirv binary
std::vector<uint32_t> spirvBinary;
//! For the compilation of the shader. Vulkan backend will use it too
SH_SHADER_TYPE shaderType;
//! Name of the shader file (without parent path)
std::string name;
//! id of the shader
uint32_t id;
SHShaderData(void) noexcept;
SHShaderData(SHShaderData const& rhs) noexcept;
SHShaderData(SHShaderData&& rhs) noexcept;
SHShaderData& operator= (SHShaderData&& rhs) noexcept;
SHShaderData& operator= (SHShaderData const& rhs) noexcept;
};
// TODO: This class is purely temporary and will be converted/changed when XQ implements his resource manager
class SHShaderSourceLibrary
{
private:
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
//! Stores all the source data. Take note that the source here is GLSL source and NOT binary data.
//! Binary data gets passed to the backend to convert to spirv.
std::vector<SHShaderData> sourceLibrary;
//! The directory where the shaders are located.
std::string shaderDirectory;
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
std::vector<uint32_t> CompileToBinary(std::string const& glslSource, char const* const spirvFilename, SH_SHADER_TYPE type, shaderc_optimization_level opLevel = shaderc_optimization_level_zero);
// TODO: Delete after file IO is implemented
std::string GetStringFromFile(char const* filePath) noexcept;
public:
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void Init (std::string directory) noexcept;
bool LoadShader (uint32_t id, std::string glslFile, SH_SHADER_TYPE type, bool checkSpirvOutdated = true, bool recompileAnyway = false) noexcept;
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
std::vector<SHShaderData> const& GetSourceLibrary(void) const noexcept;
};
}
#endif

View File

@ -1,14 +0,0 @@
#ifndef SH_SHADER_TYPE_H
#define SH_SHADER_TYPE_H
namespace SHADE
{
enum class SH_SHADER_TYPE
{
VERTEX,
FRAGMENT,
COMPUTE
};
}
#endif

View File

@ -214,66 +214,4 @@ namespace SHADE
SHLOG_ERROR("Image layouts are invalid. "); SHLOG_ERROR("Image layouts are invalid. ");
} }
} }
vk::Format SHTextureLibrary::ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear)
{
switch (format)
{
case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm:
return vk::Format::eBc1RgbaUnormBlock;
case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm_SRGB:
return vk::Format::eBc1RgbaSrgbBlock;
case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm_SRGB:
return isLinear ? vk::Format::eBc2UnormBlock : vk::Format::eBc2SrgbBlock;
case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm_SRGB:
return isLinear ? vk::Format::eBc3UnormBlock : vk::Format::eBc3SrgbBlock;
case tinyddsloader::DDSFile::DXGIFormat::BC5_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::BC5_SNorm:
return isLinear ? vk::Format::eBc5UnormBlock : vk::Format::eBc5SnormBlock;
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm_SRGB:
return isLinear ? vk::Format::eR8G8B8A8Unorm : vk::Format::eR8G8B8A8Srgb;
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_SNorm:
return vk::Format::eR8G8B8A8Snorm;
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm_SRGB:
return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8A8Srgb;
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm_SRGB:
return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8Srgb;
default:
throw std::runtime_error("Unsupported DDS format.");
}
//switch (format)
//{
//case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm:
//case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm_SRGB:
// return (isLinear) ? vk::Format::eR8G8B8A8Unorm : vk::Format::eR8G8B8A8Srgb;
//
//case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm:
//case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm_SRGB:
// return (isLinear) ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8A8Srgb;
//
//case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm:
//case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm_SRGB:
// return (isLinear) ? vk::Format::eBc1RgbaUnormBlock : vk::Format::eBc1RgbaSrgbBlock;
//case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm:
//case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm_SRGB:
// return (isLinear) ? vk::Format::eBc2UnormBlock : vk::Format::eBc2SrgbBlock;
//case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm:
//case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm_SRGB:
// return (isLinear) ? vk::Format::eBc3UnormBlock : vk::Format::eBc3SrgbBlock;
//case tinyddsloader::DDSFile::DXGIFormat::BC5_UNorm:
// return (isLinear) ? vk::Format::eBc5UnormBlock : vk::Format::eBc5SnormBlock;
//
//}
}
} }

View File

@ -14,8 +14,6 @@ of DigiPen Institute of Technology is prohibited.
// STL Includes // STL Includes
#include <vector> #include <vector>
// External Dependencies
#include "tinyddsloader.h"
// Project Includes // Project Includes
#include "Resource/SHHandle.h" #include "Resource/SHHandle.h"
#include "Resource/SHResourceLibrary.h" #include "Resource/SHResourceLibrary.h"
@ -169,6 +167,5 @@ namespace SHADE
/* Helper Functions */ /* Helper Functions */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
void preparePipelineBarriers(vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::PipelineStageFlagBits& srcStage, vk::PipelineStageFlagBits& dstStage, std::vector<vk::ImageMemoryBarrier>& barriers); void preparePipelineBarriers(vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::PipelineStageFlagBits& srcStage, vk::PipelineStageFlagBits& dstStage, std::vector<vk::ImageMemoryBarrier>& barriers);
vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear);
}; };
} }

View File

@ -244,7 +244,15 @@ namespace SHADE
} }
// Add subpass to container and create mapping for it // 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); subpassIndexing.try_emplace(subpassName, static_cast<uint32_t>(subpasses.size()) - 1u);
Handle<SHSubpass> subpass = subpasses.back(); Handle<SHSubpass> subpass = subpasses.back();
subpass->Init(*graphStorage->resourceManager); 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 } : resourceAttachmentMapping{ mapping }
, parentNode{ parent } , parentNode{ parent }
, subpassIndex{ index } , subpassIndex{ index }
@ -38,6 +38,7 @@ namespace SHADE
, colorReferences{} , colorReferences{}
, depthReferences{} , depthReferences{}
, inputReferences{} , inputReferences{}
, name { name }
, graphStorage{ renderGraphStorage } , graphStorage{ renderGraphStorage }
, inputImageDescriptors {SHGraphicsConstants::NUM_FRAME_BUFFERS} , inputImageDescriptors {SHGraphicsConstants::NUM_FRAME_BUFFERS}
{ {
@ -411,4 +412,8 @@ namespace SHADE
return parentNode->GetResource(attachmentReference)->GetResourceFormat(); 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 //! are always the last things drawn, so DO NOT USE THIS FUNCTIONALITY FOR ANYTHING
//! COMPLEX. //! COMPLEX.
std::vector<std::function<void(Handle<SHVkCommandBuffer>&)>> exteriorDrawCalls; std::vector<std::function<void(Handle<SHVkCommandBuffer>&)>> exteriorDrawCalls;
/// For identifying subpasses
std::string name;
public: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */ /* 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(SHSubpass&& rhs) noexcept;
SHSubpass& operator=(SHSubpass&& rhs) noexcept; SHSubpass& operator=(SHSubpass&& rhs) noexcept;
@ -117,6 +119,7 @@ namespace SHADE
Handle<SHSuperBatch> GetSuperBatch(void) const noexcept; Handle<SHSuperBatch> GetSuperBatch(void) const noexcept;
std::vector<vk::AttachmentReference> const& GetColorAttachmentReferences (void) const noexcept; std::vector<vk::AttachmentReference> const& GetColorAttachmentReferences (void) const noexcept;
vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept; vk::Format GetFormatFromAttachmentReference (uint32_t attachmentReference) const noexcept;
const std::string& GetName() const;
friend class SHRenderGraphNode; friend class SHRenderGraphNode;
friend class SHRenderGraph; friend class SHRenderGraph;

View File

@ -14,6 +14,7 @@ namespace SHADE
return; return;
} }
variables.emplace_back(std::move(newVariable)); variables.emplace_back(std::move(newVariable));
variableNames.emplace_back(name);
variableIndexing.try_emplace(std::move(name), static_cast<uint32_t>(variables.size() - 1)); variableIndexing.try_emplace(std::move(name), static_cast<uint32_t>(variables.size() - 1));
} }
@ -41,6 +42,19 @@ namespace SHADE
return variableIndexing.at(variableName); 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 SHShaderBlockInterface::SHShaderBlockInterface(void) noexcept
: bytesRequired{ 0 } : bytesRequired{ 0 }
{} {}

View File

@ -12,13 +12,24 @@ namespace SHADE
public: public:
struct Variable struct Variable
{ {
enum class Type
{
OTHER,
FLOAT,
INT,
VECTOR2,
VECTOR3,
VECTOR4
};
//! Offset of the variable in the block //! Offset of the variable in the block
uint32_t offset; uint32_t offset;
Type type;
}; };
private: private:
//! containers of variable information //! containers of variable information
std::vector<Variable> variables; std::vector<Variable> variables;
std::vector<std::string> variableNames;
std::unordered_map<std::string, uint32_t> variableIndexing; std::unordered_map<std::string, uint32_t> variableIndexing;
//! bytes required by the block (includes padding). This variable is required //! 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 (std::string const& variableName) const noexcept;
Variable const* const GetVariable(uint32_t index) const noexcept; Variable const* const GetVariable(uint32_t index) const noexcept;
uint32_t GetVariableIndex(std::string const& variableName) const; 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 */ /* CTORS AND DTORS */

View File

@ -97,17 +97,45 @@ namespace SHADE
switch (member.type_description->op) switch (member.type_description->op)
{ {
case SpvOp::SpvOpTypeFloat: 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); biggestAlignment = std::max (biggestAlignment, 4u);
break; break;
case SpvOp::SpvOpTypeVector: 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) if (dim == 3)
dim = 4; dim = 4;
biggestAlignment = std::max (biggestAlignment, dim * member.type_description->traits.numeric.scalar.width / 8); biggestAlignment = std::max (biggestAlignment, dim * member.type_description->traits.numeric.scalar.width / 8);
break; break;
case SpvOp::SpvOpTypeInt: 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); biggestAlignment = std::max(biggestAlignment, 4u);
break; break;
case SpvOp::SpvOpTypeStruct: case SpvOp::SpvOpTypeStruct:

View File

@ -27,10 +27,9 @@ namespace SHADE
/* Getter Function Definitions */ /* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHShape::Type SHShape::GetType() const SHShape::Type SHShape::GetType() const noexcept
{ {
return type; return type;
} }
} // namespace SHADE } // namespace SHADE

View File

@ -63,7 +63,7 @@ namespace SHADE
/* Getter Functions */ /* Getter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] Type GetType() const; [[nodiscard]] Type GetType () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */

View File

@ -61,9 +61,9 @@ namespace SHADE
void SHTransformSystem::Init() void SHTransformSystem::Init()
{ {
std::shared_ptr thisReceiver { std::make_shared<SHEventReceiverSpec<SHTransformSystem>>(this, &SHTransformSystem::ChangeParent) }; const std::shared_ptr CHANGE_PARENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHTransformSystem>>(this, &SHTransformSystem::ChangeParent) };
ReceiverPtr receiver = std::dynamic_pointer_cast<SHEventReceiver>(thisReceiver); const ReceiverPtr CHANGE_PARENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(CHANGE_PARENT_RECEIVER);
SHEventManager::SubscribeTo(SH_SCENEGRAPH_CHANGE_PARENT_EVENT, receiver); SHEventManager::SubscribeTo(SH_SCENEGRAPH_CHANGE_PARENT_EVENT, CHANGE_PARENT_RECEIVER_PTR);
} }
void SHTransformSystem::Exit() void SHTransformSystem::Exit()
@ -75,50 +75,6 @@ namespace SHADE
/* Private Function Member Definitions */ /* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHEventHandle SHTransformSystem::ChangeParent(SHEventPtr changeParentEvent)
{
const auto& eventData = reinterpret_cast<const SHEventSpec<SHSceneGraphChangeParentEvent>*>(changeParentEvent.get());
auto* node = eventData->data->node;
auto* tf = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID());
// Recompute local transform and store localToWorld Matrix
SHMatrix localToWorld = SHMatrix::Identity;
SHMatrix worldToLocal = SHMatrix::Identity;
auto* newParent = eventData->data->newParent;
const auto* PARENT_TF = SHComponentManager::GetComponent_s<SHTransformComponent>(newParent->GetEntityID());
if (PARENT_TF != nullptr) // Not the root
{
localToWorld = PARENT_TF->GetTRS();
worldToLocal = SHMatrix::Inverse(localToWorld);
}
// Maintain World Transform and recompute Local Transform
// Compute Local Position
tf->local.position = SHVec3::Transform(tf->world.position, worldToLocal);
tf->localRotation = tf->worldRotation;
tf->local.scale = tf->world.scale;
if (PARENT_TF != nullptr)
{
// Compute Local Rotation
tf->localRotation -= PARENT_TF->GetLocalRotation();
// Compute Local Scale
tf->local.scale /= PARENT_TF->GetLocalScale();
}
tf->local.trs = localToWorld;
// Propagate maintaining world transform down the branch
UpdateChildrenLocalTransforms(node);
return eventData->handle;
}
void SHTransformSystem::UpdateChildrenLocalTransforms(SHSceneNode* node) void SHTransformSystem::UpdateChildrenLocalTransforms(SHSceneNode* node)
{ {
// Structure is similar to update entity, albeit without a queue to do being a forced update // Structure is similar to update entity, albeit without a queue to do being a forced update
@ -300,4 +256,49 @@ namespace SHADE
tf.world.ComputeTRS(); tf.world.ComputeTRS();
} }
SHEventHandle SHTransformSystem::ChangeParent(SHEventPtr changeParentEvent)
{
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHSceneGraphChangeParentEvent>*>(changeParentEvent.get());
auto* node = EVENT_DATA->data->node;
auto* tf = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID());
// Recompute local transform and store localToWorld Matrix
SHMatrix localToWorld = SHMatrix::Identity;
SHMatrix worldToLocal = SHMatrix::Identity;
auto* newParent = EVENT_DATA->data->newParent;
const auto* PARENT_TF = SHComponentManager::GetComponent_s<SHTransformComponent>(newParent->GetEntityID());
if (PARENT_TF != nullptr) // Not the root
{
localToWorld = PARENT_TF->GetTRS();
worldToLocal = SHMatrix::Inverse(localToWorld);
}
// Maintain World Transform and recompute Local Transform
// Compute Local Position
tf->local.position = SHVec3::Transform(tf->world.position, worldToLocal);
tf->localRotation = tf->worldRotation;
tf->local.scale = tf->world.scale;
if (PARENT_TF != nullptr)
{
// Compute Local Rotation
tf->localRotation -= PARENT_TF->GetLocalRotation();
// Compute Local Scale
tf->local.scale /= PARENT_TF->GetLocalScale();
}
tf->local.trs = localToWorld;
// Propagate maintaining world transform down the branch
UpdateChildrenLocalTransforms(node);
return EVENT_DATA->handle;
}
} // namespace SHADE } // namespace SHADE

View File

@ -11,9 +11,9 @@
#pragma once #pragma once
// Project Headers // Project Headers
#include "SHTransformComponent.h"
#include "Scene/SHSceneGraph.h"
#include "ECS_Base/System/SHSystemRoutine.h" #include "ECS_Base/System/SHSystemRoutine.h"
#include "Scene/SHSceneGraph.h"
#include "SHTransformComponent.h"
namespace SHADE namespace SHADE
{ {
@ -53,17 +53,6 @@ namespace SHADE
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
TransformPostLogicUpdate (); TransformPostLogicUpdate ();
~TransformPostLogicUpdate () = default;
TransformPostLogicUpdate (const TransformPostLogicUpdate&) = delete;
TransformPostLogicUpdate (TransformPostLogicUpdate&&) = delete;
/*-------------------------------------------------------------------------------*/
/* Operator Overloads */
/*-------------------------------------------------------------------------------*/
TransformPostLogicUpdate& operator= (const TransformPostLogicUpdate&) = delete;
TransformPostLogicUpdate& operator= (TransformPostLogicUpdate&&) = delete;
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */
@ -80,17 +69,6 @@ namespace SHADE
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
TransformPostPhysicsUpdate (); TransformPostPhysicsUpdate ();
~TransformPostPhysicsUpdate () = default;
TransformPostPhysicsUpdate (const TransformPostPhysicsUpdate&) = delete;
TransformPostPhysicsUpdate (TransformPostPhysicsUpdate&&) = delete;
/*-------------------------------------------------------------------------------*/
/* Operator Overloads */
/*-------------------------------------------------------------------------------*/
TransformPostPhysicsUpdate& operator= (const TransformPostPhysicsUpdate&) = delete;
TransformPostPhysicsUpdate& operator= (TransformPostPhysicsUpdate&&) = delete;
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */
@ -111,11 +89,14 @@ namespace SHADE
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHEventHandle ChangeParent (SHEventPtr changeParentEvent);
static void UpdateChildrenLocalTransforms (SHSceneNode* node); static void UpdateChildrenLocalTransforms (SHSceneNode* node);
static void UpdateEntity (const SHSceneNode* node, bool clearDirtyFlag); static void UpdateEntity (const SHSceneNode* node, bool clearDirtyFlag);
static void UpdateTransform (SHTransformComponent& tf, const SHTransformComponent* parent = nullptr); static void UpdateTransform (SHTransformComponent& tf, const SHTransformComponent* parent = nullptr);
// Event Handlers
SHEventHandle ChangeParent (SHEventPtr changeParentEvent);
}; };

View File

@ -26,7 +26,6 @@ namespace SHADE
SHColliderComponent::SHColliderComponent() noexcept SHColliderComponent::SHColliderComponent() noexcept
: system { nullptr } : system { nullptr }
, colliders {}
{} {}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -59,7 +58,7 @@ namespace SHADE
if (index < 0 || static_cast<size_t>(index) >= colliders.size()) if (index < 0 || static_cast<size_t>(index) >= colliders.size())
throw std::invalid_argument("Out-of-range access!"); throw std::invalid_argument("Out-of-range access!");
return colliders[index].first; return colliders[index];
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -69,44 +68,29 @@ namespace SHADE
void SHColliderComponent::OnCreate() void SHColliderComponent::OnCreate()
{ {
system = SHSystemManager::GetSystem<SHPhysicsSystem>(); system = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (!system)
{
SHLOG_ERROR("Physics system does not exist, Collider Component not added!")
return;
}
system->AddCollider(GetEID());
} }
void SHColliderComponent::OnDestroy() void SHColliderComponent::OnDestroy()
{ {
if (!system)
{
SHLOG_ERROR("Physics system does not exist, unable to remove Collider component!")
return;
}
system->RemoveCollider(GetEID());
} }
SHBoundingBox* SHColliderComponent::AddBoundingBox(const SHVec3& halfExtents, const SHVec3& posOffset) noexcept SHBoundingBox* SHColliderComponent::AddBoundingBox(const SHVec3& halfExtents, const SHVec3& posOffset) noexcept
{ {
const auto TYPE = SHCollider::Type::BOX;
auto boxPair = std::make_pair(SHCollider{TYPE}, true);
auto& collider = colliders.emplace_back(boxPair).first;
const auto* tf = SHComponentManager::GetComponent<SHTransformComponent>(GetEID());
collider.SetPositionOffset(posOffset);
collider.SetAsBoundingBox(tf->GetWorldScale() * halfExtents);
if (!system) if (!system)
{ {
SHLOG_ERROR("Physics system does not exist, unable to add Box Collider!") SHLOG_ERROR("Physics system does not exist, unable to add Box Collider!")
return nullptr; return nullptr;
} }
static constexpr auto TYPE = SHCollider::Type::BOX;
auto& collider = colliders.emplace_back(SHCollider{ GetEID(), TYPE });
collider.entityID = GetEID();
collider.SetPositionOffset(posOffset);
collider.SetBoundingBox(halfExtents);
// Notify Physics System // Notify Physics System
system->AddCollisionShape(GetEID(), &collider); system->AddCollisionShape(GetEID(), &collider);
@ -115,25 +99,20 @@ namespace SHADE
SHBoundingSphere* SHColliderComponent::AddBoundingSphere(float radius, const SHVec3& posOffset) noexcept SHBoundingSphere* SHColliderComponent::AddBoundingSphere(float radius, const SHVec3& posOffset) noexcept
{ {
const auto TYPE = SHCollider::Type::SPHERE;
auto spherePair = std::make_pair(SHCollider{ TYPE }, true);
auto& collider = colliders.emplace_back(spherePair).first;
const auto* tf = SHComponentManager::GetComponent<SHTransformComponent>(GetEID());
collider.SetPositionOffset(posOffset);
const SHVec3 TF_WORLD_SCALE = tf->GetWorldScale();
const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z });
collider.SetAsBoundingSphere(MAX_SCALE * 0.5f);
if (!system) if (!system)
{ {
SHLOG_ERROR("Physics system does not exist, unable to add Sphere Collider!") SHLOG_ERROR("Physics system does not exist, unable to add Sphere Collider!")
return nullptr; return nullptr;
} }
static constexpr auto TYPE = SHCollider::Type::SPHERE;
auto& collider = colliders.emplace_back(SHCollider{ GetEID(), TYPE });
collider.entityID = GetEID();
collider.SetPositionOffset(posOffset);
collider.SetBoundingSphere(radius);
// Notify Physics System // Notify Physics System
system->AddCollisionShape(GetEID(), &collider); system->AddCollisionShape(GetEID(), &collider);

View File

@ -43,8 +43,7 @@ namespace SHADE
/* Type Definitions */ /* Type Definitions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
using ColliderDirtyPair = std::pair<SHCollider, bool>; using Colliders = std::vector<SHCollider>;
using Colliders = std::vector<ColliderDirtyPair>;
public: public:

View File

@ -10,6 +10,9 @@
#include <SHpch.h> #include <SHpch.h>
// External Dependencies
#include <reactphysics3d/reactphysics3d.h>
// Primary Header // Primary Header
#include "SHRigidBodyComponent.h" #include "SHRigidBodyComponent.h"
@ -28,11 +31,10 @@ namespace SHADE
, flags { 0 } , flags { 0 }
, dirtyFlags { 0 } , dirtyFlags { 0 }
, interpolate { true } , interpolate { true }
, system { nullptr } , rp3dBody { nullptr }
, mass { 1.0f } , mass { 1.0f }
, drag { 0.01f } , drag { 0.01f }
, angularDrag { 0.01f } , angularDrag { 0.01f }
{ {
// Set default flags: Gravity & Sleeping enabled // Set default flags: Gravity & Sleeping enabled
flags |= 1U << 0; flags |= 1U << 0;
@ -161,7 +163,13 @@ namespace SHADE
void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept
{ {
constexpr int FLAG_POS = 0; static constexpr int FLAG_POS = 0;
if (type != Type::DYNAMIC)
{
SHLOG_WARNING("Cannot enable gravity of a non-dynamic object {}", GetEID())
return;
}
dirtyFlags |= 1U << FLAG_POS; dirtyFlags |= 1U << FLAG_POS;
enableGravity ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); enableGravity ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@ -169,7 +177,13 @@ namespace SHADE
void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept
{ {
constexpr int FLAG_POS = 1; static constexpr int FLAG_POS = 1;
if (type != Type::DYNAMIC)
{
SHLOG_WARNING("Cannot enable sleeping of a non-dynamic object {}", GetEID())
return;
}
dirtyFlags |= 1U << 1; dirtyFlags |= 1U << 1;
isAllowedToSleep ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); isAllowedToSleep ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@ -177,7 +191,13 @@ namespace SHADE
void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept
{ {
constexpr int FLAG_POS = 2; static constexpr int FLAG_POS = 2;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 2; dirtyFlags |= 1U << 2;
freezePositionX ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); freezePositionX ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@ -185,7 +205,13 @@ namespace SHADE
void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept
{ {
constexpr int FLAG_POS = 3; static constexpr int FLAG_POS = 3;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 2; dirtyFlags |= 1U << 2;
freezePositionY ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); freezePositionY ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@ -193,7 +219,13 @@ namespace SHADE
void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept
{ {
constexpr int FLAG_POS = 4; static constexpr int FLAG_POS = 4;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 2; dirtyFlags |= 1U << 2;
freezePositionZ ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); freezePositionZ ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@ -201,7 +233,13 @@ namespace SHADE
void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept
{ {
constexpr int FLAG_POS = 5; static constexpr int FLAG_POS = 5;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 3; dirtyFlags |= 1U << 3;
freezeRotationX ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); freezeRotationX ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@ -209,7 +247,13 @@ namespace SHADE
void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept
{ {
constexpr int FLAG_POS = 6; static constexpr int FLAG_POS = 6;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 3; dirtyFlags |= 1U << 3;
freezeRotationY ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); freezeRotationY ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@ -217,7 +261,13 @@ namespace SHADE
void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept
{ {
constexpr int FLAG_POS = 7; static constexpr int FLAG_POS = 7;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 3; dirtyFlags |= 1U << 3;
freezeRotationZ ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS); freezeRotationZ ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@ -230,30 +280,60 @@ namespace SHADE
void SHRigidBodyComponent::SetMass(float newMass) noexcept void SHRigidBodyComponent::SetMass(float newMass) noexcept
{ {
if (type != Type::DYNAMIC)
{
SHLOG_WARNING("Cannot set mass of a non-dynamic object {}", GetEID())
return;
}
dirtyFlags |= 1U << 5; dirtyFlags |= 1U << 5;
mass = newMass; mass = newMass;
} }
void SHRigidBodyComponent::SetDrag(float newDrag) noexcept void SHRigidBodyComponent::SetDrag(float newDrag) noexcept
{ {
if (type != Type::DYNAMIC)
{
SHLOG_WARNING("Cannot set drag of a non-dynamic object {}", GetEID())
return;
}
dirtyFlags |= 1U << 6; dirtyFlags |= 1U << 6;
drag = newDrag; drag = newDrag;
} }
void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept
{ {
if (type != Type::DYNAMIC)
{
SHLOG_WARNING("Cannot set angular drag of a non-dynamic object {}", GetEID())
return;
}
dirtyFlags |= 1U << 7; dirtyFlags |= 1U << 7;
angularDrag = newAngularDrag; angularDrag = newAngularDrag;
} }
void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept
{ {
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set linear velocity of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 8; dirtyFlags |= 1U << 8;
linearVelocity = newLinearVelocity; linearVelocity = newLinearVelocity;
} }
void SHRigidBodyComponent::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept void SHRigidBodyComponent::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept
{ {
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set angular velocity of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 9; dirtyFlags |= 1U << 9;
angularVelocity = newAngularVelocity; angularVelocity = newAngularVelocity;
} }
@ -262,125 +342,92 @@ namespace SHADE
/* Public Function Member Definitions */ /* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHRigidBodyComponent::OnCreate()
{
system = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (!system)
{
SHLOG_ERROR("Physics system does not exist, Rigid Body Component not added!")
return;
}
// Notify Physics System
system->AddRigidBody(GetEID());
}
void SHRigidBodyComponent::OnDestroy()
{
// Notify Physics System
if (!system)
{
SHLOG_ERROR("Physics system does not exist, unable to remove Rigid Body Component!")
return;
}
system->RemoveRigidBody(GetEID());
}
void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept
{ {
if (!system) if (rp3dBody == nullptr)
{ {
SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
return; return;
} }
// Notify Physics Systems rp3dBody->applyWorldForceAtCenterOfMass(force);
system->AddForce(GetEID(), force);
} }
void SHRigidBodyComponent::AddForceAtLocalPos(const SHVec3& force, const SHVec3& localPos) const noexcept void SHRigidBodyComponent::AddForceAtLocalPos(const SHVec3& force, const SHVec3& localPos) const noexcept
{ {
if (!system) if (rp3dBody == nullptr)
{ {
SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
return; return;
} }
// Notify Physics Systems rp3dBody->applyWorldForceAtLocalPosition(force, localPos);
system->AddForceAtLocalPos(GetEID(), force, localPos);
} }
void SHRigidBodyComponent::AddForceAtWorldPos(const SHVec3& force, const SHVec3& worldPos) const noexcept void SHRigidBodyComponent::AddForceAtWorldPos(const SHVec3& force, const SHVec3& worldPos) const noexcept
{ {
if (!system) if (rp3dBody == nullptr)
{ {
SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
return; return;
} }
// Notify Physics Systems rp3dBody->applyWorldForceAtWorldPosition(force, worldPos);
system->AddForceAtWorldPos(GetEID(), force, worldPos);
} }
void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept
{ {
if (!system) if (rp3dBody == nullptr)
{ {
SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
return; return;
} }
// Notify Physics Systems rp3dBody->applyLocalForceAtCenterOfMass(relativeForce);
system->AddRelativeForce(GetEID(), force);
} }
void SHRigidBodyComponent::AddRelativeForceAtLocalPos(const SHVec3& relativeForce, const SHVec3& localPos) const noexcept void SHRigidBodyComponent::AddRelativeForceAtLocalPos(const SHVec3& relativeForce, const SHVec3& localPos) const noexcept
{ {
if (!system) if (rp3dBody == nullptr)
{ {
SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
return; return;
} }
// Notify Physics Systems rp3dBody->applyLocalForceAtLocalPosition(relativeForce, localPos);
system->AddRelativeForceAtLocalPos(GetEID(), force, localPos);
} }
void SHRigidBodyComponent::AddRelativeForceAtWorldPos(const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept void SHRigidBodyComponent::AddRelativeForceAtWorldPos(const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept
{ {
if (!system) if (rp3dBody == nullptr)
{ {
SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
return; return;
} }
// Notify Physics Systems rp3dBody->applyLocalForceAtWorldPosition(relativeForce, worldPos);
system->AddRelativeForceAtWorldPos(GetEID(), force, worldPos);
} }
void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept
{ {
if (!system) if (rp3dBody == nullptr)
{ {
SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
return; return;
} }
// Notify Physics Systems rp3dBody->applyWorldTorque(torque);
system->AddTorque(GetEID(), torque);
} }
void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept
{ {
if (!system) if (rp3dBody == nullptr)
{ {
SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!") SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
return; return;
} }
// Notify Physics Systems rp3dBody->applyLocalTorque(relativeTorque);
system->AddRelativeTorque(GetEID(), relativeTorque);
} }
} // namespace SHADE } // namespace SHADE

View File

@ -22,6 +22,11 @@
// class SHPhysicsSystem; // class SHPhysicsSystem;
//} //}
namespace reactphysics3d
{
class RigidBody;
}
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -125,9 +130,6 @@ namespace SHADE
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void OnCreate () override;
void OnDestroy () override;
void AddForce (const SHVec3& force) const noexcept; void AddForce (const SHVec3& force) const noexcept;
void AddForceAtLocalPos (const SHVec3& force, const SHVec3& localPos) const noexcept; void AddForceAtLocalPos (const SHVec3& force, const SHVec3& localPos) const noexcept;
void AddForceAtWorldPos (const SHVec3& force, const SHVec3& worldPos) const noexcept; void AddForceAtWorldPos (const SHVec3& force, const SHVec3& worldPos) const noexcept;
@ -155,7 +157,7 @@ namespace SHADE
uint16_t dirtyFlags; uint16_t dirtyFlags;
bool interpolate; bool interpolate;
SHPhysicsSystem* system; reactphysics3d::RigidBody* rp3dBody;
float mass; float mass;
float drag; float drag;
@ -167,8 +169,6 @@ namespace SHADE
SHVec3 torque; SHVec3 torque;
SHVec3 angularVelocity; SHVec3 angularVelocity;
// TODO(Diren): Once quaternions have replaced euler angles in transforms, store it for the rigidbody.
SHVec3 position; SHVec3 position;
SHQuaternion orientation; SHQuaternion orientation;

View File

@ -15,6 +15,8 @@
// Project Headers // Project Headers
#include "Math/Geometry/SHBoundingBox.h" #include "Math/Geometry/SHBoundingBox.h"
#include "Math/Geometry/SHBoundingSphere.h" #include "Math/Geometry/SHBoundingSphere.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Math/SHMathHelpers.h"
namespace SHADE namespace SHADE
{ {
@ -22,22 +24,24 @@ namespace SHADE
/* Constructors & Destructor Definitions */ /* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHCollider::SHCollider(Type colliderType) SHCollider::SHCollider(EntityID eid, Type colliderType, const SHPhysicsMaterial& physicsMaterial)
: type { colliderType } : type { colliderType }
, entityID { eid }
, isTrigger { false } , isTrigger { false }
, dirty { true } , dirty { true }
, shape { nullptr } , shape { nullptr }
, material { physicsMaterial }
{ {
switch (type) switch (type)
{ {
case Type::BOX: case Type::BOX:
{ {
SetAsBoundingBox(SHVec3::One); shape = new SHBoundingBox{ SHVec3::Zero, SHVec3::One };
break; break;
} }
case Type::SPHERE: case Type::SPHERE:
{ {
SetAsBoundingSphere(1.0f); shape = new SHBoundingSphere{ SHVec3::Zero, 0.5f };
break; break;
} }
default: break; default: break;
@ -46,19 +50,27 @@ namespace SHADE
SHCollider::SHCollider(const SHCollider& rhs) noexcept SHCollider::SHCollider(const SHCollider& rhs) noexcept
: type { rhs.type} : type { rhs.type}
, entityID { rhs.entityID }
, isTrigger { rhs.isTrigger } , isTrigger { rhs.isTrigger }
, dirty { true } , dirty { true }
, shape { rhs.shape } , shape { nullptr }
, material { rhs.material }
, positionOffset { rhs.positionOffset } , positionOffset { rhs.positionOffset }
{} {
CopyShape(rhs.shape);
}
SHCollider::SHCollider(SHCollider&& rhs) noexcept SHCollider::SHCollider(SHCollider&& rhs) noexcept
: type { rhs.type} : type { rhs.type}
, entityID { rhs.entityID }
, isTrigger { rhs.isTrigger } , isTrigger { rhs.isTrigger }
, dirty { true } , dirty { true }
, shape { rhs.shape } , shape { nullptr }
, material { rhs.material }
, positionOffset { rhs.positionOffset } , positionOffset { rhs.positionOffset }
{} {
CopyShape(rhs.shape);
}
SHCollider::~SHCollider() noexcept SHCollider::~SHCollider() noexcept
{ {
@ -75,22 +87,30 @@ namespace SHADE
return *this; return *this;
type = rhs.type; type = rhs.type;
entityID = rhs.entityID;
isTrigger = rhs.isTrigger; isTrigger = rhs.isTrigger;
dirty = true; dirty = true;
shape = rhs.shape; material = rhs.material;
positionOffset = rhs.positionOffset; positionOffset = rhs.positionOffset;
delete shape;
CopyShape(rhs.shape);
return *this; return *this;
} }
SHCollider& SHCollider::operator=(SHCollider&& rhs) noexcept SHCollider& SHCollider::operator=(SHCollider&& rhs) noexcept
{ {
type = rhs.type; type = rhs.type;
entityID = rhs.entityID;
isTrigger = rhs.isTrigger; isTrigger = rhs.isTrigger;
dirty = true; dirty = true;
shape = rhs.shape; material = rhs.material;
positionOffset = rhs.positionOffset; positionOffset = rhs.positionOffset;
delete shape;
CopyShape(rhs.shape);
return *this; return *this;
} }
@ -115,19 +135,22 @@ namespace SHADE
float SHCollider::GetFriction() const noexcept float SHCollider::GetFriction() const noexcept
{ {
// TODO(Diren): Fix after implementing materials return material.GetFriction();
return 0.0f;
} }
float SHCollider::GetBounciness() const noexcept float SHCollider::GetBounciness() const noexcept
{ {
// TODO(Diren): Fix after implementing materials return material.GetBounciness();
return 0.0f;
} }
float SHCollider::GetDensity() const noexcept float SHCollider::GetDensity() const noexcept
{ {
// TODO(Diren): Fix after implementing materials return material.GetDensity();
return 0.0f; }
const SHPhysicsMaterial& SHCollider::GetMaterial() const noexcept
{
return material;
} }
const SHVec3& SHCollider::GetPositionOffset() const noexcept const SHVec3& SHCollider::GetPositionOffset() const noexcept
@ -145,22 +168,60 @@ namespace SHADE
/* Setter Function Definitions */ /* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHCollider::SetAsBoundingBox(const SHVec3& halfExtents) void SHCollider::SetBoundingBox(const SHVec3& halfExtents)
{ {
dirty = true; dirty = true;
// Set the half extents relative to transform
SHVec3 worldHalfExtents = halfExtents;
const auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
if (transformComponent != nullptr)
worldHalfExtents *= (transformComponent->GetWorldScale() * 0.5f);
if (type == Type::BOX)
{
auto* box = reinterpret_cast<SHBoundingBox*>(shape);
box->SetHalfExtents(worldHalfExtents);
}
else
{
type = Type::BOX; type = Type::BOX;
delete shape; delete shape;
shape = new SHBoundingBox{ positionOffset, halfExtents }; shape = new SHBoundingBox{ positionOffset, worldHalfExtents };
}
} }
void SHCollider::SetAsBoundingSphere(float radius) void SHCollider::SetBoundingSphere(float radius)
{ {
dirty = true; dirty = true;
// Set the radius relative to transform
float worldRadius = radius;
const auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
if (transformComponent != nullptr)
{
const SHVec3 TF_WORLD_SCALE = transformComponent->GetWorldScale();
const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z });
worldRadius *= MAX_SCALE;
}
if (type == Type::SPHERE)
{
auto* sphere = reinterpret_cast<SHBoundingSphere*>(shape);
sphere->SetRadius(worldRadius);
}
else
{
type = Type::SPHERE; type = Type::SPHERE;
delete shape; delete shape;
shape = new SHBoundingSphere{ positionOffset, radius }; shape = new SHBoundingSphere{ positionOffset, worldRadius };
}
} }
void SHCollider::SetIsTrigger(bool trigger) noexcept void SHCollider::SetIsTrigger(bool trigger) noexcept
@ -172,23 +233,74 @@ namespace SHADE
void SHCollider::SetFriction(float friction) noexcept void SHCollider::SetFriction(float friction) noexcept
{ {
dirty = true; dirty = true;
material.SetFriction(friction);
} }
void SHCollider::SetBounciness(float bounciness) noexcept void SHCollider::SetBounciness(float bounciness) noexcept
{ {
dirty = true; dirty = true;
material.SetBounciness(bounciness);
} }
void SHCollider::SetDensity(float density) noexcept void SHCollider::SetDensity(float density) noexcept
{ {
dirty = true; dirty = true;
material.SetDensity(density);
}
void SHCollider::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept
{
dirty = true;
material = newMaterial;
} }
void SHCollider::SetPositionOffset(const SHVec3& posOffset) noexcept void SHCollider::SetPositionOffset(const SHVec3& posOffset) noexcept
{ {
dirty = true; dirty = true;
positionOffset = posOffset; positionOffset = posOffset;
switch (type)
{
case Type::BOX:
{
reinterpret_cast<SHBoundingBox*>(shape)->SetCenter(positionOffset);
break;
} }
case Type::SPHERE:
{
reinterpret_cast<SHBoundingSphere*>(shape)->SetCenter(positionOffset);
break;
}
default: break;
}
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHCollider::CopyShape(const SHShape* rhs)
{
switch (type)
{
case Type::BOX:
{
const auto* RHS_BOX = reinterpret_cast<const SHBoundingBox*>(rhs);
shape = new SHBoundingBox{ positionOffset, RHS_BOX->GetHalfExtents() };
break;
}
case Type::SPHERE:
{
const auto* RHS_SPHERE = reinterpret_cast<const SHBoundingSphere*>(rhs);
shape = new SHBoundingSphere{ positionOffset, RHS_SPHERE->GetRadius() };
break;
}
default: break;
}
}
} // namespace SHADE } // namespace SHADE
RTTR_REGISTRATION RTTR_REGISTRATION
@ -205,5 +317,4 @@ RTTR_REGISTRATION
registration::class_<SHCollider>("Collider") registration::class_<SHCollider>("Collider")
.property("Position Offset", &SHCollider::GetPositionOffset, &SHCollider::SetPositionOffset); .property("Position Offset", &SHCollider::GetPositionOffset, &SHCollider::SetPositionOffset);
// TODO(Diren): Add Physics Materials
} }

View File

@ -13,8 +13,10 @@
#include <rttr/registration> #include <rttr/registration>
// Project Headers // Project Headers
#include "ECS_Base/Entity/SHEntity.h"
#include "Math/Geometry/SHShape.h" #include "Math/Geometry/SHShape.h"
#include "Math/SHQuaternion.h" #include "Math/SHQuaternion.h"
#include "SHPhysicsMaterial.h"
namespace SHADE namespace SHADE
{ {
@ -24,6 +26,15 @@ namespace SHADE
class SH_API SHCollider class SH_API SHCollider
{ {
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHColliderComponent;
friend class SHPhysicsObject;
public: public:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
@ -40,7 +51,7 @@ namespace SHADE
/* Constructors & Destructor */ /* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHCollider (Type colliderType = Type::BOX); SHCollider (EntityID eid, Type colliderType = Type::BOX, const SHPhysicsMaterial& physicsMaterial = SHPhysicsMaterial::DEFAULT);
SHCollider (const SHCollider& rhs) noexcept; SHCollider (const SHCollider& rhs) noexcept;
SHCollider (SHCollider&& rhs) noexcept; SHCollider (SHCollider&& rhs) noexcept;
@ -66,6 +77,7 @@ namespace SHADE
[[nodiscard]] float GetFriction () const noexcept; [[nodiscard]] float GetFriction () const noexcept;
[[nodiscard]] float GetBounciness () const noexcept; [[nodiscard]] float GetBounciness () const noexcept;
[[nodiscard]] float GetDensity () const noexcept; [[nodiscard]] float GetDensity () const noexcept;
[[nodiscard]] const SHPhysicsMaterial& GetMaterial () const noexcept;
[[nodiscard]] const SHVec3& GetPositionOffset () const noexcept; [[nodiscard]] const SHVec3& GetPositionOffset () const noexcept;
@ -75,13 +87,14 @@ namespace SHADE
/* Setter Functions */ /* Setter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SetAsBoundingBox (const SHVec3& halfExtents); void SetBoundingBox (const SHVec3& halfExtents);
void SetAsBoundingSphere (float radius); void SetBoundingSphere (float radius);
void SetIsTrigger (bool isTrigger) noexcept; void SetIsTrigger (bool isTrigger) noexcept;
void SetFriction (float friction) noexcept; void SetFriction (float friction) noexcept;
void SetBounciness (float bounciness) noexcept; void SetBounciness (float bounciness) noexcept;
void SetDensity (float density) noexcept; void SetDensity (float density) noexcept;
void SetMaterial (const SHPhysicsMaterial& newMaterial) noexcept;
void SetPositionOffset (const SHVec3& positionOffset) noexcept; void SetPositionOffset (const SHVec3& positionOffset) noexcept;
@ -91,11 +104,19 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
Type type; Type type;
EntityID entityID; // The entity this collider belongs to
bool isTrigger; bool isTrigger;
bool dirty; bool dirty;
SHShape* shape; SHShape* shape;
SHPhysicsMaterial material;
SHVec3 positionOffset; SHVec3 positionOffset;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void CopyShape(const SHShape* rhs);
RTTR_ENABLE() RTTR_ENABLE()
}; };

View File

@ -0,0 +1,104 @@
/****************************************************************************************
* \file SHPhysicsMaterial.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Physics Material.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#include <SHpch.h>
// Primary Header
#include "SHPhysicsMaterial.h"
// Project Headers
#include "Math/SHMathHelpers.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Static Data Member Definitions */
/*-----------------------------------------------------------------------------------*/
const SHPhysicsMaterial SHPhysicsMaterial::DEFAULT { 0.4f, 0.0f, 1.0f };
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsMaterial::SHPhysicsMaterial(float _friction, float _bounciness, float _density) noexcept
: friction { std::clamp(_friction, 0.0f, 1.0f) }
, bounciness{ std::clamp(_bounciness, 0.0f, 1.0f) }
, density { std::fabs(_density) }
{}
/*-----------------------------------------------------------------------------------*/
/* Operator Overload Definitions */
/*-----------------------------------------------------------------------------------*/
bool SHPhysicsMaterial::operator==(const SHPhysicsMaterial& rhs) const noexcept
{
return SHMath::CompareFloat(friction, rhs.friction)
&& SHMath::CompareFloat(bounciness, rhs.bounciness)
&& SHMath::CompareFloat(density, rhs.density);
}
bool SHPhysicsMaterial::operator!=(const SHPhysicsMaterial& rhs) const noexcept
{
return !SHMath::CompareFloat(friction, rhs.friction)
|| !SHMath::CompareFloat(bounciness, rhs.bounciness)
|| !SHMath::CompareFloat(density, rhs.density);
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
float SHPhysicsMaterial::GetFriction() const noexcept
{
return friction;
}
float SHPhysicsMaterial::GetBounciness() const noexcept
{
return bounciness;
}
float SHPhysicsMaterial::GetDensity() const noexcept
{
return density;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsMaterial::SetFriction(float newFriction) noexcept
{
if (newFriction < 0.0f || newFriction > 1.0f)
{
SHLOG_WARNING("Clamping friction of Physics Material between [0,1].")
}
friction = std::clamp(newFriction, 0.0f, 1.0f);
}
void SHPhysicsMaterial::SetBounciness(float newBounciness) noexcept
{
if (newBounciness < 0.0f || newBounciness > 1.0f)
{
SHLOG_WARNING("Clamping bounciness of Physics Material between [0,1].")
}
bounciness = std::clamp(newBounciness, 0.0f, 1.0f);
}
void SHPhysicsMaterial::SetDensity(float newDensity) noexcept
{
if (newDensity < 0.0f)
{
SHLOG_WARNING("Setting negative density of Physics Material to positive.")
}
density = std::fabs(newDensity);
}
} // namespace SHADE

View File

@ -0,0 +1,113 @@
/****************************************************************************************
* \file SHPhysicsMaterial.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Physics Material.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#pragma once
// Project Headers
#include "SH_API.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHPhysicsMaterial
{
public:
/*---------------------------------------------------------------------------------*/
/* Static Data Members */
/*---------------------------------------------------------------------------------*/
static const SHPhysicsMaterial DEFAULT;
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsMaterial (const SHPhysicsMaterial&) noexcept = default;
SHPhysicsMaterial (SHPhysicsMaterial&&) noexcept = default;
~SHPhysicsMaterial() = default;
/**
* @brief Default constructor for a physics material.
* @param friction The friction of the material. Clamped between [0,1]. Defaults to 0.4.
* @param bounciness The bounciness of the material. Clamped between [0,1].
* @param density The mass density of the material. Always made positive.
*/
SHPhysicsMaterial (float friction = 0.4f, float bounciness = 0.0f, float density = 1.0f) noexcept;
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
SHPhysicsMaterial& operator= (const SHPhysicsMaterial&) noexcept = default;
SHPhysicsMaterial& operator= (SHPhysicsMaterial&&) noexcept = default;
bool operator==(const SHPhysicsMaterial& rhs) const noexcept;
bool operator!=(const SHPhysicsMaterial& rhs) const noexcept;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] float GetFriction () const noexcept;
[[nodiscard]] float GetBounciness () const noexcept;
[[nodiscard]] float GetDensity () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
/**
* @brief Sets the friction coefficient of the physics material.
* @param newFriction The friction value to set. Clamped between [0,1].
*/
void SetFriction (float newFriction) noexcept;
/**
* @brief Sets the bounciness factor of the physics material.
* @param newBounciness The bounciness value to set. Clamped between [0,1].
*/
void SetBounciness (float newBounciness) noexcept;
/**
* @brief Sets the mass density of the physics material.
* @param newDensity The density value to set. Always made positive.
*/
void SetDensity (float newDensity) noexcept;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
/**
* @brief The friction coefficient of the physics object., clamped between [0,1].<br/>
* 0 means the object will never experience friction.
* 1 means the friction force against the object is equal to the applied force.
*/
float friction;
/**
* @brief The bounciness factor of the physics object., clamped between [0,1].<br/>
* 0 means the object will never bounce.
* 1 means the object never loses energy on a bounce.
*/
float bounciness;
/**
* @brief The density of the collider that determines the mass of the collision shape
* if it is automatically computed. Must be a positive number.
*/
float density;
};
}

View File

@ -26,8 +26,6 @@ namespace SHADE
SHPhysicsObject::SHPhysicsObject(EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept SHPhysicsObject::SHPhysicsObject(EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept
: entityID { eid } : entityID { eid }
, isRigidBody { false }
, hasColliders{ false }
, factory { physicsFactory } , factory { physicsFactory }
, world { physicsWorld } , world { physicsWorld }
, rp3dBody { nullptr } , rp3dBody { nullptr }
@ -130,42 +128,6 @@ namespace SHADE
/* Public Function Member Definitions */ /* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHPhysicsObject::CreateRigidBody(const SHTransformComponent* tf, SHRigidBodyComponent* rb, SHColliderComponent* c)
{
// If collider already exists, recreate the collision body as a rigid body
if (hasColliders)
world->destroyCollisionBody(rp3dBody);
rp3dBody = world->createRigidBody(rp3d::Transform{ tf->GetWorldPosition(), tf->GetWorldRotation() });
isRigidBody = true;
rb->position = tf->GetWorldPosition();
rb->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation());
if (hasColliders)
{
c->position = tf->GetWorldPosition();
c->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation());
// Get array of colliders and add them back into the rigidbody
for (auto& collider : c->colliders | std::views::keys)
AddCollider(&collider);
}
}
void SHPhysicsObject::CreateCollisionBody(const SHTransformComponent* tf, SHColliderComponent* c)
{
if (rp3dBody == nullptr)
rp3dBody = world->createCollisionBody(rp3d::Transform{ tf->GetWorldPosition(), tf->GetWorldRotation() });
hasColliders = true;
c->position = tf->GetWorldPosition();
c->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation());
for (auto& collider : c->colliders | std::views::keys)
AddCollider(&collider);
}
int SHPhysicsObject::AddCollider(SHCollider* collider) int SHPhysicsObject::AddCollider(SHCollider* collider)
{ {
switch (collider->GetType()) switch (collider->GetType())
@ -193,31 +155,6 @@ namespace SHADE
return static_cast<int>(rp3dBody->getNbColliders()) - 1; return static_cast<int>(rp3dBody->getNbColliders()) - 1;
} }
void SHPhysicsObject::DestroyRigidBody(SHColliderComponent* c) noexcept
{
world->destroyRigidBody(reinterpret_cast<rp3d::RigidBody*>(rp3dBody));
if (hasColliders)
{
// Preserve colliders as a collision body
rp3dBody = world->createCollisionBody(rp3d::Transform{ c->position, c->orientation });
for (auto& collider : c->colliders | std::views::keys)
AddCollider(&collider);
}
isRigidBody = false;
}
void SHPhysicsObject::DestroyCollisionBody() noexcept
{
// Remove all colliders
for (uint32_t i = 0; i < rp3dBody->getNbColliders(); ++i)
{
auto* collider = rp3dBody->getCollider(i);
rp3dBody->removeCollider(collider);
}
}
void SHPhysicsObject::RemoveCollider(int index) void SHPhysicsObject::RemoveCollider(int index)
{ {
const int NUM_COLLIDERS = static_cast<int>(rp3dBody->getNbColliders()); const int NUM_COLLIDERS = static_cast<int>(rp3dBody->getNbColliders());
@ -324,9 +261,9 @@ namespace SHADE
void SHPhysicsObject::SyncColliders(SHColliderComponent* c) const noexcept void SHPhysicsObject::SyncColliders(SHColliderComponent* c) const noexcept
{ {
int index = 0; int index = 0;
for (auto& [collider, dirty] : c->colliders) for (auto& collider : c->colliders)
{ {
if (!dirty) if (!collider.dirty)
continue; continue;
// Update offsets // Update offsets
@ -356,7 +293,7 @@ namespace SHADE
default: break; default: break;
} }
dirty = false; collider.dirty = false;
++index; ++index;
} }
} }

View File

@ -69,13 +69,8 @@ namespace SHADE
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void CreateRigidBody (const SHTransformComponent* tf, SHRigidBodyComponent* rb, SHColliderComponent* c);
void CreateCollisionBody (const SHTransformComponent* tf, SHColliderComponent* c);
int AddCollider (SHCollider* collider); int AddCollider (SHCollider* collider);
void DestroyRigidBody (SHColliderComponent* c) noexcept;
void RemoveCollider (int index); void RemoveCollider (int index);
void DestroyCollisionBody () noexcept;
void SyncRigidBody (SHRigidBodyComponent* rb) const noexcept; void SyncRigidBody (SHRigidBodyComponent* rb) const noexcept;
void SyncColliders (SHColliderComponent* c) const noexcept; void SyncColliders (SHColliderComponent* c) const noexcept;
@ -86,8 +81,6 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
EntityID entityID; EntityID entityID;
bool isRigidBody;
bool hasColliders;
rp3d::PhysicsCommon* factory; rp3d::PhysicsCommon* factory;
rp3d::PhysicsWorld* world; rp3d::PhysicsWorld* world;

View File

@ -16,6 +16,8 @@
// Project Headers // Project Headers
#include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHEntityManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.hpp"
#include "Math/SHMathHelpers.h" #include "Math/SHMathHelpers.h"
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
@ -175,11 +177,9 @@ namespace SHADE
void SHPhysicsSystem::Init() void SHPhysicsSystem::Init()
{ {
using namespace rp3d;
// Create a physics world with the default settings // Create a physics world with the default settings
PhysicsWorld::WorldSettings settings; rp3d::PhysicsWorld::WorldSettings settings;
settings.gravity = Vector3{ 0.0f, -9.81f, 0.0f }; settings.gravity = SHVec3{ 0.0f, -9.81f, 0.0f };
settings.isSleepingEnabled = true; settings.isSleepingEnabled = true;
settings.defaultVelocitySolverNbIterations = 8; settings.defaultVelocitySolverNbIterations = 8;
settings.defaultPositionSolverNbIterations = 3; settings.defaultPositionSolverNbIterations = 3;
@ -190,6 +190,16 @@ namespace SHADE
// Set up solvers // Set up solvers
world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::SPLIT_IMPULSES); world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::SPLIT_IMPULSES);
// Subscribe to component events
const std::shared_ptr ADD_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::AddPhysicsComponent) };
const ReceiverPtr ADD_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(ADD_COMPONENT_RECEIVER);
SHEventManager::SubscribeTo(SH_COMPONENT_ADDED_EVENT, ADD_COMPONENT_RECEIVER_PTR);
const std::shared_ptr REMOVE_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::RemovePhysicsComponent) };
const ReceiverPtr REMOVE_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(REMOVE_COMPONENT_RECEIVER);
SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, REMOVE_COMPONENT_RECEIVER_PTR);
} }
void SHPhysicsSystem::Exit() void SHPhysicsSystem::Exit()
@ -197,128 +207,83 @@ namespace SHADE
factory.destroyPhysicsWorld(world); factory.destroyPhysicsWorld(world);
} }
void SHPhysicsSystem::AddRigidBody(EntityID entityID) noexcept
{
//#ifdef _DEBUG
// SHLOG_INFO("Adding a Rigidbody to the Physics World.")
//#endif
auto* physicsObject = CreatePhysicsObject(entityID);
physicsObject->CreateRigidBody
(
EnsureTransform(entityID),
SHComponentManager::GetComponent<SHRigidBodyComponent>(entityID),
SHComponentManager::GetComponent_s<SHColliderComponent>(entityID)
);
}
void SHPhysicsSystem::AddCollider(EntityID entityID) noexcept
{
//#ifdef _DEBUG
// SHLOG_INFO("Adding a Collider to the Physics World.")
//#endif
auto* physicsObject = CreatePhysicsObject(entityID);
physicsObject->CreateCollisionBody
(
EnsureTransform(entityID),
SHComponentManager::GetComponent<SHColliderComponent>(entityID)
);
}
void SHPhysicsSystem::RemoveRigidBody(EntityID entityID) noexcept
{
#ifdef _DEBUG
SHLOG_INFO("Removing a Rigidbody from the Physics World.")
#endif
auto* physicsObject = GetPhysicsObject(entityID);
SHASSERT(physicsObject != nullptr, "Physics object has been lost from the world!")
physicsObject->DestroyRigidBody(SHComponentManager::GetComponent_s<SHColliderComponent>(entityID));
if (physicsObject->rp3dBody == nullptr)
DestroyPhysicsObject(entityID);
}
void SHPhysicsSystem::RemoveCollider(EntityID entityID) noexcept
{
#ifdef _DEBUG
SHLOG_INFO("Removing a Collider from the Physics World.")
#endif
}
void SHPhysicsSystem::AddForce(EntityID entityID, const SHVec3& force) const noexcept
{
}
void SHPhysicsSystem::AddForceAtLocalPos(EntityID entityID, const SHVec3& force, const SHVec3& localPos) const noexcept
{
}
void SHPhysicsSystem::AddForceAtWorldPos(EntityID entityID, const SHVec3& force, const SHVec3& worldPos) const noexcept
{
}
void SHPhysicsSystem::AddRelativeForce(EntityID entityID, const SHVec3& relativeForce) const noexcept
{
}
void SHPhysicsSystem::AddRelativeForceAtLocalPos(EntityID entityID, const SHVec3& relativeForce, const SHVec3& localPos) const noexcept
{
}
void SHPhysicsSystem::AddRelativeForceAtWorldPos(EntityID entityID, const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept
{
}
void SHPhysicsSystem::AddTorque(EntityID entityID, const SHVec3& torque) const noexcept
{
}
void SHPhysicsSystem::AddRelativeTorque(EntityID entityID, const SHVec3& relativeTorque) const noexcept
{
}
void SHPhysicsSystem::AddCollisionShape(EntityID entityID, SHCollider* collider) void SHPhysicsSystem::AddCollisionShape(EntityID entityID, SHCollider* collider)
{ {
auto* physicsObject = GetPhysicsObject(entityID); auto* physicsObject = GetPhysicsObject(entityID);
physicsObject->AddCollider(collider);
const SHPhysicsColliderAddedEvent COLLIDER_ADDED_EVENT_DATA
{
.entityID = entityID
, .colliderType = collider->GetType()
, .colliderIndex = physicsObject->AddCollider(collider)
};
SHEventManager::BroadcastEvent<SHPhysicsColliderAddedEvent>(COLLIDER_ADDED_EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT);
} }
void SHPhysicsSystem::RemoveCollisionShape(EntityID entityID, int index) void SHPhysicsSystem::RemoveCollisionShape(EntityID entityID, int index)
{ {
auto* physicsObject = GetPhysicsObject(entityID);
physicsObject->RemoveCollider(index);
const SHPhysicsColliderRemovedEvent COLLIDER_REMOVED_EVENT_DATA
{
.entityID = entityID
, .colliderIndex = index
};
SHEventManager::BroadcastEvent<SHPhysicsColliderRemovedEvent>(COLLIDER_REMOVED_EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT);
} }
void SHPhysicsSystem::PhysicsPreUpdate::Execute(double) noexcept void SHPhysicsSystem::PhysicsPreUpdate::Execute(double) noexcept
{ {
auto* system = reinterpret_cast<SHPhysicsSystem*>(GetSystem()); auto* system = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
// Sync transforms
for (auto& [entityID, physicsObject] : system->map)
{
// Ensure a valid physics Object
if (physicsObject.rp3dBody == nullptr)
continue;
const auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
if (transformComponent && transformComponent->HasChanged())
{
const auto WORLD_POS = transformComponent->GetWorldPosition();
const auto WORLD_ROT = transformComponent->GetWorldOrientation();
physicsObject.SetPosition(WORLD_POS);
physicsObject.SetOrientation(WORLD_ROT);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
if (rigidBodyComponent)
{
rigidBodyComponent->position = WORLD_POS;
rigidBodyComponent->orientation = WORLD_ROT;
// Clear all forces and velocities if editor is stopped
if (SHSystemManager::GetSystem<SHEditor>()->editorState == SHEditor::State::STOP)
{
auto* rp3dRigidBody = reinterpret_cast<rp3d::RigidBody*>(physicsObject.rp3dBody);
rp3dRigidBody->resetForce();
rp3dRigidBody->resetTorque();
rp3dRigidBody->setLinearVelocity(SHVec3::Zero);
rp3dRigidBody->setAngularVelocity(SHVec3::Zero);
}
}
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
if (colliderComponent)
{
colliderComponent->position = WORLD_POS;
colliderComponent->orientation = WORLD_ROT;
}
}
}
// Update bodies and colliders if component is dirty // Update bodies and colliders if component is dirty
system->SyncRigidBodyComponents(SHComponentManager::GetDense<SHRigidBodyComponent>()); system->SyncRigidBodyComponents(SHComponentManager::GetDense<SHRigidBodyComponent>());
system->SyncColliderComponents(SHComponentManager::GetDense<SHColliderComponent>()); system->SyncColliderComponents(SHComponentManager::GetDense<SHColliderComponent>());
// Sync transforms
for (auto& physicsObject : system->map | std::views::values)
{
const auto* TF = SHComponentManager::GetComponent<SHTransformComponent>(physicsObject.entityID);
if (TF->HasChanged())
{
physicsObject.SetPosition(TF->GetWorldPosition());
physicsObject.SetOrientation(TF->GetWorldOrientation());
}
}
} }
void SHPhysicsSystem::PhysicsFixedUpdate::Execute(double dt) noexcept void SHPhysicsSystem::PhysicsFixedUpdate::Execute(double dt) noexcept
@ -359,7 +324,7 @@ namespace SHADE
/* Private Function Member Definitions */ /* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHPhysicsObject* SHPhysicsSystem::CreatePhysicsObject(EntityID entityID) noexcept SHPhysicsObject* SHPhysicsSystem::EnsurePhysicsObject(EntityID entityID) noexcept
{ {
const auto it = map.find(entityID); const auto it = map.find(entityID);
if (it == map.end()) if (it == map.end())
@ -451,15 +416,18 @@ namespace SHADE
const rp3d::Transform CURRENT_TF = physicsObject.rp3dBody->getTransform(); const rp3d::Transform CURRENT_TF = physicsObject.rp3dBody->getTransform();
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
// Check if transform should be interpolated // Check if transform should be interpolated
if (physicsObject.isRigidBody) if (rigidBodyComponent != nullptr)
{ {
auto* rbComponent = SHComponentManager::GetComponent<SHRigidBodyComponent>(entityID);
if (rbComponent->GetType() == SHRigidBodyComponent::Type::STATIC) if (rigidBodyComponent->GetType() == SHRigidBodyComponent::Type::STATIC)
continue; continue;
if (rbComponent->IsInterpolating()) if (rigidBodyComponent->IsInterpolating())
{ {
const rp3d::Transform PREV_TF = physicsObject.prevTransform; const rp3d::Transform PREV_TF = physicsObject.prevTransform;
const rp3d::Transform INTERPOLATED_TF = rp3d::Transform::interpolateTransforms(PREV_TF, CURRENT_TF, static_cast<rp3d::decimal>(interpolationFactor)); const rp3d::Transform INTERPOLATED_TF = rp3d::Transform::interpolateTransforms(PREV_TF, CURRENT_TF, static_cast<rp3d::decimal>(interpolationFactor));
@ -474,12 +442,12 @@ namespace SHADE
rp3dRot = CURRENT_TF.getOrientation(); rp3dRot = CURRENT_TF.getOrientation();
} }
rbComponent->position = CURRENT_TF.getPosition(); rigidBodyComponent->position = CURRENT_TF.getPosition();
rbComponent->orientation = CURRENT_TF.getOrientation(); rigidBodyComponent->orientation = CURRENT_TF.getOrientation();
if (physicsObject.hasColliders) if (colliderComponent != nullptr)
{ {
auto* colliderComponent = SHComponentManager::GetComponent<SHColliderComponent>(entityID);
colliderComponent->position = CURRENT_TF.getPosition(); colliderComponent->position = CURRENT_TF.getPosition();
colliderComponent->orientation = CURRENT_TF.getOrientation(); colliderComponent->orientation = CURRENT_TF.getOrientation();
} }
@ -491,28 +459,148 @@ namespace SHADE
} }
// Convert RP3D Transform to SHADE // Convert RP3D Transform to SHADE
auto* tfComponent = SHComponentManager::GetComponent<SHTransformComponent>(entityID); auto* transformComponent = SHComponentManager::GetComponent<SHTransformComponent>(entityID);
tfComponent->SetWorldPosition(rp3dPos); transformComponent->SetWorldPosition(rp3dPos);
tfComponent->SetWorldOrientation(SHQuaternion{ rp3dRot }); transformComponent->SetWorldOrientation(rp3dRot);
// Cache transforms // Cache transforms
physicsObject.prevTransform = CURRENT_TF; physicsObject.prevTransform = CURRENT_TF;
} }
} }
SHTransformComponent* SHPhysicsSystem::EnsureTransform(EntityID entityID) SHEventHandle SHPhysicsSystem::AddPhysicsComponent(SHEventPtr addComponentEvent)
{ {
auto* tf = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID); const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentAddedEvent>*>(addComponentEvent.get());
// Possibly redundant static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
if (!tf) static const auto COLLIDER_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto ADDED_ID = EVENT_DATA->data->addedComponentType;
const bool IS_PHYSICS_COMPONENT = ADDED_ID == RIGID_BODY_ID || ADDED_ID == COLLIDER_ID;
if (IS_PHYSICS_COMPONENT)
{ {
SHComponentManager::AddComponent<SHTransformComponent>(entityID); const EntityID ENTITY_ID = EVENT_DATA->data->eid;
tf = SHComponentManager::GetComponent<SHTransformComponent>(entityID); auto* physicsObject = EnsurePhysicsObject(ENTITY_ID);
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(ENTITY_ID);
if (transformComponent == nullptr)
{
SHLOG_ERROR("Entity {} cannot add a Physics Component without a Transform! Component not created!", ENTITY_ID)
return EVENT_DATA->handle;
} }
return tf; auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ENTITY_ID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(ENTITY_ID);
if (ADDED_ID == RIGID_BODY_ID)
{
if (colliderComponent != nullptr)
{
world->destroyCollisionBody(physicsObject->rp3dBody);
physicsObject->rp3dBody = nullptr;
} }
rigidBodyComponent->position = transformComponent->GetWorldPosition();
rigidBodyComponent->orientation = transformComponent->GetWorldOrientation();
physicsObject->rp3dBody = world->createRigidBody
(
rp3d::Transform{ rigidBodyComponent->position, rigidBodyComponent->orientation }
);
rigidBodyComponent->rp3dBody = reinterpret_cast<rp3d::RigidBody*>(physicsObject->rp3dBody);
// Add collision shapes back into the body
if (colliderComponent != nullptr)
{
for (auto& collider : colliderComponent->colliders)
physicsObject->AddCollider(&collider);
}
}
if (ADDED_ID == COLLIDER_ID)
{
SHASSERT(colliderComponent != nullptr, "Collider Component was not added to Entity " + std::to_string(ENTITY_ID) + "!");
colliderComponent->position = transformComponent->GetWorldPosition();
colliderComponent->orientation = transformComponent->GetWorldOrientation();
if (physicsObject->rp3dBody == nullptr)
{
physicsObject->rp3dBody = world->createCollisionBody
(
rp3d::Transform{ colliderComponent->position, colliderComponent->orientation }
);
}
// Add Collision Shapes
for (auto& collider : colliderComponent->colliders)
physicsObject->AddCollider(&collider);
}
}
return EVENT_DATA->handle;
}
SHEventHandle SHPhysicsSystem::RemovePhysicsComponent(SHEventPtr removeComponentEvent)
{
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentRemovedEvent>*>(removeComponentEvent.get());
static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto REMOVED_ID = EVENT_DATA->data->removedComponentType;
const bool IS_PHYSICS_COMPONENT = REMOVED_ID == RIGID_BODY_ID || REMOVED_ID == COLLIDER_ID;
if (IS_PHYSICS_COMPONENT)
{
const EntityID ENTITY_ID = EVENT_DATA->data->eid;
auto* physicsObject = GetPhysicsObject(ENTITY_ID);
SHASSERT(physicsObject != nullptr, "Physics object has been lost from the world!")
if (REMOVED_ID == RIGID_BODY_ID)
{
world->destroyRigidBody(reinterpret_cast<rp3d::RigidBody*>(physicsObject->rp3dBody));
physicsObject->rp3dBody = nullptr;
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(ENTITY_ID);
if (colliderComponent != nullptr)
{
// Preserve colliders as a collision body
physicsObject->rp3dBody = world->createCollisionBody
(
rp3d::Transform{ colliderComponent->position, colliderComponent->orientation }
);
for (auto& collider : colliderComponent->colliders)
physicsObject->AddCollider(&collider);
}
// Wake up all physics objects
for (auto& [entityID, object] : map)
{
if (SHComponentManager::HasComponent<SHRigidBodyComponent>(entityID))
reinterpret_cast<rp3d::RigidBody*>(object.rp3dBody)->setIsSleeping(false);
}
}
if (REMOVED_ID == COLLIDER_ID)
{
// Remove all colliders
const int NUM_COLLIDERS = static_cast<int>(physicsObject->rp3dBody->getNbColliders());
for (int i = NUM_COLLIDERS - 1; i >= 0; --i)
{
auto* collider = physicsObject->rp3dBody->getCollider(i);
physicsObject->rp3dBody->removeCollider(collider);
}
}
if (physicsObject->rp3dBody == nullptr)
DestroyPhysicsObject(ENTITY_ID);
}
return EVENT_DATA->handle;
}
} // namespace SHADE } // namespace SHADE

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