Merge branch 'main' into SP3-141-Camera-System

This commit is contained in:
maverickdgg 2022-10-31 16:55:56 +08:00
commit acf52c77ce
202 changed files with 9702 additions and 1990 deletions

View File

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

View File

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

Binary file not shown.

View File

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

View File

@ -1,3 +1,3 @@
Name: RaccoonPreTexturedVer1_Base9
ID: 91918845
Type: 4
Name: RaccoonPreTexturedVer1_Base9
ID: 64651793
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: 39301863
Type: 2

View File

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

View File

@ -13,37 +13,38 @@ struct MatPropData
layout(location = 0) in struct
{
vec4 vertColor;
vec2 uv;
vec4 vertPos; // location 0
vec2 uv; // location = 1
vec4 normal; // location = 2
} In;
// material stuff
layout(location = 2) flat in struct
layout(location = 3) flat in struct
{
int materialIndex;
uint eid;
uint lightLayerIndex;
} In2;
//layout (set = 0, binding = )
layout (set = 0, binding = 1) uniform sampler2D textures[]; // for textures (global)
layout (set = 3, binding = 0) buffer MaterialProperties // For materials
layout (std430, set = 3, binding = 0) buffer MaterialProperties // For materials
{
MatPropData data[];
} MatProp;
layout(location = 0) out vec4 outColor;
layout(location = 0) out vec4 position;
layout(location = 1) out uint outEntityID;
layout(location = 2) out uint lightLayerIndices;
layout(location = 3) out vec4 normals;
layout(location = 4) out vec4 albedo;
void main()
{
outColor = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) +
MatProp.data[In2.materialIndex].color / MatProp.data[In2.materialIndex].alpha;
position = In.vertPos;
normals = In.normal;
albedo = texture(textures[nonuniformEXT(MatProp.data[In2.materialIndex].textureIndex)], In.uv) + MatProp.data[In2.materialIndex].color / MatProp.data[In2.materialIndex].alpha;
outEntityID = In2.eid;
lightLayerIndices = In2.lightLayerIndex;
//outColor = vec4 (1.0f);
}

Binary file not shown.

View File

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

View File

@ -14,13 +14,14 @@ layout(location = 8) in uvec2 integerData;
layout(location = 0) out struct
{
vec4 vertColor; // location 0
vec4 vertPos; // location 0
vec2 uv; // location = 1
vec4 normal; // location = 2
} Out;
// material stuff
layout(location = 2) out struct
layout(location = 3) out struct
{
int materialIndex;
uint eid;
@ -36,10 +37,14 @@ layout(set = 2, binding = 0) uniform CameraData
void main()
{
Out.uv = aUV;
Out2.materialIndex = gl_InstanceIndex;
Out2.eid = integerData[0];
Out2.lightLayerIndex = integerData[1];
Out.vertPos = worldTransform * vec4(aVertexPos, 1.0f);
Out.uv = aUV;
Out.normal.rgb = mat3(transpose(inverse(worldTransform))) * aNormal.rgb;
Out.normal.rgb = normalize (Out.normal.rgb);
gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f);
Out.vertColor = vec4 (aVertexPos, 1.0f);
}

Binary file not shown.

View File

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

Binary file not shown.

View File

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

View File

@ -4,7 +4,7 @@
//#define SHEDITOR
#ifdef SHEDITOR
#include "Editor/SHEditor.hpp"
#include "Editor/SHEditor.h"
//#include "Scenes/SBEditorScene.h"
#endif // SHEDITOR
@ -94,7 +94,7 @@ namespace Sandbox
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BatcherDispatcherRoutine>();
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BeginRoutine>();
SHSystemManager::RegisterRoutine<SHCameraSystem, SHCameraSystem::EditorCameraUpdate>();
//SHSystemManager::RegisterRoutine<SHCameraSystem, SHCameraSystem::EditorCameraUpdate>();
SHSystemManager::RegisterRoutine<SHCameraSystem, SHCameraSystem::CameraSystemUpdate>();
#ifdef SHEDITOR
@ -110,14 +110,7 @@ namespace Sandbox
SHComponentManager::CreateComponentSparseSet<SHRenderable>();
//SHComponentManager::CreateComponentSparseSet<SHCameraComponent>();
//TODO: REMOVE AFTER PRESENTATION
//SHAssetManager::LoadDataTemp("../../Assets/racoon.gltf");
//SHAssetManager::LoadDataTemp("../../Assets/Cube.012.shmesh");
//SHAssetManager::LoadDataTemp("../../Assets/RaccoonBag_Color_Ver4.dds");
//SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.dds");
//SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.shtex");
//TODO: REMOVE AFTER PRESENTATION
SHAssetManager::Load();
SHSystemManager::RegisterRoutine<SHAudioSystem, SHAudioSystem::AudioRoutine>();
@ -130,8 +123,6 @@ namespace Sandbox
SHSceneManager::InitSceneManager<SBTestScene>("TestScene");
SHFrameRateController::UpdateFRC();
SHAssetManager::Load();
}
void SBApplication::Update(void)
@ -165,7 +156,7 @@ namespace Sandbox
SHSceneManager::Exit();
SHSystemManager::Exit();
SHAssetManager::Unload();
SHAssetManager::Exit();
}
}

View File

@ -53,7 +53,8 @@ namespace Sandbox
if (asset.name == "Cube.012")
handles.emplace_back(SHResourceManager::LoadOrGet<SHMesh>(asset.id));
break;
case AssetType::IMAGE:
case AssetType::TEXTURE:
if (asset.name == "RaccoonPreTexturedVer1_Base9")
texHandles.emplace_back(SHResourceManager::LoadOrGet<SHTexture>(asset.id));
break;
}
@ -83,7 +84,7 @@ namespace Sandbox
auto& collider = *SHComponentManager::GetComponent_s<SHColliderComponent>(entity);
//renderable.Mesh = handles.front();
renderable.Mesh = CUBE_MESH;
renderable.SetMesh(CUBE_MESH);
renderable.SetMaterial(customMat);
if (y == 50)
@ -95,11 +96,7 @@ namespace Sandbox
transform.SetWorldRotation(SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f));
transform.SetWorldScale(TEST_OBJ_SCALE);
//if (const bool IS_EVEN = (y * NUM_ROWS + x) % 2; IS_EVEN)
collider.AddBoundingBox(SHVec3::One * 0.5f, SHVec3::Zero);
//else
// collider.AddBoundingSphere(0.5f, SHVec3::Zero);
collider.AddBoundingBox(SHVec3::One, SHVec3::Zero);
stressTestObjects.emplace_back(entity);
}
@ -107,7 +104,7 @@ namespace Sandbox
auto& renderable = *SHComponentManager::GetComponent_s<SHRenderable>(raccoonSpin);
auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(raccoonSpin);
renderable.Mesh = handles.front();
renderable.SetMesh(handles.front());
renderable.SetMaterial(customMat);
renderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f));
renderable.GetModifiableMaterial()->SetProperty("data.alpha", 1.0f);
@ -122,9 +119,8 @@ namespace Sandbox
auto& floorRigidBody = *SHComponentManager::GetComponent_s<SHRigidBodyComponent>(floor);
auto& floorCollider = *SHComponentManager::GetComponent_s<SHColliderComponent>(floor);
floorRenderable.Mesh = CUBE_MESH;
floorRenderable.SetMaterial(customMat);
floorRenderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(1.0f, 1.0f, 1.0f, 1.0f));
floorRenderable.SetMesh(CUBE_MESH);
floorRenderable.SetMaterial(graphicsSystem->GetDefaultMaterialInstance());
floorTransform.SetWorldScale({ 7.5f, 0.5f, 7.5 });
floorTransform.SetWorldPosition({ 0.0f, -3.0f, -5.0f });
@ -148,7 +144,7 @@ namespace Sandbox
auto& renderableShowcase = *SHComponentManager::GetComponent_s<SHRenderable>(raccoonShowcase);
auto& transformShowcase = *SHComponentManager::GetComponent_s<SHTransformComponent>(raccoonShowcase);
renderableShowcase.Mesh = handles.front();
renderableShowcase.SetMesh(handles.front());
renderableShowcase.SetMaterial(customMat);
renderableShowcase.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f));
renderableShowcase.GetModifiableMaterial()->SetProperty("data.alpha", 1.0f);
@ -162,12 +158,22 @@ namespace Sandbox
SHComponentManager::AddComponent<SHLightComponent>(0);
SHComponentManager::RemoveComponent <SHRigidBodyComponent>(0);
SHComponentManager::RemoveComponent <SHColliderComponent>(0);
auto ambientLight = SHEntityManager::CreateEntity<SHLightComponent>();
SHComponentManager::GetComponent<SHLightComponent>(ambientLight)->SetColor(SHVec4(1.0f, 1.0f, 1.0f, 1.0f));
SHComponentManager::GetComponent<SHLightComponent>(ambientLight)->SetStrength(0.25f);
SHComponentManager::GetComponent<SHLightComponent>(ambientLight)->SetType(SH_LIGHT_TYPE::AMBIENT);
}
void SBTestScene::Update(float dt)
{
static float rotation = 0.0f;
SHVec3 direction{0.0f, 0.0f, 1.0f};
direction = SHVec3::RotateY(direction, rotation);
auto* lightComp =SHComponentManager::GetComponent<SHLightComponent>(0);
lightComp->SetDirection (direction);
rotation += 0.005f;
//auto& transform = *SHADE::SHComponentManager::GetComponent_s<SHADE::SHTransformComponent>(testObj);
//transform.SetWorldPosition({1.0f, 1.0f, -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)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,149 @@
<#
/************************************************************************************//*!
\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 static
/// method.
/// </summary>
/// <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(MethodInfo method)
{
// No errors, assign
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[<#=i#>];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// 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[<#=i#>];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action">Action that wraps a function to be called.</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 (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

@ -8,7 +8,7 @@ project "SHADE_Engine"
pchheader "SHpch.h"
pchsource "%{prj.location}/src/SHpch.cpp"
staticruntime "off"
buildoptions{"/bigobj"}
files
{
"%{prj.location}/src/**.h",

View File

@ -0,0 +1,23 @@
/******************************************************************************
* \file SHMaterialAsset.h
* \author Loh Xiao Qi
* \date 29 October 2022
* \brief
*
* \copyright Copyright (c) 2021 Digipen Institute of Technology. Reproduction
* or disclosure of this file or its contents without the prior
* written consent of Digipen Institute of Technology is prohibited.
******************************************************************************/
#pragma once
#include "Assets/Asset Types/SHAssetData.h"
#include <string>
namespace SHADE
{
struct SHMaterialAsset : SHAssetData
{
std::string name;
std::string data;
};
}

View File

@ -0,0 +1,23 @@
/******************************************************************************
* \file SHPrefabAsset.h
* \author Loh Xiao Qi
* \date 28 October 2022
* \brief
*
* \copyright Copyright (c) 2021 Digipen Institute of Technology. Reproduction
* or disclosure of this file or its contents without the prior
* written consent of Digipen Institute of Technology is prohibited.
******************************************************************************/
#pragma once
#include "SHAssetData.h"
#include <string>
namespace SHADE
{
struct SHPrefabAsset : SHAssetData
{
std::string name;
std::string data;
};
}

View File

@ -0,0 +1,23 @@
/******************************************************************************
* \file SHSceneAsset.h
* \author Loh Xiao Qi
* \date 28 October 2022
* \brief
*
* \copyright Copyright (c) 2021 Digipen Institute of Technology. Reproduction
* or disclosure of this file or its contents without the prior
* written consent of Digipen Institute of Technology is prohibited.
******************************************************************************/
#pragma once
#include "SHAssetData.h"
#include <string>
namespace SHADE
{
struct SHSceneAsset : SHAssetData
{
std::string name;
std::string data;
};
}

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,24 +1,30 @@
/*************************************************************************//**
* \file SHAssimpLibrary.cpp
* \file SHMeshCompiler.cpp
* \author Loh Xiao Qi
* \date October 2022
* \brief
* \date 30 September 2022
* \brief Library to write data in SHMeshAsset into binary file for faster
* loading in the future
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#include "SHpch.h"
#include "SHAssimpLibrary.h"
#include "SHMeshCompiler.h"
#include "Graphics/MiddleEnd/Meshes/SHMeshData.h"
#include <assimp/postprocess.h>
#include <fstream>
namespace SHADE
{
Assimp::Importer SHAssimpLibrary::aiImporter;
void SHAssimpLibrary::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept
{
for (size_t i {0}; i < node.mNumMeshes; ++i)
Assimp::Importer SHMeshCompiler::aiImporter;
void SHMeshCompiler::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept
{
for (size_t i{ 0 }; i < node.mNumMeshes; ++i)
{
aiMesh* mesh = scene.mMeshes[node.mMeshes[i]];
meshes.push_back(ProcessMesh(*mesh));
@ -28,16 +34,16 @@ namespace SHADE
{
ProcessNode(*node.mChildren[i], scene, meshes);
}
}
}
void SHAssimpLibrary::ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept
{
if (scene.HasAnimations())
void SHMeshCompiler::ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept
{
if (scene.HasAnimations())
{
std::vector<SHAnimationAsset> anims(scene.mNumAnimations);
for (auto i{0}; i < scene.mNumAnimations; ++i)
{
auto const& anim {*scene.mAnimations[i]};
std::vector<SHAnimationAsset> anims(scene.mNumAnimations);
for (auto i{ 0 }; i < scene.mNumAnimations; ++i)
{
auto const& anim{ *scene.mAnimations[i] };
anims[i].name = anim.mName.C_Str();
@ -47,17 +53,17 @@ namespace SHADE
std::copy_n(anim.mChannels, anim.mNumChannels, anims[i].nodeChannels.data());
std::copy_n(anim.mMeshChannels, anim.mNumMeshChannels, anims[i].meshChannels.data());
std::copy_n(anim.mMorphMeshChannels, anim.mNumMorphMeshChannels, anims[i].morphMeshChannels.data());
}
}
}
}
}
SHMeshAsset* SHAssimpLibrary::ProcessMesh(aiMesh const& mesh) noexcept
{
SHMeshAsset* SHMeshCompiler::ProcessMesh(aiMesh const& mesh) noexcept
{
SHMeshAsset* result = new SHMeshAsset();
result->compiled = false;
result->changed = false;
for (size_t i{0}; i < mesh.mNumVertices; ++i)
for (size_t i{ 0 }; i < mesh.mNumVertices; ++i)
{
// Vertex position
SHVec3 vertex;
@ -67,7 +73,7 @@ namespace SHADE
result->vertexPosition.push_back(vertex);
// Tex coords
SHVec2 texCoord{0.f, 0.f};
SHVec2 texCoord{ 0.f, 0.f };
if (mesh.mTextureCoords[0])
{
texCoord.x = mesh.mTextureCoords[0][i].x;
@ -76,7 +82,7 @@ namespace SHADE
result->texCoords.push_back(texCoord);
// Normals
SHVec3 normal{0.f, 0.f, 0.f};
SHVec3 normal{ 0.f, 0.f, 0.f };
if (mesh.mNormals)
{
normal.x = mesh.mNormals[i].x;
@ -86,7 +92,7 @@ namespace SHADE
result->vertexNormal.push_back(normal);
// Tangent
SHVec3 tangent{0.f, 0.f, 0.f};
SHVec3 tangent{ 0.f, 0.f, 0.f };
if (mesh.mTangents)
{
tangent.x = mesh.mTangents[i].x;
@ -96,10 +102,10 @@ namespace SHADE
result->vertexTangent.push_back(tangent);
}
for (size_t i {0}; i < mesh.mNumFaces; ++i)
for (size_t i{ 0 }; i < mesh.mNumFaces; ++i)
{
aiFace face = mesh.mFaces[i];
for (size_t j{0}; j < face.mNumIndices; ++j)
for (size_t j{ 0 }; j < face.mNumIndices; ++j)
{
result->indices.push_back(face.mIndices[j]);
}
@ -110,10 +116,10 @@ namespace SHADE
result->header.name = mesh.mName.C_Str();
return result;
}
}
void SHAssimpLibrary::LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept
{
void SHMeshCompiler::LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept
{
const aiScene* scene = aiImporter.ReadFile(path.string().c_str(),
aiProcess_Triangulate // Make sure we get triangles rather than nvert polygons
| aiProcess_GenUVCoords // Convert any type of mapping to uv mapping
@ -132,10 +138,64 @@ namespace SHADE
return;
}
ExtractAnimations(*scene, anims);
//ExtractAnimations(*scene, anims);
ProcessNode(*scene->mRootNode, *scene, meshes);
aiImporter.FreeScene();
}
}
std::optional<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

@ -11,14 +11,23 @@
* 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
{
struct SHTextureCompiler
class SHTextureCompiler
{
static std::string CompileTextureBinary(SHTextureAsset const& asset, AssetPath path);
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
#include "Assets/SHAssetMacros.h"
#include "Assets/Asset Types/SHAssetData.h"
namespace SHADE
@ -17,5 +18,6 @@ namespace SHADE
struct SHAssetLoader
{
virtual SHAssetData* Load(AssetPath path) = 0;
virtual void Write(SHAssetData const* data, AssetPath path) = 0;
};
}

View File

@ -22,6 +22,7 @@ namespace SHADE
if (!file.is_open())
{
SHLOG_ERROR("Unable to open SHMesh File: {}", path.string());
return;
}
const std::string name{ path.stem().string() };
@ -75,4 +76,55 @@ namespace SHADE
return result;
}
void SHMeshLoader::Write(SHAssetData const* data, AssetPath path)
{
std::ofstream file{ path, 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());
}
auto asset = *dynamic_cast<SHMeshAsset const*>(data);
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();
}
}

View File

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

View File

@ -0,0 +1,69 @@
/*************************************************************************//**
* \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;
}
void SHShaderSourceLoader::Write(SHAssetData const* data, AssetPath path)
{
std::ofstream file{ path, std::ios::binary | std::ios::out | std::ios::trunc };
auto asset = *dynamic_cast<SHShaderAsset const*>(data);
file.write(
reinterpret_cast<char const*>(&asset.shaderType), sizeof(uint8_t)
);
size_t const byteCount = sizeof(uint32_t) * asset.spirvBinary.size();
file.write(
reinterpret_cast<char const*>(&byteCount), sizeof(size_t)
);
file.write(
reinterpret_cast<char const*>(asset.spirvBinary.data()), byteCount
);
file.close();
}
}

View File

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

View File

@ -0,0 +1,95 @@
/******************************************************************************
* \file SHTextBasedLoader.cpp
* \author Loh Xiao Qi
* \date 28 October 2022
* \brief
*
* \copyright Copyright (c) 2021 Digipen Institute of Technology. Reproduction
* or disclosure of this file or its contents without the prior
* written consent of Digipen Institute of Technology is prohibited.
******************************************************************************/
#include "SHpch.h"
#include "SHTextBasedLoader.h"
#include "Assets/Asset Types/SHSceneAsset.h"
#include "Assets/Asset Types/SHPrefabAsset.h"
#include "Assets/Asset Types/SHMaterialAsset.h"
#include <fstream>
#include <sstream>
namespace SHADE
{
SHAssetData* SHTextBasedLoader::Load(AssetPath path)
{
std::ifstream file{ path, std::ios::in };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open text File: {}", path.string());
return nullptr;
}
std::stringstream stream;
stream << file.rdbuf();
std::string content = stream.str();
SHAssetData* result;
if (path.extension().string() == SCENE_EXTENSION)
{
auto data = new SHSceneAsset();
data->name = path.stem().string();
data->data = std::move(content);
result = data;
}
else if (path.extension().string() == PREFAB_EXTENSION)
{
auto data = new SHPrefabAsset();
data->name = path.stem().string();
data->data = std::move(content);
result = data;
}
else if (path.extension().string() == MATERIAL_EXTENSION)
{
auto data = new SHMaterialAsset();
data->name = path.stem().string();
data->data = std::move(content);
result = data;
}
file.close();
return result;
}
void SHTextBasedLoader::Write(SHAssetData const* data, AssetPath path)
{
std::ofstream file{ path, std::ios::out | std::ios::trunc };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open text File: {}", path.string());
return;
}
if (path.extension().string() == SCENE_EXTENSION)
{
auto scene = dynamic_cast<SHSceneAsset const*>(data);
file << scene->data;
}
else if (path.extension().string() == PREFAB_EXTENSION)
{
auto prefab = dynamic_cast<SHPrefabAsset const*>(data);
file << prefab->data;
}
else if (path.extension().string() == MATERIAL_EXTENSION)
{
auto material = dynamic_cast<SHMaterialAsset const*>(data);
file << material->data;
}
file.close();
}
}

View File

@ -0,0 +1,21 @@
/******************************************************************************
* \file Header.h
* \author Loh Xiao Qi
* \date 28 October 2022
* \brief
*
* \copyright Copyright (c) 2021 Digipen Institute of Technology. Reproduction
* or disclosure of this file or its contents without the prior
* written consent of Digipen Institute of Technology is prohibited.
******************************************************************************/
#pragma once
#include "SHAssetLoader.h"
namespace SHADE
{
struct SHTextBasedLoader : SHAssetLoader
{
SHAssetData* Load(AssetPath path) override;
void Write(SHAssetData const* data, AssetPath path) override;
};
}

View File

@ -0,0 +1,110 @@
/*************************************************************************//**
* \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;
}
void SHTextureLoader::Write(SHAssetData const* data, AssetPath path)
{
std::ofstream file{ path, std::ios::out | std::ios::binary };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open file for writing texture file: {}", path.string());
}
auto asset = *dynamic_cast<SHTextureAsset const*>(data);
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();
}
}

View File

@ -10,25 +10,15 @@
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#define TINYDDSLOADER_IMPLEMENTATION
#include "../SHAssetMacros.h"
#include "../Asset Types/SHTextureAsset.h"
#include "tinyddsloader.h"
#include "Assets/Asset Types/SHTextureAsset.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;
void Write(SHAssetData const* data, 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

@ -11,7 +11,6 @@
*****************************************************************************/
#pragma once
#include "Filesystem/SHFileSystem.h"
#include "Assets/SHAssetMacros.h"
#include "SH_API.h"
@ -23,6 +22,5 @@ namespace SHADE
AssetID id;
AssetType type;
AssetPath path;
FolderLocation location;
};
}

View File

@ -42,62 +42,84 @@ constexpr std::string_view ASSET_META_VER { "1.0" };
// Asset type enum
enum class AssetType : AssetTypeMeta
{
INVALID = 0,
AUDIO = 1,
INVALID,
SHADER,
MATERIAL,
IMAGE,
TEXTURE,
MESH,
SCRIPT,
SCENE,
PREFAB,
AUDIO_WAV,
DDS,
SHADER_BUILT_IN,
TEXTURE,
MESH,
SCENE,
PREFAB,
MATERIAL,
MAX_COUNT
};
constexpr size_t TYPE_COUNT{ static_cast<size_t>(AssetType::MAX_COUNT) };
//Directory
#ifdef _PUBLISH
constexpr std::string_view ASSET_ROOT {"Assets"};
constexpr std::string_view ASSET_ROOT{ "Assets" };
constexpr std::string_view BUILT_IN_ASSET_ROOT {"Built_In"};
#else
constexpr std::string_view ASSET_ROOT {"../../Assets"};
constexpr std::string_view BUILT_IN_ASSET_ROOT{ "../../Built_In" };
#endif
// INTERNAL ASSET PATHS
constexpr std::string_view SCENE_FOLDER{ "/Scenes/" };
constexpr std::string_view PREFAB_FOLDER{ "/Prefabs/" };
constexpr std::string_view MATERIAL_FOLDER{ "/Materials/" };
// ASSET EXTENSIONS
constexpr std::string_view META_EXTENSION {".shmeta"};
constexpr std::string_view IMAGE_EXTENSION {".png"};
constexpr std::string_view AUDIO_EXTENSION {".ogg"};
constexpr std::string_view AUDIO_WAV_EXTENSION {".wav"};
constexpr std::string_view SHADER_EXTENSION {".glsl"};
constexpr std::string_view SHADER_EXTENSION{ ".shshader" };
constexpr std::string_view SHADER_BUILT_IN_EXTENSION{".shshaderb"};
constexpr std::string_view SCRIPT_EXTENSION {".cs"};
constexpr std::string_view SCENE_EXTENSION {".SHADE"};
constexpr std::string_view PREFAB_EXTENSION {".SHPrefab"};
constexpr std::string_view MATERIAL_EXTENSION {".SHMat"};
constexpr std::string_view SCENE_EXTENSION {".shade"};
constexpr std::string_view PREFAB_EXTENSION {".shprefab"};
constexpr std::string_view MATERIAL_EXTENSION {".shmat"};
constexpr std::string_view TEXTURE_EXTENSION {".shtex"};
constexpr std::string_view DDS_EXTENSION {".dds"};
constexpr std::string_view FBX_EXTENSION {".fbx"};
constexpr std::string_view GLTF_EXTENSION {".gltf"};
constexpr std::string_view MESH_EXTENSION {".shmesh"};
constexpr std::string_view EXTENSIONS[] = {
AUDIO_EXTENSION,
SHADER_EXTENSION,
SHADER_BUILT_IN_EXTENSION,
MATERIAL_EXTENSION,
IMAGE_EXTENSION,
TEXTURE_EXTENSION,
DDS_EXTENSION,
MESH_EXTENSION,
SCRIPT_EXTENSION,
SCENE_EXTENSION,
PREFAB_EXTENSION,
AUDIO_WAV_EXTENSION,
};
// EXTERNAL EXTENSIONS
constexpr std::string_view GLSL_EXTENSION{ ".glsl" };
constexpr std::string_view DDS_EXTENSION{ ".dds" };
constexpr std::string_view FBX_EXTENSION{ ".fbx" };
constexpr std::string_view GLTF_EXTENSION{ ".gltf" };
constexpr std::string_view EXTERNALS[] = {
GLSL_EXTENSION,
DDS_EXTENSION,
FBX_EXTENSION,
GLTF_EXTENSION
};
constexpr size_t TYPE_COUNT {static_cast<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
constexpr std::string_view FILE_NOT_FOUND_ERR {"FILE NOT FOUND"};

View File

@ -10,26 +10,33 @@
#include "SHpch.h"
#include <random>
#include <chrono>
#include <ranges>
#include "SHAssetManager.h"
#include "SHAssetMetaHandler.h"
#include "Libraries/Loaders/SHMeshLoader.h"
#include "Libraries/Loaders/SHTextureLoader.h"
#include "Libraries/Loaders/SHShaderSourceLoader.h"
#include "Libraries/Loaders/SHTextBasedLoader.h"
#include "Libraries/Compilers/SHMeshCompiler.h"
#include "Libraries/Compilers/SHTextureCompiler.h"
#include "Libraries/Compilers/SHShaderSourceCompiler.h"
#include "Filesystem/SHFileSystem.h"
#include "Libraries/SHAssimpLibrary.h"
#include "Libraries/SHMeshLoader.h"
#include "Libraries/SHTextureLoader.h"
#include "Libraries/SHMeshCompiler.h"
#include "Libraries/SHTextureCompiler.h"
namespace SHADE
{
FolderPointer SHAssetManager::folderRoot{ nullptr };
FMOD::System* SHAssetManager::audioSystem;
std::unordered_map<AssetID, SHSound >* SHAssetManager::audioSoundList;
std::vector<SHAssetLoader*> SHAssetManager::loaders(TYPE_COUNT);
std::vector<SHAsset> SHAssetManager::assetCollection;
std::unordered_map<AssetID, SHAsset> SHAssetManager::assetCollection;
std::unordered_map<AssetID, SHAssetData * const> SHAssetManager::assetData;
/****************************************************************************
* \brief Static function to generate asset ID.
@ -44,7 +51,7 @@ namespace SHADE
result |= unique;
while (result == 0)
while (result == 0 || assetCollection.contains(result))
{
result = GenerateAssetID(type);
}
@ -54,17 +61,25 @@ namespace SHADE
/****************************************************************************
* \brief Deallocate all memory used by asset data
****************************************************************************/
void SHAssetManager::Unload() noexcept
{
}
void SHAssetManager::Unload(AssetID assetId) noexcept
{
// TODO
}
AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept
void SHAssetManager::Exit() noexcept
{
delete loaders[static_cast<size_t>(AssetType::SHADER)];
delete loaders[static_cast<size_t>(AssetType::TEXTURE)];
delete loaders[static_cast<size_t>(AssetType::MESH)];
delete loaders[static_cast<size_t>(AssetType::SCENE)];
for (auto const& data : std::ranges::views::values(assetData))
{
delete data;
}
}
AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept
{
if (!IsRecognised(path.extension().string().c_str()))
{
@ -91,16 +106,9 @@ namespace SHADE
switch(type)
{
case AssetType::SCENE:
folder = "scenes/";
break;
case AssetType::PREFAB:
folder = "prefabs/";
break;
case AssetType::MATERIAL:
folder = "materials/";
case AssetType::SHADER:
case AssetType::SHADER_BUILT_IN:
folder = "Shaders/";
break;
default:
@ -120,9 +128,17 @@ namespace SHADE
*
* \return const& to unordered_map<AssetName, AssetID>
****************************************************************************/
std::vector<SHAsset> const& SHAssetManager::GetAllAssets() noexcept
std::vector<SHAsset> SHAssetManager::GetAllAssets() noexcept
{
return assetCollection;
std::vector<SHAsset> result;
result.reserve(assetCollection.size());
for (auto const& asset : std::ranges::views::values(assetCollection))
{
result.push_back(asset);
}
return result;
}
/****************************************************************************
@ -135,41 +151,113 @@ namespace SHADE
****************************************************************************/
AssetID SHAssetManager::CreateNewAsset(AssetType type, AssetName name) noexcept
{
AssetID id{ GenerateAssetID(type) };
SHAsset meta;
meta.id = id;
meta.type = type;
std::string newPath{ ASSET_ROOT };
switch (type)
{
case AssetType::PREFAB:
newPath += PREFAB_FOLDER;
break;
std::string folder;
//TODO implement folder choosing
//switch (type)
//{
//default:
// folder = "";
// break;
//}
AssetPath path{ std::string{ASSET_ROOT} + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) };
case AssetType::SCENE:
newPath += SCENE_FOLDER;
break;
SHAssetMetaHandler::WriteMetaData(meta);
case AssetType::MATERIAL:
newPath += MATERIAL_FOLDER;
break;
assetCollection.push_back(meta);
default:
SHLOG_ERROR("Asset type of {} not an internal asset type, cannot be created", name);
return 0;
}
auto id = GenerateAssetID(type);
SHAsset asset{
name,
id,
type,
newPath
};
assetCollection.insert({
id,
SHAsset(
name,
id,
type,
newPath
)
});
return id;
}
AssetID SHAssetManager::CreateAsset(AssetName name, AssetType type) noexcept
{
AssetID id = GenerateAssetID(type);
bool SHAssetManager::SaveAsset(AssetID id) noexcept
{
if (assetCollection.contains(id))
{
auto const& asset = assetCollection[id];
if (
asset.type == AssetType::SCENE ||
asset.type == AssetType::PREFAB ||
asset.type == AssetType::MATERIAL
)
{
if (assetData.contains(id))
{
auto const data = assetData.at(id);
loaders[static_cast<size_t>(asset.type)]->Write(data, asset.path);
SHAssetMetaHandler::WriteMetaData(asset);
return true;
}
SHLOG_ERROR("Asset data has not been written into, cannot be saved: {}",
asset.path.filename().string());
return false;
}
}
SHLOG_WARNING("Asset id: {} not an internal asset type, save cannot be triggered", id);
return false;
}
bool SHAssetManager::DeleteAsset(AssetID id) noexcept
{
if (assetCollection.contains(id))
{
auto const& asset = assetCollection[id];
if (
asset.type == AssetType::SCENE ||
asset.type == AssetType::PREFAB ||
asset.type == AssetType::MATERIAL
)
{
return (DeleteLocalFile(asset.path) && DeleteLocalFile(asset.path.string() + META_EXTENSION.data()));
}
SHLOG_WARNING("Asset id: {} not an internal asset type, file deletion not allowed", id);
}
SHLOG_WARNING("Asset id does not exist, nothing was deleted: {}", id);
return false;
}
//AssetID SHAssetManager::CreateAsset(AssetName name, AssetType type) noexcept
//{
// AssetID id = GenerateAssetID(type);
// assetCollection.emplace_back(
// name,
// id,
// type,
// GenerateNewPath(name, type)
// );
// return id;
//}
assetCollection.emplace_back(
name,
id,
type,
GenerateNewPath(name, type),
0
);
return id;
}
/****************************************************************************
* \brief Import new asset from outside editor window.
*
@ -192,7 +280,8 @@ namespace SHADE
std::filesystem::copy(path, newPath);
assetCollection.push_back(CreateAssetFromPath(newPath));
auto asset = CreateAssetFromPath(newPath);
assetCollection.insert({asset.id, asset});
return id;
}
@ -206,7 +295,60 @@ namespace SHADE
}
bool SHAssetManager::IsRecognised(char const* ext) noexcept
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 : std::ranges::views::values(assetCollection))
{
if (asset.type == type)
{
result.push_back(asset);
}
}
return result;
}
AssetID SHAssetManager::CompileAsset(AssetPath const& path) noexcept
{
SHAsset newAsset
{
.name = path.stem().string()
};
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.insert({ newAsset.id, newAsset });
SHAssetMetaHandler::WriteMetaData(newAsset);
return newAsset.id;
}
FolderPointer SHAssetManager::GetRootFolder() noexcept
{
return folderRoot;
}
bool SHAssetManager::IsRecognised(char const* ext) noexcept
{
for (auto const& e : EXTENSIONS)
{
@ -231,19 +373,84 @@ namespace SHADE
return result;
}
void SHAssetManager::InitLoaders() noexcept
void SHAssetManager::CompileAll() noexcept
{
loaders[static_cast<size_t>(AssetType::AUDIO)] = nullptr;
loaders[static_cast<size_t>(AssetType::SHADER)] = nullptr;
loaders[static_cast<size_t>(AssetType::MATERIAL)] = nullptr;
loaders[static_cast<size_t>(AssetType::IMAGE)] = dynamic_cast<SHAssetLoader*>(new SHTextureLoader());
loaders[static_cast<size_t>(AssetType::TEXTURE)] = nullptr;
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()
};
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
};
meshAsset.path = SHMeshCompiler::CompileMeshBinary(*mesh, path).value();
meshAsset.id = GenerateAssetID(AssetType::MESH);
meshAsset.type = AssetType::MESH;
assetCollection.insert({ meshAsset.id, meshAsset });
SHAssetMetaHandler::WriteMetaData(meshAsset);
}
continue;
}
assetCollection.insert({ newAsset.id, newAsset });
SHAssetMetaHandler::WriteMetaData(newAsset);
}
}
bool SHAssetManager::DeleteLocalFile(AssetPath path) noexcept
{
//TODO Move this to dedicated library
return std::filesystem::remove(path);
}
void SHAssetManager:: InitLoaders() noexcept
{
loaders[static_cast<size_t>(AssetType::SHADER)] = dynamic_cast<SHAssetLoader*>(new SHShaderSourceLoader());
loaders[static_cast<size_t>(AssetType::SHADER_BUILT_IN)] = loaders[static_cast<size_t>(AssetType::SHADER)];
loaders[static_cast<size_t>(AssetType::TEXTURE)] = dynamic_cast<SHAssetLoader*>(new SHTextureLoader());
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;
loaders[static_cast<size_t>(AssetType::SCENE)] = dynamic_cast<SHAssetLoader*>(new SHTextBasedLoader());
loaders[static_cast<size_t>(AssetType::PREFAB)] = loaders[static_cast<size_t>(AssetType::SCENE)];
loaders[static_cast<size_t>(AssetType::MATERIAL)] = loaders[static_cast<size_t>(AssetType::SCENE)];
}
/****************************************************************************
@ -251,8 +458,9 @@ namespace SHADE
****************************************************************************/
void SHAssetManager::Load() noexcept
{
//CompileAll();
BuildAssetCollection();
InitLoaders();
BuildAssetCollection();
//LoadAllData();
}
@ -261,7 +469,7 @@ namespace SHADE
****************************************************************************/
void SHAssetManager::LoadAllData() noexcept
{
for (auto const& asset : assetCollection)
for (auto const& asset : std::ranges::views::values(assetCollection))
{
SHAssetData* data = loaders[static_cast<size_t>(asset.type)]->Load(asset.path);
assetData.emplace(asset.id, data);
@ -284,17 +492,8 @@ namespace SHADE
return data;
}
void SHAssetManager::BuildAssetCollection() noexcept
{
for (auto const& dir : std::filesystem::recursive_directory_iterator{ASSET_ROOT})
{
if (dir.is_regular_file())
{
if (dir.path().extension().string() == META_EXTENSION.data())
{
assetCollection.push_back(SHAssetMetaHandler::RetrieveMetaData(dir.path()));
}
}
}
}
void SHAssetManager::BuildAssetCollection() noexcept
{
SHFileSystem::BuildDirectory(ASSET_ROOT.data(), folderRoot, assetCollection);
}
}

View File

@ -10,10 +10,12 @@
******************************************************************************/
#pragma once
#include "tinyddsloader.h"
#include "SHAsset.h"
#include "Asset Types/SHAssetData.h"
#include "Libraries/SHAssetLoader.h"
#include <memory>
#include "Assets/Libraries/Loaders/SHAssetLoader.h"
#include "Filesystem/SHFolder.h"
#include "SH_API.h"
@ -26,16 +28,16 @@ namespace SHADE
* \brief Static function to generate resource ID.
****************************************************************************/
static AssetID GenerateAssetID(AssetType type) noexcept;
static AssetPath GenerateLocalPath(AssetPath path) noexcept;
static AssetPath GenerateNewPath(AssetName name, AssetType type);
/****************************************************************************
* \brief Deallocate all memory used by resource data
****************************************************************************/
static void Unload() noexcept;
static void Unload(AssetID assetId) noexcept;
static void Exit() noexcept;
static void Unload(AssetID assetId) noexcept;
/****************************************************************************
* \brief Load all resources that are in the folder
@ -47,7 +49,7 @@ namespace SHADE
*
* \return const& to unordered_map<AssetName, AssetID>
****************************************************************************/
static std::vector<SHAsset> const& GetAllAssets() noexcept;
static std::vector<SHAsset> GetAllAssets() noexcept;
/****************************************************************************
* \brief Create record for new resource. CAN ONLY CREATE FOR CUSTOM
@ -57,8 +59,9 @@ namespace SHADE
* \param name of resource
* \return resource id generated for new asset
****************************************************************************/
static AssetID CreateNewAsset(AssetType, AssetName) noexcept;
static AssetID CreateAsset(AssetName name, AssetType type) noexcept;
static AssetID CreateNewAsset(AssetType type, AssetName name) noexcept;
static bool SaveAsset(AssetID id) noexcept;
static bool DeleteAsset(AssetID id) noexcept;
/****************************************************************************
* \brief Import new resource from outside editor window.
@ -76,22 +79,37 @@ namespace SHADE
// -------------------------------------------------------------------------/
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> GetData(AssetID id) noexcept;
template<typename T>
static std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> GetConstData(AssetID id) noexcept;
static std::vector<SHAssetData const*> GetAllDataOfType(AssetType type) noexcept;
static std::vector<SHAsset> GetAllRecordOfType(AssetType type) noexcept;
static AssetID CompileAsset(AssetPath const& path) noexcept;
static FolderPointer GetRootFolder() noexcept;
private:
/****************************************************************************
* \brief Load resource data into memory
****************************************************************************/
static void InitLoaders() noexcept;
static void LoadAllData() noexcept;
static SHAssetData* LoadData(SHAsset const& asset) noexcept;
inline static void BuildAssetCollection() noexcept;
static bool IsRecognised(char const*) noexcept;
static SHAsset CreateAssetFromPath(AssetPath path) noexcept;
static void InitLoaders() noexcept;
static void CompileAll() noexcept;
static bool DeleteLocalFile(AssetPath path) noexcept;
//TODO use this function to create asset data internall at all calls to generate id
//static AssetID CreateAsset(AssetName name, AssetType type) noexcept;
static FolderPointer folderRoot;
static FMOD::System* audioSystem;
static std::unordered_map<AssetID,SHSound>* audioSoundList;
@ -99,7 +117,7 @@ namespace SHADE
static std::vector<SHAssetLoader*> loaders;
// For all resources
static std::vector<SHAsset> assetCollection;
static std::unordered_map<AssetID, SHAsset> assetCollection;
static std::unordered_map<AssetID, SHAssetData * const> assetData;
};
}

View File

@ -4,16 +4,16 @@
namespace SHADE
{
template<typename T>
std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> SHAssetManager::GetData(AssetID id) noexcept
std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T* const> SHAssetManager::GetData(AssetID id) noexcept
{
if (!assetData.contains(id))
{
for (auto const& asset : assetCollection)
for (auto const& asset : std::ranges::views::values(assetCollection))
{
if (asset.id == id)
{
assetData.emplace(id, LoadData(asset));
return dynamic_cast<T const* const>(assetData[id]);
return dynamic_cast<T* const>(assetData[id]);
}
}
@ -21,6 +21,27 @@ namespace SHADE
return nullptr;
}
return dynamic_cast<T const* const>(assetData[id]);
return dynamic_cast<T* const>(assetData[id]);
}
template<typename T>
std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const * const> SHAssetManager::GetConstData(AssetID id) noexcept
{
if (!assetData.contains(id))
{
for (auto const& asset : std::ranges::views::values(assetCollection))
{
if (asset.id == id)
{
assetData.emplace(id, LoadData(asset));
return dynamic_cast<T const* const>(assetData[id]);
}
}
SHLOG_ERROR("Asset ID provided does not exist: {}", id);
return nullptr;
}
return dynamic_cast<T const* const>(assetData[id]);
}
}

View File

@ -213,5 +213,14 @@ namespace SHADE
return SHSerialization::DeserializeEntityToSceneFromString(data);
}*/
EntityID SHEntityManager::GetEntityByName(std::string const& name) noexcept
{
EntityID result = MAX_EID;
for (auto& entity : entityVec)
{
if (entity->name == name)
result = entity->GetEID();
}
return result;
}
}

View File

@ -209,6 +209,8 @@ namespace SHADE
//static EntityID DuplicateEntity(EntityID eid) noexcept;
static EntityID GetEntityByName(std::string const& name) noexcept;
protected:

View File

@ -6,12 +6,12 @@
namespace SHADE
{
//TODO: Convert to RTTR?
constexpr auto DRAG_EID = "DragEID";
constexpr auto DRAG_RESOURCE = "DragResource";
struct SHDragDrop
{
using DragDropTag = std::string_view;
static constexpr DragDropTag DRAG_EID = "DragEID";
static constexpr DragDropTag DRAG_RESOURCE = "DragResource";
static bool BeginSource(ImGuiDragDropFlags const flags = 0);
/**
* \brief Ends the DragDrop Source. ONLY CALL IF BeginSource returns true

View File

@ -4,14 +4,16 @@
#include "Editor/IconsMaterialDesign.h"
#include "Editor/SHImGuiHelpers.hpp"
#include <imgui.h>
#include <imgui_internal.h>
#include "Assets/SHAssetManager.h"
#include "Editor/IconsFontAwesome6.h"
#include "Editor/DragDrop/SHDragDrop.hpp"
namespace SHADE
{
SHAssetBrowser::SHAssetBrowser()
:SHEditorWindow("\xee\x8b\x87 Asset Browser", ImGuiWindowFlags_MenuBar)
:SHEditorWindow("\xee\x8b\x87 Asset Browser", ImGuiWindowFlags_MenuBar), rootFolder(SHAssetManager::GetRootFolder()), prevFolder(rootFolder), currentFolder(rootFolder)
{
}
@ -23,62 +25,140 @@ namespace SHADE
void SHAssetBrowser::Update()
{
SHEditorWindow::Update();
if(Begin())
if (Begin())
{
RecursivelyDrawTree(rootFolder);
DrawMenuBar();
auto const& assets = SHAssetManager::GetAllAssets();
if(ImGui::BeginTable("AssetBrowserTable", 3))
{
ImGui::TableNextColumn();
ImGui::TableHeader("Asset ID");
ImGui::TableNextColumn();
ImGui::TableHeader("Name");
ImGui::TableNextColumn();
ImGui::TableHeader("Type");
for(SHAsset const& asset : assets)
{
DrawAsset(asset);
}
ImGui::EndTable();
}
DrawCurrentFolder();
}
ImGui::End();
}
void SHAssetBrowser::DrawMenuBar()
{
if(ImGui::BeginMenuBar())
if (ImGui::BeginMenuBar())
{
ImGui::EndMenuBar();
}
}
void SHAssetBrowser::DrawAsset(SHAsset const& asset)
ImRect SHAssetBrowser::RecursivelyDrawTree(FolderPointer folder)
{
ImGui::PushID(asset.id);
ImGui::BeginGroup();
ImGui::TableNextColumn();
ImGui::Selectable(std::format("{}", asset.id).data(), false, ImGuiSelectableFlags_SpanAllColumns);
if(SHDragDrop::BeginSource())
auto const& subFolders = folder->subFolders;
auto const& files = folder->files;
const bool isSelected = std::ranges::find(selectedFolders, folder) != selectedFolders.end();
ImGuiTreeNodeFlags flags = (subFolders.empty() && files.empty()) ? ImGuiTreeNodeFlags_Leaf : ImGuiTreeNodeFlags_OpenOnArrow;
if (isSelected)
flags |= ImGuiTreeNodeFlags_Selected;
if (folder == rootFolder)
flags |= ImGuiTreeNodeFlags_DefaultOpen;
bool isOpen = ImGui::TreeNodeEx(folder, flags, "%s %s", ICON_MD_FOLDER, folder->name.data());
const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
if(ImGui::IsItemClicked())
{
auto id = asset.id;
ImGui::Text("Moving Asset: %zu", id);
SHDragDrop::SetPayload<AssetID>(DRAG_RESOURCE, &id);
SHDragDrop::EndSource();
selectedFolders.clear();
selectedFolders.push_back(folder);
}
if (isOpen)
{
const ImColor treeLineColor = ImGui::GetColorU32(ImGuiCol_CheckMark);
const float horizontalOffset = 0.0f;
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 vertLineStart = ImGui::GetCursorScreenPos();
vertLineStart.x += horizontalOffset;
ImVec2 vertLineEnd = vertLineStart;
for (auto const& subFolder : subFolders)
{
const float horizontalLineSize = 8.0f;
const ImRect childRect = RecursivelyDrawTree(subFolder);
const float midPoint = (childRect.Min.y + childRect.Max.y) * 0.5f;
drawList->AddLine(ImVec2(vertLineStart.x, midPoint), ImVec2(vertLineStart.x + horizontalLineSize, midPoint), treeLineColor, 1);
vertLineEnd.y = midPoint;
}
for (auto const& file : files)
{
const float horizontalLineSize = 25.0f;
const ImRect childRect = DrawFile(file);
const float midPoint = (childRect.Min.y + childRect.Max.y) * 0.5f;
drawList->AddLine(ImVec2(vertLineStart.x, midPoint), ImVec2(vertLineStart.x + horizontalLineSize, midPoint), treeLineColor, 1);
vertLineEnd.y = midPoint;
}
drawList->AddLine(vertLineStart, vertLineEnd, treeLineColor, 1);
ImGui::TreePop();
}
return nodeRect;
}
void SHAssetBrowser::DrawCurrentFolder()
{
//auto const& subFolders = currentFolder->subFolders;
//ImVec2 initialCursorPos = ImGui::GetCursorPos();
//ImVec2 initialRegionAvail = ImGui::GetContentRegionAvail();
//int maxTiles = initialRegionAvail.x / tileWidth;
//float maxX = (maxTiles - 1)*tileWidth;
//ImVec2 tilePos = initialCursorPos;
//for (auto const& subFolder : subFolders)
//{
// ImGui::SetCursorPos(tilePos);
// ImGui::BeginGroup();
// ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, {0.0f, 0.0f});
// ImGui::Button(ICON_MD_FOLDER, {tileWidth});
// ImGui::Text(subFolder->name.data());
// ImGui::PopStyleVar();
// ImGui::EndGroup();
// if(tilePos.x >= maxX)
// {
// tilePos.x = initialCursorPos.x;
// }
// else
// {
// ImGui::SameLine();
// tilePos.x += tileWidth;
// }
//}
}
ImRect SHAssetBrowser::DrawFile(SHFile const& file) noexcept
{
if (file.assetMeta == nullptr)
return ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
const bool isSelected = std::ranges::find(selectedAssets, file.assetMeta->id) != selectedAssets.end();
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf;
if (isSelected)
flags |= ImGuiTreeNodeFlags_Selected;
std::string icon{};
switch(file.assetMeta->type)
{
case AssetType::INVALID: break;
case AssetType::SHADER: icon = ICON_FA_FILE_CODE; break;
case AssetType::SHADER_BUILT_IN: icon = ICON_FA_FILE_CODE; break;
case AssetType::TEXTURE: icon = ICON_FA_IMAGES; break;
case AssetType::MESH: icon = ICON_FA_CUBES; break;
case AssetType::SCENE: icon = ICON_MD_IMAGE; break;
case AssetType::PREFAB: icon = ICON_FA_BOX_OPEN; break;
case AssetType::MATERIAL: break;
case AssetType::MAX_COUNT: break;
default: ;
}
ImGui::TableNextColumn();
ImGui::Text("%s", asset.name.c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", "Type");
ImGui::EndGroup();
ImGui::PopID();
ImGui::TreeNodeEx(file.assetMeta, flags, "%s %s", icon.data(), file.assetMeta->name.data());
const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
if(SHDragDrop::BeginSource())
{
auto id = file.assetMeta->id;
ImGui::Text("Moving Asset: %s [%zu]", file.name.data(), file.assetMeta->id);
SHDragDrop::SetPayload<AssetID>(SHDragDrop::DRAG_RESOURCE, &id);
SHDragDrop::EndSource();
}
if(ImGui::IsItemClicked())
{
selectedAssets.clear();
selectedAssets.push_back(file.assetMeta->id);
}
ImGui::TreePop();
return nodeRect;
}
}

View File

@ -1,7 +1,9 @@
#pragma once
#include "imgui_internal.h"
#include "Assets/SHAsset.h"
#include "Editor/EditorWindow/SHEditorWindow.h"
#include "Filesystem/SHFolder.h"
namespace SHADE
{
@ -16,9 +18,14 @@ namespace SHADE
void Refresh();
private:
void DrawMenuBar();
void DrawAsset(SHAsset const& asset);
ImRect RecursivelyDrawTree(FolderPointer folder);
void DrawCurrentFolder();
ImRect DrawFile(SHFile const& file) noexcept;
float idColumnWidth, nameColumnWidth, typeColumnWidth;
FolderPointer rootFolder, prevFolder, currentFolder;
std::vector<FolderPointer> selectedFolders;
std::vector<AssetID> selectedAssets;
static constexpr float tileWidth = 50.0f;
};
}
}

View File

@ -6,7 +6,7 @@
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "Editor/SHEditor.hpp"
#include "Editor/SHEditor.h"
#include "Editor/SHImGuiHelpers.hpp"
#include "Editor/SHEditorWidgets.hpp"
#include "SHHierarchyPanel.h"
@ -48,15 +48,28 @@ namespace SHADE
if (Begin())
{
if (skipFrame)
{
ImGui::End();
skipFrame = false;
return;
}
DrawMenuBar();
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
if(const auto root = sceneGraph.GetRoot())
if (const auto root = sceneGraph.GetRoot())
{
auto const& children = root->GetChildren();
for (const auto child : children)
{
RecursivelyDrawEntityNode(child);
if (child)
RecursivelyDrawEntityNode(child);
if (skipFrame)
{
ImGui::End();
return;
}
}
}
else
@ -64,12 +77,36 @@ namespace SHADE
SHLOG_WARNING("Scene Graph root is null! Unable to render hierarchy.")
}
if(ImGui::IsWindowHovered() && !SHDragDrop::hasDragDrop && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
if (ImGui::IsWindowHovered() && !SHDragDrop::hasDragDrop && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
if(auto editor = SHSystemManager::GetSystem<SHEditor>())
if (auto editor = SHSystemManager::GetSystem<SHEditor>())
editor->selectedEntities.clear();
}
ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal);
if (ImGui::IsWindowFocused())
{
if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_A))
{
SelectAllEntities();
}
if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_C))
{
CopySelectedEntities();
}
if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && !ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyReleased(ImGuiKey_V))
{
PasteEntities();
}
if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyReleased(ImGuiKey_V))
{
const auto editor = SHSystemManager::GetSystem<SHEditor>();
if (editor->selectedEntities.size() == 1)
{
PasteEntities(editor->selectedEntities.back());
}
}
}
}
ImGui::End();
}
@ -81,7 +118,7 @@ namespace SHADE
void SHHierarchyPanel::SetScrollTo(EntityID eid)
{
if(eid == MAX_EID)
if (eid == MAX_EID)
return;
scrollTo = eid;
}
@ -93,8 +130,10 @@ namespace SHADE
{
if (ImGui::BeginMenuBar())
{
ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x * 0.75f);
if(ImGui::SmallButton(ICON_MD_DESELECT))
auto size = ImGui::GetWindowSize();
auto g = ImGui::GetCurrentContext();
ImGui::SetCursorPosX(size.x - g->Style.FramePadding.x * 15.0f);
if (ImGui::SmallButton(ICON_MD_CLEAR_ALL))
{
auto editor = SHSystemManager::GetSystem<SHEditor>();
editor->selectedEntities.clear();
@ -119,15 +158,17 @@ namespace SHADE
}
}
ImRect SHHierarchyPanel::RecursivelyDrawEntityNode(SHSceneNode* currentNode)
ImRect SHHierarchyPanel::RecursivelyDrawEntityNode(SHSceneNode* const currentNode)
{
if (currentNode == nullptr)
return {};
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
//Get node data (Children, eid, selected)
auto& children = currentNode->GetChildren();
EntityID eid = currentNode->GetEntityID();
if(scrollTo != MAX_EID && eid == scrollTo)
if (scrollTo != MAX_EID && eid == scrollTo)
{
ImGui::SetScrollHereY();
scrollTo = MAX_EID;
@ -154,23 +195,23 @@ namespace SHADE
if (SHDragDrop::BeginSource())
{
std::string moveLabel = "Moving EID: ";
if(!isSelected)
if (!isSelected)
editor->selectedEntities.push_back(eid);
for(int i = 0; i < static_cast<int>(editor->selectedEntities.size()); ++i)
for (int i = 0; i < static_cast<int>(editor->selectedEntities.size()); ++i)
{
moveLabel.append(std::to_string(editor->selectedEntities[i]));
if(i + 1 < static_cast<int>(editor->selectedEntities.size()))
if (i + 1 < static_cast<int>(editor->selectedEntities.size()))
{
moveLabel.append(", ");
}
}
ImGui::Text(moveLabel.c_str());
SHDragDrop::SetPayload<std::vector<EntityID>>(DRAG_EID, &editor->selectedEntities);
SHDragDrop::SetPayload<std::vector<EntityID>>(SHDragDrop::DRAG_EID, &editor->selectedEntities);
SHDragDrop::EndSource();
}
else if (SHDragDrop::BeginTarget()) //If Received DragDrop
{
if (const std::vector<EntityID>* eidPayload = SHDragDrop::AcceptPayload<std::vector<EntityID>>(DRAG_EID)) //If payload is valid
if (const std::vector<EntityID>* eidPayload = SHDragDrop::AcceptPayload<std::vector<EntityID>>(SHDragDrop::DRAG_EID)) //If payload is valid
{
ParentSelectedEntities(eid);
SHDragDrop::EndTarget();
@ -178,37 +219,43 @@ namespace SHADE
}
//Context menu
if(ImGui::BeginPopupContextItem(std::to_string(eid).c_str()))
if (ImGui::BeginPopupContextItem(std::to_string(eid).c_str()))
{
if(!isSelected)
if (!isSelected)
{
editor->selectedEntities.clear();
editor->selectedEntities.push_back(eid);
}
if(ImGui::Selectable("Copy"))
if (ImGui::Selectable("Copy"))
{
SHClipboardUtilities::WriteToClipboard(SHSerialization::SerializeEntitiesToString(editor->selectedEntities));
CopySelectedEntities();
}
if(ImGui::Selectable("Paste"))
if (ImGui::Selectable("Paste"))
{
SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard()));
PasteEntities();
skipFrame = true;
ImGui::EndPopup();
if (isNodeOpen)
ImGui::TreePop();
return nodeRect;
}
if(ImGui::Selectable("Paste as Child"))
if (ImGui::Selectable("Paste as Child"))
{
SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard(), eid));
PasteEntities(eid);
skipFrame = true;
}
if(ImGui::Selectable(std::format("{} Delete", ICON_MD_DELETE).data()))
if (ImGui::Selectable(std::format("{} Delete", ICON_MD_DELETE).data()))
{
SHEntityManager::DestroyEntity(eid);
}
if((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data()))
if ((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data()))
{
ParentSelectedEntities(MAX_EID);
}
ImGui::EndPopup();
}
//Handle node selection
if (ImGui::IsItemHovered())
{
@ -216,11 +263,11 @@ namespace SHADE
{
if (!isSelected)
{
if(ImGui::IsKeyDown(ImGuiKey_LeftShift))
if (ImGui::IsKeyDown(ImGuiKey_LeftShift))
{
if(editor->selectedEntities.size() >= 1)
if (editor->selectedEntities.size() >= 1)
{
SelectRangeOfEntities(editor->selectedEntities[0], eid);
SelectRangeOfEntities(editor->selectedEntities[0], eid);
}
else editor->selectedEntities.clear();
}
@ -278,12 +325,12 @@ namespace SHADE
auto const editor = SHSystemManager::GetSystem<SHEditor>();
SHEntityParentCommand::EntityParentData entityParentData;
std::vector<EntityID> parentedEIDS;
for(auto const& eid : editor->selectedEntities)
for (auto const& eid : editor->selectedEntities)
{
if(sceneGraph.GetChild(eid, parentEID) == nullptr)
if (sceneGraph.GetChild(eid, parentEID) == nullptr)
{
parentedEIDS.push_back(eid);
if(auto parent = sceneGraph.GetParent(eid))
if (auto parent = sceneGraph.GetParent(eid))
entityParentData[eid].oldParentEID = parent->GetEntityID();
entityParentData[eid].newParentEID = parentEID;
}
@ -298,34 +345,57 @@ namespace SHADE
editor->selectedEntities.clear();
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
sceneGraph.Traverse([&](SHSceneNode* nodePtr)
{
auto eid = nodePtr->GetEntityID();
if(!startSelecting)
{
if(eid == beginEID || eid == endEID)
auto eid = nodePtr->GetEntityID();
if (!startSelecting)
{
startSelecting = true;
editor->selectedEntities.push_back(eid);
}
}
else
{
if(!endSelecting)
{
editor->selectedEntities.push_back(eid);
if(eid == endEID || eid == beginEID)
if (eid == beginEID || eid == endEID)
{
endSelecting = true;
startSelecting = true;
editor->selectedEntities.push_back(eid);
}
}
}
});
else
{
if (!endSelecting)
{
editor->selectedEntities.push_back(eid);
if (eid == endEID || eid == beginEID)
{
endSelecting = true;
}
}
}
});
}
void SHHierarchyPanel::SelectAllEntities()
{
const auto editor = SHSystemManager::GetSystem<SHEditor>();
editor->selectedEntities.clear();
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
sceneGraph.Traverse([&](SHSceneNode* nodePtr)
{
auto eid = nodePtr->GetEntityID();
editor->selectedEntities.push_back(eid);
});
}
void SHHierarchyPanel::CopySelectedEntities()
{
const auto editor = SHSystemManager::GetSystem<SHEditor>();
SHClipboardUtilities::WriteToClipboard(SHSerialization::SerializeEntitiesToString(editor->selectedEntities));
}
void SHHierarchyPanel::PasteEntities(EntityID parentEID)
{
SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard(), parentEID));
}
void SHCreateEntityCommand::Execute()
{
EntityID newEID = SHEntityManager::CreateEntity(eid);
if(eid == MAX_EID)
if (eid == MAX_EID)
eid = newEID;
}
@ -337,9 +407,9 @@ namespace SHADE
void SHEntityParentCommand::Execute()
{
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
for(auto const& eid : entities)
for (auto const& eid : entities)
{
if(entityParentData[eid].newParentEID == MAX_EID)
if (entityParentData[eid].newParentEID == MAX_EID)
sceneGraph.SetParent(eid, nullptr);
else
sceneGraph.SetParent(eid, entityParentData[eid].newParentEID);
@ -349,9 +419,9 @@ namespace SHADE
void SHEntityParentCommand::Undo()
{
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
for(auto const& eid : entities)
for (auto const& eid : entities)
{
if(entityParentData[eid].oldParentEID == MAX_EID)
if (entityParentData[eid].oldParentEID == MAX_EID)
sceneGraph.SetParent(eid, nullptr);
else
sceneGraph.SetParent(eid, entityParentData[eid].oldParentEID);

View File

@ -26,10 +26,14 @@ namespace SHADE
void SetScrollTo(EntityID eid);
private:
void DrawMenuBar() const noexcept;
ImRect RecursivelyDrawEntityNode(SHSceneNode*);
ImRect RecursivelyDrawEntityNode(SHSceneNode* const);
void CreateChildEntity(EntityID parentEID) const noexcept;
void ParentSelectedEntities(EntityID parentEID) const noexcept;
void SelectRangeOfEntities(EntityID beginEID, EntityID EndEID);
void SelectAllEntities();
void CopySelectedEntities();
void PasteEntities(EntityID parentEID = MAX_EID);
bool skipFrame = false;
std::string filter;
bool isAnyNodeSelected = false;
EntityID scrollTo = MAX_EID;

View File

@ -0,0 +1,12 @@
#pragma once
#include "ECS_Base/Components/SHComponent.h"
namespace SHADE
{
template<typename T, std::enable_if_t<std::is_base_of<SHComponent, T>::value, bool> = true>
static void DrawContextMenu(T* component);
template<typename T, std::enable_if_t<std::is_base_of_v<SHComponent, T>, bool> = true>
static void DrawComponent(T* component);
}
#include "SHEditorComponentView.hpp"

View File

@ -13,11 +13,28 @@
#include "Editor/IconsFontAwesome6.h"
#include "ECS_Base/Components/SHComponent.h"
#include "Editor/SHEditorWidgets.hpp"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Physics/Components/SHColliderComponent.h"
#include "Reflection/SHReflectionMetadata.h"
#include "Resource/SHResourceManager.h"
namespace SHADE
{
template<typename T, std::enable_if_t<std::is_base_of<SHComponent, T>::value, bool> = true>
template<typename T>
std::vector<const char*> GetRTTREnumNames()
{
auto const rttrType = rttr::type::get<T>();
if (!rttrType.is_enumeration())
return {};
auto const enumAlign = rttrType.get_enumeration();
auto const names = enumAlign.get_names();
std::vector<const char*> result;
std::transform(names.begin(), names.end(), std::back_inserter(result), [](rttr::string_view const& name) {return name.data(); });
return result;
}
template<typename T, std::enable_if_t<std::is_base_of<SHComponent, T>::value, bool>>
static void DrawContextMenu(T* component)
{
if (!component)
@ -46,13 +63,15 @@ namespace SHADE
ImGui::EndPopup();
}
}
template<typename T, std::enable_if_t<std::is_base_of_v<SHComponent, T>, bool> = true>
template<typename T, std::enable_if_t<std::is_base_of_v<SHComponent, T>, bool>>
static void DrawComponent(T* component)
{
if (!component)
return;
const auto componentType = rttr::type::get(*component);
const auto componentType = rttr::type::get<T>();
ImGui::PushID(SHFamilyID<SHComponent>::GetID<T>());
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::PopID();
ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data()))
{
@ -61,7 +80,8 @@ namespace SHADE
for (auto const& property : properties)
{
auto const& type = property.get_type();
auto tooltip = property.get_metadata(META::tooltip);
bool const& isAngleInRad = property.get_metadata(META::angleInRad).is_valid() ? property.get_metadata(META::angleInRad).template get_value<bool>() : false;
if (type.is_enumeration())
{
auto enumAlign = type.get_enumeration();
@ -75,29 +95,25 @@ namespace SHADE
auto values = enumAlign.get_values();
auto it = std::next(values.begin(), idx);
property.set_value(component, *it);
});
}, tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string());
}
else if (type.is_arithmetic())
{
if (type == rttr::type::get<bool>())
{
SHEditorWidgets::CheckBox(property.get_name().data(), [component, property] {return property.get_value(component).to_bool(); }, [component, property](bool const& result) {property.set_value(component, result); });
SHEditorWidgets::CheckBox(property.get_name().data(), [component, property] {return property.get_value(component).to_bool(); }, [component, property](bool const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string());
}
//else if (type == rttr::type::get<char>())
//{
//
//}
else if (type == rttr::type::get<int8_t>() || type == rttr::type::get<int16_t>() || type == rttr::type::get<int32_t>() || type == rttr::type::get<int64_t>())
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
if (metaMin && metaMax)
{
SHEditorWidgets::SliderInt(property.get_name().data(), metaMin.template get_value<int>(), metaMax.template get_value<int>(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); });
SHEditorWidgets::SliderInt(property.get_name().data(), metaMin.template get_value<int>(), metaMax.template get_value<int>(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string());
}
else
{
SHEditorWidgets::DragInt(property.get_name().data(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); });
SHEditorWidgets::DragInt(property.get_name().data(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string());
}
}
else if (type == rttr::type::get<uint8_t>())
@ -106,11 +122,11 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<uint8_t>(property.get_name().data(), ImGuiDataType_U8, metaMin.template get_value<uint8_t>(), metaMax.template get_value<uint8_t>(), [component, property] {return property.get_value(component).to_uint8(); }, [component, property](uint8_t const& result) {property.set_value(component, result); }, "%zu");
SHEditorWidgets::SliderScalar<uint8_t>(property.get_name().data(), ImGuiDataType_U8, metaMin.template get_value<uint8_t>(), metaMax.template get_value<uint8_t>(), [component, property] {return property.get_value(component).to_uint8(); }, [component, property](uint8_t const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string(), "%zu");
}
else
{
SHEditorWidgets::DragScalar<uint8_t>(property.get_name().data(), ImGuiDataType_U8, [component, property] {return property.get_value(component).to_uint8(); }, [component, property](uint8_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu");
SHEditorWidgets::DragScalar<uint8_t>(property.get_name().data(), ImGuiDataType_U8, [component, property] {return property.get_value(component).to_uint8(); }, [component, property](uint8_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu", tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string());
}
}
else if (type == rttr::type::get<uint16_t>())
@ -119,11 +135,11 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value<uint16_t>(), metaMax.template get_value<uint16_t>(), [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, "%zu");
SHEditorWidgets::SliderScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value<uint16_t>(), metaMax.template get_value<uint16_t>(), [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string(), "%zu");
}
else
{
SHEditorWidgets::DragScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu");
SHEditorWidgets::DragScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu", tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string());
}
}
else if (type == rttr::type::get<uint32_t>())
@ -132,11 +148,11 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value<uint32_t>(), metaMax.template get_value<uint32_t>(), [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, "%zu");
SHEditorWidgets::SliderScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value<uint32_t>(), metaMax.template get_value<uint32_t>(), [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string(), "%zu");
}
else
{
SHEditorWidgets::DragScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu");
SHEditorWidgets::DragScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu", tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string());
}
}
else if (type == rttr::type::get<uint64_t>())
@ -145,11 +161,11 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value<uint64_t>(), metaMax.template get_value<uint64_t>(), [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, "%zu");
SHEditorWidgets::SliderScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value<uint64_t>(), metaMax.template get_value<uint64_t>(), [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string(), "%zu");
}
else
{
SHEditorWidgets::DragScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu");
SHEditorWidgets::DragScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, 0.1f, 0, 0, "%zu", tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string());
}
}
else if (type == rttr::type::get<float>())
@ -157,17 +173,17 @@ namespace SHADE
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
float min{}, max{};
if(metaMin.is_valid())
if (metaMin.is_valid())
min = std::max(metaMin.template get_value<float>(), -FLT_MAX * 0.5f);
if(metaMax.is_valid())
if (metaMax.is_valid())
max = std::min(metaMax.template get_value<float>(), FLT_MAX * 0.5f);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderFloat(property.get_name().data(), min, max, [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); });
SHEditorWidgets::SliderFloat(property.get_name().data(), min, max, [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string());
}
else
{
SHEditorWidgets::DragFloat(property.get_name().data(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); }, "Test");
SHEditorWidgets::DragFloat(property.get_name().data(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string());
}
}
else if (type == rttr::type::get<double>())
@ -176,25 +192,25 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<double>(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value<double>(), metaMax.template get_value<double>(), [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); });
SHEditorWidgets::SliderScalar<double>(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value<double>(), metaMax.template get_value<double>(), [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); }, tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string());
}
else
{
SHEditorWidgets::DragScalar<double>(property.get_name().data(), ImGuiDataType_Double, [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); }, 0.1f);
SHEditorWidgets::DragScalar<double>(property.get_name().data(), ImGuiDataType_Double, [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); }, 0.1f, {}, {}, "%.3f", tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string());
}
}
}
else if (type == rttr::type::get<SHVec4>())
{
SHEditorWidgets::DragVec4(property.get_name().data(), { "X", "Y", "Z", "W" }, [component, property]() {return property.get_value(component).template convert<SHVec4>(); }, [component, property](SHVec4 vec) {return property.set_value(component, vec); });
SHEditorWidgets::DragVec4(property.get_name().data(), { "X", "Y", "Z", "W" }, [component, property]() {return property.get_value(component).template convert<SHVec4>(); }, [component, property](SHVec4 vec) {return property.set_value(component, vec); }, isAngleInRad, tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string());
}
else if (type == rttr::type::get<SHVec3>())
{
SHEditorWidgets::DragVec3(property.get_name().data(), { "X", "Y", "Z" }, [component, property]() {return property.get_value(component).template convert<SHVec3>(); }, [component, property](SHVec3 vec) {return property.set_value(component, vec); });
SHEditorWidgets::DragVec3(property.get_name().data(), { "X", "Y", "Z" }, [component, property]() {return property.get_value(component).template convert<SHVec3>(); }, [component, property](SHVec3 vec) {return property.set_value(component, vec); }, isAngleInRad, tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string());
}
else if (type == rttr::type::get<SHVec2>())
{
SHEditorWidgets::DragVec2(property.get_name().data(), { "X", "Y" }, [component, property]() {return property.get_value(component).template convert<SHVec2>(); }, [component, property](SHVec2 vec) {return property.set_value(component, vec); });
SHEditorWidgets::DragVec2(property.get_name().data(), { "X", "Y" }, [component, property]() {return property.get_value(component).template convert<SHVec2>(); }, [component, property](SHVec2 vec) {return property.set_value(component, vec); }, isAngleInRad, tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string());
}
}
@ -207,8 +223,12 @@ namespace SHADE
{
if (!component)
return;
// Get transform component for extrapolating relative sizes
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(component->GetEID());
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; }, "Is Component Active");
ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data()))
{
@ -216,43 +236,56 @@ namespace SHADE
auto& colliders = component->GetColliders();
int const size = static_cast<int>(colliders.size());
ImGui::BeginChild("Colliders", {0.0f, colliders.empty() ? 1.0f : 250.0f}, true);
std::optional<int> colliderToDelete{std::nullopt};
ImGui::BeginChild("Colliders", { 0.0f, colliders.empty() ? 1.0f : 250.0f }, true);
std::optional<int> colliderToDelete{ std::nullopt };
for (int i{}; i < size; ++i)
{
ImGui::PushID(i);
SHCollider& collider = component->GetCollider(i);
SHCollider* collider = &component->GetCollider(i);
auto cursorPos = ImGui::GetCursorPos();
if (collider.GetType() == SHCollider::Type::BOX)
if (collider->GetType() == SHCollider::Type::BOX)
{
SHEditorWidgets::BeginPanel( std::format("{} Box Collider #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
auto box = reinterpret_cast<SHBoundingBox*>(collider.GetShape());
SHEditorWidgets::DragVec3("Half Extents", { "X", "Y", "Z" }, [box] {return box->GetHalfExtents(); }, [box](SHVec3 const& vec) {box->SetHalfExtents(vec);});
SHEditorWidgets::BeginPanel(std::format("{} Box Collider #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
auto box = reinterpret_cast<SHBoundingBox*>(collider->GetShape());
SHEditorWidgets::DragVec3
(
"Half Extents", { "X", "Y", "Z" },
[box, transformComponent] { return (transformComponent->GetWorldScale() * 2.0f) * box->GetHalfExtents(); },
[collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); });
}
else if (collider.GetType() == SHCollider::Type::SPHERE)
else if (collider->GetType() == SHCollider::Type::SPHERE)
{
SHEditorWidgets::BeginPanel(std::format("{} Sphere Collider #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
auto sphere = reinterpret_cast<SHBoundingSphere*>(collider.GetShape());
SHEditorWidgets::DragFloat("Radius", [sphere] {return sphere->GetRadius(); }, [sphere](float const& value) {sphere->SetRadius(value);});
auto sphere = reinterpret_cast<SHBoundingSphere*>(collider->GetShape());
SHEditorWidgets::DragFloat
(
"Radius",
[sphere, transformComponent]
{
const SHVec3& TF_WORLD_SCALE = transformComponent->GetWorldScale();
const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z });
return sphere->GetRadius() / MAX_SCALE;
},
[collider](float const& value) { collider->SetBoundingSphere(value); });
}
else if (collider.GetType() == SHCollider::Type::CAPSULE)
else if (collider->GetType() == SHCollider::Type::CAPSULE)
{
}
{
SHEditorWidgets::BeginPanel("Offset", { ImGui::GetContentRegionAvail().x, 30.0f });
SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider.GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider.SetPositionOffset(vec); });
SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider->GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider->SetPositionOffset(vec); });
SHEditorWidgets::EndPanel();
}
if(ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data()))
if (ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data()))
{
colliderToDelete = i;
}
SHEditorWidgets::EndPanel();
ImGui::PopID();
}
if(colliderToDelete.has_value())
if (colliderToDelete.has_value())
{
component->RemoveCollider(colliderToDelete.value());
}
@ -260,11 +293,11 @@ namespace SHADE
if (ImGui::BeginMenu("Add Collider"))
{
if(ImGui::Selectable("Box Collider"))
if (ImGui::Selectable("Box Collider"))
{
component->AddBoundingBox();
}
if(ImGui::Selectable("Sphere Collider"))
if (ImGui::Selectable("Sphere Collider"))
{
component->AddBoundingSphere();
}
@ -273,4 +306,63 @@ namespace SHADE
}
else DrawContextMenu(component);
}
}
template<>
static void DrawComponent(SHLightComponent* component)
{
if (!component)
return;
const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data()))
{
DrawContextMenu(component);
static auto const enumAlign = rttr::type::get<SH_LIGHT_TYPE>().get_enumeration();
static std::vector<const char*> list(GetRTTREnumNames<SH_LIGHT_TYPE>());
SHEditorWidgets::ComboBox("Type", list, [component] {return static_cast<int>(component->GetType()); }, [component](int const& idx)
{
component->SetType(static_cast<SH_LIGHT_TYPE>(idx));
});
SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [component]() {return component->GetPosition(); }, [component](SHVec3 const& vec) {component->SetPosition(vec); });
SHEditorWidgets::DragVec3("Direction", { "X", "Y", "Z" }, [component]() {return component->GetDirection(); }, [component](SHVec3 const& vec) {component->SetDirection(vec); });
SHEditorWidgets::ColorPicker("Color", [component]() {return component->GetColor(); }, [component](SHVec4 const& rgba) {component->SetColor(rgba); });
SHEditorWidgets::DragFloat("Strength", [component]() {return component->GetStrength(); }, [component](float const& value) {component->SetStrength(value); });
}
else
{
DrawContextMenu(component);
}
}
template<>
static void DrawComponent(SHRenderable* component)
{
if (!component)
return;
const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data()))
{
DrawContextMenu(component);
Handle<SHMesh> const& mesh = component->GetMesh();
SHEditorWidgets::DragDropReadOnlyField<AssetID>("Mesh", std::to_string(SHResourceManager::GetAssetID<SHMesh>(mesh).value_or(0)).data(), [component]()
{
Handle<SHMesh> const& mesh = component->GetMesh();
return SHResourceManager::GetAssetID<SHMesh>(mesh).value_or(0);
},
[component](AssetID const& id)
{
component->SetMesh(SHResourceManager::LoadOrGet<SHMesh>(id));
}, SHDragDrop::DRAG_RESOURCE);
}
else
{
DrawContextMenu(component);
}
}
}

View File

@ -1,6 +1,6 @@
#include "SHpch.h"
#include "Editor/SHEditor.hpp"
#include "Editor/SHEditor.h"
#include "SHEditorInspector.h"
#include "ECS_Base/SHECSMacros.h"
@ -10,18 +10,15 @@
#include "Editor/SHImGuiHelpers.hpp"
#include "Editor/SHEditorWidgets.hpp"
#include "SHEditorComponentView.hpp"
#include "ECS_Base/UnitTesting/SHTestComponents.h"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Scripting/SHScriptEngine.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "AudioSystem/SHAudioSystem.h"
#include "Physics/Components/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h"
#include "Camera/SHCameraComponent.h"
#include "Camera/SHCameraArmComponent.h"
#include "SHEditorComponentView.h"
namespace SHADE
{
@ -31,8 +28,17 @@ namespace SHADE
bool selected = false;
if(!SHComponentManager::HasComponent<ComponentType>(eid))
{
if(selected = ImGui::Selectable(std::format("Add {}", rttr::type::get<ComponentType>().get_name().data()).data()); selected)
const char* componentName = rttr::type::get<ComponentType>().get_name().data();
if(selected = ImGui::Selectable(std::format("Add {}", componentName).data()); selected)
SHComponentManager::AddComponent<ComponentType>(eid);
if(ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Adds", componentName); ImGui::SameLine();
ImGui::TextColored(ImGuiColors::green, "%s", componentName); ImGui::SameLine();
ImGui::Text("to this entity", componentName);
ImGui::EndTooltip();
}
}
return selected;
}
@ -43,13 +49,26 @@ namespace SHADE
bool selected = false;
if (!SHComponentManager::HasComponent<ComponentType>(eid))
{
if(selected = ImGui::Selectable(std::format("Add {}", rttr::type::get<ComponentType>().get_name().data()).data()); selected)
const char* componentName = rttr::type::get<ComponentType>().get_name().data();
if(selected = ImGui::Selectable(std::format("Add {}", componentName).data()); selected)
{
if(SHComponentManager::GetComponent_s<EnforcedComponent>(eid) == nullptr)
SHComponentManager::AddComponent<EnforcedComponent>(eid);
SHComponentManager::AddComponent<ComponentType>(eid);
}
if(ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Adds", componentName); ImGui::SameLine();
ImGui::TextColored(ImGuiColors::green, "%s", componentName); ImGui::SameLine();
ImGui::Text("to this entity", componentName);
ImGui::Text("Adds"); ImGui::SameLine();
ImGui::TextColored(ImGuiColors::red, "%s", rttr::type::get<EnforcedComponent>().get_name().data()); ImGui::SameLine();
ImGui::Text("if the entity does not already have it");
ImGui::EndTooltip();
}
}
return selected;
}
@ -101,6 +120,10 @@ namespace SHADE
{
DrawComponent(rigidbodyComponent);
}
if(auto lightComponent = SHComponentManager::GetComponent_s<SHLightComponent>(eid))
{
DrawComponent(lightComponent);
}
if (auto cameraComponent = SHComponentManager::GetComponent_s<SHCameraComponent>(eid))
{
DrawComponent(cameraComponent);
@ -118,6 +141,7 @@ namespace SHADE
DrawAddComponentButton<SHTransformComponent>(eid);
DrawAddComponentButton<SHCameraComponent>(eid);
DrawAddComponentButton<SHCameraArmComponent>(eid);
DrawAddComponentButton<SHLightComponent>(eid);
// Components that require Transforms

View File

@ -3,7 +3,7 @@
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "Editor/SHEditor.hpp"
#include "Editor/SHEditor.h"
#include "SHEditorMenuBar.h"
#include "Editor/IconsMaterialDesign.h"
#include "Editor/Command/SHCommandManager.h"

View File

@ -5,13 +5,16 @@
#include "ImGuizmo.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/IconsMaterialDesign.h"
#include "Editor/SHEditor.hpp"
#include "Editor/SHEditor.h"
#include "Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h"
#include <Editor/IconsFontAwesome6.h>
#include "Camera/SHCameraSystem.h"
#include "FRC/SHFramerateController.h"
constexpr std::string_view windowName = "\xef\x80\x95 Viewport";
namespace SHADE
@ -30,8 +33,15 @@ namespace SHADE
void SHEditorViewport::Update()
{
SHEditorWindow::Update();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f,0.0f));
if(Begin())
if (shouldUpdateCamera)
{
auto camSystem = SHSystemManager::GetSystem<SHCameraSystem>();
camSystem->UpdateEditorCamera(SHFrameRateController::GetRawDeltaTime());
shouldUpdateCamera = false;
}
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
if (Begin())
{
ImGuizmo::SetDrawlist();
DrawMenuBar();
@ -39,21 +49,38 @@ namespace SHADE
auto const& descriptorSet = gfxSystem->GetPostOffscreenRenderSystem()->GetDescriptorSetGroup()->GetVkHandle()[0];
auto mousePos = ImGui::GetMousePos();
beginCursorPos = ImGui::GetCursorScreenPos();
viewportMousePos = {mousePos.x - beginCursorPos.x, mousePos.y - beginCursorPos.y};
gfxSystem->GetMousePickSystem ()->SetViewportMousePos (viewportMousePos);
viewportMousePos = { mousePos.x - beginCursorPos.x, mousePos.y - beginCursorPos.y };
gfxSystem->GetMousePickSystem()->SetViewportMousePos(viewportMousePos);
ImGui::Image((ImTextureID)descriptorSet, {beginContentRegionAvailable.x, beginContentRegionAvailable.y});
ImGui::Image((ImTextureID)descriptorSet, { beginContentRegionAvailable.x, beginContentRegionAvailable.y });
if(ImGui::IsWindowHovered() && ImGui::IsMouseDown(ImGuiMouseButton_Right))
if (ImGui::IsWindowHovered() && ImGui::IsMouseDown(ImGuiMouseButton_Right))
{
ImGui::SetMouseCursor(ImGuiMouseCursor_None);
ImGui::SetCursorScreenPos(ImGui::GetMousePos());
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiColors::green);
ImGui::Text(ICON_FA_EYE);
ImGui::PopStyleColor();
shouldUpdateCamera = true;
}
if (ImGui::IsWindowFocused() && !ImGui::IsMouseDown(ImGuiMouseButton_Right))
{
if (ImGui::IsKeyReleased(ImGuiKey_Q))
{
transformGizmo.operation = SHTransformGizmo::Operation::TRANSLATE;
}
if (ImGui::IsKeyReleased(ImGuiKey_W))
{
transformGizmo.operation = SHTransformGizmo::Operation::ROTATE;
}
if (ImGui::IsKeyReleased(ImGuiKey_E))
{
transformGizmo.operation = SHTransformGizmo::Operation::SCALE;
}
}
}
ImGuizmo::SetRect(beginCursorPos.x , beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y);
ImGuizmo::SetRect(beginCursorPos.x, beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y);
transformGizmo.Draw();
ImGui::End();
ImGui::PopStyleVar();
@ -72,11 +99,12 @@ namespace SHADE
//auto pos = ImGui::GetCursorPos();
//windowCursorPos = {}
if(beginContentRegionAvailable.x == 0 || beginContentRegionAvailable.y == 0)
if (beginContentRegionAvailable.x == 0 || beginContentRegionAvailable.y == 0)
{
beginContentRegionAvailable = windowSize;
beginContentRegionAvailable = windowSize;
}
gfxSystem->PrepareResize(static_cast<uint32_t>(beginContentRegionAvailable.x), static_cast<uint32_t>(beginContentRegionAvailable.y));
shouldUpdateCamera = true;
}
void SHEditorViewport::OnPosChange()
@ -86,44 +114,63 @@ namespace SHADE
void SHEditorViewport::DrawMenuBar() noexcept
{
if(ImGui::BeginMenuBar())
if (ImGui::BeginMenuBar())
{
ImGui::BeginDisabled(ImGui::IsWindowFocused() && ImGui::IsMouseDown(ImGuiMouseButton_Right));
bool const isTranslate = transformGizmo.operation == SHTransformGizmo::Operation::TRANSLATE;
ImGui::BeginDisabled(isTranslate);
if(isTranslate)
if (isTranslate)
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]);
if(ImGui::Button(ICON_MD_OPEN_WITH))
if (ImGui::Button(ICON_MD_OPEN_WITH))
{
transformGizmo.operation = SHTransformGizmo::Operation::TRANSLATE;
}
ImGui::EndDisabled();
if(isTranslate)
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
{
ImGui::BeginTooltip();
ImGui::Text("Translate [Q]");
ImGui::EndTooltip();
}
if (isTranslate)
ImGui::PopStyleColor();
bool const isRotate = transformGizmo.operation == SHTransformGizmo::Operation::ROTATE;
ImGui::BeginDisabled(isRotate);
if(isRotate)
if (isRotate)
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]);
if(ImGui::Button(ICON_MD_AUTORENEW))
if (ImGui::Button(ICON_MD_AUTORENEW))
{
transformGizmo.operation = SHTransformGizmo::Operation::ROTATE;
}
ImGui::EndDisabled();
if(isRotate)
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
{
ImGui::BeginTooltip();
ImGui::Text("Rotate [W]");
ImGui::EndTooltip();
}
if (isRotate)
ImGui::PopStyleColor();
bool const isScale = transformGizmo.operation == SHTransformGizmo::Operation::SCALE;
ImGui::BeginDisabled(isScale);
if(isScale)
if (isScale)
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]);
if(ImGui::Button(ICON_MD_EXPAND))
if (ImGui::Button(ICON_MD_EXPAND))
{
transformGizmo.operation = SHTransformGizmo::Operation::SCALE;
}
ImGui::EndDisabled();
if(isScale)
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
{
ImGui::BeginTooltip();
ImGui::Text("Scale [E]");
ImGui::EndTooltip();
}
if (isScale)
ImGui::PopStyleColor();
ImGui::EndDisabled();
ImGui::EndMenuBar();
}
}

View File

@ -14,7 +14,7 @@
namespace SHADE
{
class SHEditorViewport final : public SHEditorWindow
class SHEditorViewport final : public SHEditorWindow
{
public:
SHEditorViewport();
@ -28,5 +28,6 @@ namespace SHADE
private:
void DrawMenuBar() noexcept;
SHVec2 beginCursorPos;
bool shouldUpdateCamera = false;
};//class SHEditorViewport
}//namespace SHADE

View File

@ -3,7 +3,7 @@
#include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.hpp"
#include "Editor/SHEditor.h"
#include "Editor/SHImGuiHelpers.hpp"
#include <imgui.h>
#include <ImGuizmo.h>
@ -63,6 +63,9 @@ namespace SHADE
if (selectedEntityTransformComponent == nullptr)
return;
if(!selectedEntityTransformComponent->isActive)
return;
SHMatrix mat = selectedEntityTransformComponent->GetTRS();
useSnap = ImGui::IsKeyDown(ImGuiKey_LeftCtrl);
if(useSnap)

View File

@ -21,7 +21,7 @@
#include "Graphics/MiddleEnd/Interface/SHViewport.h"
#include "Graphics/MiddleEnd/Interface/SHRenderer.h"
#include "SHEditor.hpp"
#include "SHEditor.h"
#include "SHEditorWidgets.hpp"
#include "Math/Transform/SHTransformSystem.h"
@ -175,7 +175,7 @@ namespace SHADE
ImFontConfig icons_config{}; icons_config.MergeMode = true; icons_config.GlyphOffset.y = 5.f;
constexpr ImWchar icon_ranges_fa[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
ImFont* UIFontFA = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/fa-solid-900.ttf", 20.f, &icons_config, icon_ranges_fa); //TODO: Change to config based assets path
constexpr ImWchar icon_ranges_md[] = { ICON_MIN_MD, ICON_MAX_MD, 0 };
constexpr ImWchar icon_ranges_md[] = { ICON_MIN_MD, ICON_MAX_16_MD, 0 };
ImFont* UIFontMD = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/MaterialIcons-Regular.ttf", 20.f, &icons_config, icon_ranges_md); //TODO: Change to config based assets path
io->Fonts->Build();
}
@ -293,6 +293,7 @@ namespace SHADE
//#==============================================================#
void SHEditor::InitBackend()
{
#ifdef SHEDITOR
if(ImGui_ImplSDL2_InitForVulkan(sdlWindow) == false)
{
SHLOG_CRITICAL("Editor backend initialisation; Failed to perform SDL initialisation for Vulkan")
@ -339,6 +340,7 @@ namespace SHADE
renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle<SHVkCommandBuffer>& cmd) {
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer());
});
#endif
}
void SHEditor::PollPicking()

View File

@ -15,7 +15,7 @@
#include "ECS_Base/System/SHSystemRoutine.h"
#include "Resource/SHHandle.h"
#include "EditorWindow/SHEditorWindow.h"
#include "Tools/SHLogger.h"
#include "Tools/SHLog.h"
#include "Gizmos/SHTransformGizmo.h"
@ -76,7 +76,7 @@ namespace SHADE
}
else
{
SHLOG_WARNING("Attempt to create duplicate of Editor window type")
SHLog::Warning("Attempt to create duplicate of Editor window type");
}
}

View File

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

View File

@ -22,6 +22,8 @@
#include <misc/cpp/imgui_stdlib.h>
#include <rttr/type.h>
#include "DragDrop/SHDragDrop.hpp"
namespace SHADE
{
class SH_API SHEditorWidgets
@ -41,7 +43,7 @@ namespace SHADE
ImGui::BeginGroup();
auto itemSpacing = ImGui::GetStyle().ItemSpacing;
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.2f));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
auto frameHeight = ImGui::GetFrameHeight();
@ -86,7 +88,7 @@ namespace SHADE
auto itemSpacing = ImGui::GetStyle().ItemSpacing;
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.2f));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
auto frameHeight = ImGui::GetFrameHeight();
@ -127,7 +129,7 @@ namespace SHADE
ImGui::GetWindowDrawList()->AddRect(
frameRect.Min, frameRect.Max,
ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Button)),
ImColor(ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled)),
halfFrame.x);
ImGui::PopClipRect();
@ -174,15 +176,19 @@ namespace SHADE
ImGui::SetColumnWidth(-1, 80.0f);
ImGui::Text(label.c_str());
if (isHovered)
*isHovered = ImGui::IsItemHovered();
*isHovered |= ImGui::IsItemHovered();
ImGui::NextColumn();
for (std::size_t i = 0; i < N; ++i)
{
ImGui::PushID(static_cast<int>(i));
ImGui::TextUnformatted(componentLabels[i].c_str(), ImGui::FindRenderedTextEnd(componentLabels[i].c_str())); ImGui::SameLine();
ImGui::TextUnformatted(componentLabels[i].c_str(), ImGui::FindRenderedTextEnd(componentLabels[i].c_str()));
if (isHovered)
*isHovered |= ImGui::IsItemHovered();
ImGui::SameLine();
ImGui::SetNextItemWidth(80.0f);
valueChanged |= ImGui::DragFloat("##v", values[i], speed, valueMin, valueMax, displayFormat, flags);
if (isHovered)
*isHovered |= ImGui::IsItemHovered();
const ImVec2 min = ImGui::GetItemRectMin();
const ImVec2 max = ImGui::GetItemRectMax();
const float spacing = g.Style.FrameRounding;
@ -192,8 +198,8 @@ namespace SHADE
ImGuiColors::colors[i], 4);
ImGui::SameLine(0, g.Style.ItemInnerSpacing.x);
ImGui::PopID();
ImGui::PopItemWidth();
ImGui::PopID();
}
ImGui::EndColumns();
ImGui::PopID();
@ -203,23 +209,31 @@ namespace SHADE
}
static bool DragVec2(const std::string& label, std::vector<std::string>const& componentLabels, std::function<SHVec2(void)> get,
std::function<void(SHVec2)> set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f,
std::function<void(SHVec2)> set, bool const& isAnAngleInRad = false, std::string_view const& tooltip = {}, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
ImGuiSliderFlags flags = 0)
{
SHVec2 values = get();
if(isAnAngleInRad)
{
values = {SHMath::RadiansToDegrees(values.x), SHMath::RadiansToDegrees(values.y)};
}
bool const changed = DragN<float, 2>(label, componentLabels, { &values.x, &values.y }, speed, displayFormat, valueMin, valueMax, flags);
static bool startRecording = false;
if (changed)
{
if(isAnAngleInRad)
{
values = {SHMath::DegreesToRadians(values.x), SHMath::DegreesToRadians(values.y)};
}
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), startRecording);
if (!startRecording)
startRecording = true;
}
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
startRecording = false;
if(!tooltip.empty())
if (!tooltip.empty())
{
if(ImGui::IsItemHovered())
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
@ -230,17 +244,24 @@ namespace SHADE
}
static bool DragVec3(const std::string& label, std::vector<std::string>const& componentLabels, std::function<SHVec3(void)> get,
std::function<void(SHVec3)> set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f,
std::function<void(SHVec3)> set, bool const& isAnAngleInRad = false, std::string_view const& tooltip = {}, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
ImGuiSliderFlags flags = 0)
{
SHVec3 values = get();
bool const changed = DragN<float, 3>(label, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags);
if(isAnAngleInRad)
{
values = {SHMath::RadiansToDegrees(values.x), SHMath::RadiansToDegrees(values.y), SHMath::RadiansToDegrees(values.z)};
}
bool isHovered = false;
bool const changed = DragN<float, 3>(label, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags, &isHovered);
static bool startRecording = false;
if (changed)
{
SHVec3 old = get();
if(isAnAngleInRad)
{
values = {SHMath::DegreesToRadians(values.x), SHMath::DegreesToRadians(values.y), SHMath::DegreesToRadians(values.z)};
}
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(old, values, set)), startRecording);
if (!startRecording)
startRecording = true;
@ -249,9 +270,9 @@ namespace SHADE
{
startRecording = false;
}
if(!tooltip.empty())
if (!tooltip.empty())
{
if(ImGui::IsItemHovered())
if (isHovered)
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
@ -262,14 +283,22 @@ namespace SHADE
}
static bool DragVec4(const std::string& label, std::vector<std::string>const& componentLabels, std::function<SHVec4(void)> get,
std::function<void(SHVec4)> set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f,
std::function<void(SHVec4)> set, bool const& isAnAngleInRad = false, std::string_view const& tooltip = {}, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
ImGuiSliderFlags flags = 0)
{
SHVec4 values = get();
if(isAnAngleInRad)
{
values = {SHMath::RadiansToDegrees(values.x), SHMath::RadiansToDegrees(values.y), SHMath::RadiansToDegrees(values.z), SHMath::RadiansToDegrees(values.w)};
}
bool const changed = DragN<float, 4>(label, componentLabels, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags);
static bool startRecording = false;
if (changed)
{
if(isAnAngleInRad)
{
values = {SHMath::DegreesToRadians(values.x), SHMath::DegreesToRadians(values.y), SHMath::DegreesToRadians(values.z), SHMath::DegreesToRadians(values.w)};
}
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), startRecording);
if (!startRecording)
startRecording = true;
@ -278,9 +307,9 @@ namespace SHADE
{
startRecording = false;
}
if(!tooltip.empty())
if (!tooltip.empty())
{
if(ImGui::IsItemHovered())
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
@ -297,7 +326,7 @@ namespace SHADE
static void TextLabel(std::string_view const& text, bool sameLine = true)
{
const ImVec2 textSize = ImGui::CalcTextSize(text.data(), NULL, true);
if(textSize.x > 0.0f)
if (textSize.x > 0.0f)
{
ImGui::Text(text.data());
ImGui::SameLine();
@ -310,32 +339,32 @@ namespace SHADE
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
if (ImGui::Checkbox("##", &value))
bool const changed = ImGui::Checkbox("##", &value);
if (changed)
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<bool>>(get(), value, set)), false);
return true;
}
ImGui::PopID();
ImGui::EndGroup();
if(!tooltip.empty())
if (!tooltip.empty())
{
if(ImGui::IsItemHovered())
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return false;
return changed;
}
template<typename T>
static bool RadioButton(std::vector<std::string> const& label, std::vector<T> const& listTypes, std::function<T(void)> get, std::function<void(T const&)> set ,std::string_view const& tooltip = {})
static bool RadioButton(std::vector<std::string> const& label, std::vector<T> const& listTypes, std::function<T(void)> get, std::function<void(T const&)> set, std::string_view const& tooltip = {})
{
T type = get();
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
//TextLabel(label);
for (size_t i = 0; i < listTypes.size(); i++)
{
if (ImGui::RadioButton(label[i].c_str(), type == listTypes[i]))
@ -366,12 +395,11 @@ namespace SHADE
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
if (ImGui::InputText("##", &text, flag, callback, userData))
bool const changed = ImGui::InputText("##", &text, flag, callback, userData);
if (changed)
{
if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<std::string>>(get(), text, set)), false);
return true;
}
ImGui::PopID();
ImGui::EndGroup();
@ -384,7 +412,37 @@ namespace SHADE
ImGui::EndTooltip();
}
}
return false;
return changed;
}
template<typename T>
static bool DragDropReadOnlyField(std::string const& label, std::string_view const& fieldVTextValue, std::function<T (void)> const& get, std::function<void(T const&)> const& set, SHDragDrop::DragDropTag const& dragDropTag, std::string_view const& tooltip = {})
{
std::string text = fieldVTextValue.data();
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
bool const changed = ImGui::InputText("##", &text, ImGuiInputTextFlags_ReadOnly, nullptr, nullptr);
if(SHDragDrop::BeginTarget())
{
if(T* payload = SHDragDrop::AcceptPayload<T>(dragDropTag))
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), *payload, set)), false);
SHDragDrop::EndTarget();
}
}
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return changed;
}
template <typename T>
@ -442,9 +500,9 @@ namespace SHADE
}
ImGui::PopID();
ImGui::EndGroup();
if(!tooltip.empty())
if (!tooltip.empty())
{
if(ImGui::IsItemHovered())
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
@ -615,5 +673,43 @@ namespace SHADE
}
return edited;
}
static bool ColorPicker(const std::string_view& label, std::function<SHVec4(void)> get, std::function<void(SHVec4 const&)> set, std::string_view const& tooltip = {}, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
ImGuiSliderFlags flags = 0)
{
bool changed = false;
ImGui::BeginGroup();
ImGui::PushID(label.data());
SHVec4 values = get();
//changed |= DragN<float, 4>(label.data(), {"R", "G", "B", "A"}, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags);
//ImGui::SameLine();
TextLabel(label);
changed = ImGui::ColorEdit4("##Col4", &values.x, ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_AlphaBar | ImGuiColorEditFlags_DisplayRGB );
static bool startRecording = false;
if(changed)
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), startRecording);
if(!startRecording)
startRecording = true;
}
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
startRecording = false;
}
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return changed;
}
};
}//namespace SHADE

View File

@ -1,159 +1,82 @@
/*************************************************************************//**
* \file SHFileSystem.cpp
* \author Loh Xiao Qi
* \date 30 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 "SHFileSystem.h"
#include "fileapi.h"
#include <filesystem>
#include <queue>
#include "Assets/SHAssetMetaHandler.h"
namespace SHADE
{
char const FOLDER_MAX_COUNT {15};
std::unordered_map<FolderLocation, std::unique_ptr<SHFolder>> SHFileSystem::folders;
FolderPointer SHFileSystem::root {nullptr};
SHFolder::SHFolder(FolderHandle id, FolderName name)
:id{ id }, name{ name }, subFolders(0), folded{ false }, path{""}
{
}
FolderLocation SHFileSystem::CreateNewFolderHere(FolderName name, FolderLocation here) noexcept
{
if (here == 0)
{
if (!folders.contains(0))
{
folders[0] = std::make_unique<SHFolder>(0, "root");
}
auto const count = static_cast<FolderCounter>(folders[here]->subFolders.size());
if (count >= FOLDER_MAX_COUNT)
{
SHLOG_ERROR("Max subfolder reached: {}\n", name);
}
auto const location = static_cast<FolderLocation>(count);
CreateFolder(folders[0]->path, here, location, name);
return location;
}
if (!folders.contains(here))
{
SHLOG_ERROR("Folder creation location does not exist/invalid: {}\n", here);
}
auto const count = static_cast<FolderCounter>(folders[here]->subFolders.size());
FolderHandle location = here;
location <<= FOLDER_BIT_ALLOCATE;
location |= count;
if (count >= FOLDER_MAX_COUNT)
{
SHLOG_ERROR("Max subfolder reached: {}\n", name);
}
CreateFolder(folders[0]->path, here, location, name);
return location;
}
bool SHFileSystem::DeleteFolder(FolderPointer location) noexcept
{
if (!folders.contains(location->id))
{
SHLOG_ERROR("Delete target does not exist/invalid: {}\n", location->name);
}
for (auto const& subFolder : folders[location->id]->subFolders)
{
DeleteFolder(subFolder);
}
RemoveDirectoryA(folders[location->id]->path.c_str());
//TODO IMPLEMENT
return true;
}
void SHFileSystem::StartupFillDirectories(FolderPath path) noexcept
void SHFileSystem::BuildDirectory(FolderPath path, FolderPointer& root, std::unordered_map<AssetID, SHAsset>& assetCollection) noexcept
{
std::queue<FolderPointer> folderQueue;
folderQueue.push(RegisterFolder(path, 0, 0, "Root"));
root = new SHFolder("root");
root->path = path;
folderQueue.push(root);
while (!folderQueue.empty())
{
auto folder = folderQueue.front();
auto const folder = folderQueue.front();
folderQueue.pop();
FolderCounter count = 0;
std::vector<SHAsset> assets;
for (auto const& dirEntry : std::filesystem::directory_iterator(folder->path))
{
auto const& path = dirEntry.path();
if (!dirEntry.is_directory())
{
folder->files.emplace_back(
dirEntry.path().filename().string(),
dirEntry.path().string(),
dirEntry.path().extension().string()
);
continue;
if (path.extension().string() == META_EXTENSION)
{
//auto asset = SHAssetMetaHandler::RetrieveMetaData(path);
//assetCollection.insert({ asset.id, asset });
assets.push_back(SHAssetMetaHandler::RetrieveMetaData(path));
}
else
{
folder->files.emplace_back(
path.stem().string(),
path.string(),
path.extension().string(),
nullptr
);
}
continue;
}
FolderLocation location = folder->id;
location <<= FOLDER_BIT_ALLOCATE;
location |= ++count;
std::string name = dirEntry.path().string();
name = name.substr(name.find_last_of('/') + 1, name.length() - name.find_last_of('/'));
FolderPointer newFolder{ RegisterFolder(
dirEntry.path().string(),
folder->id,
location,
name)
};
folderQueue.push(newFolder);
folder->subFolders.push_back(newFolder);
auto newFolder{ folder->CreateSubFolderHere(path.stem().string()) };
folderQueue.push(newFolder);
}
for (auto const& asset : assets)
{
assetCollection.emplace(asset.id, asset);
for(auto& file : folder->files)
{
if (file.name == asset.name)
{
file.assetMeta = &assetCollection[asset.id];
break;
}
}
}
}
}
FolderPointer SHFileSystem::GetRoot() noexcept
{
return root;
}
FolderPointer SHFileSystem::CreateFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept
{
if (!CreateDirectoryA(path.c_str(), nullptr))
{
SHLOG_ERROR("Failed to create folder: {}\n", path);
}
folders[location] = std::make_unique<SHFolder>(location, name);
folders[location]->path = path;
folders[parent]->subFolders.push_back(folders[location].get());
return FolderMakeHelper(path, parent, location, name);
}
FolderPointer SHFileSystem::RegisterFolder(FolderPath path, FolderLocation parent, FolderHandle location,
FolderName name) noexcept
{
return FolderMakeHelper(path, parent, location, name);
}
FolderPointer SHFileSystem::FolderMakeHelper(FolderPath path, FolderLocation parent, FolderHandle location,
FolderName name) noexcept
{
folders[location] = std::make_unique<SHFolder>(location, name);
folders[location]->path = path;
folders[parent]->subFolders.push_back(folders[location].get());
return folders[location].get();
}
}

View File

@ -1,70 +1,28 @@
/******************************************************************************
* \file SHFileSystem.h
* \author Loh Xiao Qi
* \date 28 October 2022
* \brief
*
* \copyright Copyright (c) 2021 Digipen Institute of Technology. Reproduction
* or disclosure of this file or its contents without the prior
* written consent of Digipen Institute of Technology is prohibited.
******************************************************************************/
#pragma once
#include <string>
#include <vector>
#include <memory>
#include "SHFolder.h"
#include <unordered_map>
namespace SHADE
{
class SHFolder;
typedef unsigned char FolderCounter;
typedef unsigned char FileCounter;
typedef uint64_t FolderLocation;
typedef uint64_t FolderHandle;
typedef std::string FolderName;
typedef std::string FileName;
typedef std::string FolderPath;
typedef std::string FilePath;
typedef std::string FileExt;
typedef SHFolder* FolderPointer;
constexpr char FOLDER_BIT_ALLOCATE{ 4 };
constexpr char FOLDER_MAX_DEPTH{ 16 };
struct SHFile
{
FileName name;
FilePath path;
FileExt ext;
};
class SHFolder
{
public:
SHFolder(FolderHandle id, FolderName name);
FolderHandle id;
FolderName name;
std::vector<FolderPointer> subFolders;
std::vector<SHFile> files;
bool folded;
private:
FolderPath path;
friend class SHFileSystem;
};
class SHFileSystem
{
public:
static FolderLocation CreateNewFolderHere(FolderName name, FolderLocation here = 0) noexcept;
static bool DeleteFolder(FolderPointer location) noexcept;
static void StartupFillDirectories(FolderPath path) noexcept;
static FolderPointer GetRoot() noexcept;
static void BuildDirectory(FolderPath path, FolderPointer& root, std::unordered_map<AssetID, SHAsset>& assetCollection) noexcept;
private:
static FolderPointer root;
static std::unordered_map<FolderLocation, std::unique_ptr<SHFolder>> folders;
static FolderPointer CreateFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept;
static FolderPointer RegisterFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept;
static FolderPointer FolderMakeHelper(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept;
static bool DeleteFolder(FolderPointer location) noexcept;
};
}

View File

@ -0,0 +1,38 @@
/*************************************************************************//**
* \file SHFolder.cpp
* \author Loh Xiao Qi
* \date 30 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 "SHFolder.h"
namespace SHADE
{
SHFolder::SHFolder(FolderName name)
:name{ name }, subFolders(0), folded{ false }, path{ "" }
{
}
FolderPointer SHFolder::CreateSubFolderHere(FolderName name)
{
for (auto const& folder : subFolders)
{
if (name == folder->name)
{
SHLOG_ERROR("Unable to create subfolder {} at {} as it already exists", name, folder->name);
return nullptr;
}
}
auto result = new SHFolder(name);
result->path = path + "/" + name;
subFolders.push_back(result);
return result;
}
}

View File

@ -0,0 +1,52 @@
/******************************************************************************
* \file SHFolder.h
* \author Loh Xiao Qi
* \date 28 October 2022
* \brief
*
* \copyright Copyright (c) 2021 Digipen Institute of Technology. Reproduction
* or disclosure of this file or its contents without the prior
* written consent of Digipen Institute of Technology is prohibited.
******************************************************************************/
#pragma once
#include <string>
#include <vector>
#include "Assets/SHAsset.h"
namespace SHADE
{
class SHFolder;
typedef unsigned char FolderCounter;
typedef unsigned char FileCounter;
typedef std::string FolderName;
typedef std::string FileName;
typedef std::string FolderPath;
typedef std::string FilePath;
typedef std::string FileExt;
typedef SHFolder* FolderPointer;
struct SHFile
{
FileName name;
FilePath path;
FileExt ext;
SHAsset const* assetMeta;
};
class SHFolder
{
public:
SHFolder(FolderName name);
FolderName name;
std::vector<FolderPointer> subFolders;
std::vector<SHFile> files;
bool folded;
FolderPointer CreateSubFolderHere(FolderName name);
FolderPath path;
};
}

View File

@ -186,9 +186,10 @@ namespace SHADE
vk::PhysicalDeviceFeatures features{}; // ADD MORE FEATURES HERE IF NEEDED
// point and lines fill mode
features.fillModeNonSolid = true;
features.fillModeNonSolid = VK_TRUE;
features.samplerAnisotropy = VK_TRUE;
features.multiDrawIndirect = true;
features.multiDrawIndirect = VK_TRUE;
features.independentBlend = VK_TRUE;
// for wide lines
features.wideLines = true;

View File

@ -45,16 +45,20 @@ namespace SHADE
void SHBatch::Add(const SHRenderable* renderable)
{
// Ignore if null
if (!renderable->GetMesh())
return;
// Check if we have a SubBatch with the same mesh yet
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
{
return batch.Mesh == renderable->Mesh;
});
{
return batch.Mesh == renderable->GetMesh();
});
// Create one if not found
if (subBatch == subBatches.end())
{
subBatches.emplace_back(renderable->Mesh);
subBatches.emplace_back(renderable->GetMesh());
subBatch = subBatches.end() - 1;
}
@ -73,7 +77,7 @@ namespace SHADE
// Check if we have a SubBatch with the same mesh yet
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
{
return batch.Mesh == renderable->Mesh;
return batch.Mesh == renderable->GetMesh();
});
// Attempt to remove if it exists
@ -84,13 +88,18 @@ namespace SHADE
// Check if other renderables in subBatches contain the same material instance
bool matUnused = true;
Handle<SHMaterialInstance> matToCheck = renderable->HasMaterialChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial();
for (const auto& sb : subBatches)
{
// Check material usage
for (const auto& rendId : sb.Renderables)
{
auto rend = SHComponentManager::GetComponent<SHRenderable>(rendId);
if (rend)
{
if (rend->GetMaterial() == renderable->GetMaterial())
if (rend->GetMaterial() == matToCheck)
{
matUnused = false;
break;
@ -101,10 +110,15 @@ namespace SHADE
SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
}
}
}
// Material is no longer in this library, so we remove it
if (matUnused)
referencedMatInstances.erase(renderable->WasMaterialChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial());
referencedMatInstances.erase(renderable->HasChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial());
// Mesh is no longer in this batch, so we remove the associated sub batch
if (subBatch->Renderables.empty())
subBatches.erase(subBatch);
// Mark all as dirty
setAllDirtyFlags();
@ -180,7 +194,8 @@ namespace SHADE
{
SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
}
propsCurrPtr += singleMatPropAlignedSize;
//propsCurrPtr += singleMatPropAlignedSize;
propsCurrPtr += singleMatPropSize;
}
// Transfer to GPU
@ -302,7 +317,7 @@ namespace SHADE
{
singleMatPropSize = SHADER_INFO->GetBytesRequired();
singleMatPropAlignedSize = device->PadSSBOSize(static_cast<uint32_t>(singleMatPropSize));
matPropTotalBytes = numTotalElements * singleMatPropAlignedSize;
matPropTotalBytes = numTotalElements * singleMatPropSize;
if (matPropsDataSize < matPropTotalBytes)
{
matPropsData.reset(new char[matPropTotalBytes]);
@ -361,7 +376,8 @@ namespace SHADE
{
SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
}
propsCurrPtr += singleMatPropAlignedSize;
//propsCurrPtr += singleMatPropAlignedSize;
propsCurrPtr += singleMatPropSize;
}
}
}

View File

@ -47,36 +47,35 @@ namespace SHADE
// For global data (generic data and textures)
Handle<SHVkDescriptorSetLayout> staticGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS,{ genericDataBinding, texturesBinding });
std::vector<SHVkDescriptorSetLayout::Binding> lightBindings{};
for (uint32_t i = 0; i < SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); ++i)
// This is the binding we use to count the lights (binding 0)
lightBindings.push_back(SHVkDescriptorSetLayout::Binding
{
.Type = vk::DescriptorType::eUniformBufferDynamic,
.Stage = vk::ShaderStageFlagBits::eCompute,
.BindPoint = 0,
.DescriptorCount = 1,
});
for (uint32_t i = 1; i <= SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); ++i)
{
lightBindings.push_back (SHVkDescriptorSetLayout::Binding
{
.Type = vk::DescriptorType::eStorageBufferDynamic,
.Stage = vk::ShaderStageFlagBits::eFragment,
.Stage = vk::ShaderStageFlagBits::eCompute,
.BindPoint = i,
.DescriptorCount = 1,
});
}
//SHVkDescriptorSetLayout::Binding pointLightBinding
//{
// .Type = vk::DescriptorType::eStorageBufferDynamic,
// .Stage = vk::ShaderStageFlagBits::eFragment,
// .BindPoint = SHGraphicsConstants::DescriptorSetBindings::POINT_LIGHT_DATA,
// .DescriptorCount = 1,
//};
//SHVkDescriptorSetLayout::Binding spotLightBinding
//{
// .Type = vk::DescriptorType::eStorageBufferDynamic,
// .Stage = vk::ShaderStageFlagBits::eFragment,
// .BindPoint = SHGraphicsConstants::DescriptorSetBindings::SPOT_LIGHT_DATA,
// .DescriptorCount = 1,
//};
// For Dynamic global data (lights)
Handle<SHVkDescriptorSetLayout> dynamicGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, lightBindings);
SHVkDescriptorSetLayout::Binding cameraDataBinding
{
.Type = vk::DescriptorType::eUniformBufferDynamic,

View File

@ -94,32 +94,14 @@ namespace SHADE
/***************************************************************************/
static constexpr uint32_t IMAGE_AND_SAMPLERS_DATA = 1;
///***************************************************************************/
///*!
// \brief
// DescriptorSet binding for directional lights.
/***************************************************************************/
/*!
\brief
DescriptorSet binding for combined image sampler data.
//*/
///***************************************************************************/
//static constexpr uint32_t DIRECTIONAL_LIGHT_DATA = 0;
///***************************************************************************/
///*!
// \brief
// DescriptorSet binding for directional lights.
//*/
///***************************************************************************/
//static constexpr uint32_t POINT_LIGHT_DATA = 1;
///***************************************************************************/
///*!
// \brief
// DescriptorSet binding for directional lights.
//*/
///***************************************************************************/
//static constexpr uint32_t SPOT_LIGHT_DATA = 2;
*/
/***************************************************************************/
static constexpr uint32_t LIGHTING_COUNT = 0;
/***************************************************************************/
/*!

View File

@ -17,7 +17,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/Windowing/Surface/SHVkSurface.h"
#include "Graphics/Swapchain/SHVkSwapchain.h"
#include "Camera/SHCameraSystem.h"
#include "Editor/SHEditor.hpp"
#include "Editor/SHEditor.h"
#include "ECS_Base/Managers/SHSystemManager.h"
//#include "SHRenderer.h"
#include "Graphics/Windowing/SHWindow.h"
@ -73,15 +73,7 @@ namespace SHADE
if (width == 0 || height == 0)
return;
#ifdef SHEDITOR
//PrepareResize(1, 1, SHVec2(0, 0));
#else
PrepareResize(resizeWidth, resizeHeight, SHVec2(0, 0));
#endif
PrepareResize(resizeWidth, resizeHeight);
});
window->RegisterWindowCloseCallback([&](void)
@ -118,24 +110,8 @@ namespace SHADE
graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
// TODO: This is VERY temporarily here until a more solid resource management system is implemented
shaderSourceLibrary.Init("../../TempShaderFolder/");
shaderSourceLibrary.LoadShader(0, "TestCubeVs.glsl", SH_SHADER_TYPE::VERTEX, true);
shaderSourceLibrary.LoadShader(1, "TestCubeFs.glsl", SH_SHADER_TYPE::FRAGMENT, true);
shaderSourceLibrary.LoadShader(2, "KirschCs.glsl", SH_SHADER_TYPE::COMPUTE, true);
shaderSourceLibrary.LoadShader(3, "PureCopyCs.glsl", SH_SHADER_TYPE::COMPUTE, true);
shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary);
auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl");
auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl");
auto greyscale = shaderModuleLibrary.GetShaderModule("KirschCs.glsl");
auto pureCopy = shaderModuleLibrary.GetShaderModule("PureCopyCs.glsl");
cubeVS->Reflect();
cubeFS->Reflect();
greyscale->Reflect();
pureCopy->Reflect();
shaderModuleLibrary.ImportAllShaderSource(device);
shaderModuleLibrary.ReflectAllShaderModules();
}
void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept
@ -176,26 +152,45 @@ namespace SHADE
// Initialize world render graph
worldRenderGraph->Init(device, swapchain);
worldRenderGraph->AddResource("Scene Pre-Process", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
worldRenderGraph->AddResource("Scene", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
worldRenderGraph->AddResource("Position", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
worldRenderGraph->AddResource("Normals", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
worldRenderGraph->AddResource("Albedo", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
worldRenderGraph->AddResource("Depth Buffer", { SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint);
worldRenderGraph->AddResource("Entity ID", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
worldRenderGraph->AddResource("Light Layer Indices", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
worldRenderGraph->AddResource("Entity ID", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
worldRenderGraph->AddResource("Light Layer Indices", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
worldRenderGraph->AddResource("Scene", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
auto gBufferNode = worldRenderGraph->AddNode("G-Buffer",
{
"Position",
"Entity ID",
"Light Layer Indices",
"Normals",
"Albedo",
"Depth Buffer",
"Scene"
},
{}); // no predecessors
auto gBufferNode = worldRenderGraph->AddNode("G-Buffer", { "Light Layer Indices", "Entity ID", "Depth Buffer", "Scene", "Scene Pre-Process"}, {}); // no predecessors
auto gBufferSubpass = gBufferNode->AddSubpass("G-Buffer Write");
gBufferSubpass->AddColorOutput("Scene Pre-Process");
gBufferSubpass->AddColorOutput("Position");
gBufferSubpass->AddColorOutput("Entity ID");
gBufferSubpass->AddColorOutput("Light Layer Indices");
gBufferSubpass->AddColorOutput("Normals");
gBufferSubpass->AddColorOutput("Albedo");
gBufferSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL);
//// kirsch
//auto kirschShader = shaderModuleLibrary.GetShaderModule("KirschCs.glsl");
//gBufferNode->AddNodeCompute(kirschShader, { "Scene Pre-Process", "Scene" });
//gBufferNode->AddNodeCompute(kirschShader, { "Position", "Scene" });
// copy
auto pureCopyShader = shaderModuleLibrary.GetShaderModule("PureCopyCs.glsl");
gBufferNode->AddNodeCompute(pureCopyShader, { "Scene Pre-Process", "Scene" });
//// copy
//auto pureCopyShader = shaderModuleLibrary.GetShaderModule("PureCopyCs.glsl");
//gBufferNode->AddNodeCompute(pureCopyShader, { "Position", "Scene" });
// deferred composite
auto deferredCompositeShader = shaderModuleLibrary.GetBuiltInShaderModule("DeferredComposite_CS");
gBufferNode->AddNodeCompute(deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "Scene" });
auto dummyNode = worldRenderGraph->AddNode("Dummy Pass", { "Scene" }, {"G-Buffer"}); // no predecessors
@ -212,11 +207,10 @@ namespace SHADE
worldRenderer->SetCameraDirector(cameraSystem->CreateDirector());
auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl");
auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl");
auto cubeVS = shaderModuleLibrary.GetBuiltInShaderModule("TestCube_VS");
auto cubeFS = shaderModuleLibrary.GetBuiltInShaderModule("TestCube_FS");
defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferSubpass);
}
void SHGraphicsSystem::InitMiddleEnd(void) noexcept
@ -328,6 +322,12 @@ namespace SHADE
void SHGraphicsSystem::Run(double) noexcept
{
if (window->IsMinimized() || renderContext.GetWindowIsDead())
{
restoredFromMinimize = true;
return;
}
if (restoredFromMinimize)
return;
// Frame data for the current frame
@ -379,6 +379,7 @@ namespace SHADE
// Force set the pipeline layout
currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout(), SH_PIPELINE_TYPE::GRAPHICS);
currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout(), SH_PIPELINE_TYPE::COMPUTE);
// Bind all the buffers required for meshes
for (auto& [buffer, bindingPoint] : MESH_DATA)
@ -461,7 +462,15 @@ namespace SHADE
void SHGraphicsSystem::BeginRender()
{
if (window->IsMinimized() || renderContext.GetWindowIsDead())
{
restoredFromMinimize = true;
return;
}
if (restoredFromMinimize)
{
return;
}
// Finalise all batches
for (auto vp : viewports)
@ -510,7 +519,17 @@ namespace SHADE
void SHGraphicsSystem::EndRender()
{
if (window->IsMinimized() || renderContext.GetWindowIsDead())
{
restoredFromMinimize = true;
return;
}
if (restoredFromMinimize)
{
restoredFromMinimize = false;
return;
}
const uint32_t CURR_FRAME_IDX = renderContext.GetCurrentFrame();
auto& currFrameData = renderContext.GetCurrentFrameData();
@ -696,7 +715,7 @@ namespace SHADE
auto& renderables = SHComponentManager::GetDense<SHRenderable>();
for (auto& renderable : renderables)
{
if (!renderable.WasMaterialChanged())
if (!renderable.HasChanged())
continue;
// Remove from old material's SuperBatch
@ -784,5 +803,10 @@ namespace SHADE
}
Handle<SHRenderGraphNode> SHGraphicsSystem::GetPrimaryRenderpass() const noexcept
{
return worldRenderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data());
}
#pragma endregion MISC
}

View File

@ -25,7 +25,6 @@ of DigiPen Institute of Technology is prohibited.
#include "ECS_Base/System/SHSystemRoutine.h"
#include "Graphics/Descriptors/SHVkDescriptorPool.h"
#include "Graphics/RenderGraph/SHRenderGraph.h"
#include "Graphics/MiddleEnd/Shaders/SHShaderSourceLibrary.h"
#include "Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.h"
#include "SHMeshLibrary.h"
#include "Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.h"
@ -136,7 +135,7 @@ namespace SHADE
void RemoveViewport(Handle<SHViewport> viewport);
/*-----------------------------------------------------------------------------*/
/* Material Creation Functions */
/* Material Functions */
/*-----------------------------------------------------------------------------*/
Handle<SHMaterial> AddMaterial(Handle<SHVkShaderModule> vertShader, Handle<SHVkShaderModule> fragShader, Handle<SHSubpass> subpass);
void RemoveMaterial(Handle<SHMaterial> material);
@ -144,6 +143,8 @@ namespace SHADE
Handle<SHMaterialInstance> AddOrGetBaseMaterialInstance(Handle<SHMaterial> material);
Handle<SHMaterialInstance> AddMaterialInstanceCopy(Handle<SHMaterialInstance> materialInst);
void RemoveMaterialInstance(Handle<SHMaterialInstance> materialInstance);
Handle<SHMaterial> GetDefaultMaterial() { return defaultMaterial; }
Handle<SHMaterialInstance> GetDefaultMaterialInstance() { return AddOrGetBaseMaterialInstance(defaultMaterial); }
/*-----------------------------------------------------------------------------*/
/* Mesh Registration Functions */
@ -287,12 +288,21 @@ namespace SHADE
#endif
Handle<SHMousePickSystem> GetMousePickSystem(void) const noexcept {return mousePickSystem;};
Handle<SHPostOffscreenRenderSystem> GetPostOffscreenRenderSystem(void) const noexcept {return postOffscreenRender;};
Handle<SHRenderGraphNode> GetPrimaryRenderpass() const noexcept;
//SHRenderGraph const& GetRenderGraph(void) const noexcept;
//Handle<SHVkRenderpass> GetRenderPass() const { return renderPass; }
/*-----------------------------------------------------------------------------*/
/* Getters */
/*-----------------------------------------------------------------------------*/
SHWindow* GetWindow() noexcept { return window; }
private:
/*-----------------------------------------------------------------------------*/
/* Constants */
/*-----------------------------------------------------------------------------*/
static constexpr std::string_view G_BUFFER_RENDER_GRAPH_NODE_NAME = "G-Buffer";
/*-----------------------------------------------------------------------------*/
/* Data Members */
@ -314,12 +324,12 @@ namespace SHADE
SHWindow* window = nullptr;
// Middle End Resources
SHResourceHub resourceManager;
SHResourceHub resourceManager;
SHMeshLibrary meshLibrary;
SHTextureLibrary texLibrary;
SHSamplerCache samplerCache;
SHMaterialInstanceCache materialInstanceCache;
// Viewports
// Viewports
#ifdef SHEDITOR
Handle<SHViewport> editorViewport;
Handle<SHRenderer> editorRenderer;
@ -339,9 +349,7 @@ namespace SHADE
// Temp Cameras
Handle<SHCamera> worldCamera;
Handle<SHCamera> screenCamera;
// TODO: Temporary only until resource library from Xiao Qi is implemented
SHShaderSourceLibrary shaderSourceLibrary;
SHShaderModuleLibrary shaderModuleLibrary;
// Temp Materials
@ -356,5 +364,7 @@ namespace SHADE
uint32_t resizeWidth;
uint32_t resizeHeight;
bool restoredFromMinimize = false;
};
}

View File

@ -0,0 +1,77 @@
/************************************************************************************//*!
\file SHGraphicsSystemInterface.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 31, 2022
\brief Contains the definitions of the functions of the static
SHGraphicsSystemInterface class.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
// Precompiled Headers
#include "SHpch.h"
// Primary Header
#include "SHGraphicsSystemInterface.h"
// Project Includes
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h"
#include "Graphics/Windowing/SHWindow.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Static Usage Functions */
/*-----------------------------------------------------------------------------------*/
uint32_t SHGraphicsSystemInterface::GetWindowWidth()
{
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
if (gfxSystem)
{
const auto WND = gfxSystem->GetWindow();
return WND->GetWindowSize().first;
}
SHLOG_WARNING("[SHGraphicsSystemInterface] Failed to get window width. Value of 0 returned instead.");
return 0;
}
uint32_t SHGraphicsSystemInterface::GetWindowHeight()
{
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
if (gfxSystem)
{
const auto WND = gfxSystem->GetWindow();
return WND->GetWindowSize().second;
}
SHLOG_WARNING("[SHGraphicsSystemInterface] Failed to get window height. Value of 0 returned instead.");
return 0;
}
bool SHGraphicsSystemInterface::IsFullscreen()
{
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
if (gfxSystem)
{
const auto WND = gfxSystem->GetWindow();
return WND->GetWindowData().isFullscreen;
}
SHLOG_WARNING("[SHGraphicsSystemInterface] Failed to get window fullscreen status. Value of false returned instead.");
return false;
}
void SHGraphicsSystemInterface::CloseWindow()
{
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
if (gfxSystem)
{
auto WND = gfxSystem->GetWindow();
return WND->Close();
}
SHLOG_WARNING("[SHGraphicsSystemInterface] Failed to close window.");
}
}

View File

@ -0,0 +1,52 @@
/************************************************************************************//*!
\file SHGraphicsSystemInterface.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 31, 2022
\brief Contains the definition of the SHGraphicsSystemInterface static class.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
namespace SHADE
{
/// <summary>
/// Static class that wraps up certain functions in the SHGraphicsSystem so that
/// accessing it from SHADE_Managed would not cause issues due to C++20 features.
/// </summary>
class SH_API SHGraphicsSystemInterface final
{
public:
/*---------------------------------------------------------------------------------*/
/* Constructor */
/*---------------------------------------------------------------------------------*/
SHGraphicsSystemInterface() = delete;
/*---------------------------------------------------------------------------------*/
/* Static Usage Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Retrieves the current window width.
/// </summary>
/// <returns>The current window width.</returns>
static uint32_t GetWindowWidth();
/// <summary>
/// Retrieves the current window height.
/// </summary>
/// <returns>The current window height.</returns>
static uint32_t GetWindowHeight();
/// <summary>
/// Retrieves the current window fullscreen status.
/// </summary>
/// <returns>The current window fullscreen status..</returns>
static bool IsFullscreen();
/// <summary>
/// Closes the current window, and depending on the implementation, should also
/// close the application.
/// </summary>
static void CloseWindow();
};
}

View File

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

View File

@ -50,13 +50,24 @@ namespace SHADE
template<typename T>
void SetProperty(const std::string& key, const T& value);
template<typename T>
void SetProperty(uint32_t memOffset, const T& value);
template<typename T>
T& GetProperty(const std::string& key);
template<typename T>
const T& GetProperty(const std::string& key) const;
template<typename T>
T& GetProperty(uint32_t memOffset);
template<typename T>
const T& GetProperty(uint32_t memOffset) const;
void ResetProperties();
void ExportProperties(void* dest) const noexcept;
Byte GetPropertiesMemorySize() const noexcept;
/*-----------------------------------------------------------------------------*/
/* Query Functions */
/*-----------------------------------------------------------------------------*/
Handle<SHShaderBlockInterface> GetShaderBlockInterface() const noexcept;
private:
/*-----------------------------------------------------------------------------*/
/* Data Members */
@ -68,7 +79,8 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
/* 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>
void SHMaterial::SetProperty(const std::string& key, const T& value)
{
const auto SHADER_INFO = getShaderBlockInterface();
const auto SHADER_INFO = GetShaderBlockInterface();
const auto PROP_INFO = SHADER_INFO->GetVariable(key);
if (PROP_INFO == nullptr)
{
@ -33,21 +33,32 @@ namespace SHADE
}
// 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;
}
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>
T& SHMaterial::GetProperty(const std::string& key)
{
const auto SHADER_INFO = getShaderBlockInterface();
const auto SHADER_INFO = GetShaderBlockInterface();
const auto PROP_INFO = SHADER_INFO->GetVariable(key);
if (PROP_INFO == nullptr)
{
throw std::invalid_argument("Attempted to set an invalid property!");
throw std::invalid_argument("Attempted to retrieve an invalid property!");
}
// Get offset and return the memory directly
T* dataPtr = propMemory.get() + PROP_INFO->offset;
T* dataPtr = reinterpret_cast<T*>(propMemory.get() + PROP_INFO->offset);
return *dataPtr;
}
template<typename T>
@ -55,5 +66,25 @@ namespace SHADE
{
return const_cast<const T&>(const_cast<SHMaterial*>(this)->GetProperty(key));
}
template<typename T>
const T& SHMaterial::GetProperty(uint32_t memOffset) const
{
// Check if out of bounds
if (memOffset + sizeof(T) > propMemorySize)
throw std::invalid_argument("Attempted to retrieve an invalid property!");
return *(reinterpret_cast<T*>(propMemory.get() + memOffset));
}
template<typename T>
T& SHMaterial::GetProperty(uint32_t memOffset)
{
return const_cast<const T&>(const_cast<SHMaterial*>(this)->GetProperty(memOffset));
}
template<typename T>
void SHMaterial::setPropertyUnsafe(uint32_t memOffset, const T& value)
{
(*reinterpret_cast<T*>(propMemory.get() + memOffset)) = value;
}
}

View File

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

View File

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

View File

@ -23,12 +23,12 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/
void SHRenderable::OnCreate()
{
materialChanged = true;
matChanged = true;
sharedMaterial = {};
material = {};
oldMaterial = {};
lightLayer = 0;
lightLayer = 1;
}
void SHRenderable::OnDestroy()
@ -55,7 +55,7 @@ namespace SHADE
return;
// Flag that material was changed
materialChanged = true;
matChanged = true;
// Free copies of materials if any
if (material)
@ -92,15 +92,41 @@ namespace SHADE
return material;
}
/*-----------------------------------------------------------------------------------*/
/* Mesh Functions */
/*-----------------------------------------------------------------------------------*/
void SHRenderable::SetMesh(Handle<SHMesh> newMesh)
{
oldMesh = mesh;
mesh = newMesh;
meshChanged = true;
}
/*-----------------------------------------------------------------------------------*/
/* Light Functions */
/*-----------------------------------------------------------------------------------*/
uint8_t SHRenderable::GetLightLayer(void) const noexcept
{
return lightLayer;
}
/*-----------------------------------------------------------------------------------*/
/* Batcher Dispatcher Functions */
/*-----------------------------------------------------------------------------------*/
void SHRenderable::ResetChangedFlag()
{
materialChanged = false;
oldMaterial = {};
matChanged = false;
meshChanged = false;
oldMaterial = {};
oldMesh = {};
}
}
RTTR_REGISTRATION
{
using namespace SHADE;
using namespace rttr;
registration::class_<SHRenderable>("Renderable Component");
}

View File

@ -11,9 +11,10 @@ of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
// External Dependencies
#include <rttr/registration>
// Project Includes
#include "Resource/SHHandle.h"
//#include "SHTransform.h"
#include "ECS_Base/Components/SHComponent.h"
#include "Math/SHMatrix.h"
#include "SH_API.h"
@ -50,33 +51,42 @@ namespace SHADE
void SetMaterial(Handle<SHMaterialInstance> materialInstance);
Handle<SHMaterialInstance> GetMaterial() const;
Handle<SHMaterialInstance> GetModifiableMaterial();
Handle<SHMaterialInstance> GetPrevMaterial() const noexcept { return oldMaterial; }
bool HasMaterialChanged() const noexcept { return matChanged; }
/*-------------------------------------------------------------------------------*/
/* Getter Functions */
/* Mesh Functions */
/*-------------------------------------------------------------------------------*/
void SetMesh(Handle<SHMesh> newMesh);
Handle<SHMesh> GetMesh() const noexcept { return mesh; }
Handle<SHMesh> GetPrevMesh() const noexcept { return oldMesh; }
bool HasMeshChanged() const noexcept { return meshChanged; }
/*-------------------------------------------------------------------------------*/
/* Light Functions */
/*-------------------------------------------------------------------------------*/
bool WasMaterialChanged() const noexcept { return materialChanged; }
Handle<SHMaterialInstance> GetPrevMaterial() const noexcept { return oldMaterial; }
uint8_t GetLightLayer (void) const noexcept;
/*-------------------------------------------------------------------------------*/
/* Batcher Dispatcher Functions */
/*-------------------------------------------------------------------------------*/
bool HasChanged() const noexcept { return matChanged || meshChanged; } // Whether or not the mesh or material has changed
void ResetChangedFlag(); // TODO: Lock it so that only SHBatcherDispatcher can access this
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
Handle<SHMesh> Mesh;
private:
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
Handle<SHMesh> mesh;
Handle<SHMesh> oldMesh;
bool meshChanged = true;
Handle<SHMaterialInstance> sharedMaterial;
Handle<SHMaterialInstance> material;
bool materialChanged = true;
bool matChanged = true;
Handle<SHMaterialInstance> oldMaterial;
uint8_t lightLayer;
RTTR_ENABLE()
};
}

View File

@ -10,7 +10,7 @@ namespace SHADE
lightData.Reset();
SetType(SH_LIGHT_TYPE::DIRECTIONAL);
indexInBuffer = std::numeric_limits<uint32_t>::max();
active = true;
isActive = true;
Unbind();
}
@ -20,7 +20,7 @@ namespace SHADE
}
void SHLightComponent::SetPosition(SHVec3 position) noexcept
void SHLightComponent::SetPosition(SHVec3 const& position) noexcept
{
lightData.position = position;
MakeDirty();
@ -34,20 +34,20 @@ namespace SHADE
}
void SHLightComponent::SetDirection(SHVec3 direction) noexcept
void SHLightComponent::SetDirection(SHVec3 const& direction) noexcept
{
lightData.direction = direction;
MakeDirty();
}
void SHLightComponent::SetDiffuseColor(SHVec4 diffuseColor) noexcept
void SHLightComponent::SetColor(SHVec4 const& color) noexcept
{
lightData.diffuseColor = diffuseColor;
lightData.color = color;
MakeDirty();
}
void SHLightComponent::ModifyLayer(uint8_t layerIndex, bool value) noexcept
void SHLightComponent::ModifyCullingMask(uint8_t layerIndex, bool value) noexcept
{
if (value)
lightData.cullingMask |= (1u << layerIndex);
@ -57,6 +57,10 @@ namespace SHADE
MakeDirty();
}
void SHLightComponent::SetCullingMask(uint32_t const& value) noexcept
{
lightData.cullingMask = value;
}
void SHLightComponent::SetAllLayers(void) noexcept
{
@ -93,11 +97,11 @@ namespace SHADE
indexInBuffer = inIndexInBuffer;
}
void SHLightComponent::SetActive(bool flag) noexcept
{
MakeDirty();
active = flag;
void SHLightComponent::SetStrength(float value) noexcept
{
lightData.strength = value;
MakeDirty();
}
SHLightData const& SHLightComponent::GetLightData(void) const noexcept
@ -105,6 +109,32 @@ namespace SHADE
return lightData;
}
SHVec3 const& SHLightComponent::GetPosition(void) const noexcept
{
return lightData.position;
}
SH_LIGHT_TYPE SHLightComponent::GetType(void) const noexcept
{
return lightData.type;
}
SHVec3 const& SHLightComponent::GetDirection(void) const noexcept
{
return lightData.direction;
}
SHVec4 const& SHLightComponent::GetColor(void) const noexcept
{
return lightData.color;
}
uint32_t const& SHLightComponent::GetCullingMask(void) const noexcept
{
return lightData.cullingMask;
}
bool SHLightComponent::IsDirty(void) const noexcept
{
return dirty;
@ -120,4 +150,32 @@ namespace SHADE
return indexInBuffer;
}
float SHLightComponent::GetStrength(void) const noexcept
{
return lightData.strength;
}
}
RTTR_REGISTRATION
{
using namespace SHADE;
using namespace rttr;
registration::enumeration<SH_LIGHT_TYPE>("Light Type")
(
value("Directional", SH_LIGHT_TYPE::DIRECTIONAL),
value("Point", SH_LIGHT_TYPE::POINT),
value("Spot", SH_LIGHT_TYPE::SPOT),
value("Ambient", SH_LIGHT_TYPE::AMBIENT)
);
registration::class_<SHLightComponent>("Light Component")
.property("Position", &SHLightComponent::GetPosition, &SHLightComponent::SetPosition)
.property("Type", &SHLightComponent::GetType, &SHLightComponent::SetType)
.property("Direction", &SHLightComponent::GetDirection, &SHLightComponent::SetDirection)
.property("Color", &SHLightComponent::GetColor, &SHLightComponent::SetColor)
.property("Layer", &SHLightComponent::GetCullingMask, &SHLightComponent::SetCullingMask)
.property("Strength", &SHLightComponent::GetStrength, &SHLightComponent::SetStrength)
;
}

View File

@ -1,5 +1,6 @@
#pragma once
#include <rttr/registration>
#include "ECS_Base/Components/SHComponent.h"
#include "SHLightData.h"
@ -24,8 +25,6 @@ namespace SHADE
//! If the light's data is already in the buffers, this will be set to true.
bool bound;
//! If the light is active, this is true.
bool active;
public:
/*-----------------------------------------------------------------------*/
@ -37,24 +36,31 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
void SetPosition (SHVec3 position) noexcept;
void SetType (SH_LIGHT_TYPE type) noexcept;
void SetDirection (SHVec3 direction) noexcept;
void SetDiffuseColor (SHVec4 diffuseColor) noexcept;
void ModifyLayer (uint8_t layerIndex, bool value) noexcept;
void SetAllLayers (void) noexcept;
void ClearAllLayers (void) noexcept;
void MakeDirty (void) noexcept;
void ClearDirtyFlag (void) noexcept;
void Unbind (void) noexcept;
void SetBound (uint32_t inIndexInBuffer) noexcept;
void SetActive (bool flag) noexcept;
void SetPosition (SHVec3 const& position) noexcept; // serialized
void SetType (SH_LIGHT_TYPE type) noexcept; // serialized
void SetDirection (SHVec3 const& direction) noexcept; // serialized
void SetColor (SHVec4 const& color) noexcept; // serialized
void ModifyCullingMask (uint8_t layerIndex, bool value) noexcept; // serialized
void SetCullingMask (uint32_t const& value) noexcept;
void SetAllLayers (void) noexcept; // serialized
void ClearAllLayers (void) noexcept; // serialized
void MakeDirty (void) noexcept;
void ClearDirtyFlag (void) noexcept;
void Unbind (void) noexcept;
void SetBound (uint32_t inIndexInBuffer) noexcept;
void SetStrength (float value) noexcept; // serialized
SHLightData const& GetLightData (void) const noexcept;
SHLightData const& GetLightData (void) const noexcept;
SHVec3 const& GetPosition (void) const noexcept; // serialized
SH_LIGHT_TYPE GetType (void) const noexcept; // serialized
SHVec3 const& GetDirection (void) const noexcept; // serialized
SHVec4 const& GetColor (void) const noexcept; // serialized
uint32_t const& GetCullingMask (void) const noexcept; // serialized
bool IsDirty (void) const noexcept;
bool GetBound (void) const noexcept;
uint32_t GetIndexInBuffer (void) const noexcept;
float GetStrength (void) const noexcept;
RTTR_ENABLE()
};
}

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