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

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

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

View File

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

View File

@ -13,37 +13,38 @@ struct MatPropData
layout(location = 0) in struct 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

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

View File

@ -14,13 +14,14 @@ layout(location = 8) in uvec2 integerData;
layout(location = 0) out struct 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

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

Binary file not shown.

View File

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

View File

@ -4,7 +4,7 @@
//#define SHEDITOR //#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
@ -110,14 +110,7 @@ namespace Sandbox
SHComponentManager::CreateComponentSparseSet<SHRenderable>(); SHComponentManager::CreateComponentSparseSet<SHRenderable>();
//SHComponentManager::CreateComponentSparseSet<SHCameraComponent>(); //SHComponentManager::CreateComponentSparseSet<SHCameraComponent>();
//TODO: REMOVE AFTER PRESENTATION SHAssetManager::Load();
//SHAssetManager::LoadDataTemp("../../Assets/racoon.gltf");
//SHAssetManager::LoadDataTemp("../../Assets/Cube.012.shmesh");
//SHAssetManager::LoadDataTemp("../../Assets/RaccoonBag_Color_Ver4.dds");
//SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.dds");
//SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.shtex");
//TODO: REMOVE AFTER PRESENTATION
SHSystemManager::RegisterRoutine<SHAudioSystem, SHAudioSystem::AudioRoutine>(); SHSystemManager::RegisterRoutine<SHAudioSystem, SHAudioSystem::AudioRoutine>();
@ -130,8 +123,6 @@ namespace Sandbox
SHSceneManager::InitSceneManager<SBTestScene>("TestScene"); SHSceneManager::InitSceneManager<SBTestScene>("TestScene");
SHFrameRateController::UpdateFRC(); SHFrameRateController::UpdateFRC();
SHAssetManager::Load();
} }
void SBApplication::Update(void) void SBApplication::Update(void)
@ -165,7 +156,7 @@ namespace Sandbox
SHSceneManager::Exit(); SHSceneManager::Exit();
SHSystemManager::Exit(); SHSystemManager::Exit();
SHAssetManager::Unload(); SHAssetManager::Exit();
} }
} }

View File

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

52
SHADE_CSharp/premake5.lua Normal file
View File

@ -0,0 +1,52 @@
project "SHADE_CSharp"
architecture "x64"
kind "SharedLib"
language "C#"
clr "NetCore"
dotnetframework "net5.0"
namespace ("SHADE")
targetdir (outputdir)
objdir (interdir)
systemversion "latest"
files
{
"%{prj.location}/src/**.cs",
"%{prj.location}/src/**.tt"
}
flags
{
"MultiProcessorCompile"
}
dependson
{
"SHADE_Engine"
}
warnings 'Extra'
filter "configurations:Debug"
symbols "On"
defines {"_DEBUG"}
filter "configurations:Release"
optimize "On"
defines{"_RELEASE"}
filter "configurations:Publish"
optimize "On"
defines{"_RELEASE"}
require "vstudio"
function platformsElement(cfg)
_p(2,'<Platforms>x64</Platforms>')
end
premake.override(premake.vstudio.cs2005.elements, "projectProperties", function (oldfn, cfg)
return table.join(oldfn(cfg), {
platformsElement,
})
end)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,149 @@
<#
/************************************************************************************//*!
\file CallbackAction.tt
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 23, 2022
\brief Contains the T4 template for the definition of CallbackAction and
related classes.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/#>
<#@ template hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<# var max = 10; #>
/************************************************************************************//*!
\file CallbackAction.cs
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 23, 2022
\brief Contains the definition of CallbackAction and related classes.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
using System;
using System.Reflection;
namespace SHADE
{
/// <summary>
/// Interface for a CallbackAction that all variants inherit from.
/// </summary>
public interface ICallbackAction
{
/// <summary>
/// Whether or not this CallbackAction is runtime assigned. If it is, then the
/// TargetMethodName and TargetObject properties are invalid.
/// </summary>
bool IsRuntimeAction { get; }
/// <summary>
/// Name of the method that this CallbackAction is using.
/// </summary>
string TargetMethodName { get; }
/// <summary>
/// Object which the specified target method is called on.
/// </summary>
Object TargetObject { get; }
}
<# for (int i = 1; i <= max; ++i) { #>
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with <#=i#> parameter<# if (i > 1) {#>s<#} #>.
/// </summary>
public class CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified static
/// method.
/// </summary>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(MethodInfo method)
{
// No errors, assign
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[<#=i#>];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(Object target, MethodInfo method)
{
// Error Checks
if (method.DeclaringType != target.GetType())
throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
// No errors, assign
TargetObject = target;
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[<#=i#>];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
public void Invoke(<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#> t<#=t#><# if (t != i) { #>, <# } #><# } #>)
{
if (targetAction != null)
{
targetAction.Invoke(<# for (int t = 1; t < i + 1; ++t) { #>t<#=t#><# if (t != i) { #>, <# } #><# } #>);
}
else if (targetMethod != null)
{
<# for (int t = 0; t < i; ++t) {#>parameters[<#=t#>] = t<#=t+1#>;
<# } #>_ = targetMethod.Invoke(TargetObject, parameters);
}
}
#endregion
}
<# } #>
}

View File

@ -0,0 +1,908 @@
/************************************************************************************//*!
\file CallbackEvent.cs
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 23, 2022
\brief Contains the definition of CallbackEvent and related classes.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Metadata.Ecma335;
namespace SHADE
{
/// <summary>
/// Interface for a CallbackEvent that all variants inherit from.
/// </summary>
public interface ICallbackEvent
{
/// <summary>
/// Registers an empty ICallbackAction.
/// </summary>
void RegisterAction();
/// <summary>
/// Registers an ICallbackAction with the event such that it will be called in
/// future
/// </summary>
/// <param name="action">ICallbackAction to register with.</param>
void RegisterAction(ICallbackAction action);
/// <summary>
/// Deregisters an ICallbackAction that was previously added. This should
/// only emit a warning if an action that was not previous added was
/// provided.
/// </summary>
/// <param name="action">ICallbackAction to remove.</param>
void DeregisterAction(ICallbackAction action);
/// <summary>
/// Iterable set of ICallbackActions that were registered to this event.
/// </summary>
IEnumerable<ICallbackAction> Actions { get; }
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1> action)
{
actions.Add(new CallbackAction<T1>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1)
{
foreach (CallbackAction<T1> action in actions)
{
try
{
action.Invoke(t1);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2> action)
{
actions.Add(new CallbackAction<T1, T2>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2)
{
foreach (CallbackAction<T1, T2> action in actions)
{
try
{
action.Invoke(t1, t2);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2, T3> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3> action)
{
actions.Add(new CallbackAction<T1, T2, T3>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3)
{
foreach (CallbackAction<T1, T2, T3> action in actions)
{
try
{
action.Invoke(t1, t2, t3);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4)
{
foreach (CallbackAction<T1, T2, T3, T4> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
{
foreach (CallbackAction<T1, T2, T3, T4, T5> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5, T6> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5, T6>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5, T6> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5, T6> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
{
foreach (CallbackAction<T1, T2, T3, T4, T5, T6> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5, t6);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5, T6, T7> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5, T6, T7>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5, T6, T7> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5, T6, T7> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
{
foreach (CallbackAction<T1, T2, T3, T4, T5, T6, T7> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5, t6, t7);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5, T6, T7, T8> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5, T6, T7, T8> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
{
foreach (CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5, t6, t7, t8);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5, T6, T7, T8, T9> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9)
{
foreach (CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10)
{
foreach (CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
}

View File

@ -0,0 +1,152 @@
<#
/************************************************************************************//*!
\file CallbackEvent.tt
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 23, 2022
\brief Contains the T4 template for the definition of CallbackEvent and
related classes.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/#>
<#@ template hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<# var max = 10; #>
/************************************************************************************//*!
\file CallbackEvent.cs
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 23, 2022
\brief Contains the definition of CallbackEvent and related classes.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Metadata.Ecma335;
namespace SHADE
{
/// <summary>
/// Interface for a CallbackEvent that all variants inherit from.
/// </summary>
public interface ICallbackEvent
{
/// <summary>
/// Registers an empty ICallbackAction.
/// </summary>
void RegisterAction();
/// <summary>
/// Registers an ICallbackAction with the event such that it will be called in
/// future
/// </summary>
/// <param name="action">ICallbackAction to register with.</param>
void RegisterAction(ICallbackAction action);
/// <summary>
/// Deregisters an ICallbackAction that was previously added. This should
/// only emit a warning if an action that was not previous added was
/// provided.
/// </summary>
/// <param name="action">ICallbackAction to remove.</param>
void DeregisterAction(ICallbackAction action);
/// <summary>
/// Iterable set of ICallbackActions that were registered to this event.
/// </summary>
IEnumerable<ICallbackAction> Actions { get; }
}
<# for (int i = 1; i <= max; ++i) { #>
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action)
{
actions.Add(new CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#> t<#=t#><# if (t != i) { #>, <# } #><# } #>)
{
foreach (CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action in actions)
{
try
{
action.Invoke(<# for (int t = 1; t < i + 1; ++t) { #>t<#=t#><# if (t != i) { #>, <# } #><# } #>);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
<# } #>
}

View File

@ -0,0 +1,37 @@
using System;
using System.Runtime.InteropServices;
namespace SHADE
{
internal static class Debug
{
[DllImport("SHADE_Engine.dll", EntryPoint = "SHLog_Info")]
public static extern void LogInfo([MarshalAs(UnmanagedType.LPStr)] string str);
[DllImport("SHADE_Engine.dll", EntryPoint = "SHLog_Warning")]
public static extern void LogWarning([MarshalAs(UnmanagedType.LPStr)] string str);
[DllImport("SHADE_Engine.dll", EntryPoint = "SHLog_Error")]
public static extern void LogError([MarshalAs(UnmanagedType.LPStr)] string str);
[DllImport("SHADE_Engine.dll", EntryPoint = "SHLog_Critical")]
public static extern void LogCritical([MarshalAs(UnmanagedType.LPStr)] string str);
public static void LogInfo(string msg, Object thrower)
{
LogInfo($"[{thrower.GetType().Name}] {msg}");
}
public static void LogWarning(string msg, Object thrower)
{
LogWarning($"[{thrower.GetType().Name}] {msg}");
}
public static void LogError(string msg, Object thrower)
{
LogError($"[{thrower.GetType().Name}] {msg}");
}
public static void LogCritical(string msg, Object thrower)
{
LogCritical($"[{thrower.GetType().Name}] {msg}");
}
public static void LogException(Exception exception, Object thrower)
{
LogError($"[{ thrower.GetType().Name }] Unhandled exception: { exception.ToString() }");
}
}
}

View File

@ -8,7 +8,7 @@ project "SHADE_Engine"
pchheader "SHpch.h" 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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,14 +11,23 @@
* of DigiPen Institute of Technology is prohibited. * of DigiPen Institute of Technology is prohibited.
*****************************************************************************/ *****************************************************************************/
#pragma once #pragma once
#define TINYDDSLOADER_IMPLEMENTATION
#include "Assets/Asset Types/SHTextureAsset.h" #include "Assets/Asset Types/SHTextureAsset.h"
#include "Assets/SHAssetMacros.h" #include "Assets/SHAssetMacros.h"
#include "tinyddsloader.h"
namespace SHADE namespace SHADE
{ {
struct SHTextureCompiler class SHTextureCompiler
{ {
static std::string CompileTextureBinary(SHTextureAsset const& asset, AssetPath path); private:
static std::string TinyDDSResultToString(tinyddsloader::Result value);
static vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear);
static void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept;
static std::string WriteToFile(SHTextureAsset const& asset, AssetPath path) noexcept;
public:
static std::optional<AssetPath> CompileTextureAsset(AssetPath path);
}; };
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,25 +10,15 @@
* of DigiPen Institute of Technology is prohibited. * of DigiPen Institute of Technology is prohibited.
*****************************************************************************/ *****************************************************************************/
#pragma once #pragma once
#define TINYDDSLOADER_IMPLEMENTATION #include "Assets/Asset Types/SHTextureAsset.h"
#include "../SHAssetMacros.h"
#include "../Asset Types/SHTextureAsset.h"
#include "tinyddsloader.h"
#include "SHAssetLoader.h" #include "SHAssetLoader.h"
namespace SHADE namespace SHADE
{ {
class SHTextureLoader : public SHAssetLoader class SHTextureLoader : public SHAssetLoader
{ {
private:
std::string TinyDDSResultToString(tinyddsloader::Result value);
vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear);
void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept;
public:
void LoadImageAsset(AssetPath paths, SHTextureAsset& image);
void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept; 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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,7 +11,6 @@
*****************************************************************************/ *****************************************************************************/
#pragma once #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

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

View File

@ -10,26 +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 "Libraries/Loaders/SHMeshLoader.h"
#include "Libraries/Loaders/SHTextureLoader.h"
#include "Libraries/Loaders/SHShaderSourceLoader.h"
#include "Libraries/Loaders/SHTextBasedLoader.h"
#include "Libraries/Compilers/SHMeshCompiler.h"
#include "Libraries/Compilers/SHTextureCompiler.h"
#include "Libraries/Compilers/SHShaderSourceCompiler.h"
#include "Filesystem/SHFileSystem.h" #include "Filesystem/SHFileSystem.h"
#include "Libraries/SHAssimpLibrary.h"
#include "Libraries/SHMeshLoader.h"
#include "Libraries/SHTextureLoader.h"
#include "Libraries/SHMeshCompiler.h"
#include "Libraries/SHTextureCompiler.h"
namespace SHADE 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.
@ -44,7 +51,7 @@ namespace SHADE
result |= unique; result |= unique;
while (result == 0) while (result == 0 || assetCollection.contains(result))
{ {
result = GenerateAssetID(type); result = GenerateAssetID(type);
} }
@ -54,17 +61,25 @@ 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
} }
AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept void SHAssetManager::Exit() noexcept
{
delete loaders[static_cast<size_t>(AssetType::SHADER)];
delete loaders[static_cast<size_t>(AssetType::TEXTURE)];
delete loaders[static_cast<size_t>(AssetType::MESH)];
delete loaders[static_cast<size_t>(AssetType::SCENE)];
for (auto const& data : std::ranges::views::values(assetData))
{
delete data;
}
}
AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept
{ {
if (!IsRecognised(path.extension().string().c_str())) if (!IsRecognised(path.extension().string().c_str()))
{ {
@ -91,16 +106,9 @@ namespace SHADE
switch(type) switch(type)
{ {
case AssetType::SCENE: case AssetType::SHADER:
folder = "scenes/"; case AssetType::SHADER_BUILT_IN:
break; folder = "Shaders/";
case AssetType::PREFAB:
folder = "prefabs/";
break;
case AssetType::MATERIAL:
folder = "materials/";
break; break;
default: default:
@ -120,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;
} }
/**************************************************************************** /****************************************************************************
@ -135,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.
* *
@ -192,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;
} }
@ -206,7 +295,60 @@ namespace SHADE
} }
bool SHAssetManager::IsRecognised(char const* ext) noexcept std::vector<SHAssetData const*> SHAssetManager::GetAllDataOfType(AssetType type) noexcept
{
auto const toRetrieve = GetAllRecordOfType(type);
std::vector<SHAssetData const*> result;
result.reserve(toRetrieve.size());
for (auto const& get : toRetrieve)
{
result.push_back(LoadData(get));
}
return result;
}
std::vector<SHAsset> SHAssetManager::GetAllRecordOfType(AssetType type) noexcept
{
std::vector<SHAsset> result;
for (auto const& asset : std::ranges::views::values(assetCollection))
{
if (asset.type == type)
{
result.push_back(asset);
}
}
return result;
}
AssetID SHAssetManager::CompileAsset(AssetPath const& path) noexcept
{
SHAsset newAsset
{
.name = path.stem().string()
};
auto const ext{ path.extension().string() };
if (ext == GLSL_EXTENSION.data())
{
newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value();
newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN);
newAsset.type = AssetType::SHADER_BUILT_IN;
}
assetCollection.insert({ newAsset.id, newAsset });
SHAssetMetaHandler::WriteMetaData(newAsset);
return newAsset.id;
}
FolderPointer SHAssetManager::GetRootFolder() noexcept
{
return folderRoot;
}
bool SHAssetManager::IsRecognised(char const* ext) noexcept
{ {
for (auto const& e : EXTENSIONS) for (auto const& e : EXTENSIONS)
{ {
@ -231,19 +373,84 @@ namespace SHADE
return result; return result;
} }
void SHAssetManager::InitLoaders() noexcept void SHAssetManager::CompileAll() noexcept
{ {
loaders[static_cast<size_t>(AssetType::AUDIO)] = nullptr; std::vector<AssetPath> paths;
loaders[static_cast<size_t>(AssetType::SHADER)] = nullptr;
loaders[static_cast<size_t>(AssetType::MATERIAL)] = nullptr; for (auto const& dir : std::filesystem::recursive_directory_iterator{ ASSET_ROOT })
loaders[static_cast<size_t>(AssetType::IMAGE)] = dynamic_cast<SHAssetLoader*>(new SHTextureLoader()); {
loaders[static_cast<size_t>(AssetType::TEXTURE)] = nullptr; if (dir.is_regular_file())
{
for (auto const& ext : EXTERNALS)
{
if (dir.path().extension().string() == ext.data())
{
paths.push_back(dir.path());
}
}
}
}
for (auto const& path : paths)
{
SHAsset newAsset
{
.name = path.stem().string()
};
auto const ext{ path.extension().string() };
if (ext == GLSL_EXTENSION.data())
{
newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value();
newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN);
newAsset.type = AssetType::SHADER_BUILT_IN;
}
else if (ext == DDS_EXTENSION.data())
{
newAsset.path = SHTextureCompiler::CompileTextureAsset(path).value();
newAsset.id = GenerateAssetID(AssetType::TEXTURE);
newAsset.type = AssetType::TEXTURE;
}
else if (ext == GLTF_EXTENSION.data() || ext == FBX_EXTENSION.data())
{
std::vector<SHMeshAsset*> meshes;
std::vector<SHAnimationAsset*> anims;
SHMeshCompiler::LoadFromFile(path, meshes, anims);
for (auto const& mesh : meshes)
{
SHAsset meshAsset{
.name = mesh->header.name
};
meshAsset.path = SHMeshCompiler::CompileMeshBinary(*mesh, path).value();
meshAsset.id = GenerateAssetID(AssetType::MESH);
meshAsset.type = AssetType::MESH;
assetCollection.insert({ meshAsset.id, meshAsset });
SHAssetMetaHandler::WriteMetaData(meshAsset);
}
continue;
}
assetCollection.insert({ newAsset.id, newAsset });
SHAssetMetaHandler::WriteMetaData(newAsset);
}
}
bool SHAssetManager::DeleteLocalFile(AssetPath path) noexcept
{
//TODO Move this to dedicated library
return std::filesystem::remove(path);
}
void SHAssetManager:: InitLoaders() noexcept
{
loaders[static_cast<size_t>(AssetType::SHADER)] = dynamic_cast<SHAssetLoader*>(new SHShaderSourceLoader());
loaders[static_cast<size_t>(AssetType::SHADER_BUILT_IN)] = loaders[static_cast<size_t>(AssetType::SHADER)];
loaders[static_cast<size_t>(AssetType::TEXTURE)] = dynamic_cast<SHAssetLoader*>(new SHTextureLoader());
loaders[static_cast<size_t>(AssetType::MESH)] = dynamic_cast<SHAssetLoader*>(new SHMeshLoader()); loaders[static_cast<size_t>(AssetType::MESH)] = dynamic_cast<SHAssetLoader*>(new SHMeshLoader());
loaders[static_cast<size_t>(AssetType::SCRIPT)] = nullptr; loaders[static_cast<size_t>(AssetType::SCENE)] = dynamic_cast<SHAssetLoader*>(new SHTextBasedLoader());
loaders[static_cast<size_t>(AssetType::SCENE)] = nullptr; loaders[static_cast<size_t>(AssetType::PREFAB)] = loaders[static_cast<size_t>(AssetType::SCENE)];
loaders[static_cast<size_t>(AssetType::PREFAB)] = nullptr; loaders[static_cast<size_t>(AssetType::MATERIAL)] = loaders[static_cast<size_t>(AssetType::SCENE)];
loaders[static_cast<size_t>(AssetType::AUDIO_WAV)] = nullptr;
loaders[static_cast<size_t>(AssetType::DDS)] = nullptr;
} }
/**************************************************************************** /****************************************************************************
@ -251,8 +458,9 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
void SHAssetManager::Load() noexcept void SHAssetManager::Load() noexcept
{ {
//CompileAll();
BuildAssetCollection();
InitLoaders(); InitLoaders();
BuildAssetCollection();
//LoadAllData(); //LoadAllData();
} }
@ -261,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);
@ -284,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 "Libraries/SHAssetLoader.h" #include "Assets/Libraries/Loaders/SHAssetLoader.h"
#include <memory>
#include "Filesystem/SHFolder.h"
#include "SH_API.h" #include "SH_API.h"
@ -26,16 +28,16 @@ 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 Exit() noexcept;
static void Unload(AssetID assetId) 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
@ -47,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
@ -57,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.
@ -76,22 +79,37 @@ 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<SHAsset> GetAllRecordOfType(AssetType type) noexcept;
static AssetID CompileAsset(AssetPath const& path) noexcept;
static FolderPointer GetRootFolder() noexcept;
private: private:
/****************************************************************************
* \brief Load resource data into memory static void InitLoaders() noexcept;
****************************************************************************/
static void LoadAllData() noexcept; static void LoadAllData() noexcept;
static SHAssetData* LoadData(SHAsset const& asset) noexcept; static SHAssetData* LoadData(SHAsset const& asset) noexcept;
inline static void BuildAssetCollection() noexcept; inline static void BuildAssetCollection() noexcept;
static bool IsRecognised(char const*) noexcept; static bool IsRecognised(char const*) noexcept;
static SHAsset CreateAssetFromPath(AssetPath path) noexcept; static SHAsset CreateAssetFromPath(AssetPath path) noexcept;
static void InitLoaders() noexcept; static void CompileAll() noexcept;
static 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;
@ -99,7 +117,7 @@ namespace SHADE
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

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

View File

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

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());
} }
} }
@ -207,8 +223,12 @@ namespace SHADE
{ {
if (!component) if (!component)
return; return;
// Get transform component for extrapolating relative sizes
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()))
{ {
@ -216,43 +236,56 @@ 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);
SHCollider& collider = component->GetCollider(i); SHCollider* collider = &component->GetCollider(i);
auto cursorPos = ImGui::GetCursorPos(); auto cursorPos = ImGui::GetCursorPos();
if (collider.GetType() == SHCollider::Type::BOX) if (collider->GetType() == SHCollider::Type::BOX)
{ {
SHEditorWidgets::BeginPanel( std::format("{} Box Collider #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); SHEditorWidgets::BeginPanel(std::format("{} Box Collider #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
auto box = reinterpret_cast<SHBoundingBox*>(collider.GetShape()); auto box = reinterpret_cast<SHBoundingBox*>(collider->GetShape());
SHEditorWidgets::DragVec3("Half Extents", { "X", "Y", "Z" }, [box] {return box->GetHalfExtents(); }, [box](SHVec3 const& vec) {box->SetHalfExtents(vec);}); SHEditorWidgets::DragVec3
(
"Half Extents", { "X", "Y", "Z" },
[box, transformComponent] { return (transformComponent->GetWorldScale() * 2.0f) * box->GetHalfExtents(); },
[collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); });
} }
else if (collider.GetType() == SHCollider::Type::SPHERE) else if (collider->GetType() == SHCollider::Type::SPHERE)
{ {
SHEditorWidgets::BeginPanel(std::format("{} Sphere Collider #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); SHEditorWidgets::BeginPanel(std::format("{} Sphere Collider #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
auto sphere = reinterpret_cast<SHBoundingSphere*>(collider.GetShape()); auto sphere = reinterpret_cast<SHBoundingSphere*>(collider->GetShape());
SHEditorWidgets::DragFloat("Radius", [sphere] {return sphere->GetRadius(); }, [sphere](float const& value) {sphere->SetRadius(value);}); SHEditorWidgets::DragFloat
(
"Radius",
[sphere, transformComponent]
{
const SHVec3& TF_WORLD_SCALE = transformComponent->GetWorldScale();
const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z });
return sphere->GetRadius() / MAX_SCALE;
},
[collider](float const& value) { collider->SetBoundingSphere(value); });
} }
else if (collider.GetType() == SHCollider::Type::CAPSULE) else if (collider->GetType() == SHCollider::Type::CAPSULE)
{ {
} }
{ {
SHEditorWidgets::BeginPanel("Offset", { ImGui::GetContentRegionAvail().x, 30.0f }); SHEditorWidgets::BeginPanel("Offset", { ImGui::GetContentRegionAvail().x, 30.0f });
SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider.GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider.SetPositionOffset(vec); }); SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider->GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider->SetPositionOffset(vec); });
SHEditorWidgets::EndPanel(); SHEditorWidgets::EndPanel();
} }
if(ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data())) if (ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data()))
{ {
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());
} }
@ -260,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();
} }
@ -273,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,18 +10,15 @@
#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 "Camera/SHCameraArmComponent.h" #include "Camera/SHCameraArmComponent.h"
#include "SHEditorComponentView.h"
namespace SHADE namespace SHADE
{ {
@ -31,8 +28,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;
} }
@ -43,13 +49,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;
} }
@ -101,6 +120,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);
@ -118,6 +141,7 @@ namespace SHADE
DrawAddComponentButton<SHTransformComponent>(eid); DrawAddComponentButton<SHTransformComponent>(eid);
DrawAddComponentButton<SHCameraComponent>(eid); DrawAddComponentButton<SHCameraComponent>(eid);
DrawAddComponentButton<SHCameraArmComponent>(eid); DrawAddComponentButton<SHCameraArmComponent>(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

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

View File

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

View File

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

@ -45,16 +45,20 @@ namespace SHADE
void SHBatch::Add(const SHRenderable* renderable) void SHBatch::Add(const SHRenderable* renderable)
{ {
// Ignore if null
if (!renderable->GetMesh())
return;
// Check if we have a SubBatch with the same mesh yet // Check if we have a SubBatch with the same mesh yet
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch) auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
{ {
return batch.Mesh == renderable->Mesh; return batch.Mesh == renderable->GetMesh();
}); });
// Create one if not found // Create one if not found
if (subBatch == subBatches.end()) if (subBatch == subBatches.end())
{ {
subBatches.emplace_back(renderable->Mesh); subBatches.emplace_back(renderable->GetMesh());
subBatch = subBatches.end() - 1; subBatch = subBatches.end() - 1;
} }
@ -73,7 +77,7 @@ namespace SHADE
// Check if we have a SubBatch with the same mesh yet // Check if we have a SubBatch with the same mesh yet
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch) auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
{ {
return batch.Mesh == renderable->Mesh; return batch.Mesh == renderable->GetMesh();
}); });
// Attempt to remove if it exists // Attempt to remove if it exists
@ -84,13 +88,18 @@ namespace SHADE
// Check if other renderables in subBatches contain the same material instance // Check if other renderables in subBatches contain the same material instance
bool matUnused = true; bool matUnused = true;
Handle<SHMaterialInstance> matToCheck = renderable->HasMaterialChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial();
for (const auto& sb : subBatches) for (const auto& sb : subBatches)
{
// Check material usage
for (const auto& rendId : sb.Renderables) for (const auto& rendId : sb.Renderables)
{ {
auto rend = SHComponentManager::GetComponent<SHRenderable>(rendId); auto rend = SHComponentManager::GetComponent<SHRenderable>(rendId);
if (rend) if (rend)
{ {
if (rend->GetMaterial() == renderable->GetMaterial()) if (rend->GetMaterial() == matToCheck)
{ {
matUnused = false; matUnused = false;
break; break;
@ -101,10 +110,15 @@ namespace SHADE
SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!"); SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
} }
} }
}
// Material is no longer in this library, so we remove it // Material is no longer in this library, so we remove it
if (matUnused) if (matUnused)
referencedMatInstances.erase(renderable->WasMaterialChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial()); referencedMatInstances.erase(renderable->HasChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial());
// Mesh is no longer in this batch, so we remove the associated sub batch
if (subBatch->Renderables.empty())
subBatches.erase(subBatch);
// Mark all as dirty // Mark all as dirty
setAllDirtyFlags(); setAllDirtyFlags();
@ -180,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
@ -302,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]);
@ -361,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)
@ -118,24 +110,8 @@ namespace SHADE
graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
// TODO: This is VERY temporarily here until a more solid resource management system is implemented shaderModuleLibrary.ImportAllShaderSource(device);
shaderSourceLibrary.Init("../../TempShaderFolder/"); shaderModuleLibrary.ReflectAllShaderModules();
shaderSourceLibrary.LoadShader(0, "TestCubeVs.glsl", SH_SHADER_TYPE::VERTEX, true);
shaderSourceLibrary.LoadShader(1, "TestCubeFs.glsl", SH_SHADER_TYPE::FRAGMENT, true);
shaderSourceLibrary.LoadShader(2, "KirschCs.glsl", SH_SHADER_TYPE::COMPUTE, true);
shaderSourceLibrary.LoadShader(3, "PureCopyCs.glsl", SH_SHADER_TYPE::COMPUTE, true);
shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary);
auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl");
auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl");
auto greyscale = shaderModuleLibrary.GetShaderModule("KirschCs.glsl");
auto pureCopy = shaderModuleLibrary.GetShaderModule("PureCopyCs.glsl");
cubeVS->Reflect();
cubeFS->Reflect();
greyscale->Reflect();
pureCopy->Reflect();
} }
void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept
@ -176,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.glsl"); //auto kirschShader = shaderModuleLibrary.GetShaderModule("KirschCs.glsl");
//gBufferNode->AddNodeCompute(kirschShader, { "Scene Pre-Process", "Scene" }); //gBufferNode->AddNodeCompute(kirschShader, { "Position", "Scene" });
// copy //// copy
auto pureCopyShader = shaderModuleLibrary.GetShaderModule("PureCopyCs.glsl"); //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
@ -212,11 +207,10 @@ namespace SHADE
worldRenderer->SetCameraDirector(cameraSystem->CreateDirector()); worldRenderer->SetCameraDirector(cameraSystem->CreateDirector());
auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl"); auto cubeVS = shaderModuleLibrary.GetBuiltInShaderModule("TestCube_VS");
auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl"); auto cubeFS = shaderModuleLibrary.GetBuiltInShaderModule("TestCube_FS");
defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferSubpass); defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferSubpass);
} }
void SHGraphicsSystem::InitMiddleEnd(void) noexcept void SHGraphicsSystem::InitMiddleEnd(void) noexcept
@ -328,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
@ -379,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)
@ -461,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)
@ -510,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();
@ -696,7 +715,7 @@ namespace SHADE
auto& renderables = SHComponentManager::GetDense<SHRenderable>(); auto& renderables = SHComponentManager::GetDense<SHRenderable>();
for (auto& renderable : renderables) for (auto& renderable : renderables)
{ {
if (!renderable.WasMaterialChanged()) if (!renderable.HasChanged())
continue; continue;
// Remove from old material's SuperBatch // Remove from old material's SuperBatch
@ -784,5 +803,10 @@ namespace SHADE
} }
Handle<SHRenderGraphNode> SHGraphicsSystem::GetPrimaryRenderpass() const noexcept
{
return worldRenderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data());
}
#pragma endregion MISC #pragma endregion MISC
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -25,7 +25,7 @@ namespace SHADE
template<typename T> template<typename T>
void SHMaterial::SetProperty(const std::string& key, const T& value) void SHMaterial::SetProperty(const std::string& key, const T& value)
{ {
const auto SHADER_INFO = getShaderBlockInterface(); const auto SHADER_INFO = GetShaderBlockInterface();
const auto PROP_INFO = SHADER_INFO->GetVariable(key); const auto PROP_INFO = SHADER_INFO->GetVariable(key);
if (PROP_INFO == nullptr) if (PROP_INFO == nullptr)
{ {
@ -33,21 +33,32 @@ namespace SHADE
} }
// Get offset and modify the memory directly // Get offset and modify the memory directly
T* dataPtr = propMemory.get() + PROP_INFO->offset; T* dataPtr = reinterpret_cast<T*>(propMemory.get() + PROP_INFO->offset);
*dataPtr = value; *dataPtr = value;
} }
template<typename T>
void SHMaterial::SetProperty(uint32_t memOffset, const T& value)
{
// Check if out of bounds
if (memOffset + sizeof(T) > propMemorySize)
throw std::invalid_argument("Attempted to set an invalid property!");
// Set
setPropertyUnsafe(memOffset, value);
}
template<typename T> template<typename T>
T& SHMaterial::GetProperty(const std::string& key) T& SHMaterial::GetProperty(const std::string& key)
{ {
const auto SHADER_INFO = getShaderBlockInterface(); const auto SHADER_INFO = GetShaderBlockInterface();
const auto PROP_INFO = SHADER_INFO->GetVariable(key); const auto PROP_INFO = SHADER_INFO->GetVariable(key);
if (PROP_INFO == nullptr) if (PROP_INFO == nullptr)
{ {
throw std::invalid_argument("Attempted to set an invalid property!"); throw std::invalid_argument("Attempted to retrieve an invalid property!");
} }
// Get offset and return the memory directly // Get offset and return the memory directly
T* dataPtr = propMemory.get() + PROP_INFO->offset; T* dataPtr = reinterpret_cast<T*>(propMemory.get() + PROP_INFO->offset);
return *dataPtr; return *dataPtr;
} }
template<typename T> template<typename T>
@ -55,5 +66,25 @@ namespace SHADE
{ {
return const_cast<const T&>(const_cast<SHMaterial*>(this)->GetProperty(key)); return const_cast<const T&>(const_cast<SHMaterial*>(this)->GetProperty(key));
} }
template<typename T>
const T& SHMaterial::GetProperty(uint32_t memOffset) const
{
// Check if out of bounds
if (memOffset + sizeof(T) > propMemorySize)
throw std::invalid_argument("Attempted to retrieve an invalid property!");
return *(reinterpret_cast<T*>(propMemory.get() + memOffset));
}
template<typename T>
T& SHMaterial::GetProperty(uint32_t memOffset)
{
return const_cast<const T&>(const_cast<SHMaterial*>(this)->GetProperty(memOffset));
}
template<typename T>
void SHMaterial::setPropertyUnsafe(uint32_t memOffset, const T& value)
{
(*reinterpret_cast<T*>(propMemory.get() + memOffset)) = value;
}
} }

View File

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

View File

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

View File

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

View File

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

View File

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

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