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

This commit is contained in:
Brandon Mak 2022-10-26 15:26:41 +08:00
commit 43ea33cabf
76 changed files with 2781 additions and 1668 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 Name: Cube.003
ID: 110152941 ID: 110152941
Type:  Type: 6

View File

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

View File

@ -4,13 +4,13 @@ Size=1920,20
Collapsed=0 Collapsed=0
[Window][SHEditorMenuBar] [Window][SHEditorMenuBar]
Pos=0,24 Pos=0,48
Size=1920,1036 Size=1920,1012
Collapsed=0 Collapsed=0
[Window][Hierarchy Panel] [Window][Hierarchy Panel]
Pos=0,120 Pos=0,197
Size=225,940 Size=308,863
Collapsed=0 Collapsed=0
DockId=0x00000004,0 DockId=0x00000004,0
@ -20,29 +20,96 @@ Size=400,400
Collapsed=0 Collapsed=0
[Window][Inspector] [Window][Inspector]
Pos=1686,24 Pos=1528,48
Size=234,1036 Size=392,1012
Collapsed=0 Collapsed=0
DockId=0x00000006,0 DockId=0x00000006,0
[Window][Profiler] [Window][Profiler]
Pos=0,24 Pos=0,48
Size=225,94 Size=308,147
Collapsed=0 Collapsed=0
DockId=0x00000003,0 DockId=0x00000003,0
[Window][Viewport] [Window][Viewport]
Pos=227,24 Pos=227,48
Size=1457,1036 Size=1457,1012
Collapsed=0 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] [Docking][Data]
DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,55 Size=1920,1036 Split=X DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,79 Size=1920,1012 Split=X
DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1684,1036 Split=X DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1526,1036 Split=X
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=225,1036 Split=Y Selected=0x1E6EB881 DockNode ID=0x00000001 Parent=0x00000005 SizeRef=308,1036 Split=Y Selected=0x1E6EB881
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881 DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,147 Selected=0x1E6EB881
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Selected=0xE096E5AE DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,863 Selected=0xE096E5AE
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1293,1036 CentralNode=1 Selected=0x13926F0B DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1216,1036 Split=Y Selected=0xB41284E7
DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=234,1036 Selected=0xE7039252 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

@ -10,9 +10,9 @@ Collapsed=0
[Window][Hierarchy Panel] [Window][Hierarchy Panel]
Pos=0,142 Pos=0,142
Size=494,918 Size=494,690
Collapsed=0 Collapsed=0
DockId=0x00000004,0 DockId=0x00000007,0
[Window][Debug##Default] [Window][Debug##Default]
Pos=60,60 Pos=60,60
@ -43,12 +43,20 @@ Size=1151,1012
Collapsed=0 Collapsed=0
DockId=0x00000002,0 DockId=0x00000002,0
[Docking][Data] [Window][ Asset Browser]
DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,79 Size=1920,1012 Split=X Pos=0,834
DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1992,1036 Split=X Size=494,226
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=494,1036 Split=Y Selected=0x1E6EB881 Collapsed=0
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881 DockId=0x00000008,0
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Selected=0xE096E5AE
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1151,1036 CentralNode=1 Selected=0xB41284E7 [Docking][Data]
DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=271,1036 Selected=0xE7039252 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=494,1036 Split=Y Selected=0x1E6EB881
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Split=Y Selected=0xE096E5AE
DockNode ID=0x00000007 Parent=0x00000004 SizeRef=494,690 Selected=0xE096E5AE
DockNode ID=0x00000008 Parent=0x00000004 SizeRef=494,226 Selected=0xB128252A
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1151,1036 CentralNode=1 Selected=0xB41284E7
DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=271,1036 Selected=0xE7039252

View File

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

View File

@ -56,8 +56,8 @@ namespace Sandbox
_In_ INT nCmdShow _In_ INT nCmdShow
) )
{ {
// Set working directory // Set working directory
SHFileUtilities::SetWorkDirToExecDir(); SHFileUtilities::SetWorkDirToExecDir();
window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow); window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
@ -83,11 +83,13 @@ namespace Sandbox
SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::LateUpdateRoutine>(); SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::LateUpdateRoutine>();
SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::FrameCleanUpRoutine>(); SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::FrameCleanUpRoutine>();
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostLogicUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>();
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformUpdateRoutine>(); SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>();
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BatcherDispatcherRoutine>(); SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BatcherDispatcherRoutine>();
SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BeginRoutine>(); SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BeginRoutine>();
@ -150,16 +152,16 @@ namespace Sandbox
SHSceneManager::SceneUpdate(0.016f); SHSceneManager::SceneUpdate(0.016f);
#endif #endif
SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, 0.016f); SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, 0.016f);
//editor->PollPicking(); editor->PollPicking();
} }
// Finish all graphics jobs first // Finish all graphics jobs first
graphicsSystem->AwaitGraphicsExecution(); graphicsSystem->AwaitGraphicsExecution();
} }
void SBApplication::Exit(void) void SBApplication::Exit(void)
{ {
#ifdef SHEDITOR #ifdef SHEDITOR
SDL_DestroyWindow(sdlWindow); SDL_DestroyWindow(sdlWindow);
SDL_Quit(); SDL_Quit();
#endif #endif

View File

@ -53,7 +53,7 @@ namespace Sandbox
if (asset.name == "Cube.012") if (asset.name == "Cube.012")
handles.emplace_back(SHResourceManager::LoadOrGet<SHMesh>(asset.id)); handles.emplace_back(SHResourceManager::LoadOrGet<SHMesh>(asset.id));
break; break;
case AssetType::TEXTURE: case AssetType::IMAGE:
texHandles.emplace_back(SHResourceManager::LoadOrGet<SHTexture>(asset.id)); texHandles.emplace_back(SHResourceManager::LoadOrGet<SHTexture>(asset.id));
break; break;
} }
@ -68,9 +68,9 @@ namespace Sandbox
customMat->SetProperty("data.alpha", 0.1f); customMat->SetProperty("data.alpha", 0.1f);
// Create Stress Test Objects // Create Stress Test Objects
static const SHVec3 TEST_OBJ_SCALE = SHVec3::One * 0.5f; static const SHVec3 TEST_OBJ_SCALE = SHVec3::One;
constexpr int NUM_ROWS = 0; constexpr int NUM_ROWS = 3;
constexpr int NUM_COLS = 0; constexpr int NUM_COLS = 1;
static const SHVec3 TEST_OBJ_SPACING = { 0.1f, 0.1f, 0.1f }; 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 }; static const SHVec3 TEST_OBJ_START_POS = { -(NUM_COLS / 2 * TEST_OBJ_SPACING.x) + 1.0f, -2.0f, -1.0f };
@ -92,13 +92,13 @@ namespace Sandbox
//Set initial positions //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(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.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); 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); collider.AddBoundingBox(SHVec3::One * 0.5f, SHVec3::Zero);
else //else
collider.AddBoundingSphere(0.5f, SHVec3::Zero); // collider.AddBoundingSphere(0.5f, SHVec3::Zero);
stressTestObjects.emplace_back(entity); stressTestObjects.emplace_back(entity);
} }

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 "SH_API.power h"
namespace SHADE
{
struct SH_API SHAnimationAsset
{
std::string name;
std::vector<aiNodeAnim*> nodeChannels;
std::vector<aiMeshAnim*> meshChannels;
std::vector<aiMeshMorphAnim*> morphMeshChannels;
double duration;
double ticksPerSecond;
};
}

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

View File

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

View File

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

View File

@ -0,0 +1,141 @@
/*************************************************************************//**
* \file SHAssimpLibrary.cpp
* \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.
*****************************************************************************/
#include "SHpch.h"
#include "SHAssimpLibrary.h"
#include <assimp/postprocess.h>
namespace SHADE
{
Assimp::Importer SHAssimpLibrary::aiImporter;
void SHAssimpLibrary::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept
{
for (size_t i {0}; i < node.mNumMeshes; ++i)
{
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 SHAssimpLibrary::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* SHAssimpLibrary::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 SHAssimpLibrary::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();
}
}

View File

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

View File

@ -20,7 +20,7 @@ std::string SHADE::SHMeshCompiler::CompileMeshBinary(SHMeshAsset const& asset, A
{ {
std::string newPath{ path.string() }; std::string newPath{ path.string() };
newPath = newPath.substr(0, newPath.find_last_of('/') + 1); newPath = newPath.substr(0, newPath.find_last_of('/') + 1);
newPath += asset.header.meshName + MESH_EXTENSION; newPath += asset.header.name + MESH_EXTENSION.data();
std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc }; std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc };
if (!file.is_open()) if (!file.is_open())

View File

@ -12,129 +12,11 @@
*****************************************************************************/ *****************************************************************************/
#include "SHpch.h" #include "SHpch.h"
#include "SHMeshLoader.h" #include "SHMeshLoader.h"
#include <assimp/postprocess.h>
#include <fstream> #include <fstream>
namespace SHADE namespace SHADE
{ {
Assimp::Importer SHMeshLoader::aiImporter; void SHMeshLoader::LoadSHMesh(AssetPath path, SHMeshAsset& mesh) noexcept
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 }; std::ifstream file{ path.string(), std::ios::in | std::ios::binary };
if (!file.is_open()) if (!file.is_open())
@ -169,44 +51,12 @@ namespace SHADE
file.read(reinterpret_cast<char *>(texCoord.data()), vertexVec2Byte); file.read(reinterpret_cast<char *>(texCoord.data()), vertexVec2Byte);
file.read(reinterpret_cast<char *>(indices.data()), sizeof(uint32_t) * indexCount); 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.compiled = true;
mesh.changed = false; mesh.changed = false;
mesh.header.indexCount = indexCount; mesh.header.indexCount = indexCount;
mesh.header.vertexCount = vertCount; mesh.header.vertexCount = vertCount;
mesh.header.meshName = name; mesh.header.name = name;
mesh.vertexPosition = std::move(vertPos); mesh.vertexPosition = std::move(vertPos);
mesh.vertexTangent = std::move(vertTan); mesh.vertexTangent = std::move(vertTan);
@ -217,15 +67,12 @@ namespace SHADE
file.close(); file.close();
} }
void SHMeshLoader::LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept SHAssetData* SHMeshLoader::Load(AssetPath path)
{ {
if (path.extension().string() == GLTF_EXTENSION) auto result = new SHMeshAsset();
{
LoadExternal(meshes, path);
return;
}
meshes.emplace_back(); LoadSHMesh(path, *result);
LoadSHMesh(meshes.back(), path);
return result;
} }
} }

View File

@ -10,27 +10,15 @@
* of DigiPen Institute of Technology is prohibited. * of DigiPen Institute of Technology is prohibited.
*****************************************************************************/ *****************************************************************************/
#pragma once #pragma once
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include "../SHAssetMacros.h" #include "../SHAssetMacros.h"
#include "../Asset Types/SHMeshAsset.h" #include "../Asset Types/SHMeshAsset.h"
#include <vector> #include "SHAssetLoader.h"
namespace SHADE namespace SHADE
{ {
class SHMeshLoader struct SHMeshLoader : public SHAssetLoader
{ {
private: void LoadSHMesh(AssetPath path, SHMeshAsset& meshes) noexcept;
static Assimp::Importer aiImporter; SHAssetData* Load(AssetPath path) override;
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

@ -133,6 +133,15 @@ namespace SHADE
file.close(); file.close();
} }
SHAssetData* SHTextureLoader::Load(AssetPath path)
{
auto result = new SHTextureAsset();
LoadImageAsset(path, *result);
return result;
}
void SHTextureLoader::LoadImageAsset(AssetPath path, SHTextureAsset& asset) void SHTextureLoader::LoadImageAsset(AssetPath path, SHTextureAsset& asset)
{ {
if (path.extension().string() == DDS_EXTENSION) if (path.extension().string() == DDS_EXTENSION)

View File

@ -15,19 +15,20 @@
#include "../SHAssetMacros.h" #include "../SHAssetMacros.h"
#include "../Asset Types/SHTextureAsset.h" #include "../Asset Types/SHTextureAsset.h"
#include "tinyddsloader.h" #include "tinyddsloader.h"
#include "SHAssetLoader.h"
namespace SHADE namespace SHADE
{ {
class SHTextureLoader class SHTextureLoader : public SHAssetLoader
{ {
private: private:
static std::string TinyDDSResultToString(tinyddsloader::Result value); std::string TinyDDSResultToString(tinyddsloader::Result value);
static vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear); vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear);
void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept;
static void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept;
public: public:
static void LoadImageAsset(AssetPath paths, SHTextureAsset& image); void LoadImageAsset(AssetPath paths, SHTextureAsset& image);
static void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept; void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept;
SHAssetData* Load(AssetPath path) override;
}; };
} }

View File

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

View File

@ -32,12 +32,12 @@ typedef std::filesystem::path AssetPath;
typedef unsigned char* AssetData; typedef unsigned char* AssetData;
typedef std::string AssetMetaVersion; typedef std::string AssetMetaVersion;
typedef std::string AssetExtension; typedef std::string AssetExtension;
typedef unsigned char AssetTypeMeta; typedef size_t AssetTypeMeta;
typedef FMOD::Sound* SHSound; typedef FMOD::Sound* SHSound;
// Asset Meta Version // Asset Meta Version
#define ASSET_META_VER "1.0" constexpr std::string_view ASSET_META_VER { "1.0" };
// Asset type enum // Asset type enum
enum class AssetType : AssetTypeMeta enum class AssetType : AssetTypeMeta
@ -53,34 +53,35 @@ enum class AssetType : AssetTypeMeta
SCENE, SCENE,
PREFAB, PREFAB,
AUDIO_WAV, AUDIO_WAV,
DDS DDS,
MAX_COUNT
}; };
//Directory //Directory
#ifdef _PUBLISH #ifdef _PUBLISH
#define ASSET_ROOT "Assets" constexpr std::string_view ASSET_ROOT {"Assets"};
#else #else
#define ASSET_ROOT "../../Assets" constexpr std::string_view ASSET_ROOT {"../../Assets"};
#endif #endif
// ASSET EXTENSIONS // ASSET EXTENSIONS
#define META_EXTENSION ".shmeta" constexpr std::string_view META_EXTENSION {".shmeta"};
#define IMAGE_EXTENSION ".png" constexpr std::string_view IMAGE_EXTENSION {".png"};
#define AUDIO_EXTENSION ".ogg" constexpr std::string_view AUDIO_EXTENSION {".ogg"};
#define AUDIO_WAV_EXTENSION ".wav" constexpr std::string_view AUDIO_WAV_EXTENSION {".wav"};
#define SHADER_EXTENSION ".glsl" constexpr std::string_view SHADER_EXTENSION {".glsl"};
#define SCRIPT_EXTENSION ".cs" constexpr std::string_view SCRIPT_EXTENSION {".cs"};
#define SCENE_EXTENSION ".SHADE" constexpr std::string_view SCENE_EXTENSION {".SHADE"};
#define PREFAB_EXTENSION ".SHPrefab" constexpr std::string_view PREFAB_EXTENSION {".SHPrefab"};
#define MATERIAL_EXTENSION ".SHMat" constexpr std::string_view MATERIAL_EXTENSION {".SHMat"};
#define TEXTURE_EXTENSION ".shtex" constexpr std::string_view TEXTURE_EXTENSION {".shtex"};
#define DDS_EXTENSION ".dds" constexpr std::string_view DDS_EXTENSION {".dds"};
#define FBX_EXTENSION ".fbx" constexpr std::string_view FBX_EXTENSION {".fbx"};
#define GLTF_EXTENSION ".gltf" constexpr std::string_view GLTF_EXTENSION {".gltf"};
#define MESH_EXTENSION ".shmesh" constexpr std::string_view MESH_EXTENSION {".shmesh"};
std::string const EXTENSIONS[] = { constexpr std::string_view EXTENSIONS[] = {
AUDIO_EXTENSION, AUDIO_EXTENSION,
SHADER_EXTENSION, SHADER_EXTENSION,
MATERIAL_EXTENSION, MATERIAL_EXTENSION,
@ -96,10 +97,12 @@ std::string const EXTENSIONS[] = {
GLTF_EXTENSION GLTF_EXTENSION
}; };
constexpr size_t TYPE_COUNT {static_cast<size_t>(AssetType::MAX_COUNT) };
// Error flags // Error flags
#define FILE_NOT_FOUND_ERR "FILE NOT FOUND" constexpr std::string_view FILE_NOT_FOUND_ERR {"FILE NOT FOUND"};
#define META_NOT_FOUND_ERR "META NOT FOUND" constexpr std::string_view META_NOT_FOUND_ERR {"META NOT FOUND"};
#define ASSET_NOT_FOUND_ERR "ASSET NOT FOUND" constexpr std::string_view ASSET_NOT_FOUND_ERR {"ASSET NOT FOUND"};
#define EXT_DOES_NOT_EXIST "TYPE DOES NOT HAVE EXTENSION DEFINED" constexpr std::string_view EXT_DOES_NOT_EXIST {"TYPE DOES NOT HAVE EXTENSION DEFINED"};
#endif // !SH_ASSET_MACROS_H #endif // !SH_ASSET_MACROS_H

View File

@ -14,6 +14,7 @@
#include "SHAssetMetaHandler.h" #include "SHAssetMetaHandler.h"
#include "Filesystem/SHFileSystem.h" #include "Filesystem/SHFileSystem.h"
#include "Libraries/SHAssimpLibrary.h"
#include "Libraries/SHMeshLoader.h" #include "Libraries/SHMeshLoader.h"
#include "Libraries/SHTextureLoader.h" #include "Libraries/SHTextureLoader.h"
@ -25,11 +26,10 @@ namespace SHADE
FMOD::System* SHAssetManager::audioSystem; FMOD::System* SHAssetManager::audioSystem;
std::unordered_map<AssetID, SHSound >* SHAssetManager::audioSoundList; std::unordered_map<AssetID, SHSound >* SHAssetManager::audioSoundList;
std::vector<SHAsset> SHAssetManager::assetCollection; std::vector<SHAssetLoader*> SHAssetManager::loaders(TYPE_COUNT);
std::unordered_map<AssetID, SHAsset> SHAssetManager::assetRegistry;
std::unordered_map<AssetID, SHMeshAsset> SHAssetManager::meshCollection; std::vector<SHAsset> SHAssetManager::assetCollection;
std::unordered_map<AssetID, SHTextureAsset> SHAssetManager::textureCollection; std::unordered_map<AssetID, SHAssetData * const> SHAssetManager::assetData;
/**************************************************************************** /****************************************************************************
* \brief Static function to generate asset ID. * \brief Static function to generate asset ID.
@ -56,18 +56,15 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
void SHAssetManager::Unload() noexcept void SHAssetManager::Unload() noexcept
{ {
for (auto const& asset : assetCollection)
{
SHAssetMetaHandler::WriteMetaData(asset);
}
} }
void SHAssetManager::Unload(AssetID assetId) noexcept void SHAssetManager::Unload(AssetID assetId) noexcept
{ {
// TODO // TODO
} }
AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept
{ {
if (!IsRecognised(path.extension().string().c_str())) if (!IsRecognised(path.extension().string().c_str()))
{ {
@ -85,7 +82,37 @@ namespace SHADE
// return std::filesystem::path(); // 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::SCENE:
folder = "scenes/";
break;
case AssetType::PREFAB:
folder = "prefabs/";
break;
case AssetType::MATERIAL:
folder = "materials/";
break;
default:
folder = "/";
}
return std::filesystem::path{
std::string(ASSET_ROOT) +
folder +
name +
std::string(EXTENSIONS[static_cast<size_t>(type)])
};
} }
/**************************************************************************** /****************************************************************************
@ -121,7 +148,7 @@ namespace SHADE
// folder = ""; // folder = "";
// break; // break;
//} //}
AssetPath path{ ASSET_ROOT + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) }; AssetPath path{ std::string{ASSET_ROOT} + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) };
SHAssetMetaHandler::WriteMetaData(meta); SHAssetMetaHandler::WriteMetaData(meta);
@ -130,6 +157,19 @@ namespace SHADE
return id; 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. * \brief Import new asset from outside editor window.
* *
@ -138,7 +178,10 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
AssetID SHAssetManager::ImportNewAsset(char const* p) noexcept 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) }; std::filesystem::path const newPath{ GenerateLocalPath(path) };
if (newPath.empty()) if (newPath.empty())
@ -149,11 +192,7 @@ namespace SHADE
std::filesystem::copy(path, newPath); std::filesystem::copy(path, newPath);
AssetID id{ RetrieveAsset(newPath.string().c_str()) }; assetCollection.push_back(CreateAssetFromPath(newPath));
if (id != 0)
{
LoadData(id);
}
return id; return id;
} }
@ -164,158 +203,14 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
void SHAssetManager::RefreshAllAssets() noexcept 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)
{
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;
}
}
if (!found && IsRecognised(asset.extension().string().c_str()))
{
AssetFilesNew.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);
}
return result;
}
SHMeshAsset const* SHAssetManager::GetMesh(AssetID id) noexcept
{
if (meshCollection.find(id) == meshCollection.end())
{
return nullptr;
}
return &meshCollection[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) for (auto const& e : EXTENSIONS)
{ {
if (strcmp(ext, e.c_str()) == 0) if (strcmp(ext, e.data()) == 0)
{ {
return true; return true;
} }
@ -324,54 +219,31 @@ namespace SHADE
return false; 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;
for (auto const& mesh : meshes) return result;
{
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
);
}
} }
void SHAssetManager::LoadDDS(SHAsset asset) noexcept void SHAssetManager::InitLoaders() noexcept
{ {
SHTextureAsset image; loaders[static_cast<size_t>(AssetType::AUDIO)] = nullptr;
loaders[static_cast<size_t>(AssetType::SHADER)] = nullptr;
SHTextureLoader::LoadImageAsset(asset.path, image); loaders[static_cast<size_t>(AssetType::MATERIAL)] = nullptr;
loaders[static_cast<size_t>(AssetType::IMAGE)] = dynamic_cast<SHAssetLoader*>(new SHTextureLoader());
if (!image.compiled) loaders[static_cast<size_t>(AssetType::TEXTURE)] = nullptr;
{ loaders[static_cast<size_t>(AssetType::MESH)] = dynamic_cast<SHAssetLoader*>(new SHMeshLoader());
auto id{ GenerateAssetID(AssetType::TEXTURE) }; loaders[static_cast<size_t>(AssetType::SCRIPT)] = nullptr;
textureCollection.emplace(id, image); loaders[static_cast<size_t>(AssetType::SCENE)] = nullptr;
loaders[static_cast<size_t>(AssetType::PREFAB)] = nullptr;
auto path{ SHTextureCompiler::CompileTextureBinary(image, asset.path) }; loaders[static_cast<size_t>(AssetType::AUDIO_WAV)] = nullptr;
loaders[static_cast<size_t>(AssetType::DDS)] = nullptr;
assetCollection.emplace_back(
image.name,
id,
AssetType::TEXTURE,
path,
0
);
}
} }
/**************************************************************************** /****************************************************************************
@ -379,8 +251,9 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
void SHAssetManager::Load() noexcept void SHAssetManager::Load() noexcept
{ {
RetrieveAssets(); InitLoaders();
LoadAllData(); BuildAssetCollection();
//LoadAllData();
} }
/**************************************************************************** /****************************************************************************
@ -388,143 +261,40 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
void SHAssetManager::LoadAllData() noexcept void SHAssetManager::LoadAllData() noexcept
{ {
//TODO Remove when on demand loading is done
for (auto const& asset : assetCollection) for (auto const& asset : assetCollection)
{ {
switch (asset.type) SHAssetData* data = loaders[static_cast<size_t>(asset.type)]->Load(asset.path);
{ assetData.emplace(asset.id, data);
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;
}
} }
} }
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);
}
/**************************************************************************** if (data == nullptr)
* \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 (dir.path().extension().string() == META_EXTENSION) SHLOG_ERROR("Unable to load asset into memory: {}\n", asset.path.string());
{
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;
} }
else else
{ {
std::cout << "Unsupported File Format: " << p.filename() << "\n"; assetData.emplace(asset.id, data);
} }
// Assert that file imported is not recognised return data;
return 0;
} }
/**************************************************************************** void SHAssetManager::BuildAssetCollection() 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
****************************************************************************/
AssetName SHAssetManager::GetNameFromPath(AssetPath filepath) noexcept
{ {
std::string name{ filepath.filename().string() }; for (auto const& dir : std::filesystem::recursive_directory_iterator{ASSET_ROOT})
name = name.substr(0, name.find_last_of('.')); {
if (dir.is_regular_file())
//if (name[0] <= 122 && name[0] >= 97) {
//{ if (dir.path().extension().string() == META_EXTENSION.data())
// name[0] -= 32; {
//} assetCollection.push_back(SHAssetMetaHandler::RetrieveMetaData(dir.path()));
}
//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;
} }
} }

View File

@ -11,9 +11,10 @@
#pragma once #pragma once
#include "tinyddsloader.h" #include "tinyddsloader.h"
#include "SHAsset.h" #include "SHAsset.h"
#include "Asset Types/SHAssetData.h"
#include "Libraries/SHAssetLoader.h"
#include <memory>
#include "Asset Types/SHMeshAsset.h"
#include "Asset Types/SHTextureAsset.h"
#include "SH_API.h" #include "SH_API.h"
namespace SHADE namespace SHADE
@ -28,6 +29,8 @@ namespace SHADE
static AssetPath GenerateLocalPath(AssetPath path) noexcept; static AssetPath GenerateLocalPath(AssetPath path) noexcept;
static AssetPath GenerateNewPath(AssetName name, AssetType type);
/**************************************************************************** /****************************************************************************
* \brief Deallocate all memory used by resource data * \brief Deallocate all memory used by resource data
****************************************************************************/ ****************************************************************************/
@ -55,6 +58,7 @@ namespace SHADE
* \return resource id generated for new asset * \return resource id generated for new asset
****************************************************************************/ ****************************************************************************/
static AssetID CreateNewAsset(AssetType, AssetName) noexcept; static AssetID CreateNewAsset(AssetType, AssetName) noexcept;
static AssetID CreateAsset(AssetName name, AssetType type) noexcept;
/**************************************************************************** /****************************************************************************
* \brief Import new resource from outside editor window. * \brief Import new resource from outside editor window.
@ -71,66 +75,33 @@ namespace SHADE
static void RefreshAllAssets() noexcept; static void RefreshAllAssets() noexcept;
// -------------------------------------------------------------------------/ // -------------------------------------------------------------------------/
//TODO: TEMPORARY FOR TESTING GLTF & DDS template<typename T>
static void LoadDataTemp(std::string path) noexcept; static std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> GetData(AssetID id) noexcept;
static std::vector<SHMeshAsset> GetAllMeshes() noexcept;
static std::vector<SHTextureAsset> GetAllTextures() noexcept;
static SHMeshAsset const* GetMesh(AssetID id) noexcept;
static SHTextureAsset const* GetTexture(AssetID id) noexcept;
private: private:
/**************************************************************************** /****************************************************************************
* \brief Load resource data into memory * \brief Load resource data into memory
****************************************************************************/ ****************************************************************************/
static void LoadAllData() noexcept; static void LoadAllData() noexcept;
static void LoadData(AssetID id) noexcept; static SHAssetData* LoadData(SHAsset const& asset) noexcept;
/**************************************************************************** inline static void BuildAssetCollection() 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 bool IsRecognised(char const*) noexcept; static bool IsRecognised(char const*) noexcept;
// Specialised load calls static SHAsset CreateAssetFromPath(AssetPath path) noexcept;
static void LoadGLTF(SHAsset asset) noexcept;
static void LoadDDS(SHAsset asset) noexcept; static void InitLoaders() noexcept;
static FMOD::System* audioSystem; static FMOD::System* audioSystem;
static std::unordered_map<AssetID,SHSound>* audioSoundList; static std::unordered_map<AssetID,SHSound>* audioSoundList;
static std::vector<SHAssetLoader*> loaders;
// For all resources // For all resources
static std::vector<SHAsset> assetCollection; static std::vector<SHAsset> assetCollection;
static std::unordered_map<AssetID, SHAsset> assetRegistry; static std::unordered_map<AssetID, SHAssetData * const> assetData;
static std::unordered_map<AssetID, SHMeshAsset> meshCollection;
static std::unordered_map<AssetID, SHTextureAsset> textureCollection;
}; };
} }
#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) 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); return static_cast<AssetType>(i);
} }
@ -53,7 +53,7 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
AssetExtension SHAssetMetaHandler::GetExtensionFromType(AssetType type) noexcept 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 << "ID: " << meta.id << "\n";
metaFile << "Type: " << static_cast<AssetTypeMeta>(meta.type) << std::endl; 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(); metaFile.close();
} }

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

@ -93,8 +93,7 @@ namespace SHADE
{ {
if (ImGui::BeginMenuBar()) if (ImGui::BeginMenuBar())
{ {
ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x * 0.75f);
ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x - 35.0f);
if(ImGui::SmallButton(ICON_MD_DESELECT)) if(ImGui::SmallButton(ICON_MD_DESELECT))
{ {
auto editor = SHSystemManager::GetSystem<SHEditor>(); auto editor = SHSystemManager::GetSystem<SHEditor>();

View File

@ -39,6 +39,10 @@ namespace SHADE
{ {
SHComponentManager::RemoveComponent<T>(component->GetEID()); SHComponentManager::RemoveComponent<T>(component->GetEID());
} }
if (ImGui::Selectable(std::format("{} Reset {}", ICON_MD_RESTART_ALT, componentName.data()).data()))
{
*component = T();
}
ImGui::EndPopup(); ImGui::EndPopup();
} }
} }
@ -48,7 +52,7 @@ namespace SHADE
if (!component) if (!component)
return; return;
const auto componentType = rttr::type::get(*component); const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data())) if (ImGui::CollapsingHeader(componentType.get_name().data()))
{ {
@ -89,7 +93,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
if (metaMin && metaMax) if (metaMin && metaMax)
{ {
SHEditorWidgets::SliderInt(property.get_name().data(), metaMin.template get_value<int>(), 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 else
{ {
@ -115,7 +119,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid()) if (metaMin.is_valid() && metaMax.is_valid())
{ {
SHEditorWidgets::SliderScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value<uint16_t>(), 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 else
{ {
@ -128,7 +132,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid()) if (metaMin.is_valid() && metaMax.is_valid())
{ {
SHEditorWidgets::SliderScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value<uint32_t>(), 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 else
{ {
@ -141,7 +145,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid()) if (metaMin.is_valid() && metaMax.is_valid())
{ {
SHEditorWidgets::SliderScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value<uint64_t>(), 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 else
{ {
@ -152,13 +156,18 @@ namespace SHADE
{ {
auto metaMin = property.get_metadata(META::min); auto metaMin = property.get_metadata(META::min);
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
float min{}, max{};
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()) 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 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>()) else if (type == rttr::type::get<double>())
@ -167,7 +176,7 @@ namespace SHADE
auto metaMax = property.get_metadata(META::max); auto metaMax = property.get_metadata(META::max);
if (metaMin.is_valid() && metaMax.is_valid()) if (metaMin.is_valid() && metaMax.is_valid())
{ {
SHEditorWidgets::SliderScalar<double>(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value<double>(), 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 else
{ {

View File

@ -84,8 +84,8 @@ namespace SHADE
} }
ImGui::Separator(); ImGui::Separator();
// Render Scripts // Render Scripts
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>()); SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
scriptEngine->RenderScriptsInInspector(eid); scriptEngine->RenderScriptsInInspector(eid);
ImGui::Separator(); ImGui::Separator();
if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data())) if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data()))
{ {

View File

@ -4,3 +4,4 @@
#include "Inspector/SHEditorInspector.h" //Inspector #include "Inspector/SHEditorInspector.h" //Inspector
#include "Profiling/SHEditorProfiler.h" //Profiler #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

@ -24,12 +24,13 @@ namespace SHADE
void SHEditorViewport::Init() void SHEditorViewport::Init()
{ {
SHEditorWindow::Init(); SHEditorWindow::Init();
transformGizmo.Init();
} }
void SHEditorViewport::Update() void SHEditorViewport::Update()
{ {
SHEditorWindow::Update(); SHEditorWindow::Update();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f,0.0f));
if(Begin()) if(Begin())
{ {
ImGuizmo::SetDrawlist(); ImGuizmo::SetDrawlist();
@ -55,7 +56,7 @@ namespace SHADE
ImGuizmo::SetRect(beginCursorPos.x , beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y); ImGuizmo::SetRect(beginCursorPos.x , beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y);
transformGizmo.Draw(); transformGizmo.Draw();
ImGui::End(); ImGui::End();
ImGui::PopStyleVar();
} }
void SHEditorViewport::Exit() void SHEditorViewport::Exit()

View File

@ -13,6 +13,12 @@
#include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h" #include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h"
namespace SHADE namespace SHADE
{ {
void SHTransformGizmo::Init()
{
auto& style = ImGuizmo::GetStyle();
style.RotationLineThickness = 2.5f;
}
void SHTransformGizmo::Draw() void SHTransformGizmo::Draw()
{ {
bool justChangedTfm = false; bool justChangedTfm = false;
@ -26,9 +32,12 @@ namespace SHADE
SHMatrix view = SHMatrix::Transpose(editorCamera->GetViewMatrix()); SHMatrix view = SHMatrix::Transpose(editorCamera->GetViewMatrix());
SHMatrix proj = SHMatrix::Transpose(editorCamera->GetProjMatrix()); SHMatrix proj = SHMatrix::Transpose(editorCamera->GetProjMatrix());
//Invert projection y-axis
proj(1, 1) *= -1; proj(1, 1) *= -1;
static SHMatrix gridMat = SHMatrix::Translate(0, -0.5f, 0.f) * SHMatrix::Identity; static SHMatrix gridMat = SHMatrix::Translate(0, -0.5f, 0.f) * SHMatrix::Identity;
//ImGuizmo::DrawGrid(&view._11, &proj._11, &gridMat._11, 100.f);
if (selectedEntityTransformComponent == nullptr) if (selectedEntityTransformComponent == nullptr)
{ {
SHEditor* editor = SHSystemManager::GetSystem<SHEditor>(); SHEditor* editor = SHSystemManager::GetSystem<SHEditor>();
@ -55,31 +64,37 @@ namespace SHADE
return; return;
SHMatrix mat = selectedEntityTransformComponent->GetTRS(); SHMatrix mat = selectedEntityTransformComponent->GetTRS();
isManipulating = ImGuizmo::Manipulate(&view._11, &proj._11, static_cast<ImGuizmo::OPERATION>(operation), ImGuizmo::MODE::WORLD, &mat._11); useSnap = ImGui::IsKeyDown(ImGuiKey_LeftCtrl);
if (!justChangedTfm) if(useSnap)
{ {
if (ImGui::IsItemClicked()) switch (operation)
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = std::move(selectedEntityTransformComponent)](SHMatrix const& mtx) {
{ case Operation::TRANSLATE: snap = &translationSnap.x; break;
if (!tfm) case Operation::ROTATE: snap = &rotationSnap; break;
return; case Operation::SCALE: snap = &scaleSnap; break;
SHVec3 translate{}, rotate{}, scale{}; default: snap = &translationSnap.x;
mtx.Decompose(translate, rotate, scale); }
tfm->SetWorldPosition(translate);
tfm->SetWorldRotation(rotate);
tfm->SetWorldScale(scale);
})));
else if (ImGui::IsItemHovered(ImGuiMouseButton_Left) && ImGui::IsMouseDown(ImGuiMouseButton_Left) && isManipulating)
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = std::move(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);
})), true);
} }
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

@ -37,11 +37,17 @@ namespace SHADE
UNIVERSAL = TRANSLATE | ROTATE | SCALEU UNIVERSAL = TRANSLATE | ROTATE | SCALEU
}; };
void Init();
void Draw(); void Draw();
bool isManipulating = false; bool isManipulating = false;
bool useSnap = false;
Mode mode = Mode::WORLD; Mode mode = Mode::WORLD;
Operation operation = Operation::TRANSLATE; Operation operation = Operation::TRANSLATE;
private: private:
float scaleSnap = 0.25f;
float rotationSnap = 1.0f;
SHVec3 translationSnap = SHVec3(0.25f, 0.25f, 0.25f);
float* snap = nullptr;
SHTransformComponent* selectedEntityTransformComponent{nullptr}; SHTransformComponent* selectedEntityTransformComponent{nullptr};
SHCameraComponent* editorCamera{nullptr}; SHCameraComponent* editorCamera{nullptr};
}; };

View File

@ -92,6 +92,7 @@ namespace SHADE
SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>(); SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>();
SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>(); SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>();
SHEditorWindowManager::CreateEditorWindow<SHEditorProfiler>(); SHEditorWindowManager::CreateEditorWindow<SHEditorProfiler>();
SHEditorWindowManager::CreateEditorWindow<SHAssetBrowser>();
SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>(); SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>();
io = &ImGui::GetIO(); io = &ImGui::GetIO();
@ -134,7 +135,7 @@ namespace SHADE
} }
} }
PollPicking(); //PollPicking();
if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z)) if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z))
{ {

View File

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

View File

@ -5,8 +5,9 @@ typedef uint32_t SHEventIdentifier;
typedef uint32_t SHEventHandle; typedef uint32_t SHEventHandle;
//Add your event identifiers here: //Add your event identifiers here:
constexpr SHEventIdentifier SH_EXAMPLE_EVENT{0}; constexpr SHEventIdentifier SH_EXAMPLE_EVENT { 0 };
constexpr SHEventIdentifier SH_ENTITY_DESTROYED_EVENT{ 1 }; constexpr SHEventIdentifier SH_ENTITY_DESTROYED_EVENT { 1 };
constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT{ 2 }; constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT { 2 };
constexpr SHEventIdentifier SH_COMPONENT_ADDED_EVENT{ 3 }; constexpr SHEventIdentifier SH_COMPONENT_ADDED_EVENT { 3 };
constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT{ 4 }; constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT { 4 };
constexpr SHEventIdentifier SH_SCENEGRAPH_CHANGE_PARENT_EVENT { 5 };

View File

@ -49,7 +49,7 @@ namespace SHADE
SHVkSampler::~SHVkSampler() noexcept SHVkSampler::~SHVkSampler() noexcept
{ {
if (vkSampler) if (vkSampler)
device->GetVkLogicalDevice().destroySampler(); device->GetVkLogicalDevice().destroySampler(vkSampler);
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/

View File

@ -30,184 +30,199 @@ of DigiPen Institute of Technology is prohibited.
namespace SHADE namespace SHADE
{ {
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* SHBatch - Usage Functions */ /* SHBatch - Usage Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHBatch::SHBatch(Handle<SHVkPipeline> pipeline) SHBatch::SHBatch(Handle<SHVkPipeline> pipeline)
: pipeline{ pipeline } : pipeline{ pipeline }
{ {
if (!pipeline) if (!pipeline)
throw std::invalid_argument("Attempted to create a SHBatch with an invalid SHPipeline!"); throw std::invalid_argument("Attempted to create a SHBatch with an invalid SHPipeline!");
// Mark all as dirty // Mark all as dirty
setAllDirtyFlags(); setAllDirtyFlags();
}
void SHBatch::Add(const SHRenderable* renderable)
{
// Check if we have a SubBatch with the same mesh yet
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
{
return batch.Mesh == renderable->Mesh;
});
// Create one if not found
if (subBatch == subBatches.end())
{
subBatches.emplace_back(renderable->Mesh);
subBatch = subBatches.end() - 1;
} }
void SHBatch::Add(const SHRenderable* renderable) // Add renderable in
{ subBatch->Renderables.insert(renderable->GetEID());
// Check if we have a SubBatch with the same mesh yet
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
{
return batch.Mesh == renderable->Mesh;
});
// Create one if not found // Also add material instance in
if (subBatch == subBatches.end()) referencedMatInstances.insert(renderable->GetMaterial());
// Mark all as dirty
setAllDirtyFlags();
}
void SHBatch::Remove(const SHRenderable* renderable)
{
// Check if we have a SubBatch with the same mesh yet
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
{
return batch.Mesh == renderable->Mesh;
});
// Attempt to remove if it exists
if (subBatch == subBatches.end())
return;
subBatch->Renderables.erase(renderable->GetEID());
// Check if other renderables in subBatches contain the same material instance
bool matUnused = true;
for (const auto& sb : subBatches)
for (const auto& rendId : sb.Renderables)
{
auto rend = SHComponentManager::GetComponent<SHRenderable>(rendId);
if (rend)
{ {
subBatches.emplace_back(renderable->Mesh); if (rend->GetMaterial() == renderable->GetMaterial())
subBatch = subBatches.end() - 1; {
matUnused = false;
break;
}
} }
else
{
SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
}
}
// Add renderable in // Material is no longer in this library, so we remove it
subBatch->Renderables.insert(renderable); if (matUnused)
referencedMatInstances.erase(renderable->WasMaterialChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial());
// Also add material instance in // Mark all as dirty
referencedMatInstances.insert(renderable->GetMaterial()); setAllDirtyFlags();
}
// Mark all as dirty void SHBatch::Clear()
setAllDirtyFlags(); {
subBatches.clear();
// Clear CPU buffers
drawData.clear();
transformData.clear();
instancedIntegerData.clear();
matPropsData.reset();
matPropsDataSize = 0;
// Clear GPU buffers
for (int i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{
drawDataBuffer[i].Free();
transformDataBuffer[i].Free();
instancedIntegerBuffer[i].Free();
matPropsBuffer[i].Free();
}
}
void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
return;
} }
void SHBatch::Remove(const SHRenderable* renderable) // Check if there are even material properties to update
if (!matPropsData)
return;
// Check if any materials have changed
bool hasChanged = false;
for (const auto& material : referencedMatInstances)
{ {
// Check if we have a SubBatch with the same mesh yet if (material->HasChanged())
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch) {
{ hasChanged = true;
return batch.Mesh == renderable->Mesh; break;
}); }
// Attempt to remove if it exists
if (subBatch == subBatches.end())
return;
subBatch->Renderables.erase(renderable);
// Check if other renderables in subBatches contain the same material instance
bool matUnused = true;
for (const auto& sb : subBatches)
for (const auto& rend : sb.Renderables)
{
if (rend->GetMaterial() == renderable->GetMaterial())
{
matUnused = false;
break;
}
}
// Material is no longer in this library, so we remove it
if (matUnused)
referencedMatInstances.erase(renderable->GetMaterial());
// Mark all as dirty
for (bool& dirt : isDirty)
dirt = true;
} }
void SHBatch::Clear() // We need to update all the material buffers if the materials have changed
if (hasChanged)
{ {
subBatches.clear(); for (auto& dirt : matBufferDirty)
dirt = true;
// Clear CPU buffers
drawData.clear();
transformData.clear();
instancedIntegerData.clear();
matPropsData.reset();
matPropsDataSize = 0;
// Clear GPU buffers
for (int i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{
drawDataBuffer[i].Free();
transformDataBuffer[i].Free();
instancedIntegerBuffer[i].Free();
matPropsBuffer[i].Free();
}
} }
void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) // Check if this frame's buffer is dirty
{ if (!matBufferDirty[frameIndex])
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) return;
{
SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
return;
}
// Check if there are even material properties to update // Build CPU Buffer
if (!matPropsData) char* propsCurrPtr = matPropsData.get();
return; for (auto& subBatch : subBatches)
for (auto rendId : subBatch.Renderables)
// Check if any materials have changed {
bool hasChanged = false; const SHRenderable* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
for (const auto& material : referencedMatInstances) if (renderable)
{ {
if (material->HasChanged()) renderable->GetMaterial()->ExportProperties(propsCurrPtr);
{
hasChanged = true;
break;
}
} }
else
// We need to update all the material buffers if the materials have changed
if (hasChanged)
{ {
for (auto& dirt : matBufferDirty) SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
dirt = true;
} }
propsCurrPtr += singleMatPropAlignedSize;
}
// Check if this frame's buffer is dirty // Transfer to GPU
if (!matBufferDirty[frameIndex]) rebuildMaterialBuffers(frameIndex, descPool);
return;
// Build CPU Buffer // This frame is updated
char* propsCurrPtr = matPropsData.get(); matBufferDirty[frameIndex] = false;
for (auto& subBatch : subBatches) }
for (const SHRenderable* renderable : subBatch.Renderables)
{
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
propsCurrPtr += singleMatPropAlignedSize;
}
// Transfer to GPU void SHBatch::UpdateTransformBuffer(uint32_t frameIndex)
rebuildMaterialBuffers(frameIndex, descPool); {
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
// This frame is updated
matBufferDirty[frameIndex] = false;
}
void SHBatch::UpdateTransformBuffer(uint32_t frameIndex)
{ {
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
{ return;
SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
return;
}
// Reset Transform Data
transformData.clear();
// Populate on the CPU
for (auto& subBatch : subBatches)
for (const SHRenderable* renderable : subBatch.Renderables)
{
// Transform
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(renderable->GetEID());
if (!transform)
{
SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
transformData.emplace_back();
}
else
{
transformData.emplace_back(transform->GetTRS());
}
}
// Transfer to GPU
if (transformDataBuffer[frameIndex])
transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix)), 0, 0);
} }
// Reset Transform Data
transformData.clear();
// Populate on the CPU
for (auto& subBatch : subBatches)
for (auto rendId : subBatch.Renderables)
{
// Transform
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(rendId);
if (transform)
{
transformData.emplace_back(transform->GetTRS());
}
else
{
SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
transformData.emplace_back();
}
}
// Transfer to GPU
if (transformDataBuffer[frameIndex])
transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix)), 0, 0);
}
void SHBatch::UpdateInstancedIntegerBuffer(uint32_t frameIndex) void SHBatch::UpdateInstancedIntegerBuffer(uint32_t frameIndex)
{ {
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
@ -221,11 +236,12 @@ namespace SHADE
// Populate on the CPU // Populate on the CPU
for (auto& subBatch : subBatches) for (auto& subBatch : subBatches)
for (const SHRenderable* renderable : subBatch.Renderables) for (auto rendId : subBatch.Renderables)
{ {
auto* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
instancedIntegerData.emplace_back(SHInstancedIntegerData instancedIntegerData.emplace_back(SHInstancedIntegerData
{ {
renderable->GetEID(), rendId,
renderable->GetLightLayer() renderable->GetLightLayer()
} }
); );
@ -238,213 +254,222 @@ namespace SHADE
} }
void SHBatch::Build(Handle<SHVkLogicalDevice> _device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) void SHBatch::Build(Handle<SHVkLogicalDevice> _device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{ {
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) SHLOG_WARNING("[SHBatch] Attempted to update build batch buffers with an invalid frame index.");
{ return;
SHLOG_WARNING("[SHBatch] Attempted to update build batch buffers with an invalid frame index.");
return;
}
// Save logical device
device = _device;
// No need to build as there are no changes
if (!isDirty[frameIndex])
return;
// Count number of elements
size_t numTotalElements = 0;
for (const auto& subBatch : subBatches)
{
numTotalElements += subBatch.Renderables.size();
}
// Generate CPU buffers if there are changes
if (isCPUBuffersDirty)
{
// - Draw data
drawData.reserve(subBatches.size());
drawData.clear();
// - Transform data
transformData.reserve(numTotalElements);
transformData.clear();
// - EID data
instancedIntegerData.reserve(numTotalElements);
instancedIntegerData.clear();
// - Material Properties Data
const Handle<SHShaderBlockInterface> SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
vk::ShaderStageFlagBits::eFragment
);
const bool EMPTY_MAT_PROPS = !SHADER_INFO;
Byte matPropTotalBytes = 0;
if (!EMPTY_MAT_PROPS)
{
singleMatPropSize = SHADER_INFO->GetBytesRequired();
singleMatPropAlignedSize = device->PadSSBOSize(static_cast<uint32_t>(singleMatPropSize));
matPropTotalBytes = numTotalElements * singleMatPropAlignedSize;
if (matPropsDataSize < matPropTotalBytes)
{
matPropsData.reset(new char[matPropTotalBytes]);
matPropsDataSize = matPropTotalBytes;
}
}
// Build Sub Batches
uint32_t nextInstanceIndex = 0;
char* propsCurrPtr = matPropsData.get();
for (auto& subBatch : subBatches)
{
// Create command
drawData.emplace_back(vk::DrawIndexedIndirectCommand
{
.indexCount = subBatch.Mesh->IndexCount,
.instanceCount = static_cast<uint32_t>(subBatch.Renderables.size()),
.firstIndex = subBatch.Mesh->FirstIndex,
.vertexOffset = subBatch.Mesh->FirstVertex,
.firstInstance = nextInstanceIndex++
});
// Fill in buffers (CPU)
for (const SHRenderable* renderable : subBatch.Renderables)
{
// Transform
EntityID eid = renderable->GetEID();
auto transform = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
if (!transform)
{
SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
transformData.emplace_back();
}
else
{
transformData.emplace_back(transform->GetTRS());
}
instancedIntegerData.emplace_back(SHInstancedIntegerData
{
eid,
renderable->GetLightLayer()
}
);
// Material Properties
if (!EMPTY_MAT_PROPS)
{
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
propsCurrPtr += singleMatPropAlignedSize;
}
}
}
// Successfully update CPU buffers
isCPUBuffersDirty = false;
}
// Send all buffered data to the GPU buffers
using BuffUsage = vk::BufferUsageFlagBits;
// - Draw Data
const uint32_t DRAW_DATA_BYTES = static_cast<uint32_t>(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES,
BuffUsage::eIndirectBuffer
);
// - Transform Buffer
const uint32_t TF_DATA_BYTES = static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
BuffUsage::eVertexBuffer
);
const uint32_t EID_DATA_BYTES = static_cast<uint32_t>(instancedIntegerData.size() * sizeof(SHInstancedIntegerData));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, instancedIntegerBuffer[frameIndex], instancedIntegerData.data(), EID_DATA_BYTES,
BuffUsage::eVertexBuffer
);
// - Material Properties Buffer
rebuildMaterialBuffers(frameIndex, descPool);
// Mark this frame as no longer dirty
isDirty[frameIndex] = false;
} }
/*---------------------------------------------------------------------------------*/ // Save logical device
/* SHBatch - Usage Functions */ device = _device;
/*---------------------------------------------------------------------------------*/
void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to draw a batch with an invalid frame index.");
return;
}
// Bind all required objects before drawing // No need to build as there are no changes
static std::array<uint32_t, 1> dynamicOffset { 0 }; if (!isDirty[frameIndex])
cmdBuffer->BindPipeline(pipeline); return;
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0); // Count number of elements
if (matPropsDescSet[frameIndex]) size_t numTotalElements = 0;
for (const auto& subBatch : subBatches)
{
numTotalElements += subBatch.Renderables.size();
}
// Generate CPU buffers if there are changes
if (isCPUBuffersDirty)
{
// - Draw data
drawData.reserve(subBatches.size());
drawData.clear();
// - Transform data
transformData.reserve(numTotalElements);
transformData.clear();
// - EID data
instancedIntegerData.reserve(numTotalElements);
instancedIntegerData.clear();
// - Material Properties Data
const Handle<SHShaderBlockInterface> SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
vk::ShaderStageFlagBits::eFragment
);
const bool EMPTY_MAT_PROPS = !SHADER_INFO;
Byte matPropTotalBytes = 0;
if (!EMPTY_MAT_PROPS)
{
singleMatPropSize = SHADER_INFO->GetBytesRequired();
singleMatPropAlignedSize = device->PadSSBOSize(static_cast<uint32_t>(singleMatPropSize));
matPropTotalBytes = numTotalElements * singleMatPropAlignedSize;
if (matPropsDataSize < matPropTotalBytes)
{ {
cmdBuffer->BindDescriptorSet matPropsData.reset(new char[matPropTotalBytes]);
( matPropsDataSize = matPropTotalBytes;
matPropsDescSet[frameIndex], }
SH_PIPELINE_TYPE::GRAPHICS, }
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
dynamicOffset // Build Sub Batches
uint32_t nextInstanceIndex = 0;
char* propsCurrPtr = matPropsData.get();
for (auto& subBatch : subBatches)
{
// Create command
const uint32_t CURR_INSTANCES = static_cast<uint32_t>(subBatch.Renderables.size());
drawData.emplace_back(vk::DrawIndexedIndirectCommand
{
.indexCount = subBatch.Mesh->IndexCount,
.instanceCount = CURR_INSTANCES,
.firstIndex = subBatch.Mesh->FirstIndex,
.vertexOffset = subBatch.Mesh->FirstVertex,
.firstInstance = nextInstanceIndex
});
nextInstanceIndex += CURR_INSTANCES;
// Fill in buffers (CPU)
for (auto rendId : subBatch.Renderables)
{
// Transform
auto transform = SHComponentManager::GetComponent_s<SHTransformComponent>(rendId);
if (!transform)
{
SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
transformData.emplace_back();
}
else
{
transformData.emplace_back(transform->GetTRS());
}
const SHRenderable* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
instancedIntegerData.emplace_back(SHInstancedIntegerData
{
rendId,
renderable->GetLightLayer()
}
); );
}
cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
}
/*---------------------------------------------------------------------------------*/ // Material Properties
/* SHBatch - Helper Functions */ if (!EMPTY_MAT_PROPS)
/*---------------------------------------------------------------------------------*/ {
void SHBatch::setAllDirtyFlags() if (renderable)
{
for (bool& dirt : isDirty)
dirt = true;
isCPUBuffersDirty = true;
}
void SHBatch::rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
if (matPropsData)
{
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
vk::BufferUsageFlagBits::eStorageBuffer
);
if (!matPropsDescSet[frameIndex])
{ {
matPropsDescSet[frameIndex] = descPool->Allocate renderable->GetMaterial()->ExportProperties(propsCurrPtr);
(
{ SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE] },
{ 0 }
);
} }
std::array<Handle<SHVkBuffer>, 1> bufferList = { matPropsBuffer[frameIndex] }; else
matPropsDescSet[frameIndex]->ModifyWriteDescBuffer {
( SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, }
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA, propsCurrPtr += singleMatPropAlignedSize;
bufferList, }
0, static_cast<uint32_t>(matPropsDataSize)
);
matPropsDescSet[frameIndex]->UpdateDescriptorSetBuffer
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA
);
} }
}
// Successfully update CPU buffers
isCPUBuffersDirty = false;
} }
// Send all buffered data to the GPU buffers
using BuffUsage = vk::BufferUsageFlagBits;
// - Draw Data
const uint32_t DRAW_DATA_BYTES = static_cast<uint32_t>(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES,
BuffUsage::eIndirectBuffer
);
// - Transform Buffer
const uint32_t TF_DATA_BYTES = static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
BuffUsage::eVertexBuffer
);
const uint32_t EID_DATA_BYTES = static_cast<uint32_t>(instancedIntegerData.size() * sizeof(SHInstancedIntegerData));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, instancedIntegerBuffer[frameIndex], instancedIntegerData.data(), EID_DATA_BYTES,
BuffUsage::eVertexBuffer
);
// - Material Properties Buffer
rebuildMaterialBuffers(frameIndex, descPool);
// Mark this frame as no longer dirty
isDirty[frameIndex] = false;
}
/*---------------------------------------------------------------------------------*/
/* SHBatch - Usage Functions */
/*---------------------------------------------------------------------------------*/
void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
{
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to draw a batch with an invalid frame index.");
return;
}
// Bind all required objects before drawing
static std::array<uint32_t, 1> dynamicOffset{ 0 };
cmdBuffer->BindPipeline(pipeline);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0);
if (matPropsDescSet[frameIndex])
{
cmdBuffer->BindDescriptorSet
(
matPropsDescSet[frameIndex],
SH_PIPELINE_TYPE::GRAPHICS,
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
dynamicOffset
);
}
cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
}
/*---------------------------------------------------------------------------------*/
/* SHBatch - Helper Functions */
/*---------------------------------------------------------------------------------*/
void SHBatch::setAllDirtyFlags()
{
for (bool& dirt : isDirty)
dirt = true;
isCPUBuffersDirty = true;
}
void SHBatch::rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
{
if (matPropsData)
{
SHVkUtil::EnsureBufferAndCopyHostVisibleData
(
device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
vk::BufferUsageFlagBits::eStorageBuffer
);
if (!matPropsDescSet[frameIndex])
{
matPropsDescSet[frameIndex] = descPool->Allocate
(
{ SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE] },
{ 0 }
);
}
std::array<Handle<SHVkBuffer>, 1> bufferList = { matPropsBuffer[frameIndex] };
matPropsDescSet[frameIndex]->ModifyWriteDescBuffer
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
bufferList,
0, static_cast<uint32_t>(matPropsDataSize)
);
matPropsDescSet[frameIndex]->UpdateDescriptorSetBuffer
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA
);
}
}
} }

View File

@ -56,7 +56,7 @@ namespace SHADE
/* Data Members */ /* Data Members */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
Handle<SHMesh> Mesh; Handle<SHMesh> Mesh;
std::unordered_set<const SHRenderable*> Renderables; std::unordered_set<EntityID> Renderables;
}; };
/***********************************************************************************/ /***********************************************************************************/
/*! /*!

View File

@ -700,10 +700,10 @@ namespace SHADE
continue; continue;
// Remove from old material's SuperBatch // Remove from old material's SuperBatch
Handle<SHMaterial> prevMaterial = renderable.GetPrevMaterial(); Handle<SHMaterialInstance> prevMaterial = renderable.GetPrevMaterial();
if (prevMaterial) if (prevMaterial)
{ {
Handle<SHSuperBatch> oldSuperBatch = prevMaterial->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch(); Handle<SHSuperBatch> oldSuperBatch = prevMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
oldSuperBatch->Remove(&renderable); oldSuperBatch->Remove(&renderable);
} }

View File

@ -33,15 +33,16 @@ namespace SHADE
void SHRenderable::OnDestroy() void SHRenderable::OnDestroy()
{ {
// Remove from SuperBatch
Handle<SHSuperBatch> superBatch = sharedMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
superBatch->Remove(this);
// Free resources
if (material) if (material)
{ {
material.Free(); material.Free();
material = {}; material = {};
} }
// Remove from SuperBatch
Handle<SHSuperBatch> superBatch = sharedMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
superBatch->Remove(this);
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -53,17 +54,20 @@ namespace SHADE
if (!material && sharedMaterial == materialInstance) if (!material && sharedMaterial == materialInstance)
return; return;
// Flag that material was changed
materialChanged = true;
// Free copies of materials if any // Free copies of materials if any
if (material) if (material)
{ {
oldMaterial = material;
material.Free(); material.Free();
material = {}; material = {};
} }
else if (sharedMaterial)
// Flag that material was changed {
materialChanged = true; oldMaterial = sharedMaterial;
if (sharedMaterial) }
oldMaterial = sharedMaterial->GetBaseMaterial();
// Update the material // Update the material
sharedMaterial = materialInstance; sharedMaterial = materialInstance;

View File

@ -55,7 +55,7 @@ namespace SHADE
/* Getter Functions */ /* Getter Functions */
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
bool WasMaterialChanged() const noexcept { return materialChanged; } bool WasMaterialChanged() const noexcept { return materialChanged; }
Handle<SHMaterial> GetPrevMaterial() const noexcept { return oldMaterial; } Handle<SHMaterialInstance> GetPrevMaterial() const noexcept { return oldMaterial; }
uint8_t GetLightLayer (void) const noexcept; uint8_t GetLightLayer (void) const noexcept;
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
@ -75,7 +75,7 @@ namespace SHADE
Handle<SHMaterialInstance> sharedMaterial; Handle<SHMaterialInstance> sharedMaterial;
Handle<SHMaterialInstance> material; Handle<SHMaterialInstance> material;
bool materialChanged = true; bool materialChanged = true;
Handle<SHMaterial> oldMaterial; Handle<SHMaterialInstance> oldMaterial;
uint8_t lightLayer; uint8_t lightLayer;
}; };
} }

View File

@ -295,32 +295,33 @@ namespace SHADE
) != 0; ) != 0;
} }
SHMatrix::operator XMMATRIX() const noexcept
{
return XMLoadFloat4x4(this);
}
SHMatrix operator*(float lhs, const SHMatrix& rhs) noexcept SHMatrix operator*(float lhs, const SHMatrix& rhs) noexcept
{ {
return rhs * lhs; return rhs * lhs;
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Function Member Definitions */ /* Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHMatrix::Transpose() noexcept void SHMatrix::Transpose() noexcept
{ {
const XMMATRIX M = XMLoadFloat4x4(this); XMStoreFloat4x4(this, XMMatrixTranspose(*this));
XMStoreFloat4x4(this, XMMatrixTranspose(M));
} }
void SHMatrix::Invert() noexcept void SHMatrix::Invert() noexcept
{ {
const XMMATRIX M = XMLoadFloat4x4(this); XMStoreFloat4x4(this, XMMatrixInverse(nullptr, *this));
XMStoreFloat4x4(this, XMMatrixInverse(nullptr, M));
} }
float SHMatrix::Determinant() const noexcept float SHMatrix::Determinant() const noexcept
{ {
const XMMATRIX M = XMLoadFloat4x4(this); return XMVectorGetX(XMMatrixDeterminant(*this));
return XMVectorGetX(XMMatrixDeterminant(M));
} }
std::string SHMatrix::ToString() const noexcept std::string SHMatrix::ToString() const noexcept
@ -337,9 +338,8 @@ namespace SHADE
bool SHMatrix::Decompose(SHVec3& translation, SHVec3& rotation, SHVec3& scale) const noexcept bool SHMatrix::Decompose(SHVec3& translation, SHVec3& rotation, SHVec3& scale) const noexcept
{ {
XMVECTOR s, r, t; XMVECTOR s, r, t;
const XMMATRIX M = XMLoadFloat4x4(this);
if (!XMMatrixDecompose(&s, &r, &t, M)) if (!XMMatrixDecompose(&s, &r, &t, *this))
return false; return false;
SHQuaternion orientation; SHQuaternion orientation;
@ -356,9 +356,8 @@ namespace SHADE
bool SHMatrix::Decompose(SHVec3& translation, SHQuaternion& orientation, SHVec3& scale) const noexcept bool SHMatrix::Decompose(SHVec3& translation, SHQuaternion& orientation, SHVec3& scale) const noexcept
{ {
XMVECTOR s, r, t; XMVECTOR s, r, t;
const XMMATRIX M = XMLoadFloat4x4(this);
if (!XMMatrixDecompose(&s, &r, &t, M)) if (!XMMatrixDecompose(&s, &r, &t, *this))
return false; return false;
XMStoreFloat3(&scale, s); XMStoreFloat3(&scale, s);
@ -376,8 +375,7 @@ namespace SHADE
{ {
SHMatrix result; SHMatrix result;
const XMMATRIX M = XMLoadFloat4x4(&matrix); XMStoreFloat4x4(&result, XMMatrixTranspose(matrix));
XMStoreFloat4x4(&result, XMMatrixTranspose(M));
return result; return result;
} }
@ -385,8 +383,7 @@ namespace SHADE
{ {
SHMatrix result; SHMatrix result;
const XMMATRIX M = XMLoadFloat4x4(&matrix); XMStoreFloat4x4(&result, XMMatrixInverse(nullptr, matrix));
XMStoreFloat4x4(&result, XMMatrixInverse(nullptr, M));
return result; return result;
} }
@ -401,8 +398,8 @@ namespace SHADE
SHMatrix SHMatrix::Translate(const SHVec3& pos) noexcept SHMatrix SHMatrix::Translate(const SHVec3& pos) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixTranslation(pos.x, pos.y, pos.z));
XMStoreFloat4x4(&result, XMMatrixTranslation(pos.x, pos.y, pos.z));
return result; return result;
} }
@ -410,25 +407,23 @@ namespace SHADE
{ {
SHMatrix result; SHMatrix result;
const XMVECTOR A = XMLoadFloat3(&axis); XMStoreFloat4x4(&result, XMMatrixRotationAxis(axis, angleInRad));
XMStoreFloat4x4(&result, XMMatrixRotationAxis(A, angleInRad));
return result; return result;
} }
SHMatrix SHMatrix::Rotate(float yaw, float pitch, float roll) noexcept SHMatrix SHMatrix::Rotate(float yaw, float pitch, float roll) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(pitch, yaw, roll));
XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(pitch, yaw, roll));
return result; return result;
} }
SHMatrix SHMatrix::Rotate(const SHVec3& eulerAngles) noexcept SHMatrix SHMatrix::Rotate(const SHVec3& eulerAngles) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(eulerAngles.x, eulerAngles.y, eulerAngles.z));
XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYawFromVector(eulerAngles));
return result; return result;
} }
@ -436,57 +431,55 @@ namespace SHADE
{ {
SHMatrix result; SHMatrix result;
const XMVECTOR Q = XMLoadFloat4(&q); XMStoreFloat4x4(&result, XMMatrixRotationQuaternion(q));
XMStoreFloat4x4(&result, XMMatrixRotationQuaternion(Q));
return result; return result;
} }
SHMatrix SHMatrix::RotateX(float angleInRad) noexcept SHMatrix SHMatrix::RotateX(float angleInRad) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixRotationX(angleInRad));
XMStoreFloat4x4(&result, XMMatrixRotationX(angleInRad));
return result; return result;
} }
SHMatrix SHMatrix::RotateY(float angleInRad) noexcept SHMatrix SHMatrix::RotateY(float angleInRad) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixRotationY(angleInRad));
XMStoreFloat4x4(&result, XMMatrixRotationY(angleInRad));
return result; return result;
} }
SHMatrix SHMatrix::RotateZ(float angleInRad) noexcept SHMatrix SHMatrix::RotateZ(float angleInRad) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixRotationZ(angleInRad));
XMStoreFloat4x4(&result, XMMatrixRotationZ(angleInRad));
return result; return result;
} }
SHMatrix SHMatrix::Scale(float uniformScaleFactor) noexcept SHMatrix SHMatrix::Scale(float uniformScaleFactor) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixScaling(uniformScaleFactor, uniformScaleFactor, uniformScaleFactor));
XMStoreFloat4x4(&result, XMMatrixScaling(uniformScaleFactor, uniformScaleFactor, uniformScaleFactor));
return result; return result;
} }
SHMatrix SHMatrix::Scale(float x, float y, float z) noexcept SHMatrix SHMatrix::Scale(float x, float y, float z) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixScaling(x, y, z));
XMStoreFloat4x4(&result, XMMatrixScaling(x, y, z));
return result; return result;
} }
SHMatrix SHMatrix::Scale(const SHVec3& scale) noexcept SHMatrix SHMatrix::Scale(const SHVec3& scale) noexcept
{ {
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixScaling(scale.x, scale.y, scale.z));
XMStoreFloat4x4(&result, XMMatrixScalingFromVector(scale));
return result; return result;
} }
@ -494,12 +487,7 @@ namespace SHADE
{ {
SHMatrix result; SHMatrix result;
const XMVECTOR EYE = XMLoadFloat3(&eye); XMStoreFloat4x4(&result, XMMatrixLookAtRH(eye, target, up));
const XMVECTOR TGT = XMLoadFloat3(&target);
const XMVECTOR UP = XMLoadFloat3(&up);
XMStoreFloat4x4(&result, XMMatrixLookAtRH(EYE, TGT, UP));
return result; return result;
} }
@ -507,12 +495,7 @@ namespace SHADE
{ {
SHMatrix result; SHMatrix result;
const XMVECTOR EYE = XMLoadFloat3(&eye); XMStoreFloat4x4(&result, XMMatrixLookAtLH(eye, target, up));
const XMVECTOR TGT = XMLoadFloat3(&target);
const XMVECTOR UP = XMLoadFloat3(&up);
XMStoreFloat4x4(&result, XMMatrixLookAtLH(EYE, TGT, UP));
return result; return result;
} }
@ -522,8 +505,8 @@ namespace SHADE
const SHVec3 FWD_HAT = SHVec3::Normalise(-forward); const SHVec3 FWD_HAT = SHVec3::Normalise(-forward);
const XMVECTOR Z_HAT = XMVector3Normalize(XMLoadFloat3(&FWD_HAT)); const XMVECTOR Z_HAT = XMVector3Normalize(FWD_HAT);
const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(XMLoadFloat3(&up), Z_HAT)); const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(up, Z_HAT));
const XMVECTOR Y_HAT = XMVector3Cross(Z_HAT, X_HAT); const XMVECTOR Y_HAT = XMVector3Cross(Z_HAT, X_HAT);
XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&result._11), X_HAT); XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&result._11), X_HAT);
@ -543,8 +526,8 @@ namespace SHADE
const SHVec3 FWD_HAT = SHVec3::Normalise(forward); const SHVec3 FWD_HAT = SHVec3::Normalise(forward);
const XMVECTOR Z_HAT = XMVector3Normalize(XMLoadFloat3(&FWD_HAT)); const XMVECTOR Z_HAT = XMVector3Normalize(FWD_HAT);
const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(XMLoadFloat3(&up), Z_HAT)); const XMVECTOR X_HAT = XMVector3Normalize(XMVector3Cross(up, Z_HAT));
const XMVECTOR Y_HAT = XMVector3Cross(Z_HAT, X_HAT); const XMVECTOR Y_HAT = XMVector3Cross(Z_HAT, X_HAT);
XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&result._11), X_HAT); XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&result._11), X_HAT);
@ -563,7 +546,6 @@ namespace SHADE
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixPerspectiveFovRH(fov, aspectRatio, nearPlane, farPlane)); XMStoreFloat4x4(&result, XMMatrixPerspectiveFovRH(fov, aspectRatio, nearPlane, farPlane));
return result; return result;
} }
@ -572,7 +554,6 @@ namespace SHADE
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixPerspectiveFovLH(fov, aspectRatio, nearPlane, farPlane)); XMStoreFloat4x4(&result, XMMatrixPerspectiveFovLH(fov, aspectRatio, nearPlane, farPlane));
return result; return result;
} }
@ -581,7 +562,6 @@ namespace SHADE
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixPerspectiveRH(width, height, nearPlane, farPlane)); XMStoreFloat4x4(&result, XMMatrixPerspectiveRH(width, height, nearPlane, farPlane));
return result; return result;
} }
@ -590,7 +570,6 @@ namespace SHADE
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixPerspectiveLH(width, height, nearPlane, farPlane)); XMStoreFloat4x4(&result, XMMatrixPerspectiveLH(width, height, nearPlane, farPlane));
return result; return result;
} }
@ -599,7 +578,6 @@ namespace SHADE
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixOrthographicRH(width, height, nearPlane, farPlane)); XMStoreFloat4x4(&result, XMMatrixOrthographicRH(width, height, nearPlane, farPlane));
return result; return result;
} }
@ -608,7 +586,6 @@ namespace SHADE
SHMatrix result; SHMatrix result;
XMStoreFloat4x4(&result, XMMatrixOrthographicLH(width, height, nearPlane, farPlane)); XMStoreFloat4x4(&result, XMMatrixOrthographicLH(width, height, nearPlane, farPlane));
return result; return result;
} }

View File

@ -77,6 +77,8 @@ namespace SHADE
SHMatrix& operator= (const SHMatrix& rhs) = default; SHMatrix& operator= (const SHMatrix& rhs) = default;
SHMatrix& operator= (SHMatrix&& rhs) = default; SHMatrix& operator= (SHMatrix&& rhs) = default;
operator DirectX::XMMATRIX () const noexcept;
SHMatrix& operator+= (const SHMatrix& rhs) noexcept; SHMatrix& operator+= (const SHMatrix& rhs) noexcept;
SHMatrix& operator-= (const SHMatrix& rhs) noexcept; SHMatrix& operator-= (const SHMatrix& rhs) noexcept;
SHMatrix& operator*= (const SHMatrix& rhs) noexcept; SHMatrix& operator*= (const SHMatrix& rhs) noexcept;

View File

@ -36,44 +36,18 @@ namespace SHADE
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
{} {}
SHQuaternion::SHQuaternion(const SHVec4& vec4) noexcept
: XMFLOAT4( vec4.x, vec4.y, vec4.z, vec4.w )
{}
SHQuaternion::SHQuaternion(float _x, float _y, float _z, float _w) noexcept SHQuaternion::SHQuaternion(float _x, float _y, float _z, float _w) noexcept
: XMFLOAT4( _x, _y, _z, _w ) : XMFLOAT4( _x, _y, _z, _w )
{} {}
SHQuaternion::SHQuaternion(float yaw, float pitch, float roll) noexcept
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
{
XMStoreFloat4(this, XMQuaternionRotationRollPitchYaw(pitch, yaw, roll));
}
SHQuaternion::SHQuaternion(const SHVec3& eulerAngles) noexcept
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
{
const XMVECTOR V = XMLoadFloat3(&eulerAngles);
XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(V));
}
SHQuaternion::SHQuaternion(const SHVec3& axis, float angleInRad) noexcept
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
{
const XMVECTOR AXIS = XMLoadFloat3(&axis);
XMStoreFloat4(this, XMQuaternionRotationAxis(AXIS, angleInRad));
}
SHQuaternion::SHQuaternion(const SHMatrix& rotationMatrix) noexcept
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
{
const XMMATRIX M = XMLoadFloat4x4(&rotationMatrix);
XMStoreFloat4(this, XMQuaternionRotationMatrix(M));
}
SHQuaternion::SHQuaternion(const reactphysics3d::Vector3& rp3dEuler) noexcept SHQuaternion::SHQuaternion(const reactphysics3d::Vector3& rp3dEuler) noexcept
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
{ {
const SHVec3& SHADE_VEC{ rp3dEuler }; XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(SHVec3 { rp3dEuler }));
const XMVECTOR V = XMLoadFloat3(&SHADE_VEC);
XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(V));
} }
SHQuaternion::SHQuaternion(const reactphysics3d::Quaternion& rp3dQuat) noexcept SHQuaternion::SHQuaternion(const reactphysics3d::Quaternion& rp3dQuat) noexcept
@ -113,10 +87,7 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q1 = XMLoadFloat4(this); XMStoreFloat4(&result, XMVectorAdd(*this, rhs));
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
XMStoreFloat4(&result, XMVectorAdd(Q1, Q2));
return result; return result;
} }
@ -124,10 +95,7 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q1 = XMLoadFloat4(this); XMStoreFloat4(&result, XMVectorSubtract(*this, rhs));
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
XMStoreFloat4(&result, XMVectorSubtract(Q1, Q2));
return result; return result;
} }
@ -135,9 +103,7 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q = XMLoadFloat4(this); XMStoreFloat4(&result, XMVectorNegate(*this));
XMStoreFloat4(&result, XMVectorNegate(Q));
return result; return result;
} }
@ -145,10 +111,7 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q1 = XMLoadFloat4(this); XMStoreFloat4(&result, XMQuaternionMultiply(*this, rhs));
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q2));
return result; return result;
} }
@ -156,9 +119,7 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q = XMLoadFloat4(this); XMStoreFloat4(&result, XMVectorScale(*this, rhs));
XMStoreFloat4(&result, XMVectorScale(Q, rhs));
return result; return result;
} }
@ -166,27 +127,18 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q1 = XMLoadFloat4(this); XMStoreFloat4(&result, XMQuaternionMultiply(*this, XMQuaternionInverse(rhs)));
const XMVECTOR Q2 = XMQuaternionInverse(XMLoadFloat4(&rhs));
XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q2));
return result; return result;
} }
bool SHQuaternion::operator==(const SHQuaternion& rhs) const noexcept bool SHQuaternion::operator==(const SHQuaternion& rhs) const noexcept
{ {
const XMVECTOR Q1 = XMLoadFloat4(this); return XMQuaternionEqual(*this, rhs);
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
return XMQuaternionEqual(Q1, Q2);
} }
bool SHQuaternion::operator!=(const SHQuaternion& rhs) const noexcept bool SHQuaternion::operator!=(const SHQuaternion& rhs) const noexcept
{ {
const XMVECTOR Q1 = XMLoadFloat4(this); return XMQuaternionNotEqual(*this, rhs);
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
return XMQuaternionNotEqual(Q1, Q2);
} }
SHQuaternion::operator reactphysics3d::Quaternion() const noexcept SHQuaternion::operator reactphysics3d::Quaternion() const noexcept
@ -199,6 +151,11 @@ namespace SHADE
return reactphysics3d::Vector3{ ToEuler() }; return reactphysics3d::Vector3{ ToEuler() };
} }
SHQuaternion::operator XMVECTOR() const noexcept
{
return XMLoadFloat4(this);
}
SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept
{ {
return rhs * lhs; return rhs * lhs;
@ -213,8 +170,7 @@ namespace SHADE
XMVECTOR axis; XMVECTOR axis;
float angle; float angle;
const XMVECTOR Q = XMLoadFloat4(this); XMQuaternionToAxisAngle(&axis, &angle, *this);
XMQuaternionToAxisAngle(&axis, &angle, Q);
return angle; return angle;
} }
@ -223,8 +179,7 @@ namespace SHADE
XMVECTOR axis; XMVECTOR axis;
float angle; float angle;
const XMVECTOR Q = XMLoadFloat4(this); XMQuaternionToAxisAngle(&axis, &angle, *this);
XMQuaternionToAxisAngle(&axis, &angle, Q);
return SHVec4{XMVectorGetX(axis), XMVectorGetY(axis), XMVectorGetZ(axis), angle}; return SHVec4{XMVectorGetX(axis), XMVectorGetY(axis), XMVectorGetZ(axis), angle};
@ -238,64 +193,49 @@ namespace SHADE
void SHQuaternion::Invert() noexcept void SHQuaternion::Invert() noexcept
{ {
const XMVECTOR Q = XMLoadFloat4(this); XMStoreFloat4(this, XMQuaternionInverse(*this));
XMStoreFloat4(this, XMQuaternionInverse(Q));
} }
float SHQuaternion::Length() const noexcept float SHQuaternion::Length() const noexcept
{ {
const XMVECTOR Q = XMLoadFloat4(this); return XMVectorGetX(XMQuaternionLength(*this));
return XMVectorGetX(XMQuaternionLength(Q));
} }
float SHQuaternion::LengthSquared() const noexcept float SHQuaternion::LengthSquared() const noexcept
{ {
const XMVECTOR Q = XMLoadFloat4(this); return XMVectorGetX(XMQuaternionLengthSq(*this));
return XMVectorGetX(XMQuaternionLengthSq(Q));
} }
float SHQuaternion::Dot(const SHQuaternion& rhs) const noexcept float SHQuaternion::Dot(const SHQuaternion& rhs) const noexcept
{ {
const XMVECTOR Q1 = XMLoadFloat4(this); return XMVectorGetX(XMQuaternionDot(*this, rhs));
const XMVECTOR Q2 = XMLoadFloat4(&rhs);
return XMVectorGetX(XMQuaternionDot(Q1, Q2));
}
SHQuaternion SHQuaternion::RotateTowards(const SHQuaternion&, float) const noexcept
{
SHQuaternion result;
// TODO (Diren)
return result;
} }
SHVec3 SHQuaternion::ToEuler() const noexcept SHVec3 SHQuaternion::ToEuler() const noexcept
{ {
const float xx = x * x; const float XX = x * x;
const float yy = y * y; const float YY = y * y;
const float zz = z * z; const float ZZ = z * z;
const float m31 = 2.f * x * z + 2.f * y * w; const float M_31 = 2.f * x * z + 2.f * y * w;
const float m32 = 2.f * y * z - 2.f * x * w; const float M_32 = 2.f * y * z - 2.f * x * w;
const float m33 = 1.f - 2.f * xx - 2.f * yy; const float M_33 = 1.f - 2.f * XX - 2.f * YY;
const float cy = sqrtf(m33 * m33 + m31 * m31); const float CY = sqrtf(M_33 * M_33 + M_31 * M_31);
const float cx = atan2f(-m32, cy); const float CX = atan2f(-M_32, CY);
if (cy > 16.0f * SHMath::EPSILON) if (CY > 16.0f * SHMath::EPSILON)
{ {
const float m12 = 2.f * x * y + 2.f * z * w; const float M_12 = 2.f * x * y + 2.f * z * w;
const float m22 = 1.f - 2.f * xx - 2.f * zz; const float M_22 = 1.f - 2.f * XX - 2.f * ZZ;
return SHVec3(cx, atan2f(m31, m33), atan2f(m12, m22)); return SHVec3(CX, atan2f(M_31, M_33), atan2f(M_12, M_22));
} }
else else
{ {
const float m11 = 1.f - 2.f * yy - 2.f * zz; const float m11 = 1.f - 2.f * YY - 2.f * ZZ;
const float m21 = 2.f * x * y - 2.f * z * w; const float m21 = 2.f * x * y - 2.f * z * w;
return SHVec3(cx, 0.f, atan2f(-m21, m11)); return SHVec3(CX, 0.f, atan2f(-m21, m11));
} }
} }
@ -311,13 +251,43 @@ namespace SHADE
/* Static Function Member Definitions */ /* Static Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHQuaternion SHQuaternion::FromEuler(const SHVec3& eulerAngles) noexcept
{
SHQuaternion result;
XMStoreFloat4(&result, XMQuaternionRotationRollPitchYawFromVector(eulerAngles));
return result;
}
SHQuaternion SHQuaternion::FromPitchYawRoll(float pitch, float yaw, float roll) noexcept
{
SHQuaternion result;
XMStoreFloat4(&result, XMQuaternionRotationRollPitchYaw(pitch, yaw, roll));
return result;
}
SHQuaternion SHQuaternion::FromAxisAngle(const SHVec3& axis, float angle) noexcept
{
SHQuaternion result;
XMStoreFloat4(&result, XMQuaternionRotationAxis(axis, angle));
return result;
}
SHQuaternion SHQuaternion::FromRotationMatrix(const SHMatrix& rotationMatrix) noexcept
{
SHQuaternion result;
XMStoreFloat4(&result, XMQuaternionRotationMatrix(rotationMatrix));
return result;
}
SHQuaternion SHQuaternion::Normalise(const SHQuaternion& q) noexcept SHQuaternion SHQuaternion::Normalise(const SHQuaternion& q) noexcept
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q = XMLoadFloat4(&q); XMStoreFloat4(&result, XMQuaternionNormalize(q));
XMStoreFloat4(&result, XMQuaternionNormalize(Q));
return result; return result;
} }
@ -325,9 +295,7 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q = XMLoadFloat4(&q); XMStoreFloat4(&result, XMQuaternionConjugate(q));
XMStoreFloat4(&result, XMQuaternionConjugate(Q));
return result; return result;
} }
@ -335,26 +303,37 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q = XMLoadFloat4(&q); XMStoreFloat4(&result, XMQuaternionInverse(q));
XMStoreFloat4(&result, XMQuaternionInverse(Q));
return result; return result;
} }
float SHQuaternion::Angle(const SHQuaternion&, const SHQuaternion&) noexcept float SHQuaternion::Angle(const SHQuaternion& q1, const SHQuaternion& q2) noexcept
{ {
// TODO (Diren) XMVECTOR R = XMQuaternionMultiply(XMQuaternionConjugate(q1), q2);
return 0.0f; const float RS = XMVectorGetW(R);
R = XMVector3Length(R);
return 2.0f * atan2f(XMVectorGetX(R), RS);
} }
SHQuaternion SHQuaternion::Lerp(const SHQuaternion&, const SHQuaternion&, float) noexcept SHQuaternion SHQuaternion::Lerp(const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept
{ {
SHQuaternion result; SHQuaternion result;
// TODO (Diren) XMVECTOR R = XMVectorZero();
if (XMVector4GreaterOrEqual(XMVector4Dot(q1, q2), R))
{
R = XMVectorLerp(q1, q2, t);
}
else
{
const XMVECTOR X0 = XMVectorMultiply(q1, XMVectorReplicate(1.f - t));
const XMVECTOR X1 = XMVectorMultiply(q2, XMVectorReplicate(t));
R = XMVectorSubtract(X0, X1);
}
XMStoreFloat4(&result, XMQuaternionNormalize(R));
return result; return result;
} }
@ -362,19 +341,105 @@ namespace SHADE
{ {
SHQuaternion result; SHQuaternion result;
const XMVECTOR Q1 = XMLoadFloat4(&q1); XMStoreFloat4(&result, XMQuaternionSlerp(q1, q2, t));
const XMVECTOR Q2 = XMLoadFloat4(&q2);
XMStoreFloat4(&result, XMQuaternionSlerp(Q1, Q2, t));
return result; return result;
} }
SHQuaternion SHQuaternion::Rotate(const SHVec3& , const SHVec3&) noexcept SHQuaternion SHQuaternion::ClampedLerp(const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin, float tMax) noexcept
{
return Lerp(q1, q2, std::clamp(t, tMin, tMax));
}
SHQuaternion SHQuaternion::ClampedSlerp(const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin, float tMax) noexcept
{
return Slerp(q1, q2, std::clamp(t, tMin, tMax));
}
SHQuaternion SHQuaternion::FromToRotation(const SHVec3& from, const SHVec3& to) noexcept
{
// Melax, "The Shortest Arc Quaternion", Game Programming Gems
SHQuaternion result;
const XMVECTOR F = XMVector3Normalize(from);
const XMVECTOR T = XMVector3Normalize(to);
const float dot = XMVectorGetX(XMVector3Dot(F, T));
if (dot >= 1.f)
{
result = Identity;
}
else if (dot <= -1.f)
{
XMVECTOR axis = XMVector3Cross(F, SHVec3::Right);
if (XMVector3NearEqual(XMVector3LengthSq(axis), g_XMZero, g_XMEpsilon))
{
axis = XMVector3Cross(F, SHVec3::Up);
}
const XMVECTOR Q = XMQuaternionRotationAxis(axis, XM_PI);
XMStoreFloat4(&result, Q);
}
else
{
const XMVECTOR C = XMVector3Cross(F, T);
XMStoreFloat4(&result, C);
const float s = sqrtf((1.f + dot) * 2.f);
result.x /= s;
result.y /= s;
result.z /= s;
result.w = s * 0.5f;
}
return result;
}
SHQuaternion SHQuaternion::LookRotation(const SHVec3& forward, const SHVec3& up) noexcept
{ {
SHQuaternion result; SHQuaternion result;
// TODO (Diren) const SHQuaternion Q1 = FromToRotation(SHVec3::Forward, forward);
const XMVECTOR C = XMVector3Cross(forward, up);
if (XMVector3NearEqual(XMVector3LengthSq(C), g_XMZero, g_XMEpsilon))
{
// forward and up are co-linear
return Q1;
}
SHVec3 qU;
XMStoreFloat3(&qU, XMQuaternionMultiply(Q1, SHVec3::Up));
const SHQuaternion Q2 = FromToRotation(qU, up);
XMStoreFloat4(&result, XMQuaternionMultiply(Q2, Q1));
return result;
}
SHQuaternion SHQuaternion::RotateTowards(const SHQuaternion& from, const SHQuaternion& to, float maxAngleInRad) noexcept
{
SHQuaternion result;
// We can use the conjugate here instead of inverse assuming q1 & q2 are normalized.
const XMVECTOR R = XMQuaternionMultiply(XMQuaternionConjugate(from), to);
const float RS = XMVectorGetW(R);
const XMVECTOR L = XMVector3Length(R);
const float angle = 2.f * atan2f(XMVectorGetX(L), RS);
if (angle > maxAngleInRad)
{
const XMVECTOR delta = XMQuaternionRotationAxis(R, maxAngleInRad);
const XMVECTOR Q = XMQuaternionMultiply(delta, from);
XMStoreFloat4(&result, Q);
}
else
{
// Don't overshoot.
result = to;
}
return result; return result;
} }

View File

@ -49,11 +49,8 @@ namespace SHADE
SHQuaternion (SHQuaternion&& rhs) = default; SHQuaternion (SHQuaternion&& rhs) = default;
SHQuaternion () noexcept; SHQuaternion () noexcept;
SHQuaternion (const SHVec4& vec4) noexcept;
SHQuaternion (float x, float y, float z, float w) noexcept; SHQuaternion (float x, float y, float z, float w) noexcept;
SHQuaternion (float yaw, float pitch, float roll) noexcept;
SHQuaternion (const SHVec3& eulerAngles) noexcept;
SHQuaternion (const SHVec3& axis, float angleInRad) noexcept;
SHQuaternion (const SHMatrix& rotationMatrix) noexcept;
// Conversion from other math types // Conversion from other math types
@ -87,6 +84,7 @@ namespace SHADE
operator reactphysics3d::Quaternion () const noexcept; operator reactphysics3d::Quaternion () const noexcept;
operator reactphysics3d::Vector3 () const noexcept; operator reactphysics3d::Vector3 () const noexcept;
operator DirectX::XMVECTOR () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */
@ -99,29 +97,37 @@ namespace SHADE
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void Invert () noexcept; void Invert () noexcept;
[[nodiscard]] float Length () const noexcept; [[nodiscard]] float Length () const noexcept;
[[nodiscard]] float LengthSquared () const noexcept; [[nodiscard]] float LengthSquared () const noexcept;
[[nodiscard]] float Dot (const SHQuaternion& rhs) const noexcept; [[nodiscard]] float Dot (const SHQuaternion& rhs) const noexcept;
[[nodiscard]] SHQuaternion RotateTowards (const SHQuaternion& target, float maxAngleInRad) const noexcept;
[[nodiscard]] SHVec3 ToEuler () const noexcept; [[nodiscard]] SHVec3 ToEuler () const noexcept;
[[nodiscard]] std::string ToString () const noexcept; [[nodiscard]] std::string ToString () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Static Function Members */ /* Static Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] static SHQuaternion Normalise (const SHQuaternion& q) noexcept; [[nodiscard]] static SHQuaternion FromEuler (const SHVec3& eulerAngles) noexcept;
[[nodiscard]] static SHQuaternion Conjugate (const SHQuaternion& q) noexcept; [[nodiscard]] static SHQuaternion FromPitchYawRoll (float pitch, float yaw, float roll) noexcept;
[[nodiscard]] static SHQuaternion Inverse (const SHQuaternion& q) noexcept; [[nodiscard]] static SHQuaternion FromAxisAngle (const SHVec3& axis, float angle) noexcept;
[[nodiscard]] static float Angle (const SHQuaternion& q1, const SHQuaternion& q2) noexcept; [[nodiscard]] static SHQuaternion FromRotationMatrix(const SHMatrix& rotationMatrix) noexcept;
[[nodiscard]] static SHQuaternion Lerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept; [[nodiscard]] static SHQuaternion Normalise (const SHQuaternion& q) noexcept;
[[nodiscard]] static SHQuaternion Slerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept; [[nodiscard]] static SHQuaternion Conjugate (const SHQuaternion& q) noexcept;
[[nodiscard]] static SHQuaternion Inverse (const SHQuaternion& q) noexcept;
[[nodiscard]] static float Angle (const SHQuaternion& q1, const SHQuaternion& q2) noexcept;
[[nodiscard]] static SHQuaternion Rotate (const SHVec3& from, const SHVec3& to) noexcept; [[nodiscard]] static SHQuaternion Lerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept;
[[nodiscard]] static SHQuaternion Slerp (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept;
[[nodiscard]] static SHQuaternion ClampedLerp (const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept;
[[nodiscard]] static SHQuaternion ClampedSlerp (const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept;
[[nodiscard]] static SHQuaternion FromToRotation (const SHVec3& from, const SHVec3& to) noexcept;
[[nodiscard]] static SHQuaternion LookRotation (const SHVec3& forward, const SHVec3& up) noexcept;
[[nodiscard]] static SHQuaternion RotateTowards (const SHQuaternion& from, const SHQuaternion& to, float maxAngleInRad) noexcept;
}; };
SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept; SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept;

View File

@ -26,15 +26,15 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHTransform::SHTransform() noexcept SHTransform::SHTransform() noexcept
: position { SHVec3::Zero } : position { SHVec3::Zero }
, rotation { SHVec3::Zero } , orientation { SHQuaternion::Identity }
, scale { SHVec3::One } , scale { SHVec3::One }
{} {}
SHTransform::SHTransform(const SHVec3& pos, const SHVec3& rot, const SHVec3& scl) noexcept SHTransform::SHTransform(const SHVec3& pos, const SHVec3& rot, const SHVec3& scl) noexcept
: position { pos } : position { pos }
, rotation { rot } , orientation { SHQuaternion::FromEuler(rot) }
, scale { scl } , scale { scl }
{} {}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -43,12 +43,12 @@ namespace SHADE
bool SHTransform::operator==(const SHTransform& rhs) const noexcept bool SHTransform::operator==(const SHTransform& rhs) const noexcept
{ {
return !(position != rhs.position || rotation != rhs.rotation || scale != rhs.scale); return !(position != rhs.position || orientation != rhs.orientation || scale != rhs.scale);
} }
bool SHTransform::operator!=(const SHTransform& rhs) const noexcept bool SHTransform::operator!=(const SHTransform& rhs) const noexcept
{ {
return (position != rhs.position || rotation != rhs.rotation || scale != rhs.scale); return (position != rhs.position || orientation != rhs.orientation || scale != rhs.scale);
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -59,7 +59,7 @@ namespace SHADE
{ {
const SHMatrix T = SHMatrix::Translate(position); const SHMatrix T = SHMatrix::Translate(position);
const SHMatrix R = SHMatrix::Rotate(rotation); const SHMatrix R = SHMatrix::Rotate(orientation);
const SHMatrix S = SHMatrix::Scale(scale); const SHMatrix S = SHMatrix::Scale(scale);
trs = S * R * T; trs = S * R * T;

View File

@ -12,8 +12,8 @@
// Project Headers // Project Headers
#include "SH_API.h" #include "SH_API.h"
#include "Math/Vector/SHVec2.h"
#include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec3.h"
#include "Math/SHQuaternion.h"
#include "Math/SHMatrix.h" #include "Math/SHMatrix.h"
namespace SHADE namespace SHADE
@ -31,22 +31,23 @@ namespace SHADE
static const SHTransform Identity; static const SHTransform Identity;
SHVec3 position; SHVec3 position;
SHVec3 rotation; SHQuaternion orientation;
SHVec3 scale; SHVec3 scale;
SHMatrix trs; SHMatrix trs;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */ /* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHTransform (const SHTransform&) = default; SHTransform (const SHTransform&) = default;
SHTransform (SHTransform&&) = default; SHTransform (SHTransform&&) = default;
~SHTransform () = default; ~SHTransform () = default;
SHTransform () noexcept; SHTransform () noexcept;
SHTransform (const SHVec3& pos, const SHVec3& rot, const SHVec3& scl) noexcept; SHTransform (const SHVec3& pos, const SHVec3& rot, const SHVec3& scl) noexcept;
SHTransform (const SHVec3& pos, const SHQuaternion& quat, const SHVec3& scl) noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Operator Overloads */ /* Operator Overloads */
@ -63,7 +64,6 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
const SHMatrix& ComputeTRS(); const SHMatrix& ComputeTRS();
}; };
} // namespace SHADE } // namespace SHADE

View File

@ -12,6 +12,8 @@
// Primary Header // Primary Header
#include "SHTransformComponent.h" #include "SHTransformComponent.h"
// Project Headers
#include "Math/SHMathHelpers.h"
namespace SHADE namespace SHADE
{ {
@ -40,7 +42,12 @@ namespace SHADE
const SHVec3& SHTransformComponent::GetLocalRotation() const noexcept const SHVec3& SHTransformComponent::GetLocalRotation() const noexcept
{ {
return local.rotation; return localRotation;
}
const SHQuaternion& SHTransformComponent::GetLocalOrientation() const noexcept
{
return local.orientation;
} }
const SHVec3& SHTransformComponent::GetLocalScale() const noexcept const SHVec3& SHTransformComponent::GetLocalScale() const noexcept
@ -55,7 +62,12 @@ namespace SHADE
const SHVec3& SHTransformComponent::GetWorldRotation() const noexcept const SHVec3& SHTransformComponent::GetWorldRotation() const noexcept
{ {
return world.rotation; return worldRotation;
}
const SHQuaternion& SHTransformComponent::GetWorldOrientation() const noexcept
{
return world.orientation;
} }
const SHVec3& SHTransformComponent::GetWorldScale() const noexcept const SHVec3& SHTransformComponent::GetWorldScale() const noexcept
@ -91,16 +103,28 @@ namespace SHADE
void SHTransformComponent::SetLocalRotation(const SHVec3& newLocalRotation) noexcept void SHTransformComponent::SetLocalRotation(const SHVec3& newLocalRotation) noexcept
{ {
dirty = true; dirty = true;
local.rotation = newLocalRotation;
localRotation = newLocalRotation;
updateQueue.push({ UpdateCommandType::LOCAL_ROTATION, newLocalRotation });
} }
void SHTransformComponent::SetLocalRotation(float pitch, float yaw, float roll) noexcept void SHTransformComponent::SetLocalRotation(float pitch, float yaw, float roll) noexcept
{ {
dirty = true; dirty = true;
local.rotation.x = pitch; localRotation.x = pitch;
local.rotation.y = yaw; localRotation.y = yaw;
local.rotation.z = roll; localRotation.z = roll;
updateQueue.push({ UpdateCommandType::LOCAL_ROTATION, SHVec3{pitch, yaw, roll} });
}
void SHTransformComponent::SetLocalOrientation(const SHQuaternion& newLocalOrientation) noexcept
{
dirty = true;
local.orientation = newLocalOrientation;
updateQueue.push({ UpdateCommandType::LOCAL_ORIENTATION, newLocalOrientation });
} }
void SHTransformComponent::SetLocalScale(const SHVec3& newLocalScale) noexcept void SHTransformComponent::SetLocalScale(const SHVec3& newLocalScale) noexcept
@ -121,7 +145,7 @@ namespace SHADE
{ {
dirty = true; dirty = true;
world.rotation = newWorldRotation; worldRotation = newWorldRotation;
updateQueue.push({ UpdateCommandType::WORLD_ROTATION, newWorldRotation }); updateQueue.push({ UpdateCommandType::WORLD_ROTATION, newWorldRotation });
} }
@ -129,13 +153,21 @@ namespace SHADE
{ {
dirty = true; dirty = true;
world.rotation.x = pitch; worldRotation.x = pitch;
world.rotation.y = yaw; worldRotation.y = yaw;
world.rotation.z = roll; worldRotation.z = roll;
updateQueue.push({ UpdateCommandType::WORLD_ROTATION, SHVec3{ pitch, yaw, roll} }); updateQueue.push({ UpdateCommandType::WORLD_ROTATION, SHVec3{ pitch, yaw, roll} });
} }
void SHTransformComponent::SetWorldOrientation(const SHQuaternion& newWorldOrientation) noexcept
{
dirty = true;
world.orientation = newWorldOrientation;
updateQueue.push({ UpdateCommandType::WORLD_ORIENTATION, newWorldOrientation });
}
void SHTransformComponent::SetWorldScale(const SHVec3& newWorldScale) noexcept void SHTransformComponent::SetWorldScale(const SHVec3& newWorldScale) noexcept
{ {
dirty = true; dirty = true;
@ -153,6 +185,6 @@ RTTR_REGISTRATION
registration::class_<SHTransformComponent>("Transform Component") registration::class_<SHTransformComponent>("Transform Component")
.property("Translate" , &SHTransformComponent::GetLocalPosition , &SHTransformComponent::SetLocalPosition ) .property("Translate" , &SHTransformComponent::GetLocalPosition , &SHTransformComponent::SetLocalPosition )
.property("Rotate" , &SHTransformComponent::GetLocalRotation , select_overload<void(SHVec3 const&)>(&SHTransformComponent::SetLocalRotation) ) .property("Rotate" , &SHTransformComponent::GetLocalRotation , select_overload<void(const SHVec3&)>(&SHTransformComponent::SetLocalRotation) )
.property("Scale" , &SHTransformComponent::GetLocalScale , &SHTransformComponent::SetLocalScale ); .property("Scale" , &SHTransformComponent::GetLocalScale , &SHTransformComponent::SetLocalScale );
} }

View File

@ -56,42 +56,52 @@ namespace SHADE
/* Getter Functions */ /* Getter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] bool HasChanged () const noexcept; [[nodiscard]] bool HasChanged () const noexcept;
[[nodiscard]] const SHVec3& GetLocalPosition () const noexcept; [[nodiscard]] const SHVec3& GetLocalPosition () const noexcept;
[[nodiscard]] const SHVec3& GetLocalRotation () const noexcept; [[nodiscard]] const SHVec3& GetLocalRotation () const noexcept;
[[nodiscard]] const SHVec3& GetLocalScale () const noexcept; [[nodiscard]] const SHQuaternion& GetLocalOrientation () const noexcept;
[[nodiscard]] const SHVec3& GetWorldPosition () const noexcept; [[nodiscard]] const SHVec3& GetLocalScale () const noexcept;
[[nodiscard]] const SHVec3& GetWorldRotation () const noexcept; [[nodiscard]] const SHVec3& GetWorldPosition () const noexcept;
[[nodiscard]] const SHVec3& GetWorldScale () const noexcept; [[nodiscard]] const SHVec3& GetWorldRotation () const noexcept;
[[nodiscard]] const SHQuaternion& GetWorldOrientation () const noexcept;
[[nodiscard]] const SHVec3& GetWorldScale () const noexcept;
[[nodiscard]] const SHMatrix& GetLocalToWorld () const noexcept; [[nodiscard]] const SHMatrix& GetLocalToWorld () const noexcept;
[[nodiscard]] SHMatrix GetWorldToLocal () const noexcept; [[nodiscard]] SHMatrix GetWorldToLocal () const noexcept;
[[nodiscard]] const SHMatrix& GetTRS () const noexcept; [[nodiscard]] const SHMatrix& GetTRS () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Setter Functions */ /* Setter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SetLocalPosition (const SHVec3& newLocalPosition) noexcept; void SetLocalPosition (const SHVec3& newLocalPosition) noexcept;
void SetLocalRotation (const SHVec3& newLocalRotation) noexcept; void SetLocalRotation (const SHVec3& newLocalRotation) noexcept;
void SetLocalRotation (float pitch, float yaw, float roll) noexcept; void SetLocalRotation (float pitch, float yaw, float roll) noexcept;
void SetLocalScale (const SHVec3& newLocalScale) noexcept; void SetLocalOrientation (const SHQuaternion& newLocalOrientation) noexcept;
void SetWorldPosition (const SHVec3& newWorldPosition) noexcept; void SetLocalScale (const SHVec3& newLocalScale) noexcept;
void SetWorldRotation (const SHVec3& newWorldRotation) noexcept; void SetWorldPosition (const SHVec3& newWorldPosition) noexcept;
void SetWorldRotation (float pitch, float yaw, float roll) noexcept; void SetWorldRotation (const SHVec3& newWorldRotation) noexcept;
void SetWorldScale (const SHVec3& newWorldScale) noexcept; void SetWorldRotation (float pitch, float yaw, float roll) noexcept;
void SetWorldOrientation (const SHQuaternion& newWorldOrientation) noexcept;
void SetWorldScale (const SHVec3& newWorldScale) noexcept;
private: private:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
// Differentiate between rotation and orientation for setters
// Setting a quaternion directly is different from using euler angle rotations.
enum class UpdateCommandType enum class UpdateCommandType
{ {
WORLD_POSITION LOCAL_ROTATION
, LOCAL_ORIENTATION
, WORLD_POSITION
, WORLD_ROTATION , WORLD_ROTATION
, WORLD_ORIENTATION
, WORLD_SCALE , WORLD_SCALE
}; };
@ -103,7 +113,7 @@ namespace SHADE
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
UpdateCommandType type; UpdateCommandType type;
SHVec3 data; SHVec4 data;
}; };
using UpdateQueue = std::queue<UpdateCommand>; using UpdateQueue = std::queue<UpdateCommand>;
@ -114,6 +124,12 @@ namespace SHADE
bool dirty; bool dirty;
// We store euler angle rotations separately to interface with transform quaternions.
// Reading quaternions are unreliable.
SHVec3 localRotation; // Stored in Radians
SHVec3 worldRotation; // Stored in Radians
SHTransform local; // Local TRS holds Local To World Transform SHTransform local; // Local TRS holds Local To World Transform
SHTransform world; SHTransform world;

View File

@ -17,7 +17,8 @@
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
#include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHEntityManager.h"
#include "Tools/SHException.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Math/SHMathHelpers.h"
namespace SHADE namespace SHADE
{ {
@ -29,8 +30,12 @@ namespace SHADE
/* Constructors & Destructor Definitions */ /* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHTransformSystem::TransformUpdateRoutine::TransformUpdateRoutine() SHTransformSystem::TransformPostLogicUpdate::TransformPostLogicUpdate()
: SHSystemRoutine { "Transform Update", true } : SHSystemRoutine { "Transform Post-Logic Update", true }
{}
SHTransformSystem::TransformPostPhysicsUpdate::TransformPostPhysicsUpdate()
: SHSystemRoutine { "Transform Post-Physics Update", false }
{} {}
@ -38,16 +43,27 @@ namespace SHADE
/* Public Function Member Definitions */ /* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHTransformSystem::TransformUpdateRoutine::Execute(double) noexcept void SHTransformSystem::TransformPostLogicUpdate::Execute(double) noexcept
{ {
// Get the current scene graph to traverse and update // Get the current scene graph to traverse and update
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph(); const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
UpdateEntity(SCENE_GRAPH.GetRoot());
// TODO(Diren): Consider how to clear dirty in pause / stop mode and update physics, but do not clear in play mode.
UpdateEntity(SCENE_GRAPH.GetRoot(), false);
}
void SHTransformSystem::TransformPostPhysicsUpdate::Execute(double) noexcept
{
// Get the current scene graph to traverse and update
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
UpdateEntity(SCENE_GRAPH.GetRoot(), true);
} }
void SHTransformSystem::Init() void SHTransformSystem::Init()
{ {
std::shared_ptr thisReceiver { std::make_shared<SHEventReceiverSpec<SHTransformSystem>>(this, &SHTransformSystem::ChangeParent) };
ReceiverPtr receiver = std::dynamic_pointer_cast<SHEventReceiver>(thisReceiver);
SHEventManager::SubscribeTo(SH_SCENEGRAPH_CHANGE_PARENT_EVENT, receiver);
} }
void SHTransformSystem::Exit() void SHTransformSystem::Exit()
@ -59,7 +75,97 @@ namespace SHADE
/* Private Function Member Definitions */ /* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHTransformSystem::UpdateEntity(const SHSceneNode* node) SHEventHandle SHTransformSystem::ChangeParent(SHEventPtr changeParentEvent)
{
const auto& eventData = reinterpret_cast<const SHEventSpec<SHSceneGraphChangeParentEvent>*>(changeParentEvent.get());
auto* node = eventData->data->node;
auto* tf = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID());
// Recompute local transform and store localToWorld Matrix
SHMatrix localToWorld = SHMatrix::Identity;
SHMatrix worldToLocal = SHMatrix::Identity;
auto* newParent = eventData->data->newParent;
const auto* PARENT_TF = SHComponentManager::GetComponent_s<SHTransformComponent>(newParent->GetEntityID());
if (PARENT_TF != nullptr) // Not the root
{
localToWorld = PARENT_TF->GetTRS();
worldToLocal = SHMatrix::Inverse(localToWorld);
}
// Maintain World Transform and recompute Local Transform
// Compute Local Position
tf->local.position = SHVec3::Transform(tf->world.position, worldToLocal);
tf->localRotation = tf->worldRotation;
tf->local.scale = tf->world.scale;
if (PARENT_TF != nullptr)
{
// Compute Local Rotation
tf->localRotation -= PARENT_TF->GetLocalRotation();
// Compute Local Scale
tf->local.scale /= PARENT_TF->GetLocalScale();
}
tf->local.trs = localToWorld;
// Propagate maintaining world transform down the branch
UpdateChildrenLocalTransforms(node);
return eventData->handle;
}
void SHTransformSystem::UpdateChildrenLocalTransforms(SHSceneNode* node)
{
// Structure is similar to update entity, albeit without a queue to do being a forced update
for (const auto* child : node->GetChildren())
{
if (auto* childTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(child->GetEntityID()); childTransform)
{
const bool IS_NODE_ACTIVE = child->IsActive();
if (IS_NODE_ACTIVE && childTransform->isActive)
{
// Recompute local transform and store localToWorld Matrix
SHMatrix localToWorld = SHMatrix::Identity;
SHMatrix worldToLocal = SHMatrix::Identity;
const auto* parent = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID());
if (parent != nullptr) // Not the root
{
localToWorld = parent->GetTRS();
worldToLocal = SHMatrix::Inverse(localToWorld);
}
// Maintain World Transform and recompute Local Transform
// Compute Local Position
childTransform->local.position = SHVec3::Transform(childTransform->world.position, worldToLocal);
childTransform->localRotation = childTransform->worldRotation;
childTransform->local.scale = childTransform->world.scale;
if (parent)
{
// Compute Local Rotation
childTransform->localRotation -= parent->GetLocalRotation();
// Compute Local Scale
childTransform->local.scale /= parent->GetLocalScale();
}
childTransform->local.trs = localToWorld;
}
}
}
}
void SHTransformSystem::UpdateEntity(const SHSceneNode* node, bool clearDirtyFlag)
{ {
const auto* NODE_TRANSFORM = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID()); const auto* NODE_TRANSFORM = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID());
const bool HAS_PARENT_CHANGED = NODE_TRANSFORM && NODE_TRANSFORM->dirty; const bool HAS_PARENT_CHANGED = NODE_TRANSFORM && NODE_TRANSFORM->dirty;
@ -74,14 +180,17 @@ namespace SHADE
if (IS_NODE_ACTIVE && childTransform->isActive) if (IS_NODE_ACTIVE && childTransform->isActive)
{ {
if (childTransform->dirty || HAS_PARENT_CHANGED) if (childTransform->dirty || HAS_PARENT_CHANGED)
{
UpdateTransform(*childTransform, NODE_TRANSFORM); UpdateTransform(*childTransform, NODE_TRANSFORM);
childTransform->dirty = true;
}
} }
} }
UpdateEntity(child); UpdateEntity(child, clearDirtyFlag);
// Clear dirty flag after all children are updated // Clear dirty flag after all children are updated
if (childTransform) if (childTransform && clearDirtyFlag)
childTransform->dirty = false; childTransform->dirty = false;
} }
} }
@ -91,6 +200,8 @@ namespace SHADE
SHMatrix localToWorld = SHMatrix::Identity; SHMatrix localToWorld = SHMatrix::Identity;
SHMatrix worldToLocal = SHMatrix::Identity; SHMatrix worldToLocal = SHMatrix::Identity;
bool convertRotation = true;
if (parent) if (parent)
{ {
localToWorld = parent->GetTRS(); localToWorld = parent->GetTRS();
@ -103,22 +214,44 @@ namespace SHADE
switch (UPDATE_COMMAND.type) switch (UPDATE_COMMAND.type)
{ {
case SHTransformComponent::UpdateCommandType::LOCAL_ROTATION:
{
convertRotation = true;
break;
}
case SHTransformComponent::UpdateCommandType::LOCAL_ORIENTATION:
{
convertRotation = false;
break;
}
case SHTransformComponent::UpdateCommandType::WORLD_POSITION: case SHTransformComponent::UpdateCommandType::WORLD_POSITION:
{ {
tf.local.position = SHVec3::Transform(UPDATE_COMMAND.data, worldToLocal); tf.local.position = SHVec3::Transform(UPDATE_COMMAND.data.ToVec3(), worldToLocal);
break; break;
} }
case SHTransformComponent::UpdateCommandType::WORLD_ROTATION: case SHTransformComponent::UpdateCommandType::WORLD_ROTATION:
{ {
tf.local.rotation = tf.world.rotation; tf.localRotation = UPDATE_COMMAND.data.ToVec3();
if (parent) if (parent)
tf.local.rotation -= parent->GetLocalRotation(); tf.localRotation -= parent->GetLocalRotation();
convertRotation = true;
break;
}
case SHTransformComponent::UpdateCommandType::WORLD_ORIENTATION:
{
tf.local.orientation = UPDATE_COMMAND.data;
if (parent)
tf.local.orientation /= parent->GetLocalOrientation();
convertRotation = false;
break; break;
} }
case SHTransformComponent::UpdateCommandType::WORLD_SCALE: case SHTransformComponent::UpdateCommandType::WORLD_SCALE:
{ {
tf.local.scale = tf.world.scale; tf.local.scale = UPDATE_COMMAND.data.ToVec3();
if (parent) if (parent)
tf.local.scale /= parent->GetLocalScale(); tf.local.scale /= parent->GetLocalScale();
@ -133,15 +266,38 @@ namespace SHADE
tf.local.trs = localToWorld; tf.local.trs = localToWorld;
// Compute world transforms
tf.world.position = SHVec3::Transform(tf.local.position, localToWorld); tf.world.position = SHVec3::Transform(tf.local.position, localToWorld);
tf.world.rotation = tf.local.rotation + (parent ? parent->GetLocalRotation() : SHVec3::Zero);
tf.world.scale = tf.local.scale * (parent ? parent->GetLocalScale() : SHVec3::One); tf.world.scale = tf.local.scale * (parent ? parent->GetLocalScale() : SHVec3::One);
tf.world.ComputeTRS();
// Transpose TRS to column major
//tf.local.trs.Transpose(); if (convertRotation)
//tf.world.trs.Transpose(); {
tf.worldRotation = tf.localRotation + (parent ? parent->GetLocalRotation() : SHVec3::Zero);
// Set the orientation
// Wrap rotations between -360 and 360 and convert to radians
SHVec3 worldRotRad, localRotRad;
for (size_t i = 0; i < SHVec3::SIZE; ++i)
{
worldRotRad[i] = SHMath::Wrap(tf.worldRotation[i], -SHMath::TWO_PI, SHMath::TWO_PI);
localRotRad[i] = SHMath::Wrap(tf.localRotation[i], -SHMath::TWO_PI, SHMath::TWO_PI);
}
tf.world.orientation = SHQuaternion::FromEuler(worldRotRad);
tf.local.orientation = SHQuaternion::FromEuler(localRotRad);
}
else
{
tf.world.orientation = (parent ? parent->GetLocalOrientation() : SHQuaternion::Identity) * tf.local.orientation;
// Set the euler angle rotations
tf.worldRotation = tf.world.orientation.ToEuler();
tf.localRotation = tf.local.orientation.ToEuler();
}
tf.world.ComputeTRS();
} }
} // namespace SHADE } // namespace SHADE

View File

@ -45,25 +45,52 @@ namespace SHADE
/* System Routines */ /* System Routines */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
class SH_API TransformUpdateRoutine final: public SHSystemRoutine class SH_API TransformPostLogicUpdate final: public SHSystemRoutine
{ {
public: public:
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */ /* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
TransformUpdateRoutine (); TransformPostLogicUpdate ();
~TransformUpdateRoutine () = default; ~TransformPostLogicUpdate () = default;
TransformUpdateRoutine (const TransformUpdateRoutine&) = delete; TransformPostLogicUpdate (const TransformPostLogicUpdate&) = delete;
TransformUpdateRoutine (TransformUpdateRoutine&&) = delete; TransformPostLogicUpdate (TransformPostLogicUpdate&&) = delete;
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
/* Operator Overloads */ /* Operator Overloads */
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
TransformUpdateRoutine& operator= (const TransformUpdateRoutine&) = delete; TransformPostLogicUpdate& operator= (const TransformPostLogicUpdate&) = delete;
TransformUpdateRoutine& operator= (TransformUpdateRoutine&&) = delete; TransformPostLogicUpdate& operator= (TransformPostLogicUpdate&&) = delete;
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void Execute(double dt) noexcept override;
};
class SH_API TransformPostPhysicsUpdate final: public SHSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
TransformPostPhysicsUpdate ();
~TransformPostPhysicsUpdate () = default;
TransformPostPhysicsUpdate (const TransformPostPhysicsUpdate&) = delete;
TransformPostPhysicsUpdate (TransformPostPhysicsUpdate&&) = delete;
/*-------------------------------------------------------------------------------*/
/* Operator Overloads */
/*-------------------------------------------------------------------------------*/
TransformPostPhysicsUpdate& operator= (const TransformPostPhysicsUpdate&) = delete;
TransformPostPhysicsUpdate& operator= (TransformPostPhysicsUpdate&&) = delete;
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */
@ -84,8 +111,11 @@ namespace SHADE
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
static void UpdateEntity (const SHSceneNode* node); SHEventHandle ChangeParent (SHEventPtr changeParentEvent);
static void UpdateTransform(SHTransformComponent& tf, const SHTransformComponent* parent = nullptr); static void UpdateChildrenLocalTransforms (SHSceneNode* node);
static void UpdateEntity (const SHSceneNode* node, bool clearDirtyFlag);
static void UpdateTransform (SHTransformComponent& tf, const SHTransformComponent* parent = nullptr);
}; };

View File

@ -38,6 +38,10 @@ namespace SHADE
: XMFLOAT4( 0.0f, 0.0f, 0.0f, 0.0f ) : XMFLOAT4( 0.0f, 0.0f, 0.0f, 0.0f )
{} {}
SHVec4::SHVec4(const SHVec3& vec3) noexcept
: XMFLOAT4( vec3.x, vec3.y, vec3.z, 1.0f )
{}
SHVec4::SHVec4(const XMFLOAT4& xmfloat4) noexcept SHVec4::SHVec4(const XMFLOAT4& xmfloat4) noexcept
: XMFLOAT4( xmfloat4.x, xmfloat4.y, xmfloat4.z, xmfloat4.w ) : XMFLOAT4( xmfloat4.x, xmfloat4.y, xmfloat4.z, xmfloat4.w )
{} {}
@ -271,6 +275,11 @@ namespace SHADE
return result; return result;
} }
SHVec3 SHVec4::ToVec3() const noexcept
{
return SHVec3{ x, y, z };
}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Static Function Member Definitions */ /* Static Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/

View File

@ -16,6 +16,7 @@
// Project Headers // Project Headers
#include "SH_API.h" #include "SH_API.h"
#include "SHVec3.h"
namespace SHADE namespace SHADE
{ {
@ -53,6 +54,7 @@ namespace SHADE
~SHVec4 () = default; ~SHVec4 () = default;
SHVec4 () noexcept; SHVec4 () noexcept;
SHVec4 (const SHVec3& vec3) noexcept;
SHVec4 (const XMFLOAT4& xmfloat4) noexcept; SHVec4 (const XMFLOAT4& xmfloat4) noexcept;
SHVec4 (float x, float y, float z, float w) noexcept; SHVec4 (float x, float y, float z, float w) noexcept;
@ -103,15 +105,17 @@ namespace SHADE
[[nodiscard]] SHVec4 Cross3D (const SHVec4& rhs) const noexcept; [[nodiscard]] SHVec4 Cross3D (const SHVec4& rhs) const noexcept;
[[nodiscard]] SHVec4 Cross (const SHVec4& v1, const SHVec4& v2) const noexcept; [[nodiscard]] SHVec4 Cross (const SHVec4& v1, const SHVec4& v2) const noexcept;
[[nodiscard]] SHVec3 ToVec3 () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Static Function Members */ /* Static Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] static SHVec4 Normalise (const SHVec4& v) noexcept; [[nodiscard]] static SHVec4 Normalise (const SHVec4& v) noexcept;
[[nodiscard]] static SHVec4 Normalise3D (const SHVec4& v) noexcept; [[nodiscard]] static SHVec4 Normalise3D (const SHVec4& v) noexcept;
[[nodiscard]] static SHVec4 Abs (const SHVec4& v) noexcept; [[nodiscard]] static SHVec4 Abs (const SHVec4& v) noexcept;
[[nodiscard]] static SHVec4 Min (const std::initializer_list<SHVec4>& vs) noexcept; [[nodiscard]] static SHVec4 Min (const std::initializer_list<SHVec4>& vs) noexcept;
[[nodiscard]] static SHVec4 Max (const std::initializer_list<SHVec4>& vs) noexcept; [[nodiscard]] static SHVec4 Max (const std::initializer_list<SHVec4>& vs) noexcept;
[[nodiscard]] static SHVec4 Clamp (const SHVec4& v, const SHVec4& vMin, const SHVec4& vMax) noexcept; [[nodiscard]] static SHVec4 Clamp (const SHVec4& v, const SHVec4& vMin, const SHVec4& vMax) noexcept;
[[nodiscard]] static SHVec4 Lerp (const SHVec4& a, const SHVec4& b, float t) noexcept; [[nodiscard]] static SHVec4 Lerp (const SHVec4& a, const SHVec4& b, float t) noexcept;
[[nodiscard]] static SHVec4 ClampedLerp (const SHVec4& a, const SHVec4& b, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept; [[nodiscard]] static SHVec4 ClampedLerp (const SHVec4& a, const SHVec4& b, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept;

View File

@ -140,12 +140,12 @@ namespace SHADE
isRigidBody = true; isRigidBody = true;
rb->position = tf->GetWorldPosition(); rb->position = tf->GetWorldPosition();
rb->orientation = tf->GetWorldRotation(); rb->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation());
if (hasColliders) if (hasColliders)
{ {
c->position = tf->GetWorldPosition(); c->position = tf->GetWorldPosition();
c->orientation = tf->GetWorldRotation(); c->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation());
// Get array of colliders and add them back into the rigidbody // Get array of colliders and add them back into the rigidbody
for (auto& collider : c->colliders | std::views::keys) for (auto& collider : c->colliders | std::views::keys)
AddCollider(&collider); AddCollider(&collider);
@ -160,7 +160,7 @@ namespace SHADE
hasColliders = true; hasColliders = true;
c->position = tf->GetWorldPosition(); c->position = tf->GetWorldPosition();
c->orientation = tf->GetWorldRotation(); c->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation());
for (auto& collider : c->colliders | std::views::keys) for (auto& collider : c->colliders | std::views::keys)
AddCollider(&collider); AddCollider(&collider);

View File

@ -16,6 +16,7 @@
// Project Headers // Project Headers
#include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHEntityManager.h"
#include "Math/SHMathHelpers.h"
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
@ -315,7 +316,7 @@ namespace SHADE
if (TF->HasChanged()) if (TF->HasChanged())
{ {
physicsObject.SetPosition(TF->GetWorldPosition()); physicsObject.SetPosition(TF->GetWorldPosition());
physicsObject.SetRotation(TF->GetWorldRotation()); physicsObject.SetOrientation(TF->GetWorldOrientation());
} }
} }
} }
@ -492,8 +493,7 @@ namespace SHADE
// Convert RP3D Transform to SHADE // Convert RP3D Transform to SHADE
auto* tfComponent = SHComponentManager::GetComponent<SHTransformComponent>(entityID); auto* tfComponent = SHComponentManager::GetComponent<SHTransformComponent>(entityID);
tfComponent->SetWorldPosition(rp3dPos); tfComponent->SetWorldPosition(rp3dPos);
tfComponent->SetWorldRotation(SHQuaternion{ rp3dRot }.ToEuler()); tfComponent->SetWorldOrientation(SHQuaternion{ rp3dRot });
// Cache transforms // Cache transforms
physicsObject.prevTransform = CURRENT_TF; physicsObject.prevTransform = CURRENT_TF;

View File

@ -15,6 +15,7 @@ of DigiPen Institute of Technology is prohibited.
#include "SHResourceManager.h" #include "SHResourceManager.h"
// Project Includes // Project Includes
#include "Assets/SHAssetManager.h" #include "Assets/SHAssetManager.h"
#include "Assets/Asset Types/SHAssetIncludes.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h"
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Tools/SHLog.h" #include "Tools/SHLog.h"
@ -48,7 +49,7 @@ namespace SHADE
throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed."); throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed.");
// Load // Load
const SHMeshAsset* assetData = SHAssetManager::GetMesh(assetId); const SHMeshAsset* assetData = SHAssetManager::GetData<SHMeshAsset>(assetId);
if (assetData == nullptr) if (assetData == nullptr)
{ {
SHLog::Warning("[SHResourceManager] Attempted to load an asset with an invalid Asset ID."); SHLog::Warning("[SHResourceManager] Attempted to load an asset with an invalid Asset ID.");
@ -80,7 +81,7 @@ namespace SHADE
throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed."); throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed.");
// Load // Load
const SHTextureAsset* assetData = SHAssetManager::GetTexture(assetId); const SHTextureAsset* assetData = SHAssetManager::GetData<SHTextureAsset>(assetId);
if (assetData == nullptr) if (assetData == nullptr)
{ {
SHLog::Warning("[SHResourceManager] Attempted to load an asset with an invalid Asset ID."); SHLog::Warning("[SHResourceManager] Attempted to load an asset with an invalid Asset ID.");
@ -133,7 +134,7 @@ namespace SHADE
/* Query Functions */ /* Query Functions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
template<typename T> template<typename T>
static std::optional<AssetID> SHResourceManager::GetAssetID(Handle<T> handle) std::optional<AssetID> SHResourceManager::GetAssetID(Handle<T> handle)
{ {
const Handle GENERIC_HANDLE = Handle(handle); const Handle GENERIC_HANDLE = Handle(handle);
auto [typedHandleMap, typedAssetIdMap] = getAssetHandleMap<T>(); auto [typedHandleMap, typedAssetIdMap] = getAssetHandleMap<T>();

View File

@ -15,6 +15,7 @@
// Project Headers // Project Headers
#include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHEntityManager.h"
#include "Events/SHEventManager.hpp"
#include "Tools/SHLogger.h" #include "Tools/SHLogger.h"
#include "Tools/SHException.h" #include "Tools/SHException.h"
@ -317,6 +318,11 @@ namespace SHADE
if (parentNode == nullptr) if (parentNode == nullptr)
{ {
SHLOG_WARNING("Removing Entity {}'s parent", entityID) SHLOG_WARNING("Removing Entity {}'s parent", entityID)
if (parent)
parent->RemoveChild(this);
return;
} }
// Handle self assignment // Handle self assignment
@ -359,10 +365,19 @@ namespace SHADE
} }
//////////////////////////////////////// ////////////////////////////////////////
const SHSceneGraphChangeParentEvent EVENT_DATA
{
.node = NODE_ITER->second
, .oldParent = NODE_ITER->second->GetParent()
, .newParent = parent ? parent : root
};
if (parent == nullptr) if (parent == nullptr)
parent = root; parent = root;
NODE_ITER->second->SetParent(parent); NODE_ITER->second->SetParent(parent);
SHEventManager::BroadcastEvent<SHSceneGraphChangeParentEvent>(EVENT_DATA, SH_SCENEGRAPH_CHANGE_PARENT_EVENT);
} }
void SHSceneGraph::SetParent(EntityID entityID, EntityID parent) const noexcept void SHSceneGraph::SetParent(EntityID entityID, EntityID parent) const noexcept
@ -396,8 +411,17 @@ namespace SHADE
} }
//////////////////////////////////////// ////////////////////////////////////////
const SHSceneGraphChangeParentEvent EVENT_DATA
{
.node = NODE_ITER->second
, .oldParent = NODE_ITER->second->GetParent()
, .newParent = PARENT_ITER->second
};
SHSceneNode* currentNode = NODE_ITER->second; SHSceneNode* currentNode = NODE_ITER->second;
currentNode->SetParent(PARENT_ITER->second); currentNode->SetParent(PARENT_ITER->second);
SHEventManager::BroadcastEvent<SHSceneGraphChangeParentEvent>(EVENT_DATA, SH_SCENEGRAPH_CHANGE_PARENT_EVENT);
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -558,7 +582,7 @@ namespace SHADE
ReleaseNode(node); ReleaseNode(node);
} }
void SHSceneGraph::Traverse (const UnaryPredicate& predicate) const void SHSceneGraph::Traverse (const UnaryFunction& predicate) const
{ {
TraverseAndInvokePredicate(root, predicate); TraverseAndInvokePredicate(root, predicate);
} }
@ -597,7 +621,7 @@ namespace SHADE
delete node; delete node;
} }
void SHSceneGraph::TraverseAndInvokePredicate(const SHSceneNode* node, const UnaryPredicate& predicate) void SHSceneGraph::TraverseAndInvokePredicate(const SHSceneNode* node, const UnaryFunction& predicate)
{ {
for (auto* child : node->children) for (auto* child : node->children)
{ {

View File

@ -97,9 +97,8 @@ namespace SHADE
/* Type Definitions */ /* Type Definitions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
using EntityNodeMap = std::unordered_map<EntityID, SHSceneNode*>; using EntityNodeMap = std::unordered_map<EntityID, SHSceneNode*>;
using UnaryFunction = std::function<void(SHSceneNode*)>;
using UnaryPredicate = std::function<void(SHSceneNode*)>;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -143,8 +142,7 @@ namespace SHADE
bool RemoveNode (SHSceneNode* nodeToRemove) noexcept; bool RemoveNode (SHSceneNode* nodeToRemove) noexcept;
void Reset () noexcept; void Reset () noexcept;
void Traverse (const UnaryPredicate& predicate) const; void Traverse (const UnaryFunction& predicate) const;
private: private:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -160,8 +158,14 @@ namespace SHADE
SHSceneNode* AllocateNode (EntityID entityID); SHSceneNode* AllocateNode (EntityID entityID);
void ReleaseNode (SHSceneNode* node) noexcept; void ReleaseNode (SHSceneNode* node) noexcept;
static void TraverseAndInvokePredicate (const SHSceneNode* node, const UnaryPredicate& predicate); static void TraverseAndInvokePredicate (const SHSceneNode* node, const UnaryFunction& predicate);
}; };
struct SHSceneGraphChangeParentEvent
{
SHSceneNode* node;
SHSceneNode* oldParent;
SHSceneNode* newParent;
};
} // namespace SHADE } // namespace SHADE

View File

@ -29,13 +29,21 @@ namespace SHADE
{ {
GetNativeComponent()->SetLocalPosition(Convert::ToNative(val)); GetNativeComponent()->SetLocalPosition(Convert::ToNative(val));
} }
Vector3 Transform::LocalRotation::get() Quaternion Transform::LocalRotation::get()
{ {
return Convert::ToCLI(GetNativeComponent()->GetLocalRotation()); return Convert::ToCLI(GetNativeComponent()->GetLocalOrientation());
} }
void Transform::LocalRotation::set(Vector3 val) void Transform::LocalRotation::set(Quaternion val)
{ {
GetNativeComponent()->SetLocalRotation(Convert::ToNative(val)); GetNativeComponent()->SetLocalOrientation(Convert::ToNative(val));
}
Vector3 Transform::LocalEulerAngles::get()
{
return Convert::ToCLI(GetNativeComponent()->GetLocalRotation());
}
void Transform::LocalEulerAngles::set(Vector3 val)
{
GetNativeComponent()->SetLocalRotation(Convert::ToNative(val));
} }
Vector3 Transform::LocalScale::get() Vector3 Transform::LocalScale::get()
{ {
@ -54,13 +62,21 @@ namespace SHADE
{ {
GetNativeComponent()->SetWorldPosition(Convert::ToNative(val)); GetNativeComponent()->SetWorldPosition(Convert::ToNative(val));
} }
Vector3 Transform::GlobalRotation::get() Quaternion Transform::GlobalRotation::get()
{ {
return Convert::ToCLI(GetNativeComponent()->GetWorldRotation()); return Convert::ToCLI(GetNativeComponent()->GetLocalOrientation());
} }
void Transform::GlobalRotation::set(Vector3 val) void Transform::GlobalRotation::set(Quaternion val)
{ {
GetNativeComponent()->SetWorldRotation(Convert::ToNative(val)); GetNativeComponent()->SetWorldOrientation(Convert::ToNative(val));
}
Vector3 Transform::GlobalEulerAngles::get()
{
return Convert::ToCLI(GetNativeComponent()->GetWorldRotation());
}
void Transform::GlobalEulerAngles::set(Vector3 val)
{
GetNativeComponent()->SetWorldRotation(Convert::ToNative(val));
} }
Vector3 Transform::GlobalScale::get() Vector3 Transform::GlobalScale::get()
{ {

View File

@ -17,14 +17,14 @@ of DigiPen Institute of Technology is prohibited.
// Project Includes // Project Includes
#include "Components/Component.hxx" #include "Components/Component.hxx"
#include "Math/Vector3.hxx" #include "Math/Vector3.hxx"
#include "Utility/Convert.hxx" #include "Math/Quaternion.hxx"
// External Dependencies // External Dependencies
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
namespace SHADE namespace SHADE
{ {
/// <summary> /// <summary>
/// CLR version of the the SHADE Engine's TransformComponent. /// CLR version of the SHADE Engine's TransformComponent.
/// </summary> /// </summary>
public ref class Transform : public Component<SHTransformComponent> public ref class Transform : public Component<SHTransformComponent>
{ {
@ -52,9 +52,17 @@ namespace SHADE
void set(Vector3 val); void set(Vector3 val);
} }
/// <summary> /// <summary>
/// Local Z-axis rotation angle stored by this Transform in Radians. /// Local rotation quaternion stored by this Transform.
/// </summary> /// </summary>
property Vector3 LocalRotation property Quaternion LocalRotation
{
Quaternion get();
void set(Quaternion val);
}
/// <summary>
/// Local euler angle rotations stored by this Transform.
/// </summary>
property Vector3 LocalEulerAngles
{ {
Vector3 get(); Vector3 get();
void set(Vector3 val); void set(Vector3 val);
@ -76,16 +84,23 @@ namespace SHADE
void set(Vector3 val); void set(Vector3 val);
} }
/// <summary> /// <summary>
/// Global Z-axis rotation angle stored by this Transform in Radians. /// Global rotation quaternion stored by this Transform.
/// </summary> /// </summary>
property Vector3 GlobalRotation property Quaternion GlobalRotation
{
Quaternion get();
void set(Quaternion val);
}
/// <summary>
/// Global euler angle rotations stored by this Transform.
/// </summary>
property Vector3 GlobalEulerAngles
{ {
Vector3 get(); Vector3 get();
void set(Vector3 val); void set(Vector3 val);
} }
/// <summary> /// <summary>
/// Global scale stored by this Transform. /// Global scale stored by this Transform.
/// Note that this operation is expensive.
/// </summary> /// </summary>
property Vector3 GlobalScale property Vector3 GlobalScale
{ {

View File

@ -21,7 +21,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Utility Functions */ /* Utility Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
double Math::Wrap(double value, double min, double max) float Math::Wrap(float value, float min, float max)
{ {
while (value < min) while (value < min)
{ {
@ -33,24 +33,24 @@ namespace SHADE
} }
return value; return value;
} }
double Math::DegreesToRadians(double degrees) float Math::DegreesToRadians(float degrees)
{ {
return degrees * Deg2Rad; return degrees * Deg2Rad;
} }
double Math::RadiansToDegrees(double radians) float Math::RadiansToDegrees(float radians)
{ {
return radians * Rad2Deg; return radians * Rad2Deg;
} }
double Math::Lerp(double a, double b, double t) float Math::Lerp(float a, float b, float t)
{ {
return LerpUnclamped(a, b, System::Math::Clamp(t, 0.0, 1.0)); return LerpUnclamped(a, b, System::Math::Clamp(t, 0.0f, 1.0f));
} }
double Math::LerpUnclamped(double a, double b, double t) float Math::LerpUnclamped(float a, float b, float t)
{ {
return a + t * (b - a); return a + t * (b - a);
} }
double Math::InverseLerp(double a, double b, double value) float Math::InverseLerp(float a, float b, float value)
{ {
return (value - a) / (b - a); return (value - a) / (b - a);
} }

View File

@ -27,11 +27,11 @@ namespace SHADE
/// <summary> /// <summary>
/// Degrees-to-radians conversion constant /// Degrees-to-radians conversion constant
/// </summary> /// </summary>
static constexpr double Deg2Rad = System::Math::PI / 180.0; static constexpr float Deg2Rad = System::Math::PI / 180.0f;
/// <summary> /// <summary>
/// Radians-to-degrees conversion constant /// Radians-to-degrees conversion constant
/// </summary> /// </summary>
static constexpr double Rad2Deg = 180.0 / System::Math::PI; static constexpr float Rad2Deg = 180.0f / System::Math::PI;
/// <summary> /// <summary>
/// Small value used for single precision floating point comparisons. /// Small value used for single precision floating point comparisons.
/// </summary> /// </summary>
@ -47,28 +47,28 @@ namespace SHADE
/// <param name="min">Minimum value to wrap at.</param> /// <param name="min">Minimum value to wrap at.</param>
/// <param name="max">Maximum value to wrap at.</param> /// <param name="max">Maximum value to wrap at.</param>
/// <returns>Wrapped value.</returns> /// <returns>Wrapped value.</returns>
static double Wrap(double value, double min, double max); static float Wrap(float value, float min, float max);
/// <summary> /// <summary>
/// Converts an angle from degree representation to radian representation. /// Converts an angle from degree representation to radian representation.
/// </summary> /// </summary>
/// <param name="degrees">Degree-based angle to convert.</param> /// <param name="degrees">Degree-based angle to convert.</param>
/// <returns>The specified angle in radians.</returns> /// <returns>The specified angle in radians.</returns>
static double DegreesToRadians(double degrees); static float DegreesToRadians(float degrees);
/// <summary> /// <summary>
/// Converts an angle from radian representation to degree representation. /// Converts an angle from radian representation to degree representation.
/// </summary> /// </summary>
/// <param name="radians">Radian-based angle to convert.</param> /// <param name="radians">Radian-based angle to convert.</param>
/// <returns>The specified angle in degrees.</returns> /// <returns>The specified angle in degrees.</returns>
static double RadiansToDegrees(double radians); static float RadiansToDegrees(float radians);
/// <summary> /// <summary>
/// Linearly interpolates between a and b by t. /// Linearly interpolates between a and b by t.
/// The parameter t is clamped to the range [0, 1]. /// The parameter t is clamped to the range [0, 1].
/// </summary> /// </summary>
/// <param name="a">The start value.</param> /// <param name="a">The start value.</param>
/// <param name="b">The end value.</param> /// <param name="b">The end value.</param>
/// <param name="t">The interpolation value between the two double.</param> /// <param name="t">The interpolation value between the two float.</param>
/// <returns>The interpolated double result between the two double values.</returns> /// <returns>The interpolated float result between the two float values.</returns>
static double Lerp(double a, double b, double t); static float Lerp(float a, float b, float t);
/// <summary> /// <summary>
/// Linearly interpolates between a and b by t. /// Linearly interpolates between a and b by t.
/// The parameter t is not clamped and a value based on a and b is supported. /// The parameter t is not clamped and a value based on a and b is supported.
@ -77,9 +77,9 @@ namespace SHADE
/// </summary> /// </summary>
/// <param name="a">The start value.</param> /// <param name="a">The start value.</param>
/// <param name="b">The end value.</param> /// <param name="b">The end value.</param>
/// <param name="t">The interpolation value between the two double.</param> /// <param name="t">The interpolation value between the two float.</param>
/// <returns>The interpolated double result between the two double values.</returns> /// <returns>The interpolated float result between the two float values.</returns>
static double LerpUnclamped(double a, double b, double t); static float LerpUnclamped(float a, float b, float t);
/// <summary> /// <summary>
/// Calculates the linear parameter t that produces the interpolant value within the range [a, b]. /// Calculates the linear parameter t that produces the interpolant value within the range [a, b].
/// </summary> /// </summary>
@ -87,6 +87,6 @@ namespace SHADE
/// <param name="b">End value.</param> /// <param name="b">End value.</param>
/// <param name="value">Value between start and end.</param> /// <param name="value">Value between start and end.</param>
/// <returns>Percentage of value between start and end.</returns> /// <returns>Percentage of value between start and end.</returns>
static double InverseLerp(double a, double b, double value); static float InverseLerp(float a, float b, float value);
}; };
} }

View File

@ -0,0 +1,170 @@
/************************************************************************************//*!
\file Quaternion.cxx
\author Diren D Bharwani, diren.dbharwani, 390002520
\par email: diren.dbharwani\@digipen.edu
\date Oct 23, 2022
\brief Contains the definitions of functions in the Quaternion struct.
Note: This file is written in C++17/CLI.
Copyright (C) 2021 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
// Precompiled Headers
#include "SHpch.h"
// Primary Header
#include "Quaternion.hxx"
// External Dependencies
#include "Math/SHQuaternion.h"
#include "Math/Vector/SHVec4.h"
// Project Headers
#include "Utility/Convert.hxx"
#include "Math.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Constructors */
/*---------------------------------------------------------------------------------*/
Quaternion::Quaternion(float _x, float _y, float _z, float _w)
: x { _x }
, y { _y }
, z { _z }
, w { _w }
{}
/*---------------------------------------------------------------------------------*/
/* Usage Functions */
/*---------------------------------------------------------------------------------*/
void Quaternion::SetFromToRotation(Vector3 fromDirection, Vector3 toDirection)
{
const SHQuaternion R = SHQuaternion::FromToRotation(Convert::ToNative(fromDirection), Convert::ToNative(toDirection));
*this = Convert::ToCLI(R);
}
void Quaternion::SetLookRotation(Vector3 view, Vector3 up)
{
const SHQuaternion R = SHQuaternion::LookRotation(Convert::ToNative(view), Convert::ToNative(up));
*this = Convert::ToCLI(R);
}
void Quaternion::ToAngleAxis(float^% angle, Vector3^% axis)
{
const SHVec4 NATIVE_AXIS_ANGLE = Convert::ToNative(*this).GetAxisAngle();
axis = Convert::ToCLI(NATIVE_AXIS_ANGLE.ToVec3());
angle = NATIVE_AXIS_ANGLE.w;
}
System::String^ Quaternion::ToString()
{
return ValueType::ToString();
}
/*---------------------------------------------------------------------------------*/
/* IEquatable */
/*---------------------------------------------------------------------------------*/
bool Quaternion::Equals(Quaternion other)
{
const float DOT = Dot(*this, other);
return fabs(1.0f - DOT) <= Math::Epsilon;
}
/*---------------------------------------------------------------------------------*/
/* Object Overrides */
/*---------------------------------------------------------------------------------*/
bool Quaternion::Equals(Object^ o)
{
return ValueType::Equals(o);
}
int Quaternion::GetHashCode()
{
return ValueType::GetHashCode();
}
/*---------------------------------------------------------------------------------*/
/* Static Functions */
/*---------------------------------------------------------------------------------*/
float Quaternion::Angle(Quaternion a, Quaternion b)
{
return SHQuaternion::Angle(Convert::ToNative(a), Convert::ToNative(b));
}
Quaternion Quaternion::AngleAxis(float angle, Vector3 axis)
{
return Convert::ToCLI(SHQuaternion::FromAxisAngle(Convert::ToNative(axis), angle));
}
float Quaternion::Dot(Quaternion a, Quaternion b)
{
return (a.x * b.x) + (a.y * b.y) + (a.z * b.z) + (a.w * b.w);
}
Quaternion Quaternion::Euler(float _x, float _y, float _z)
{
return Convert::ToCLI(SHQuaternion::FromPitchYawRoll(_x, _y, _z));
}
Quaternion Quaternion::FromToRotation(Vector3 fromDirection, Vector3 toDirection)
{
return Convert::ToCLI(SHQuaternion::FromToRotation(Convert::ToNative(fromDirection), Convert::ToNative(toDirection)));
}
Quaternion Quaternion::Inverse(Quaternion rotation)
{
return Convert::ToCLI(SHQuaternion::Inverse(Convert::ToNative(rotation)));
}
Quaternion Quaternion::Lerp(Quaternion a, Quaternion b, float t)
{
return Convert::ToCLI(SHQuaternion::ClampedLerp(Convert::ToNative(a), Convert::ToNative(b), t));
}
Quaternion Quaternion::LerpUnclamped(Quaternion a, Quaternion b, float t)
{
return Convert::ToCLI(SHQuaternion::Lerp(Convert::ToNative(a), Convert::ToNative(b), t));
}
Quaternion Quaternion::LookRotation(Vector3 forward, Vector3 upwards)
{
return Convert::ToCLI(SHQuaternion::LookRotation(Convert::ToNative(forward), Convert::ToNative(upwards)));
}
Quaternion Quaternion::Normalize(Quaternion q)
{
return Convert::ToCLI(SHQuaternion::Normalise(Convert::ToNative(q)));
}
Quaternion Quaternion::RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta)
{
return Convert::ToCLI(SHQuaternion::RotateTowards(Convert::ToNative(from), Convert::ToNative(to), Math::DegreesToRadians(maxDegreesDelta)));
}
Quaternion Quaternion::Slerp(Quaternion a, Quaternion b, float t)
{
return Convert::ToCLI(SHQuaternion::ClampedSlerp(Convert::ToNative(a), Convert::ToNative(b), t));
}
Quaternion Quaternion::SlerpUnclamped(Quaternion a, Quaternion b, float t)
{
return Convert::ToCLI(SHQuaternion::Slerp(Convert::ToNative(a), Convert::ToNative(b), t));
}
Quaternion Quaternion::operator*(Quaternion lhs, Quaternion rhs)
{
return Convert::ToCLI(Convert::ToNative(lhs) * Convert::ToNative(rhs));
}
bool Quaternion::operator==(Quaternion lhs, Quaternion rhs)
{
return lhs.Equals(rhs);
}
}

View File

@ -0,0 +1,237 @@
/************************************************************************************//*!
\file Quaternion.hxx
\author Diren D Bharwani, diren.dbharwani, 390002520
\par email: diren.dbharwani\@digipen.edu
\date Oct 23, 2022
\brief Contains the definitions of Quaternion struct.
Note: This file is written in C++17/CLI.
Copyright (C) 2021 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
// Standard Libraries
#include <limits>
// Project Includes
#include "Vector3.hxx"
namespace SHADE
{
///<summary>
/// CLR version of SHADE's Quaternion class that represents an orientation.
/// Designed to closely match Unity's Quaternion struct.
/// </summary>
[System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)]
public value struct Quaternion : public System::IEquatable<Quaternion>
{
public:
/*-----------------------------------------------------------------------------*/
/* Constants */
/*-----------------------------------------------------------------------------*/
#pragma region Constants
///<summary>
/// Shorthand for writing Quaternion(0, 0, 0, 1).
///</summary>
static initonly Quaternion Identity = Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
#pragma endregion
/*-----------------------------------------------------------------------------*/
/* Public Members */
/*-----------------------------------------------------------------------------*/
///<summary>
/// X-component of the Quaternion.
/// Don't modify this directly unless you know quaternions inside out.
///</summary>
float x;
///<summary>
/// Y-component of the Quaternion.
/// Don't modify this directly unless you know quaternions inside out.
///</summary>
float y;
///<summary>
/// Z-component of the Quaternion.
/// Don't modify this directly unless you know quaternions inside out.
///</summary>
float z;
///<summary>
/// W-component of the Quaternion. Do not directly modify quaternions.
///</summary>
float w;
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructor to construct a Quaternion with the specified components.
/// </summary>
/// <param name="_x">X-coordinate to set.</param>
/// <param name="_y">Y-coordinate to set.</param>
/// <param name="_z">Z-coordinate to set.</param>
/// <param name="_z">W-coordinate to set.</param>
Quaternion(float _x, float _y, float _z, float _w);
/*-----------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Creates a rotation which rotates from fromDirection to toDirection. <br/>
/// Use this to create a rotation which starts at the first Vector (fromDirection) and rotates to the second Vector (toDirection).
/// These Vectors must be set up in a script.
/// </summary>
void SetFromToRotation(Vector3 fromDirection, Vector3 toDirection);
/// <summary>
/// Creates a rotation with the specified forward and upwards directions. <br/>
/// The result is applied to this quaternion.
/// If used to orient a Transform, the Z axis will be aligned with forward and the Y axis with upwards, assuming these vectors are orthogonal.
/// Logs an error if the forward direction is zero.
/// </summary>
/// <param name="view">The direction to look in.</param>
/// <param name="up">The vector that defines in which direction up is.</param>
void SetLookRotation(Vector3 view, Vector3 up);
/// <summary>
/// Converts a rotation to angle-axis representation (angles in degrees).
/// </summary>
void ToAngleAxis(float^% angle, Vector3^% axis);
System::String^ ToString() override;
/*-----------------------------------------------------------------------------*/
/* IEquatable */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Compares equality with an object of the same type.
/// </summary>
/// <param name="other">The object to compare with.</param>
/// <returns>True if both objects are the same.</returns>
virtual bool Equals(Quaternion other);
/*-----------------------------------------------------------------------------*/
/* Object */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Compares equality with another unboxed object.
/// </summary>
/// <param name="o">The unboxed object to compare with.</param>
/// <returns>True if both objects are the same.</returns>
bool Equals(Object^ o) override;
/// <summary>
/// Gets a unique hash for this object.
/// </summary>
/// <returns>Unique hash for this object.</returns>
int GetHashCode() override;
/*-----------------------------------------------------------------------------*/
/* Static Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Returns the angle in degrees between two rotations a and b.<br/>
/// </summary>
/// <returns>The angle in degrees between the two vectors. </returns>
static float Angle(Quaternion a, Quaternion b);
/// <summary>
/// Creates a rotation which rotates angle degrees around axis.
/// </summary>
static Quaternion AngleAxis(float angle, Vector3 axis);
/// <summary>
/// The dot product between two rotations.
/// </summary>
static float Dot(Quaternion a, Quaternion b);
/// <summary>
/// Returns a rotation that rotates y degrees around the y axis, x degrees around the x axis, and z degrees around the z axis; applied in that order.
/// </summary>
static Quaternion Euler(float _x, float _y, float _z);
/// <summary>
/// Creates a rotation which rotates from fromDirection to toDirection.
/// </summary>
static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection);
/// <summary>
/// Returns the Inverse of rotation.
/// </summary>
static Quaternion Inverse(Quaternion rotation);
/// <summary>
/// Interpolates between a and b by t and normalizes the result afterwards. The parameter t is clamped to the range [0, 1].
/// </summary>
/// <param name="a">Start value, returned when t = 0.</param>
/// <param name="b">End value, returned when t = 1.</param>
/// <param name="t">Interpolation ratio.</param>
/// <returns> A quaternion interpolated between quaternions a and b.</returns>
static Quaternion Lerp(Quaternion a, Quaternion b, float t);
/// <summary>
/// Interpolates between a and b by t and normalizes the result afterwards. The parameter t is not clamped.
/// </summary>
static Quaternion LerpUnclamped(Quaternion a, Quaternion b, float t);
/// <summary>
/// Creates a rotation with the specified forward and upwards directions. <br/>
/// Z axis will be aligned with forward, X axis aligned with cross product between forward and upwards, and Y axis aligned with cross product between Z and X.
/// </summary>
static Quaternion LookRotation(Vector3 forward, Vector3 upwards);
/// <summary>
/// Converts this quaternion to one with the same orientation but with a magnitude of 1.
/// </summary>
static Quaternion Normalize(Quaternion q);
/// <summary>
/// Rotates a rotation from towards to. <br/>
/// The from quaternion is rotated towards to by an angular step of maxDegreesDelta (but note that the rotation will not overshoot).
/// Negative values of maxDegreesDelta will move away from to until the rotation is exactly the opposite direction.
/// </summary>
static Quaternion RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta);
/// <summary>
/// Spherically interpolates between quaternions a and b by ratio t. The parameter t is clamped to the range [0, 1].
/// </summary>
/// <param name="a">Start value, returned when t = 0.</param>
/// <param name="b">End value, returned when t = 1.</param>
/// <param name="t">Interpolation ratio.</param>
/// <returns> A quaternion spherically interpolated between quaternions a and b.</returns>
static Quaternion Slerp(Quaternion a, Quaternion b, float t);
/// <summary>
/// Spherically interpolates between a and b by t. The parameter t is not clamped.
/// </summary>
static Quaternion SlerpUnclamped(Quaternion a, Quaternion b, float t);
/*-----------------------------------------------------------------------------*/
/* Overloaded Operators */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Combines rotations lhs and rhs.
/// </summary>
/// <param name="lhs">Left-hand side quaternion.</param>
/// <param name="rhs">Right-hand side quaternion.</param>
static Quaternion operator*(Quaternion lhs, Quaternion rhs);
/// <summary>
/// Are two quaternions equal to each other?
/// </summary>
/// <param name="lhs">Left-hand side quaternion.</param>
/// <param name="rhs">Right-hand side quaternion.</param>
static bool operator==(Quaternion lhs, Quaternion rhs);
};
} // namespace SHADE

View File

@ -26,10 +26,10 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Constructors */ /* Constructors */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
Vector2::Vector2(double _x) Vector2::Vector2(float _x)
: Vector2 { _x, 0.0 } : Vector2 { _x, 0.0f }
{} {}
Vector2::Vector2(double _x, double _y) Vector2::Vector2(float _x, float _y)
: x { _x } : x { _x }
, y { _y } , y { _y }
{} {}
@ -47,22 +47,22 @@ namespace SHADE
return *this / GetMagnitude(); return *this / GetMagnitude();
} }
double Vector2::GetMagnitude() float Vector2::GetMagnitude()
{ {
return sqrt(x * x + y * y); return sqrt(x * x + y * y);
} }
double Vector2::GetSqrMagnitude() float Vector2::GetSqrMagnitude()
{ {
return x * x + y * y; return x * x + y * y;
} }
double Vector2::AngleFromRightRadians() float Vector2::AngleFromRightRadians()
{ {
return atan2(y, x); return atan2(y, x);
} }
double Vector2::AngleFromRightDegrees() float Vector2::AngleFromRightDegrees()
{ {
return Math::RadiansToDegrees(AngleFromRightRadians()); return Math::RadiansToDegrees(AngleFromRightRadians());
} }
@ -72,7 +72,7 @@ namespace SHADE
return IsNearPoint(point, Math::Epsilon); return IsNearPoint(point, Math::Epsilon);
} }
bool Vector2::IsNearPoint(Vector2 point, double tolerance) bool Vector2::IsNearPoint(Vector2 point, float tolerance)
{ {
return (*this - point).GetSqrMagnitude() < (tolerance * tolerance); return (*this - point).GetSqrMagnitude() < (tolerance * tolerance);
} }
@ -113,13 +113,13 @@ namespace SHADE
{ {
return IsNear(lhs, rhs, Math::Epsilon); return IsNear(lhs, rhs, Math::Epsilon);
} }
bool Vector2::IsNear(Vector2 lhs, Vector2 rhs, double tolerance) bool Vector2::IsNear(Vector2 lhs, Vector2 rhs, float tolerance)
{ {
return (std::abs(lhs.x) - std::abs(rhs.x)) < tolerance return (std::abs(lhs.x) - std::abs(rhs.x)) < tolerance
&& &&
(std::abs(lhs.y) - std::abs(rhs.y)) < tolerance; (std::abs(lhs.y) - std::abs(rhs.y)) < tolerance;
} }
double Vector2::Dot(Vector2 lhs, Vector2 rhs) float Vector2::Dot(Vector2 lhs, Vector2 rhs)
{ {
return lhs.x * rhs.x + lhs.y * rhs.y; return lhs.x * rhs.x + lhs.y * rhs.y;
} }
@ -153,12 +153,12 @@ namespace SHADE
} }
Vector2 Vector2::Reflect(Vector2 vec, Vector2 normal) Vector2 Vector2::Reflect(Vector2 vec, Vector2 normal)
{ {
return vec - (Project(vec, normal.GetNormalised()) * 2.0); return vec - (Project(vec, normal.GetNormalised()) * 2.0f);
} }
Vector2 Vector2::RotateRadians(Vector2 vec, double radians) Vector2 Vector2::RotateRadians(Vector2 vec, float radians)
{ {
const double SINE = sin(radians); const float SINE = sin(radians);
const double COSINE = cos(radians); const float COSINE = cos(radians);
return Vector2 return Vector2
( (
@ -166,35 +166,35 @@ namespace SHADE
vec.x * SINE + vec.y * COSINE vec.x * SINE + vec.y * COSINE
); );
} }
Vector2 Vector2::RotateDegrees(Vector2 vec, double degrees) Vector2 Vector2::RotateDegrees(Vector2 vec, float degrees)
{ {
return RotateRadians(vec, Math::DegreesToRadians(degrees)); return RotateRadians(vec, Math::DegreesToRadians(degrees));
} }
Vector2 Vector2::Min(Vector2 lhs, Vector2 rhs) Vector2 Vector2::Min(Vector2 lhs, Vector2 rhs)
{ {
double lx = lhs.x, rx = rhs.x; float lx = lhs.x, rx = rhs.x;
double ly = lhs.y, ry = rhs.y; float ly = lhs.y, ry = rhs.y;
return Vector2(std::min(lx, rx), return Vector2(std::min(lx, rx),
std::min(ly, ry)); std::min(ly, ry));
} }
Vector2 Vector2::Max(Vector2 lhs, Vector2 rhs) Vector2 Vector2::Max(Vector2 lhs, Vector2 rhs)
{ {
double lx = lhs.x, rx = rhs.x; float lx = lhs.x, rx = rhs.x;
double ly = lhs.y, ry = rhs.y; float ly = lhs.y, ry = rhs.y;
return Vector2(std::max(lx, rx), return Vector2(std::max(lx, rx),
std::max(ly, ry)); std::max(ly, ry));
} }
Vector2 Vector2::Lerp(Vector2 a, Vector2 b, double t) Vector2 Vector2::Lerp(Vector2 a, Vector2 b, float t)
{ {
return LerpUnclamped(a, b, std::clamp(t, 0.0, 1.0)); return LerpUnclamped(a, b, std::clamp(t, 0.0f, 1.0f));
} }
Vector2 Vector2::LerpUnclamped(Vector2 a, Vector2 b, double t) Vector2 Vector2::LerpUnclamped(Vector2 a, Vector2 b, float t)
{ {
return a + ((b - a) * t); return a + ((b - a) * t);
} }
Vector2 Vector2::MoveTowards(Vector2 current, Vector2 target, double maxDistanceDelta) Vector2 Vector2::MoveTowards(Vector2 current, Vector2 target, float maxDistanceDelta)
{ {
// Ignore if it is exactly on the same point // Ignore if it is exactly on the same point
if (current == target) if (current == target)
@ -206,7 +206,7 @@ namespace SHADE
// Check if check if is behind or ahead of target // Check if check if is behind or ahead of target
Vector2 DIFF = target - newPos; Vector2 DIFF = target - newPos;
if (Dot(DELTA, DIFF) < 0.0) if (Dot(DELTA, DIFF) < 0.0f)
{ {
newPos = target; newPos = target;
} }
@ -236,7 +236,7 @@ namespace SHADE
lhs.y * rhs.y lhs.y * rhs.y
); );
} }
Vector2 Vector2::operator*(Vector2 lhs, double rhs) Vector2 Vector2::operator*(Vector2 lhs, float rhs)
{ {
return Vector2 return Vector2
( (
@ -244,7 +244,7 @@ namespace SHADE
lhs.y * rhs lhs.y * rhs
); );
} }
Vector2 Vector2::operator/(Vector2 lhs, double rhs) Vector2 Vector2::operator/(Vector2 lhs, float rhs)
{ {
return Vector2 return Vector2
( (

View File

@ -19,8 +19,8 @@ of DigiPen Institute of Technology is prohibited.
namespace SHADE namespace SHADE
{ {
///<summary> ///<summary>
/// CLR version of the the SHADE Engine's Vector2 class that represents a /// CLR version of SHADE Engine's Vector2 class that represents a 2-Dimensional Vector.
/// 2-Dimensional Vector. Designed to closely match Unity's Vector2 struct. /// Designed to closely match Unity's Vector2 struct.
/// </summary> /// </summary>
[System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)] [System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)]
public value struct Vector2 : public System::IEquatable<Vector2> public value struct Vector2 : public System::IEquatable<Vector2>
@ -33,37 +33,37 @@ namespace SHADE
///<summary> ///<summary>
/// Shorthand for writing Vector2(0, -1). /// Shorthand for writing Vector2(0, -1).
///</summary> ///</summary>
static initonly Vector2 Down = Vector2(0.0, -1.0); static initonly Vector2 Down = Vector2(0.0f, -1.0f);
///<summary> ///<summary>
/// Shorthand for writing Vector2(-1, 0). /// Shorthand for writing Vector2(-1, 0).
///</summary> ///</summary>
static initonly Vector2 Left = Vector2(-1.0, 0.0); static initonly Vector2 Left = Vector2(-1.0f, 0.0f);
///<summary> ///<summary>
/// Shorthand for writing Vector2(double.NegativeInfinity, /// Shorthand for writing Vector2(float.NegativeInfinity,
/// double.NegativeInfinity). /// float.NegativeInfinity).
///</summary> ///</summary>
static initonly Vector2 NegativeInfinity = Vector2(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest()); static initonly Vector2 NegativeInfinity = Vector2(std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest());
///<summary> ///<summary>
/// Shorthand for writing Vector2(1, 1). /// Shorthand for writing Vector2(1, 1).
///</summary> ///</summary>
static initonly Vector2 One = Vector2(1.0, 1.0); static initonly Vector2 One = Vector2(1.0f, 1.0f);
///<summary> ///<summary>
/// Shorthand for writing Vector2(double.PositiveInfinity, /// Shorthand for writing Vector2(float.PositiveInfinity,
/// double.PositiveInfinity). /// float.PositiveInfinity).
///</summary> ///</summary>
static initonly Vector2 PositiveInfinity = Vector2(std::numeric_limits<double>::max(), std::numeric_limits<double>::max()); static initonly Vector2 PositiveInfinity = Vector2(std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
///<summary> ///<summary>
/// Shorthand for writing Vector2(1, 0). /// Shorthand for writing Vector2(1, 0).
///</summary> ///</summary>
static initonly Vector2 Right = Vector2(1.0, 0.0); static initonly Vector2 Right = Vector2(1.0f, 0.0f);
///<summary> ///<summary>
/// Shorthand for writing Vector2(0, 1). /// Shorthand for writing Vector2(0, 1).
///</summary> ///</summary>
static initonly Vector2 Up = Vector2(0.0, 1.0); static initonly Vector2 Up = Vector2(0.0f, 1.0f);
///<summary> ///<summary>
/// Shorthand for writing Vector2(0, 0). /// Shorthand for writing Vector2(0, 0).
///</summary> ///</summary>
static initonly Vector2 Zero = Vector2(0.0, 0.0); static initonly Vector2 Zero = Vector2(0.0f, 0.0f);
#pragma endregion #pragma endregion
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -72,27 +72,27 @@ namespace SHADE
///<summary> ///<summary>
/// X-component of the Vector2. /// X-component of the Vector2.
///</summary> ///</summary>
double x; float x;
///<summary> ///<summary>
/// Y-component of the Vector2. /// Y-component of the Vector2.
///</summary> ///</summary>
double y; float y;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Constructors */ /* Constructors */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Constructor to construct a Vector2 with the specified components with the /// Constructor to construct a Vector2 with the specified components with the
/// Y-component set to 0.0. /// Y-component set to 0.0f.
/// </summary> /// </summary>
/// <param name="_x">X-coordinate to set.</param> /// <param name="_x">X-coordinate to set.</param>
Vector2(double _x); Vector2(float _x);
/// <summary> /// <summary>
/// Constructor to construct a Vector2 with the specified components.. /// Constructor to construct a Vector2 with the specified components..
/// </summary> /// </summary>
/// <param name="_x">X-coordinate to set.</param> /// <param name="_x">X-coordinate to set.</param>
/// <param name="_y">Y-coordinate to set.</param> /// <param name="_y">Y-coordinate to set.</param>
Vector2(double _x, double _y); Vector2(float _x, float _y);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Usage Functions */ /* Usage Functions */
@ -117,24 +117,24 @@ namespace SHADE
/// need the precise magnitude, consider using GetSqrMagnitude() instead. /// need the precise magnitude, consider using GetSqrMagnitude() instead.
/// </summary> /// </summary>
/// <returns>Returns the length of this Vector2.</returns> /// <returns>Returns the length of this Vector2.</returns>
double GetMagnitude(); float GetMagnitude();
/// <summary> /// <summary>
/// Calculates and returns the squared magnitude of this Vector2. /// Calculates and returns the squared magnitude of this Vector2.
/// </summary> /// </summary>
/// <returns>Returns the squared length of this Vector2.</returns> /// <returns>Returns the squared length of this Vector2.</returns>
double GetSqrMagnitude(); float GetSqrMagnitude();
/// <summary> /// <summary>
/// Calculates and returns the angle of this vector from the right vector. This /// Calculates and returns the angle of this vector from the right vector. This
/// function returns values between -Math.PI and Math.PI. /// function returns values between -Math.PI and Math.PI.
/// </summary> /// </summary>
/// <returns>Returns the angle of this vector from the right vector in radians.</returns> /// <returns>Returns the angle of this vector from the right vector in radians.</returns>
double AngleFromRightRadians(); float AngleFromRightRadians();
/// <summary> /// <summary>
/// Calculates and returns the angle of this vector from the right vector. This /// Calculates and returns the angle of this vector from the right vector. This
/// function returns values between -180.0 and 180.0. /// function returns values between -180.0f and 180.0f.
/// </summary> /// </summary>
/// <returns>Returns the angle of this vector from the right vector in degrees.</returns> /// <returns>Returns the angle of this vector from the right vector in degrees.</returns>
double AngleFromRightDegrees(); float AngleFromRightDegrees();
/// <summary> /// <summary>
/// Checks if a specified point is near this Vector2 that represents a point with /// Checks if a specified point is near this Vector2 that represents a point with
/// a tolerance value of PLS_EPSILON. /// a tolerance value of PLS_EPSILON.
@ -156,7 +156,7 @@ namespace SHADE
/// True if this Vector2 representing a point and the specified point are within /// True if this Vector2 representing a point and the specified point are within
/// the range of the specified tolerance. False otherwise. /// the range of the specified tolerance. False otherwise.
/// </returns> /// </returns>
bool IsNearPoint(Vector2 point, double tolerance); bool IsNearPoint(Vector2 point, float tolerance);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* IEquatable */ /* IEquatable */
@ -206,7 +206,7 @@ namespace SHADE
/// <returns> /// <returns>
/// True if the two Vector2s are within the tolerance value specified /// True if the two Vector2s are within the tolerance value specified
/// </returns> /// </returns>
static bool IsNear(Vector2 lhs, Vector2 rhs, double tolerance); static bool IsNear(Vector2 lhs, Vector2 rhs, float tolerance);
/// <summary> /// <summary>
/// Computes and returns the dot product of 2 specified Vector2s. /// Computes and returns the dot product of 2 specified Vector2s.
/// </summary> /// </summary>
@ -215,7 +215,7 @@ namespace SHADE
/// <returns> /// <returns>
/// Scalar value representing the dot product of the two Vector2s. /// Scalar value representing the dot product of the two Vector2s.
/// </returns> /// </returns>
static double Dot(Vector2 lhs, Vector2 rhs); static float Dot(Vector2 lhs, Vector2 rhs);
/// <summary> /// <summary>
/// Computes the inward perpendicular Vector2 to the specified Vector2. /// Computes the inward perpendicular Vector2 to the specified Vector2.
/// Equivalent to calling Perpendicular(lhs, true). This means, the /// Equivalent to calling Perpendicular(lhs, true). This means, the
@ -260,7 +260,7 @@ namespace SHADE
/// Angle to rotate the vector by in an anti-clockwise direction in radians. /// Angle to rotate the vector by in an anti-clockwise direction in radians.
/// </param> /// </param>
/// <returns>The Vector2 that represents the rotated vector.</returns> /// <returns>The Vector2 that represents the rotated vector.</returns>
static Vector2 RotateRadians(Vector2 vec, double radians); static Vector2 RotateRadians(Vector2 vec, float radians);
/// <summary> /// <summary>
/// Rotates a Vector2 on the Z-axis by a specified angle in an anti-clockwise /// Rotates a Vector2 on the Z-axis by a specified angle in an anti-clockwise
/// direction. /// direction.
@ -270,7 +270,7 @@ namespace SHADE
/// Angle to rotate the vector by in an anti-clockwise direction in degrees. /// Angle to rotate the vector by in an anti-clockwise direction in degrees.
/// </param> /// </param>
/// <returns>The Vector2 that represents the rotated vector.</returns> /// <returns>The Vector2 that represents the rotated vector.</returns>
static Vector2 RotateDegrees(Vector2 vec, double degrees); static Vector2 RotateDegrees(Vector2 vec, float degrees);
/// <summary> /// <summary>
/// Computes and returns a Vector2 that is made from the smallest components of /// Computes and returns a Vector2 that is made from the smallest components of
/// the two specified Vector2s. /// the two specified Vector2s.
@ -298,25 +298,25 @@ namespace SHADE
/// This is most commonly used to find a point some fraction of the way along a /// This is most commonly used to find a point some fraction of the way along a
/// line between two endpoints. /// line between two endpoints.
/// </summary> /// </summary>
/// <param name="a">The start Vector2, returned when t = 0.0.</param> /// <param name="a">The start Vector2, returned when t = 0.0f.</param>
/// <param name="b">The end Vector2, returned when t = 1.0.</param> /// <param name="b">The end Vector2, returned when t = 1.0f.</param>
/// <param name="t"> /// <param name="t">
/// Value used to interpolate between a and b which is clamped to /// Value used to interpolate between a and b which is clamped to
/// the range[0, 1]. /// the range[0, 1].
/// </param> /// </param>
/// <returns>The interpolated Vector2.</returns> /// <returns>The interpolated Vector2.</returns>
static Vector2 Lerp(Vector2 a, Vector2 b, double t); static Vector2 Lerp(Vector2 a, Vector2 b, float t);
/// <summary> /// <summary>
/// Linearly interpolates between two specified points. /// Linearly interpolates between two specified points.
/// This is most commonly used to find a point some fraction of the way along a /// This is most commonly used to find a point some fraction of the way along a
/// line between two endpoints. /// line between two endpoints.
/// Unlike Lerp(), t is not clamped to a range at all. /// Unlike Lerp(), t is not clamped to a range at all.
/// </summary> /// </summary>
/// <param name="a">The start Vector2, returned when t = 0.0.</param> /// <param name="a">The start Vector2, returned when t = 0.0f.</param>
/// <param name="b">The end Vector2, returned when t = 1.0.</param> /// <param name="b">The end Vector2, returned when t = 1.0f.</param>
/// <param name="t">Value used to interpolate between a and b.</param> /// <param name="t">Value used to interpolate between a and b.</param>
/// <returns>The interpolated Vector2.</returns> /// <returns>The interpolated Vector2.</returns>
static Vector2 LerpUnclamped(Vector2 a, Vector2 b, double t); static Vector2 LerpUnclamped(Vector2 a, Vector2 b, float t);
/// <summary> /// <summary>
/// Moves a point current towards target. /// Moves a point current towards target.
/// Similar to Lerp(), however, the function will ensure that the distance never /// Similar to Lerp(), however, the function will ensure that the distance never
@ -327,7 +327,7 @@ namespace SHADE
/// <param name="target">The target position to move to.</param> /// <param name="target">The target position to move to.</param>
/// <param name="maxDistanceDelta">Maximum distance moved per call.</param> /// <param name="maxDistanceDelta">Maximum distance moved per call.</param>
/// <returns>Vector representing the moved point.</returns> /// <returns>Vector representing the moved point.</returns>
static Vector2 MoveTowards(Vector2 current, Vector2 target, double maxDistanceDelta); static Vector2 MoveTowards(Vector2 current, Vector2 target, float maxDistanceDelta);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Overloaded Operators */ /* Overloaded Operators */
@ -361,7 +361,7 @@ namespace SHADE
/// <param name="lhs">Vector2 to multiply with.</param> /// <param name="lhs">Vector2 to multiply with.</param>
/// <param name="rhs">Scalar to multiply with.</param> /// <param name="rhs">Scalar to multiply with.</param>
/// <returns>The result of the scalar multiplication.</returns> /// <returns>The result of the scalar multiplication.</returns>
static Vector2 operator*(Vector2 lhs, double rhs); static Vector2 operator*(Vector2 lhs, float rhs);
/// <summary> /// <summary>
/// Calculates the division of a Vector2 with a scalar value and returns /// Calculates the division of a Vector2 with a scalar value and returns
/// the result. /// the result.
@ -369,7 +369,7 @@ namespace SHADE
/// <param name="lhs">Scalar to divide with.</param> /// <param name="lhs">Scalar to divide with.</param>
/// <param name="rhs">Vector2 to divide with.</param> /// <param name="rhs">Vector2 to divide with.</param>
/// <returns>The result of the scalar division.</returns> /// <returns>The result of the scalar division.</returns>
static Vector2 operator/(Vector2 lhs, double rhs); static Vector2 operator/(Vector2 lhs, float rhs);
/// <summary> /// <summary>
/// Checks if two Vector2s are approximately equal. This is equivalent to /// Checks if two Vector2s are approximately equal. This is equivalent to
/// calling Vector2.IsNear() with default tolerance values. /// calling Vector2.IsNear() with default tolerance values.

View File

@ -11,6 +11,7 @@ Copyright (C) 2021 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited. of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/ *//*************************************************************************************/
// Precompiled Headers // Precompiled Headers
#include "SHpch.h" #include "SHpch.h"
// Primary Header // Primary Header
@ -26,13 +27,13 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Constructors */ /* Constructors */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
Vector3::Vector3(double _x) Vector3::Vector3(float _x)
: Vector3 {_x, 0.0, 0.0} : Vector3 {_x, 0.0f, 0.0f}
{} {}
Vector3::Vector3(double _x, double _y) Vector3::Vector3(float _x, float _y)
: Vector3 {_x, _y, 0.0} : Vector3 {_x, _y, 0.0f}
{} {}
Vector3::Vector3(double _x, double _y, double _z) Vector3::Vector3(float _x, float _y, float _z)
: x { _x } : x { _x }
, y { _y } , y { _y }
, z { _z } , z { _z }
@ -54,22 +55,22 @@ namespace SHADE
return *this / GetSqrMagnitude(); return *this / GetSqrMagnitude();
} }
double Vector3::GetMagnitude() float Vector3::GetMagnitude()
{ {
return sqrt(x * x + y * y + z * z); return sqrt(x * x + y * y + z * z);
} }
double Vector3::GetSqrMagnitude() float Vector3::GetSqrMagnitude()
{ {
return x * x + y * y + z * z; return x * x + y * y + z * z;
} }
double Vector3::Angle2DFromRightRadians() float Vector3::Angle2DFromRightRadians()
{ {
return atan2(y, x); return atan2(y, x);
} }
double Vector3::Angle2DFromRightDegrees() float Vector3::Angle2DFromRightDegrees()
{ {
return Math::RadiansToDegrees(Angle2DFromRightRadians()); return Math::RadiansToDegrees(Angle2DFromRightRadians());
} }
@ -79,7 +80,7 @@ namespace SHADE
return IsNearPoint(point, Math::Epsilon); return IsNearPoint(point, Math::Epsilon);
} }
bool Vector3::IsNearPoint(Vector3 point, double tolerance) bool Vector3::IsNearPoint(Vector3 point, float tolerance)
{ {
return (*this - point).GetSqrMagnitude() < (tolerance * tolerance); return (*this - point).GetSqrMagnitude() < (tolerance * tolerance);
} }
@ -121,7 +122,7 @@ namespace SHADE
{ {
return IsNear(lhs, rhs, Math::Epsilon); return IsNear(lhs, rhs, Math::Epsilon);
} }
bool Vector3::IsNear(Vector3 lhs, Vector3 rhs, double tolerance) bool Vector3::IsNear(Vector3 lhs, Vector3 rhs, float tolerance)
{ {
return (std::abs(lhs.x) - std::abs(rhs.x)) < tolerance return (std::abs(lhs.x) - std::abs(rhs.x)) < tolerance
&& &&
@ -129,7 +130,7 @@ namespace SHADE
&& &&
(std::abs(lhs.z) - std::abs(rhs.z)) < tolerance; (std::abs(lhs.z) - std::abs(rhs.z)) < tolerance;
} }
double Vector3::Dot(Vector3 lhs, Vector3 rhs) float Vector3::Dot(Vector3 lhs, Vector3 rhs)
{ {
return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z; return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
} }
@ -145,12 +146,12 @@ namespace SHADE
} }
Vector3 Vector3::Reflect(Vector3 vec, Vector3 normal) Vector3 Vector3::Reflect(Vector3 vec, Vector3 normal)
{ {
return vec - (Project(vec, normal.GetNormalised()) * 2.0); return vec - (Project(vec, normal.GetNormalised()) * 2.0f);
} }
Vector3 Vector3::RotateRadians(Vector3 vec, double radians) Vector3 Vector3::RotateRadians(Vector3 vec, float radians)
{ {
const double SINE = sin(radians); const float SINE = sin(radians);
const double COSINE = cos(radians); const float COSINE = cos(radians);
return Vector3 return Vector3
( (
@ -159,15 +160,15 @@ namespace SHADE
vec.z vec.z
); );
} }
Vector3 Vector3::RotateDegrees(Vector3 vec, double degrees) Vector3 Vector3::RotateDegrees(Vector3 vec, float degrees)
{ {
return RotateRadians(vec, Math::DegreesToRadians(degrees)); return RotateRadians(vec, Math::DegreesToRadians(degrees));
} }
Vector3 Vector3::Min(Vector3 lhs, Vector3 rhs) Vector3 Vector3::Min(Vector3 lhs, Vector3 rhs)
{ {
double lx = lhs.x, rx = rhs.x; float lx = lhs.x, rx = rhs.x;
double ly = lhs.y, ry = rhs.y; float ly = lhs.y, ry = rhs.y;
double lz = lhs.z, rz = rhs.z; float lz = lhs.z, rz = rhs.z;
return Vector3(std::min(lx, rx), return Vector3(std::min(lx, rx),
std::min(ly, ry), std::min(ly, ry),
@ -175,23 +176,23 @@ namespace SHADE
} }
Vector3 Vector3::Max(Vector3 lhs, Vector3 rhs) Vector3 Vector3::Max(Vector3 lhs, Vector3 rhs)
{ {
double lx = lhs.x, rx = rhs.x; float lx = lhs.x, rx = rhs.x;
double ly = lhs.y, ry = rhs.y; float ly = lhs.y, ry = rhs.y;
double lz = lhs.z, rz = rhs.z; float lz = lhs.z, rz = rhs.z;
return Vector3(std::max(lx, rx), return Vector3(std::max(lx, rx),
std::max(ly, ry), std::max(ly, ry),
std::max(lz, rz)); std::max(lz, rz));
} }
Vector3 Vector3::Lerp(Vector3 a, Vector3 b, double t) Vector3 Vector3::Lerp(Vector3 a, Vector3 b, float t)
{ {
return LerpUnclamped(a, b, std::clamp(t, 0.0, 1.0)); return LerpUnclamped(a, b, std::clamp(t, 0.0f, 1.0f));
} }
Vector3 Vector3::LerpUnclamped(Vector3 a, Vector3 b, double t) Vector3 Vector3::LerpUnclamped(Vector3 a, Vector3 b, float t)
{ {
return a + ((b - a) * t); return a + ((b - a) * t);
} }
Vector3 Vector3::MoveTowards(Vector3 current, Vector3 target, double maxDistanceDelta) Vector3 Vector3::MoveTowards(Vector3 current, Vector3 target, float maxDistanceDelta)
{ {
// Ignore if it is exactly on the same point // Ignore if it is exactly on the same point
if (current == target) if (current == target)
@ -203,7 +204,7 @@ namespace SHADE
// Check if check if is behind or ahead of target // Check if check if is behind or ahead of target
Vector3 DIFF = target - newPos; Vector3 DIFF = target - newPos;
if (Dot(DELTA, DIFF) < 0.0) if (Dot(DELTA, DIFF) < 0.0f)
{ {
newPos = target; newPos = target;
} }
@ -236,7 +237,7 @@ namespace SHADE
lhs.z * rhs.z lhs.z * rhs.z
); );
} }
Vector3 Vector3::operator*(Vector3 lhs, double rhs) Vector3 Vector3::operator*(Vector3 lhs, float rhs)
{ {
return Vector3 return Vector3
( (
@ -245,7 +246,7 @@ namespace SHADE
lhs.z * rhs lhs.z * rhs
); );
} }
Vector3 Vector3::operator/(Vector3 lhs, double rhs) Vector3 Vector3::operator/(Vector3 lhs, float rhs)
{ {
return Vector3 return Vector3
( (

View File

@ -11,6 +11,7 @@ Copyright (C) 2021 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited. of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/ *//*************************************************************************************/
#pragma once #pragma once
// Standard Libraries // Standard Libraries
@ -21,8 +22,8 @@ of DigiPen Institute of Technology is prohibited.
namespace SHADE namespace SHADE
{ {
///<summary> ///<summary>
/// CLR version of the the PlushieEngine's Vector3 class that represents a /// CLR version of SHADE Engine's Vector3 class that represents a 3-Dimensional Vector.
/// 3-Dimensional Vector. Designed to closely match Unity's Vector3 struct. /// Designed to closely match Unity's Vector3 struct.
/// </summary> /// </summary>
[System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)] [System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)]
public value struct Vector3 : public System::IEquatable<Vector3> public value struct Vector3 : public System::IEquatable<Vector3>
@ -35,49 +36,49 @@ namespace SHADE
///<summary> ///<summary>
/// Shorthand for writing Vector3(0, 0, -1). /// Shorthand for writing Vector3(0, 0, -1).
///</summary> ///</summary>
static initonly Vector3 Back = Vector3(0.0, 0.0, -1.0); static initonly Vector3 Back = Vector3(0.0f, 0.0f, -1.0f);
///<summary> ///<summary>
/// Shorthand for writing Vector3(0, -1, 0). /// Shorthand for writing Vector3(0, -1, 0).
///</summary> ///</summary>
static initonly Vector3 Down = Vector3(0.0, -1.0, 0.0); static initonly Vector3 Down = Vector3(0.0f, -1.0f, 0.0f);
///<summary> ///<summary>
/// Shorthand for writing Vector3(0, 0, 1). /// Shorthand for writing Vector3(0, 0, 1).
///</summary> ///</summary>
static initonly Vector3 Forward = Vector3(0.0, 0.0, 1.0); static initonly Vector3 Forward = Vector3(0.0f, 0.0f, 1.0f);
///<summary> ///<summary>
/// Shorthand for writing Vector3(-1, 0, 0). /// Shorthand for writing Vector3(-1, 0, 0).
///</summary> ///</summary>
static initonly Vector3 Left = Vector3(-1.0, 0.0, 0.0); static initonly Vector3 Left = Vector3(-1.0f, 0.0f, 0.0f);
///<summary> ///<summary>
/// Shorthand for writing Vector3(double.NegativeInfinity, /// Shorthand for writing Vector3(float.NegativeInfinity,
/// double.NegativeInfinity, double.NegativeInfinity). /// float.NegativeInfinity, float.NegativeInfinity).
///</summary> ///</summary>
static initonly Vector3 NegativeInfinity = Vector3(std::numeric_limits<double>::lowest(), static initonly Vector3 NegativeInfinity = Vector3(std::numeric_limits<float>::lowest(),
std::numeric_limits<double>::lowest(), std::numeric_limits<float>::lowest(),
std::numeric_limits<double>::lowest()); std::numeric_limits<float>::lowest());
///<summary> ///<summary>
/// Shorthand for writing Vector3(1, 1, 1). /// Shorthand for writing Vector3(1, 1, 1).
///</summary> ///</summary>
static initonly Vector3 One = Vector3(1.0, 1.0, 1.0); static initonly Vector3 One = Vector3(1.0f, 1.0f, 1.0f);
///<summary> ///<summary>
/// Shorthand for writing Vector3(double.PositiveInfinity, /// Shorthand for writing Vector3(float.PositiveInfinity,
/// double.PositiveInfinity, double.PositiveInfinity). /// float.PositiveInfinity, float.PositiveInfinity).
///</summary> ///</summary>
static initonly Vector3 PositiveInfinity = Vector3(std::numeric_limits<double>::max(), static initonly Vector3 PositiveInfinity = Vector3(std::numeric_limits<float>::max(),
std::numeric_limits<double>::max(), std::numeric_limits<float>::max(),
std::numeric_limits<double>::max()); std::numeric_limits<float>::max());
///<summary> ///<summary>
/// Shorthand for writing Vector3(1, 0, 0). /// Shorthand for writing Vector3(1, 0, 0).
///</summary> ///</summary>
static initonly Vector3 Right = Vector3(1.0, 0.0, 0.0); static initonly Vector3 Right = Vector3(1.0f, 0.0f, 0.0f);
///<summary> ///<summary>
/// Shorthand for writing Vector3(0, 1, 0). /// Shorthand for writing Vector3(0, 1, 0).
///</summary> ///</summary>
static initonly Vector3 Up = Vector3(0.0, 1.0, 0.0); static initonly Vector3 Up = Vector3(0.0f, 1.0f, 0.0f);
///<summary> ///<summary>
/// Shorthand for writing Vector3(0, 0, 0). /// Shorthand for writing Vector3(0, 0, 0).
///</summary> ///</summary>
static initonly Vector3 Zero = Vector3(0.0, 0.0, 0.0); static initonly Vector3 Zero = Vector3(0.0f, 0.0f, 0.0f);
#pragma endregion #pragma endregion
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -86,39 +87,39 @@ namespace SHADE
///<summary> ///<summary>
/// X-component of the Vector3. /// X-component of the Vector3.
///</summary> ///</summary>
double x; float x;
///<summary> ///<summary>
/// Y-component of the Vector3. /// Y-component of the Vector3.
///</summary> ///</summary>
double y; float y;
///<summary> ///<summary>
/// Z-component of the Vector3. /// Z-component of the Vector3.
///</summary> ///</summary>
double z; float z;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Constructors */ /* Constructors */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Constructor to construct a Vector3 with the specified components with the /// Constructor to construct a Vector3 with the specified components with the
/// Y and Z-component set to 0.0. /// Y and Z-component set to 0.0f.
/// </summary> /// </summary>
/// <param name="_x">X-coordinate to set.</param> /// <param name="_x">X-coordinate to set.</param>
Vector3(double _x); Vector3(float _x);
/// <summary> /// <summary>
/// Constructor to construct a Vector3 with the specified components with the /// Constructor to construct a Vector3 with the specified components with the
/// Z-component set to 0.0. /// Z-component set to 0.0f.
/// </summary> /// </summary>
/// <param name="_x">X-coordinate to set.</param> /// <param name="_x">X-coordinate to set.</param>
/// <param name="_y">Y-coordinate to set.</param> /// <param name="_y">Y-coordinate to set.</param>
Vector3(double _x, double _y); Vector3(float _x, float _y);
/// <summary> /// <summary>
/// Constructor to construct a Vector3 with the specified components. /// Constructor to construct a Vector3 with the specified components.
/// </summary> /// </summary>
/// <param name="_x">X-coordinate to set.</param> /// <param name="_x">X-coordinate to set.</param>
/// <param name="_y">Y-coordinate to set.</param> /// <param name="_y">Y-coordinate to set.</param>
/// <param name="_z">Z-coordinate to set.</param> /// <param name="_z">Z-coordinate to set.</param>
Vector3(double _x, double _y, double _z); Vector3(float _x, float _y, float _z);
/// <summary> /// <summary>
/// Conversion constructor to construct a Vector3 using a Vector2. /// Conversion constructor to construct a Vector3 using a Vector2.
/// </summary> /// </summary>
@ -148,24 +149,24 @@ namespace SHADE
/// need the precise magnitude, consider using GetSqrMagnitude() instead. /// need the precise magnitude, consider using GetSqrMagnitude() instead.
/// </summary> /// </summary>
/// <returns>Returns the length of this Vector3.</returns> /// <returns>Returns the length of this Vector3.</returns>
double GetMagnitude(); float GetMagnitude();
/// <summary> /// <summary>
/// Calculates and returns the squared magnitude of this Vector3. /// Calculates and returns the squared magnitude of this Vector3.
/// </summary> /// </summary>
/// <returns>Returns the squared length of this Vector3.</returns> /// <returns>Returns the squared length of this Vector3.</returns>
double GetSqrMagnitude(); float GetSqrMagnitude();
/// <summary> /// <summary>
/// Calculates and returns the angle of this vector from the right vector. This /// Calculates and returns the angle of this vector from the right vector. This
/// function returns values between -Math.PI and Math.PI. /// function returns values between -Math.PI and Math.PI.
/// </summary> /// </summary>
/// <returns>Returns the angle of this vector from the right vector in radians.</returns> /// <returns>Returns the angle of this vector from the right vector in radians.</returns>
double Angle2DFromRightRadians(); float Angle2DFromRightRadians();
/// <summary> /// <summary>
/// Calculates and returns the angle of this vector from the right vector. This /// Calculates and returns the angle of this vector from the right vector. This
/// function returns values between -180.0 and 180.0. /// function returns values between -180.0f and 180.0f.
/// </summary> /// </summary>
/// <returns>Returns the angle of this vector from the right vector in degrees.</returns> /// <returns>Returns the angle of this vector from the right vector in degrees.</returns>
double Angle2DFromRightDegrees(); float Angle2DFromRightDegrees();
/// <summary> /// <summary>
/// Checks if a specified point is near this Vector3 that represents a point with /// Checks if a specified point is near this Vector3 that represents a point with
/// a tolerance value of PLS_EPSILON. /// a tolerance value of PLS_EPSILON.
@ -187,7 +188,7 @@ namespace SHADE
/// True if this Vector3 representing a point and the specified point are within /// True if this Vector3 representing a point and the specified point are within
/// the range of the specified tolerance. False otherwise. /// the range of the specified tolerance. False otherwise.
/// </returns> /// </returns>
bool IsNearPoint(Vector3 point, double tolerance); bool IsNearPoint(Vector3 point, float tolerance);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* IEquatable */ /* IEquatable */
@ -235,14 +236,14 @@ namespace SHADE
/// <returns> /// <returns>
/// True if the two Vector3s are within the tolerance value specified /// True if the two Vector3s are within the tolerance value specified
/// </returns> /// </returns>
static bool IsNear(Vector3 lhs, Vector3 rhs, double tolerance); static bool IsNear(Vector3 lhs, Vector3 rhs, float tolerance);
/// <summary> /// <summary>
/// Computes and returns the dot product of 2 specified Vector3s. /// Computes and returns the dot product of 2 specified Vector3s.
/// </summary> /// </summary>
/// <param name="lhs">Vector3 to calculate dot product with.</param> /// <param name="lhs">Vector3 to calculate dot product with.</param>
/// <param name="rhs">Another Vector3 to calculate dot product with.</param> /// <param name="rhs">Another Vector3 to calculate dot product with.</param>
/// <returns>Scalar value representing the dot product of the two Vector3s.</returns> /// <returns>Scalar value representing the dot product of the two Vector3s.</returns>
static double Dot(Vector3 lhs, Vector3 rhs); static float Dot(Vector3 lhs, Vector3 rhs);
/// <summary> /// <summary>
/// Computes and returns the cross product of 2 specified Vector3s. /// Computes and returns the cross product of 2 specified Vector3s.
/// </summary> /// </summary>
@ -273,7 +274,7 @@ namespace SHADE
/// Angle to rotate the vector by in an anti-clockwise direction in radians. /// Angle to rotate the vector by in an anti-clockwise direction in radians.
/// </param> /// </param>
/// <returns>The Vector3 that represents the rotated vector.</returns> /// <returns>The Vector3 that represents the rotated vector.</returns>
static Vector3 RotateRadians(Vector3 vec, double radians); static Vector3 RotateRadians(Vector3 vec, float radians);
/// <summary> /// <summary>
/// Rotates a Vector3 on the Z-axis by a specified angle in an anti-clockwise /// Rotates a Vector3 on the Z-axis by a specified angle in an anti-clockwise
/// direction. /// direction.
@ -283,7 +284,7 @@ namespace SHADE
/// Angle to rotate the vector by in an anti-clockwise direction in degrees. /// Angle to rotate the vector by in an anti-clockwise direction in degrees.
/// </param> /// </param>
/// <returns>The Vector3 that represents the rotated vector.</returns> /// <returns>The Vector3 that represents the rotated vector.</returns>
static Vector3 RotateDegrees(Vector3 vec, double degrees); static Vector3 RotateDegrees(Vector3 vec, float degrees);
/// <summary> /// <summary>
/// Computes and returns a Vector3 that is made from the smallest components of /// Computes and returns a Vector3 that is made from the smallest components of
/// the two specified Vector3s. /// the two specified Vector3s.
@ -311,25 +312,25 @@ namespace SHADE
/// This is most commonly used to find a point some fraction of the way along a /// This is most commonly used to find a point some fraction of the way along a
/// line between two endpoints. /// line between two endpoints.
/// </summary> /// </summary>
/// <param name="a">The start Vector3, returned when t = 0.0.</param> /// <param name="a">The start Vector3, returned when t = 0.0f.</param>
/// <param name="b">The end Vector3, returned when t = 1.0.</param> /// <param name="b">The end Vector3, returned when t = 1.0f.</param>
/// <param name="t"> /// <param name="t">
/// Value used to interpolate between a and b which is clamped to /// Value used to interpolate between a and b which is clamped to
/// the range[0, 1]. /// the range[0, 1].
/// </param> /// </param>
/// <returns>The interpolated Vector3.</returns> /// <returns>The interpolated Vector3.</returns>
static Vector3 Lerp(Vector3 a, Vector3 b, double t); static Vector3 Lerp(Vector3 a, Vector3 b, float t);
/// <summary> /// <summary>
/// Linearly interpolates between two specified points. /// Linearly interpolates between two specified points.
/// This is most commonly used to find a point some fraction of the way along a /// This is most commonly used to find a point some fraction of the way along a
/// line between two endpoints. /// line between two endpoints.
/// Unlike Lerp(), t is not clamped to a range at all. /// Unlike Lerp(), t is not clamped to a range at all.
/// </summary> /// </summary>
/// <param name="a">The start Vector3, returned when t = 0.0.</param> /// <param name="a">The start Vector3, returned when t = 0.0f.</param>
/// <param name="b">The end Vector3, returned when t = 1.0.</param> /// <param name="b">The end Vector3, returned when t = 1.0f.</param>
/// <param name="t">Value used to interpolate between a and b.</param> /// <param name="t">Value used to interpolate between a and b.</param>
/// <returns>The interpolated Vector3.</returns> /// <returns>The interpolated Vector3.</returns>
static Vector3 LerpUnclamped(Vector3 a, Vector3 b, double t); static Vector3 LerpUnclamped(Vector3 a, Vector3 b, float t);
/// <summary> /// <summary>
/// Moves a point current towards target. /// Moves a point current towards target.
/// Similar to Lerp(), however, the function will ensure that the distance never /// Similar to Lerp(), however, the function will ensure that the distance never
@ -340,7 +341,7 @@ namespace SHADE
/// <param name="target">The target position to move to.</param> /// <param name="target">The target position to move to.</param>
/// <param name="maxDistanceDelta">Maximum distance moved per call.</param> /// <param name="maxDistanceDelta">Maximum distance moved per call.</param>
/// <returns>Vector representing the moved point.</returns> /// <returns>Vector representing the moved point.</returns>
static Vector3 MoveTowards(Vector3 current, Vector3 target, double maxDistanceDelta); static Vector3 MoveTowards(Vector3 current, Vector3 target, float maxDistanceDelta);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Overloaded Operators */ /* Overloaded Operators */
@ -374,7 +375,7 @@ namespace SHADE
/// <param name="lhs">Vector3 to multiply with.</param> /// <param name="lhs">Vector3 to multiply with.</param>
/// <param name="rhs">Scalar to multiply with.</param> /// <param name="rhs">Scalar to multiply with.</param>
/// <returns>The result of the scalar multiplication.</returns> /// <returns>The result of the scalar multiplication.</returns>
static Vector3 operator*(Vector3 lhs, double rhs); static Vector3 operator*(Vector3 lhs, float rhs);
/// <summary> /// <summary>
/// Calculates the division of a Vector3 with a scalar value and returns /// Calculates the division of a Vector3 with a scalar value and returns
/// the result. /// the result.
@ -382,7 +383,7 @@ namespace SHADE
/// <param name="lhs">Scalar to divide with.</param> /// <param name="lhs">Scalar to divide with.</param>
/// <param name="rhs">Vector3 to divide with.</param> /// <param name="rhs">Vector3 to divide with.</param>
/// <returns>The result of the scalar division.</returns> /// <returns>The result of the scalar division.</returns>
static Vector3 operator/(Vector3 lhs, double rhs); static Vector3 operator/(Vector3 lhs, float rhs);
/// <summary> /// <summary>
/// Checks if two Vector3s are approximately equal. This is equivalent to /// Checks if two Vector3s are approximately equal. This is equivalent to
/// calling Vector3.IsNear() with default tolerance values. /// calling Vector3.IsNear() with default tolerance values.

View File

@ -35,10 +35,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHVec3 Convert::ToNative(Vector3 vec) SHVec3 Convert::ToNative(Vector3 vec)
{ {
const double X = vec.x; return SHVec3(vec.x, vec.y, vec.z);
const double Y = vec.y;
const double Z = vec.z;
return SHVec3(X, Y, Z);
} }
Vector3 Convert::ToCLI(const SHVec3& vec) Vector3 Convert::ToCLI(const SHVec3& vec)
{ {
@ -46,9 +43,7 @@ namespace SHADE
} }
SHVec2 Convert::ToNative(Vector2 vec) SHVec2 Convert::ToNative(Vector2 vec)
{ {
const double X = vec.x; return SHVec2(vec.x, vec.y);
const double Y = vec.y;
return SHVec2(X, Y);
} }
Vector2 Convert::ToCLI(const SHVec2& vec) Vector2 Convert::ToCLI(const SHVec2& vec)
@ -56,6 +51,16 @@ namespace SHADE
return Vector2(vec.x, vec.y); return Vector2(vec.x, vec.y);
} }
SHQuaternion Convert::ToNative(Quaternion quat)
{
return SHQuaternion{ quat.x, quat.y, quat.z, quat.w };
}
Quaternion Convert::ToCLI(const SHQuaternion& quat)
{
return Quaternion{ quat.x, quat.y, quat.z, quat.w };
}
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* String Conversions */ /* String Conversions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/

View File

@ -18,10 +18,12 @@ of DigiPen Institute of Technology is prohibited.
#include "ECS_Base/Entity/SHEntity.h" #include "ECS_Base/Entity/SHEntity.h"
#include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec2.h"
#include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec3.h"
#include "Math/SHQuaternion.h"
// Project Includes // Project Includes
#include "Engine/Entity.hxx" #include "Engine/Entity.hxx"
#include "Math/Vector2.hxx" #include "Math/Vector2.hxx"
#include "Math/Vector3.hxx" #include "Math/Vector3.hxx"
#include "Math/Quaternion.hxx"
namespace SHADE namespace SHADE
{ {
@ -74,6 +76,18 @@ namespace SHADE
/// <param name="vec">The native Vector2 to convert from.</param> /// <param name="vec">The native Vector2 to convert from.</param>
/// <returns>Managed copy of a native Vector2.</returns> /// <returns>Managed copy of a native Vector2.</returns>
static Vector2 ToCLI(const SHVec2& vec); static Vector2 ToCLI(const SHVec2& vec);
/// <summary>
/// Converts from a managed Quaternion to a native Quaternion.
/// </summary>
/// <param name="quat">The managed Quaternion to convert from.</param>
/// <returns>Native copy of a managed Quaternion.</returns>
static SHQuaternion ToNative(Quaternion quat);
/// <summary>
/// Converts from a native Quaternion to a managed Quaternion.
/// </summary>
/// <param name="quat">The native Quaternion to convert from.</param>
/// <returns>Managed copy of a native Quaternion.</returns>
static Quaternion ToCLI(const SHQuaternion& quat);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* String Conversions */ /* String Conversions */