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

This commit is contained in:
Diren D Bharwani 2022-10-28 15:37:33 +08:00
commit 5bcf20142e
267 changed files with 14310 additions and 3628 deletions

5
.editorconfig Normal file
View File

@ -0,0 +1,5 @@
root = true
[*.{c,cpp,h,hpp}]
indent_style = space
indent_size = 2

View File

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

View File

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

Binary file not shown.

View File

@ -4,13 +4,13 @@ Size=1920,20
Collapsed=0
[Window][SHEditorMenuBar]
Pos=0,24
Size=1920,1036
Pos=0,48
Size=1920,1012
Collapsed=0
[Window][Hierarchy Panel]
Pos=0,120
Size=225,940
Pos=0,197
Size=308,863
Collapsed=0
DockId=0x00000004,0
@ -20,29 +20,96 @@ Size=400,400
Collapsed=0
[Window][Inspector]
Pos=1686,24
Size=234,1036
Pos=1528,48
Size=392,1012
Collapsed=0
DockId=0x00000006,0
[Window][Profiler]
Pos=0,24
Size=225,94
Pos=0,48
Size=308,147
Collapsed=0
DockId=0x00000003,0
[Window][Viewport]
Pos=227,24
Size=1457,1036
Pos=227,48
Size=1457,1012
Collapsed=0
DockId=0x00000002,0
DockId=0x0000000B,0
[Window][ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌð‡Žoû]
Pos=60,60
Size=32,64
Collapsed=0
[Window][ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ]
Pos=60,60
Size=999,581
Collapsed=0
[Window][ð‡]
Pos=60,60
Size=32,64
Collapsed=0
[Window][ÌÌÌÌ]
Pos=60,60
Size=553,422
Collapsed=0
[Window][]
Pos=60,60
Size=770,394
Collapsed=0
[Window][ Viewport]
Pos=227,48
Size=1457,1012
Collapsed=0
DockId=0x0000000B,0
[Window][ Viewport]
Pos=227,48
Size=1457,1012
Collapsed=0
DockId=0x0000000B,0
[Window][î<> Viewport]
Pos=310,48
Size=1216,715
Collapsed=0
DockId=0x0000000B,0
[Window][V]
Pos=310,722
Size=1501,338
Collapsed=0
DockId=0x00000008,0
[Window][p£€Ê]
Pos=310,750
Size=1501,310
Collapsed=0
DockId=0x0000000A,0
[Window][ Asset Browser]
Pos=310,765
Size=1216,295
Collapsed=0
DockId=0x0000000C,0
[Docking][Data]
DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,55 Size=1920,1036 Split=X
DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1684,1036 Split=X
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=225,1036 Split=Y Selected=0x1E6EB881
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Selected=0xE096E5AE
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1293,1036 CentralNode=1 Selected=0x13926F0B
DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=234,1036 Selected=0xE7039252
DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,79 Size=1920,1012 Split=X
DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1526,1036 Split=X
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=308,1036 Split=Y Selected=0x1E6EB881
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,147 Selected=0x1E6EB881
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,863 Selected=0xE096E5AE
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1216,1036 Split=Y Selected=0xB41284E7
DockNode ID=0x00000007 Parent=0x00000002 SizeRef=1501,672 Split=Y Selected=0xB41284E7
DockNode ID=0x00000009 Parent=0x00000007 SizeRef=1501,700 Split=Y Selected=0xB41284E7
DockNode ID=0x0000000B Parent=0x00000009 SizeRef=1501,715 CentralNode=1 Selected=0xB41284E7
DockNode ID=0x0000000C Parent=0x00000009 SizeRef=1501,295 Selected=0xB128252A
DockNode ID=0x0000000A Parent=0x00000007 SizeRef=1501,310 Selected=0xD446F7B6
DockNode ID=0x00000008 Parent=0x00000002 SizeRef=1501,338 Selected=0xD9F31532
DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=392,1036 Selected=0xE7039252

View File

@ -1,48 +0,0 @@
[Window][MainStatusBar]
Pos=0,1060
Size=1920,20
Collapsed=0
[Window][SHEditorMenuBar]
Pos=0,48
Size=1920,1012
Collapsed=0
[Window][Hierarchy Panel]
Pos=0,142
Size=571,918
Collapsed=0
DockId=0x00000004,0
[Window][Debug##Default]
Pos=60,60
Size=400,400
Collapsed=0
[Window][Inspector]
Pos=1649,48
Size=271,1012
Collapsed=0
DockId=0x00000006,0
[Window][Profiler]
Pos=0,48
Size=571,92
Collapsed=0
DockId=0x00000003,0
[Window][Viewport]
Pos=573,48
Size=1074,1012
Collapsed=0
DockId=0x00000002,0
[Docking][Data]
DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,79 Size=1920,1012 Split=X
DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1992,1036 Split=X
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=571,1036 Split=Y Selected=0x1E6EB881
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Selected=0xE096E5AE
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1074,1036 CentralNode=1 Selected=0x13926F0B
DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=271,1036 Selected=0xE7039252

Binary file not shown.

View File

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

View File

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

View File

@ -0,0 +1,167 @@
//#version 450
//
//layout(local_size_x = 16, local_size_y = 16) in;
//layout(set = 4, binding = 0, rgba8) uniform image2D targetImage;
//
//
//void main()
//{
// ivec2 imageSize = imageSize (targetImage);
//
// if (gl_GlobalInvocationID.x >= imageSize.x && gl_GlobalInvocationID.y >= imageSize.y)
// return;
//
// // load the image
// vec4 color = imageLoad (targetImage, ivec2 (gl_GlobalInvocationID));
//
// // get the average
// float average = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
//
// // store result into result image
// imageStore(targetImage, ivec2(gl_GlobalInvocationID), vec4(average, average, average, 1.0f));
//
//}
//
//
//
//
/* Start Header *****************************************************************/
/*! \file (e.g. kirsch.comp)
\author William Zheng, william.zheng, 60001906. Brandon Mak, brandon.hao 390003920.
\par william.zheng\@digipen.edu. brandon.hao\@digipen.edu.
\date Sept 20, 2022
\brief Copyright (C) 20xx 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. */
/* End Header *******************************************************************/
#version 450
#define MASK_WIDTH 3
#define HALF_M_WIDTH MASK_WIDTH / 2
#define SHM_WIDTH 18
#define NUM_MASKS 8
layout(local_size_x = 16, local_size_y = 16) in;
layout(set = 4, binding = 0, rgba8) uniform image2D inputImage;
layout(set = 4, binding = 1, rgba8) uniform image2D resultImage;
const float kirsch[8][3][3] = {
{
{5, 5, 5},
{-3, 0, -3}, /*rotation 1 */
{-3, -3, -3}
},
{
{5, 5, -3},
{5, 0, -3}, /*rotation 2 */
{-3, -3, -3}
},
{
{5, -3, -3},
{5, 0, -3}, /*rotation 3 */
{5, -3, -3}
},
{
{-3, -3, -3},
{5, 0, -3}, /*rotation 4 */
{5, 5, -3}
},
{
{-3, -3, -3},
{-3, 0, -3}, /*rotation 5 */
{5, 5, 5}
},
{
{-3, -3, -3},
{-3, 0, 5}, /*rotation 6 */
{-3, 5, 5}
},
{
{-3, -3, 5},
{-3, 0, 5}, /*rotation 7 */
{-3, -3, 5}
},
{
{-3, 5, 5},
{-3, 0, 5}, /*rotation 8 */
{-3, -3, -3}
}
};
vec3 GetImageValues(ivec2 uv, ivec2 inputImageSize)
{
if (uv.x >= 0 && uv.y >= 0 && uv.x < inputImageSize.x && uv.y < inputImageSize.y)
{
return imageLoad(inputImage, uv).rgb;
}
else
return vec3(0.0f);
}
//two extra row/col
shared vec3 sData[16 + 2][16 + 2];
void main()
{
// convenient variables
ivec3 globalThread = ivec3(gl_GlobalInvocationID);
ivec3 localThread = ivec3(gl_LocalInvocationID);
ivec2 inputImageSize = imageSize(inputImage);
// load shared memory
ivec2 start = ivec2(gl_WorkGroupID) * ivec2(gl_WorkGroupSize) - ivec2(HALF_M_WIDTH);
for (int i = localThread.x; i < SHM_WIDTH; i += int(gl_WorkGroupSize.x))
{
for (int j = localThread.y; j < SHM_WIDTH; j += int(gl_WorkGroupSize.y))
{
// get from source image (either real values or 0)
vec3 sourceValue = GetImageValues(start + ivec2(i, j), inputImageSize);
sData[i][j] = sourceValue;
}
}
// wait for shared memory to finish loading
barrier();
// max (between all 8 masks)
vec3 maxSum = vec3(0.0f);
// loop through all masks
for (int i = 0; i < NUM_MASKS; ++i)
{
vec3 sum = vec3(0.0f);
// start of shared memory
ivec2 shmStart = ivec2(localThread + HALF_M_WIDTH);
for (int j = -1; j < HALF_M_WIDTH + 1; ++j)
{
for (int k = -1; k < HALF_M_WIDTH + 1; ++k)
{
// Perform convolution using shared_memory
sum += sData[shmStart.x + j][shmStart.y + k] * kirsch[i][j + 1][k + 1];
}
}
// Get highest sum
maxSum = max(sum, maxSum);
}
// average the max sum
maxSum = min(max(maxSum / 8, 0), 1.0f);
// store result into result image
imageStore(resultImage, ivec2(gl_GlobalInvocationID.xy), vec4(maxSum, 1.0f));
}

Binary file not shown.

View File

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

View File

@ -0,0 +1,67 @@
//#version 450
//
//layout(local_size_x = 16, local_size_y = 16) in;
//layout(set = 4, binding = 0, rgba8) uniform image2D targetImage;
//
//
//void main()
//{
// ivec2 imageSize = imageSize (targetImage);
//
// if (gl_GlobalInvocationID.x >= imageSize.x && gl_GlobalInvocationID.y >= imageSize.y)
// return;
//
// // load the image
// vec4 color = imageLoad (targetImage, ivec2 (gl_GlobalInvocationID));
//
// // get the average
// float average = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
//
// // store result into result image
// imageStore(targetImage, ivec2(gl_GlobalInvocationID), vec4(average, average, average, 1.0f));
//
//}
//
//
//
//
/* Start Header *****************************************************************/
/*! \file (e.g. kirsch.comp)
\author William Zheng, william.zheng, 60001906. Brandon Mak, brandon.hao 390003920.
\par william.zheng\@digipen.edu. brandon.hao\@digipen.edu.
\date Sept 20, 2022
\brief Copyright (C) 20xx 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. */
/* End Header *******************************************************************/
#version 450
layout(local_size_x = 16, local_size_y = 16) in;
layout(set = 4, binding = 0, rgba8) uniform image2D inputImage;
layout(set = 4, binding = 1, rgba8) uniform image2D targetImage;
void main()
{
// convenient variables
ivec2 globalThread = ivec2(gl_GlobalInvocationID);
vec3 color = imageLoad (inputImage, globalThread).rgb;
// store result into result image
imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(color, 1.0f));
}

Binary file not shown.

View File

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

View File

@ -23,6 +23,7 @@ layout(location = 2) flat in struct
{
int materialIndex;
uint eid;
uint lightLayerIndex;
} In2;
//layout (set = 0, binding = )
@ -35,6 +36,7 @@ layout (set = 3, binding = 0) buffer MaterialProperties // For materials
layout(location = 0) out vec4 outColor;
layout(location = 1) out uint outEntityID;
layout(location = 2) out uint lightLayerIndices;
void main()
{
@ -42,5 +44,6 @@ void main()
MatProp.data[In2.materialIndex].color / MatProp.data[In2.materialIndex].alpha;
outEntityID = In2.eid;
lightLayerIndices = In2.lightLayerIndex;
//outColor = vec4 (1.0f);
}

Binary file not shown.

View File

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

View File

@ -3,12 +3,13 @@
//#include "ShaderDescriptorDefinitions.glsl"
layout(location = 0) in vec3 aVertexPos;
layout(location = 1) in vec2 aUV;
layout(location = 2) in vec3 aNormal;
layout(location = 3) in vec3 aTangent;
layout(location = 4) in mat4 worldTransform;
layout(location = 8) in uint eid;
layout(location = 8) in uvec2 integerData;
layout(location = 0) out struct
@ -23,6 +24,7 @@ layout(location = 2) out struct
{
int materialIndex;
uint eid;
uint lightLayerIndex;
} Out2;
@ -36,7 +38,8 @@ void main()
{
Out.uv = aUV;
Out2.materialIndex = gl_InstanceIndex;
Out2.eid = eid;
Out2.eid = integerData[0];
Out2.lightLayerIndex = integerData[1];
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: 29315909
Type: 2

Binary file not shown.

View File

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

View File

@ -56,8 +56,8 @@ namespace Sandbox
_In_ INT nCmdShow
)
{
// Set working directory
SHFileUtilities::SetWorkDirToExecDir();
// Set working directory
SHFileUtilities::SetWorkDirToExecDir();
window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
@ -83,16 +83,19 @@ namespace Sandbox
SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::LateUpdateRoutine>();
SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::FrameCleanUpRoutine>();
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostLogicUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>();
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformUpdateRoutine>();
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>();
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BatcherDispatcherRoutine>();
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BeginRoutine>();
SHSystemManager::RegisterRoutine<SHCameraSystem, SHCameraSystem::EditorCameraUpdate>();
SHSystemManager::RegisterRoutine<SHCameraSystem, SHCameraSystem::CameraSystemUpdate>();
#ifdef SHEDITOR
SHSystemManager::RegisterRoutine<SHEditor, SHEditor::EditorRoutine>();
@ -107,14 +110,7 @@ namespace Sandbox
SHComponentManager::CreateComponentSparseSet<SHRenderable>();
SHComponentManager::CreateComponentSparseSet<SHCameraComponent>();
//TODO: REMOVE AFTER PRESENTATION
//SHAssetManager::LoadDataTemp("../../Assets/racoon.gltf");
//SHAssetManager::LoadDataTemp("../../Assets/Cube.012.shmesh");
//SHAssetManager::LoadDataTemp("../../Assets/RaccoonBag_Color_Ver4.dds");
//SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.dds");
//SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.shtex");
//TODO: REMOVE AFTER PRESENTATION
SHAssetManager::Load();
auto id = SHFamilyID<SHSystem>::GetID<SHGraphicsSystem>();
auto id2 = SHFamilyID<SHSystem>::GetID<SHGraphicsSystem>();
@ -130,8 +126,6 @@ namespace Sandbox
SHSceneManager::InitSceneManager<SBTestScene>("TestScene");
SHFrameRateController::UpdateFRC();
SHAssetManager::Load();
}
void SBApplication::Update(void)
@ -151,15 +145,14 @@ namespace Sandbox
SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, 0.016f);
editor->PollPicking();
}
// Finish all graphics jobs first
graphicsSystem->AwaitGraphicsExecution();
graphicsSystem->AwaitGraphicsExecution();
}
void SBApplication::Exit(void)
{
#ifdef SHEDITOR
#ifdef SHEDITOR
SDL_DestroyWindow(sdlWindow);
SDL_Quit();
#endif

View File

@ -1,4 +1,4 @@
#include "SBpch.h"
#include "SBpch.h"
#include "SBTestScene.h"
#include "ECS_Base/Managers/SHSystemManager.h"
@ -12,8 +12,11 @@
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Physics/Components/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Assets/SHAssetManager.h"
#include "Camera/SHCameraComponent.h"
#include "Resource/SHResourceManager.h"
using namespace SHADE;
@ -40,34 +43,23 @@ namespace Sandbox
const auto CUBE_MESH = SHADE::SHPrimitiveGenerator::Cube(*graphicsSystem);
//Test Racoon mesh
auto meshes = SHADE::SHAssetManager::GetAllMeshes();
std::vector<Handle<SHMesh>> handles;
for (auto const& mesh : meshes)
std::vector<Handle<SHTexture>> texHandles;
for (const auto& asset : SHAssetManager::GetAllAssets())
{
if (mesh.header.meshName == "Cube.012")
switch (asset.type)
{
handles.push_back(graphicsSystem->AddMesh(
mesh.header.vertexCount,
mesh.vertexPosition.data(),
mesh.texCoords.data(),
mesh.vertexTangent.data(),
mesh.vertexNormal.data(),
mesh.header.indexCount,
mesh.indices.data()
));
case AssetType::MESH:
if (asset.name == "Cube.012")
handles.emplace_back(SHResourceManager::LoadOrGet<SHMesh>(asset.id));
break;
case AssetType::TEXTURE:
if (asset.name == "RaccoonPreTexturedVer1_Base9")
texHandles.emplace_back(SHResourceManager::LoadOrGet<SHTexture>(asset.id));
break;
}
}
graphicsSystem->BuildMeshBuffers();
// Load Textures
auto textures = SHADE::SHAssetManager::GetAllTextures();
std::vector<Handle<SHTexture>> texHandles;
for (const auto& tex : textures)
{
auto texture = graphicsSystem->Add(tex);
texHandles.push_back(texture);
}
graphicsSystem->BuildTextures();
SHResourceManager::FinaliseChanges();
// Create Materials
auto matInst = graphicsSystem->AddOrGetBaseMaterialInstance();
@ -77,9 +69,9 @@ namespace Sandbox
customMat->SetProperty("data.alpha", 0.1f);
// Create Stress Test Objects
static const SHVec3 TEST_OBJ_SCALE = SHVec3::One * 0.5f;
constexpr int NUM_ROWS = 10;
constexpr int NUM_COLS = 10;
static const SHVec3 TEST_OBJ_SCALE = SHVec3::One;
constexpr int NUM_ROWS = 3;
constexpr int NUM_COLS = 1;
static const SHVec3 TEST_OBJ_SPACING = { 0.1f, 0.1f, 0.1f };
static const SHVec3 TEST_OBJ_START_POS = { -(NUM_COLS / 2 * TEST_OBJ_SPACING.x) + 1.0f, -2.0f, -1.0f };
@ -92,7 +84,7 @@ namespace Sandbox
auto& collider = *SHComponentManager::GetComponent_s<SHColliderComponent>(entity);
//renderable.Mesh = handles.front();
renderable.Mesh = CUBE_MESH;
renderable.SetMesh(CUBE_MESH);
renderable.SetMaterial(customMat);
if (y == 50)
@ -101,13 +93,13 @@ namespace Sandbox
//Set initial positions
transform.SetWorldPosition(TEST_OBJ_START_POS + SHVec3{ x * TEST_OBJ_SPACING.x, y * TEST_OBJ_SPACING.y, SHMath::GenerateRandomNumber(-3.5f, -5.0f) });
//transform.SetWorldPosition({-1.0f, -1.0f, -1.0f});
transform.SetWorldRotation(SHMath::GenerateRandomNumber(), SHMath::GenerateRandomNumber(), SHMath::GenerateRandomNumber());
transform.SetWorldRotation(SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f));
transform.SetWorldScale(TEST_OBJ_SCALE);
if (const bool IS_EVEN = (y * NUM_ROWS + x) % 2; IS_EVEN)
//if (const bool IS_EVEN = (y * NUM_ROWS + x) % 2; IS_EVEN)
collider.AddBoundingBox(SHVec3::One * 0.5f, SHVec3::Zero);
else
collider.AddBoundingSphere(0.5f, SHVec3::Zero);
//else
// collider.AddBoundingSphere(0.5f, SHVec3::Zero);
stressTestObjects.emplace_back(entity);
}
@ -116,7 +108,7 @@ namespace Sandbox
auto& renderable = *SHComponentManager::GetComponent_s<SHRenderable>(raccoonSpin);
auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(raccoonSpin);
renderable.Mesh = handles.front();
renderable.SetMesh(handles.front());
renderable.SetMaterial(customMat);
renderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f));
renderable.GetModifiableMaterial()->SetProperty("data.alpha", 1.0f);
@ -131,7 +123,7 @@ namespace Sandbox
auto& floorRigidBody = *SHComponentManager::GetComponent_s<SHRigidBodyComponent>(floor);
auto& floorCollider = *SHComponentManager::GetComponent_s<SHColliderComponent>(floor);
floorRenderable.Mesh = CUBE_MESH;
floorRenderable.SetMesh(CUBE_MESH);
floorRenderable.SetMaterial(customMat);
floorRenderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(1.0f, 1.0f, 1.0f, 1.0f));
@ -157,7 +149,7 @@ namespace Sandbox
auto& renderableShowcase = *SHComponentManager::GetComponent_s<SHRenderable>(raccoonShowcase);
auto& transformShowcase = *SHComponentManager::GetComponent_s<SHTransformComponent>(raccoonShowcase);
renderableShowcase.Mesh = handles.front();
renderableShowcase.SetMesh(handles.front());
renderableShowcase.SetMaterial(customMat);
renderableShowcase.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f));
renderableShowcase.GetModifiableMaterial()->SetProperty("data.alpha", 1.0f);
@ -166,6 +158,11 @@ namespace Sandbox
transformShowcase.SetWorldPosition({ 3.0f, -1.0f, -1.0f });
transformShowcase.SetLocalScale({ 5.0f, 5.0f, 5.0f });
scriptEngine->AddScript(raccoonShowcase, "RaccoonShowcase");
SHComponentManager::AddComponent<SHCameraComponent>(0);
SHComponentManager::AddComponent<SHLightComponent>(0);
SHComponentManager::RemoveComponent <SHRigidBodyComponent>(0);
SHComponentManager::RemoveComponent <SHColliderComponent>(0);
}
void SBTestScene::Update(float dt)

52
SHADE_CSharp/premake5.lua Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,30 @@
/*************************************************************************//**
* \file SHAnimationAsset.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 <vector>
#include <assimp/anim.h>
#include "SHAssetData.h"
namespace SHADE
{
struct SH_API SHAnimationAsset : SHAssetData
{
std::string name;
std::vector<aiNodeAnim*> nodeChannels;
std::vector<aiMeshAnim*> meshChannels;
std::vector<aiMeshMorphAnim*> morphMeshChannels;
double duration;
double ticksPerSecond;
};
}

View File

@ -0,0 +1,19 @@
/*************************************************************************//**
* \file SHAssetDataBase.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
namespace SHADE
{
struct SHAssetData
{
virtual ~SHAssetData(){}
};
}

View File

@ -0,0 +1,4 @@
#pragma once
#include "SHMeshAsset.h"
#include "SHTextureAsset.h"

View File

@ -0,0 +1,21 @@
/*************************************************************************//**
* \file SHInternalAsset.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 "SHAsset.h"
namespace SHADE
{
struct SHInternalAsset : SHAsset
{
};
}

View File

@ -14,7 +14,7 @@
#include <vector>
#include "Math/SHMath.h"
#include "SH_API.h"
#include "SHAssetData.h"
namespace SHADE
{
@ -22,10 +22,10 @@ namespace SHADE
{
uint32_t vertexCount;
uint32_t indexCount;
std::string meshName;
std::string name;
};
struct SH_API SHMeshAsset
struct SH_API SHMeshAsset : SHAssetData
{
bool compiled;
bool changed;

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

@ -2,10 +2,11 @@
#include "tinyddsloader.h"
#include "Graphics/MiddleEnd/Textures/SHTextureLibrary.h"
#include "SHAssetData.h"
namespace SHADE
{
struct SHTextureAsset
struct SHTextureAsset : SHAssetData
{
bool compiled;

View File

@ -0,0 +1,201 @@
/*************************************************************************//**
* \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 <assimp/postprocess.h>
#include <fstream>
namespace SHADE
{
Assimp::Importer SHMeshCompiler::aiImporter;
void SHMeshCompiler::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept
{
for (size_t i{ 0 }; i < node.mNumMeshes; ++i)
{
aiMesh* mesh = scene.mMeshes[node.mMeshes[i]];
meshes.push_back(ProcessMesh(*mesh));
}
for (size_t i{ 0 }; i < node.mNumChildren; ++i)
{
ProcessNode(*node.mChildren[i], scene, meshes);
}
}
void SHMeshCompiler::ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept
{
if (scene.HasAnimations())
{
std::vector<SHAnimationAsset> anims(scene.mNumAnimations);
for (auto i{ 0 }; i < scene.mNumAnimations; ++i)
{
auto const& anim{ *scene.mAnimations[i] };
anims[i].name = anim.mName.C_Str();
anims[i].duration = anim.mDuration;
anims[i].ticksPerSecond = anim.mTicksPerSecond;
std::copy_n(anim.mChannels, anim.mNumChannels, anims[i].nodeChannels.data());
std::copy_n(anim.mMeshChannels, anim.mNumMeshChannels, anims[i].meshChannels.data());
std::copy_n(anim.mMorphMeshChannels, anim.mNumMorphMeshChannels, anims[i].morphMeshChannels.data());
}
}
}
SHMeshAsset* SHMeshCompiler::ProcessMesh(aiMesh const& mesh) noexcept
{
SHMeshAsset* result = new SHMeshAsset();
result->compiled = false;
result->changed = false;
for (size_t i{ 0 }; i < mesh.mNumVertices; ++i)
{
// Vertex position
SHVec3 vertex;
vertex.x = mesh.mVertices[i].x;
vertex.y = mesh.mVertices[i].y;
vertex.z = mesh.mVertices[i].z;
result->vertexPosition.push_back(vertex);
// Tex coords
SHVec2 texCoord{ 0.f, 0.f };
if (mesh.mTextureCoords[0])
{
texCoord.x = mesh.mTextureCoords[0][i].x;
texCoord.y = mesh.mTextureCoords[0][i].y;
}
result->texCoords.push_back(texCoord);
// Normals
SHVec3 normal{ 0.f, 0.f, 0.f };
if (mesh.mNormals)
{
normal.x = mesh.mNormals[i].x;
normal.y = mesh.mNormals[i].y;
normal.z = mesh.mNormals[i].z;
}
result->vertexNormal.push_back(normal);
// Tangent
SHVec3 tangent{ 0.f, 0.f, 0.f };
if (mesh.mTangents)
{
tangent.x = mesh.mTangents[i].x;
tangent.y = mesh.mTangents[i].y;
tangent.z = mesh.mTangents[i].z;
}
result->vertexTangent.push_back(tangent);
}
for (size_t i{ 0 }; i < mesh.mNumFaces; ++i)
{
aiFace face = mesh.mFaces[i];
for (size_t j{ 0 }; j < face.mNumIndices; ++j)
{
result->indices.push_back(face.mIndices[j]);
}
}
result->header.vertexCount = static_cast<uint32_t>(result->vertexPosition.size());
result->header.indexCount = static_cast<uint32_t>(result->indices.size());
result->header.name = mesh.mName.C_Str();
return result;
}
void SHMeshCompiler::LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept
{
const aiScene* scene = aiImporter.ReadFile(path.string().c_str(),
aiProcess_Triangulate // Make sure we get triangles rather than nvert polygons
| aiProcess_GenUVCoords // Convert any type of mapping to uv mapping
| aiProcess_TransformUVCoords // preprocess UV transformations (scaling, translation ...)
| aiProcess_FindInstances // search for instanced meshes and remove them by references to one master
| aiProcess_CalcTangentSpace // calculate tangents and bitangents if possible
| aiProcess_JoinIdenticalVertices // join identical vertices/ optimize indexing
| aiProcess_RemoveRedundantMaterials // remove redundant materials
| aiProcess_FindInvalidData // detect invalid model data, such as invalid normal vectors
| aiProcess_FlipUVs // flip the V to match the Vulkans way of doing UVs
);
if (!scene || !scene->HasMeshes())
{
SHLOG_ERROR("ERROR in GLTF::ASSIMP: {}\nFile: {}", aiImporter.GetErrorString(), path.string());
return;
}
//ExtractAnimations(*scene, anims);
ProcessNode(*scene->mRootNode, *scene, meshes);
aiImporter.FreeScene();
}
std::optional<AssetPath> SHMeshCompiler::CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept
{
std::string newPath{ path.parent_path().string() + '/' };
newPath += asset.header.name + MESH_EXTENSION.data();
std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open file for writing mesh file: {}", path.string());
}
file.write(
reinterpret_cast<char const*>(&(asset.header.vertexCount)),
sizeof(uint32_t)
);
file.write(
reinterpret_cast<const char*>(&(asset.header.indexCount)),
sizeof(uint32_t)
);
auto const vertexVec3Byte{ sizeof(SHVec3) * asset.header.vertexCount };
auto const vertexVec2Byte{ sizeof(SHVec2) * asset.header.vertexCount };
file.write(
reinterpret_cast<char const*>(asset.vertexPosition.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexTangent.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexNormal.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.texCoords.data()),
vertexVec2Byte
);
file.write(
reinterpret_cast<char const*>(asset.indices.data()),
sizeof(uint32_t) * asset.header.indexCount
);
file.close();
return newPath;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,22 @@
/*************************************************************************//**
* \file SHAssetLoader.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 "Assets/SHAssetMacros.h"
#include "Assets/Asset Types/SHAssetData.h"
namespace SHADE
{
struct SHAssetLoader
{
virtual SHAssetData* Load(AssetPath path) = 0;
};
}

View File

@ -0,0 +1,78 @@
/*************************************************************************//**
* \file SHMeshLoader.cpp
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Implementation for Mesh loader. Accounts for custom binary format
* as well as GLTF file 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 "SHMeshLoader.h"
#include <fstream>
namespace SHADE
{
void SHMeshLoader::LoadSHMesh(AssetPath path, SHMeshAsset& mesh) noexcept
{
std::ifstream file{ path.string(), std::ios::in | std::ios::binary };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open SHMesh File: {}", path.string());
}
const std::string name{ path.stem().string() };
file.seekg(0);
uint32_t vertCount, indexCount;
std::vector<SHVec3> vertPos, vertTan, vertNorm;
std::vector<SHVec2> texCoord;
std::vector<uint32_t> indices;
file.read(reinterpret_cast<char*>(&vertCount), sizeof(uint32_t));
file.read(reinterpret_cast<char*>(&indexCount), sizeof(uint32_t));
auto const vertexVec3Byte{ sizeof(SHVec3) * vertCount };
auto const vertexVec2Byte{ sizeof(SHVec2) * vertCount };
vertPos.resize(vertCount);
vertTan.resize(vertCount);
vertNorm.resize(vertCount);
texCoord.resize(vertCount);
indices.resize(indexCount);
file.read(reinterpret_cast<char *>(vertPos.data()), vertexVec3Byte);
file.read(reinterpret_cast<char *>(vertTan.data()), vertexVec3Byte);
file.read(reinterpret_cast<char *>(vertNorm.data()), vertexVec3Byte);
file.read(reinterpret_cast<char *>(texCoord.data()), vertexVec2Byte);
file.read(reinterpret_cast<char *>(indices.data()), sizeof(uint32_t) * indexCount);
mesh.compiled = true;
mesh.changed = false;
mesh.header.indexCount = indexCount;
mesh.header.vertexCount = vertCount;
mesh.header.name = name;
mesh.vertexPosition = std::move(vertPos);
mesh.vertexTangent = std::move(vertTan);
mesh.vertexNormal = std::move(vertNorm);
mesh.texCoords = std::move(texCoord);
mesh.indices = std::move(indices);
file.close();
}
SHAssetData* SHMeshLoader::Load(AssetPath path)
{
auto result = new SHMeshAsset();
LoadSHMesh(path, *result);
return result;
}
}

View File

@ -1,9 +1,8 @@
/*************************************************************************//**
* \file SHMeshCompiler.h
* \file SHMeshLoader.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
* \brief Library to load gltf mesh files and custom binary format
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
@ -11,16 +10,15 @@
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#include "../Asset Types/SHMeshAsset.h"
#include "../SHAssetMacros.h"
#include "Assets/SHAssetMacros.h"
#include "Assets/Asset Types/SHMeshAsset.h"
#include "SHAssetLoader.h"
namespace SHADE
{
class SHMeshCompiler
struct SHMeshLoader : SHAssetLoader
{
private:
public:
static std::string CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept;
void LoadSHMesh(AssetPath path, SHMeshAsset& meshes) noexcept;
SHAssetData* Load(AssetPath path) override;
};
}

View File

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

View File

@ -0,0 +1,22 @@
/*************************************************************************//**
* \file SHShaderSourceLoader.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/Libraries/Loaders/SHAssetLoader.h"
#include "Assets/SHAssetMacros.h"
namespace SHADE
{
struct SHShaderSourceLoader : SHAssetLoader
{
SHAssetData* Load(AssetPath path) override;
};
}

View File

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

View File

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

View File

@ -1,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.meshName + MESH_EXTENSION;
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,231 +0,0 @@
/*************************************************************************//**
* \file SHMeshLoader.cpp
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Implementation for Mesh loader. Accounts for custom binary format
* as well as GLTF file 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 "SHMeshLoader.h"
#include <assimp/postprocess.h>
#include <fstream>
namespace SHADE
{
Assimp::Importer SHMeshLoader::aiImporter;
void SHMeshLoader::ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes) noexcept
{
for (size_t i {0}; i < node.mNumMeshes; ++i)
{
aiMesh* mesh = scene.mMeshes[node.mMeshes[i]];
meshes.push_back(ProcessMesh(*mesh, scene));
}
for (size_t i{ 0 }; i < node.mNumChildren; ++i)
{
ProcessNode(*node.mChildren[i], scene, meshes);
}
}
SHMeshAsset SHMeshLoader::ProcessMesh(aiMesh const& mesh, aiScene const& scene) noexcept
{
(void)scene;
SHMeshAsset result
{
.compiled { false},
.changed { false }
};
for (size_t i{0}; i < mesh.mNumVertices; ++i)
{
// Vertex position
SHVec3 vertex;
vertex.x = mesh.mVertices[i].x;
vertex.y = mesh.mVertices[i].y;
vertex.z = mesh.mVertices[i].z;
result.vertexPosition.push_back(vertex);
// Tex coords
SHVec2 texCoord{0.f, 0.f};
if (mesh.mTextureCoords[0])
{
texCoord.x = mesh.mTextureCoords[0][i].x;
texCoord.y = mesh.mTextureCoords[0][i].y;
}
result.texCoords.push_back(texCoord);
// Normals
SHVec3 normal{0.f, 0.f, 0.f};
if (mesh.mNormals)
{
normal.x = mesh.mNormals[i].x;
normal.y = mesh.mNormals[i].y;
normal.z = mesh.mNormals[i].z;
}
result.vertexNormal.push_back(normal);
// Tangent
SHVec3 tangent{0.f, 0.f, 0.f};
if (mesh.mTangents)
{
tangent.x = mesh.mTangents[i].x;
tangent.y = mesh.mTangents[i].y;
tangent.z = mesh.mTangents[i].z;
}
result.vertexTangent.push_back(tangent);
}
for (size_t i {0}; i < mesh.mNumFaces; ++i)
{
aiFace face = mesh.mFaces[i];
for (size_t j{0}; j < face.mNumIndices; ++j)
{
result.indices.push_back(face.mIndices[j]);
}
}
result.header.vertexCount = static_cast<uint32_t>(result.vertexPosition.size());
result.header.indexCount = static_cast<uint32_t>(result.indices.size());
result.header.meshName = mesh.mName.C_Str();
return result;
}
void SHMeshLoader::LoadExternal(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept
{
const aiScene* scene = aiImporter.ReadFile(path.string().c_str(),
aiProcess_Triangulate // Make sure we get triangles rather than nvert polygons
| aiProcess_GenUVCoords // Convert any type of mapping to uv mapping
| aiProcess_TransformUVCoords // preprocess UV transformations (scaling, translation ...)
| aiProcess_FindInstances // search for instanced meshes and remove them by references to one master
| aiProcess_CalcTangentSpace // calculate tangents and bitangents if possible
| aiProcess_JoinIdenticalVertices // join identical vertices/ optimize indexing
| aiProcess_RemoveRedundantMaterials // remove redundant materials
| aiProcess_FindInvalidData // detect invalid model data, such as invalid normal vectors
| aiProcess_FlipUVs // flip the V to match the Vulkans way of doing UVs
);
if (!scene || !scene->HasMeshes())
{
SHLOG_ERROR("ERROR in GLTF::ASSIMP: {}\nFile: {}", aiImporter.GetErrorString(), path.string());
return;
}
//TODO MATERIALS FROM MESHES
//if (scene->HasMaterials())
//{
// for (int i{0}; i < scene->mNumMaterials; ++i)
// {
// if (scene->mMaterials[i]->mNumProperties > 0)
// {
// for (int j{0}; j < scene->mMaterials[i]->mProperties[j].)
// }
//std::cout << scene->mMaterials[i]->;
// }
//}
ProcessNode(*scene->mRootNode, *scene, meshes);
}
void SHMeshLoader::LoadSHMesh(SHMeshAsset& mesh, AssetPath path) noexcept
{
std::ifstream file{ path.string(), std::ios::in | std::ios::binary };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open SHMesh File: {}", path.string());
}
const std::string name{ path.stem().string() };
file.seekg(0);
uint32_t vertCount, indexCount;
std::vector<SHVec3> vertPos, vertTan, vertNorm;
std::vector<SHVec2> texCoord;
std::vector<uint32_t> indices;
file.read(reinterpret_cast<char*>(&vertCount), sizeof(uint32_t));
file.read(reinterpret_cast<char*>(&indexCount), sizeof(uint32_t));
auto const vertexVec3Byte{ sizeof(SHVec3) * vertCount };
auto const vertexVec2Byte{ sizeof(SHVec2) * vertCount };
vertPos.resize(vertCount);
vertTan.resize(vertCount);
vertNorm.resize(vertCount);
texCoord.resize(vertCount);
indices.resize(indexCount);
file.read(reinterpret_cast<char *>(vertPos.data()), vertexVec3Byte);
file.read(reinterpret_cast<char *>(vertTan.data()), vertexVec3Byte);
file.read(reinterpret_cast<char *>(vertNorm.data()), vertexVec3Byte);
file.read(reinterpret_cast<char *>(texCoord.data()), vertexVec2Byte);
file.read(reinterpret_cast<char *>(indices.data()), sizeof(uint32_t) * indexCount);
//for (auto i{ 0 }; i < vertCount; ++i)
//{
// file >> vertPos[i].x;
// file >> vertPos[i].y;
// file >> vertPos[i].z;
//}
//
//for (auto i{ 0 }; i < vertCount; ++i)
//{
// file >> vertTan[i].x;
// file >> vertTan[i].y;
// file >> vertTan[i].z;
//}
//for (auto i{ 0 }; i < vertCount; ++i)
//{
// file >> vertNorm[i].x;
// file >> vertNorm[i].y;
// file >> vertNorm[i].z;
//}
//for (auto i{ 0 }; i < vertCount; ++i)
//{
// file >> texCoord[i].x;
// file >> texCoord[i].y;
//}
//for (auto i{ 0 }; i < indexCount; ++i)
//{
// file >> indices[i];
//}
mesh.compiled = true;
mesh.changed = false;
mesh.header.indexCount = indexCount;
mesh.header.vertexCount = vertCount;
mesh.header.meshName = name;
mesh.vertexPosition = std::move(vertPos);
mesh.vertexTangent = std::move(vertTan);
mesh.vertexNormal = std::move(vertNorm);
mesh.texCoords = std::move(texCoord);
mesh.indices = std::move(indices);
file.close();
}
void SHMeshLoader::LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept
{
if (path.extension().string() == GLTF_EXTENSION)
{
LoadExternal(meshes, path);
return;
}
meshes.emplace_back();
LoadSHMesh(meshes.back(), path);
}
}

View File

@ -1,36 +0,0 @@
/*************************************************************************//**
* \file SHMeshLoader.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to load gltf mesh files and custom binary format
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include "../SHAssetMacros.h"
#include "../Asset Types/SHMeshAsset.h"
#include <vector>
namespace SHADE
{
class SHMeshLoader
{
private:
static Assimp::Importer aiImporter;
static void ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes) noexcept;
static SHMeshAsset ProcessMesh(aiMesh const& mesh, aiScene const& scene) noexcept;
static void LoadExternal(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept;
public:
static void LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept;
static void LoadSHMesh(SHMeshAsset& meshes, 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,147 +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();
}
void SHTextureLoader::LoadImageAsset(AssetPath path, SHTextureAsset& asset)
{
if (path.extension().string() == DDS_EXTENSION)
{
LoadTinyDDS(path, asset);
}
else if (path.extension().string() == TEXTURE_EXTENSION)
{
LoadSHTexture(path, asset);
}
}
}

View File

@ -1,33 +0,0 @@
/*************************************************************************//**
* \file SHTextureLoader.h
* \author Loh Xiao Qi
* \date 30 September 2022
* \brief Library to load dds textures and custom binary format
*
*
* Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
*****************************************************************************/
#pragma once
#define TINYDDSLOADER_IMPLEMENTATION
#include "../SHAssetMacros.h"
#include "../Asset Types/SHTextureAsset.h"
#include "tinyddsloader.h"
namespace SHADE
{
class SHTextureLoader
{
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;
public:
static void LoadImageAsset(AssetPath paths, SHTextureAsset& image);
static void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept;
};
}

View File

@ -12,11 +12,12 @@
#pragma once
#include "Filesystem/SHFileSystem.h"
#include "SHAssetMacros.h"
#include "Assets/SHAssetMacros.h"
#include "SH_API.h"
namespace SHADE
{
struct SHAsset
struct SH_API SHAsset
{
AssetName name;
AssetID id;

View File

@ -32,74 +32,89 @@ typedef std::filesystem::path AssetPath;
typedef unsigned char* AssetData;
typedef std::string AssetMetaVersion;
typedef std::string AssetExtension;
typedef unsigned char AssetTypeMeta;
typedef size_t AssetTypeMeta;
typedef FMOD::Sound* SHSound;
// Asset Meta Version
#define ASSET_META_VER "1.0"
constexpr std::string_view ASSET_META_VER { "1.0" };
// Asset type enum
enum class AssetType : AssetTypeMeta
{
INVALID = 0,
AUDIO = 1,
INVALID,
SHADER,
MATERIAL,
IMAGE,
TEXTURE,
MESH,
SCRIPT,
SCENE,
PREFAB,
AUDIO_WAV,
DDS
SHADER_BUILT_IN,
TEXTURE,
MESH,
MAX_COUNT
};
constexpr size_t TYPE_COUNT{ static_cast<size_t>(AssetType::MAX_COUNT) };
//Directory
#ifdef _PUBLISH
#define ASSET_ROOT "Assets"
constexpr std::string_view ASSET_ROOT {"Assets"};
#else
#define ASSET_ROOT "../../Assets"
constexpr std::string_view ASSET_ROOT {"../../Assets"};
#endif
// ASSET EXTENSIONS
#define META_EXTENSION ".shmeta"
#define IMAGE_EXTENSION ".png"
#define AUDIO_EXTENSION ".ogg"
#define AUDIO_WAV_EXTENSION ".wav"
#define SHADER_EXTENSION ".glsl"
#define SCRIPT_EXTENSION ".cs"
#define SCENE_EXTENSION ".SHADE"
#define PREFAB_EXTENSION ".SHPrefab"
#define MATERIAL_EXTENSION ".SHMat"
#define TEXTURE_EXTENSION ".shtex"
#define DDS_EXTENSION ".dds"
#define FBX_EXTENSION ".fbx"
#define GLTF_EXTENSION ".gltf"
#define MESH_EXTENSION ".shmesh"
constexpr std::string_view META_EXTENSION {".shmeta"};
constexpr std::string_view AUDIO_EXTENSION {".ogg"};
constexpr std::string_view AUDIO_WAV_EXTENSION {".wav"};
constexpr std::string_view SHADER_EXTENSION{ ".shshader" };
constexpr std::string_view SHADER_BUILT_IN_EXTENSION{".shshaderb"};
constexpr std::string_view SCRIPT_EXTENSION {".cs"};
constexpr std::string_view SCENE_EXTENSION {".shade"};
constexpr std::string_view PREFAB_EXTENSION {".shprefab"};
constexpr std::string_view MATERIAL_EXTENSION {".shmat"};
constexpr std::string_view TEXTURE_EXTENSION {".shtex"};
constexpr std::string_view MESH_EXTENSION {".shmesh"};
std::string const EXTENSIONS[] = {
constexpr std::string_view EXTENSIONS[] = {
AUDIO_EXTENSION,
SHADER_EXTENSION,
SHADER_BUILT_IN_EXTENSION,
MATERIAL_EXTENSION,
IMAGE_EXTENSION,
TEXTURE_EXTENSION,
DDS_EXTENSION,
MESH_EXTENSION,
SCRIPT_EXTENSION,
SCENE_EXTENSION,
PREFAB_EXTENSION,
AUDIO_WAV_EXTENSION,
};
// EXTERNAL EXTENSIONS
constexpr std::string_view GLSL_EXTENSION{ ".glsl" };
constexpr std::string_view DDS_EXTENSION{ ".dds" };
constexpr std::string_view FBX_EXTENSION{ ".fbx" };
constexpr std::string_view GLTF_EXTENSION{ ".gltf" };
constexpr std::string_view EXTERNALS[] = {
GLSL_EXTENSION,
DDS_EXTENSION,
FBX_EXTENSION,
GLTF_EXTENSION
};
// 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
#define FILE_NOT_FOUND_ERR "FILE NOT FOUND"
#define META_NOT_FOUND_ERR "META NOT FOUND"
#define ASSET_NOT_FOUND_ERR "ASSET NOT FOUND"
#define EXT_DOES_NOT_EXIST "TYPE DOES NOT HAVE EXTENSION DEFINED"
constexpr std::string_view FILE_NOT_FOUND_ERR {"FILE NOT FOUND"};
constexpr std::string_view META_NOT_FOUND_ERR {"META NOT FOUND"};
constexpr std::string_view ASSET_NOT_FOUND_ERR {"ASSET NOT FOUND"};
constexpr std::string_view EXT_DOES_NOT_EXIST {"TYPE DOES NOT HAVE EXTENSION DEFINED"};
#endif // !SH_ASSET_MACROS_H

View File

@ -14,22 +14,23 @@
#include "SHAssetMetaHandler.h"
#include "Filesystem/SHFileSystem.h"
#include "Libraries/SHMeshLoader.h"
#include "Libraries/SHTextureLoader.h"
#include "Libraries/Loaders/SHMeshLoader.h"
#include "Libraries/Loaders/SHTextureLoader.h"
#include "Libraries/Loaders/SHShaderSourceLoader.h"
#include "Libraries/SHMeshCompiler.h"
#include "Libraries/SHTextureCompiler.h"
#include "Libraries/Compilers/SHMeshCompiler.h"
#include "Libraries/Compilers/SHTextureCompiler.h"
#include "Libraries/Compilers/SHShaderSourceCompiler.h"
namespace SHADE
{
FMOD::System* SHAssetManager::audioSystem;
std::unordered_map<AssetID, SHSound >* SHAssetManager::audioSoundList;
std::vector<SHAsset> SHAssetManager::assetCollection;
std::unordered_map<AssetID, SHAsset> SHAssetManager::assetRegistry;
std::vector<SHAssetLoader*> SHAssetManager::loaders(TYPE_COUNT);
std::unordered_map<AssetID, SHMeshAsset> SHAssetManager::meshCollection;
std::unordered_map<AssetID, SHTextureAsset> SHAssetManager::textureCollection;
std::vector<SHAsset> SHAssetManager::assetCollection;
std::unordered_map<AssetID, SHAssetData * const> SHAssetManager::assetData;
/****************************************************************************
* \brief Static function to generate asset ID.
@ -44,7 +45,13 @@ namespace SHADE
result |= unique;
while (result == 0)
while (result == 0 ||
std::ranges::any_of(
assetCollection.begin(),
assetCollection.end(),
[result](SHAsset const& asset) { return asset.id == result; }
)
)
{
result = GenerateAssetID(type);
}
@ -56,9 +63,24 @@ namespace SHADE
****************************************************************************/
void SHAssetManager::Unload() noexcept
{
for (auto const& asset : assetCollection)
}
void SHAssetManager::Unload(AssetID assetId) noexcept
{
// TODO
}
void SHAssetManager::Exit() noexcept
{
for (auto const& loader : loaders)
{
SHAssetMetaHandler::WriteMetaData(asset);
delete loader;
}
for (auto const& data : assetData)
{
delete data.second;
}
}
@ -80,7 +102,30 @@ namespace SHADE
// return std::filesystem::path();
//}
return std::filesystem::path(ASSET_ROOT + folder + path.filename().string());
return std::filesystem::path(std::string(ASSET_ROOT) + folder + path.filename().string());
}
AssetPath SHAssetManager::GenerateNewPath(AssetName name, AssetType type)
{
std::string folder;
switch(type)
{
case AssetType::SHADER:
case AssetType::SHADER_BUILT_IN:
folder = "Shaders/";
break;
default:
folder = "/";
}
return std::filesystem::path{
std::string(ASSET_ROOT) +
folder +
name +
std::string(EXTENSIONS[static_cast<size_t>(type)])
};
}
/****************************************************************************
@ -116,7 +161,7 @@ namespace SHADE
// folder = "";
// break;
//}
AssetPath path{ ASSET_ROOT + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) };
AssetPath path{ std::string{ASSET_ROOT} + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) };
SHAssetMetaHandler::WriteMetaData(meta);
@ -125,6 +170,19 @@ namespace SHADE
return id;
}
AssetID SHAssetManager::CreateAsset(AssetName name, AssetType type) noexcept
{
AssetID id = GenerateAssetID(type);
assetCollection.emplace_back(
name,
id,
type,
GenerateNewPath(name, type),
0
);
return id;
}
/****************************************************************************
* \brief Import new asset from outside editor window.
*
@ -133,7 +191,10 @@ namespace SHADE
****************************************************************************/
AssetID SHAssetManager::ImportNewAsset(char const* p) noexcept
{
std::filesystem::path const path{ p };
std::filesystem::path const path{ p };
auto const type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string());
auto const id = GenerateAssetID(type);
std::filesystem::path const newPath{ GenerateLocalPath(path) };
if (newPath.empty())
@ -144,11 +205,7 @@ namespace SHADE
std::filesystem::copy(path, newPath);
AssetID id{ RetrieveAsset(newPath.string().c_str()) };
if (id != 0)
{
LoadData(id);
}
assetCollection.push_back(CreateAssetFromPath(newPath));
return id;
}
@ -159,158 +216,63 @@ namespace SHADE
****************************************************************************/
void SHAssetManager::RefreshAllAssets() noexcept
{
std::vector<AssetPath> metaFiles;
std::vector<AssetPath> AssetFiles;
//SHFileSystem::LoadAllFiles(metaFiles, AssetFiles);
//std::vector<AssetPath> AssetFilesVerified;
std::vector<AssetPath> AssetFilesNew;
}
for (auto const& asset : AssetFiles)
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)
{
bool found = false;
for (auto it {metaFiles.begin()}; it != metaFiles.end(); ++it)
{
std::string fileExtCheck{ asset.filename().string() };
fileExtCheck += META_EXTENSION;
if (it->filename().string() == fileExtCheck)
{
metaFiles.erase(it);
found = true;
break;
}
}
result.push_back(LoadData(get));
}
if (!found && IsRecognised(asset.extension().string().c_str()))
return result;
}
std::vector<SHAsset> SHAssetManager::GetAllRecordOfType(AssetType type) noexcept
{
std::vector<SHAsset> result;
for (auto const& asset : assetCollection)
{
if (asset.type == type)
{
AssetFilesNew.push_back(asset);
result.push_back(asset);
}
}
std::vector<SHAsset> newLoad;
newLoad.reserve(AssetFilesNew.size());
//TODO: Handle if meta does not match all assets (if meta exist and asset doesnt, vice versa)
for (auto const& file : AssetFilesNew)
{
newLoad.push_back(RegisterAssetNew(file));
}
//UpdateAllSpriteSets();
}
void SHAssetManager::LoadDataTemp(std::string p) noexcept
{
AssetPath path{ p };
if (path.extension().string() == FBX_EXTENSION
|| path.extension().string() == GLTF_EXTENSION
|| path.extension().string() == MESH_EXTENSION)
{
LoadGLTF(
{
.name {path.filename().string()},
.id {0},
.type {AssetType::MESH},
.path {path},
.location {0}
}
);
}
else if (path.extension().string() == DDS_EXTENSION
|| path.extension().string() == TEXTURE_EXTENSION)
{
LoadDDS(
{
.name {path.filename().string()},
.id {0},
.type {AssetType::DDS},
.path {path},
.location {0}
}
);
}
}
std::vector<SHMeshAsset> SHAssetManager::GetAllMeshes() noexcept
{
std::vector<SHMeshAsset> result;
for (auto const& mesh : meshCollection)
{
result.push_back(mesh.second);
}
return result;
}
std::vector<SHTextureAsset> SHAssetManager::GetAllTextures() noexcept
{
std::vector<SHTextureAsset> result;
for (auto const& dds : textureCollection)
{
result.push_back(dds.second);
}
AssetID SHAssetManager::CompileAsset(AssetPath path) noexcept
{
SHAsset newAsset
{
.name = path.stem().string(),
.location = 0
};
return result;
}
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;
}
SHMeshAsset const* SHAssetManager::GetMesh(AssetID id) noexcept
{
if (meshCollection.find(id) == meshCollection.end())
{
return nullptr;
}
assetCollection.push_back(newAsset);
SHAssetMetaHandler::WriteMetaData(newAsset);
return &meshCollection[id];
}
return newAsset.id;
}
SHTextureAsset const* SHAssetManager::GetTexture(AssetID id) noexcept
{
if (textureCollection.find(id) == textureCollection.end())
{
return nullptr;
}
return &textureCollection[id];
}
/****************************************************************************
* \param Path for meta data file
* \param Path for asset file
* \brief Links meta data to asset in registries. Meta data should
* already exist
****************************************************************************/
void SHAssetManager::RegisterAsset(AssetPath const& metaPath, AssetPath const& path) noexcept
{
SHAsset const meta = SHAssetMetaHandler::RetrieveMetaData(metaPath);
assetCollection.push_back(meta);
}
/****************************************************************************
* \param Path for asset file
* \brief Creates new meta data for new asset.
****************************************************************************/
SHAsset SHAssetManager::RegisterAssetNew(AssetPath const& asset) noexcept
{
SHAsset meta;
meta.type = SHAssetMetaHandler::GetTypeFromExtension(asset.extension().string());
meta.id = GenerateAssetID(meta.type);
assetCollection.push_back(meta);
SHAssetMetaHandler::WriteMetaData(meta);
return assetCollection.back();
}
bool SHAssetManager::IsRecognised(char const* ext) noexcept
bool SHAssetManager::IsRecognised(char const* ext) noexcept
{
for (auto const& e : EXTENSIONS)
{
if (strcmp(ext, e.c_str()) == 0)
if (strcmp(ext, e.data()) == 0)
{
return true;
}
@ -319,54 +281,90 @@ namespace SHADE
return false;
}
void SHAssetManager::LoadGLTF(SHAsset asset) noexcept
SHAsset SHAssetManager::CreateAssetFromPath(AssetPath path) noexcept
{
std::vector<SHMeshAsset> meshes;
SHAsset result;
SHMeshLoader::LoadMesh(meshes, asset.path);
result.name = path.stem().string();
result.type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string());
result.id = GenerateAssetID(result.type);
result.path = path;
result.location = 0;
for (auto const& mesh : meshes)
{
auto id{ GenerateAssetID(AssetType::MESH) };
meshCollection.emplace(id, mesh);
AssetPath path;
if (!mesh.compiled)
{
path = SHMeshCompiler::CompileMeshBinary(mesh, asset.path);
}
assetCollection.emplace_back(
mesh.header.meshName,
id,
AssetType::MESH,
path,
0
);
}
return result;
}
void SHAssetManager::LoadDDS(SHAsset asset) noexcept
void SHAssetManager::CompileAll() noexcept
{
std::vector<AssetPath> paths;
for (auto const& dir : std::filesystem::recursive_directory_iterator{ ASSET_ROOT })
{
if (dir.is_regular_file())
{
for (auto const& ext : EXTERNALS)
{
if (dir.path().extension().string() == ext.data())
{
paths.push_back(dir.path());
}
}
}
}
for (auto const& path : paths)
{
SHAsset newAsset
{
.name = path.stem().string(),
.location = 0
};
auto const ext{ path.extension().string() };
if (ext == GLSL_EXTENSION.data())
{
newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value();
newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN);
newAsset.type = AssetType::SHADER_BUILT_IN;
}
else if (ext == DDS_EXTENSION.data())
{
newAsset.path = SHTextureCompiler::CompileTextureAsset(path).value();
newAsset.id = GenerateAssetID(AssetType::TEXTURE);
newAsset.type = AssetType::TEXTURE;
}
else if (ext == GLTF_EXTENSION.data() || ext == FBX_EXTENSION.data())
{
std::vector<SHMeshAsset*> meshes;
std::vector<SHAnimationAsset*> anims;
SHMeshCompiler::LoadFromFile(path, meshes, anims);
for (auto const& mesh : meshes)
{
SHAsset meshAsset{
.name = mesh->header.name,
.location = 0
};
meshAsset.path = SHMeshCompiler::CompileMeshBinary(*mesh, path).value();
meshAsset.id = GenerateAssetID(AssetType::MESH);
meshAsset.type = AssetType::MESH;
assetCollection.push_back(meshAsset);
SHAssetMetaHandler::WriteMetaData(meshAsset);
}
continue;
}
assetCollection.push_back(newAsset);
SHAssetMetaHandler::WriteMetaData(newAsset);
}
}
void SHAssetManager::InitLoaders() noexcept
{
SHTextureAsset image;
SHTextureLoader::LoadImageAsset(asset.path, image);
if (!image.compiled)
{
auto id{ GenerateAssetID(AssetType::TEXTURE) };
textureCollection.emplace(id, image);
auto path{ SHTextureCompiler::CompileTextureBinary(image, asset.path) };
assetCollection.emplace_back(
image.name,
id,
AssetType::TEXTURE,
path,
0
);
}
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());
}
/****************************************************************************
@ -374,8 +372,10 @@ namespace SHADE
****************************************************************************/
void SHAssetManager::Load() noexcept
{
RetrieveAssets();
LoadAllData();
//CompileAll();
InitLoaders();
BuildAssetCollection();
//LoadAllData();
}
/****************************************************************************
@ -383,143 +383,40 @@ namespace SHADE
****************************************************************************/
void SHAssetManager::LoadAllData() noexcept
{
//TODO Remove when on demand loading is done
for (auto const& asset : assetCollection)
{
switch (asset.type)
{
case AssetType::MESH:
meshCollection.emplace(asset.id, SHMeshAsset());
SHMeshLoader::LoadSHMesh(meshCollection[asset.id], asset.path);
break;
case AssetType::TEXTURE:
textureCollection.emplace(asset.id, SHTextureAsset());
SHTextureLoader::LoadSHTexture(asset.path, textureCollection[asset.id]);
break;
default:
void;
}
SHAssetData* data = loaders[static_cast<size_t>(asset.type)]->Load(asset.path);
assetData.emplace(asset.id, data);
}
}
void SHAssetManager::LoadData(AssetID id) noexcept
SHAssetData* SHAssetManager::LoadData(SHAsset const& asset) noexcept
{
(void)id;
}
SHAssetData* data = loaders[static_cast<size_t>(asset.type)]->Load(asset.path);
/****************************************************************************
* \brief Retrieve all asset files and meta files from filesystem
****************************************************************************/
void SHAssetManager::RetrieveAssets() noexcept
{
std::vector<AssetPath> metaFiles;
std::vector<AssetPath> AssetFiles;
for (auto const dir : std::filesystem::recursive_directory_iterator(ASSET_ROOT))
if (data == nullptr)
{
if (dir.path().extension().string() == META_EXTENSION)
{
auto meta{ SHAssetMetaHandler::RetrieveMetaData(dir.path()) };
assetCollection.push_back(meta);
assetRegistry.emplace(meta.id, meta);
}
}
//TODO: Write new function for file manager to loop through all files
//SHFileSystem::StartupFillDirectories(ASSET_ROOT);
//FolderPointer rootFolder = SHFileSystem::GetRoot();
//for (auto const& meta : metaFiles)
//{
// for (std::vector<AssetPath>::const_iterator it{ AssetFiles.cbegin() };
// it != AssetFiles.cend();
// ++it)
// {
// // Asset exists for meta file
// std::string fileExtCheck{ it->filename().string() };
// fileExtCheck += META_EXTENSION;
// if (meta.filename().string() == fileExtCheck)
// {
// RegisterAsset(meta, *it);
// AssetFiles.erase(it);
// break;
// }
// }
//}
//TODO: Handle if meta does not match all assets (if meta exist and asset doesnt, vice versa)
//for (auto const& file : AssetFiles)
//{
// if (IsRecognised(file.extension().string().c_str()))
// {
// SHAssetMetaHandler::WriteMetaData(RegisterAssetNew(file));
// }
// else
// {
// std::cout << "Unsupported File Format: " << file.filename() << "\n";
// }
//}
}
AssetID SHAssetManager::RetrieveAsset(char const* path) noexcept
{
std::filesystem::path p{ path };
if (IsRecognised(p.extension().string().c_str()))
{
SHAsset const& meta{ RegisterAssetNew(p) };
SHAssetMetaHandler::WriteMetaData(meta);
return meta.id;
SHLOG_ERROR("Unable to load asset into memory: {}\n", asset.path.string());
}
else
{
std::cout << "Unsupported File Format: " << p.filename() << "\n";
assetData.emplace(asset.id, data);
}
// Assert that file imported is not recognised
return 0;
return data;
}
/****************************************************************************
* \param Full path of file
* \brief Extracts file name from path. Formats file name into readable
* with spaces and capitalises first letter of every word
****************************************************************************/
AssetName SHAssetManager::GetNameFromPath(AssetPath filepath) noexcept
void SHAssetManager::BuildAssetCollection() noexcept
{
std::string name{ filepath.filename().string() };
name = name.substr(0, name.find_last_of('.'));
//if (name[0] <= 122 && name[0] >= 97)
//{
// name[0] -= 32;
//}
//for (size_t i{ 1 }; i < name.length(); ++i)
//{
// // Replace all underscores with spaces
// if (name[i] == '_')
// {
// name[i] = ' ';
// continue;
// }
// if (name[i + 1] <= 'Z' && name[i + 1] >= 'A'
// && name[i] <= 'z' && name[i] >= 'a')
// {
// name.insert(i + 1, 1, ' ');
// continue;
// }
// if (name[i - 1] == ' ' && name[i] <= 'z' && name[i] >= 'a')
// {
// name[i] -= 32;
// }
//}
return name;
for (auto const& dir : std::filesystem::recursive_directory_iterator{ASSET_ROOT})
{
if (dir.is_regular_file())
{
if (dir.path().extension().string() == META_EXTENSION.data())
{
assetCollection.push_back(SHAssetMetaHandler::RetrieveMetaData(dir.path()));
}
}
}
}
}

View File

@ -11,9 +11,10 @@
#pragma once
#include "tinyddsloader.h"
#include "SHAsset.h"
#include "Asset Types/SHAssetData.h"
#include "Assets/Libraries/Loaders/SHAssetLoader.h"
#include <memory>
#include "Asset Types/SHMeshAsset.h"
#include "Asset Types/SHTextureAsset.h"
#include "SH_API.h"
namespace SHADE
@ -28,10 +29,15 @@ namespace SHADE
static AssetPath GenerateLocalPath(AssetPath path) noexcept;
static AssetPath GenerateNewPath(AssetName name, AssetType type);
/****************************************************************************
* \brief Deallocate all memory used by resource data
****************************************************************************/
static void Unload() noexcept;
static void Unload(AssetID assetId) noexcept;
static void Exit() noexcept;
/****************************************************************************
* \brief Load all resources that are in the folder
@ -54,6 +60,7 @@ namespace SHADE
* \return resource id generated for new asset
****************************************************************************/
static AssetID CreateNewAsset(AssetType, AssetName) noexcept;
static AssetID CreateAsset(AssetName name, AssetType type) noexcept;
/****************************************************************************
* \brief Import new resource from outside editor window.
@ -70,66 +77,36 @@ namespace SHADE
static void RefreshAllAssets() noexcept;
// -------------------------------------------------------------------------/
//TODO: TEMPORARY FOR TESTING GLTF & DDS
static void LoadDataTemp(std::string path) noexcept;
static std::vector<SHMeshAsset> GetAllMeshes() noexcept;
static std::vector<SHTextureAsset> GetAllTextures() noexcept;
template<typename T>
static std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> GetData(AssetID id) noexcept;
static SHMeshAsset const* GetMesh(AssetID id) noexcept;
static SHTextureAsset const* GetTexture(AssetID id) noexcept;
static std::vector<SHAssetData const*> GetAllDataOfType(AssetType type) noexcept;
static std::vector<SHAsset> GetAllRecordOfType(AssetType type) noexcept;
static AssetID CompileAsset(AssetPath path) noexcept;
private:
/****************************************************************************
* \brief Load resource data into memory
****************************************************************************/
static void InitLoaders() noexcept;
static void LoadAllData() noexcept;
static void LoadData(AssetID id) noexcept;
/****************************************************************************
* \brief Retrieve all resource files and meta files from filesystem
****************************************************************************/
static void RetrieveAssets() noexcept;
static AssetID RetrieveAsset(char const* path) noexcept;
/****************************************************************************
* \param Full path of file
* \brief Extracts file name from path. Formats file name into readable
* with spaces and capitalises first letter of every word
****************************************************************************/
static AssetName GetNameFromPath(AssetPath) noexcept;
/****************************************************************************
* \param Path for meta data file
* \param Path for resource file
* \brief Links meta data to resource in registries. Meta data should
* already exist
****************************************************************************/
static void RegisterAsset(AssetPath const&, AssetPath const&) noexcept;
/****************************************************************************
* \param Path for resource file
* \brief Creates new meta data for new resource.
****************************************************************************/
static SHAsset RegisterAssetNew(AssetPath const&) noexcept;
static SHAssetData* LoadData(SHAsset const& asset) noexcept;
inline static void BuildAssetCollection() noexcept;
static bool IsRecognised(char const*) noexcept;
static SHAsset CreateAssetFromPath(AssetPath path) noexcept;
// Specialised load calls
static void LoadGLTF(SHAsset asset) noexcept;
static void LoadDDS(SHAsset asset) noexcept;
static void CompileAll() noexcept;
static FMOD::System* audioSystem;
static std::unordered_map<AssetID,SHSound>* audioSoundList;
static std::vector<SHAssetLoader*> loaders;
// For all resources
static std::vector<SHAsset> assetCollection;
static std::unordered_map<AssetID, SHAsset> assetRegistry;
static std::unordered_map<AssetID, SHMeshAsset> meshCollection;
static std::unordered_map<AssetID, SHTextureAsset> textureCollection;
static std::unordered_map<AssetID, SHAssetData * const> assetData;
};
}
#include "SHAssetManager.hpp"

View File

@ -0,0 +1,26 @@
#include "SHAssetManager.h"
namespace SHADE
{
template<typename T>
std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> SHAssetManager::GetData(AssetID id) noexcept
{
if (!assetData.contains(id))
{
for (auto const& asset : 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

@ -37,7 +37,7 @@ namespace SHADE
{
for (int i{0}; i < EXTENSIONS->size(); ++i)
{
if (ext == EXTENSIONS[i])
if (strcmp(ext.c_str(), EXTENSIONS[i].data()) == 0)
{
return static_cast<AssetType>(i);
}
@ -53,7 +53,7 @@ namespace SHADE
****************************************************************************/
AssetExtension SHAssetMetaHandler::GetExtensionFromType(AssetType type) noexcept
{
return EXTENSIONS[static_cast<size_t>(type)];
return AssetExtension(EXTENSIONS[static_cast<size_t>(type)]);
}
/****************************************************************************
@ -124,16 +124,6 @@ namespace SHADE
metaFile << "ID: " << meta.id << "\n";
metaFile << "Type: " << static_cast<AssetTypeMeta>(meta.type) << std::endl;
////TODO Add in information that is specific to types like mesh
//switch(meta.type)
//{
//case AssetType::MESH:
// break;
//default:
// break;
//}
metaFile.close();
}

View File

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

View File

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

View File

@ -0,0 +1,65 @@
#include "SHpch.h"
#include "SHCameraDirector.h"
#include "SHCameraComponent.h"
#include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/SHECSMacros.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Tools/SHLog.h"
namespace SHADE
{
SHCameraDirector::SHCameraDirector()
:mainCameraEID(MAX_EID), transitionCameraEID(MAX_EID)
{
}
SHMatrix SHCameraDirector::GetViewMatrix() const noexcept
{
return viewMatrix;
}
SHMatrix SHCameraDirector::GetProjMatrix() const noexcept
{
return projMatrix;
}
SHMatrix SHCameraDirector::GetVPMatrix() const noexcept
{
return projMatrix * viewMatrix;
}
void SHCameraDirector::UpdateMatrix() noexcept
{
if (mainCameraEID == MAX_EID)
{
auto& dense = SHComponentManager::GetDense<SHCameraComponent>();
if (dense.size() == 0)
{
return;
}
mainCameraEID = dense[0].GetEID();
}
SHCameraComponent* camComponent = SHComponentManager::GetComponent_s<SHCameraComponent>(mainCameraEID);
if (!camComponent)
{
SHLOG_WARNING("Camera Director warning: Entity does not have a camera");
}
else
{
viewMatrix = camComponent->GetViewMatrix();
projMatrix = camComponent->GetProjMatrix();
}
}
void SHCameraDirector::SetMainCamera(SHCameraComponent& camera) noexcept
{
if (SHEntityManager::IsValidEID(camera.GetEID()) == false)
{
SHLOG_WARNING("Camera Director Warning: Attempting to set an invalid entity as main camera.")
return;
}
mainCameraEID = camera.GetEID();
}
}

View File

@ -0,0 +1,43 @@
#pragma once
#include "SH_API.h"
#include "ECS_Base/Entity/SHEntity.h"
#include "Math/SHMatrix.h"
#include "Resource/SHHandle.h"
namespace SHADE
{
class SHCameraComponent;
class SH_API SHCameraDirector
{
public:
SHCameraDirector();
~SHCameraDirector() = default;
EntityID mainCameraEID;
EntityID transitionCameraEID;
SHMatrix GetViewMatrix() const noexcept;
SHMatrix GetProjMatrix() const noexcept;
SHMatrix GetVPMatrix() const noexcept;
void UpdateMatrix() noexcept;
void SetMainCamera(SHCameraComponent& cam) noexcept;
private:
protected:
SHMatrix viewMatrix;
SHMatrix projMatrix;
};
typedef Handle<SHCameraDirector> DirectorHandle;
}

View File

@ -3,12 +3,63 @@
#include "Math/SHMathHelpers.h"
#include "Input/SHInputManager.h"
#include "Math/Vector/SHVec2.h"
#include "ECS_Base/Managers/SHComponentManager.h"
#include "Math/Transform/SHTransformComponent.h"
namespace SHADE
{
void SHCameraSystem::UpdateEditorCamera(double dt) noexcept
{
auto& camera = editorCamera;
SHVec3 view, right, UP;
GetCameraAxis(camera, view, right, UP);
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::A))
{
camera.position -= right * dt * camera.movementSpeed;
camera.dirtyView = true;
}
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::D))
{
camera.position += right * dt * camera.movementSpeed;
camera.dirtyView = true;
}
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::W))
{
camera.position += view * dt * camera.movementSpeed;
camera.dirtyView = true;
}
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::S))
{
camera.position -= view * dt * camera.movementSpeed;
camera.dirtyView = true;
}
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::Q))
{
camera.position += UP * dt * camera.movementSpeed;
camera.dirtyView = true;
}
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::E))
{
camera.position -= UP * dt * camera.movementSpeed;
camera.dirtyView = true;
}
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::RMB))
{
double mouseX, mouseY;
SHInputManager::GetMouseVelocity(&mouseX, &mouseY);
//std::cout << camera.yaw << std::endl;
camera.pitch -= mouseY * dt * camera.turnSpeed.x;
camera.yaw -= mouseX * dt * camera.turnSpeed.y;
camera.dirtyView = true;
}
UpdateCameraComponent(editorCamera);
}
void SHCameraSystem::EditorCameraUpdate::Execute(double dt) noexcept
{
SHCameraSystem* system = static_cast<SHCameraSystem*>(GetSystem());
@ -18,6 +69,7 @@ namespace SHADE
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::A))
{
//std::cout << "Camera movement: "<<right.x<<", " << right.y << std::endl;
camera.position -= right * dt * camera.movementSpeed;
camera.dirtyView = true;
}
@ -58,6 +110,7 @@ namespace SHADE
camera.dirtyView = true;
}
//std::cout << "Camera position: " << camera.position.x << " " << camera.position.y << std::endl;
system->UpdateCameraComponent(system->editorCamera);
}
@ -83,10 +136,26 @@ namespace SHADE
void SHCameraSystem::UpdateCameraComponent(SHCameraComponent& camera) noexcept
{
if (SHComponentManager::HasComponent<SHTransformComponent>(camera.GetEID()) == true && &camera != &editorCamera)
{
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(camera.GetEID());
SHVec3 rotation = transform->GetWorldRotation();
camera.pitch = SHMath::RadiansToDegrees(rotation.x);
camera.yaw = SHMath::RadiansToDegrees(rotation.y);
camera.roll = SHMath::RadiansToDegrees(rotation.z);
camera.position = transform->GetWorldPosition();
camera.dirtyView = true;
}
if (camera.dirtyView)
{
SHVec3 view, right, UP;
ClampCameraRotation(camera);
GetCameraAxis(camera, view, right, UP);
camera.viewMatrix = SHMatrix::Identity;
@ -152,9 +221,8 @@ namespace SHADE
SHVec3 up = { 0.0f,1.0f,0.0f };
target = SHVec3::RotateX(target, SHMath::DegreesToRadians(camera.pitch));
target = SHVec3::RotateY(target, SHMath::DegreesToRadians(camera.yaw));
target =SHVec3::RotateX(target, SHMath::DegreesToRadians(camera.pitch));
std::cout << "Target vec: " << target.x<<", "<<target.y<<", "<<target.z << std::endl;
target += camera.position;
////SHVec3::RotateZ(target, SHMath::DegreesToRadians(camera.roll));
@ -169,5 +237,55 @@ namespace SHADE
upVec = SHVec3::Cross(forward, right);
}
void SHCameraSystem::CameraSystemUpdate::Execute(double dt) noexcept
{
SHCameraSystem* system = static_cast<SHCameraSystem*>(GetSystem());
auto& dense = SHComponentManager::GetDense<SHCameraComponent>();
for (auto& cam : dense)
{
system->UpdateCameraComponent(cam);
}
for (auto& handle : system->directorHandleList)
{
handle->UpdateMatrix();
}
}
DirectorHandle SHCameraSystem::CreateDirector() noexcept
{
auto handle = directorLibrary.Create();
directorHandleList.emplace_back(handle);
return handle;
}
DirectorHandle SHCameraSystem::GetDirector(size_t index) noexcept
{
if (index < directorHandleList.size())
{
return directorHandleList[index];
}
else
{
return CreateDirector();
}
}
void SHCameraSystem::ClampCameraRotation(SHCameraComponent& camera) noexcept
{
if (camera.pitch > 85)
camera.SetPitch(85);
if (camera.pitch < -85)
camera.SetPitch(-85);
if (camera.roll > 85)
camera.SetRoll(85);
if (camera.roll < -85)
camera.SetRoll(-85);
}
}

View File

@ -3,9 +3,10 @@
#include "ECS_Base/System/SHSystem.h"
#include "SHCameraComponent.h"
#include "ECS_Base/System/SHSystemRoutine.h"
#include "Resource/SHResourceLibrary.h"
#include "SHCameraDirector.h"
#include "SH_API.h"
namespace SHADE
{
class SH_API SHCameraSystem final : public SHSystem
@ -14,8 +15,9 @@ namespace SHADE
//A camera component that represents editor camera.
//This is not tied to any entity. Hence this EID should not be used.
SHCameraComponent editorCamera;
SHResourceLibrary<SHCameraDirector> directorLibrary;
std::vector<DirectorHandle> directorHandleList;
public:
SHCameraSystem(void) = default;
@ -34,13 +36,26 @@ namespace SHADE
};
friend class EditorCameraUpdate;
SHCameraComponent* GetEditorCamera (void) noexcept;
class SH_API CameraSystemUpdate final: public SHSystemRoutine
{
public:
CameraSystemUpdate() : SHSystemRoutine("Camera System Update", false) {};
virtual void Execute(double dt)noexcept override final;
};
friend class CameraSystemUpdate;
SHCameraComponent* GetEditorCamera (void) noexcept;
void GetCameraAxis(SHCameraComponent const& camera, SHVec3& forward, SHVec3& right, SHVec3& up) const noexcept;
DirectorHandle CreateDirector() noexcept;
DirectorHandle GetDirector(size_t index) noexcept;
void ClampCameraRotation(SHCameraComponent& camera) noexcept;
void UpdateEditorCamera(double dt) noexcept;
protected:
void UpdateCameraComponent(SHCameraComponent& camera) noexcept;
void GetCameraAxis(SHCameraComponent const& camera, SHVec3& forward, SHVec3& right, SHVec3& up) const noexcept;
};

View File

@ -24,6 +24,7 @@ namespace SHADE
class SHCommand : SHBaseCommand
{
public:
using SHCommandPtr = std::unique_ptr<T>;
typedef std::function<void(T const&)> SetterFunction;
SHCommand(T const& oldVal, T const& value, SetterFunction setFnc)

View File

@ -13,7 +13,7 @@ namespace SHADE
SHCommandManager::CommandStack SHCommandManager::undoStack{};
SHCommandManager::CommandStack SHCommandManager::redoStack{};
void SHCommandManager::PerformCommand(CommandPtr commandPtr, bool const& overrideValue)
void SHCommandManager::PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue)
{
redoStack = CommandStack();
commandPtr->Execute();
@ -27,9 +27,9 @@ namespace SHADE
}
}
void SHCommandManager::RegisterCommand(CommandPtr commandPtr)
void SHCommandManager::RegisterCommand(BaseCommandPtr commandPtr)
{
undoStack.push(commandPtr);
undoStack.push(commandPtr);
}
void SHCommandManager::UndoCommand()
@ -59,4 +59,14 @@ namespace SHADE
{
return redoStack.size();
}
void SHCommandManager::PopLatestCommandFromRedoStack()
{
redoStack.pop();
}
void SHCommandManager::PopLatestCommandFromUndoStack()
{
undoStack.pop();
}
}//namespace SHADE

View File

@ -19,16 +19,21 @@ namespace SHADE
//#==============================================================#
//|| Type Aliases ||
//#==============================================================#
using CommandPtr = std::shared_ptr<SHBaseCommand>;
using CommandStack = std::stack<CommandPtr>;
using BaseCommandPtr = std::shared_ptr<SHBaseCommand>;
template<typename T>
using SHCommandPtr = std::shared_ptr<SHCommand<T>>;
using CommandStack = std::stack<BaseCommandPtr>;
static void PerformCommand(CommandPtr commandPtr, bool const& overrideValue = false);
static void RegisterCommand(CommandPtr commandPtr);
static void PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue = false);
static void RegisterCommand(BaseCommandPtr commandPtr);
static void UndoCommand();
static void RedoCommand();
static std::size_t GetUndoStackSize();
static std::size_t GetRedoStackSize();
static void PopLatestCommandFromRedoStack();
static void PopLatestCommandFromUndoStack();
private:
static CommandStack undoStack;
static CommandStack redoStack;

View File

@ -0,0 +1,84 @@
#include "SHpch.h"
#include "SHAssetBrowser.h"
#include "Editor/IconsMaterialDesign.h"
#include "Editor/SHImGuiHelpers.hpp"
#include <imgui.h>
#include "Assets/SHAssetManager.h"
#include "Editor/DragDrop/SHDragDrop.hpp"
namespace SHADE
{
SHAssetBrowser::SHAssetBrowser()
:SHEditorWindow("\xee\x8b\x87 Asset Browser", ImGuiWindowFlags_MenuBar)
{
}
void SHAssetBrowser::Init()
{
SHEditorWindow::Init();
}
void SHAssetBrowser::Update()
{
SHEditorWindow::Update();
if(Begin())
{
DrawMenuBar();
auto const& assets = SHAssetManager::GetAllAssets();
if(ImGui::BeginTable("AssetBrowserTable", 3))
{
ImGui::TableNextColumn();
ImGui::TableHeader("Asset ID");
ImGui::TableNextColumn();
ImGui::TableHeader("Name");
ImGui::TableNextColumn();
ImGui::TableHeader("Type");
for(SHAsset const& asset : assets)
{
DrawAsset(asset);
}
ImGui::EndTable();
}
}
ImGui::End();
}
void SHAssetBrowser::DrawMenuBar()
{
if(ImGui::BeginMenuBar())
{
ImGui::EndMenuBar();
}
}
void SHAssetBrowser::DrawAsset(SHAsset const& asset)
{
ImGui::PushID(asset.id);
ImGui::BeginGroup();
ImGui::TableNextColumn();
ImGui::Selectable(std::format("{}", asset.id).data(), false, ImGuiSelectableFlags_SpanAllColumns);
if(SHDragDrop::BeginSource())
{
auto id = asset.id;
ImGui::Text("Moving Asset: %zu", id);
SHDragDrop::SetPayload<AssetID>(DRAG_RESOURCE, &id);
SHDragDrop::EndSource();
}
ImGui::TableNextColumn();
ImGui::Text("%s", asset.name.c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", "Type");
ImGui::EndGroup();
ImGui::PopID();
}
}

View File

@ -0,0 +1,24 @@
#pragma once
#include "Assets/SHAsset.h"
#include "Editor/EditorWindow/SHEditorWindow.h"
namespace SHADE
{
class SHAssetBrowser final : public SHEditorWindow
{
public:
SHAssetBrowser();
void Init();
void Update();
void Refresh();
private:
void DrawMenuBar();
void DrawAsset(SHAsset const& asset);
float idColumnWidth, nameColumnWidth, typeColumnWidth;
};
}

View File

@ -22,6 +22,7 @@
#include <imgui.h>
#include "Serialization/SHSerialization.h"
#include "Tools/SHClipboardUtilities.h"
namespace SHADE
@ -52,6 +53,7 @@ namespace SHADE
if(const auto root = sceneGraph.GetRoot())
{
auto const& children = root->GetChildren();
for (const auto child : children)
{
RecursivelyDrawEntityNode(child);
@ -79,6 +81,8 @@ namespace SHADE
void SHHierarchyPanel::SetScrollTo(EntityID eid)
{
if(eid == MAX_EID)
return;
scrollTo = eid;
}
@ -89,8 +93,7 @@ namespace SHADE
{
if (ImGui::BeginMenuBar())
{
ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x - 35.0f);
ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x * 0.75f);
if(ImGui::SmallButton(ICON_MD_DESELECT))
{
auto editor = SHSystemManager::GetSystem<SHEditor>();
@ -104,7 +107,7 @@ namespace SHADE
}
if (ImGui::SmallButton(ICON_MD_ADD_CIRCLE))
{
SHEntityManager::CreateEntity();
SHCommandManager::PerformCommand(std::make_shared<SHCreateEntityCommand>());
}
if (ImGui::IsItemHovered())
{
@ -144,23 +147,32 @@ namespace SHADE
auto* entity = SHEntityManager::GetEntityByID(currentNode->GetEntityID());
//Draw Node
bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast<void*>(entity), nodeFlags, "%u: %s", EntityHandleGenerator::GetIndex(eid), entity->name.c_str());
bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast<void*>(entity), nodeFlags, "%u: %s", SHEntityManager::GetEntityIndex(eid), entity->name.c_str());
const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
//Check For Begin Drag
if (SHDragDrop::BeginSource())
{
ImGui::Text("Moving EID: %zu", eid);
SHDragDrop::SetPayload<EntityID>(DRAG_EID, &eid);
std::string moveLabel = "Moving EID: ";
if(!isSelected)
editor->selectedEntities.push_back(eid);
for(int i = 0; i < static_cast<int>(editor->selectedEntities.size()); ++i)
{
moveLabel.append(std::to_string(editor->selectedEntities[i]));
if(i + 1 < static_cast<int>(editor->selectedEntities.size()))
{
moveLabel.append(", ");
}
}
ImGui::Text(moveLabel.c_str());
SHDragDrop::SetPayload<std::vector<EntityID>>(DRAG_EID, &editor->selectedEntities);
SHDragDrop::EndSource();
}
else if (SHDragDrop::BeginTarget()) //If Received DragDrop
{
if (const EntityID* eidPayload = SHDragDrop::AcceptPayload<EntityID>(DRAG_EID)) //If payload is valid
if (const std::vector<EntityID>* eidPayload = SHDragDrop::AcceptPayload<std::vector<EntityID>>(DRAG_EID)) //If payload is valid
{
EntityID const dropEID = *eidPayload;
if(!sceneGraph.GetChild(dropEID, eid))
sceneGraph.SetParent(dropEID, eid); //Set dropEID parent to eid (belonging to current Node)
ParentSelectedEntities(eid);
SHDragDrop::EndTarget();
}
}
@ -175,7 +187,15 @@ namespace SHADE
}
if(ImGui::Selectable("Copy"))
{
SHLOG_INFO(SHSerialization::SerializeEntitiesToString(editor->selectedEntities))
SHClipboardUtilities::WriteToClipboard(SHSerialization::SerializeEntitiesToString(editor->selectedEntities));
}
if(ImGui::Selectable("Paste"))
{
SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard()));
}
if(ImGui::Selectable("Paste as Child"))
{
SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard(), eid));
}
if(ImGui::Selectable(std::format("{} Delete", ICON_MD_DELETE).data()))
{
@ -184,7 +204,7 @@ namespace SHADE
if((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data()))
{
sceneGraph.SetParent(currentNode->GetEntityID(), nullptr);
ParentSelectedEntities(MAX_EID);
}
ImGui::EndPopup();
}
@ -196,7 +216,15 @@ namespace SHADE
{
if (!isSelected)
{
if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
if(ImGui::IsKeyDown(ImGuiKey_LeftShift))
{
if(editor->selectedEntities.size() >= 1)
{
SelectRangeOfEntities(editor->selectedEntities[0], eid);
}
else editor->selectedEntities.clear();
}
else if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
editor->selectedEntities.clear();
editor->selectedEntities.push_back(eid);
}//if not selected
@ -243,4 +271,90 @@ namespace SHADE
{
SHEntityManager::CreateEntity(MAX_EID, "DefaultChild", parentEID);
}
void SHHierarchyPanel::ParentSelectedEntities(EntityID parentEID) const noexcept
{
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
auto const editor = SHSystemManager::GetSystem<SHEditor>();
SHEntityParentCommand::EntityParentData entityParentData;
std::vector<EntityID> parentedEIDS;
for(auto const& eid : editor->selectedEntities)
{
if(sceneGraph.GetChild(eid, parentEID) == nullptr)
{
parentedEIDS.push_back(eid);
if(auto parent = sceneGraph.GetParent(eid))
entityParentData[eid].oldParentEID = parent->GetEntityID();
entityParentData[eid].newParentEID = parentEID;
}
}
SHCommandManager::PerformCommand(std::make_shared<SHEntityParentCommand>(parentedEIDS, entityParentData));
}
void SHHierarchyPanel::SelectRangeOfEntities(EntityID beginEID, EntityID endEID)
{
bool startSelecting = false; bool endSelecting = false;
auto const editor = SHSystemManager::GetSystem<SHEditor>();
editor->selectedEntities.clear();
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
sceneGraph.Traverse([&](SHSceneNode* nodePtr)
{
auto eid = nodePtr->GetEntityID();
if(!startSelecting)
{
if(eid == beginEID || eid == endEID)
{
startSelecting = true;
editor->selectedEntities.push_back(eid);
}
}
else
{
if(!endSelecting)
{
editor->selectedEntities.push_back(eid);
if(eid == endEID || eid == beginEID)
{
endSelecting = true;
}
}
}
});
}
void SHCreateEntityCommand::Execute()
{
EntityID newEID = SHEntityManager::CreateEntity(eid);
if(eid == MAX_EID)
eid = newEID;
}
void SHCreateEntityCommand::Undo()
{
SHEntityManager::DestroyEntity(eid);
}
void SHEntityParentCommand::Execute()
{
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
for(auto const& eid : entities)
{
if(entityParentData[eid].newParentEID == MAX_EID)
sceneGraph.SetParent(eid, nullptr);
else
sceneGraph.SetParent(eid, entityParentData[eid].newParentEID);
}
}
void SHEntityParentCommand::Undo()
{
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
for(auto const& eid : entities)
{
if(entityParentData[eid].oldParentEID == MAX_EID)
sceneGraph.SetParent(eid, nullptr);
else
sceneGraph.SetParent(eid, entityParentData[eid].oldParentEID);
}
}
}//namespace SHADE

View File

@ -10,7 +10,7 @@
#include "imgui_internal.h"
#include "ECS_Base/SHECSMacros.h"
#include "Editor/EditorWindow/SHEditorWindow.h"
#include "Editor/Command/SHCommand.hpp"
namespace SHADE
{
class SHSceneNode;
@ -28,8 +28,40 @@ namespace SHADE
void DrawMenuBar() const noexcept;
ImRect RecursivelyDrawEntityNode(SHSceneNode*);
void CreateChildEntity(EntityID parentEID) const noexcept;
void ParentSelectedEntities(EntityID parentEID) const noexcept;
void SelectRangeOfEntities(EntityID beginEID, EntityID EndEID);
std::string filter;
bool isAnyNodeSelected = false;
EntityID scrollTo = MAX_EID;
};//class SHHierarchyPanel
//Might move to a different file
class SHCreateEntityCommand final : public SHBaseCommand
{
public:
void Execute() override;
void Undo() override;
private:
EntityID eid = MAX_EID;
};
class SHEntityParentCommand final : public SHBaseCommand
{
public:
struct Data
{
EntityID oldParentEID = MAX_EID;
EntityID newParentEID = MAX_EID;
};
using EntityParentData = std::unordered_map<EntityID, Data>;
SHEntityParentCommand(std::vector<EntityID> entityIDs, EntityParentData inEntityParentData):entities(entityIDs),entityParentData(inEntityParentData){}
void Execute() override;
void Undo() override;
private:
std::vector<EntityID> entities;
std::unordered_map<EntityID, Data> entityParentData;
};
}//namespace SHADE

View File

@ -10,6 +10,7 @@
//|| SHADE Includes ||
//#==============================================================#
#include "Editor/IconsMaterialDesign.h"
#include "Editor/IconsFontAwesome6.h"
#include "ECS_Base/Components/SHComponent.h"
#include "Editor/SHEditorWidgets.hpp"
#include "Physics/Components/SHColliderComponent.h"
@ -38,6 +39,10 @@ namespace SHADE
{
SHComponentManager::RemoveComponent<T>(component->GetEID());
}
if (ImGui::Selectable(std::format("{} Reset {}", ICON_MD_RESTART_ALT, componentName.data()).data()))
{
*component = T();
}
ImGui::EndPopup();
}
}
@ -47,7 +52,7 @@ namespace SHADE
if (!component)
return;
const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; });
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data()))
{
@ -88,7 +93,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max);
if (metaMin && metaMax)
{
SHEditorWidgets::SliderInt(property.get_name().data(), metaMin.template get_value<int>(), metaMin.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); });
}
else
{
@ -114,7 +119,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value<uint16_t>(), metaMin.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); }, "%zu");
}
else
{
@ -127,7 +132,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value<uint32_t>(), metaMin.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); }, "%zu");
}
else
{
@ -140,7 +145,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value<uint64_t>(), metaMin.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); }, "%zu");
}
else
{
@ -151,13 +156,18 @@ namespace SHADE
{
auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max);
float min{}, max{};
if(metaMin.is_valid())
min = std::max(metaMin.template get_value<float>(), -FLT_MAX * 0.5f);
if(metaMax.is_valid())
max = std::min(metaMax.template get_value<float>(), FLT_MAX * 0.5f);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderFloat(property.get_name().data(), metaMin.template get_value<float>(), metaMin.template get_value<float>(), [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); });
}
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); });
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");
}
}
else if (type == rttr::type::get<double>())
@ -166,7 +176,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid())
{
SHEditorWidgets::SliderScalar<double>(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value<double>(), metaMin.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); });
}
else
{
@ -216,7 +226,7 @@ namespace SHADE
if (collider.GetType() == SHCollider::Type::BOX)
{
SHEditorWidgets::BeginPanel( std::format("{} Box Collider #{}", ICON_MD_VIEW_IN_AR, 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());
SHEditorWidgets::DragVec3("Half Extents", { "X", "Y", "Z" }, [box] {return box->GetHalfExtents(); }, [box](SHVec3 const& vec) {box->SetHalfExtents(vec);});
}

View File

@ -20,6 +20,7 @@
#include "AudioSystem/SHAudioSystem.h"
#include "Physics/Components/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h"
#include "Camera/SHCameraComponent.h"
namespace SHADE
{
@ -35,6 +36,23 @@ namespace SHADE
return selected;
}
template <typename ComponentType, typename EnforcedComponent, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true, std::enable_if_t<std::is_base_of_v<SHComponent, EnforcedComponent>, bool> = true>
bool DrawAddComponentWithEnforcedComponentButton(EntityID const& eid)
{
bool selected = false;
if (!SHComponentManager::HasComponent<ComponentType>(eid))
{
if(selected = ImGui::Selectable(std::format("Add {}", rttr::type::get<ComponentType>().get_name().data()).data()); selected)
{
if(SHComponentManager::GetComponent_s<EnforcedComponent>(eid) == nullptr)
SHComponentManager::AddComponent<EnforcedComponent>(eid);
SHComponentManager::AddComponent<ComponentType>(eid);
}
}
return selected;
}
SHEditorInspector::SHEditorInspector()
:SHEditorWindow("Inspector", ImGuiWindowFlags_MenuBar)
{
@ -55,7 +73,11 @@ namespace SHADE
{
EntityID const& eid = editor->selectedEntities[0];
SHEntity* entity = SHEntityManager::GetEntityByID(eid);
if(!entity)
{
ImGui::End();
return;
}
ImGui::TextColored(ImGuiColors::green, "EID: %zu", eid);
SHEditorWidgets::CheckBox("##IsActive", [entity]()->bool {return entity->GetActive(); }, [entity](bool const& active) {entity->SetActive(active); });
ImGui::SameLine();
@ -78,23 +100,27 @@ namespace SHADE
{
DrawComponent(rigidbodyComponent);
}
if (auto cameraComponent = SHComponentManager::GetComponent_s<SHCameraComponent>(eid))
{
DrawComponent(cameraComponent);
}
ImGui::Separator();
// Render Scripts
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->RenderScriptsInInspector(eid);
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->RenderScriptsInInspector(eid);
ImGui::Separator();
if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data()))
{
DrawAddComponentButton<SHTransformComponent>(eid);
DrawAddComponentButton<SHRenderable>(eid);
DrawAddComponentButton<SHColliderComponent>(eid);
if(DrawAddComponentButton<SHRigidBodyComponent>(eid))
{
if(SHComponentManager::GetComponent_s<SHTransformComponent>(eid) == nullptr)
{
SHComponentManager::AddComponent<SHTransformComponent>(eid);
}
}
DrawAddComponentButton<SHCameraComponent>(eid);
// Components that require Transforms
DrawAddComponentWithEnforcedComponentButton<SHRenderable, SHTransformComponent>(eid);
DrawAddComponentWithEnforcedComponentButton<SHRigidBodyComponent, SHTransformComponent>(eid);
DrawAddComponentWithEnforcedComponentButton<SHColliderComponent, SHTransformComponent>(eid);
ImGui::EndMenu();
}

View File

@ -3,6 +3,7 @@
#include <imgui.h>
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/Command/SHCommandManager.h"
#include "FRC/SHFramerateController.h"
namespace SHADE
@ -38,6 +39,11 @@ namespace SHADE
{
ImGui::PlotLines("DT", frames.data(), static_cast<int>(frames.size()), 0, nullptr, 0.0f, 16.0f);
}
if(ImGui::CollapsingHeader("Command Manager"))
{
ImGui::Text("Undo: %zu", SHCommandManager::GetUndoStackSize());
ImGui::Text("Redo: %zu", SHCommandManager::GetRedoStackSize());
}
ImGui::End();
}

View File

@ -43,9 +43,12 @@ namespace SHADE
bool result = ImGui::Begin(windowName.data(), &isOpen, windowFlags);
auto wndSize = ImGui::GetWindowSize();
if(windowSize.x != wndSize.x || windowSize.y != wndSize.y)
auto contentRegionAvail = ImGui::GetContentRegionAvail();
if( beginContentRegionAvailable.x != contentRegionAvail.x || beginContentRegionAvailable.y != contentRegionAvail.y || windowSize.x != wndSize.x || windowSize.y != wndSize.y)
{
windowSize = {wndSize.x, wndSize.y};
beginContentRegionAvailable = {contentRegionAvail.x, contentRegionAvail.y};
OnResize();
}
auto wndPos = ImGui::GetWindowPos();

View File

@ -26,6 +26,10 @@ namespace SHADE
bool isOpen;
bool isWindowHovered;
std::string_view windowName;
SHVec2 windowSize;
SHVec2 windowPos;
SHVec2 viewportMousePos;
SHVec2 beginContentRegionAvailable;
protected:
virtual bool Begin();
virtual void OnResize();
@ -33,8 +37,6 @@ namespace SHADE
ImGuiWindowFlags windowFlags = 0;
ImGuiIO& io;
SHVec2 windowSize;
SHVec2 windowPos;
SHVec2 viewportMousePos;
};//class SHEditorWindow
}//namespace SHADE

View File

@ -3,4 +3,5 @@
#include "HierarchyPanel/SHHierarchyPanel.h" //Hierarchy Panel
#include "Inspector/SHEditorInspector.h" //Inspector
#include "Profiling/SHEditorProfiler.h" //Profiler
#include "ViewportWindow/SHEditorViewport.h" //Editor Viewport
#include "ViewportWindow/SHEditorViewport.h" //Editor Viewport
#include "AssetBrowser/SHAssetBrowser.h" //Asset Browser

View File

@ -1,56 +1,62 @@
#include "SHpch.h"
#include "Editor/SHImGuiHelpers.hpp"
#include "SHEditorViewport.h"
#include "ImGuizmo.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/IconsMaterialDesign.h"
#include "Editor/SHEditor.hpp"
#include "Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h"
#include <Editor/IconsFontAwesome6.h>
constexpr std::string_view windowName = "\xef\x80\x95 Viewport";
namespace SHADE
{
SHEditorViewport::SHEditorViewport()
:SHEditorWindow("Viewport", ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoScrollbar)
:SHEditorWindow("\xee\x90\x8b Viewport", ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoScrollbar)
{
}
void SHEditorViewport::Init()
{
SHEditorWindow::Init();
transformGizmo.Init();
}
void SHEditorViewport::Update()
{
SHEditorWindow::Update();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f,0.0f));
if(Begin())
{
ImGuizmo::SetDrawlist();
DrawMenuBar();
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
auto const& descriptorSet = gfxSystem->GetPostOffscreenRenderSystem()->GetDescriptorSetGroup()->GetVkHandle()[0];
auto mousePos = ImGui::GetMousePos();
auto cursorPos = ImGui::GetCursorScreenPos();
viewportMousePos = {mousePos.x - cursorPos.x, mousePos.y - cursorPos.y};
beginCursorPos = ImGui::GetCursorScreenPos();
viewportMousePos = {mousePos.x - beginCursorPos.x, mousePos.y - beginCursorPos.y};
gfxSystem->GetMousePickSystem ()->SetViewportMousePos (viewportMousePos);
//if (ImGui::IsMouseReleased(ImGuiMouseButton_Left))
//{
// auto eid = gfxSystem->GetMousePickSystem ()->GetPickedEntity();
// if(eid != MAX_EID)
// {
// auto editor = SHSystemManager::GetSystem<SHEditor>();
// editor->selectedEntities.clear();
// editor->selectedEntities.push_back(eid);
// if (const auto hierarchyPanel = SHEditorWindowManager::GetEditorWindow<SHHierarchyPanel>())
// {
// hierarchyPanel->SetScrollTo(eid);
// }
// }
//}
ImGui::Image((ImTextureID)descriptorSet, ImGui::GetWindowSize());
ImGui::Image((ImTextureID)descriptorSet, {beginContentRegionAvailable.x, beginContentRegionAvailable.y});
if(ImGui::IsWindowHovered() && ImGui::IsMouseDown(ImGuiMouseButton_Right))
{
ImGui::SetMouseCursor(ImGuiMouseCursor_None);
ImGui::SetCursorScreenPos(ImGui::GetMousePos());
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiColors::green);
ImGui::Text(ICON_FA_EYE);
ImGui::PopStyleColor();
}
}
ImGuizmo::SetRect(beginCursorPos.x , beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y);
transformGizmo.Draw();
ImGui::End();
ImGui::PopStyleVar();
}
void SHEditorViewport::Exit()
@ -66,7 +72,11 @@ namespace SHADE
//auto pos = ImGui::GetCursorPos();
//windowCursorPos = {}
gfxSystem->PrepareResize(static_cast<uint32_t>(windowSize.x), static_cast<uint32_t>(windowSize.y));
if(beginContentRegionAvailable.x == 0 || beginContentRegionAvailable.y == 0)
{
beginContentRegionAvailable = windowSize;
}
gfxSystem->PrepareResize(static_cast<uint32_t>(beginContentRegionAvailable.x), static_cast<uint32_t>(beginContentRegionAvailable.y));
}
void SHEditorViewport::OnPosChange()
@ -74,10 +84,46 @@ namespace SHADE
SHEditorWindow::OnPosChange();
}
void SHEditorViewport::DrawMenuBar() const noexcept
void SHEditorViewport::DrawMenuBar() noexcept
{
if(ImGui::BeginMenuBar())
{
bool const isTranslate = transformGizmo.operation == SHTransformGizmo::Operation::TRANSLATE;
ImGui::BeginDisabled(isTranslate);
if(isTranslate)
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]);
if(ImGui::Button(ICON_MD_OPEN_WITH))
{
transformGizmo.operation = SHTransformGizmo::Operation::TRANSLATE;
}
ImGui::EndDisabled();
if(isTranslate)
ImGui::PopStyleColor();
bool const isRotate = transformGizmo.operation == SHTransformGizmo::Operation::ROTATE;
ImGui::BeginDisabled(isRotate);
if(isRotate)
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]);
if(ImGui::Button(ICON_MD_AUTORENEW))
{
transformGizmo.operation = SHTransformGizmo::Operation::ROTATE;
}
ImGui::EndDisabled();
if(isRotate)
ImGui::PopStyleColor();
bool const isScale = transformGizmo.operation == SHTransformGizmo::Operation::SCALE;
ImGui::BeginDisabled(isScale);
if(isScale)
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]);
if(ImGui::Button(ICON_MD_EXPAND))
{
transformGizmo.operation = SHTransformGizmo::Operation::SCALE;
}
ImGui::EndDisabled();
if(isScale)
ImGui::PopStyleColor();
ImGui::EndMenuBar();
}
}

View File

@ -10,6 +10,7 @@
#include "imgui_internal.h"
#include "ECS_Base/SHECSMacros.h"
#include "Editor/EditorWindow/SHEditorWindow.h"
#include "Editor/Gizmos/SHTransformGizmo.h"
namespace SHADE
{
@ -20,10 +21,12 @@ namespace SHADE
void Init() override;
void Update() override;
void Exit() override;
SHTransformGizmo transformGizmo;
protected:
void OnResize() override;
void OnPosChange() override;
private:
void DrawMenuBar() const noexcept;
void DrawMenuBar() noexcept;
SHVec2 beginCursorPos;
};//class SHEditorViewport
}//namespace SHADE

View File

@ -0,0 +1,100 @@
#include "SHpch.h"
#include "SHTransformGizmo.h"
#include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.hpp"
#include "Editor/SHImGuiHelpers.hpp"
#include <imgui.h>
#include <ImGuizmo.h>
#include "Camera/SHCameraSystem.h"
#include "Editor/Command/SHCommandManager.h"
#include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h"
namespace SHADE
{
void SHTransformGizmo::Init()
{
auto& style = ImGuizmo::GetStyle();
style.RotationLineThickness = 2.5f;
}
void SHTransformGizmo::Draw()
{
bool justChangedTfm = false;
if (!editorCamera)
{
auto const cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
editorCamera = cameraSystem->GetEditorCamera();
}
auto viewportWindow = SHEditorWindowManager::GetEditorWindow<SHEditorViewport>();
ImGuizmo::SetOrthographic(false);
SHMatrix view = SHMatrix::Transpose(editorCamera->GetViewMatrix());
SHMatrix proj = SHMatrix::Transpose(editorCamera->GetProjMatrix());
//Invert projection y-axis
proj(1, 1) *= -1;
static SHMatrix gridMat = SHMatrix::Translate(0, -0.5f, 0.f) * SHMatrix::Identity;
if (selectedEntityTransformComponent == nullptr)
{
SHEditor* editor = SHSystemManager::GetSystem<SHEditor>();
if (editor->selectedEntities.empty())
return;
EntityID eid = editor->selectedEntities.back();
selectedEntityTransformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
justChangedTfm = true;
}
else
{
SHEditor* editor = SHSystemManager::GetSystem<SHEditor>();
if (editor->selectedEntities.empty())
return;
EntityID eid = editor->selectedEntities.back();
auto tfmComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
if (selectedEntityTransformComponent != tfmComponent)
{
selectedEntityTransformComponent = tfmComponent;
justChangedTfm = true;
}
}
if (selectedEntityTransformComponent == nullptr)
return;
SHMatrix mat = selectedEntityTransformComponent->GetTRS();
useSnap = ImGui::IsKeyDown(ImGuiKey_LeftCtrl);
if(useSnap)
{
switch (operation)
{
case Operation::TRANSLATE: snap = &translationSnap.x; break;
case Operation::ROTATE: snap = &rotationSnap; break;
case Operation::SCALE: snap = &scaleSnap; break;
default: snap = &translationSnap.x;
}
}
ImGuizmo::Manipulate(&view._11, &proj._11, static_cast<ImGuizmo::OPERATION>(operation), ImGuizmo::MODE::WORLD, &mat._11, nullptr, useSnap ? snap : nullptr);
static bool startRecording = false;
if (!justChangedTfm && ImGuizmo::IsUsing())
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = (selectedEntityTransformComponent)](SHMatrix const& mtx)
{
if (!tfm)
return;
SHVec3 translate{}, rotate{}, scale{};
mtx.Decompose(translate, rotate, scale);
tfm->SetWorldPosition(translate);
tfm->SetWorldRotation(rotate);
tfm->SetWorldScale(scale);
})), startRecording);
if(!startRecording)
startRecording = true;
}
isManipulating = ImGuizmo::IsUsing() || startRecording;
if(startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
startRecording = false;
}
}

View File

@ -0,0 +1,54 @@
#pragma once
#include "Camera/SHCameraComponent.h"
#include "Math/Transform/SHTransformComponent.h"
namespace SHADE
{
class SHTransformGizmo
{
public:
enum class Mode
{
WORLD,
LOCAL
};
enum class Operation
{
TRANSLATE_X = (1u << 0),
TRANSLATE_Y = (1u << 1),
TRANSLATE_Z = (1u << 2),
ROTATE_X = (1u << 3),
ROTATE_Y = (1u << 4),
ROTATE_Z = (1u << 5),
ROTATE_SCREEN = (1u << 6),
SCALE_X = (1u << 7),
SCALE_Y = (1u << 8),
SCALE_Z = (1u << 9),
BOUNDS = (1u << 10),
SCALE_XU = (1u << 11),
SCALE_YU = (1u << 12),
SCALE_ZU = (1u << 13),
TRANSLATE = TRANSLATE_X | TRANSLATE_Y | TRANSLATE_Z,
ROTATE = ROTATE_X | ROTATE_Y | ROTATE_Z | ROTATE_SCREEN,
SCALE = SCALE_X | SCALE_Y | SCALE_Z,
SCALEU = SCALE_XU | SCALE_YU | SCALE_ZU, // universal
UNIVERSAL = TRANSLATE | ROTATE | SCALEU
};
void Init();
void Draw();
bool isManipulating = false;
bool useSnap = false;
Mode mode = Mode::WORLD;
Operation operation = Operation::TRANSLATE;
private:
float scaleSnap = 0.25f;
float rotationSnap = 1.0f;
SHVec3 translationSnap = SHVec3(0.25f, 0.25f, 0.25f);
float* snap = nullptr;
SHTransformComponent* selectedEntityTransformComponent{nullptr};
SHCameraComponent* editorCamera{nullptr};
};
}

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@
#include "SHpch.h"
#include "IconsMaterialDesign.h"
#include "IconsFontAwesome6.h"
#include "DragDrop/SHDragDrop.hpp"
//#==============================================================#
@ -36,6 +37,7 @@
#include <imgui.h>
#include <SDL.h>
#include <rttr/registration>
#include <ImGuizmo.h>
//#==============================================================#
//|| ImGui Backend Includes ||
@ -87,10 +89,11 @@ namespace SHADE
//Add editor windows
SHEditorWindowManager::CreateEditorWindow<SHEditorMenuBar>();
SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>();
SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>();
SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>();
SHEditorWindowManager::CreateEditorWindow<SHEditorProfiler>();
SHEditorWindowManager::CreateEditorWindow<SHAssetBrowser>();
SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>();
io = &ImGui::GetIO();
@ -98,7 +101,7 @@ namespace SHADE
io->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; //Enable for Multi-Viewports
io->ConfigFlags |= ImGuiConfigFlags_DockingEnable; //Enable docking
io->IniFilename = "../../Assets/Editor/Layouts/UserLayout.ini";
io->ConfigWindowsMoveFromTitleBarOnly = true;
InitLayout();
InitFonts();
@ -127,9 +130,13 @@ namespace SHADE
for (const auto& window : SHEditorWindowManager::editorWindows | std::views::values)
{
if(window->isOpen)
{
window->Update();
}
}
//PollPicking();
if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z))
{
SHCommandManager::RedoCommand();
@ -165,10 +172,11 @@ namespace SHADE
{
ImFont* mainFont = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/Segoe UI.ttf", 20.f);//TODO: Change to config based assets path
constexpr ImWchar icon_ranges[] = { ICON_MIN_MD, ICON_MAX_16_MD, 0 };
ImFontConfig icons_config{}; icons_config.MergeMode = true; icons_config.GlyphOffset.y = 5.f;
ImFont* UIFont = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/MaterialIcons-Regular.ttf", 20.f, &icons_config, icon_ranges); //TODO: Change to config based assets path
constexpr ImWchar icon_ranges_fa[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
ImFont* UIFontFA = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/fa-solid-900.ttf", 20.f, &icons_config, icon_ranges_fa); //TODO: Change to config based assets path
constexpr ImWchar icon_ranges_md[] = { ICON_MIN_MD, ICON_MAX_MD, 0 };
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();
}
@ -338,7 +346,7 @@ namespace SHADE
if (auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>())
{
auto viewportWindow = SHEditorWindowManager::GetEditorWindow<SHEditorViewport>();
if (viewportWindow->isWindowHovered && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
if (viewportWindow->isWindowHovered && !viewportWindow->transformGizmo.isManipulating && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
EntityID pickedEID = gfxSystem->GetMousePickSystem()->GetPickedEntity();
if(pickedEID == MAX_EID)
@ -366,6 +374,7 @@ namespace SHADE
ImGui_ImplVulkan_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
ImGuizmo::BeginFrame();
}

View File

@ -13,9 +13,11 @@
#include "ECS_Base/SHECSMacros.h"
#include "ECS_Base/System/SHSystem.h"
#include "ECS_Base/System/SHSystemRoutine.h"
#include "Resource/Handle.h"
#include "Resource/SHHandle.h"
#include "EditorWindow/SHEditorWindow.h"
#include "Tools/SHLogger.h"
#include "Gizmos/SHTransformGizmo.h"
//#==============================================================#
//|| Library Includes ||
@ -200,5 +202,7 @@ namespace SHADE
SDL_Window* sdlWindow {nullptr};
ImGuiIO* io{nullptr};
//SHTransformGizmo transformGizmo;
};//class SHEditor
}//namespace SHADE

View File

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

View File

@ -40,7 +40,6 @@ namespace SHADE
{
ImGui::BeginGroup();
auto cursorPos = ImGui::GetCursorScreenPos();
auto itemSpacing = ImGui::GetStyle().ItemSpacing;
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
@ -158,7 +157,7 @@ namespace SHADE
}
template <typename T, std::size_t N>
static bool DragN(const std::string& fieldLabel, std::vector<std::string>const& componentLabels,
static bool DragN(const std::string& label, std::vector<std::string>const& componentLabels,
std::vector<T*> values, float speed = 0.1f, const char* displayFormat = "", T valueMin = T(), T valueMax = T(),
ImGuiSliderFlags flags = 0, bool* isHovered = nullptr)
{
@ -169,13 +168,13 @@ namespace SHADE
const ImGuiContext& g = *GImGui;
bool valueChanged = false;
ImGui::BeginGroup();
ImGui::PushID(fieldLabel.c_str());
ImGui::PushID(label.c_str());
PushMultiItemsWidthsAndLabels(componentLabels, 0.0f);
ImGui::BeginColumns("DragVecCol", 2, ImGuiOldColumnFlags_NoBorder | ImGuiOldColumnFlags_NoResize);
ImGui::SetColumnWidth(-1, 80.0f);
ImGui::Text(fieldLabel.c_str());
ImGui::Text(label.c_str());
if (isHovered)
*isHovered = ImGui::IsItemHovered();
*isHovered = ImGui::IsItemHovered();
ImGui::NextColumn();
for (std::size_t i = 0; i < N; ++i)
{
@ -203,75 +202,91 @@ namespace SHADE
return valueChanged;
}
static bool DragVec2(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec2(void)> get,
std::function<void(SHVec2)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
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,
ImGuiSliderFlags flags = 0)
{
SHVec2 values = get();
bool changed = false;
if (DragN<float, 2>(fieldLabel, componentLabels, { &values.x, &values.y }, speed, displayFormat, valueMin, valueMax, flags))
{
changed = true;
}
bool const changed = DragN<float, 2>(label, componentLabels, { &values.x, &values.y }, speed, displayFormat, valueMin, valueMax, flags);
static bool startRecording = false;
if (changed)
{
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false);
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), startRecording);
if (!startRecording)
startRecording = true;
}
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
startRecording = false;
if(!tooltip.empty())
{
if(ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return changed;
}
static bool DragVec3(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec3(void)> get,
std::function<void(SHVec3)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
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,
ImGuiSliderFlags flags = 0)
{
SHVec3 values = get();
bool changed = false;
if (DragN<float, 3>(fieldLabel, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags))
{
changed = true;
}
bool const changed = DragN<float, 3>(label, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags);
static bool startRecording = false;
if (changed)
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false);
SHVec3 old = get();
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(old, values, set)), startRecording);
if (!startRecording)
startRecording = true;
}
if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
startRecording = false;
}
if(!tooltip.empty())
{
if(ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return changed;
}
static bool DragVec4(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec4(void)> get,
std::function<void(SHVec4)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
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,
ImGuiSliderFlags flags = 0)
{
SHVec4 values = get();
bool changed = false;
if (DragN<float, 4>(fieldLabel, componentLabels, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags))
{
changed = true;
}
bool const changed = DragN<float, 4>(label, componentLabels, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags);
static bool startRecording = false;
if (changed)
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), false);
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;
}
if(!tooltip.empty())
{
if(ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return changed;
}
@ -279,173 +294,325 @@ namespace SHADE
//|| Widget Extensions ||
//#==============================================================#
static bool CheckBox(std::string const& label, std::function<bool(void)> get, std::function<void(bool const&)> set)
static void TextLabel(std::string_view const& text, bool sameLine = true)
{
const ImVec2 textSize = ImGui::CalcTextSize(text.data(), NULL, true);
if(textSize.x > 0.0f)
{
ImGui::Text(text.data());
ImGui::SameLine();
}
}
static bool CheckBox(std::string_view const& label, std::function<bool(void)> get, std::function<void(bool const&)> set, std::string_view const& tooltip = {})
{
bool value = get();
if (ImGui::Checkbox(label.c_str(), &value))
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
if (ImGui::Checkbox("##", &value))
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<bool>>(get(), value, set)), false);
return true;
}
ImGui::PopID();
ImGui::EndGroup();
if(!tooltip.empty())
{
if(ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return false;
}
template<typename T>
static bool RadioButton(std::vector<std::string> const& listLabels, std::vector<T> const& listTypes, std::function<T(void)> get, std::function<void(T const&)> set)
static bool RadioButton(std::vector<std::string> const& label, std::vector<T> const& listTypes, std::function<T(void)> get, std::function<void(T const&)> set ,std::string_view const& tooltip = {})
{
T type = get();
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
for (size_t i = 0; i < listTypes.size(); i++)
{
if (ImGui::RadioButton(listLabels[i].c_str(), type == listTypes[i]))
if (ImGui::RadioButton(label[i].c_str(), type == listTypes[i]))
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), listTypes[i], set)), false);
}
ImGui::SameLine();
}
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return true;
}
static bool InputText(const std::string& label, const std::function<std::string(void)> get,
const std::function<void(std::string)> set, ImGuiInputTextFlags flag = 0,
ImGuiInputTextCallback callback = (ImGuiInputTextCallback)0, void* userData = (void*)0)
const std::function<void(std::string)> set, std::string_view const& tooltip = {},
ImGuiInputTextFlags flag = 0, ImGuiInputTextCallback callback = (ImGuiInputTextCallback)0, void* userData = (void*)0)
{
std::string text = get();
if (ImGui::InputText(label.c_str(), &text, flag, callback, userData))
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
if (ImGui::InputText("##", &text, flag, callback, userData))
{
if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<std::string>>(get(), text, set)), false);
return true;
}
return false;
}
template <typename T>
static bool DragScalar(const std::string& fieldLabel, ImGuiDataType data_type, std::function<T(void)> get, std::function<void(T const&)> set,
float speed = 1.0f, T p_min = T(), T p_max = T(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{
T value = get();
std::cout << value << " \n";
//bool hasChange = ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags);
if (ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags))
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
return true;
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return false;
}
static bool DragFloat(const std::string& fieldLabel, std::function<float(void)> get, std::function<void(float const&)> set,
template <typename T>
static bool DragScalar(const std::string& label, ImGuiDataType data_type, std::function<T(void)> get, std::function<void(T const&)> set,
float speed = 1.0f, T p_min = T(), T p_max = T(), const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, ImGuiSliderFlags flags = 0)
{
T value = get();
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
const bool hasChange = ImGui::DragScalar("##", data_type, &value, speed, &p_min, &p_max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, 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 hasChange;
}
static bool DragFloat(const std::string_view& label, std::function<float(void)> get, std::function<void(float const&)> set, std::string_view const& tooltip = {},
float speed = 0.1f, float p_min = float(), float p_max = float(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{
float value = get();
//bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags);
if (ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags))
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
const bool hasChange = ImGui::DragFloat("##", &value, speed, p_min, p_max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
return true;
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), startRecording);
if (!startRecording)
startRecording = true;
}
return false;
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 hasChange;
}
static bool DragInt(const std::string& fieldLabel, std::function<int(void)> get, std::function<void(int const&)> set,
static bool DragInt(const std::string& label, std::function<int(void)> get, std::function<void(int const&)> set, std::string_view const& tooltip = {},
float speed = 1.0f, int p_min = int(), int p_max = int(), const char* displayFormat = "%d", ImGuiSliderFlags flags = 0)
{
int value = get();
//bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags);
if (ImGui::DragInt(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags))
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
const bool hasChange = ImGui::DragInt("##", &value, speed, p_min, p_max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), true);
else if (ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
return true;
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), startRecording);
if (!startRecording)
startRecording = true;
}
return false;
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 hasChange;
}
template <typename T>
static bool SliderScalar(const std::string& fieldLabel, ImGuiDataType data_type, T min, T max, std::function<T(void)> get, std::function<void(T const&)> set,
static bool SliderScalar(const std::string& label, ImGuiDataType data_type, T min, T max, std::function<T(void)> get, std::function<void(T const&)> set, std::string_view const& tooltip = {},
const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{
T value = get();
if (ImGui::SliderScalar(fieldLabel.c_str(), data_type, &value, &min, &max, displayFormat, flags))
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
bool const hasChange = ImGui::SliderScalar("##", data_type, &value, &min, &max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), true);
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), startRecording);
if (!startRecording)
startRecording = true;
return true;
}
return false;
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 hasChange;
}
static bool SliderFloat(const std::string& fieldLabel, float min, float max, std::function<float(void)> get, std::function<void(float const&)> set,
static bool SliderFloat(const std::string& label, float const& min, float const& max, std::function<float(void)> get, std::function<void(float const&)> set, std::string_view const& tooltip = {},
const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
{
float value = get();
if (ImGui::SliderFloat(fieldLabel.c_str(), &value, min, max, displayFormat, flags))
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
bool const hasChange = ImGui::SliderFloat("##", &value, min, max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), true);
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), startRecording);
if (!startRecording)
startRecording = true;
return true;
}
return false;
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 hasChange;
}
static bool SliderInt(const std::string& fieldLabel, int min, int max, std::function<int(void)> get, std::function<void(int const&)> set,
static bool SliderInt(const std::string& label, int min, int max, std::function<int(void)> get, std::function<void(int const&)> set, std::string_view const& tooltip = {},
const char* displayFormat = "%d", ImGuiSliderFlags flags = 0)
{
int value = get();
if (ImGui::SliderInt(fieldLabel.c_str(), &value, min, max, displayFormat, flags))
ImGui::BeginGroup();
ImGui::PushID(label.data());
TextLabel(label);
bool const hasChange = ImGui::SliderInt("##", &value, min, max, displayFormat, flags);
static bool startRecording = false;
if (hasChange)
{
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), true);
return true;
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), startRecording);
if (!startRecording)
startRecording = true;
}
return false;
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 hasChange;
}
static bool ComboBox(const std::string& fieldLabel, std::vector<const char*> list, std::function<int(void)> get, std::function<void(int const&)> set)
static bool ComboBox(const std::string& label, std::vector<const char*> list, std::function<int(void)> get, std::function<void(int const&)> set, std::string_view const& tooltip = {})
{
bool edited = false;
int selected = get();
ImGui::PushID(fieldLabel.c_str());
ImGui::Text(fieldLabel.c_str()); ImGui::SameLine();
ImGui::BeginGroup();
ImGui::PushID(label.c_str());
TextLabel(label);
ImGui::SameLine();
if (edited = ImGui::Combo("##Combo", &selected, list.data(), static_cast<int>(list.size())))
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), selected, set)), false);
}
ImGui::PopID();
ImGui::EndGroup();
if (!tooltip.empty())
{
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text(tooltip.data());
ImGui::EndTooltip();
}
}
return edited;
}
};

View File

@ -15,7 +15,7 @@
//#==============================================================#
#ifndef SH_IM_MATH
#define IM_VEC2_CLASS_EXTRA \
ImVec2(const SHADE::SHVec2& vec) {x = vec.x; y = vec.y;} \
ImVec2(const SHADE::SHVec2& vec) {x = vec.x; y = vec.y;} \
operator SHADE::SHVec2() const {return SHADE::SHVec2(x,y);}
#define IM_VEC3_CLASS_EXTRA \
ImVec3(const SHADE::SHVec3& vec) {x = vec.x; y = vec.y; z = vec.z;} \
@ -43,6 +43,10 @@ namespace SHADE
constexpr ImVec4 blue = {0.0f, 0.0f, 1.0f, 1.f};
constexpr ImVec4 white = {1.0f, 1.0f, 1.0f, 1.f};
constexpr int colors_red = 0;
constexpr int colors_green = 1;
constexpr int colors_blue = 2;
constexpr int colors_white = 3;
constexpr ImU32 colors[] = {
0xBB0000FF, // red
0xBB00FF00, // green

View File

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

View File

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

View File

@ -3,7 +3,7 @@
#include "Graphics/SHVulkanIncludes.h"
#include "vk_mem_alloc.h"
#include "Resource/Handle.h"
#include "Resource/SHHandle.h"
namespace SHADE
{

View File

@ -10,6 +10,7 @@
#include "Graphics/Buffers/SHVkBuffer.h"
#include "Graphics/Images/SHVkImage.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/SHVkUtil.h"
namespace SHADE
@ -299,7 +300,7 @@ namespace SHADE
SHLOG_ERROR("Command buffer must have started recording before a pipeline can be bound. ");
return;
}
boundPipelineLayoutHdl = pipelineHdl->GetPipelineLayout();
bindPointData[static_cast<uint32_t>(pipelineHdl->GetPipelineType())].boundPipelineLayoutHdl = pipelineHdl->GetPipelineLayout();
vkCommandBuffer.bindPipeline(pipelineHdl->GetPipelineBindPoint(), pipelineHdl->GetVkPipeline());
}
@ -358,9 +359,10 @@ namespace SHADE
}
}
void SHVkCommandBuffer::BindDescriptorSet(Handle<SHVkDescriptorSetGroup> descSetGroup, vk::PipelineBindPoint bindPoint, uint32_t firstSet, std::span<uint32_t> dynamicOffsets)
void SHVkCommandBuffer::BindDescriptorSet(Handle<SHVkDescriptorSetGroup> descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span<uint32_t> dynamicOffsets)
{
vkCommandBuffer.bindDescriptorSets(bindPoint, boundPipelineLayoutHdl->GetVkPipelineLayout(), firstSet, descSetGroup->GetVkHandle(), dynamicOffsets);
uint32_t bindPointIndex = static_cast<uint32_t>(bindPoint);
vkCommandBuffer.bindDescriptorSets(SHVkUtil::GetPipelineBindPointFromType(bindPoint), bindPointData[bindPointIndex].boundPipelineLayoutHdl->GetVkPipelineLayout(), firstSet, descSetGroup->GetVkHandle(), dynamicOffsets);
}
/***************************************************************************/
@ -452,6 +454,11 @@ namespace SHADE
vkCommandBuffer.drawIndexedIndirect(indirectDrawData->GetVkBuffer(), 0, drawCount, sizeof(vk::DrawIndexedIndirectCommand));
}
void SHVkCommandBuffer::ComputeDispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept
{
vkCommandBuffer.dispatch (groupCountX, groupCountY, groupCountZ);
}
void SHVkCommandBuffer::CopyBufferToImage(const vk::Buffer& src, const vk::Image& dst, const std::vector<vk::BufferImageCopy>& copyInfo)
{
vkCommandBuffer.copyBufferToImage
@ -500,9 +507,9 @@ namespace SHADE
// //vkCommandBuffer.pipelineBarrier()
//}
void SHVkCommandBuffer::ForceSetPipelineLayout(Handle<SHVkPipelineLayout> pipelineLayout) noexcept
void SHVkCommandBuffer::ForceSetPipelineLayout(Handle<SHVkPipelineLayout> pipelineLayout, SH_PIPELINE_TYPE pipelineType) noexcept
{
boundPipelineLayoutHdl = pipelineLayout;
bindPointData[static_cast<uint32_t>(pipelineType)].boundPipelineLayoutHdl = pipelineLayout;
}
/***************************************************************************/
@ -513,12 +520,13 @@ namespace SHADE
*/
/***************************************************************************/
void SHVkCommandBuffer::SubmitPushConstants(void) const noexcept
void SHVkCommandBuffer::SubmitPushConstants(SH_PIPELINE_TYPE bindPoint) const noexcept
{
vkCommandBuffer.pushConstants(boundPipelineLayoutHdl->GetVkPipelineLayout(),
boundPipelineLayoutHdl->GetPushConstantInterface().GetShaderStageFlags(),
auto layoutHdl = bindPointData[static_cast<uint32_t>(bindPoint)].boundPipelineLayoutHdl;
vkCommandBuffer.pushConstants(layoutHdl->GetVkPipelineLayout(),
layoutHdl->GetPushConstantInterface().GetShaderStageFlags(),
0,
boundPipelineLayoutHdl->GetPushConstantInterface().GetSize(), pushConstantData);
layoutHdl->GetPushConstantInterface().GetSize(), pushConstantData);
}
/***************************************************************************/
@ -695,7 +703,7 @@ namespace SHADE
, usageFlags{ rhs.usageFlags }
, commandBufferCount{ rhs.commandBufferCount }
, parentPool{ rhs.parentPool }
, boundPipelineLayoutHdl{ rhs.boundPipelineLayoutHdl }
, bindPointData{ std::move (rhs.bindPointData)}
{
memcpy(pushConstantData, rhs.pushConstantData, PUSH_CONSTANT_SIZE);
@ -728,7 +736,7 @@ namespace SHADE
usageFlags = rhs.usageFlags;
commandBufferCount = rhs.commandBufferCount;
parentPool = rhs.parentPool;
boundPipelineLayoutHdl = rhs.boundPipelineLayoutHdl;
bindPointData = std::move(rhs.bindPointData);
memcpy(pushConstantData, rhs.pushConstantData, PUSH_CONSTANT_SIZE);
rhs.vkCommandBuffer = VK_NULL_HANDLE;

View File

@ -4,8 +4,9 @@
#include "Graphics/SHVulkanIncludes.h"
#include "Graphics/SHVulkanDefines.h"
#include "SHCommandPoolResetMode.h"
#include "Resource/ResourceLibrary.h"
#include "Resource/SHResourceLibrary.h"
#include "Graphics/Pipeline/SHVkPipelineLayout.h"
#include "Graphics/Pipeline/SHPipelineType.h"
namespace SHADE
{
@ -36,10 +37,17 @@ namespace SHADE
class SHVkCommandBuffer
{
friend class SHVkCommandPool;
friend class ResourceLibrary<SHVkCommandBuffer>;
friend class SHResourceLibrary<SHVkCommandBuffer>;
static constexpr uint16_t PUSH_CONSTANT_SIZE = 512;
private:
struct PipelineBindPointData
{
//! The currently bound pipeline
Handle<SHVkPipelineLayout> boundPipelineLayoutHdl;
};
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */
/*-----------------------------------------------------------------------*/
@ -66,8 +74,8 @@ namespace SHADE
//! The command pool that this command buffer belongs to
Handle<SHVkCommandPool> parentPool;
//! The currently bound pipeline
Handle<SHVkPipelineLayout> boundPipelineLayoutHdl;
//! Every command buffer will have a set of pipeline bind point specific data
std::array<PipelineBindPointData, static_cast<uint32_t>(SH_PIPELINE_TYPE::NUM_TYPES)> bindPointData;
//! The push constant data for the command buffer
uint8_t pushConstantData[PUSH_CONSTANT_SIZE];
@ -112,13 +120,16 @@ namespace SHADE
void BindPipeline (Handle<SHVkPipeline> const& pipelineHdl) noexcept;
void BindVertexBuffer (uint32_t bindingPoint, Handle<SHVkBuffer> const& buffer, vk::DeviceSize offset) noexcept;
void BindIndexBuffer (Handle<SHVkBuffer> const& buffer, uint32_t startingIndex) const noexcept;
void BindDescriptorSet (Handle<SHVkDescriptorSetGroup> descSetGroup, vk::PipelineBindPoint bindPoint, uint32_t firstSet, std::span<uint32_t> dynamicOffsets);
void BindDescriptorSet (Handle<SHVkDescriptorSetGroup> descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span<uint32_t> dynamicOffsets);
// Draw Commands
void DrawArrays (uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept;
void DrawIndexed (uint32_t indexCount, uint32_t firstIndex, uint32_t vertexOffset) const noexcept;
void DrawMultiIndirect (Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount);
// Compute Commands
void ComputeDispatch (uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept;
// Buffer Copy
void CopyBufferToImage (const vk::Buffer& src, const vk::Image& dst, const std::vector<vk::BufferImageCopy>& copyInfo);
void CopyImageToBuffer (const vk::Image& src, const vk::Buffer& dst, const std::vector<vk::BufferImageCopy>& copyInfo);
@ -138,13 +149,13 @@ namespace SHADE
// Push Constant variable setting
template <typename T>
void SetPushConstantVariable(std::string variableName, T const& data) noexcept
void SetPushConstantVariable(std::string variableName, T const& data, SH_PIPELINE_TYPE bindPoint) noexcept
{
memcpy (static_cast<uint8_t*>(pushConstantData) + boundPipelineLayoutHdl->GetPushConstantInterface().GetOffset(variableName), &data, sizeof (T));
memcpy (static_cast<uint8_t*>(pushConstantData) + bindPointData[static_cast<uint32_t>(bindPoint)].boundPipelineLayoutHdl->GetPushConstantInterface().GetOffset(variableName), &data, sizeof (T));
};
void ForceSetPipelineLayout (Handle<SHVkPipelineLayout> pipelineLayout) noexcept;
void ForceSetPipelineLayout (Handle<SHVkPipelineLayout> pipelineLayout, SH_PIPELINE_TYPE pipelineType) noexcept;
void SubmitPushConstants (void) const noexcept;
void SubmitPushConstants (SH_PIPELINE_TYPE bindPoint) const noexcept;
/*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */

View File

@ -2,7 +2,7 @@
#include "SHVkCommandPool.h"
#include "Graphics/Devices/SHVkLogicalDevice.h"
#include "Graphics/Instance/SHVkInstance.h"
#include "Resource/ResourceLibrary.h"
#include "Resource/SHResourceLibrary.h"
#include "Tools/SHLogger.h"
namespace SHADE

View File

@ -6,7 +6,7 @@
#include "Graphics/Queues/SHVkQueue.h"
#include "SHCommandPoolResetMode.h"
#include "SHVkCommandBuffer.h"
#include "Resource/ResourceLibrary.h"
#include "Resource/SHResourceLibrary.h"
namespace SHADE
{

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