Merge remote-tracking branch 'origin/main' into SP3-12-SceneGraph

This commit is contained in:
Diren D Bharwani 2022-10-31 13:15:07 +08:00
commit ed88b9e5d3
89 changed files with 2821 additions and 912 deletions

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

@ -1,3 +1,3 @@
Name: Kirsch_CS Name: Kirsch_CS
ID: 19931255 ID: 39301863
Type: 2 Type: 2

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

@ -4,7 +4,7 @@
//#define SHEDITOR //#define SHEDITOR
#ifdef SHEDITOR #ifdef SHEDITOR
#include "Editor/SHEditor.hpp" #include "Editor/SHEditor.h"
//#include "Scenes/SBEditorScene.h" //#include "Scenes/SBEditorScene.h"
#endif // SHEDITOR #endif // SHEDITOR
@ -94,7 +94,7 @@ namespace Sandbox
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BatcherDispatcherRoutine>(); SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BatcherDispatcherRoutine>();
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BeginRoutine>(); SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BeginRoutine>();
SHSystemManager::RegisterRoutine<SHCameraSystem, SHCameraSystem::EditorCameraUpdate>(); //SHSystemManager::RegisterRoutine<SHCameraSystem, SHCameraSystem::EditorCameraUpdate>();
SHSystemManager::RegisterRoutine<SHCameraSystem, SHCameraSystem::CameraSystemUpdate>(); SHSystemManager::RegisterRoutine<SHCameraSystem, SHCameraSystem::CameraSystemUpdate>();
#ifdef SHEDITOR #ifdef SHEDITOR
@ -159,7 +159,7 @@ namespace Sandbox
SHSceneManager::Exit(); SHSceneManager::Exit();
SHSystemManager::Exit(); SHSystemManager::Exit();
SHAssetManager::Unload(); SHAssetManager::Exit();
} }
} }

View File

@ -158,12 +158,22 @@ namespace Sandbox
SHComponentManager::AddComponent<SHLightComponent>(0); SHComponentManager::AddComponent<SHLightComponent>(0);
SHComponentManager::RemoveComponent <SHRigidBodyComponent>(0); SHComponentManager::RemoveComponent <SHRigidBodyComponent>(0);
SHComponentManager::RemoveComponent <SHColliderComponent>(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) void SBTestScene::Update(float dt)
{ {
static float rotation = 0.0f; 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); //auto& transform = *SHADE::SHComponentManager::GetComponent_s<SHADE::SHTransformComponent>(testObj);
//transform.SetWorldPosition({1.0f, 1.0f, -1.0f}); //transform.SetWorldPosition({1.0f, 1.0f, -1.0f});

View File

@ -61,8 +61,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// 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[1];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -86,7 +103,7 @@ namespace SHADE
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1> action) public CallbackAction(Action<T1> action)
{ {
targetAction = action; targetAction = action;
@ -103,7 +120,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1); targetAction.Invoke(t1);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
_ = targetMethod.Invoke(TargetObject, parameters); _ = targetMethod.Invoke(TargetObject, parameters);
@ -138,8 +155,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// 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[2];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -158,12 +192,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[2];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2> action) public CallbackAction(Action<T1, T2> action)
{ {
targetAction = action; targetAction = action;
@ -180,7 +214,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2); targetAction.Invoke(t1, t2);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;
@ -216,8 +250,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// 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[3];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -236,12 +287,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[3];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2, T3> action) public CallbackAction(Action<T1, T2, T3> action)
{ {
targetAction = action; targetAction = action;
@ -258,7 +309,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2, t3); targetAction.Invoke(t1, t2, t3);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;
@ -295,8 +346,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// 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[4];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -315,12 +383,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[4];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2, T3, T4> action) public CallbackAction(Action<T1, T2, T3, T4> action)
{ {
targetAction = action; targetAction = action;
@ -337,7 +405,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2, t3, t4); targetAction.Invoke(t1, t2, t3, t4);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;
@ -375,8 +443,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// 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[5];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -395,12 +480,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[5];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2, T3, T4, T5> action) public CallbackAction(Action<T1, T2, T3, T4, T5> action)
{ {
targetAction = action; targetAction = action;
@ -417,7 +502,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2, t3, t4, t5); targetAction.Invoke(t1, t2, t3, t4, t5);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;
@ -456,8 +541,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// 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[6];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -476,12 +578,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[6];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6> action) public CallbackAction(Action<T1, T2, T3, T4, T5, T6> action)
{ {
targetAction = action; targetAction = action;
@ -498,7 +600,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2, t3, t4, t5, t6); targetAction.Invoke(t1, t2, t3, t4, t5, t6);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;
@ -538,8 +640,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// 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[7];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -558,12 +677,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[7];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7> action) public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7> action)
{ {
targetAction = action; targetAction = action;
@ -580,7 +699,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7); targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;
@ -621,8 +740,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// 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[8];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -641,12 +777,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[8];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8> action) public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8> action)
{ {
targetAction = action; targetAction = action;
@ -663,7 +799,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8); targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;
@ -705,8 +841,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// 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[9];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -725,12 +878,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[9];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9> action) public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9> action)
{ {
targetAction = action; targetAction = action;
@ -747,7 +900,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9); targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;
@ -790,8 +943,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// 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[10];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -810,12 +980,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[10];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> action) public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> action)
{ {
targetAction = action; targetAction = action;
@ -832,7 +1002,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;

View File

@ -78,8 +78,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// 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> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -98,12 +115,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[<#=i#>];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <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) public CallbackAction(Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action)
{ {
targetAction = action; targetAction = action;
@ -120,7 +137,7 @@ namespace SHADE
{ {
targetAction.Invoke(<# for (int t = 1; t < i + 1; ++t) { #>t<#=t#><# if (t != i) { #>, <# } #><# } #>); targetAction.Invoke(<# for (int t = 1; t < i + 1; ++t) { #>t<#=t#><# if (t != i) { #>, <# } #><# } #>);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
<# for (int t = 0; t < i; ++t) {#>parameters[<#=t#>] = t<#=t+1#>; <# for (int t = 0; t < i; ++t) {#>parameters[<#=t#>] = t<#=t+1#>;
<# } #>_ = targetMethod.Invoke(TargetObject, parameters); <# } #>_ = targetMethod.Invoke(TargetObject, parameters);

View File

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

@ -18,5 +18,6 @@ namespace SHADE
struct SHAssetLoader struct SHAssetLoader
{ {
virtual SHAssetData* Load(AssetPath path) = 0; 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()) if (!file.is_open())
{ {
SHLOG_ERROR("Unable to open SHMesh File: {}", path.string()); SHLOG_ERROR("Unable to open SHMesh File: {}", path.string());
return;
} }
const std::string name{ path.stem().string() }; const std::string name{ path.stem().string() };
@ -75,4 +76,55 @@ namespace SHADE
return result; 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,7 +10,6 @@
* of DigiPen Institute of Technology is prohibited. * of DigiPen Institute of Technology is prohibited.
*****************************************************************************/ *****************************************************************************/
#pragma once #pragma once
#include "Assets/SHAssetMacros.h"
#include "Assets/Asset Types/SHMeshAsset.h" #include "Assets/Asset Types/SHMeshAsset.h"
#include "SHAssetLoader.h" #include "SHAssetLoader.h"
@ -20,5 +19,6 @@ namespace SHADE
{ {
void LoadSHMesh(AssetPath path, SHMeshAsset& meshes) noexcept; void LoadSHMesh(AssetPath path, SHMeshAsset& meshes) noexcept;
SHAssetData* Load(AssetPath path) override; SHAssetData* Load(AssetPath path) override;
void Write(SHAssetData const* data, AssetPath path) override;
}; };
} }

View File

@ -43,4 +43,27 @@ namespace SHADE
return result; 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

@ -11,12 +11,12 @@
#pragma once #pragma once
#include "Assets/Libraries/Loaders/SHAssetLoader.h" #include "Assets/Libraries/Loaders/SHAssetLoader.h"
#include "Assets/SHAssetMacros.h"
namespace SHADE namespace SHADE
{ {
struct SHShaderSourceLoader : SHAssetLoader struct SHShaderSourceLoader : SHAssetLoader
{ {
SHAssetData* Load(AssetPath path) override; 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

@ -17,42 +17,94 @@
namespace SHADE namespace SHADE
{ {
void SHTextureLoader::LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept void SHTextureLoader::LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept
{ {
std::ifstream file{ path.string(), std::ios::in | std::ios::binary }; std::ifstream file{ path.string(), std::ios::in | std::ios::binary };
if (!file.is_open()) if (!file.is_open())
{ {
SHLOG_ERROR("Error opening SHTexture file: {}", path.string()); SHLOG_ERROR("Error opening SHTexture file: {}", path.string());
} }
auto const intBytes{ sizeof(uint32_t) }; auto const intBytes{ sizeof(uint32_t) };
uint32_t mipCount; uint32_t mipCount;
file.read(reinterpret_cast<char*>(&asset.numBytes), intBytes); file.read(reinterpret_cast<char*>(&asset.numBytes), intBytes);
file.read(reinterpret_cast<char*>(&asset.width), intBytes); file.read(reinterpret_cast<char*>(&asset.width), intBytes);
file.read(reinterpret_cast<char*>(&asset.height), intBytes); file.read(reinterpret_cast<char*>(&asset.height), intBytes);
file.read(reinterpret_cast<char*>(&asset.format), sizeof(SHTexture::TextureFormat)); file.read(reinterpret_cast<char*>(&asset.format), sizeof(SHTexture::TextureFormat));
file.read(reinterpret_cast<char*>(&mipCount), intBytes); file.read(reinterpret_cast<char*>(&mipCount), intBytes);
std::vector<uint32_t> mips(mipCount); std::vector<uint32_t> mips(mipCount);
file.read(reinterpret_cast<char*>(mips.data()), intBytes * mipCount); file.read(reinterpret_cast<char*>(mips.data()), intBytes * mipCount);
auto pixel = new SHTexture::PixelChannel[asset.numBytes]; auto pixel = new SHTexture::PixelChannel[asset.numBytes];
file.read(reinterpret_cast<char*>(pixel), asset.numBytes); file.read(reinterpret_cast<char*>(pixel), asset.numBytes);
asset.mipOffsets = std::move(mips); asset.mipOffsets = std::move(mips);
asset.pixelData = std::move(pixel); asset.pixelData = std::move(pixel);
asset.compiled = true; asset.compiled = true;
file.close(); file.close();
} }
SHAssetData* SHTextureLoader::Load(AssetPath path) SHAssetData* SHTextureLoader::Load(AssetPath path)
{ {
auto result = new SHTextureAsset(); auto result = new SHTextureAsset();
LoadSHTexture(path, *result); LoadSHTexture(path, *result);
return 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,8 +10,6 @@
* of DigiPen Institute of Technology is prohibited. * of DigiPen Institute of Technology is prohibited.
*****************************************************************************/ *****************************************************************************/
#pragma once #pragma once
#include "Assets/SHAssetMacros.h"
#include "Assets/Asset Types/SHTextureAsset.h" #include "Assets/Asset Types/SHTextureAsset.h"
#include "SHAssetLoader.h" #include "SHAssetLoader.h"
@ -21,5 +19,6 @@ namespace SHADE
{ {
void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept; void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept;
SHAssetData* Load(AssetPath path) override; SHAssetData* Load(AssetPath path) override;
void Write(SHAssetData const* data, AssetPath path) override;
}; };
} }

View File

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

View File

@ -47,17 +47,27 @@ enum class AssetType : AssetTypeMeta
SHADER_BUILT_IN, SHADER_BUILT_IN,
TEXTURE, TEXTURE,
MESH, MESH,
SCENE,
PREFAB,
MATERIAL,
MAX_COUNT MAX_COUNT
}; };
constexpr size_t TYPE_COUNT{ static_cast<size_t>(AssetType::MAX_COUNT) }; constexpr size_t TYPE_COUNT{ static_cast<size_t>(AssetType::MAX_COUNT) };
//Directory //Directory
#ifdef _PUBLISH #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 #else
constexpr std::string_view ASSET_ROOT {"../../Assets"}; constexpr std::string_view ASSET_ROOT {"../../Assets"};
constexpr std::string_view BUILT_IN_ASSET_ROOT{ "../../Built_In" };
#endif #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 // ASSET EXTENSIONS
constexpr std::string_view META_EXTENSION {".shmeta"}; constexpr std::string_view META_EXTENSION {".shmeta"};

View File

@ -10,27 +10,33 @@
#include "SHpch.h" #include "SHpch.h"
#include <random> #include <random>
#include <chrono> #include <chrono>
#include <ranges>
#include "SHAssetManager.h" #include "SHAssetManager.h"
#include "SHAssetMetaHandler.h" #include "SHAssetMetaHandler.h"
#include "Filesystem/SHFileSystem.h"
#include "Libraries/Loaders/SHMeshLoader.h" #include "Libraries/Loaders/SHMeshLoader.h"
#include "Libraries/Loaders/SHTextureLoader.h" #include "Libraries/Loaders/SHTextureLoader.h"
#include "Libraries/Loaders/SHShaderSourceLoader.h" #include "Libraries/Loaders/SHShaderSourceLoader.h"
#include "Libraries/Loaders/SHTextBasedLoader.h"
#include "Libraries/Compilers/SHMeshCompiler.h" #include "Libraries/Compilers/SHMeshCompiler.h"
#include "Libraries/Compilers/SHTextureCompiler.h" #include "Libraries/Compilers/SHTextureCompiler.h"
#include "Libraries/Compilers/SHShaderSourceCompiler.h" #include "Libraries/Compilers/SHShaderSourceCompiler.h"
#include "Filesystem/SHFileSystem.h"
namespace SHADE namespace SHADE
{ {
FolderPointer SHAssetManager::folderRoot{ nullptr };
FMOD::System* SHAssetManager::audioSystem; FMOD::System* SHAssetManager::audioSystem;
std::unordered_map<AssetID, SHSound >* SHAssetManager::audioSoundList; std::unordered_map<AssetID, SHSound >* SHAssetManager::audioSoundList;
std::vector<SHAssetLoader*> SHAssetManager::loaders(TYPE_COUNT); 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; std::unordered_map<AssetID, SHAssetData * const> SHAssetManager::assetData;
/**************************************************************************** /****************************************************************************
* \brief Static function to generate asset ID. * \brief Static function to generate asset ID.
@ -45,13 +51,7 @@ namespace SHADE
result |= unique; result |= unique;
while (result == 0 || while (result == 0 || assetCollection.contains(result))
std::ranges::any_of(
assetCollection.begin(),
assetCollection.end(),
[result](SHAsset const& asset) { return asset.id == result; }
)
)
{ {
result = GenerateAssetID(type); result = GenerateAssetID(type);
} }
@ -61,11 +61,6 @@ namespace SHADE
/**************************************************************************** /****************************************************************************
* \brief Deallocate all memory used by asset data * \brief Deallocate all memory used by asset data
****************************************************************************/ ****************************************************************************/
void SHAssetManager::Unload() noexcept
{
}
void SHAssetManager::Unload(AssetID assetId) noexcept void SHAssetManager::Unload(AssetID assetId) noexcept
{ {
// TODO // TODO
@ -73,14 +68,14 @@ namespace SHADE
void SHAssetManager::Exit() noexcept void SHAssetManager::Exit() noexcept
{ {
for (auto const& loader : loaders) delete loaders[static_cast<size_t>(AssetType::SHADER)];
{ delete loaders[static_cast<size_t>(AssetType::TEXTURE)];
delete loader; delete loaders[static_cast<size_t>(AssetType::MESH)];
} delete loaders[static_cast<size_t>(AssetType::SCENE)];
for (auto const& data : assetData) for (auto const& data : std::ranges::views::values(assetData))
{ {
delete data.second; delete data;
} }
} }
@ -113,8 +108,8 @@ namespace SHADE
{ {
case AssetType::SHADER: case AssetType::SHADER:
case AssetType::SHADER_BUILT_IN: case AssetType::SHADER_BUILT_IN:
folder = "Shaders/"; folder = "Shaders/";
break; break;
default: default:
folder = "/"; folder = "/";
@ -133,9 +128,17 @@ namespace SHADE
* *
* \return const& to unordered_map<AssetName, AssetID> * \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;
} }
/**************************************************************************** /****************************************************************************
@ -148,41 +151,113 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
AssetID SHAssetManager::CreateNewAsset(AssetType type, AssetName name) noexcept AssetID SHAssetManager::CreateNewAsset(AssetType type, AssetName name) noexcept
{ {
AssetID id{ GenerateAssetID(type) }; std::string newPath{ ASSET_ROOT };
SHAsset meta; switch (type)
meta.id = id; {
meta.type = type; case AssetType::PREFAB:
newPath += PREFAB_FOLDER;
break;
std::string folder; case AssetType::SCENE:
//TODO implement folder choosing newPath += SCENE_FOLDER;
//switch (type) break;
//{
//default:
// folder = "";
// break;
//}
AssetPath path{ std::string{ASSET_ROOT} + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) };
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; return id;
} }
AssetID SHAssetManager::CreateAsset(AssetName name, AssetType type) noexcept bool SHAssetManager::SaveAsset(AssetID id) noexcept
{ {
AssetID id = GenerateAssetID(type); 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. * \brief Import new asset from outside editor window.
* *
@ -205,7 +280,8 @@ namespace SHADE
std::filesystem::copy(path, newPath); std::filesystem::copy(path, newPath);
assetCollection.push_back(CreateAssetFromPath(newPath)); auto asset = CreateAssetFromPath(newPath);
assetCollection.insert({asset.id, asset});
return id; return id;
} }
@ -235,7 +311,7 @@ namespace SHADE
std::vector<SHAsset> SHAssetManager::GetAllRecordOfType(AssetType type) noexcept std::vector<SHAsset> SHAssetManager::GetAllRecordOfType(AssetType type) noexcept
{ {
std::vector<SHAsset> result; std::vector<SHAsset> result;
for (auto const& asset : assetCollection) for (auto const& asset : std::ranges::views::values(assetCollection))
{ {
if (asset.type == type) if (asset.type == type)
{ {
@ -246,26 +322,30 @@ namespace SHADE
return result; return result;
} }
AssetID SHAssetManager::CompileAsset(AssetPath path) noexcept 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
{ {
SHAsset newAsset return folderRoot;
{
.name = path.stem().string(),
.location = 0
};
auto const ext{ path.extension().string() };
if (ext == GLSL_EXTENSION.data())
{
newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value();
newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN);
newAsset.type = AssetType::SHADER_BUILT_IN;
}
assetCollection.push_back(newAsset);
SHAssetMetaHandler::WriteMetaData(newAsset);
return newAsset.id;
} }
bool SHAssetManager::IsRecognised(char const* ext) noexcept bool SHAssetManager::IsRecognised(char const* ext) noexcept
@ -289,82 +369,88 @@ namespace SHADE
result.type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string()); result.type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string());
result.id = GenerateAssetID(result.type); result.id = GenerateAssetID(result.type);
result.path = path; result.path = path;
result.location = 0;
return result; return result;
} }
void SHAssetManager::CompileAll() noexcept void SHAssetManager::CompileAll() noexcept
{
std::vector<AssetPath> paths;
for (auto const& dir : std::filesystem::recursive_directory_iterator{ ASSET_ROOT })
{
if (dir.is_regular_file())
{
for (auto const& ext : EXTERNALS)
{
if (dir.path().extension().string() == ext.data())
{
paths.push_back(dir.path());
}
}
}
}
for (auto const& path : paths)
{
SHAsset newAsset
{
.name = path.stem().string()
};
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
{ {
std::vector<AssetPath> paths; //TODO Move this to dedicated library
return std::filesystem::remove(path);
for (auto const& dir : std::filesystem::recursive_directory_iterator{ ASSET_ROOT })
{
if (dir.is_regular_file())
{
for (auto const& ext : EXTERNALS)
{
if (dir.path().extension().string() == ext.data())
{
paths.push_back(dir.path());
}
}
}
}
for (auto const& path : paths)
{
SHAsset newAsset
{
.name = path.stem().string(),
.location = 0
};
auto const ext{ path.extension().string() };
if (ext == GLSL_EXTENSION.data())
{
newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value();
newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN);
newAsset.type = AssetType::SHADER_BUILT_IN;
}
else if (ext == DDS_EXTENSION.data())
{
newAsset.path = SHTextureCompiler::CompileTextureAsset(path).value();
newAsset.id = GenerateAssetID(AssetType::TEXTURE);
newAsset.type = AssetType::TEXTURE;
}
else if (ext == GLTF_EXTENSION.data() || ext == FBX_EXTENSION.data())
{
std::vector<SHMeshAsset*> meshes;
std::vector<SHAnimationAsset*> anims;
SHMeshCompiler::LoadFromFile(path, meshes, anims);
for (auto const& mesh : meshes)
{
SHAsset meshAsset{
.name = mesh->header.name,
.location = 0
};
meshAsset.path = SHMeshCompiler::CompileMeshBinary(*mesh, path).value();
meshAsset.id = GenerateAssetID(AssetType::MESH);
meshAsset.type = AssetType::MESH;
assetCollection.push_back(meshAsset);
SHAssetMetaHandler::WriteMetaData(meshAsset);
}
continue;
}
assetCollection.push_back(newAsset);
SHAssetMetaHandler::WriteMetaData(newAsset);
}
} }
void SHAssetManager::InitLoaders() noexcept void SHAssetManager:: InitLoaders() noexcept
{ {
loaders[static_cast<size_t>(AssetType::SHADER)] = dynamic_cast<SHAssetLoader*>(new SHShaderSourceLoader()); 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::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::TEXTURE)] = dynamic_cast<SHAssetLoader*>(new SHTextureLoader());
loaders[static_cast<size_t>(AssetType::MESH)] = dynamic_cast<SHAssetLoader*>(new SHMeshLoader()); loaders[static_cast<size_t>(AssetType::MESH)] = dynamic_cast<SHAssetLoader*>(new SHMeshLoader());
loaders[static_cast<size_t>(AssetType::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)];
} }
/**************************************************************************** /****************************************************************************
@ -372,9 +458,9 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
void SHAssetManager::Load() noexcept void SHAssetManager::Load() noexcept
{ {
//CompileAll(); //CompileAll();
BuildAssetCollection();
InitLoaders(); InitLoaders();
BuildAssetCollection();
//LoadAllData(); //LoadAllData();
} }
@ -383,7 +469,7 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
void SHAssetManager::LoadAllData() noexcept 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); SHAssetData* data = loaders[static_cast<size_t>(asset.type)]->Load(asset.path);
assetData.emplace(asset.id, data); assetData.emplace(asset.id, data);
@ -406,17 +492,8 @@ namespace SHADE
return data; return data;
} }
void SHAssetManager::BuildAssetCollection() noexcept void SHAssetManager::BuildAssetCollection() noexcept
{ {
for (auto const& dir : std::filesystem::recursive_directory_iterator{ASSET_ROOT}) SHFileSystem::BuildDirectory(ASSET_ROOT.data(), folderRoot, assetCollection);
{ }
if (dir.is_regular_file())
{
if (dir.path().extension().string() == META_EXTENSION.data())
{
assetCollection.push_back(SHAssetMetaHandler::RetrieveMetaData(dir.path()));
}
}
}
}
} }

View File

@ -10,10 +10,12 @@
******************************************************************************/ ******************************************************************************/
#pragma once #pragma once
#include "tinyddsloader.h" #include "tinyddsloader.h"
#include "SHAsset.h" #include "SHAsset.h"
#include "Asset Types/SHAssetData.h" #include "Asset Types/SHAssetData.h"
#include "Assets/Libraries/Loaders/SHAssetLoader.h" #include "Assets/Libraries/Loaders/SHAssetLoader.h"
#include <memory>
#include "Filesystem/SHFolder.h"
#include "SH_API.h" #include "SH_API.h"
@ -26,19 +28,17 @@ namespace SHADE
* \brief Static function to generate resource ID. * \brief Static function to generate resource ID.
****************************************************************************/ ****************************************************************************/
static AssetID GenerateAssetID(AssetType type) noexcept; static AssetID GenerateAssetID(AssetType type) noexcept;
static AssetPath GenerateLocalPath(AssetPath path) noexcept; static AssetPath GenerateLocalPath(AssetPath path) noexcept;
static AssetPath GenerateNewPath(AssetName name, AssetType type); static AssetPath GenerateNewPath(AssetName name, AssetType type);
/**************************************************************************** /****************************************************************************
* \brief Deallocate all memory used by resource data * \brief Deallocate all memory used by resource data
****************************************************************************/ ****************************************************************************/
static void Unload() noexcept;
static void Unload(AssetID assetId) noexcept;
static void Exit() noexcept; static void Exit() noexcept;
static void Unload(AssetID assetId) noexcept;
/**************************************************************************** /****************************************************************************
* \brief Load all resources that are in the folder * \brief Load all resources that are in the folder
****************************************************************************/ ****************************************************************************/
@ -49,7 +49,7 @@ namespace SHADE
* *
* \return const& to unordered_map<AssetName, AssetID> * \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 * \brief Create record for new resource. CAN ONLY CREATE FOR CUSTOM
@ -59,8 +59,9 @@ namespace SHADE
* \param name of resource * \param name of resource
* \return resource id generated for new asset * \return resource id generated for new asset
****************************************************************************/ ****************************************************************************/
static AssetID CreateNewAsset(AssetType, AssetName) noexcept; static AssetID CreateNewAsset(AssetType type, AssetName name) noexcept;
static AssetID CreateAsset(AssetName name, AssetType type) noexcept; static bool SaveAsset(AssetID id) noexcept;
static bool DeleteAsset(AssetID id) noexcept;
/**************************************************************************** /****************************************************************************
* \brief Import new resource from outside editor window. * \brief Import new resource from outside editor window.
@ -78,12 +79,17 @@ namespace SHADE
// -------------------------------------------------------------------------/ // -------------------------------------------------------------------------/
template<typename T> template<typename T>
static std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> GetData(AssetID id) noexcept; static std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T* const> 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<SHAssetData const*> GetAllDataOfType(AssetType type) noexcept;
static std::vector<SHAsset> GetAllRecordOfType(AssetType type) noexcept; static std::vector<SHAsset> GetAllRecordOfType(AssetType type) noexcept;
static AssetID CompileAsset(AssetPath path) noexcept; static AssetID CompileAsset(AssetPath const& path) noexcept;
static FolderPointer GetRootFolder() noexcept;
private: private:
@ -98,13 +104,20 @@ namespace SHADE
static void CompileAll() 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 FMOD::System* audioSystem;
static std::unordered_map<AssetID,SHSound>* audioSoundList; static std::unordered_map<AssetID,SHSound>* audioSoundList;
static std::vector<SHAssetLoader*> loaders; static std::vector<SHAssetLoader*> loaders;
// For all resources // For all resources
static std::vector<SHAsset> assetCollection; static std::unordered_map<AssetID, SHAsset> assetCollection;
static std::unordered_map<AssetID, SHAssetData * const> assetData; static std::unordered_map<AssetID, SHAssetData * const> assetData;
}; };
} }

View File

@ -4,16 +4,16 @@
namespace SHADE namespace SHADE
{ {
template<typename T> 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)) if (!assetData.contains(id))
{ {
for (auto const& asset : assetCollection) for (auto const& asset : std::ranges::views::values(assetCollection))
{ {
if (asset.id == id) if (asset.id == id)
{ {
assetData.emplace(id, LoadData(asset)); 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 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

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

View File

@ -4,14 +4,16 @@
#include "Editor/IconsMaterialDesign.h" #include "Editor/IconsMaterialDesign.h"
#include "Editor/SHImGuiHelpers.hpp" #include "Editor/SHImGuiHelpers.hpp"
#include <imgui.h> #include <imgui.h>
#include <imgui_internal.h>
#include "Assets/SHAssetManager.h" #include "Assets/SHAssetManager.h"
#include "Editor/IconsFontAwesome6.h"
#include "Editor/DragDrop/SHDragDrop.hpp" #include "Editor/DragDrop/SHDragDrop.hpp"
namespace SHADE namespace SHADE
{ {
SHAssetBrowser::SHAssetBrowser() 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() void SHAssetBrowser::Update()
{ {
SHEditorWindow::Update(); SHEditorWindow::Update();
if(Begin()) if (Begin())
{ {
RecursivelyDrawTree(rootFolder);
DrawMenuBar(); DrawMenuBar();
auto const& assets = SHAssetManager::GetAllAssets(); DrawCurrentFolder();
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();
}
} }
ImGui::End(); ImGui::End();
} }
void SHAssetBrowser::DrawMenuBar() void SHAssetBrowser::DrawMenuBar()
{ {
if(ImGui::BeginMenuBar()) if (ImGui::BeginMenuBar())
{ {
ImGui::EndMenuBar(); ImGui::EndMenuBar();
} }
} }
void SHAssetBrowser::DrawAsset(SHAsset const& asset) ImRect SHAssetBrowser::RecursivelyDrawTree(FolderPointer folder)
{ {
ImGui::PushID(asset.id); auto const& subFolders = folder->subFolders;
ImGui::BeginGroup(); auto const& files = folder->files;
const bool isSelected = std::ranges::find(selectedFolders, folder) != selectedFolders.end();
ImGui::TableNextColumn(); ImGuiTreeNodeFlags flags = (subFolders.empty() && files.empty()) ? ImGuiTreeNodeFlags_Leaf : ImGuiTreeNodeFlags_OpenOnArrow;
ImGui::Selectable(std::format("{}", asset.id).data(), false, ImGuiSelectableFlags_SpanAllColumns); if (isSelected)
if(SHDragDrop::BeginSource()) 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; selectedFolders.clear();
ImGui::Text("Moving Asset: %zu", id); selectedFolders.push_back(folder);
SHDragDrop::SetPayload<AssetID>(DRAG_RESOURCE, &id); }
SHDragDrop::EndSource(); 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::TreeNodeEx(file.assetMeta, flags, "%s %s", icon.data(), file.assetMeta->name.data());
ImGui::Text("%s", asset.name.c_str()); const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
if(SHDragDrop::BeginSource())
ImGui::TableNextColumn(); {
ImGui::Text("%s", "Type"); auto id = file.assetMeta->id;
ImGui::Text("Moving Asset: %s [%zu]", file.name.data(), file.assetMeta->id);
ImGui::EndGroup(); SHDragDrop::SetPayload<AssetID>(SHDragDrop::DRAG_RESOURCE, &id);
ImGui::PopID(); 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 #pragma once
#include "imgui_internal.h"
#include "Assets/SHAsset.h" #include "Assets/SHAsset.h"
#include "Editor/EditorWindow/SHEditorWindow.h" #include "Editor/EditorWindow/SHEditorWindow.h"
#include "Filesystem/SHFolder.h"
namespace SHADE namespace SHADE
{ {
@ -16,9 +18,14 @@ namespace SHADE
void Refresh(); void Refresh();
private: private:
void DrawMenuBar(); 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 || //|| SHADE Includes ||
//#==============================================================# //#==============================================================#
#include "Editor/SHEditor.hpp" #include "Editor/SHEditor.h"
#include "Editor/SHImGuiHelpers.hpp" #include "Editor/SHImGuiHelpers.hpp"
#include "Editor/SHEditorWidgets.hpp" #include "Editor/SHEditorWidgets.hpp"
#include "SHHierarchyPanel.h" #include "SHHierarchyPanel.h"
@ -48,15 +48,28 @@ namespace SHADE
if (Begin()) if (Begin())
{ {
if (skipFrame)
{
ImGui::End();
skipFrame = false;
return;
}
DrawMenuBar(); DrawMenuBar();
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
if(const auto root = sceneGraph.GetRoot())
if (const auto root = sceneGraph.GetRoot())
{ {
auto const& children = root->GetChildren(); auto const& children = root->GetChildren();
for (const auto child : children) for (const auto child : children)
{ {
RecursivelyDrawEntityNode(child); if (child)
RecursivelyDrawEntityNode(child);
if (skipFrame)
{
ImGui::End();
return;
}
} }
} }
else else
@ -64,12 +77,36 @@ namespace SHADE
SHLOG_WARNING("Scene Graph root is null! Unable to render hierarchy.") 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(); editor->selectedEntities.clear();
} }
ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal); 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(); ImGui::End();
} }
@ -81,7 +118,7 @@ namespace SHADE
void SHHierarchyPanel::SetScrollTo(EntityID eid) void SHHierarchyPanel::SetScrollTo(EntityID eid)
{ {
if(eid == MAX_EID) if (eid == MAX_EID)
return; return;
scrollTo = eid; scrollTo = eid;
} }
@ -93,8 +130,10 @@ namespace SHADE
{ {
if (ImGui::BeginMenuBar()) if (ImGui::BeginMenuBar())
{ {
ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x * 0.75f); auto size = ImGui::GetWindowSize();
if(ImGui::SmallButton(ICON_MD_DESELECT)) 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>(); auto editor = SHSystemManager::GetSystem<SHEditor>();
editor->selectedEntities.clear(); 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(); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
//Get node data (Children, eid, selected) //Get node data (Children, eid, selected)
auto& children = currentNode->GetChildren(); auto& children = currentNode->GetChildren();
EntityID eid = currentNode->GetEntityID(); EntityID eid = currentNode->GetEntityID();
if(scrollTo != MAX_EID && eid == scrollTo) if (scrollTo != MAX_EID && eid == scrollTo)
{ {
ImGui::SetScrollHereY(); ImGui::SetScrollHereY();
scrollTo = MAX_EID; scrollTo = MAX_EID;
@ -154,23 +195,23 @@ namespace SHADE
if (SHDragDrop::BeginSource()) if (SHDragDrop::BeginSource())
{ {
std::string moveLabel = "Moving EID: "; std::string moveLabel = "Moving EID: ";
if(!isSelected) if (!isSelected)
editor->selectedEntities.push_back(eid); 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])); 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(", "); moveLabel.append(", ");
} }
} }
ImGui::Text(moveLabel.c_str()); 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(); SHDragDrop::EndSource();
} }
else if (SHDragDrop::BeginTarget()) //If Received DragDrop 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); ParentSelectedEntities(eid);
SHDragDrop::EndTarget(); SHDragDrop::EndTarget();
@ -178,37 +219,43 @@ namespace SHADE
} }
//Context menu //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.clear();
editor->selectedEntities.push_back(eid); 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); 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); ParentSelectedEntities(MAX_EID);
} }
ImGui::EndPopup(); ImGui::EndPopup();
} }
//Handle node selection //Handle node selection
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
{ {
@ -216,11 +263,11 @@ namespace SHADE
{ {
if (!isSelected) 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(); else editor->selectedEntities.clear();
} }
@ -278,12 +325,12 @@ namespace SHADE
auto const editor = SHSystemManager::GetSystem<SHEditor>(); auto const editor = SHSystemManager::GetSystem<SHEditor>();
SHEntityParentCommand::EntityParentData entityParentData; SHEntityParentCommand::EntityParentData entityParentData;
std::vector<EntityID> parentedEIDS; 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); parentedEIDS.push_back(eid);
if(auto parent = sceneGraph.GetParent(eid)) if (auto parent = sceneGraph.GetParent(eid))
entityParentData[eid].oldParentEID = parent->GetEntityID(); entityParentData[eid].oldParentEID = parent->GetEntityID();
entityParentData[eid].newParentEID = parentEID; entityParentData[eid].newParentEID = parentEID;
} }
@ -298,34 +345,57 @@ namespace SHADE
editor->selectedEntities.clear(); editor->selectedEntities.clear();
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
sceneGraph.Traverse([&](SHSceneNode* nodePtr) sceneGraph.Traverse([&](SHSceneNode* nodePtr)
{
auto eid = nodePtr->GetEntityID();
if(!startSelecting)
{ {
if(eid == beginEID || eid == endEID) auto eid = nodePtr->GetEntityID();
if (!startSelecting)
{ {
startSelecting = true; if (eid == beginEID || eid == endEID)
editor->selectedEntities.push_back(eid);
}
}
else
{
if(!endSelecting)
{
editor->selectedEntities.push_back(eid);
if(eid == endEID || eid == beginEID)
{ {
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() void SHCreateEntityCommand::Execute()
{ {
EntityID newEID = SHEntityManager::CreateEntity(eid); EntityID newEID = SHEntityManager::CreateEntity(eid);
if(eid == MAX_EID) if (eid == MAX_EID)
eid = newEID; eid = newEID;
} }
@ -337,9 +407,9 @@ namespace SHADE
void SHEntityParentCommand::Execute() void SHEntityParentCommand::Execute()
{ {
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); 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); sceneGraph.SetParent(eid, nullptr);
else else
sceneGraph.SetParent(eid, entityParentData[eid].newParentEID); sceneGraph.SetParent(eid, entityParentData[eid].newParentEID);
@ -349,9 +419,9 @@ namespace SHADE
void SHEntityParentCommand::Undo() void SHEntityParentCommand::Undo()
{ {
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); 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); sceneGraph.SetParent(eid, nullptr);
else else
sceneGraph.SetParent(eid, entityParentData[eid].oldParentEID); sceneGraph.SetParent(eid, entityParentData[eid].oldParentEID);

View File

@ -26,10 +26,14 @@ namespace SHADE
void SetScrollTo(EntityID eid); void SetScrollTo(EntityID eid);
private: private:
void DrawMenuBar() const noexcept; void DrawMenuBar() const noexcept;
ImRect RecursivelyDrawEntityNode(SHSceneNode*); ImRect RecursivelyDrawEntityNode(SHSceneNode* const);
void CreateChildEntity(EntityID parentEID) const noexcept; void CreateChildEntity(EntityID parentEID) const noexcept;
void ParentSelectedEntities(EntityID parentEID) const noexcept; void ParentSelectedEntities(EntityID parentEID) const noexcept;
void SelectRangeOfEntities(EntityID beginEID, EntityID EndEID); void SelectRangeOfEntities(EntityID beginEID, EntityID EndEID);
void SelectAllEntities();
void CopySelectedEntities();
void PasteEntities(EntityID parentEID = MAX_EID);
bool skipFrame = false;
std::string filter; std::string filter;
bool isAnyNodeSelected = false; bool isAnyNodeSelected = false;
EntityID scrollTo = MAX_EID; 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 "Editor/IconsFontAwesome6.h"
#include "ECS_Base/Components/SHComponent.h" #include "ECS_Base/Components/SHComponent.h"
#include "Editor/SHEditorWidgets.hpp" #include "Editor/SHEditorWidgets.hpp"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Components/SHColliderComponent.h"
#include "Reflection/SHReflectionMetadata.h" #include "Reflection/SHReflectionMetadata.h"
#include "Resource/SHResourceManager.h"
namespace SHADE 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) static void DrawContextMenu(T* component)
{ {
if (!component) if (!component)
@ -46,13 +63,15 @@ namespace SHADE
ImGui::EndPopup(); 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) static void DrawComponent(T* component)
{ {
if (!component) if (!component)
return; 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"); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::PopID();
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data())) if (ImGui::CollapsingHeader(componentType.get_name().data()))
{ {
@ -61,7 +80,8 @@ namespace SHADE
for (auto const& property : properties) for (auto const& property : properties)
{ {
auto const& type = property.get_type(); 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()) if (type.is_enumeration())
{ {
auto enumAlign = type.get_enumeration(); auto enumAlign = type.get_enumeration();
@ -75,29 +95,25 @@ namespace SHADE
auto values = enumAlign.get_values(); auto values = enumAlign.get_values();
auto it = std::next(values.begin(), idx); auto it = std::next(values.begin(), idx);
property.set_value(component, *it); property.set_value(component, *it);
}); }, tooltip.is_valid() ? tooltip.template get_value<std::string>() : std::string());
} }
else if (type.is_arithmetic()) else if (type.is_arithmetic())
{ {
if (type == rttr::type::get<bool>()) 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>()) 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 metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
if (metaMin && metaMax) 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 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>()) else if (type == rttr::type::get<uint8_t>())
@ -106,11 +122,11 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid()) 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 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>()) else if (type == rttr::type::get<uint16_t>())
@ -119,11 +135,11 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid()) 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 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>()) else if (type == rttr::type::get<uint32_t>())
@ -132,11 +148,11 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid()) 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 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>()) else if (type == rttr::type::get<uint64_t>())
@ -145,11 +161,11 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid()) 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 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>()) else if (type == rttr::type::get<float>())
@ -157,17 +173,17 @@ namespace SHADE
auto metaMin = property.get_metadata(META::min); auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
float min{}, max{}; float min{}, max{};
if(metaMin.is_valid()) if (metaMin.is_valid())
min = std::max(metaMin.template get_value<float>(), -FLT_MAX * 0.5f); 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); max = std::min(metaMax.template get_value<float>(), FLT_MAX * 0.5f);
if (metaMin.is_valid() && metaMax.is_valid()) 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 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>()) else if (type == rttr::type::get<double>())
@ -176,25 +192,25 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid()) 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 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>()) 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>()) 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>()) 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());
} }
} }
@ -209,10 +225,10 @@ namespace SHADE
return; return;
// Get transform component for extrapolating relative sizes // Get transform component for extrapolating relative sizes
auto* transformComponent = SHComponentManager::GetComponent<SHTransformComponent>(component->GetEID()); auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(component->GetEID());
const auto componentType = rttr::type::get(*component); const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data())) if (ImGui::CollapsingHeader(componentType.get_name().data()))
{ {
@ -220,8 +236,8 @@ namespace SHADE
auto& colliders = component->GetColliders(); auto& colliders = component->GetColliders();
int const size = static_cast<int>(colliders.size()); int const size = static_cast<int>(colliders.size());
ImGui::BeginChild("Colliders", {0.0f, colliders.empty() ? 1.0f : 250.0f}, true); ImGui::BeginChild("Colliders", { 0.0f, colliders.empty() ? 1.0f : 250.0f }, true);
std::optional<int> colliderToDelete{std::nullopt}; std::optional<int> colliderToDelete{ std::nullopt };
for (int i{}; i < size; ++i) for (int i{}; i < size; ++i)
{ {
ImGui::PushID(i); ImGui::PushID(i);
@ -230,12 +246,12 @@ namespace SHADE
if (collider->GetType() == SHCollider::Type::BOX) if (collider->GetType() == SHCollider::Type::BOX)
{ {
SHEditorWidgets::BeginPanel( std::format("{} Box Collider #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); SHEditorWidgets::BeginPanel(std::format("{} Box Collider #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
auto box = reinterpret_cast<SHBoundingBox*>(collider->GetShape()); auto box = reinterpret_cast<SHBoundingBox*>(collider->GetShape());
SHEditorWidgets::DragVec3 SHEditorWidgets::DragVec3
( (
"Half Extents", { "X", "Y", "Z" }, "Half Extents", { "X", "Y", "Z" },
[box, transformComponent] { return (transformComponent->GetWorldScale() * 2.0f) * box->GetHalfExtents(); }, [box, transformComponent] { return (transformComponent->GetWorldScale() * 2.0f) * box->GetHalfExtents(); },
[collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); }); [collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); });
} }
else if (collider->GetType() == SHCollider::Type::SPHERE) else if (collider->GetType() == SHCollider::Type::SPHERE)
@ -244,14 +260,14 @@ namespace SHADE
auto sphere = reinterpret_cast<SHBoundingSphere*>(collider->GetShape()); auto sphere = reinterpret_cast<SHBoundingSphere*>(collider->GetShape());
SHEditorWidgets::DragFloat SHEditorWidgets::DragFloat
( (
"Radius", "Radius",
[sphere, transformComponent] [sphere, transformComponent]
{ {
const SHVec3& TF_WORLD_SCALE = transformComponent->GetWorldScale(); 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 }); const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z });
return sphere->GetRadius() / MAX_SCALE; return sphere->GetRadius() / MAX_SCALE;
}, },
[collider](float const& value) { collider->SetBoundingSphere(value);}); [collider](float const& value) { collider->SetBoundingSphere(value); });
} }
else if (collider->GetType() == SHCollider::Type::CAPSULE) else if (collider->GetType() == SHCollider::Type::CAPSULE)
{ {
@ -262,14 +278,14 @@ namespace SHADE
SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider->GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider->SetPositionOffset(vec); }); SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider->GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider->SetPositionOffset(vec); });
SHEditorWidgets::EndPanel(); SHEditorWidgets::EndPanel();
} }
if(ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data())) if (ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data()))
{ {
colliderToDelete = i; colliderToDelete = i;
} }
SHEditorWidgets::EndPanel(); SHEditorWidgets::EndPanel();
ImGui::PopID(); ImGui::PopID();
} }
if(colliderToDelete.has_value()) if (colliderToDelete.has_value())
{ {
component->RemoveCollider(colliderToDelete.value()); component->RemoveCollider(colliderToDelete.value());
} }
@ -277,11 +293,11 @@ namespace SHADE
if (ImGui::BeginMenu("Add Collider")) if (ImGui::BeginMenu("Add Collider"))
{ {
if(ImGui::Selectable("Box Collider")) if (ImGui::Selectable("Box Collider"))
{ {
component->AddBoundingBox(); component->AddBoundingBox();
} }
if(ImGui::Selectable("Sphere Collider")) if (ImGui::Selectable("Sphere Collider"))
{ {
component->AddBoundingSphere(); component->AddBoundingSphere();
} }
@ -290,4 +306,63 @@ namespace SHADE
} }
else DrawContextMenu(component); 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 "SHpch.h"
#include "Editor/SHEditor.hpp" #include "Editor/SHEditor.h"
#include "SHEditorInspector.h" #include "SHEditorInspector.h"
#include "ECS_Base/SHECSMacros.h" #include "ECS_Base/SHECSMacros.h"
@ -10,17 +10,14 @@
#include "Editor/SHImGuiHelpers.hpp" #include "Editor/SHImGuiHelpers.hpp"
#include "Editor/SHEditorWidgets.hpp" #include "Editor/SHEditorWidgets.hpp"
#include "SHEditorComponentView.hpp"
#include "ECS_Base/UnitTesting/SHTestComponents.h"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
#include "ECS_Base/Managers/SHSystemManager.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/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Components/SHColliderComponent.h"
#include "Camera/SHCameraComponent.h" #include "Camera/SHCameraComponent.h"
#include "SHEditorComponentView.h"
namespace SHADE namespace SHADE
{ {
@ -30,8 +27,17 @@ namespace SHADE
bool selected = false; bool selected = false;
if(!SHComponentManager::HasComponent<ComponentType>(eid)) 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); 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; return selected;
} }
@ -42,13 +48,26 @@ namespace SHADE
bool selected = false; bool selected = false;
if (!SHComponentManager::HasComponent<ComponentType>(eid)) 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) if(SHComponentManager::GetComponent_s<EnforcedComponent>(eid) == nullptr)
SHComponentManager::AddComponent<EnforcedComponent>(eid); SHComponentManager::AddComponent<EnforcedComponent>(eid);
SHComponentManager::AddComponent<ComponentType>(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; return selected;
} }
@ -100,6 +119,10 @@ namespace SHADE
{ {
DrawComponent(rigidbodyComponent); DrawComponent(rigidbodyComponent);
} }
if(auto lightComponent = SHComponentManager::GetComponent_s<SHLightComponent>(eid))
{
DrawComponent(lightComponent);
}
if (auto cameraComponent = SHComponentManager::GetComponent_s<SHCameraComponent>(eid)) if (auto cameraComponent = SHComponentManager::GetComponent_s<SHCameraComponent>(eid))
{ {
DrawComponent(cameraComponent); DrawComponent(cameraComponent);
@ -113,6 +136,7 @@ namespace SHADE
{ {
DrawAddComponentButton<SHTransformComponent>(eid); DrawAddComponentButton<SHTransformComponent>(eid);
DrawAddComponentButton<SHCameraComponent>(eid); DrawAddComponentButton<SHCameraComponent>(eid);
DrawAddComponentButton<SHLightComponent>(eid);
// Components that require Transforms // Components that require Transforms

View File

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

View File

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

View File

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

View File

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

View File

@ -21,7 +21,7 @@
#include "Graphics/MiddleEnd/Interface/SHViewport.h" #include "Graphics/MiddleEnd/Interface/SHViewport.h"
#include "Graphics/MiddleEnd/Interface/SHRenderer.h" #include "Graphics/MiddleEnd/Interface/SHRenderer.h"
#include "SHEditor.hpp" #include "SHEditor.h"
#include "SHEditorWidgets.hpp" #include "SHEditorWidgets.hpp"
#include "Math/Transform/SHTransformSystem.h" #include "Math/Transform/SHTransformSystem.h"
@ -175,7 +175,7 @@ namespace SHADE
ImFontConfig icons_config{}; icons_config.MergeMode = true; icons_config.GlyphOffset.y = 5.f; 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 }; 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 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 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(); io->Fonts->Build();
} }
@ -293,6 +293,7 @@ namespace SHADE
//#==============================================================# //#==============================================================#
void SHEditor::InitBackend() void SHEditor::InitBackend()
{ {
#ifdef SHEDITOR
if(ImGui_ImplSDL2_InitForVulkan(sdlWindow) == false) if(ImGui_ImplSDL2_InitForVulkan(sdlWindow) == false)
{ {
SHLOG_CRITICAL("Editor backend initialisation; Failed to perform SDL initialisation for Vulkan") 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) { renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle<SHVkCommandBuffer>& cmd) {
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer()); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer());
}); });
#endif
} }
void SHEditor::PollPicking() void SHEditor::PollPicking()

View File

@ -22,6 +22,8 @@
#include <misc/cpp/imgui_stdlib.h> #include <misc/cpp/imgui_stdlib.h>
#include <rttr/type.h> #include <rttr/type.h>
#include "DragDrop/SHDragDrop.hpp"
namespace SHADE namespace SHADE
{ {
class SH_API SHEditorWidgets class SH_API SHEditorWidgets
@ -41,7 +43,7 @@ namespace SHADE
ImGui::BeginGroup(); ImGui::BeginGroup();
auto itemSpacing = ImGui::GetStyle().ItemSpacing; 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)); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
auto frameHeight = ImGui::GetFrameHeight(); auto frameHeight = ImGui::GetFrameHeight();
@ -86,7 +88,7 @@ namespace SHADE
auto itemSpacing = ImGui::GetStyle().ItemSpacing; 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)); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
auto frameHeight = ImGui::GetFrameHeight(); auto frameHeight = ImGui::GetFrameHeight();
@ -127,7 +129,7 @@ namespace SHADE
ImGui::GetWindowDrawList()->AddRect( ImGui::GetWindowDrawList()->AddRect(
frameRect.Min, frameRect.Max, frameRect.Min, frameRect.Max,
ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Button)), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled)),
halfFrame.x); halfFrame.x);
ImGui::PopClipRect(); ImGui::PopClipRect();
@ -174,15 +176,19 @@ namespace SHADE
ImGui::SetColumnWidth(-1, 80.0f); ImGui::SetColumnWidth(-1, 80.0f);
ImGui::Text(label.c_str()); ImGui::Text(label.c_str());
if (isHovered) if (isHovered)
*isHovered = ImGui::IsItemHovered(); *isHovered |= ImGui::IsItemHovered();
ImGui::NextColumn(); ImGui::NextColumn();
for (std::size_t i = 0; i < N; ++i) for (std::size_t i = 0; i < N; ++i)
{ {
ImGui::PushID(static_cast<int>(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); ImGui::SetNextItemWidth(80.0f);
valueChanged |= ImGui::DragFloat("##v", values[i], speed, valueMin, valueMax, displayFormat, flags); valueChanged |= ImGui::DragFloat("##v", values[i], speed, valueMin, valueMax, displayFormat, flags);
if (isHovered)
*isHovered |= ImGui::IsItemHovered();
const ImVec2 min = ImGui::GetItemRectMin(); const ImVec2 min = ImGui::GetItemRectMin();
const ImVec2 max = ImGui::GetItemRectMax(); const ImVec2 max = ImGui::GetItemRectMax();
const float spacing = g.Style.FrameRounding; const float spacing = g.Style.FrameRounding;
@ -192,8 +198,8 @@ namespace SHADE
ImGuiColors::colors[i], 4); ImGuiColors::colors[i], 4);
ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); ImGui::SameLine(0, g.Style.ItemInnerSpacing.x);
ImGui::PopID();
ImGui::PopItemWidth(); ImGui::PopItemWidth();
ImGui::PopID();
} }
ImGui::EndColumns(); ImGui::EndColumns();
ImGui::PopID(); 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, 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) ImGuiSliderFlags flags = 0)
{ {
SHVec2 values = get(); 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); bool const changed = DragN<float, 2>(label, componentLabels, { &values.x, &values.y }, speed, displayFormat, valueMin, valueMax, flags);
static bool startRecording = false; static bool startRecording = false;
if (changed) 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); SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), startRecording);
if (!startRecording) if (!startRecording)
startRecording = true; startRecording = true;
} }
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
startRecording = false; startRecording = false;
if(!tooltip.empty()) if (!tooltip.empty())
{ {
if(ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
{ {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::Text(tooltip.data()); 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, 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) ImGuiSliderFlags flags = 0)
{ {
SHVec3 values = get(); 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; static bool startRecording = false;
if (changed) if (changed)
{ {
SHVec3 old = get(); 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); SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(old, values, set)), startRecording);
if (!startRecording) if (!startRecording)
startRecording = true; startRecording = true;
@ -249,9 +270,9 @@ namespace SHADE
{ {
startRecording = false; startRecording = false;
} }
if(!tooltip.empty()) if (!tooltip.empty())
{ {
if(ImGui::IsItemHovered()) if (isHovered)
{ {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::Text(tooltip.data()); 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, 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) ImGuiSliderFlags flags = 0)
{ {
SHVec4 values = get(); 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); 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; static bool startRecording = false;
if (changed) 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); SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), startRecording);
if (!startRecording) if (!startRecording)
startRecording = true; startRecording = true;
@ -278,9 +307,9 @@ namespace SHADE
{ {
startRecording = false; startRecording = false;
} }
if(!tooltip.empty()) if (!tooltip.empty())
{ {
if(ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
{ {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::Text(tooltip.data()); ImGui::Text(tooltip.data());
@ -297,7 +326,7 @@ namespace SHADE
static void TextLabel(std::string_view const& text, bool sameLine = true) static void TextLabel(std::string_view const& text, bool sameLine = true)
{ {
const ImVec2 textSize = ImGui::CalcTextSize(text.data(), NULL, 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::Text(text.data());
ImGui::SameLine(); ImGui::SameLine();
@ -310,32 +339,32 @@ namespace SHADE
ImGui::BeginGroup(); ImGui::BeginGroup();
ImGui::PushID(label.data()); ImGui::PushID(label.data());
TextLabel(label); 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); SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<bool>>(get(), value, set)), false);
return true;
} }
ImGui::PopID(); ImGui::PopID();
ImGui::EndGroup(); ImGui::EndGroup();
if(!tooltip.empty()) if (!tooltip.empty())
{ {
if(ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
{ {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::Text(tooltip.data()); ImGui::Text(tooltip.data());
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
} }
return false; return changed;
} }
template<typename T> 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(); T type = get();
ImGui::BeginGroup(); ImGui::BeginGroup();
ImGui::PushID(label.data()); ImGui::PushID(label.data());
TextLabel(label); //TextLabel(label);
for (size_t i = 0; i < listTypes.size(); i++) for (size_t i = 0; i < listTypes.size(); i++)
{ {
if (ImGui::RadioButton(label[i].c_str(), type == listTypes[i])) if (ImGui::RadioButton(label[i].c_str(), type == listTypes[i]))
@ -366,12 +395,11 @@ namespace SHADE
ImGui::BeginGroup(); ImGui::BeginGroup();
ImGui::PushID(label.data()); ImGui::PushID(label.data());
TextLabel(label); TextLabel(label);
if (ImGui::InputText("##", &text, flag, callback, userData)) bool const changed = ImGui::InputText("##", &text, flag, callback, userData);
if (changed)
{ {
if (ImGui::IsItemDeactivatedAfterEdit()) if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<std::string>>(get(), text, set)), false); SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<std::string>>(get(), text, set)), false);
return true;
} }
ImGui::PopID(); ImGui::PopID();
ImGui::EndGroup(); ImGui::EndGroup();
@ -384,7 +412,37 @@ namespace SHADE
ImGui::EndTooltip(); 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> template <typename T>
@ -442,9 +500,9 @@ namespace SHADE
} }
ImGui::PopID(); ImGui::PopID();
ImGui::EndGroup(); ImGui::EndGroup();
if(!tooltip.empty()) if (!tooltip.empty())
{ {
if(ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
{ {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::Text(tooltip.data()); ImGui::Text(tooltip.data());
@ -615,5 +673,43 @@ namespace SHADE
} }
return edited; 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 }//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 "SHpch.h"
#include "SHFileSystem.h" #include "SHFileSystem.h"
#include "fileapi.h"
#include <filesystem> #include <filesystem>
#include <queue> #include <queue>
#include "Assets/SHAssetMetaHandler.h"
namespace SHADE 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 bool SHFileSystem::DeleteFolder(FolderPointer location) noexcept
{ {
if (!folders.contains(location->id)) //TODO IMPLEMENT
{
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());
return true; 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; std::queue<FolderPointer> folderQueue;
root = new SHFolder("root");
folderQueue.push(RegisterFolder(path, 0, 0, "Root")); root->path = path;
folderQueue.push(root);
while (!folderQueue.empty()) while (!folderQueue.empty())
{ {
auto folder = folderQueue.front(); auto const folder = folderQueue.front();
folderQueue.pop(); folderQueue.pop();
FolderCounter count = 0;
std::vector<SHAsset> assets;
for (auto const& dirEntry : std::filesystem::directory_iterator(folder->path)) for (auto const& dirEntry : std::filesystem::directory_iterator(folder->path))
{ {
auto const& path = dirEntry.path();
if (!dirEntry.is_directory()) if (!dirEntry.is_directory())
{ {
folder->files.emplace_back( if (path.extension().string() == META_EXTENSION)
dirEntry.path().filename().string(), {
dirEntry.path().string(), //auto asset = SHAssetMetaHandler::RetrieveMetaData(path);
dirEntry.path().extension().string() //assetCollection.insert({ asset.id, asset });
); assets.push_back(SHAssetMetaHandler::RetrieveMetaData(path));
}
continue; else
{
folder->files.emplace_back(
path.stem().string(),
path.string(),
path.extension().string(),
nullptr
);
}
continue;
} }
FolderLocation location = folder->id; auto newFolder{ folder->CreateSubFolderHere(path.stem().string()) };
location <<= FOLDER_BIT_ALLOCATE; folderQueue.push(newFolder);
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);
} }
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 #pragma once
#include <string> #include "SHFolder.h"
#include <vector>
#include <memory>
#include <unordered_map> #include <unordered_map>
namespace SHADE 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 class SHFileSystem
{ {
public: public:
static FolderLocation CreateNewFolderHere(FolderName name, FolderLocation here = 0) noexcept; static void BuildDirectory(FolderPath path, FolderPointer& root, std::unordered_map<AssetID, SHAsset>& assetCollection) noexcept;
static bool DeleteFolder(FolderPointer location) noexcept;
static void StartupFillDirectories(FolderPath path) noexcept;
static FolderPointer GetRoot() noexcept;
private: private:
static FolderPointer root; static bool DeleteFolder(FolderPointer location) noexcept;
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;
}; };
} }

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 vk::PhysicalDeviceFeatures features{}; // ADD MORE FEATURES HERE IF NEEDED
// point and lines fill mode // point and lines fill mode
features.fillModeNonSolid = true; features.fillModeNonSolid = VK_TRUE;
features.samplerAnisotropy = VK_TRUE; features.samplerAnisotropy = VK_TRUE;
features.multiDrawIndirect = true; features.multiDrawIndirect = VK_TRUE;
features.independentBlend = VK_TRUE;
// for wide lines // for wide lines
features.wideLines = true; features.wideLines = true;

View File

@ -194,7 +194,8 @@ namespace SHADE
{ {
SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!"); SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
} }
propsCurrPtr += singleMatPropAlignedSize; //propsCurrPtr += singleMatPropAlignedSize;
propsCurrPtr += singleMatPropSize;
} }
// Transfer to GPU // Transfer to GPU
@ -316,7 +317,7 @@ namespace SHADE
{ {
singleMatPropSize = SHADER_INFO->GetBytesRequired(); singleMatPropSize = SHADER_INFO->GetBytesRequired();
singleMatPropAlignedSize = device->PadSSBOSize(static_cast<uint32_t>(singleMatPropSize)); singleMatPropAlignedSize = device->PadSSBOSize(static_cast<uint32_t>(singleMatPropSize));
matPropTotalBytes = numTotalElements * singleMatPropAlignedSize; matPropTotalBytes = numTotalElements * singleMatPropSize;
if (matPropsDataSize < matPropTotalBytes) if (matPropsDataSize < matPropTotalBytes)
{ {
matPropsData.reset(new char[matPropTotalBytes]); matPropsData.reset(new char[matPropTotalBytes]);
@ -375,7 +376,8 @@ namespace SHADE
{ {
SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!"); 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) // For global data (generic data and textures)
Handle<SHVkDescriptorSetLayout> staticGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS,{ genericDataBinding, texturesBinding }); Handle<SHVkDescriptorSetLayout> staticGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS,{ genericDataBinding, texturesBinding });
std::vector<SHVkDescriptorSetLayout::Binding> lightBindings{}; 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 lightBindings.push_back (SHVkDescriptorSetLayout::Binding
{ {
.Type = vk::DescriptorType::eStorageBufferDynamic, .Type = vk::DescriptorType::eStorageBufferDynamic,
.Stage = vk::ShaderStageFlagBits::eFragment, .Stage = vk::ShaderStageFlagBits::eCompute,
.BindPoint = i, .BindPoint = i,
.DescriptorCount = 1, .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) // For Dynamic global data (lights)
Handle<SHVkDescriptorSetLayout> dynamicGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, lightBindings); Handle<SHVkDescriptorSetLayout> dynamicGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, lightBindings);
SHVkDescriptorSetLayout::Binding cameraDataBinding SHVkDescriptorSetLayout::Binding cameraDataBinding
{ {
.Type = vk::DescriptorType::eUniformBufferDynamic, .Type = vk::DescriptorType::eUniformBufferDynamic,

View File

@ -94,32 +94,14 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
static constexpr uint32_t IMAGE_AND_SAMPLERS_DATA = 1; static constexpr uint32_t IMAGE_AND_SAMPLERS_DATA = 1;
///***************************************************************************/ /***************************************************************************/
///*! /*!
// \brief \brief
// DescriptorSet binding for directional lights. DescriptorSet binding for combined image sampler data.
//*/ */
///***************************************************************************/ /***************************************************************************/
//static constexpr uint32_t DIRECTIONAL_LIGHT_DATA = 0; static constexpr uint32_t LIGHTING_COUNT = 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;
/***************************************************************************/ /***************************************************************************/
/*! /*!

View File

@ -17,7 +17,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/Windowing/Surface/SHVkSurface.h" #include "Graphics/Windowing/Surface/SHVkSurface.h"
#include "Graphics/Swapchain/SHVkSwapchain.h" #include "Graphics/Swapchain/SHVkSwapchain.h"
#include "Camera/SHCameraSystem.h" #include "Camera/SHCameraSystem.h"
#include "Editor/SHEditor.hpp" #include "Editor/SHEditor.h"
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
//#include "SHRenderer.h" //#include "SHRenderer.h"
#include "Graphics/Windowing/SHWindow.h" #include "Graphics/Windowing/SHWindow.h"
@ -73,15 +73,7 @@ namespace SHADE
if (width == 0 || height == 0) if (width == 0 || height == 0)
return; return;
#ifdef SHEDITOR PrepareResize(resizeWidth, resizeHeight);
//PrepareResize(1, 1, SHVec2(0, 0));
#else
PrepareResize(resizeWidth, resizeHeight, SHVec2(0, 0));
#endif
}); });
window->RegisterWindowCloseCallback([&](void) window->RegisterWindowCloseCallback([&](void)
@ -160,26 +152,45 @@ namespace SHADE
// Initialize world render graph // Initialize world render graph
worldRenderGraph->Init(device, swapchain); 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("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("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("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("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("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("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"); auto gBufferSubpass = gBufferNode->AddSubpass("G-Buffer Write");
gBufferSubpass->AddColorOutput("Scene Pre-Process"); gBufferSubpass->AddColorOutput("Position");
gBufferSubpass->AddColorOutput("Entity ID"); gBufferSubpass->AddColorOutput("Entity ID");
gBufferSubpass->AddColorOutput("Light Layer Indices"); gBufferSubpass->AddColorOutput("Light Layer Indices");
gBufferSubpass->AddColorOutput("Normals");
gBufferSubpass->AddColorOutput("Albedo");
gBufferSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL); gBufferSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL);
//// kirsch //// kirsch
//auto kirschShader = shaderModuleLibrary.GetShaderModule("KirschCs"); //auto kirschShader = shaderModuleLibrary.GetShaderModule("KirschCs.glsl");
//gBufferNode->AddNodeCompute(kirschShader, { "Scene Pre-Process", "Scene" }); //gBufferNode->AddNodeCompute(kirschShader, { "Position", "Scene" });
// copy //// copy
auto pureCopyShader = shaderModuleLibrary.GetBuiltInShaderModule("PureCopy_CS"); //auto pureCopyShader = shaderModuleLibrary.GetShaderModule("PureCopyCs.glsl");
gBufferNode->AddNodeCompute(pureCopyShader, { "Scene Pre-Process", "Scene" }); //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 auto dummyNode = worldRenderGraph->AddNode("Dummy Pass", { "Scene" }, {"G-Buffer"}); // no predecessors
@ -311,6 +322,12 @@ namespace SHADE
void SHGraphicsSystem::Run(double) noexcept void SHGraphicsSystem::Run(double) noexcept
{ {
if (window->IsMinimized() || renderContext.GetWindowIsDead()) if (window->IsMinimized() || renderContext.GetWindowIsDead())
{
restoredFromMinimize = true;
return;
}
if (restoredFromMinimize)
return; return;
// Frame data for the current frame // Frame data for the current frame
@ -362,6 +379,7 @@ namespace SHADE
// Force set the pipeline layout // Force set the pipeline layout
currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout(), SH_PIPELINE_TYPE::GRAPHICS); currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout(), SH_PIPELINE_TYPE::GRAPHICS);
currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout(), SH_PIPELINE_TYPE::COMPUTE);
// Bind all the buffers required for meshes // Bind all the buffers required for meshes
for (auto& [buffer, bindingPoint] : MESH_DATA) for (auto& [buffer, bindingPoint] : MESH_DATA)
@ -444,7 +462,15 @@ namespace SHADE
void SHGraphicsSystem::BeginRender() void SHGraphicsSystem::BeginRender()
{ {
if (window->IsMinimized() || renderContext.GetWindowIsDead()) if (window->IsMinimized() || renderContext.GetWindowIsDead())
{
restoredFromMinimize = true;
return; return;
}
if (restoredFromMinimize)
{
return;
}
// Finalise all batches // Finalise all batches
for (auto vp : viewports) for (auto vp : viewports)
@ -493,7 +519,17 @@ namespace SHADE
void SHGraphicsSystem::EndRender() void SHGraphicsSystem::EndRender()
{ {
if (window->IsMinimized() || renderContext.GetWindowIsDead()) if (window->IsMinimized() || renderContext.GetWindowIsDead())
{
restoredFromMinimize = true;
return; return;
}
if (restoredFromMinimize)
{
restoredFromMinimize = false;
return;
}
const uint32_t CURR_FRAME_IDX = renderContext.GetCurrentFrame(); const uint32_t CURR_FRAME_IDX = renderContext.GetCurrentFrame();
auto& currFrameData = renderContext.GetCurrentFrameData(); auto& currFrameData = renderContext.GetCurrentFrameData();

View File

@ -360,5 +360,7 @@ namespace SHADE
uint32_t resizeWidth; uint32_t resizeWidth;
uint32_t resizeHeight; uint32_t resizeHeight;
bool restoredFromMinimize = false;
}; };
} }

View File

@ -28,7 +28,7 @@ namespace SHADE
material = {}; material = {};
oldMaterial = {}; oldMaterial = {};
lightLayer = 0; lightLayer = 1;
} }
void SHRenderable::OnDestroy() void SHRenderable::OnDestroy()

View File

@ -10,7 +10,7 @@ namespace SHADE
lightData.Reset(); lightData.Reset();
SetType(SH_LIGHT_TYPE::DIRECTIONAL); SetType(SH_LIGHT_TYPE::DIRECTIONAL);
indexInBuffer = std::numeric_limits<uint32_t>::max(); indexInBuffer = std::numeric_limits<uint32_t>::max();
active = true; isActive = true;
Unbind(); Unbind();
} }
@ -20,7 +20,7 @@ namespace SHADE
} }
void SHLightComponent::SetPosition(SHVec3 position) noexcept void SHLightComponent::SetPosition(SHVec3 const& position) noexcept
{ {
lightData.position = position; lightData.position = position;
MakeDirty(); MakeDirty();
@ -34,20 +34,20 @@ namespace SHADE
} }
void SHLightComponent::SetDirection(SHVec3 direction) noexcept void SHLightComponent::SetDirection(SHVec3 const& direction) noexcept
{ {
lightData.direction = direction; lightData.direction = direction;
MakeDirty(); MakeDirty();
} }
void SHLightComponent::SetDiffuseColor(SHVec4 diffuseColor) noexcept void SHLightComponent::SetColor(SHVec4 const& color) noexcept
{ {
lightData.diffuseColor = diffuseColor; lightData.color = color;
MakeDirty(); MakeDirty();
} }
void SHLightComponent::ModifyLayer(uint8_t layerIndex, bool value) noexcept void SHLightComponent::ModifyCullingMask(uint8_t layerIndex, bool value) noexcept
{ {
if (value) if (value)
lightData.cullingMask |= (1u << layerIndex); lightData.cullingMask |= (1u << layerIndex);
@ -57,6 +57,10 @@ namespace SHADE
MakeDirty(); MakeDirty();
} }
void SHLightComponent::SetCullingMask(uint32_t const& value) noexcept
{
lightData.cullingMask = value;
}
void SHLightComponent::SetAllLayers(void) noexcept void SHLightComponent::SetAllLayers(void) noexcept
{ {
@ -93,11 +97,11 @@ namespace SHADE
indexInBuffer = inIndexInBuffer; 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 SHLightData const& SHLightComponent::GetLightData(void) const noexcept
@ -105,6 +109,32 @@ namespace SHADE
return lightData; 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 bool SHLightComponent::IsDirty(void) const noexcept
{ {
return dirty; return dirty;
@ -120,4 +150,32 @@ namespace SHADE
return indexInBuffer; 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 #pragma once
#include <rttr/registration>
#include "ECS_Base/Components/SHComponent.h" #include "ECS_Base/Components/SHComponent.h"
#include "SHLightData.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. //! If the light's data is already in the buffers, this will be set to true.
bool bound; bool bound;
//! If the light is active, this is true.
bool active;
public: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -37,24 +36,31 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */ /* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void SetPosition (SHVec3 position) noexcept; void SetPosition (SHVec3 const& position) noexcept; // serialized
void SetType (SH_LIGHT_TYPE type) noexcept; void SetType (SH_LIGHT_TYPE type) noexcept; // serialized
void SetDirection (SHVec3 direction) noexcept; void SetDirection (SHVec3 const& direction) noexcept; // serialized
void SetDiffuseColor (SHVec4 diffuseColor) noexcept; void SetColor (SHVec4 const& color) noexcept; // serialized
void ModifyLayer (uint8_t layerIndex, bool value) noexcept; void ModifyCullingMask (uint8_t layerIndex, bool value) noexcept; // serialized
void SetAllLayers (void) noexcept; void SetCullingMask (uint32_t const& value) noexcept;
void ClearAllLayers (void) noexcept; void SetAllLayers (void) noexcept; // serialized
void MakeDirty (void) noexcept; void ClearAllLayers (void) noexcept; // serialized
void ClearDirtyFlag (void) noexcept; void MakeDirty (void) noexcept;
void Unbind (void) noexcept; void ClearDirtyFlag (void) noexcept;
void SetBound (uint32_t inIndexInBuffer) noexcept; void Unbind (void) noexcept;
void SetActive (bool flag) 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 IsDirty (void) const noexcept;
bool GetBound (void) const noexcept; bool GetBound (void) const noexcept;
uint32_t GetIndexInBuffer (void) const noexcept; uint32_t GetIndexInBuffer (void) const noexcept;
float GetStrength (void) const noexcept;
RTTR_ENABLE()
}; };
} }

View File

@ -15,7 +15,7 @@ namespace SHADE
direction = SHVec3::Forward; direction = SHVec3::Forward;
// Diffuse color set to 1 // Diffuse color set to 1
diffuseColor = SHVec4::One; color = SHVec4::One;
} }
} }

View File

@ -10,6 +10,7 @@ namespace SHADE
DIRECTIONAL = 0, DIRECTIONAL = 0,
POINT, POINT,
SPOT, SPOT,
AMBIENT,
NUM_TYPES NUM_TYPES
}; };
@ -40,7 +41,11 @@ namespace SHADE
uint32_t cullingMask; uint32_t cullingMask;
//! Diffuse color emitted by the light //! Diffuse color emitted by the light
SHVec4 diffuseColor; SHVec4 color;
//! Strength of the light
float strength;
void Reset (void) noexcept; void Reset (void) noexcept;
//! TODO: //! TODO:

View File

@ -42,13 +42,23 @@ namespace SHADE
lightPtr->cullingMask = lightData.cullingMask; lightPtr->cullingMask = lightData.cullingMask;
lightPtr->direction = lightData.direction; lightPtr->direction = lightData.direction;
lightPtr->diffuseColor = lightData.diffuseColor; lightPtr->diffuseColor = lightData.color;
lightPtr->active = lightComp->isActive;
break; break;
} }
case SH_LIGHT_TYPE::POINT: case SH_LIGHT_TYPE::POINT:
break; break;
case SH_LIGHT_TYPE::SPOT: case SH_LIGHT_TYPE::SPOT:
break; break;
case SH_LIGHT_TYPE::AMBIENT:
{
SHAmbientLightData* lightPtr = reinterpret_cast<SHAmbientLightData*>(address);
lightPtr->ambientColor = lightData.color;
lightPtr->strength = lightData.strength;
lightPtr->cullingMask = lightData.cullingMask;
lightPtr->active = lightComp->isActive;
break;
}
case SH_LIGHT_TYPE::NUM_TYPES: case SH_LIGHT_TYPE::NUM_TYPES:
break; break;
default: default:
@ -57,6 +67,7 @@ namespace SHADE
} }
} }
/***************************************************************************/ /***************************************************************************/
/*! /*!
@ -76,8 +87,9 @@ namespace SHADE
// boilerplate // boilerplate
intermediateData = nullptr; intermediateData = nullptr;
// initialize alignment // Get data required for struct
lightDataAlignmentSize = logicalDevice->PadSSBOSize(GetLightTypeSize(type)); lightDataSize = GetLightTypeSize(type);
lightDataAlignedSize = logicalDevice->PadSSBOSize(lightDataSize);
// So create some data! // So create some data!
Expand(logicalDevice); Expand(logicalDevice);
@ -94,7 +106,7 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
void SHLightingSubSystem::PerTypeData::Expand(Handle<SHVkLogicalDevice> logicalDevice) noexcept void SHLightingSubSystem::PerTypeData::Expand(Handle<SHVkLogicalDevice> logicalDevice) noexcept
{ {
if (lightDataAlignmentSize == 0) if (lightDataSize == 0)
{ {
SHLOG_ERROR ("One of the types of lights have not been accounted for. Make sure lightDataAlignmentSize is not nullptr."); SHLOG_ERROR ("One of the types of lights have not been accounted for. Make sure lightDataAlignmentSize is not nullptr.");
return; return;
@ -111,10 +123,12 @@ namespace SHADE
numLights = 0; numLights = 0;
// Initialize the data for lights // Initialize the data for lights
intermediateData = std::make_unique<uint8_t[]>(lightDataAlignmentSize * maxLights); intermediateData = std::make_unique<uint8_t[]>(lightDataSize * maxLights);
lightDataTotalAlignedSize = logicalDevice->PadSSBOSize(lightDataAlignedSize * maxLights);
// We want to initialize 3 times the amount of data required. // We want to initialize 3 times the amount of data required.
dataBuffer = logicalDevice->CreateBuffer(maxLights * lightDataAlignmentSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, nullptr, maxLights * lightDataAlignmentSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); dataBuffer = logicalDevice->CreateBuffer(lightDataTotalAlignedSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, nullptr, lightDataTotalAlignedSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT);
} }
else else
{ {
@ -122,24 +136,27 @@ namespace SHADE
uint32_t const OLD_MAX_LIGHTS = maxLights; uint32_t const OLD_MAX_LIGHTS = maxLights;
// before we increase the number of lights, create space to store old data. // before we increase the number of lights, create space to store old data.
std::unique_ptr<uint8_t[]> oldData = std::make_unique<uint8_t[]>(lightDataAlignmentSize * OLD_MAX_LIGHTS); std::unique_ptr<uint8_t[]> oldData = std::make_unique<uint8_t[]>(lightDataSize * OLD_MAX_LIGHTS);
// copy data over. // copy data over.
std::memcpy (oldData.get(), intermediateData.get(), lightDataAlignmentSize * OLD_MAX_LIGHTS); std::memcpy (oldData.get(), intermediateData.get(), lightDataSize * OLD_MAX_LIGHTS);
// now we start to expand.... // now we start to expand....
// double space for lights // double space for lights
maxLights *= 2; maxLights *= 2;
// calculate total + padding
lightDataTotalAlignedSize = logicalDevice->PadSSBOSize(lightDataAlignedSize * maxLights);
// destroy old data and initialize container for double the amount of data. // destroy old data and initialize container for double the amount of data.
intermediateData = std::make_unique<uint8_t[]>(lightDataAlignmentSize * maxLights); intermediateData = std::make_unique<uint8_t[]>(lightDataSize * maxLights);
// copy old data to new container // copy old data to new container
std::memcpy(intermediateData.get(), oldData.get(), lightDataAlignmentSize * OLD_MAX_LIGHTS); std::memcpy(intermediateData.get(), oldData.get(), lightDataSize * OLD_MAX_LIGHTS);
// Resize the GPU buffer. TODO: Replace with Resize no copy here // Resize the GPU buffer. TODO: Replace with Resize no copy here
dataBuffer->ResizeReplace(maxLights * lightDataAlignmentSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, oldData.get(), lightDataAlignmentSize * OLD_MAX_LIGHTS); dataBuffer->ResizeReplace(maxLights * lightDataTotalAlignedSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, oldData.get(), lightDataTotalAlignedSize * OLD_MAX_LIGHTS);
} }
@ -171,6 +188,9 @@ namespace SHADE
case SH_LIGHT_TYPE::SPOT: case SH_LIGHT_TYPE::SPOT:
// TOOD: Change after creating spot light struct // TOOD: Change after creating spot light struct
return 4; return 4;
case SH_LIGHT_TYPE::AMBIENT:
return sizeof(SHAmbientLightData);
return 4;
case SH_LIGHT_TYPE::NUM_TYPES: case SH_LIGHT_TYPE::NUM_TYPES:
default: default:
return 4; return 4;
@ -187,7 +207,12 @@ namespace SHADE
uint32_t SHLightingSubSystem::PerTypeData::GetAlignmentSize(void) const noexcept uint32_t SHLightingSubSystem::PerTypeData::GetAlignmentSize(void) const noexcept
{ {
return lightDataAlignmentSize; return lightDataTotalAlignedSize;
}
uint32_t SHLightingSubSystem::PerTypeData::GetDataSize(void) const noexcept
{
return lightDataSize;
} }
uint32_t SHLightingSubSystem::PerTypeData::GetNumLights(void) const noexcept uint32_t SHLightingSubSystem::PerTypeData::GetNumLights(void) const noexcept
@ -231,7 +256,7 @@ namespace SHADE
// Now that the container is big enough, bind the new light // Now that the container is big enough, bind the new light
// Get address of write location // Get address of write location
void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignmentSize * numLights); void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignedSize * numLights);
// Write the light data to address // Write the light data to address
WriteLightToAddress(writeLocation, unboundLight); WriteLightToAddress(writeLocation, unboundLight);
@ -257,7 +282,7 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
void SHLightingSubSystem::PerTypeData::ModifyLight(SHLightComponent* lightComp) noexcept void SHLightingSubSystem::PerTypeData::ModifyLight(SHLightComponent* lightComp) noexcept
{ {
void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignmentSize * lightComp->GetIndexInBuffer()); void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignedSize * lightComp->GetIndexInBuffer());
WriteLightToAddress(writeLocation, lightComp); WriteLightToAddress(writeLocation, lightComp);
} }
@ -266,10 +291,15 @@ namespace SHADE
if (intermediateData) if (intermediateData)
{ {
// we want to write to the offset of the current frame // we want to write to the offset of the current frame
dataBuffer->WriteToMemory(intermediateData.get(), lightDataAlignmentSize * numLights, 0, lightDataAlignmentSize * maxLights * frameIndex); dataBuffer->WriteToMemory(intermediateData.get(), lightDataAlignedSize * numLights, 0, lightDataAlignedSize * maxLights * frameIndex);
} }
} }
void SHLightingSubSystem::PerTypeData::ResetNumLights(void) noexcept
{
numLights = 0;
}
/***************************************************************************/ /***************************************************************************/
/*! /*!
@ -287,12 +317,12 @@ namespace SHADE
// We bind the buffer with the correct desc set binding // We bind the buffer with the correct desc set binding
lightingDataDescSet->ModifyWriteDescBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, lightingDataDescSet->ModifyWriteDescBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS,
binding, binding + 1, // we want to +1 here because the first binding is reserved for count
{ &buffer, 1 }, { &buffer, 1 },
0, 0,
perTypeData[binding].GetAlignmentSize() * perTypeData[binding].GetMaxLights()); perTypeData[binding].GetDataSize() * perTypeData[binding].GetMaxLights());
lightingDataDescSet->UpdateDescriptorSetBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, binding); lightingDataDescSet->UpdateDescriptorSetBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, binding + 1); // +1 here, same reason. see above
} }
/***************************************************************************/ /***************************************************************************/
@ -307,16 +337,27 @@ namespace SHADE
{ {
for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i) for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{ {
for (uint32_t j = 0; j < dynamicOffsets.size(); ++j) dynamicOffsets[i][0] = i * lightCountsAlignedSize;
// Even if the first binding is a count, we want to account for that too
for (uint32_t j = 0; j < static_cast<uint32_t>(SH_LIGHT_TYPE::NUM_TYPES); ++j)
{ {
auto const& typeData = perTypeData[j]; auto const& typeData = perTypeData[j];
{ {
dynamicOffsets[i][j] = j * typeData.GetAlignmentSize() * typeData.GetMaxLights(); // +1 because 1st reserved for count
dynamicOffsets[i][j + 1] = i * typeData.GetAlignmentSize();
} }
} }
} }
} }
void SHLightingSubSystem::ResetNumLights(void) noexcept
{
for (auto& data : perTypeData)
{
data.ResetNumLights();
}
}
/***************************************************************************/ /***************************************************************************/
/*! /*!
@ -346,12 +387,26 @@ namespace SHADE
// initialize all the data first. We add more lights here as we add more types. // initialize all the data first. We add more lights here as we add more types.
perTypeData[i].InitializeData(logicalDevice, static_cast<SH_LIGHT_TYPE>(i)); perTypeData[i].InitializeData(logicalDevice, static_cast<SH_LIGHT_TYPE>(i));
UpdateDescSet(i); UpdateDescSet(i);
// no lights at first
lightCountsData[i] = 0;
} }
lightCountsAlignedSize = sizeof (uint32_t) * NUM_LIGHT_TYPES;
lightCountsAlignedSize = logicalDevice->PadUBOSize(lightCountsAlignedSize);
// Create the GPU buffer to hold light count
lightCountsBuffer = logicalDevice->CreateBuffer(lightCountsAlignedSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, nullptr, lightCountsAlignedSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, vk::BufferUsageFlagBits::eUniformBuffer, VMA_MEMORY_USAGE_AUTO, VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT);
lightingDataDescSet->ModifyWriteDescBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, SHGraphicsConstants::DescriptorSetBindings::LIGHTING_COUNT, {&lightCountsBuffer, 1}, 0, sizeof (uint32_t) * NUM_LIGHT_TYPES);
lightingDataDescSet->UpdateDescriptorSetBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, SHGraphicsConstants::DescriptorSetBindings::LIGHTING_COUNT);
for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i) for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{ {
dynamicOffsets[i].resize(NUM_LIGHT_TYPES); dynamicOffsets[i].resize(NUM_LIGHT_TYPES + 1); // +1 for the count
} }
numLightComponents = 0;
} }
/***************************************************************************/ /***************************************************************************/
@ -366,17 +421,32 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
void SHLightingSubSystem::Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept void SHLightingSubSystem::Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{ {
static uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES);
auto& lightComps = SHComponentManager::GetDense<SHLightComponent>(); auto& lightComps = SHComponentManager::GetDense<SHLightComponent>();
bool expanded = false; bool expanded = false;
bool rewrite = false;
if (numLightComponents > lightComps.size())
{
rewrite = true;
ResetNumLights();
}
numLightComponents = lightComps.size();
for (auto& light : lightComps) for (auto& light : lightComps)
{ {
auto enumValue = SHUtilities::ToUnderlying(light.GetLightData().type); auto enumValue = SHUtilities::ToUnderlying(light.GetLightData().type);
// First we want to make sure the light is already bound to the system. if it // First we want to make sure the light is already bound to the system. if it
// isn't, we write it to the correct buffer. // isn't, we write it to the correct buffer.
if (!light.GetBound()) if (!light.GetBound() || rewrite)
{ {
perTypeData[enumValue].AddLight(logicalDevice, &light, expanded); perTypeData[enumValue].AddLight(logicalDevice, &light, expanded);
//// add to light count
//++lightCountsData[enumValue];
} }
// if there was modification to the light data // if there was modification to the light data
@ -396,6 +466,13 @@ namespace SHADE
data.WriteToGPU(frameIndex); data.WriteToGPU(frameIndex);
} }
for (uint32_t i = 0; i < NUM_LIGHT_TYPES; ++i)
{
lightCountsData[i] = perTypeData[i].GetNumLights();
}
lightCountsBuffer->WriteToMemory(lightCountsData.data(), static_cast<uint32_t>(lightCountsData.size()) * sizeof (uint32_t), 0, lightCountsAlignedSize * frameIndex);
// If any of the buffers got expanded, the descriptor set is invalid because the expanded buffer // If any of the buffers got expanded, the descriptor set is invalid because the expanded buffer
// is a new buffer. If some expansion was detected, update descriptor sets. // is a new buffer. If some expansion was detected, update descriptor sets.
if (expanded) if (expanded)
@ -412,7 +489,7 @@ namespace SHADE
ComputeDynamicOffsets(); ComputeDynamicOffsets();
// Bind descriptor set (We bind at an offset because the buffer holds NUM_FRAME_BUFFERS sets of data). // Bind descriptor set (We bind at an offset because the buffer holds NUM_FRAME_BUFFERS sets of data).
cmdBuffer->BindDescriptorSet(lightingDataDescSet, SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, {dynamicOffsets[frameIndex]}); cmdBuffer->BindDescriptorSet(lightingDataDescSet, SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, {dynamicOffsets[frameIndex]});
} }

View File

@ -17,7 +17,7 @@ namespace SHADE
class SHVkCommandBuffer; class SHVkCommandBuffer;
// Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU. // Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU.
struct SHDirectionalLightData struct SHDirectionalLightData
{ {
//! Direction of the light //! Direction of the light
SHVec3 direction; SHVec3 direction;
@ -31,7 +31,27 @@ namespace SHADE
uint32_t cullingMask; uint32_t cullingMask;
//! Diffuse color emitted by the light //! Diffuse color emitted by the light
SHVec4 diffuseColor; alignas (16) SHVec4 diffuseColor;
};
// Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU.
struct SHAmbientLightData
{
//! Diffuse color emitted by the light
SHVec4 ambientColor;
//! Strength of the ambient light
float strength;
//! Represents if the light is active or not
uint32_t active;
//! Each bit in this 32 bit field will represent a layer. If the bit is set,
//! when a fragment is being evaluated, the shader will use the fragment's
//! layer value to AND with the light's. If result is 1, do lighting calculations.
uint32_t cullingMask;
}; };
@ -45,7 +65,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* STATIC MEMBER VARIABLES */ /* STATIC MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static constexpr uint32_t STARTING_NUM_LIGHTS = 20; static constexpr uint32_t STARTING_NUM_LIGHTS = 50;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */ /* PRIVATE MEMBER VARIABLES */
@ -53,8 +73,13 @@ namespace SHADE
//! Capacity of the container. //! Capacity of the container.
uint32_t maxLights; uint32_t maxLights;
//! SSBOs need to be aligned. This is to pad lighting structs //! SSBOs need to be aligned. This is to pad descriptor offset
uint32_t lightDataAlignmentSize; uint32_t lightDataTotalAlignedSize;
//! size needed to store 1 struct object
uint32_t lightDataSize;
uint32_t lightDataAlignedSize;
//! type of the light. Will be used later when we want to expand //! type of the light. Will be used later when we want to expand
SH_LIGHT_TYPE lightType; SH_LIGHT_TYPE lightType;
@ -80,6 +105,7 @@ namespace SHADE
void AddLight (Handle<SHVkLogicalDevice> logicalDevice, SHLightComponent* unboundLight, bool expanded) noexcept; void AddLight (Handle<SHVkLogicalDevice> logicalDevice, SHLightComponent* unboundLight, bool expanded) noexcept;
void ModifyLight (SHLightComponent* lightComp) noexcept; void ModifyLight (SHLightComponent* lightComp) noexcept;
void WriteToGPU (uint32_t frameIndex) noexcept; void WriteToGPU (uint32_t frameIndex) noexcept;
void ResetNumLights (void) noexcept;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* GETTERS */ /* GETTERS */
@ -87,6 +113,7 @@ namespace SHADE
static uint32_t GetLightTypeSize (SH_LIGHT_TYPE type) noexcept; static uint32_t GetLightTypeSize (SH_LIGHT_TYPE type) noexcept;
Handle<SHVkBuffer> GetDataBuffer (void) const noexcept; Handle<SHVkBuffer> GetDataBuffer (void) const noexcept;
uint32_t GetAlignmentSize (void) const noexcept; uint32_t GetAlignmentSize (void) const noexcept;
uint32_t GetDataSize (void) const noexcept;
uint32_t GetNumLights (void) const noexcept; uint32_t GetNumLights (void) const noexcept;
uint32_t GetMaxLights (void) const noexcept; uint32_t GetMaxLights (void) const noexcept;
}; };
@ -105,11 +132,26 @@ namespace SHADE
//! Container to store dynamic offsets for binding descriptor sets //! Container to store dynamic offsets for binding descriptor sets
std::array<std::vector<uint32_t>, static_cast<uint32_t>(SHGraphicsConstants::NUM_FRAME_BUFFERS)> dynamicOffsets; std::array<std::vector<uint32_t>, static_cast<uint32_t>(SHGraphicsConstants::NUM_FRAME_BUFFERS)> dynamicOffsets;
//! holds the data that represents how many lights are in the scene
std::array<uint32_t, static_cast<uint32_t>(SH_LIGHT_TYPE::NUM_TYPES)> lightCountsData;
//! GPU buffer to hold lightCountData
Handle<SHVkBuffer> lightCountsBuffer;
//! For padding in the buffer
uint32_t lightCountsAlignedSize;
//! Number of SHLightComponents recorded. If at the beginning of the run function the size returned by the dense
//! set is less than the size recorded, rewrite all light components into the its respective buffers. If its more,
//! don't do anything.
uint32_t numLightComponents;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */ /* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void UpdateDescSet (uint32_t binding) noexcept; void UpdateDescSet (uint32_t binding) noexcept;
void ComputeDynamicOffsets (void) noexcept; void ComputeDynamicOffsets (void) noexcept;
void ResetNumLights (void) noexcept;
public: public:

View File

@ -133,6 +133,7 @@ namespace SHADE
{ {
SHLOG_ERROR("Frame index retrieved from vkAcquireNextImageKHR is not the same as currentFrame."); SHLOG_ERROR("Frame index retrieved from vkAcquireNextImageKHR is not the same as currentFrame.");
} }
currentFrame = frameIndex; currentFrame = frameIndex;
} }

View File

@ -276,7 +276,7 @@ namespace SHADE
} }
// Create the subpass compute with the resources // Create the subpass compute with the resources
auto nodeCompute = graphStorage->resourceManager->Create<SHRenderGraphNodeCompute>(graphStorage, computeShaderModule, std::move(nodeComputeResources)); auto nodeCompute = graphStorage->resourceManager->Create<SHRenderGraphNodeCompute>(graphStorage, computeShaderModule, std::move(nodeComputeResources), nodeComputes.empty());
nodeComputes.push_back(nodeCompute); nodeComputes.push_back(nodeCompute);
return nodeCompute; return nodeCompute;

View File

@ -13,12 +13,13 @@
namespace SHADE namespace SHADE
{ {
SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, float inNumWorkGroupScale/* = 1.0f*/) noexcept SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, bool followingEndRP, float inNumWorkGroupScale/* = 1.0f*/) noexcept
: computePipeline{} : computePipeline{}
, pipelineLayout{} , pipelineLayout{}
, resources{} , resources{}
, groupSizeX{0} , groupSizeX{0}
, groupSizeY{0} , groupSizeY{0}
, followingEndRenderpass {followingEndRP}
, numWorkGroupScale {std::clamp(inNumWorkGroupScale, 0.0f, 1.0f)} , numWorkGroupScale {std::clamp(inNumWorkGroupScale, 0.0f, 1.0f)}
{ {
SHPipelineLayoutParams pipelineLayoutParams SHPipelineLayoutParams pipelineLayoutParams
@ -53,7 +54,6 @@ namespace SHADE
descSetGroups[i] = graphStorage->descriptorPool->Allocate(layouts, variableCounts); descSetGroups[i] = graphStorage->descriptorPool->Allocate(layouts, variableCounts);
} }
HandleResize(); HandleResize();
} }
@ -68,8 +68,9 @@ namespace SHADE
// dispatch compute // dispatch compute
cmdBuffer->ComputeDispatch(groupSizeX, groupSizeY, 1); cmdBuffer->ComputeDispatch(groupSizeX, groupSizeY, 1);
// TODO: barrier cmdBuffer->PipelineBarrier((followingEndRenderpass) ? vk::PipelineStageFlagBits::eFragmentShader : vk::PipelineStageFlagBits::eComputeShader,
vk::PipelineStageFlagBits::eFragmentShader,
{}, {}, {}, memoryBarriers[frameIndex]);
} }
void SHRenderGraphNodeCompute::HandleResize(void) noexcept void SHRenderGraphNodeCompute::HandleResize(void) noexcept
@ -104,6 +105,36 @@ namespace SHADE
groupSizeX = maxWidth / workGroupSizeX; groupSizeX = maxWidth / workGroupSizeX;
groupSizeY = maxHeight / workGroupSizeY; groupSizeY = maxHeight / workGroupSizeY;
for (uint32_t i = 0; auto& barriers : memoryBarriers)
{
barriers.clear();
for (auto& resource : resources)
{
vk::AccessFlags srcAccessMask = (followingEndRenderpass) ? vk::AccessFlagBits::eInputAttachmentRead : (vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite);
barriers.push_back(vk::ImageMemoryBarrier
{
.srcAccessMask = srcAccessMask,
.dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite,
.oldLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eGeneral,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = resource->GetImage((resource->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? i : 0)->GetVkImage(),
.subresourceRange = vk::ImageSubresourceRange
{
.aspectMask = resource->imageAspectFlags,
.baseMipLevel = 0,
.levelCount = resource->mipLevels,
.baseArrayLayer = 0,
.layerCount = 1,
}
});
}
++i;
}
} }
} }

View File

@ -2,6 +2,7 @@
#include "Resource/SHHandle.h" #include "Resource/SHHandle.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "Graphics/SHVulkanIncludes.h"
#include <initializer_list> #include <initializer_list>
#include <string> #include <string>
#include <unordered_set> #include <unordered_set>
@ -44,8 +45,12 @@ namespace SHADE
float numWorkGroupScale; float numWorkGroupScale;
bool followingEndRenderpass;
std::array<std::vector<vk::ImageMemoryBarrier>, SHGraphicsConstants::NUM_FRAME_BUFFERS> memoryBarriers;
public: public:
SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, float inNumWorkGroupScale = 1.0f) noexcept; SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, bool followingEndRP, float inNumWorkGroupScale = 1.0f) noexcept;
void Execute (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept; void Execute (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void HandleResize (void) noexcept; void HandleResize (void) noexcept;

View File

@ -54,13 +54,14 @@ namespace SHADE
if (wndData.isFullscreen) if (wndData.isFullscreen)
{ {
dwExStyle = WS_EX_APPWINDOW | WS_EX_ACCEPTFILES; dwExStyle = WS_EX_APPWINDOW;
dwStyle = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; dwStyle = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
dwExStyle |= WS_EX_ACCEPTFILES;
} }
else else
{ {
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE | WS_EX_ACCEPTFILES; dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwExStyle |= WS_EX_ACCEPTFILES;
if (wndData.frameEnabled) if (wndData.frameEnabled)
{ {
dwStyle = WNDSTYLE::SHWS_WINDOWED; dwStyle = WNDSTYLE::SHWS_WINDOWED;
@ -87,7 +88,7 @@ namespace SHADE
} }
} }
//DPI_AWARENESS_CONTEXT prevDPIContext = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); DPI_AWARENESS_CONTEXT prevDPIContext = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
RECT windowRect; RECT windowRect;
windowRect.left = wndData.x; //or CW_USEDEFAULT ? windowRect.left = wndData.x; //or CW_USEDEFAULT ?
@ -97,13 +98,16 @@ namespace SHADE
AdjustWindowRectEx(&windowRect, dwStyle, false, dwExStyle); AdjustWindowRectEx(&windowRect, dwStyle, false, dwExStyle);
//Create window //Create window
wndHWND = CreateWindowEx(0, (LPWSTR) wndData.name.c_str(), (LPWSTR)wndData.title.c_str(), dwStyle, 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, parent, NULL, hInstance, NULL); wndHWND = CreateWindowEx(dwExStyle, (LPWSTR) wndData.name.c_str(), (LPWSTR)wndData.title.c_str(), dwStyle, 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, parent, NULL, hInstance, NULL);
if (!wndHWND) if (!wndHWND)
{ {
//DWORD err = GetLastError(); //DWORD err = GetLastError();
return false; return false;
} }
BOOL help = ChangeWindowMessageFilter (WM_DROPFILES, MSGFLT_ADD);
help &= ChangeWindowMessageFilter (WM_COPYDATA, MSGFLT_ADD);
help &= ChangeWindowMessageFilter (0x0049, MSGFLT_ADD);
if (wndData.isVisible) if (wndData.isVisible)
{ {
@ -318,13 +322,13 @@ namespace SHADE
case WM_CREATE: case WM_CREATE:
OnCreate(hwnd, reinterpret_cast<LPCREATESTRUCT>(wparam)); OnCreate(hwnd, reinterpret_cast<LPCREATESTRUCT>(wparam));
break; break;
case WM_QUIT:
case WM_CLOSE: case WM_CLOSE:
case WM_DESTROY: case WM_DESTROY:
OnDestroy(); OnDestroy();
return 0; return 0;
case WM_DROPFILES: case WM_DROPFILES:
//OnFileDrop(reinterpret_cast<HDROP>(wparam)); OnFileDrop(reinterpret_cast<HDROP>(wparam));
break; break;
case WM_ENTERSIZEMOVE: case WM_ENTERSIZEMOVE:
case WM_EXITSIZEMOVE: case WM_EXITSIZEMOVE:
@ -386,12 +390,25 @@ namespace SHADE
void SHWindow::OnDestroy() void SHWindow::OnDestroy()
{ {
OnClose(); OnClose();
DragAcceptFiles(wndHWND, false);
this->Destroy(); this->Destroy();
} }
//void SHWindow::OnFileDrop(HDROP drop) void SHWindow::OnFileDrop(HDROP drop)
//{ {
//}
int const numFiles = static_cast<int>(DragQueryFile(drop, 0xFFFFFFFF, nullptr, 0));
for(int i = 0; i < numFiles; ++i)
{
//char fileNameBuffer[MAX_PATH];
std::wstring fileNameBuffer;
fileNameBuffer.reserve(MAX_PATH);
DragQueryFile(drop, static_cast<UINT>(i), fileNameBuffer.data(), MAX_PATH);
std::string name(fileNameBuffer.begin(), fileNameBuffer.end());
SHLOG_INFO("Dropped: {}", name)
}
DragFinish(drop);
}
void SHWindow::OnSize([[maybe_unused]] UINT msg,[[maybe_unused]] UINT type, SIZE size) void SHWindow::OnSize([[maybe_unused]] UINT msg,[[maybe_unused]] UINT type, SIZE size)
{ {

View File

@ -2,6 +2,7 @@
#define SH_WINDOW_H #define SH_WINDOW_H
#include <Windows.h> #include <Windows.h>
#include <shellapi.h>
#include <functional> #include <functional>
#include <unordered_map> #include <unordered_map>
#include "SHWindowMap.h" #include "SHWindowMap.h"
@ -10,7 +11,7 @@
namespace SHADE namespace SHADE
{ {
constexpr uint16_t MAX_BUFFER = 1024; constexpr uint16_t MAX_BUFFER = 1024;
enum WNDSTYLE : DWORD enum WNDSTYLE : DWORD
{ {
SHWS_WINDOWED = WS_OVERLAPPEDWINDOW, SHWS_WINDOWED = WS_OVERLAPPEDWINDOW,
@ -47,7 +48,7 @@ namespace SHADE
//bool canFullscreen = true; //bool canFullscreen = true;
unsigned bgColor = WHITE_BRUSH; unsigned bgColor = DKGRAY_BRUSH;
//bool transparent = false; //bool transparent = false;
@ -168,7 +169,7 @@ namespace SHADE
void OnCreate(HWND hwnd, LPCREATESTRUCT create_struct); void OnCreate(HWND hwnd, LPCREATESTRUCT create_struct);
void OnClose(); void OnClose();
void OnDestroy(); void OnDestroy();
//void OnFileDrop(HDROP drop); void OnFileDrop(HDROP drop);
void OnSize(UINT msg, UINT type, SIZE size); void OnSize(UINT msg, UINT type, SIZE size);
void OnPosChange(LPWINDOWPOS pos); void OnPosChange(LPWINDOWPOS pos);
void OnPaint(HDC hdc, LPPAINTSTRUCT paint); void OnPaint(HDC hdc, LPPAINTSTRUCT paint);

View File

@ -14,6 +14,7 @@
#include "SHTransformComponent.h" #include "SHTransformComponent.h"
// Project Headers // Project Headers
#include "Math/SHMathHelpers.h" #include "Math/SHMathHelpers.h"
#include "Reflection/SHReflectionMetadata.h"
namespace SHADE namespace SHADE
{ {
@ -184,7 +185,7 @@ RTTR_REGISTRATION
using namespace rttr; using namespace rttr;
registration::class_<SHTransformComponent>("Transform Component") registration::class_<SHTransformComponent>("Transform Component")
.property("Translate" , &SHTransformComponent::GetLocalPosition , &SHTransformComponent::SetLocalPosition ) .property("Translate" ,&SHTransformComponent::GetLocalPosition ,&SHTransformComponent::SetLocalPosition ) (metadata(META::tooltip, "Translate"))
.property("Rotate" , &SHTransformComponent::GetLocalRotation , select_overload<void(const SHVec3&)>(&SHTransformComponent::SetLocalRotation) ) .property("Rotate" ,&SHTransformComponent::GetLocalRotation ,select_overload<void(const SHVec3&)>(&SHTransformComponent::SetLocalRotation) ) (metadata(META::tooltip, "Rotate"), metadata(META::angleInRad, true))
.property("Scale" , &SHTransformComponent::GetLocalScale , &SHTransformComponent::SetLocalScale ); .property("Scale" ,&SHTransformComponent::GetLocalScale ,&SHTransformComponent::SetLocalScale ) (metadata(META::tooltip, "Scale"));
} }

View File

@ -263,6 +263,9 @@ namespace SHADE
auto* node = EVENT_DATA->data->node; auto* node = EVENT_DATA->data->node;
auto* tf = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID()); auto* tf = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID());
if(tf == nullptr)
return EVENT_DATA->handle;
// Recompute local transform and store localToWorld Matrix // Recompute local transform and store localToWorld Matrix
SHMatrix localToWorld = SHMatrix::Identity; SHMatrix localToWorld = SHMatrix::Identity;
SHMatrix worldToLocal = SHMatrix::Identity; SHMatrix worldToLocal = SHMatrix::Identity;

View File

@ -146,4 +146,12 @@ namespace SHADE
system->RemoveCollisionShape(GetEID(), index); system->RemoveCollisionShape(GetEID(), index);
} }
} // namespace SHADE } // namespace SHADE
RTTR_REGISTRATION
{
using namespace rttr;
using namespace SHADE;
registration::class_<SHColliderComponent>("Collider Component");
}

View File

@ -100,5 +100,6 @@ namespace SHADE
SHQuaternion orientation; SHQuaternion orientation;
Colliders colliders; Colliders colliders;
RTTR_ENABLE()
}; };
} // namespace SHADE } // namespace SHADE

View File

@ -17,7 +17,7 @@
#include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHEntityManager.h"
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.hpp" #include "Editor/SHEditor.h"
#include "Math/SHMathHelpers.h" #include "Math/SHMathHelpers.h"
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"

View File

@ -7,5 +7,6 @@ namespace SHADE
constexpr const char* min = "MIN"; constexpr const char* min = "MIN";
constexpr const char* max = "MAX"; constexpr const char* max = "MAX";
constexpr const char* tooltip = "tooltip"; constexpr const char* tooltip = "tooltip";
constexpr const char* angleInRad = "angleInRad";
} }
} }

View File

@ -0,0 +1,56 @@
#include "SHpch.h"
#include "SHPrefabManager.h"
namespace SHADE
{
SHPrefabManager::PrefabMap SHPrefabManager::prefabMap{};
void SHPrefabManager::AddPrefab(AssetID const& prefabAssetID) noexcept
{
prefabMap.insert({ prefabAssetID, {} });
}
void SHPrefabManager::RemovePrefab(AssetID const& prefabAssetID) noexcept
{
prefabMap.erase(prefabAssetID);
}
void SHPrefabManager::ClearPrefab(AssetID const& prefabAssetID) noexcept
{
if (prefabMap.contains(prefabAssetID))
{
prefabMap[prefabAssetID].clear();
}
}
void SHPrefabManager::UpdateAllPrefabEntities(AssetID const& prefabAssetID) noexcept
{
//Loop through all entities and deserialize new data
}
void SHPrefabManager::AddEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept
{
if (prefabMap.contains(prefabAssetID))
{
prefabMap[prefabAssetID].insert(eid);
}
}
void SHPrefabManager::RemoveEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept
{
if (prefabMap.contains(prefabAssetID))
{
prefabMap[prefabAssetID].erase(eid);
}
}
void SHPrefabManager::Clear() noexcept
{
prefabMap.clear();
}
bool SHPrefabManager::Empty() noexcept
{
return prefabMap.empty();
}
}

View File

@ -0,0 +1,28 @@
#pragma once
#include "Assets/SHAssetMacros.h"
#include "ECS_Base/SHECSMacros.h"
#include <unordered_set>
#include <unordered_map>
namespace SHADE
{
class SHPrefabManager
{
public:
using PrefabMap = std::unordered_map<AssetID, std::unordered_set<EntityID>>;
static void AddPrefab(AssetID const& prefabAssetID) noexcept;
static void RemovePrefab(AssetID const& prefabAssetID) noexcept;
static void ClearPrefab(AssetID const& prefabAssetID) noexcept;
static void UpdateAllPrefabEntities(AssetID const& prefabAssetID) noexcept;
static void AddEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept;
static void RemoveEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept;
static void Clear() noexcept;
static bool Empty() noexcept;
private:
static PrefabMap prefabMap;
};
}

View File

@ -10,10 +10,12 @@
#include "Assets/SHAssetManager.h" #include "Assets/SHAssetManager.h"
#include <fstream> #include <fstream>
#include "Camera/SHCameraComponent.h"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Physics/Components/SHRigidBodyComponent.h" #include "Physics/Components/SHRigidBodyComponent.h"
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
namespace SHADE namespace SHADE
@ -57,7 +59,7 @@ namespace SHADE
static EntityID DeserializeEntity(YAML::iterator& it, YAML::Node const& node, std::vector<EntityID>& createdEntities, EntityID parentEID = MAX_EID) static EntityID DeserializeEntity(YAML::iterator& it, YAML::Node const& node, std::vector<EntityID>& createdEntities, EntityID parentEID = MAX_EID)
{ {
EntityID eid = MAX_EID; EntityID eid = MAX_EID;
if(!node) if (!node)
return eid; return eid;
if (node[EIDNode]) if (node[EIDNode])
eid = node[EIDNode].as<EntityID>(); eid = node[EIDNode].as<EntityID>();
@ -70,13 +72,13 @@ namespace SHADE
createdEntities.push_back(eid); createdEntities.push_back(eid);
if (node[NumberOfChildrenNode]) if (node[NumberOfChildrenNode])
{ {
if(const int numOfChildren = node[NumberOfChildrenNode].as<int>(); numOfChildren > 0) if (const int numOfChildren = node[NumberOfChildrenNode].as<int>(); numOfChildren > 0)
{ {
++it; ++it;
for (int i = 0; i < numOfChildren; ++i) for (int i = 0; i < numOfChildren; ++i)
{ {
DeserializeEntity(it, (*it), createdEntities, eid); DeserializeEntity(it, (*it), createdEntities, eid);
if((i + 1) < numOfChildren) if ((i + 1) < numOfChildren)
++it; ++it;
} }
} }
@ -84,7 +86,9 @@ namespace SHADE
// Deserialise scripts // Deserialise scripts
if (node[ScriptsNode]) if (node[ScriptsNode])
SHSystemManager::GetSystem<SHScriptEngine>()->DeserialiseScripts(eid, node[ScriptsNode]); SHSystemManager::GetSystem<SHScriptEngine>()->DeserialiseScripts(eid, node[ScriptsNode]);
return eid;
} }
void SHSerialization::DeserializeSceneFromFile(std::filesystem::path const& path) void SHSerialization::DeserializeSceneFromFile(std::filesystem::path const& path)
@ -119,10 +123,10 @@ namespace SHADE
{ {
DeserializeEntity(it, (*it), createdEntities); DeserializeEntity(it, (*it), createdEntities);
} }
if(createdEntities.empty()) if (createdEntities.empty())
{ {
SHLOG_ERROR("Failed to create entities from deserializaiton") SHLOG_ERROR("Failed to create entities from deserializaiton")
return; return;
} }
//Initialize Entity //Initialize Entity
auto entityVecIt = createdEntities.begin(); auto entityVecIt = createdEntities.begin();
@ -136,7 +140,7 @@ namespace SHADE
{ {
out << SerializeEntityToNode(entityNode); out << SerializeEntityToNode(entityNode);
auto const& children = entityNode->GetChildren(); auto const& children = entityNode->GetChildren();
for(auto const& child : children) for (auto const& child : children)
{ {
EmitEntity(child, out); EmitEntity(child, out);
} }
@ -161,17 +165,36 @@ namespace SHADE
{ {
} }
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static void AddComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid)
{
if (const ComponentType* component = SHComponentManager::GetComponent_s<ComponentType>(eid))
{
componentsNode[rttr::type::get<ComponentType>().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(component);
}
}
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static void AddConvComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid)
{
if (ComponentType* component = SHComponentManager::GetComponent_s<ComponentType>(eid))
{
componentsNode[rttr::type::get<ComponentType>().get_name().data()] = YAML::convert<ComponentType>::encode(*component);
}
}
YAML::Node SHSerialization::SerializeEntityToNode(SHSceneNode* sceneNode) YAML::Node SHSerialization::SerializeEntityToNode(SHSceneNode* sceneNode)
{ {
YAML::Node node; YAML::Node node;
auto eid = sceneNode->GetEntityID(); auto eid = sceneNode->GetEntityID();
auto entity = SHEntityManager::GetEntityByID(eid); auto entity = SHEntityManager::GetEntityByID(eid);
if (!sceneNode || !entity) if (!sceneNode && !entity)
{ {
node = YAML::Null; node = YAML::Null;
return node; return node;
} }
node.SetStyle(YAML::EmitterStyle::Block); node.SetStyle(YAML::EmitterStyle::Block);
node[EIDNode] = eid; node[EIDNode] = eid;
node[EntityNameNode] = entity->name; node[EntityNameNode] = entity->name;
node[IsActiveNode] = sceneNode->IsActive(); node[IsActiveNode] = sceneNode->IsActive();
@ -180,18 +203,13 @@ namespace SHADE
YAML::Node components; YAML::Node components;
if (const auto transform = SHComponentManager::GetComponent_s<SHTransformComponent>(eid)) AddComponentToComponentNode<SHTransformComponent>(components, eid);
{ AddComponentToComponentNode<SHCameraComponent>(components, eid);
components[rttr::type::get<SHTransformComponent>().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(transform); AddConvComponentToComponentNode<SHRenderable>(components, eid);
} AddComponentToComponentNode<SHLightComponent>(components, eid);
if (const auto renderable = SHComponentManager::GetComponent_s<SHRenderable>(eid)) AddComponentToComponentNode<SHRigidBodyComponent>(components, eid);
{ AddConvComponentToComponentNode<SHColliderComponent>(components, eid);
components[rttr::type::get<SHRenderable>().get_name().data()] = *renderable;
}
if (const auto rigidbody = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(eid))
{
components[rttr::type::get<SHRigidBodyComponent>().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(rigidbody);
}
node[ComponentsNode] = components; node[ComponentsNode] = components;
YAML::Node scripts; YAML::Node scripts;
@ -203,22 +221,22 @@ namespace SHADE
EntityID SHSerialization::DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID) noexcept EntityID SHSerialization::DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID) noexcept
{ {
if(data.empty()) if (data.empty())
return MAX_EID; return MAX_EID;
YAML::Node entities = YAML::Load(data.c_str()); YAML::Node entities = YAML::Load(data.c_str());
EntityID eid{MAX_EID}; EntityID eid{ MAX_EID };
std::vector<EntityID> createdEntities; std::vector<EntityID> createdEntities;
for(auto it = entities.begin(); it != entities.end(); ++it) for (auto it = entities.begin(); it != entities.end(); ++it)
{ {
eid = DeserializeEntity(it, *it, createdEntities, parentEID); eid = DeserializeEntity(it, *it, createdEntities, parentEID);
} }
if(createdEntities.empty()) if (createdEntities.empty())
{ {
SHLOG_ERROR("Failed to create entities from deserializaiton") SHLOG_ERROR("Failed to create entities from deserializaiton")
return MAX_EID; return MAX_EID;
} }
auto entityVecIt = createdEntities.begin(); auto entityVecIt = createdEntities.begin();
for(auto it = entities.begin(); it != entities.end(); ++it) for (auto it = entities.begin(); it != entities.end(); ++it)
{ {
InitializeEntity(*it, *entityVecIt++); InitializeEntity(*it, *entityVecIt++);
} }
@ -226,29 +244,22 @@ namespace SHADE
} }
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
std::optional<ComponentTypeID> GetComponentID(YAML::Node const& componentNode) static void AddComponentID(std::vector<ComponentTypeID>& idList, YAML::Node const& componentNode)
{ {
if (componentNode[rttr::type::get<ComponentType>().get_name().data()]) if (componentNode[rttr::type::get<ComponentType>().get_name().data()])
return { SHFamilyID<SHComponent>::GetID<ComponentType>() }; idList.push_back(SHFamilyID<SHComponent>::GetID<ComponentType>());
else
return std::nullopt;
} }
std::vector<ComponentTypeID> SHSerialization::GetComponentIDList(YAML::Node const& componentsNode) std::vector<ComponentTypeID> SHSerialization::GetComponentIDList(YAML::Node const& componentsNode)
{ {
std::vector<ComponentTypeID> componentIDList; std::vector<ComponentTypeID> componentIDList;
auto id = GetComponentID<SHTransformComponent>(componentsNode); AddComponentID<SHTransformComponent>(componentIDList, componentsNode);
if (id.has_value()) AddComponentID<SHCameraComponent>(componentIDList, componentsNode);
componentIDList.push_back(id.value()); AddComponentID<SHRenderable>(componentIDList, componentsNode);
AddComponentID<SHRigidBodyComponent>(componentIDList, componentsNode);
id = GetComponentID<SHRenderable>(componentsNode); AddComponentID<SHLightComponent>(componentIDList, componentsNode);
if (id.has_value()) AddComponentID<SHColliderComponent>(componentIDList, componentsNode);
componentIDList.push_back(id.value());
id = GetComponentID<SHRigidBodyComponent>(componentsNode);
if (id.has_value())
componentIDList.push_back(id.value());
return componentIDList; return componentIDList;
} }
@ -259,6 +270,10 @@ namespace SHADE
if (!componentsNode) if (!componentsNode)
return; return;
SHSerializationHelper::InitializeComponentFromNode<SHTransformComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHTransformComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHCameraComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHRigidBodyComponent>(componentsNode, eid);
SHSerializationHelper::ConvertNodeToComponent<SHRenderable>(componentsNode, eid); SHSerializationHelper::ConvertNodeToComponent<SHRenderable>(componentsNode, eid);
SHSerializationHelper::ConvertNodeToComponent<SHColliderComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHLightComponent>(componentsNode, eid);
} }
} }

View File

@ -13,10 +13,236 @@
#include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Graphics/MiddleEnd/Interface/SHMaterial.h" #include "Graphics/MiddleEnd/Interface/SHMaterial.h"
#include "SHSerializationTools.h" #include "SHSerializationTools.h"
#include "Physics/Components/SHColliderComponent.h"
namespace YAML namespace YAML
{ {
using namespace SHADE; using namespace SHADE;
template<>
struct convert<SHVec4>
{
static constexpr const char* x = "x";
static constexpr const char* y = "y";
static constexpr const char* z = "z";
static constexpr const char* w = "w";
static Node encode(SHVec4 const& rhs)
{
Node node;
node.SetStyle(EmitterStyle::Flow);
node[x] = rhs.x;
node[y] = rhs.y;
node[z] = rhs.z;
node[w] = rhs.w;
return node;
}
static bool decode(Node const& node, SHVec4& rhs)
{
if (node[x].IsDefined())
rhs.x = node[x].as<float>();
if (node[y].IsDefined())
rhs.y = node[y].as<float>();
if (node[z].IsDefined())
rhs.z = node[z].as<float>();
if (node[w].IsDefined())
rhs.w = node[w].as<float>();
return true;
}
};
template<>
struct convert<SHVec3>
{
static constexpr const char* x = "x";
static constexpr const char* y = "y";
static constexpr const char* z = "z";
static Node encode(SHVec3 const& rhs)
{
Node node;
node.SetStyle(EmitterStyle::Flow);
node[x] = rhs.x;
node[y] = rhs.y;
node[z] = rhs.z;
return node;
}
static bool decode(Node const& node, SHVec3& rhs)
{
if (node[x].IsDefined())
rhs.x = node[x].as<float>();
if (node[y].IsDefined())
rhs.y = node[y].as<float>();
if (node[z].IsDefined())
rhs.z = node[z].as<float>();
return true;
}
};
template<>
struct convert<SHVec2>
{
static constexpr const char* x = "x";
static constexpr const char* y = "y";
static Node encode(SHVec2 const& rhs)
{
Node node;
node.SetStyle(EmitterStyle::Flow);
node[x] = rhs.x;
node[y] = rhs.y;
return node;
}
static bool decode(Node const& node, SHVec2& rhs)
{
if (node[x].IsDefined())
rhs.x = node[x].as<float>();
if (node[y].IsDefined())
rhs.y = node[y].as<float>();
return true;
}
};
template<>
struct convert<SHCollider>
{
static constexpr const char* IsTrigger = "Is Trigger";
static constexpr const char* Type = "Type";
static constexpr const char* HalfExtents = "Half Extents";
static constexpr const char* Radius = "Radius";
static constexpr const char* Friction = "Friction";
static constexpr const char* Bounciness = "Bounciness";
static constexpr const char* Density = "Density";
static constexpr const char* PositionOffset = "Position Offset";
static Node encode(SHCollider& rhs)
{
Node node;
node[IsTrigger] = rhs.IsTrigger();
rttr::type const shapeRttrType = rttr::type::get<SHCollider::Type>();
rttr::enumeration const enumAlign = shapeRttrType.get_enumeration();
SHCollider::Type colliderType = rhs.GetType();
node[Type] = enumAlign.value_to_name(colliderType).data();
switch (colliderType)
{
case SHCollider::Type::BOX:
{
auto const bb = reinterpret_cast<SHBoundingBox*>(rhs.GetShape());
node[HalfExtents] = bb->GetHalfExtents();
}
break;
case SHCollider::Type::SPHERE:
{
auto const bs = reinterpret_cast<SHBoundingSphere*>(rhs.GetShape());
node[Radius] = bs->GetRadius();
}
break;
case SHCollider::Type::CAPSULE: break;
default:;
}
node[Friction] = rhs.GetFriction();
node[Bounciness] = rhs.GetBounciness();
node[Density] = rhs.GetDensity();
node[PositionOffset] = rhs.GetPositionOffset();
return node;
}
static bool decode(Node const& node, SHCollider& rhs)
{
if (node[IsTrigger].IsDefined())
rhs.SetIsTrigger(node[IsTrigger].as<bool>());
if (!node[Type].IsDefined())
return false;
rttr::type const shapeRttrType = rttr::type::get<SHCollider::Type>();
rttr::enumeration const enumAlign = shapeRttrType.get_enumeration();
bool ok;
const SHCollider::Type colliderType = enumAlign.name_to_value(node[Type].as<std::string>()).convert<SHCollider::Type>(&ok);
if (!ok)
return false;
switch (colliderType)
{
case SHCollider::Type::BOX:
{
if(node[HalfExtents].IsDefined())
rhs.SetBoundingBox(node[HalfExtents].as<SHVec3>());
}
break;
case SHCollider::Type::SPHERE:
{
if(node[Radius].IsDefined())
rhs.SetBoundingSphere(node[Radius].as<float>());
}
break;
case SHCollider::Type::CAPSULE: break;
default:;
}
if (node[Friction].IsDefined())
rhs.SetFriction(node[Friction].as<float>());
if (node[Bounciness].IsDefined())
rhs.SetBounciness(rhs.GetBounciness());
if (node[Density].IsDefined())
rhs.SetDensity(node[Density].as<float>());
if (node[PositionOffset].IsDefined())
rhs.SetPositionOffset(node[PositionOffset].as<SHVec3>());
return true;
}
};
template<>
struct convert<SHColliderComponent>
{
static constexpr const char* Colliders = "Colliders";
static Node encode(SHColliderComponent& rhs)
{
Node node, collidersNode;
auto const& colliders = rhs.GetColliders();
int const numColliders = static_cast<int>(colliders.size());
for (int i = 0; i < numColliders; ++i)
{
auto& collider = rhs.GetCollider(i);
Node colliderNode = convert<SHCollider>::encode(collider);
if (colliderNode.IsDefined())
collidersNode[i] = colliderNode;
}
node[Colliders] = collidersNode;
return node;
}
static bool decode(Node const& node, SHColliderComponent& rhs)
{
if (node[Colliders].IsDefined())
{
int numColliders{};
for (auto const& colliderNode : node[Colliders])
{
rttr::type const shapeRttrType = rttr::type::get<SHCollider::Type>();
rttr::enumeration const enumAlign = shapeRttrType.get_enumeration();
bool ok = false;
const SHCollider::Type colliderType = enumAlign.name_to_value(colliderNode[convert<SHCollider>::Type].as<std::string>()).convert<SHCollider::Type>(&ok);
if (!ok)
return false;
switch (colliderType)
{
case SHCollider::Type::BOX: rhs.AddBoundingBox(); break;
case SHCollider::Type::SPHERE: rhs.AddBoundingSphere(); break;
case SHCollider::Type::CAPSULE: break;
default:;
}
YAML::convert<SHCollider>::decode(colliderNode, rhs.GetCollider(numColliders++));
}
}
return true;
}
};
template<> template<>
struct convert<SHMaterial> struct convert<SHMaterial>
{ {
@ -46,13 +272,13 @@ namespace YAML
propNode = rhs.GetProperty<int>(VARIABLE->offset); propNode = rhs.GetProperty<int>(VARIABLE->offset);
break; break;
case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR2: case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR2:
propNode = SHSerializationTools::ValToYAML(rhs.GetProperty<SHVec2>(VARIABLE->offset)); propNode = rhs.GetProperty<SHVec2>(VARIABLE->offset);
break; break;
case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR3: case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR3:
propNode = SHSerializationTools::ValToYAML(rhs.GetProperty<SHVec3>(VARIABLE->offset)); propNode = rhs.GetProperty<SHVec3>(VARIABLE->offset);
break; break;
case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR4: case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR4:
propNode = SHSerializationTools::ValToYAML(rhs.GetProperty<SHVec4>(VARIABLE->offset)); propNode = rhs.GetProperty<SHVec4>(VARIABLE->offset);
break; break;
case SHADE::SHShaderBlockInterface::Variable::Type::OTHER: case SHADE::SHShaderBlockInterface::Variable::Type::OTHER:
default: default:
@ -135,7 +361,7 @@ namespace YAML
return false; return false;
rhs.SetPipeline(gfxSystem->GetDefaultMaterial()->GetPipeline()); rhs.SetPipeline(gfxSystem->GetDefaultMaterial()->GetPipeline());
if (node[PROPS_YAML_TAG.data()]) if (node[PROPS_YAML_TAG.data()].IsDefined())
{ {
// Loop through all properties // Loop through all properties
Handle<SHShaderBlockInterface> pipelineProperties = rhs.GetShaderBlockInterface(); Handle<SHShaderBlockInterface> pipelineProperties = rhs.GetShaderBlockInterface();
@ -192,11 +418,11 @@ namespace YAML
} }
static bool decode(YAML::Node const& node, SHRenderable& rhs) static bool decode(YAML::Node const& node, SHRenderable& rhs)
{ {
if (node[MESH_YAML_TAG.data()]) if (node[MESH_YAML_TAG.data()].IsDefined())
{ {
rhs.SetMesh(SHResourceManager::LoadOrGet<SHMesh>(node[MESH_YAML_TAG.data()].as<AssetID>())); rhs.SetMesh(SHResourceManager::LoadOrGet<SHMesh>(node[MESH_YAML_TAG.data()].as<AssetID>()));
} }
if (node[MAT_YAML_TAG.data()]) if (node[MAT_YAML_TAG.data()].IsDefined())
{ {
// TODO: Convert Asset ID To Material HAndle // TODO: Convert Asset ID To Material HAndle
// Temporarily, use default material // Temporarily, use default material
@ -210,46 +436,34 @@ namespace YAML
}; };
} }
namespace SHADE namespace SHADE
{ {
struct SHSerializationHelper struct SHSerializationHelper
{ {
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static std::string SerializeComponentToString(ComponentType* component)
{
return std::string();
}
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static void SerializeComponentToFile(ComponentType* component, std::filesystem::path const& path)
{
}
static YAML::Node RTTRToNode(const rttr::variant& var) static YAML::Node RTTRToNode(const rttr::variant& var)
{ {
YAML::Node node; YAML::Node node;
auto varType = var.get_type(); auto varType = var.get_type();
if (varType.is_sequential_container())
{
for (auto const& elem : var.create_sequential_view())
{
node.push_back(RTTRToNode(elem));
}
}
if (varType == rttr::type::get<SHVec4>()) if (varType == rttr::type::get<SHVec4>())
{ {
node.SetStyle(YAML::EmitterStyle::Flow); node = YAML::convert<SHVec4>::encode(var.convert<SHVec4>());
node["X"] = var.convert<SHVec4>().x;
node["Y"] = var.convert<SHVec4>().y;
node["Z"] = var.convert<SHVec4>().z;
node["W"] = var.convert<SHVec4>().w;
} }
else if (varType == rttr::type::get<SHVec3>()) else if (varType == rttr::type::get<SHVec3>())
{ {
node.SetStyle(YAML::EmitterStyle::Flow); node = YAML::convert<SHVec3>::encode(var.convert<SHVec3>());
node["X"] = var.convert<SHVec3>().x;
node["Y"] = var.convert<SHVec3>().y;
node["Z"] = var.convert<SHVec3>().z;
} }
else if (varType == rttr::type::get<SHVec2>()) else if (varType == rttr::type::get<SHVec2>())
{ {
node.SetStyle(YAML::EmitterStyle::Flow); node = YAML::convert<SHVec2>::encode(var.convert<SHVec2>());
node["X"] = var.convert<SHVec3>().x;
node["Y"] = var.convert<SHVec3>().y;
} }
else if (varType.is_arithmetic()) else if (varType.is_arithmetic())
{ {
@ -300,7 +514,7 @@ namespace SHADE
else else
{ {
auto properties = var.get_type().get_properties(); auto properties = var.get_type().get_properties();
for (auto property : properties) for (auto const& property : properties)
{ {
node[property.get_name().data()] = RTTRToNode(property.get_value(var)); node[property.get_name().data()] = RTTRToNode(property.get_value(var));
} }
@ -308,6 +522,17 @@ namespace SHADE
return node; return node;
} }
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static std::string SerializeComponentToString(ComponentType* component)
{
return std::string();
}
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static void SerializeComponentToFile(ComponentType* component, std::filesystem::path const& path)
{
}
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static YAML::Node SerializeComponentToNode(ComponentType* component) static YAML::Node SerializeComponentToNode(ComponentType* component)
{ {
@ -327,15 +552,18 @@ namespace SHADE
auto propType = prop.get_type(); auto propType = prop.get_type();
if (propType == rttr::type::get<SHVec4>()) if (propType == rttr::type::get<SHVec4>())
{ {
prop.set_value(component, SHSerializationTools::YAMLToVec4(propertyNode)); SHVec4 vec = propertyNode.as<SHVec4>();
prop.set_value(component, vec);
} }
else if (propType == rttr::type::get<SHVec3>()) else if (propType == rttr::type::get<SHVec3>())
{ {
prop.set_value(component, SHSerializationTools::YAMLToVec3(propertyNode)); SHVec3 vec = propertyNode.as<SHVec3>();
prop.set_value(component, vec);
} }
else if (propType == rttr::type::get<SHVec2>()) else if (propType == rttr::type::get<SHVec2>())
{ {
prop.set_value(component, SHSerializationTools::YAMLToVec2(propertyNode)); SHVec2 vec = propertyNode.as<SHVec2>();
prop.set_value(component, vec);
} }
else if (propType.is_arithmetic()) else if (propType.is_arithmetic())
{ {
@ -371,9 +599,10 @@ namespace SHADE
else else
{ {
auto properties = propType.get_properties(); auto properties = propType.get_properties();
for (auto property : properties) for (auto const& property : properties)
{ {
InitializeProperty(component, property, propertyNode[property.get_name().data()]); if(propertyNode[property.get_name().data()].IsDefined())
InitializeProperty(component, property, propertyNode[property.get_name().data()]);
} }
} }
} }
@ -381,17 +610,17 @@ namespace SHADE
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static void InitializeComponentFromNode(YAML::Node const& componentsNode, EntityID const& eid) static void InitializeComponentFromNode(YAML::Node const& componentsNode, EntityID const& eid)
{ {
auto component = SHComponentManager::GetComponent_s<ComponentType>(eid); ComponentType* component = SHComponentManager::GetComponent_s<ComponentType>(eid);
if (componentsNode.IsNull() && !component) if (componentsNode.IsNull() && !component)
return; return;
auto rttrType = rttr::type::get<ComponentType>(); auto rttrType = rttr::type::get<ComponentType>();
auto componentNode = componentsNode[rttrType.get_name().data()]; auto componentNode = componentsNode[rttrType.get_name().data()];
if (componentsNode.IsNull()) if(!componentNode.IsDefined())
return; return;
auto properties = rttrType.get_properties(); auto properties = rttrType.get_properties();
for (auto const& prop : properties) for (auto const& prop : properties)
{ {
if (componentNode[prop.get_name().data()]) if (componentNode[prop.get_name().data()].IsDefined())
{ {
InitializeProperty<ComponentType>(component, prop, componentNode[prop.get_name().data()]); InitializeProperty<ComponentType>(component, prop, componentNode[prop.get_name().data()]);
} }
@ -406,7 +635,7 @@ namespace SHADE
return; return;
auto rttrType = rttr::type::get<ComponentType>(); auto rttrType = rttr::type::get<ComponentType>();
auto componentNode = componentsNode[rttrType.get_name().data()]; auto componentNode = componentsNode[rttrType.get_name().data()];
if (componentsNode.IsNull()) if (!componentNode.IsDefined())
return; return;
YAML::convert<ComponentType>::decode(componentNode, *component); YAML::convert<ComponentType>::decode(componentNode, *component);
} }

View File

@ -0,0 +1,71 @@
#include "SHpch.h"
#include "SHWinDialog.h"
#include <Windows.h>
#include <shobjidl.h>
namespace SHADE
{
void SHWinDialog::DisplayMessageBox(MessageBoxType const& messageBoxType, std::string const& title, std::string const& text)
{
if(messageBoxType == MessageBoxType::MB_MAX)
return;
UINT flags = MB_APPLMODAL | MB_SETFOREGROUND | MB_OK;
flags |= static_cast<UINT>(messageBoxType);
const std::wstring wTitle(title.begin(), title.end());
const std::wstring wText(text.begin(), text.end());
MessageBox(GetDesktopWindow(), wText.data(), wTitle.data(), flags);
}
std::vector<std::string> SHWinDialog::DisplayOpenDialog(OpenSaveConfig const& openSaveConfig)
{
const HWND hwnd = GetDesktopWindow();
HRESULT hResult = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if(SUCCEEDED(hResult))
{
IFileOpenDialog* pFileOpen;
//Create Dialog object
hResult = CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_ALL, IID_IFileOpenDialog, reinterpret_cast<LPVOID*>(pFileOpen));
if(SUCCEEDED(hResult))
{
//Show the open dialog box
hResult = pFileOpen->Show(hwnd);
//Get file name from the dialoh box
if(SUCCEEDED(hResult))
{
if(openSaveConfig.openMultiple)
{
IShellItemArray* pItemArray;
hResult = pFileOpen->GetResults(&pItemArray);
if(SUCCEEDED(hResult))
{
}
}
else
{
IShellItem* pItem;
hResult = pFileOpen->GetResult(&pItem);
if(SUCCEEDED(hResult))
{
PWSTR pszFilePath;
hResult = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
}
}
}
}
}
return {};
}
std::vector<std::string> SHWinDialog::DisplaySaveAsDialog(OpenSaveConfig const& openSaveConfig)
{
return{};
}
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <string>
#include <vector>
namespace SHADE
{
//https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox
enum class MessageBoxType
{
MB_ERROR = 0x00000010L,
MB_QUESTION = 0x00000020L,
MB_WARNING = 0x00000030L,
MB_INFO = 0x00000040L,
MB_MAX = 0
};
struct OpenSaveConfig
{
using Extension = std::string;
using Extensions = std::vector<Extension>;
using FileTypeDesc = std::pair<std::string, Extensions>;
using FilterList = std::vector<FileTypeDesc>;
std::string title = "Open";
bool openFolders = false;
bool openMultiple = false;
FilterList filterList{};
};
struct SHWinDialog
{
static void DisplayMessageBox(MessageBoxType const& messageBoxType, std::string const& title, std::string const& text);
static std::vector<std::string> DisplayOpenDialog(OpenSaveConfig const& openSaveConfig);
static std::vector<std::string> DisplaySaveAsDialog(OpenSaveConfig const& openSaveConfig);
};
}

View File

@ -194,7 +194,7 @@ namespace SHADE
/* Properties */ /* Properties */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Total number of ColliderBounds in the Collider component. /// Total number of ColliderShapes in the Collider component.
/// </summary> /// </summary>
property int CollisionShapeCount property int CollisionShapeCount
{ {

View File

@ -28,7 +28,7 @@ public class PhysicsTest : Script
Debug.LogError("Collider is NULL!"); Debug.LogError("Collider is NULL!");
} }
var subColider = Collider.ColliderBoundsCount; var subColider = Collider.CollisionShapeCount;
Debug.Log($"There are {subColider} colliders."); Debug.Log($"There are {subColider} colliders.");
} }
protected override void update() protected override void update()

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.

Binary file not shown.

Binary file not shown.