SP3-16 Quaternions #112
Binary file not shown.
|
@ -1,48 +0,0 @@
|
|||
[Window][MainStatusBar]
|
||||
Pos=0,1060
|
||||
Size=1920,20
|
||||
Collapsed=0
|
||||
|
||||
[Window][SHEditorMenuBar]
|
||||
Pos=0,48
|
||||
Size=1920,1012
|
||||
Collapsed=0
|
||||
|
||||
[Window][Hierarchy Panel]
|
||||
Pos=0,142
|
||||
Size=349,918
|
||||
Collapsed=0
|
||||
DockId=0x00000004,0
|
||||
|
||||
[Window][Debug##Default]
|
||||
Pos=60,60
|
||||
Size=400,400
|
||||
Collapsed=0
|
||||
|
||||
[Window][Inspector]
|
||||
Pos=1483,48
|
||||
Size=437,1012
|
||||
Collapsed=0
|
||||
DockId=0x00000006,0
|
||||
|
||||
[Window][Profiler]
|
||||
Pos=0,48
|
||||
Size=349,92
|
||||
Collapsed=0
|
||||
DockId=0x00000003,0
|
||||
|
||||
[Window][Viewport]
|
||||
Pos=351,48
|
||||
Size=1130,1012
|
||||
Collapsed=0
|
||||
DockId=0x00000002,0
|
||||
|
||||
[Docking][Data]
|
||||
DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,79 Size=1920,1012 Split=X
|
||||
DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1481,1036 Split=X
|
||||
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=349,1036 Split=Y Selected=0x1E6EB881
|
||||
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881
|
||||
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Selected=0xE096E5AE
|
||||
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1130,1036 CentralNode=1 Selected=0x13926F0B
|
||||
DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=437,1036 Selected=0xE7039252
|
||||
|
|
@ -151,9 +151,8 @@ namespace Sandbox
|
|||
SHSceneManager::SceneUpdate(0.016f);
|
||||
#endif
|
||||
SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, 0.016f);
|
||||
editor->PollPicking();
|
||||
//editor->PollPicking();
|
||||
}
|
||||
|
||||
// Finish all graphics jobs first
|
||||
graphicsSystem->AwaitGraphicsExecution();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "Physics/Components/SHColliderComponent.h"
|
||||
|
||||
#include "Assets/SHAssetManager.h"
|
||||
#include "Resource/SHResourceManager.h"
|
||||
|
||||
using namespace SHADE;
|
||||
|
||||
|
@ -40,34 +41,22 @@ namespace Sandbox
|
|||
const auto CUBE_MESH = SHADE::SHPrimitiveGenerator::Cube(*graphicsSystem);
|
||||
|
||||
//Test Racoon mesh
|
||||
auto meshes = SHADE::SHAssetManager::GetAllMeshes();
|
||||
std::vector<Handle<SHMesh>> handles;
|
||||
for (auto const& mesh : meshes)
|
||||
{
|
||||
if (mesh.header.meshName == "Cube.012")
|
||||
{
|
||||
handles.push_back(graphicsSystem->AddMesh(
|
||||
mesh.header.vertexCount,
|
||||
mesh.vertexPosition.data(),
|
||||
mesh.texCoords.data(),
|
||||
mesh.vertexTangent.data(),
|
||||
mesh.vertexNormal.data(),
|
||||
mesh.header.indexCount,
|
||||
mesh.indices.data()
|
||||
));
|
||||
}
|
||||
}
|
||||
graphicsSystem->BuildMeshBuffers();
|
||||
|
||||
// Load Textures
|
||||
auto textures = SHADE::SHAssetManager::GetAllTextures();
|
||||
std::vector<Handle<SHTexture>> texHandles;
|
||||
for (const auto& tex : textures)
|
||||
for (const auto& asset : SHAssetManager::GetAllAssets())
|
||||
{
|
||||
auto texture = graphicsSystem->Add(tex);
|
||||
texHandles.push_back(texture);
|
||||
switch (asset.type)
|
||||
{
|
||||
case AssetType::MESH:
|
||||
if (asset.name == "Cube.012")
|
||||
handles.emplace_back(SHResourceManager::LoadOrGet<SHMesh>(asset.id));
|
||||
break;
|
||||
case AssetType::TEXTURE:
|
||||
texHandles.emplace_back(SHResourceManager::LoadOrGet<SHTexture>(asset.id));
|
||||
break;
|
||||
}
|
||||
graphicsSystem->BuildTextures();
|
||||
}
|
||||
SHResourceManager::FinaliseChanges();
|
||||
|
||||
// Create Materials
|
||||
auto matInst = graphicsSystem->AddOrGetBaseMaterialInstance();
|
||||
|
|
|
@ -62,6 +62,11 @@ namespace SHADE
|
|||
}
|
||||
}
|
||||
|
||||
void SHAssetManager::Unload(AssetID assetId) noexcept
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept
|
||||
{
|
||||
if (!IsRecognised(path.extension().string().c_str()))
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace SHADE
|
|||
* \brief Deallocate all memory used by resource data
|
||||
****************************************************************************/
|
||||
static void Unload() noexcept;
|
||||
static void Unload(AssetID assetId) noexcept;
|
||||
|
||||
/****************************************************************************
|
||||
* \brief Load all resources that are in the folder
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#include "SHpch.h"
|
||||
#include "SHCameraComponent.h"
|
||||
#include "ECS_Base/Managers/SHComponentManager.h"
|
||||
|
||||
#include "SHCameraSystem.h"
|
||||
#include "ECS_Base/Managers/SHSystemManager.h"
|
||||
#include "Math/Transform/SHTransformComponent.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
@ -22,33 +24,69 @@ namespace SHADE
|
|||
void SHCameraComponent::SetYaw(float yaw) noexcept
|
||||
{
|
||||
this->yaw = yaw;
|
||||
if (SHComponentManager::HasComponent<SHTransformComponent>(GetEID()))
|
||||
{
|
||||
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(GetEID());
|
||||
SHVec3 rotation = transform->GetWorldRotation();
|
||||
transform->SetWorldRotation(SHVec3{rotation.x,yaw, rotation.z});
|
||||
}
|
||||
dirtyView = true;
|
||||
}
|
||||
|
||||
void SHCameraComponent::SetPitch(float pitch) noexcept
|
||||
{
|
||||
this->pitch = pitch;
|
||||
if (SHComponentManager::HasComponent<SHTransformComponent>(GetEID()))
|
||||
{
|
||||
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(GetEID());
|
||||
SHVec3 rotation = transform->GetWorldRotation();
|
||||
transform->SetWorldRotation(SHVec3{ pitch,rotation.y, rotation.z });
|
||||
}
|
||||
dirtyView = true;
|
||||
}
|
||||
|
||||
void SHCameraComponent::SetRoll(float roll) noexcept
|
||||
{
|
||||
this->roll = roll;
|
||||
if (SHComponentManager::HasComponent<SHTransformComponent>(GetEID()))
|
||||
{
|
||||
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(GetEID());
|
||||
SHVec3 rotation = transform->GetWorldRotation();
|
||||
transform->SetWorldRotation(SHVec3{ rotation.x,rotation.y, roll});
|
||||
}
|
||||
dirtyView = true;
|
||||
}
|
||||
void SHCameraComponent::SetPositionX(float x) noexcept
|
||||
{
|
||||
position.x = x;
|
||||
if (SHComponentManager::HasComponent<SHTransformComponent>(GetEID()))
|
||||
{
|
||||
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(GetEID());
|
||||
SHVec3 position = transform->GetWorldPosition();
|
||||
transform->SetWorldRotation(SHVec3{ x,position.y, position.z});
|
||||
}
|
||||
dirtyView = true;
|
||||
}
|
||||
void SHCameraComponent::SetPositionY(float y) noexcept
|
||||
{
|
||||
position.y = y;
|
||||
if (SHComponentManager::HasComponent<SHTransformComponent>(GetEID()))
|
||||
{
|
||||
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(GetEID());
|
||||
SHVec3 position = transform->GetWorldPosition();
|
||||
transform->SetWorldRotation(SHVec3{ position.x,y, position.z });
|
||||
}
|
||||
dirtyView = true;
|
||||
}
|
||||
void SHCameraComponent::SetPositionZ(float z) noexcept
|
||||
{
|
||||
position.z = z;
|
||||
if (SHComponentManager::HasComponent<SHTransformComponent>(GetEID()))
|
||||
{
|
||||
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(GetEID());
|
||||
SHVec3 position = transform->GetWorldPosition();
|
||||
transform->SetWorldRotation(SHVec3{ position.x,position.y, z });
|
||||
}
|
||||
dirtyView = true;
|
||||
}
|
||||
void SHCameraComponent::SetPosition(float x,float y, float z) noexcept
|
||||
|
@ -56,11 +94,23 @@ namespace SHADE
|
|||
position.x = x;
|
||||
position.y = y;
|
||||
position.z = z;
|
||||
if (SHComponentManager::HasComponent<SHTransformComponent>(GetEID()))
|
||||
{
|
||||
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(GetEID());
|
||||
SHVec3 position = transform->GetWorldPosition();
|
||||
transform->SetWorldRotation(SHVec3{ x,y, z });
|
||||
}
|
||||
dirtyView = true;
|
||||
}
|
||||
void SHCameraComponent::SetPosition(SHVec3& pos) noexcept
|
||||
{
|
||||
this->position = pos;
|
||||
if (SHComponentManager::HasComponent<SHTransformComponent>(GetEID()))
|
||||
{
|
||||
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(GetEID());
|
||||
SHVec3 position = transform->GetWorldPosition();
|
||||
transform->SetWorldRotation(pos);
|
||||
}
|
||||
dirtyView = true;
|
||||
}
|
||||
|
||||
|
@ -128,4 +178,12 @@ namespace SHADE
|
|||
return projMatrix;
|
||||
}
|
||||
|
||||
void SHCameraComponent::SetMainCamera(size_t directorCameraIndex) noexcept
|
||||
{
|
||||
auto system = SHSystemManager::GetSystem<SHCameraSystem>();
|
||||
system->GetDirector(directorCameraIndex)->SetMainCamera(*this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -70,6 +70,8 @@ namespace SHADE
|
|||
const SHMatrix& GetViewMatrix() const noexcept;
|
||||
const SHMatrix& GetProjMatrix() const noexcept;
|
||||
|
||||
void SetMainCamera(size_t cameraDirectorIndex = 0) noexcept;
|
||||
|
||||
|
||||
float movementSpeed;
|
||||
SHVec3 turnSpeed;
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
#include "SHpch.h"
|
||||
#include "SHCameraDirector.h"
|
||||
#include "SHCameraComponent.h"
|
||||
#include "ECS_Base/Managers/SHComponentManager.h"
|
||||
#include "ECS_Base/SHECSMacros.h"
|
||||
#include "ECS_Base/Managers/SHEntityManager.h"
|
||||
#include "Tools/SHLog.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
SHCameraDirector::SHCameraDirector()
|
||||
:mainCameraEID(MAX_EID), transitionCameraEID(MAX_EID)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SHMatrix SHCameraDirector::GetViewMatrix() const noexcept
|
||||
{
|
||||
return viewMatrix;
|
||||
}
|
||||
SHMatrix SHCameraDirector::GetProjMatrix() const noexcept
|
||||
{
|
||||
return projMatrix;
|
||||
}
|
||||
SHMatrix SHCameraDirector::GetVPMatrix() const noexcept
|
||||
{
|
||||
return projMatrix * viewMatrix;
|
||||
}
|
||||
|
||||
void SHCameraDirector::UpdateMatrix() noexcept
|
||||
{
|
||||
if (mainCameraEID == MAX_EID)
|
||||
{
|
||||
auto& dense = SHComponentManager::GetDense<SHCameraComponent>();
|
||||
if (dense.size() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
mainCameraEID = dense[0].GetEID();
|
||||
}
|
||||
SHCameraComponent* camComponent = SHComponentManager::GetComponent_s<SHCameraComponent>(mainCameraEID);
|
||||
if (!camComponent)
|
||||
{
|
||||
SHLOG_WARNING("Camera Director warning: Entity does not have a camera");
|
||||
}
|
||||
else
|
||||
{
|
||||
viewMatrix = camComponent->GetViewMatrix();
|
||||
projMatrix = camComponent->GetProjMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
void SHCameraDirector::SetMainCamera(SHCameraComponent& camera) noexcept
|
||||
{
|
||||
if (SHEntityManager::IsValidEID(camera.GetEID()) == false)
|
||||
{
|
||||
SHLOG_WARNING("Camera Director Warning: Attempting to set an invalid entity as main camera.")
|
||||
return;
|
||||
}
|
||||
mainCameraEID = camera.GetEID();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include "SH_API.h"
|
||||
#include "ECS_Base/Entity/SHEntity.h"
|
||||
#include "Math/SHMatrix.h"
|
||||
#include "Resource/SHHandle.h"
|
||||
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
class SHCameraComponent;
|
||||
|
||||
|
||||
|
||||
class SH_API SHCameraDirector
|
||||
{
|
||||
public:
|
||||
SHCameraDirector();
|
||||
~SHCameraDirector() = default;
|
||||
|
||||
|
||||
EntityID mainCameraEID;
|
||||
EntityID transitionCameraEID;
|
||||
|
||||
SHMatrix GetViewMatrix() const noexcept;
|
||||
SHMatrix GetProjMatrix() const noexcept;
|
||||
SHMatrix GetVPMatrix() const noexcept;
|
||||
void UpdateMatrix() noexcept;
|
||||
void SetMainCamera(SHCameraComponent& cam) noexcept;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
protected:
|
||||
SHMatrix viewMatrix;
|
||||
SHMatrix projMatrix;
|
||||
|
||||
};
|
||||
|
||||
typedef Handle<SHCameraDirector> DirectorHandle;
|
||||
|
||||
}
|
|
@ -3,18 +3,18 @@
|
|||
#include "Math/SHMathHelpers.h"
|
||||
#include "Input/SHInputManager.h"
|
||||
#include "Math/Vector/SHVec2.h"
|
||||
|
||||
#include "ECS_Base/Managers/SHComponentManager.h"
|
||||
#include "Math/Transform/SHTransformComponent.h"
|
||||
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
||||
void SHCameraSystem::EditorCameraUpdate::Execute(double dt) noexcept
|
||||
void SHCameraSystem::UpdateEditorCamera(double dt) noexcept
|
||||
{
|
||||
SHCameraSystem* system = static_cast<SHCameraSystem*>(GetSystem());
|
||||
auto& camera = system->editorCamera;
|
||||
|
||||
auto& camera = editorCamera;
|
||||
SHVec3 view, right, UP;
|
||||
system->GetCameraAxis(camera, view, right, UP);
|
||||
GetCameraAxis(camera, view, right, UP);
|
||||
|
||||
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::A))
|
||||
{
|
||||
|
@ -58,6 +58,59 @@ namespace SHADE
|
|||
camera.dirtyView = true;
|
||||
}
|
||||
|
||||
UpdateCameraComponent(editorCamera);
|
||||
}
|
||||
void SHCameraSystem::EditorCameraUpdate::Execute(double dt) noexcept
|
||||
{
|
||||
SHCameraSystem* system = static_cast<SHCameraSystem*>(GetSystem());
|
||||
auto& camera = system->editorCamera;
|
||||
SHVec3 view, right, UP;
|
||||
system->GetCameraAxis(camera, view, right, UP);
|
||||
|
||||
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::A))
|
||||
{
|
||||
std::cout << "Camera movement: "<<right.x<<", " << right.y << std::endl;
|
||||
camera.position -= right * dt * camera.movementSpeed;
|
||||
camera.dirtyView = true;
|
||||
}
|
||||
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::D))
|
||||
{
|
||||
camera.position += right * dt * camera.movementSpeed;
|
||||
camera.dirtyView = true;
|
||||
}
|
||||
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::W))
|
||||
{
|
||||
camera.position += view * dt * camera.movementSpeed;
|
||||
camera.dirtyView = true;
|
||||
}
|
||||
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::S))
|
||||
{
|
||||
camera.position -= view * dt * camera.movementSpeed;
|
||||
camera.dirtyView = true;
|
||||
}
|
||||
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::Q))
|
||||
{
|
||||
camera.position += UP * dt * camera.movementSpeed;
|
||||
camera.dirtyView = true;
|
||||
}
|
||||
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::E))
|
||||
{
|
||||
camera.position -= UP * dt * camera.movementSpeed;
|
||||
camera.dirtyView = true;
|
||||
}
|
||||
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::RMB))
|
||||
{
|
||||
double mouseX, mouseY;
|
||||
SHInputManager::GetMouseVelocity(&mouseX,&mouseY);
|
||||
|
||||
//std::cout << camera.yaw << std::endl;
|
||||
|
||||
camera.pitch -= mouseY * dt * camera.turnSpeed.x;
|
||||
camera.yaw -= mouseX * dt * camera.turnSpeed.y;
|
||||
camera.dirtyView = true;
|
||||
}
|
||||
|
||||
std::cout << "Camera position: " << camera.position.x << " " << camera.position.y << std::endl;
|
||||
system->UpdateCameraComponent(system->editorCamera);
|
||||
}
|
||||
|
||||
|
@ -83,10 +136,25 @@ namespace SHADE
|
|||
|
||||
void SHCameraSystem::UpdateCameraComponent(SHCameraComponent& camera) noexcept
|
||||
{
|
||||
if (SHComponentManager::HasComponent<SHTransformComponent>(camera.GetEID()) == true && &camera != &editorCamera)
|
||||
{
|
||||
auto transform = SHComponentManager::GetComponent<SHTransformComponent>(camera.GetEID());
|
||||
SHVec3 rotation = transform->GetWorldRotation();
|
||||
camera.pitch = rotation.x;
|
||||
camera.yaw = rotation.y;
|
||||
camera.roll = rotation.z;
|
||||
camera.position = transform->GetWorldPosition();
|
||||
}
|
||||
|
||||
|
||||
if (camera.dirtyView)
|
||||
{
|
||||
|
||||
SHVec3 view, right, UP;
|
||||
|
||||
|
||||
//ClampCameraRotation(camera);
|
||||
|
||||
GetCameraAxis(camera, view, right, UP);
|
||||
|
||||
camera.viewMatrix = SHMatrix::Identity;
|
||||
|
@ -154,7 +222,6 @@ namespace SHADE
|
|||
|
||||
target = SHVec3::RotateY(target, SHMath::DegreesToRadians(camera.yaw));
|
||||
target =SHVec3::RotateX(target, SHMath::DegreesToRadians(camera.pitch));
|
||||
std::cout << "Target vec: " << target.x<<", "<<target.y<<", "<<target.z << std::endl;
|
||||
target += camera.position;
|
||||
////SHVec3::RotateZ(target, SHMath::DegreesToRadians(camera.roll));
|
||||
|
||||
|
@ -169,5 +236,55 @@ namespace SHADE
|
|||
upVec = SHVec3::Cross(forward, right);
|
||||
}
|
||||
|
||||
void SHCameraSystem::CameraSystemUpdate::Execute(double dt) noexcept
|
||||
{
|
||||
SHCameraSystem* system = static_cast<SHCameraSystem*>(GetSystem());
|
||||
auto& dense = SHComponentManager::GetDense<SHCameraComponent>();
|
||||
for (auto& cam : dense)
|
||||
{
|
||||
system->UpdateCameraComponent(cam);
|
||||
}
|
||||
for (auto& handle : system->directorHandleList)
|
||||
{
|
||||
handle->UpdateMatrix();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
DirectorHandle SHCameraSystem::CreateDirector() noexcept
|
||||
{
|
||||
auto handle = directorLibrary.Create();
|
||||
directorHandleList.emplace_back(handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
DirectorHandle SHCameraSystem::GetDirector(size_t index) noexcept
|
||||
{
|
||||
if (index < directorHandleList.size())
|
||||
{
|
||||
return directorHandleList[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
return CreateDirector();
|
||||
}
|
||||
}
|
||||
void SHCameraSystem::ClampCameraRotation(SHCameraComponent& camera) noexcept
|
||||
{
|
||||
|
||||
|
||||
|
||||
if (camera.pitch > 85)
|
||||
camera.SetPitch(85);
|
||||
if (camera.pitch < -85)
|
||||
camera.SetPitch(-85);
|
||||
if (camera.roll > 85)
|
||||
camera.SetRoll(85);
|
||||
if (camera.roll < -85)
|
||||
camera.SetRoll(-85);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
#include "ECS_Base/System/SHSystem.h"
|
||||
#include "SHCameraComponent.h"
|
||||
#include "ECS_Base/System/SHSystemRoutine.h"
|
||||
#include "Resource/SHResourceLibrary.h"
|
||||
#include "SHCameraDirector.h"
|
||||
#include "SH_API.h"
|
||||
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
class SH_API SHCameraSystem final : public SHSystem
|
||||
|
@ -15,7 +16,8 @@ namespace SHADE
|
|||
//This is not tied to any entity. Hence this EID should not be used.
|
||||
SHCameraComponent editorCamera;
|
||||
|
||||
|
||||
SHResourceLibrary<SHCameraDirector> directorLibrary;
|
||||
std::vector<DirectorHandle> directorHandleList;
|
||||
|
||||
public:
|
||||
SHCameraSystem(void) = default;
|
||||
|
@ -34,13 +36,26 @@ namespace SHADE
|
|||
};
|
||||
friend class EditorCameraUpdate;
|
||||
|
||||
SHCameraComponent* GetEditorCamera (void) noexcept;
|
||||
class SH_API CameraSystemUpdate final: public SHSystemRoutine
|
||||
{
|
||||
public:
|
||||
CameraSystemUpdate() : SHSystemRoutine("Camera System Update", false) {};
|
||||
virtual void Execute(double dt)noexcept override final;
|
||||
};
|
||||
friend class CameraSystemUpdate;
|
||||
|
||||
|
||||
SHCameraComponent* GetEditorCamera (void) noexcept;
|
||||
void GetCameraAxis(SHCameraComponent const& camera, SHVec3& forward, SHVec3& right, SHVec3& up) const noexcept;
|
||||
DirectorHandle CreateDirector() noexcept;
|
||||
DirectorHandle GetDirector(size_t index) noexcept;
|
||||
void ClampCameraRotation(SHCameraComponent& camera) noexcept;
|
||||
void UpdateEditorCamera(double dt) noexcept;
|
||||
protected:
|
||||
|
||||
void UpdateCameraComponent(SHCameraComponent& camera) noexcept;
|
||||
|
||||
void GetCameraAxis(SHCameraComponent const& camera, SHVec3& forward, SHVec3& right, SHVec3& up) const noexcept;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace SHADE
|
|||
class SHCommand : SHBaseCommand
|
||||
{
|
||||
public:
|
||||
using SHCommandPtr = std::unique_ptr<T>;
|
||||
typedef std::function<void(T const&)> SetterFunction;
|
||||
|
||||
SHCommand(T const& oldVal, T const& value, SetterFunction setFnc)
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace SHADE
|
|||
SHCommandManager::CommandStack SHCommandManager::undoStack{};
|
||||
SHCommandManager::CommandStack SHCommandManager::redoStack{};
|
||||
|
||||
void SHCommandManager::PerformCommand(CommandPtr commandPtr, bool const& overrideValue)
|
||||
void SHCommandManager::PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue)
|
||||
{
|
||||
redoStack = CommandStack();
|
||||
commandPtr->Execute();
|
||||
|
@ -27,7 +27,7 @@ namespace SHADE
|
|||
}
|
||||
}
|
||||
|
||||
void SHCommandManager::RegisterCommand(CommandPtr commandPtr)
|
||||
void SHCommandManager::RegisterCommand(BaseCommandPtr commandPtr)
|
||||
{
|
||||
undoStack.push(commandPtr);
|
||||
}
|
||||
|
@ -59,4 +59,14 @@ namespace SHADE
|
|||
{
|
||||
return redoStack.size();
|
||||
}
|
||||
|
||||
void SHCommandManager::PopLatestCommandFromRedoStack()
|
||||
{
|
||||
redoStack.pop();
|
||||
}
|
||||
|
||||
void SHCommandManager::PopLatestCommandFromUndoStack()
|
||||
{
|
||||
undoStack.pop();
|
||||
}
|
||||
}//namespace SHADE
|
||||
|
|
|
@ -19,16 +19,21 @@ namespace SHADE
|
|||
//#==============================================================#
|
||||
//|| Type Aliases ||
|
||||
//#==============================================================#
|
||||
using CommandPtr = std::shared_ptr<SHBaseCommand>;
|
||||
using CommandStack = std::stack<CommandPtr>;
|
||||
using BaseCommandPtr = std::shared_ptr<SHBaseCommand>;
|
||||
template<typename T>
|
||||
using SHCommandPtr = std::shared_ptr<SHCommand<T>>;
|
||||
using CommandStack = std::stack<BaseCommandPtr>;
|
||||
|
||||
static void PerformCommand(CommandPtr commandPtr, bool const& overrideValue = false);
|
||||
static void RegisterCommand(CommandPtr commandPtr);
|
||||
static void PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue = false);
|
||||
static void RegisterCommand(BaseCommandPtr commandPtr);
|
||||
static void UndoCommand();
|
||||
static void RedoCommand();
|
||||
static std::size_t GetUndoStackSize();
|
||||
static std::size_t GetRedoStackSize();
|
||||
|
||||
static void PopLatestCommandFromRedoStack();
|
||||
static void PopLatestCommandFromUndoStack();
|
||||
|
||||
private:
|
||||
static CommandStack undoStack;
|
||||
static CommandStack redoStack;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <imgui.h>
|
||||
|
||||
#include "Serialization/SHSerialization.h"
|
||||
#include "Tools/SHClipboardUtilities.h"
|
||||
|
||||
|
||||
namespace SHADE
|
||||
|
@ -52,6 +53,7 @@ namespace SHADE
|
|||
if(const auto root = sceneGraph.GetRoot())
|
||||
{
|
||||
auto const& children = root->GetChildren();
|
||||
|
||||
for (const auto child : children)
|
||||
{
|
||||
RecursivelyDrawEntityNode(child);
|
||||
|
@ -79,6 +81,8 @@ namespace SHADE
|
|||
|
||||
void SHHierarchyPanel::SetScrollTo(EntityID eid)
|
||||
{
|
||||
if(eid == MAX_EID)
|
||||
return;
|
||||
scrollTo = eid;
|
||||
}
|
||||
|
||||
|
@ -104,7 +108,7 @@ namespace SHADE
|
|||
}
|
||||
if (ImGui::SmallButton(ICON_MD_ADD_CIRCLE))
|
||||
{
|
||||
SHEntityManager::CreateEntity();
|
||||
SHCommandManager::PerformCommand(std::make_shared<SHCreateEntityCommand>());
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
|
@ -144,23 +148,32 @@ namespace SHADE
|
|||
|
||||
auto* entity = SHEntityManager::GetEntityByID(currentNode->GetEntityID());
|
||||
//Draw Node
|
||||
bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast<void*>(entity), nodeFlags, "%u: %s", EntityHandleGenerator::GetIndex(eid), entity->name.c_str());
|
||||
bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast<void*>(entity), nodeFlags, "%u: %s", SHEntityManager::GetEntityIndex(eid), entity->name.c_str());
|
||||
const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
|
||||
|
||||
//Check For Begin Drag
|
||||
if (SHDragDrop::BeginSource())
|
||||
{
|
||||
ImGui::Text("Moving EID: %zu", eid);
|
||||
SHDragDrop::SetPayload<EntityID>(DRAG_EID, &eid);
|
||||
std::string moveLabel = "Moving EID: ";
|
||||
if(!isSelected)
|
||||
editor->selectedEntities.push_back(eid);
|
||||
for(int i = 0; i < static_cast<int>(editor->selectedEntities.size()); ++i)
|
||||
{
|
||||
moveLabel.append(std::to_string(editor->selectedEntities[i]));
|
||||
if(i + 1 < static_cast<int>(editor->selectedEntities.size()))
|
||||
{
|
||||
moveLabel.append(", ");
|
||||
}
|
||||
}
|
||||
ImGui::Text(moveLabel.c_str());
|
||||
SHDragDrop::SetPayload<std::vector<EntityID>>(DRAG_EID, &editor->selectedEntities);
|
||||
SHDragDrop::EndSource();
|
||||
}
|
||||
else if (SHDragDrop::BeginTarget()) //If Received DragDrop
|
||||
{
|
||||
if (const EntityID* eidPayload = SHDragDrop::AcceptPayload<EntityID>(DRAG_EID)) //If payload is valid
|
||||
if (const std::vector<EntityID>* eidPayload = SHDragDrop::AcceptPayload<std::vector<EntityID>>(DRAG_EID)) //If payload is valid
|
||||
{
|
||||
EntityID const dropEID = *eidPayload;
|
||||
if(!sceneGraph.GetChild(dropEID, eid))
|
||||
sceneGraph.SetParent(dropEID, eid); //Set dropEID parent to eid (belonging to current Node)
|
||||
ParentSelectedEntities(eid);
|
||||
SHDragDrop::EndTarget();
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +188,15 @@ namespace SHADE
|
|||
}
|
||||
if(ImGui::Selectable("Copy"))
|
||||
{
|
||||
SHLOG_INFO(SHSerialization::SerializeEntitiesToString(editor->selectedEntities))
|
||||
SHClipboardUtilities::WriteToClipboard(SHSerialization::SerializeEntitiesToString(editor->selectedEntities));
|
||||
}
|
||||
if(ImGui::Selectable("Paste"))
|
||||
{
|
||||
SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard()));
|
||||
}
|
||||
if(ImGui::Selectable("Paste as Child"))
|
||||
{
|
||||
SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard(), eid));
|
||||
}
|
||||
if(ImGui::Selectable(std::format("{} Delete", ICON_MD_DELETE).data()))
|
||||
{
|
||||
|
@ -184,7 +205,7 @@ namespace SHADE
|
|||
|
||||
if((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data()))
|
||||
{
|
||||
sceneGraph.SetParent(currentNode->GetEntityID(), nullptr);
|
||||
ParentSelectedEntities(MAX_EID);
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
@ -196,7 +217,15 @@ namespace SHADE
|
|||
{
|
||||
if (!isSelected)
|
||||
{
|
||||
if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
|
||||
if(ImGui::IsKeyDown(ImGuiKey_LeftShift))
|
||||
{
|
||||
if(editor->selectedEntities.size() >= 1)
|
||||
{
|
||||
SelectRangeOfEntities(editor->selectedEntities[0], eid);
|
||||
}
|
||||
else editor->selectedEntities.clear();
|
||||
}
|
||||
else if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
|
||||
editor->selectedEntities.clear();
|
||||
editor->selectedEntities.push_back(eid);
|
||||
}//if not selected
|
||||
|
@ -243,4 +272,90 @@ namespace SHADE
|
|||
{
|
||||
SHEntityManager::CreateEntity(MAX_EID, "DefaultChild", parentEID);
|
||||
}
|
||||
|
||||
void SHHierarchyPanel::ParentSelectedEntities(EntityID parentEID) const noexcept
|
||||
{
|
||||
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
|
||||
auto const editor = SHSystemManager::GetSystem<SHEditor>();
|
||||
SHEntityParentCommand::EntityParentData entityParentData;
|
||||
std::vector<EntityID> parentedEIDS;
|
||||
for(auto const& eid : editor->selectedEntities)
|
||||
{
|
||||
if(sceneGraph.GetChild(eid, parentEID) == nullptr)
|
||||
{
|
||||
parentedEIDS.push_back(eid);
|
||||
if(auto parent = sceneGraph.GetParent(eid))
|
||||
entityParentData[eid].oldParentEID = parent->GetEntityID();
|
||||
entityParentData[eid].newParentEID = parentEID;
|
||||
}
|
||||
}
|
||||
SHCommandManager::PerformCommand(std::make_shared<SHEntityParentCommand>(parentedEIDS, entityParentData));
|
||||
}
|
||||
|
||||
void SHHierarchyPanel::SelectRangeOfEntities(EntityID beginEID, EntityID endEID)
|
||||
{
|
||||
bool startSelecting = false; bool endSelecting = false;
|
||||
auto const editor = SHSystemManager::GetSystem<SHEditor>();
|
||||
editor->selectedEntities.clear();
|
||||
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
|
||||
sceneGraph.Traverse([&](SHSceneNode* nodePtr)
|
||||
{
|
||||
auto eid = nodePtr->GetEntityID();
|
||||
if(!startSelecting)
|
||||
{
|
||||
if(eid == beginEID || eid == endEID)
|
||||
{
|
||||
startSelecting = true;
|
||||
editor->selectedEntities.push_back(eid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!endSelecting)
|
||||
{
|
||||
editor->selectedEntities.push_back(eid);
|
||||
if(eid == endEID || eid == beginEID)
|
||||
{
|
||||
endSelecting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void SHCreateEntityCommand::Execute()
|
||||
{
|
||||
EntityID newEID = SHEntityManager::CreateEntity(eid);
|
||||
if(eid == MAX_EID)
|
||||
eid = newEID;
|
||||
}
|
||||
|
||||
void SHCreateEntityCommand::Undo()
|
||||
{
|
||||
SHEntityManager::DestroyEntity(eid);
|
||||
}
|
||||
|
||||
void SHEntityParentCommand::Execute()
|
||||
{
|
||||
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
|
||||
for(auto const& eid : entities)
|
||||
{
|
||||
if(entityParentData[eid].newParentEID == MAX_EID)
|
||||
sceneGraph.SetParent(eid, nullptr);
|
||||
else
|
||||
sceneGraph.SetParent(eid, entityParentData[eid].newParentEID);
|
||||
}
|
||||
}
|
||||
|
||||
void SHEntityParentCommand::Undo()
|
||||
{
|
||||
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
|
||||
for(auto const& eid : entities)
|
||||
{
|
||||
if(entityParentData[eid].oldParentEID == MAX_EID)
|
||||
sceneGraph.SetParent(eid, nullptr);
|
||||
else
|
||||
sceneGraph.SetParent(eid, entityParentData[eid].oldParentEID);
|
||||
}
|
||||
}
|
||||
}//namespace SHADE
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "imgui_internal.h"
|
||||
#include "ECS_Base/SHECSMacros.h"
|
||||
#include "Editor/EditorWindow/SHEditorWindow.h"
|
||||
|
||||
#include "Editor/Command/SHCommand.hpp"
|
||||
namespace SHADE
|
||||
{
|
||||
class SHSceneNode;
|
||||
|
@ -28,8 +28,40 @@ namespace SHADE
|
|||
void DrawMenuBar() const noexcept;
|
||||
ImRect RecursivelyDrawEntityNode(SHSceneNode*);
|
||||
void CreateChildEntity(EntityID parentEID) const noexcept;
|
||||
void ParentSelectedEntities(EntityID parentEID) const noexcept;
|
||||
void SelectRangeOfEntities(EntityID beginEID, EntityID EndEID);
|
||||
std::string filter;
|
||||
bool isAnyNodeSelected = false;
|
||||
EntityID scrollTo = MAX_EID;
|
||||
};//class SHHierarchyPanel
|
||||
|
||||
//Might move to a different file
|
||||
class SHCreateEntityCommand final : public SHBaseCommand
|
||||
{
|
||||
public:
|
||||
void Execute() override;
|
||||
void Undo() override;
|
||||
private:
|
||||
EntityID eid = MAX_EID;
|
||||
};
|
||||
|
||||
class SHEntityParentCommand final : public SHBaseCommand
|
||||
{
|
||||
public:
|
||||
struct Data
|
||||
{
|
||||
EntityID oldParentEID = MAX_EID;
|
||||
EntityID newParentEID = MAX_EID;
|
||||
};
|
||||
using EntityParentData = std::unordered_map<EntityID, Data>;
|
||||
|
||||
SHEntityParentCommand(std::vector<EntityID> entityIDs, EntityParentData inEntityParentData):entities(entityIDs),entityParentData(inEntityParentData){}
|
||||
|
||||
void Execute() override;
|
||||
void Undo() override;
|
||||
private:
|
||||
std::vector<EntityID> entities;
|
||||
std::unordered_map<EntityID, Data> entityParentData;
|
||||
};
|
||||
|
||||
}//namespace SHADE
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//|| SHADE Includes ||
|
||||
//#==============================================================#
|
||||
#include "Editor/IconsMaterialDesign.h"
|
||||
#include "Editor/IconsFontAwesome6.h"
|
||||
#include "ECS_Base/Components/SHComponent.h"
|
||||
#include "Editor/SHEditorWidgets.hpp"
|
||||
#include "Physics/Components/SHColliderComponent.h"
|
||||
|
@ -216,7 +217,7 @@ namespace SHADE
|
|||
|
||||
if (collider.GetType() == SHCollider::Type::BOX)
|
||||
{
|
||||
SHEditorWidgets::BeginPanel( std::format("{} Box Collider #{}", ICON_MD_VIEW_IN_AR, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
|
||||
SHEditorWidgets::BeginPanel( std::format("{} Box Collider #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
|
||||
auto box = reinterpret_cast<SHBoundingBox*>(collider.GetShape());
|
||||
SHEditorWidgets::DragVec3("Half Extents", { "X", "Y", "Z" }, [box] {return box->GetHalfExtents(); }, [box](SHVec3 const& vec) {box->SetHalfExtents(vec);});
|
||||
}
|
||||
|
|
|
@ -55,7 +55,11 @@ namespace SHADE
|
|||
{
|
||||
EntityID const& eid = editor->selectedEntities[0];
|
||||
SHEntity* entity = SHEntityManager::GetEntityByID(eid);
|
||||
|
||||
if(!entity)
|
||||
{
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
ImGui::TextColored(ImGuiColors::green, "EID: %zu", eid);
|
||||
SHEditorWidgets::CheckBox("##IsActive", [entity]()->bool {return entity->GetActive(); }, [entity](bool const& active) {entity->SetActive(active); });
|
||||
ImGui::SameLine();
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <imgui.h>
|
||||
|
||||
#include "ECS_Base/Managers/SHSystemManager.h"
|
||||
#include "Editor/Command/SHCommandManager.h"
|
||||
#include "FRC/SHFramerateController.h"
|
||||
|
||||
namespace SHADE
|
||||
|
@ -38,6 +39,11 @@ namespace SHADE
|
|||
{
|
||||
ImGui::PlotLines("DT", frames.data(), static_cast<int>(frames.size()), 0, nullptr, 0.0f, 16.0f);
|
||||
}
|
||||
if(ImGui::CollapsingHeader("Command Manager"))
|
||||
{
|
||||
ImGui::Text("Undo: %zu", SHCommandManager::GetUndoStackSize());
|
||||
ImGui::Text("Redo: %zu", SHCommandManager::GetRedoStackSize());
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
|
|
|
@ -43,9 +43,12 @@ namespace SHADE
|
|||
bool result = ImGui::Begin(windowName.data(), &isOpen, windowFlags);
|
||||
|
||||
auto wndSize = ImGui::GetWindowSize();
|
||||
if(windowSize.x != wndSize.x || windowSize.y != wndSize.y)
|
||||
auto contentRegionAvail = ImGui::GetContentRegionAvail();
|
||||
if( beginContentRegionAvailable.x != contentRegionAvail.x || beginContentRegionAvailable.y != contentRegionAvail.y || windowSize.x != wndSize.x || windowSize.y != wndSize.y)
|
||||
{
|
||||
windowSize = {wndSize.x, wndSize.y};
|
||||
beginContentRegionAvailable = {contentRegionAvail.x, contentRegionAvail.y};
|
||||
|
||||
OnResize();
|
||||
}
|
||||
auto wndPos = ImGui::GetWindowPos();
|
||||
|
|
|
@ -26,6 +26,10 @@ namespace SHADE
|
|||
bool isOpen;
|
||||
bool isWindowHovered;
|
||||
std::string_view windowName;
|
||||
SHVec2 windowSize;
|
||||
SHVec2 windowPos;
|
||||
SHVec2 viewportMousePos;
|
||||
SHVec2 beginContentRegionAvailable;
|
||||
protected:
|
||||
virtual bool Begin();
|
||||
virtual void OnResize();
|
||||
|
@ -33,8 +37,6 @@ namespace SHADE
|
|||
|
||||
ImGuiWindowFlags windowFlags = 0;
|
||||
ImGuiIO& io;
|
||||
SHVec2 windowSize;
|
||||
SHVec2 windowPos;
|
||||
SHVec2 viewportMousePos;
|
||||
|
||||
};//class SHEditorWindow
|
||||
}//namespace SHADE
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
#include "SHpch.h"
|
||||
#include "Editor/SHImGuiHelpers.hpp"
|
||||
#include "SHEditorViewport.h"
|
||||
|
||||
#include "ImGuizmo.h"
|
||||
#include "ECS_Base/Managers/SHSystemManager.h"
|
||||
#include "Editor/IconsMaterialDesign.h"
|
||||
#include "Editor/SHEditor.hpp"
|
||||
#include "Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h"
|
||||
#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h"
|
||||
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
|
||||
#include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h"
|
||||
#include <Editor/IconsFontAwesome6.h>
|
||||
|
||||
constexpr std::string_view windowName = "\xef\x80\x95 Viewport";
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
SHEditorViewport::SHEditorViewport()
|
||||
:SHEditorWindow("Viewport", ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoScrollbar)
|
||||
:SHEditorWindow("\xee\x90\x8b Viewport", ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoScrollbar)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -26,31 +32,30 @@ namespace SHADE
|
|||
SHEditorWindow::Update();
|
||||
if(Begin())
|
||||
{
|
||||
ImGuizmo::SetDrawlist();
|
||||
DrawMenuBar();
|
||||
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
|
||||
auto const& descriptorSet = gfxSystem->GetPostOffscreenRenderSystem()->GetDescriptorSetGroup()->GetVkHandle()[0];
|
||||
auto mousePos = ImGui::GetMousePos();
|
||||
auto cursorPos = ImGui::GetCursorScreenPos();
|
||||
viewportMousePos = {mousePos.x - cursorPos.x, mousePos.y - cursorPos.y};
|
||||
beginCursorPos = ImGui::GetCursorScreenPos();
|
||||
viewportMousePos = {mousePos.x - beginCursorPos.x, mousePos.y - beginCursorPos.y};
|
||||
gfxSystem->GetMousePickSystem ()->SetViewportMousePos (viewportMousePos);
|
||||
//if (ImGui::IsMouseReleased(ImGuiMouseButton_Left))
|
||||
//{
|
||||
// auto eid = gfxSystem->GetMousePickSystem ()->GetPickedEntity();
|
||||
// if(eid != MAX_EID)
|
||||
// {
|
||||
// auto editor = SHSystemManager::GetSystem<SHEditor>();
|
||||
// editor->selectedEntities.clear();
|
||||
// editor->selectedEntities.push_back(eid);
|
||||
// if (const auto hierarchyPanel = SHEditorWindowManager::GetEditorWindow<SHHierarchyPanel>())
|
||||
// {
|
||||
// hierarchyPanel->SetScrollTo(eid);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
ImGui::Image((ImTextureID)descriptorSet, ImGui::GetWindowSize());
|
||||
ImGui::Image((ImTextureID)descriptorSet, {beginContentRegionAvailable.x, beginContentRegionAvailable.y});
|
||||
|
||||
if(ImGui::IsWindowHovered() && ImGui::IsMouseDown(ImGuiMouseButton_Right))
|
||||
{
|
||||
ImGui::SetMouseCursor(ImGuiMouseCursor_None);
|
||||
ImGui::SetCursorScreenPos(ImGui::GetMousePos());
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiColors::green);
|
||||
ImGui::Text(ICON_FA_EYE);
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
}
|
||||
ImGuizmo::SetRect(beginCursorPos.x , beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y);
|
||||
transformGizmo.Draw();
|
||||
ImGui::End();
|
||||
|
||||
}
|
||||
|
||||
void SHEditorViewport::Exit()
|
||||
|
@ -66,7 +71,11 @@ namespace SHADE
|
|||
|
||||
//auto pos = ImGui::GetCursorPos();
|
||||
//windowCursorPos = {}
|
||||
gfxSystem->PrepareResize(static_cast<uint32_t>(windowSize.x), static_cast<uint32_t>(windowSize.y));
|
||||
if(beginContentRegionAvailable.x == 0 || beginContentRegionAvailable.y == 0)
|
||||
{
|
||||
beginContentRegionAvailable = windowSize;
|
||||
}
|
||||
gfxSystem->PrepareResize(static_cast<uint32_t>(beginContentRegionAvailable.x), static_cast<uint32_t>(beginContentRegionAvailable.y));
|
||||
}
|
||||
|
||||
void SHEditorViewport::OnPosChange()
|
||||
|
@ -74,10 +83,46 @@ namespace SHADE
|
|||
SHEditorWindow::OnPosChange();
|
||||
}
|
||||
|
||||
void SHEditorViewport::DrawMenuBar() const noexcept
|
||||
void SHEditorViewport::DrawMenuBar() noexcept
|
||||
{
|
||||
if(ImGui::BeginMenuBar())
|
||||
{
|
||||
bool const isTranslate = transformGizmo.operation == SHTransformGizmo::Operation::TRANSLATE;
|
||||
ImGui::BeginDisabled(isTranslate);
|
||||
if(isTranslate)
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]);
|
||||
if(ImGui::Button(ICON_MD_OPEN_WITH))
|
||||
{
|
||||
transformGizmo.operation = SHTransformGizmo::Operation::TRANSLATE;
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
if(isTranslate)
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
bool const isRotate = transformGizmo.operation == SHTransformGizmo::Operation::ROTATE;
|
||||
ImGui::BeginDisabled(isRotate);
|
||||
if(isRotate)
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]);
|
||||
if(ImGui::Button(ICON_MD_AUTORENEW))
|
||||
{
|
||||
transformGizmo.operation = SHTransformGizmo::Operation::ROTATE;
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
if(isRotate)
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
bool const isScale = transformGizmo.operation == SHTransformGizmo::Operation::SCALE;
|
||||
ImGui::BeginDisabled(isScale);
|
||||
if(isScale)
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]);
|
||||
if(ImGui::Button(ICON_MD_EXPAND))
|
||||
{
|
||||
transformGizmo.operation = SHTransformGizmo::Operation::SCALE;
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
if(isScale)
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "imgui_internal.h"
|
||||
#include "ECS_Base/SHECSMacros.h"
|
||||
#include "Editor/EditorWindow/SHEditorWindow.h"
|
||||
#include "Editor/Gizmos/SHTransformGizmo.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
@ -20,10 +21,12 @@ namespace SHADE
|
|||
void Init() override;
|
||||
void Update() override;
|
||||
void Exit() override;
|
||||
SHTransformGizmo transformGizmo;
|
||||
protected:
|
||||
void OnResize() override;
|
||||
void OnPosChange() override;
|
||||
private:
|
||||
void DrawMenuBar() const noexcept;
|
||||
void DrawMenuBar() noexcept;
|
||||
SHVec2 beginCursorPos;
|
||||
};//class SHEditorViewport
|
||||
}//namespace SHADE
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
#include "SHpch.h"
|
||||
#include "SHTransformGizmo.h"
|
||||
|
||||
#include "ECS_Base/Managers/SHComponentManager.h"
|
||||
#include "ECS_Base/Managers/SHSystemManager.h"
|
||||
#include "Editor/SHEditor.hpp"
|
||||
#include "Editor/SHImGuiHelpers.hpp"
|
||||
#include <imgui.h>
|
||||
#include <ImGuizmo.h>
|
||||
|
||||
#include "Camera/SHCameraSystem.h"
|
||||
#include "Editor/Command/SHCommandManager.h"
|
||||
#include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h"
|
||||
namespace SHADE
|
||||
{
|
||||
void SHTransformGizmo::Draw()
|
||||
{
|
||||
bool justChangedTfm = false;
|
||||
if (!editorCamera)
|
||||
{
|
||||
auto const cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
|
||||
editorCamera = cameraSystem->GetEditorCamera();
|
||||
}
|
||||
auto viewportWindow = SHEditorWindowManager::GetEditorWindow<SHEditorViewport>();
|
||||
ImGuizmo::SetOrthographic(false);
|
||||
|
||||
SHMatrix view = SHMatrix::Transpose(editorCamera->GetViewMatrix());
|
||||
SHMatrix proj = SHMatrix::Transpose(editorCamera->GetProjMatrix());
|
||||
proj(1, 1) *= -1;
|
||||
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)
|
||||
{
|
||||
SHEditor* editor = SHSystemManager::GetSystem<SHEditor>();
|
||||
if (editor->selectedEntities.empty())
|
||||
return;
|
||||
EntityID eid = editor->selectedEntities.back();
|
||||
selectedEntityTransformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
|
||||
justChangedTfm = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SHEditor* editor = SHSystemManager::GetSystem<SHEditor>();
|
||||
if (editor->selectedEntities.empty())
|
||||
return;
|
||||
EntityID eid = editor->selectedEntities.back();
|
||||
auto tfmComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
|
||||
if (selectedEntityTransformComponent != tfmComponent)
|
||||
{
|
||||
selectedEntityTransformComponent = tfmComponent;
|
||||
justChangedTfm = true;
|
||||
}
|
||||
}
|
||||
if (selectedEntityTransformComponent == nullptr)
|
||||
return;
|
||||
|
||||
SHMatrix mat = selectedEntityTransformComponent->GetTRS();
|
||||
isManipulating = ImGuizmo::Manipulate(&view._11, &proj._11, static_cast<ImGuizmo::OPERATION>(operation), ImGuizmo::MODE::WORLD, &mat._11);
|
||||
if (!justChangedTfm)
|
||||
{
|
||||
if (ImGui::IsItemClicked())
|
||||
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);
|
||||
})));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
#include "Camera/SHCameraComponent.h"
|
||||
#include "Math/Transform/SHTransformComponent.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
class SHTransformGizmo
|
||||
{
|
||||
public:
|
||||
enum class Mode
|
||||
{
|
||||
WORLD,
|
||||
LOCAL
|
||||
};
|
||||
|
||||
enum class Operation
|
||||
{
|
||||
TRANSLATE_X = (1u << 0),
|
||||
TRANSLATE_Y = (1u << 1),
|
||||
TRANSLATE_Z = (1u << 2),
|
||||
ROTATE_X = (1u << 3),
|
||||
ROTATE_Y = (1u << 4),
|
||||
ROTATE_Z = (1u << 5),
|
||||
ROTATE_SCREEN = (1u << 6),
|
||||
SCALE_X = (1u << 7),
|
||||
SCALE_Y = (1u << 8),
|
||||
SCALE_Z = (1u << 9),
|
||||
BOUNDS = (1u << 10),
|
||||
SCALE_XU = (1u << 11),
|
||||
SCALE_YU = (1u << 12),
|
||||
SCALE_ZU = (1u << 13),
|
||||
|
||||
TRANSLATE = TRANSLATE_X | TRANSLATE_Y | TRANSLATE_Z,
|
||||
ROTATE = ROTATE_X | ROTATE_Y | ROTATE_Z | ROTATE_SCREEN,
|
||||
SCALE = SCALE_X | SCALE_Y | SCALE_Z,
|
||||
SCALEU = SCALE_XU | SCALE_YU | SCALE_ZU, // universal
|
||||
UNIVERSAL = TRANSLATE | ROTATE | SCALEU
|
||||
};
|
||||
|
||||
void Draw();
|
||||
bool isManipulating = false;
|
||||
Mode mode = Mode::WORLD;
|
||||
Operation operation = Operation::TRANSLATE;
|
||||
private:
|
||||
SHTransformComponent* selectedEntityTransformComponent{nullptr};
|
||||
SHCameraComponent* editorCamera{nullptr};
|
||||
};
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -4,6 +4,7 @@
|
|||
#include "SHpch.h"
|
||||
|
||||
#include "IconsMaterialDesign.h"
|
||||
#include "IconsFontAwesome6.h"
|
||||
#include "DragDrop/SHDragDrop.hpp"
|
||||
|
||||
//#==============================================================#
|
||||
|
@ -36,6 +37,7 @@
|
|||
#include <imgui.h>
|
||||
#include <SDL.h>
|
||||
#include <rttr/registration>
|
||||
#include <ImGuizmo.h>
|
||||
|
||||
//#==============================================================#
|
||||
//|| ImGui Backend Includes ||
|
||||
|
@ -87,10 +89,10 @@ namespace SHADE
|
|||
|
||||
//Add editor windows
|
||||
SHEditorWindowManager::CreateEditorWindow<SHEditorMenuBar>();
|
||||
SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>();
|
||||
SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>();
|
||||
SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>();
|
||||
SHEditorWindowManager::CreateEditorWindow<SHEditorProfiler>();
|
||||
SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>();
|
||||
|
||||
io = &ImGui::GetIO();
|
||||
|
||||
|
@ -98,7 +100,7 @@ namespace SHADE
|
|||
io->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; //Enable for Multi-Viewports
|
||||
io->ConfigFlags |= ImGuiConfigFlags_DockingEnable; //Enable docking
|
||||
io->IniFilename = "../../Assets/Editor/Layouts/UserLayout.ini";
|
||||
|
||||
io->ConfigWindowsMoveFromTitleBarOnly = true;
|
||||
InitLayout();
|
||||
|
||||
InitFonts();
|
||||
|
@ -127,8 +129,12 @@ namespace SHADE
|
|||
for (const auto& window : SHEditorWindowManager::editorWindows | std::views::values)
|
||||
{
|
||||
if(window->isOpen)
|
||||
{
|
||||
window->Update();
|
||||
}
|
||||
}
|
||||
|
||||
PollPicking();
|
||||
|
||||
if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z))
|
||||
{
|
||||
|
@ -165,10 +171,11 @@ namespace SHADE
|
|||
{
|
||||
ImFont* mainFont = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/Segoe UI.ttf", 20.f);//TODO: Change to config based assets path
|
||||
|
||||
constexpr ImWchar icon_ranges[] = { ICON_MIN_MD, ICON_MAX_16_MD, 0 };
|
||||
ImFontConfig icons_config{}; icons_config.MergeMode = true; icons_config.GlyphOffset.y = 5.f;
|
||||
ImFont* UIFont = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/MaterialIcons-Regular.ttf", 20.f, &icons_config, icon_ranges); //TODO: Change to config based assets path
|
||||
|
||||
constexpr ImWchar icon_ranges_fa[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
|
||||
ImFont* UIFontFA = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/fa-solid-900.ttf", 20.f, &icons_config, icon_ranges_fa); //TODO: Change to config based assets path
|
||||
constexpr ImWchar icon_ranges_md[] = { ICON_MIN_MD, ICON_MAX_MD, 0 };
|
||||
ImFont* UIFontMD = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/MaterialIcons-Regular.ttf", 20.f, &icons_config, icon_ranges_md); //TODO: Change to config based assets path
|
||||
io->Fonts->Build();
|
||||
}
|
||||
|
||||
|
@ -338,7 +345,7 @@ namespace SHADE
|
|||
if (auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>())
|
||||
{
|
||||
auto viewportWindow = SHEditorWindowManager::GetEditorWindow<SHEditorViewport>();
|
||||
if (viewportWindow->isWindowHovered && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
|
||||
if (viewportWindow->isWindowHovered && !viewportWindow->transformGizmo.isManipulating && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
|
||||
{
|
||||
EntityID pickedEID = gfxSystem->GetMousePickSystem()->GetPickedEntity();
|
||||
if(pickedEID == MAX_EID)
|
||||
|
@ -366,6 +373,7 @@ namespace SHADE
|
|||
ImGui_ImplVulkan_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
ImGuizmo::BeginFrame();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include "Resource/SHHandle.h"
|
||||
#include "EditorWindow/SHEditorWindow.h"
|
||||
#include "Tools/SHLogger.h"
|
||||
#include "Gizmos/SHTransformGizmo.h"
|
||||
|
||||
|
||||
//#==============================================================#
|
||||
//|| Library Includes ||
|
||||
|
@ -200,5 +202,7 @@ namespace SHADE
|
|||
SDL_Window* sdlWindow {nullptr};
|
||||
|
||||
ImGuiIO* io{nullptr};
|
||||
|
||||
//SHTransformGizmo transformGizmo;
|
||||
};//class SHEditor
|
||||
}//namespace SHADE
|
||||
|
|
|
@ -43,6 +43,10 @@ namespace SHADE
|
|||
constexpr ImVec4 blue = {0.0f, 0.0f, 1.0f, 1.f};
|
||||
constexpr ImVec4 white = {1.0f, 1.0f, 1.0f, 1.f};
|
||||
|
||||
constexpr int colors_red = 0;
|
||||
constexpr int colors_green = 1;
|
||||
constexpr int colors_blue = 2;
|
||||
constexpr int colors_white = 3;
|
||||
constexpr ImU32 colors[] = {
|
||||
0xBB0000FF, // red
|
||||
0xBB00FF00, // green
|
||||
|
|
|
@ -585,19 +585,19 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
/* Texture Registration Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
Handle<SHTexture> SHGraphicsSystem::Add(const SHTextureAsset& texAsset)
|
||||
Handle<SHTexture> SHGraphicsSystem::AddTexture(const SHTextureAsset& texAsset)
|
||||
{
|
||||
auto sampler = samplerCache.GetSampler(device, SHVkSamplerParams { .maxLod = static_cast<float>(texAsset.mipOffsets.size()) });
|
||||
return texLibrary.Add(texAsset, sampler);
|
||||
}
|
||||
|
||||
SHADE::Handle<SHADE::SHTexture> SHGraphicsSystem::Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector<uint32_t> mipOffsets)
|
||||
SHADE::Handle<SHADE::SHTexture> SHGraphicsSystem::AddTexture(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector<uint32_t> mipOffsets)
|
||||
{
|
||||
auto sampler = samplerCache.GetSampler(device, SHVkSamplerParams{ .maxLod = static_cast<float>(mipOffsets.size()) });
|
||||
return texLibrary.Add(pixelCount, pixelData, width, height, format, mipOffsets, sampler);
|
||||
}
|
||||
|
||||
void SHGraphicsSystem::Remove(Handle<SHTexture> tex)
|
||||
void SHGraphicsSystem::RemoveTexture(Handle<SHTexture> tex)
|
||||
{
|
||||
texLibrary.Remove(tex);
|
||||
}
|
||||
|
|
|
@ -231,8 +231,8 @@ namespace SHADE
|
|||
|
||||
*/
|
||||
/*******************************************************************************/
|
||||
Handle<SHTexture> Add(const SHTextureAsset& texAsset);
|
||||
Handle<SHTexture> Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector<uint32_t> mipOffsets);
|
||||
Handle<SHTexture> AddTexture(const SHTextureAsset& texAsset);
|
||||
Handle<SHTexture> AddTexture(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector<uint32_t> mipOffsets);
|
||||
/*******************************************************************************/
|
||||
/*!
|
||||
|
||||
|
@ -246,7 +246,7 @@ namespace SHADE
|
|||
|
||||
*/
|
||||
/*******************************************************************************/
|
||||
void Remove(Handle<SHTexture> tex);
|
||||
void RemoveTexture(Handle<SHTexture> tex);
|
||||
/***************************************************************************/
|
||||
/*!
|
||||
|
||||
|
|
|
@ -20,6 +20,10 @@ namespace SHADE
|
|||
/* Static defines */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
bool SHInputManager::controllerInUse = false;
|
||||
|
||||
std::map<std::string, SHInputManager::SHLogicalBindingData> SHInputManager::bindings;
|
||||
|
||||
unsigned SHInputManager::keyCount = 0;
|
||||
bool SHInputManager::keys[MAX_KEYS];
|
||||
bool SHInputManager::keysLast[MAX_KEYS];
|
||||
|
@ -41,6 +45,60 @@ namespace SHADE
|
|||
int SHInputManager::mouseWheelVerticalDelta = 0;
|
||||
int SHInputManager::mouseWheelVerticalDeltaPoll = 0;
|
||||
|
||||
unsigned char SHInputManager::controllersConnectedCount = 0;
|
||||
unsigned SHInputManager::controllersInputCount[XUSER_MAX_COUNT];
|
||||
unsigned SHInputManager::controllersButtonCount[XUSER_MAX_COUNT];
|
||||
short SHInputManager::controllers[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT];
|
||||
short SHInputManager::controllersLast[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT];
|
||||
double SHInputManager::controllersHeldTime[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT];
|
||||
double SHInputManager::controllersReleasedTime[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT];
|
||||
|
||||
//Internal helper function for splitting between inputs
|
||||
bool SHInputManager::controllerConsideredHeld(size_t inputIdx, short value) noexcept
|
||||
{
|
||||
if (inputIdx >= MAX_CONTROLLER_INPUT) return false; //Bounds check
|
||||
else
|
||||
{
|
||||
if (inputIdx < NUM_CONTROLLER_BUTTON)
|
||||
{
|
||||
return static_cast<bool>(value);
|
||||
}
|
||||
else if (inputIdx < NUM_CONTROLLER_BUTTON + NUM_CONTROLLER_TRIGGER)
|
||||
{
|
||||
return (value > XINPUT_GAMEPAD_TRIGGER_THRESHOLD);
|
||||
}
|
||||
else if (inputIdx < NUM_CONTROLLER_BUTTON + NUM_CONTROLLER_TRIGGER + NUM_CONTROLLER_TRIGGER)
|
||||
{
|
||||
return (std::abs(value) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (std::abs(value) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Internal helper function for getting normalised input value
|
||||
double SHInputManager::controllerNormalisedValue(size_t inputIdx, short value) noexcept
|
||||
{
|
||||
if (inputIdx >= MAX_CONTROLLER_INPUT) return 0.0; //Bounds check
|
||||
else
|
||||
{
|
||||
if (inputIdx < NUM_CONTROLLER_BUTTON)
|
||||
{
|
||||
return static_cast<double>(value);
|
||||
}
|
||||
else if (inputIdx < NUM_CONTROLLER_BUTTON + NUM_CONTROLLER_TRIGGER) //8-bit triggers, 0 to 255
|
||||
{
|
||||
return static_cast<double>(value) / static_cast<double>(UCHAR_MAX);
|
||||
}
|
||||
else //16-bit thumbsticks, -32768 to 32767
|
||||
{
|
||||
return static_cast<double>(value) / static_cast<double>(SHRT_MAX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SHInputManager::UpdateInput(double dt) noexcept
|
||||
{
|
||||
//Keyboard and Mouse Buttons////////////////////////////////////////////////
|
||||
|
@ -120,6 +178,273 @@ namespace SHADE
|
|||
mouseWheelVerticalDelta = 0;
|
||||
mouseWheelVerticalDelta = mouseWheelVerticalDeltaPoll;
|
||||
mouseWheelVerticalDeltaPoll = 0;
|
||||
|
||||
//Controllers//////////////////////////////////////////////////////////////
|
||||
|
||||
controllersConnectedCount = 0;
|
||||
|
||||
//Set last controller states
|
||||
memcpy(controllersLast, controllers, sizeof(controllers));
|
||||
|
||||
//Reset controller states
|
||||
SecureZeroMemory(&controllers, sizeof(controllers));
|
||||
|
||||
//https://learn.microsoft.com/en-us/windows/win32/xinput/getting-started-with-xinput#getting-controller-state
|
||||
for (DWORD c = 0; c < XUSER_MAX_COUNT; ++c)
|
||||
{
|
||||
controllersInputCount[c] = 0;
|
||||
controllersButtonCount[c] = 0;
|
||||
|
||||
XINPUT_STATE state;
|
||||
SecureZeroMemory(&state, sizeof(XINPUT_STATE));
|
||||
|
||||
//Get the state of controller from XInput
|
||||
DWORD result = XInputGetState(c, &state);
|
||||
|
||||
//Write gamepad data
|
||||
if (result == ERROR_SUCCESS)
|
||||
{
|
||||
++controllersConnectedCount;
|
||||
|
||||
//DIGITAL BUTTONS///////////////////////////////////////
|
||||
|
||||
//DPAD UP
|
||||
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::DPAD_UP)] = 1;
|
||||
++controllersInputCount[c];
|
||||
++controllersButtonCount[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::DPAD_UP)] = 0;
|
||||
}
|
||||
|
||||
//DPAD DOWN
|
||||
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::DPAD_DOWN)] = 1;
|
||||
++controllersInputCount[c];
|
||||
++controllersButtonCount[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::DPAD_DOWN)] = 0;
|
||||
}
|
||||
|
||||
//DPAD LEFT
|
||||
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::DPAD_LEFT)] = 1;
|
||||
++controllersInputCount[c];
|
||||
++controllersButtonCount[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::DPAD_LEFT)] = 0;
|
||||
}
|
||||
|
||||
//DPAD RIGHT
|
||||
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::DPAD_RIGHT)] = 1;
|
||||
++controllersInputCount[c];
|
||||
++controllersButtonCount[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::DPAD_RIGHT)] = 0;
|
||||
}
|
||||
|
||||
//START
|
||||
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_START)
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::START)] = 1;
|
||||
++controllersInputCount[c];
|
||||
++controllersButtonCount[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::START)] = 0;
|
||||
}
|
||||
|
||||
//BACK
|
||||
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK)
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::BACK)] = 1;
|
||||
++controllersInputCount[c];
|
||||
++controllersButtonCount[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::BACK)] = 0;
|
||||
}
|
||||
|
||||
//LEFT THUMBSTICK BUTTON
|
||||
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB)
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::LEFT_THUMBSTICK)] = 1;
|
||||
++controllersInputCount[c];
|
||||
++controllersButtonCount[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::LEFT_THUMBSTICK)] = 0;
|
||||
}
|
||||
|
||||
//RIGHT THUMBSTICK BUTTON
|
||||
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB)
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::RIGHT_THUMBSTICK)] = 1;
|
||||
++controllersInputCount[c];
|
||||
++controllersButtonCount[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::RIGHT_THUMBSTICK)] = 0;
|
||||
}
|
||||
|
||||
//LEFT SHOULDER BUTTON
|
||||
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER)
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::LEFT_SHOULDER)] = 1;
|
||||
++controllersInputCount[c];
|
||||
++controllersButtonCount[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::LEFT_SHOULDER)] = 0;
|
||||
}
|
||||
|
||||
//RIGHT SHOULDER BUTTON
|
||||
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER)
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::RIGHT_SHOULDER)] = 1;
|
||||
++controllersInputCount[c];
|
||||
++controllersButtonCount[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::RIGHT_SHOULDER)] = 0;
|
||||
}
|
||||
|
||||
//A
|
||||
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_A)
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::A)] = 1;
|
||||
++controllersInputCount[c];
|
||||
++controllersButtonCount[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::A)] = 0;
|
||||
}
|
||||
|
||||
//B
|
||||
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_B)
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::B)] = 1;
|
||||
++controllersInputCount[c];
|
||||
++controllersButtonCount[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::B)] = 0;
|
||||
}
|
||||
|
||||
//X
|
||||
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_X)
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::X)] = 1;
|
||||
++controllersInputCount[c];
|
||||
++controllersButtonCount[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::X)] = 0;
|
||||
}
|
||||
|
||||
//Y
|
||||
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_Y)
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::Y)] = 1;
|
||||
++controllersInputCount[c];
|
||||
++controllersButtonCount[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::Y)] = 0;
|
||||
}
|
||||
|
||||
//8 BIT VALUES (0 - 255)///////////////////////////////////
|
||||
|
||||
//LEFT TRIGGER
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::LEFT_TRIGGER)] = state.Gamepad.bLeftTrigger;
|
||||
if (state.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
|
||||
{
|
||||
++controllersInputCount[c]; //Registered as held
|
||||
}
|
||||
|
||||
//RIGHT TRIGGER
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::RIGHT_TRIGGER)] = state.Gamepad.bRightTrigger;
|
||||
if (state.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
|
||||
{
|
||||
++controllersInputCount[c]; //Registered as held
|
||||
}
|
||||
|
||||
//16 BIT VALUES (0 - 65535)////////////////////////////////
|
||||
|
||||
//LEFT THUMBSTICK X
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::LEFT_THUMBSTICK_X)] = state.Gamepad.sThumbLX;
|
||||
if (std::abs(state.Gamepad.sThumbLX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
|
||||
{
|
||||
++controllersInputCount[c];
|
||||
}
|
||||
|
||||
//LEFT THUMBSTICK Y
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::LEFT_THUMBSTICK_Y)] = state.Gamepad.sThumbLY;
|
||||
if (std::abs(state.Gamepad.sThumbLY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
|
||||
{
|
||||
++controllersInputCount[c];
|
||||
}
|
||||
|
||||
//RIGHT THUMBSTICK X
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::RIGHT_THUMBSTICK_X)] = state.Gamepad.sThumbRX;
|
||||
if (std::abs(state.Gamepad.sThumbRX) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)
|
||||
{
|
||||
++controllersInputCount[c];
|
||||
}
|
||||
|
||||
//RIGHT THUMBSTICK Y
|
||||
controllers[c][static_cast<size_t>(SH_CONTROLLERCODE::RIGHT_THUMBSTICK_Y)] = state.Gamepad.sThumbRY;
|
||||
if (std::abs(state.Gamepad.sThumbRY) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)
|
||||
{
|
||||
++controllersInputCount[c];
|
||||
}
|
||||
}
|
||||
|
||||
//Timers and updating if controller is presently in use
|
||||
for (size_t i = 0; i < MAX_CONTROLLER_INPUT; ++i)
|
||||
{
|
||||
if (controllerConsideredHeld(i, controllers[c][i])) //Considered on
|
||||
{
|
||||
controllerInUse = true;
|
||||
if (!controllerConsideredHeld(i, controllersLast[c][i])) //Just on
|
||||
{
|
||||
controllersHeldTime[c][i] = 0.0; //Reset timer
|
||||
}
|
||||
controllersHeldTime[c][i] += dt; //Tick up
|
||||
}
|
||||
else //Considered off
|
||||
{
|
||||
if (controllerConsideredHeld(i, controllersLast[c][i])) //Just off
|
||||
{
|
||||
controllersReleasedTime[c][i] = 0.0; //Reset timer
|
||||
}
|
||||
controllersReleasedTime[c][i] += dt; //Tick up
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SHInputManager::AnyKeyDown(SH_KEYCODE* firstDetected) noexcept
|
||||
|
@ -161,4 +486,336 @@ namespace SHADE
|
|||
return false;
|
||||
}
|
||||
|
||||
//Any controller input being held
|
||||
//For analog, this means going being deadzone values
|
||||
bool SHInputManager::AnyControllerInput(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return false;
|
||||
for (size_t i = 0; i < MAX_CONTROLLER_INPUT; ++i)
|
||||
{
|
||||
if (controllerConsideredHeld(i, controllers[cNum][i]))
|
||||
{
|
||||
if (firstDetected) *firstDetected = static_cast<SH_CONTROLLERCODE>(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SHInputManager::AnyControllerInputDown(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return false;
|
||||
for (size_t i = 0; i < MAX_CONTROLLER_INPUT; ++i)
|
||||
{
|
||||
if (controllerConsideredHeld(i, controllers[cNum][i]) && !controllerConsideredHeld(i, controllersLast[cNum][i]))
|
||||
{
|
||||
if (firstDetected) *firstDetected = static_cast<SH_CONTROLLERCODE>(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SHInputManager::AnyControllerInputUp(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return false;
|
||||
for (size_t i = 0; i < MAX_CONTROLLER_INPUT; ++i)
|
||||
{
|
||||
if (!controllerConsideredHeld(i, controllers[cNum][i]) && controllerConsideredHeld(i, controllersLast[cNum][i]))
|
||||
{
|
||||
if (firstDetected) *firstDetected = static_cast<SH_CONTROLLERCODE>(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SHInputManager::AnyControllerButton(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return false;
|
||||
for (size_t i = 0; i < NUM_CONTROLLER_BUTTON; ++i)
|
||||
{
|
||||
if (controllerConsideredHeld(i, controllers[cNum][i]))
|
||||
{
|
||||
if (firstDetected) *firstDetected = static_cast<SH_CONTROLLERCODE>(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SHInputManager::AnyControllerButtonDown(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return false;
|
||||
for (size_t i = 0; i < NUM_CONTROLLER_BUTTON; ++i)
|
||||
{
|
||||
if (controllerConsideredHeld(i, controllers[cNum][i]) && !controllerConsideredHeld(i, controllersLast[cNum][i]))
|
||||
{
|
||||
if (firstDetected) *firstDetected = static_cast<SH_CONTROLLERCODE>(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SHInputManager::AnyControllerButtonUp(SH_CONTROLLERCODE* firstDetected, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return false;
|
||||
for (size_t i = 0; i < NUM_CONTROLLER_BUTTON; ++i)
|
||||
{
|
||||
if (!controllerConsideredHeld(i, controllers[cNum][i]) && controllerConsideredHeld(i, controllersLast[cNum][i]))
|
||||
{
|
||||
if (firstDetected) *firstDetected = static_cast<SH_CONTROLLERCODE>(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//Only get of largest magnitude
|
||||
double SHInputManager::GetBindingAxis(std::string bindingName, size_t cNum) noexcept
|
||||
{
|
||||
//Over keycodes, prioritise positive
|
||||
for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes)
|
||||
{
|
||||
if (GetKey(k)) return 1.0;
|
||||
}
|
||||
for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes)
|
||||
{
|
||||
if (GetKey(k)) return -1.0;
|
||||
}
|
||||
|
||||
double largestMagnitude = 0.0;
|
||||
|
||||
//Over controllerCodes
|
||||
for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes)
|
||||
{
|
||||
double newValue = 0.0;
|
||||
if (GetControllerInput(c, &newValue, nullptr, nullptr, cNum))
|
||||
if (std::abs(newValue) > std::abs(largestMagnitude)) largestMagnitude = newValue;
|
||||
}
|
||||
for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes)
|
||||
{
|
||||
double newValue = 0.0;
|
||||
if (GetControllerInput(c, &newValue, nullptr, nullptr, cNum))
|
||||
if (std::abs(newValue) > std::abs(largestMagnitude)) largestMagnitude = -newValue;
|
||||
}
|
||||
|
||||
return largestMagnitude;
|
||||
}
|
||||
|
||||
bool SHInputManager::GetBindingPositiveButton(std::string bindingName, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return false;
|
||||
|
||||
//Over keycodes
|
||||
for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes)
|
||||
{
|
||||
if (GetKey(k)) return true;
|
||||
}
|
||||
|
||||
//Over controller buttons
|
||||
for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes)
|
||||
{
|
||||
if (GetControllerInput(c, nullptr, nullptr, nullptr, cNum)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SHInputManager::GetBindingNegativeButton(std::string bindingName, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return false;
|
||||
|
||||
//Over keycodes
|
||||
for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes)
|
||||
{
|
||||
if (GetKey(k)) return true;
|
||||
}
|
||||
|
||||
//Over controller buttons
|
||||
for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes)
|
||||
{
|
||||
if (GetControllerInput(c, nullptr, nullptr, nullptr, cNum)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SHInputManager::GetBindingPositiveButtonDown(std::string bindingName, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return false;
|
||||
|
||||
//Over keycodes
|
||||
for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes)
|
||||
{
|
||||
if (GetKeyDown(k)) return true;
|
||||
}
|
||||
|
||||
//Over controller buttons
|
||||
for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes)
|
||||
{
|
||||
if (GetControllerInputDown(c, nullptr, cNum)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SHInputManager::GetBindingNegativeButtonDown(std::string bindingName, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return false;
|
||||
|
||||
//Over keycodes
|
||||
for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes)
|
||||
{
|
||||
if (GetKeyDown(k)) return true;
|
||||
}
|
||||
|
||||
//Over controller buttons
|
||||
for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes)
|
||||
{
|
||||
if (GetControllerInputDown(c, nullptr, cNum)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SHInputManager::GetBindingPositiveButtonUp(std::string bindingName, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return false;
|
||||
|
||||
//Over keycodes
|
||||
for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes)
|
||||
{
|
||||
if (GetKeyUp(k)) return true;
|
||||
}
|
||||
|
||||
//Over controller buttons
|
||||
for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes)
|
||||
{
|
||||
if (GetControllerInputUp(c, nullptr, cNum)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SHInputManager::GetBindingNegativeButtonUp(std::string bindingName, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return false;
|
||||
|
||||
//Over keycodes
|
||||
for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes)
|
||||
{
|
||||
if (GetKeyUp(k)) return true;
|
||||
}
|
||||
|
||||
//Over controller buttons
|
||||
for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes)
|
||||
{
|
||||
if (GetControllerInputUp(c, nullptr, cNum)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//Fetches longest hold time
|
||||
double SHInputManager::GetBindingPositiveHeldTime(std::string bindingName, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return 0.0;
|
||||
|
||||
double maxHeldTime = 0.0;
|
||||
|
||||
//Over keycodes
|
||||
for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes)
|
||||
{
|
||||
if (GetKeyHeldTime(k) > maxHeldTime) maxHeldTime = GetKeyHeldTime(k);
|
||||
}
|
||||
|
||||
//Over controller buttons
|
||||
for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes)
|
||||
{
|
||||
if (GetControllerInputHeldTime(c, cNum) > maxHeldTime) maxHeldTime = GetControllerInputHeldTime(c);
|
||||
}
|
||||
|
||||
return maxHeldTime;
|
||||
}
|
||||
|
||||
double SHInputManager::GetBindingNegativeHeldTime(std::string bindingName, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return 0.0;
|
||||
|
||||
double maxHeldTime = 0.0;
|
||||
|
||||
//Over keycodes
|
||||
for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes)
|
||||
{
|
||||
if (GetKeyHeldTime(k) > maxHeldTime) maxHeldTime = GetKeyHeldTime(k);
|
||||
}
|
||||
|
||||
//Over controller buttons
|
||||
for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes)
|
||||
{
|
||||
if (GetControllerInputHeldTime(c, cNum) > maxHeldTime) maxHeldTime = GetControllerInputHeldTime(c);
|
||||
}
|
||||
|
||||
return maxHeldTime;
|
||||
}
|
||||
|
||||
//Fetches shortest release time
|
||||
double SHInputManager::GetBindingPositiveReleasedTime(std::string bindingName, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return 0.0;
|
||||
|
||||
double minReleaseTime = _HUGE_ENUF;
|
||||
|
||||
//Over keycodes
|
||||
for (SH_KEYCODE k : bindings[bindingName].positiveKeyCodes)
|
||||
{
|
||||
if (GetKeyReleasedTime(k) < minReleaseTime) minReleaseTime = GetKeyReleasedTime(k);
|
||||
}
|
||||
|
||||
//Over controller buttons
|
||||
for (SH_CONTROLLERCODE c : bindings[bindingName].positiveControllerCodes)
|
||||
{
|
||||
if (GetControllerInputReleasedTime(c, cNum) < minReleaseTime) minReleaseTime = GetControllerInputReleasedTime(c);
|
||||
}
|
||||
|
||||
return minReleaseTime;
|
||||
}
|
||||
|
||||
double SHInputManager::GetBindingNegativeReleasedTime(std::string bindingName, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return 0.0;
|
||||
|
||||
double minReleaseTime = _HUGE_ENUF;
|
||||
|
||||
//Over keycodes
|
||||
for (SH_KEYCODE k : bindings[bindingName].negativeKeyCodes)
|
||||
{
|
||||
if (GetKeyReleasedTime(k) < minReleaseTime) minReleaseTime = GetKeyReleasedTime(k);
|
||||
}
|
||||
|
||||
//Over controller buttons
|
||||
for (SH_CONTROLLERCODE c : bindings[bindingName].negativeControllerCodes)
|
||||
{
|
||||
if (GetControllerInputReleasedTime(c, cNum) < minReleaseTime) minReleaseTime = GetControllerInputReleasedTime(c);
|
||||
}
|
||||
|
||||
return minReleaseTime;
|
||||
}
|
||||
|
||||
//Only for mouse movement
|
||||
//Get largest delta
|
||||
double SHInputManager::GetBindingMouseVelocity(std::string bindingName, size_t cNum) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return 0.0;
|
||||
|
||||
//Mouse velocity
|
||||
double velX = 0.0;
|
||||
double velY = 0.0;
|
||||
GetMouseVelocity(&velX, &velY);
|
||||
|
||||
return bindings[bindingName].mouseXPositiveMultiplier * velX + bindings[bindingName].mouseYPositiveMultiplier * velY;
|
||||
}
|
||||
|
||||
} //namespace SHADE
|
|
@ -10,9 +10,12 @@
|
|||
*********************************************************************/
|
||||
|
||||
#pragma once
|
||||
//#include <Xinput.h>
|
||||
//#include "../../SHADE_Managed/src/SHpch.h"
|
||||
#include <Xinput.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include "../../SHADE_Managed/src/SHpch.h"
|
||||
#include "SH_API.h"
|
||||
#pragma comment(lib, "xinput.lib")
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
@ -268,6 +271,58 @@ namespace SHADE
|
|||
OEM_CLEAR
|
||||
};
|
||||
|
||||
enum class SH_CONTROLLERCODE
|
||||
{
|
||||
//Digital
|
||||
DPAD_UP,
|
||||
DPAD_DOWN,
|
||||
DPAD_LEFT,
|
||||
DPAD_RIGHT,
|
||||
START,
|
||||
BACK,
|
||||
LEFT_THUMBSTICK,
|
||||
RIGHT_THUMBSTICK,
|
||||
LEFT_SHOULDER,
|
||||
RIGHT_SHOULDER,
|
||||
A,
|
||||
B,
|
||||
X,
|
||||
Y,
|
||||
|
||||
//1 Byte Unsigned Analog
|
||||
LEFT_TRIGGER,
|
||||
RIGHT_TRIGGER,
|
||||
|
||||
//2 Byte Signed Analog
|
||||
LEFT_THUMBSTICK_X,
|
||||
LEFT_THUMBSTICK_Y,
|
||||
RIGHT_THUMBSTICK_X,
|
||||
RIGHT_THUMBSTICK_Y
|
||||
};
|
||||
|
||||
private:
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Struct for logical bindings */
|
||||
/*------------------------------------------------------------------------*/
|
||||
struct SH_API SHLogicalBindingData
|
||||
{
|
||||
//Key codes mapped to positive
|
||||
std::set<SH_KEYCODE> positiveKeyCodes;
|
||||
|
||||
//Key codes mapped to negative
|
||||
std::set<SH_KEYCODE> negativeKeyCodes;
|
||||
|
||||
//Controller Codes mapped to positive
|
||||
std::set<SH_CONTROLLERCODE> positiveControllerCodes;
|
||||
|
||||
//Controller Codes mapped to negative
|
||||
std::set<SH_CONTROLLERCODE> negativeControllerCodes;
|
||||
|
||||
//Mouse movement mapped to axes?
|
||||
double mouseXPositiveMultiplier;
|
||||
double mouseYPositiveMultiplier;
|
||||
};
|
||||
|
||||
public:
|
||||
//Updates current state of the input, with dt to be fetched from FRC
|
||||
//TODO should dt be fixed or variable?
|
||||
|
@ -392,7 +447,7 @@ namespace SHADE
|
|||
keysToggleLast[static_cast<int>(key)]);
|
||||
}
|
||||
|
||||
//Mouse/////////////
|
||||
//Mouse/////////////////////////////////////////////////////
|
||||
|
||||
//Get the mouse location with respect to the screen
|
||||
static inline void GetMouseScreenPosition (int* x = nullptr,
|
||||
|
@ -428,7 +483,95 @@ namespace SHADE
|
|||
return mouseWheelVerticalDelta;
|
||||
}
|
||||
|
||||
//GET INPUT TIMINGS///////////////////////////////////////////////////////////
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Input state accessors (KB & M) */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
//How many controller inputs of any kind are being used now
|
||||
static inline unsigned GetControllerInputCount(size_t cNum = 0) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return 0;
|
||||
return controllersInputCount[cNum];
|
||||
}
|
||||
|
||||
//How many controller buttons are being pressed now
|
||||
//Subtract from getControllerInputCount() for analog triggers / thumbsticks
|
||||
static inline unsigned GetControllerButtonCount(size_t cNum = 0) noexcept
|
||||
{
|
||||
if (cNum >= XUSER_MAX_COUNT) return 0;
|
||||
return controllersButtonCount[cNum];
|
||||
}
|
||||
|
||||
//Any controller input being held
|
||||
//For analog, this means going being deadzone values
|
||||
//controllerNum should be between 0 and 3
|
||||
static bool AnyControllerInput(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept;
|
||||
|
||||
//Any controller input activated in THIS FRAME ONLY
|
||||
//For analog, this means going being deadzone values
|
||||
//controllerNum should be between 0 and 3
|
||||
static bool AnyControllerInputDown(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept;
|
||||
|
||||
//Any controller input deactivated in THIS FRAME ONLY
|
||||
//For analog, this means going below deadzone values
|
||||
//controllerNum should be between 0 and 3
|
||||
static bool AnyControllerInputUp(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept;
|
||||
|
||||
//Any DIGITAL controller buttons being held
|
||||
//controllerNum should be between 0 and 3
|
||||
static bool AnyControllerButton(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept;
|
||||
|
||||
//Any DIGITAL controller button activated in THIS FRAME ONLY
|
||||
//controllerNum should be between 0 and 3
|
||||
static bool AnyControllerButtonDown(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept;
|
||||
|
||||
//Any DIGITAL controller button deactivated in THIS FRAME ONLY
|
||||
//controllerNum should be between 0 and 3
|
||||
static bool AnyControllerButtonUp(SH_CONTROLLERCODE* firstDetected = nullptr, size_t controllerNum = 0) noexcept;
|
||||
|
||||
//If controller input is being held in the current frame
|
||||
//normalisedValue is the value of the input between 0 and 1, relevant for trigger and thumbstick data
|
||||
//controllerNum should be between 0 and 3
|
||||
static inline bool GetControllerInput(SH_CONTROLLERCODE input,
|
||||
double* normalisedValue = nullptr,
|
||||
double* heldTime = nullptr,
|
||||
double* releasedTime = nullptr,
|
||||
size_t controllerNum = 0) noexcept
|
||||
{
|
||||
if (controllerNum >= XUSER_MAX_COUNT) return false;
|
||||
if (normalisedValue) *normalisedValue = controllerNormalisedValue(static_cast<size_t>(input), controllers[controllerNum][static_cast<size_t>(input)]);
|
||||
if (heldTime) *heldTime = controllersHeldTime[controllerNum][static_cast<size_t>(input)];
|
||||
if (releasedTime) *releasedTime = controllersReleasedTime[controllerNum][static_cast<size_t>(input)];
|
||||
return controllerConsideredHeld(static_cast<size_t>(input), controllers[controllerNum][static_cast<size_t>(input)]);
|
||||
}
|
||||
|
||||
//If controller input was considered to be held down in THIS FRAME ONLY
|
||||
//controllerNum should be between 0 and 3
|
||||
static inline bool GetControllerInputDown(SH_CONTROLLERCODE input,
|
||||
double* releasedTime = nullptr,
|
||||
size_t controllerNum = 0) noexcept
|
||||
{
|
||||
if (controllerNum >= XUSER_MAX_COUNT) return false;
|
||||
if (releasedTime) *releasedTime = controllersReleasedTime[controllerNum][static_cast<size_t>(input)];
|
||||
return (controllerConsideredHeld(static_cast<size_t>(input), controllers[controllerNum][static_cast<size_t>(input)]) &&
|
||||
!controllerConsideredHeld(static_cast<size_t>(input), controllersLast[controllerNum][static_cast<size_t>(input)]));
|
||||
}
|
||||
|
||||
//If controller input was considered to be released in THIS FRAME ONLY
|
||||
//controllerNum should be between 0 and 3
|
||||
static inline bool GetControllerInputUp(SH_CONTROLLERCODE input,
|
||||
double* releasedTime = nullptr,
|
||||
size_t controllerNum = 0) noexcept
|
||||
{
|
||||
if (controllerNum >= XUSER_MAX_COUNT) return false;
|
||||
if (releasedTime) *releasedTime = controllersReleasedTime[controllerNum][static_cast<size_t>(input)];
|
||||
return (!controllerConsideredHeld(static_cast<size_t>(input), controllers[controllerNum][static_cast<size_t>(input)]) &&
|
||||
controllerConsideredHeld(static_cast<size_t>(input), controllersLast[controllerNum][static_cast<size_t>(input)]));
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Timing accessors */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
//Keyboard/////////////
|
||||
|
||||
|
@ -456,6 +599,191 @@ namespace SHADE
|
|||
return keysToggleOffTime[static_cast<int>(key)];
|
||||
}
|
||||
|
||||
//Controller//////////////////////
|
||||
|
||||
//How long has this controller input been considered to be held down for
|
||||
static inline double GetControllerInputHeldTime(SH_CONTROLLERCODE code,
|
||||
size_t controllerNum = 0) noexcept
|
||||
{
|
||||
if (controllerNum >= XUSER_MAX_COUNT) return 0.0;
|
||||
return controllersHeldTime[controllerNum][static_cast<size_t>(code)];
|
||||
}
|
||||
|
||||
//How long has this controller input been considered to be released for
|
||||
static inline double GetControllerInputReleasedTime(SH_CONTROLLERCODE code,
|
||||
size_t controllerNum = 0) noexcept
|
||||
{
|
||||
if (controllerNum >= XUSER_MAX_COUNT) return 0.0;
|
||||
return controllersReleasedTime[controllerNum][static_cast<size_t>(code)];
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Binding Functions */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
//Add a new binding to the map
|
||||
static inline void BindingsAdd(std::string newBindingName) noexcept
|
||||
{
|
||||
bindings.insert({ newBindingName, SHLogicalBindingData() });
|
||||
}
|
||||
|
||||
//Remove a binding from the map
|
||||
//Returns 1 if found and removed, 0 if not found
|
||||
static inline size_t BindingsRemove(std::string targetBindingName) noexcept
|
||||
{
|
||||
return bindings.erase(targetBindingName);
|
||||
}
|
||||
|
||||
//Clears all bindings from the list
|
||||
static inline void BindingsClear() noexcept
|
||||
{
|
||||
bindings.clear();
|
||||
}
|
||||
|
||||
//Get the number of bindings present
|
||||
static inline size_t BindingsCount() noexcept
|
||||
{
|
||||
return bindings.size();
|
||||
}
|
||||
|
||||
//Check positive keycodes to binding
|
||||
static inline std::set<SH_KEYCODE> const& BindingsGetPositiveKeyCodes(std::string bindingName) noexcept
|
||||
{
|
||||
return bindings[bindingName].positiveKeyCodes;
|
||||
}
|
||||
|
||||
//Add positive SH_KEYCODE to binding
|
||||
static inline void BindingsAddPositiveKeyCode(std::string targetBindingName,
|
||||
SH_KEYCODE toAdd) noexcept
|
||||
{
|
||||
bindings[targetBindingName].positiveKeyCodes.insert(toAdd);
|
||||
}
|
||||
|
||||
//Remove positive SH_KEYCODE from binding
|
||||
//If toRemove found and removed, returns 1. Otherwise, 0.
|
||||
static inline size_t BindingsRemovePositiveKeyCode(std::string targetBindingName,
|
||||
SH_KEYCODE toRemove) noexcept
|
||||
{
|
||||
return bindings[targetBindingName].positiveKeyCodes.erase(toRemove);
|
||||
}
|
||||
|
||||
//Check negative keycodes to binding
|
||||
static inline std::set<SH_KEYCODE> const& BindingsGetNegativeKeyCodes(std::string bindingName) noexcept
|
||||
{
|
||||
return bindings[bindingName].negativeKeyCodes;
|
||||
}
|
||||
|
||||
//Add negative SH_KEYCODE to binding
|
||||
static inline void BindingsAddNegativeKeyCode(std::string targetBindingName,
|
||||
SH_KEYCODE toAdd) noexcept
|
||||
{
|
||||
bindings[targetBindingName].negativeKeyCodes.insert(toAdd);
|
||||
}
|
||||
|
||||
//Remove negative SH_KEYCODE from binding
|
||||
//If toRemove found and removed, returns 1. Otherwise, 0.
|
||||
static inline size_t BindingsRemoveNegativeKeyCode(std::string targetBindingName,
|
||||
SH_KEYCODE toRemove) noexcept
|
||||
{
|
||||
return bindings[targetBindingName].negativeKeyCodes.erase(toRemove);
|
||||
}
|
||||
|
||||
//Check positive controllercodes to binding
|
||||
static inline std::set<SH_CONTROLLERCODE> const& BindingsGetPositiveControllerCodes(std::string bindingName) noexcept
|
||||
{
|
||||
return bindings[bindingName].positiveControllerCodes;
|
||||
}
|
||||
|
||||
//Add positive SH_CONTROLLERCODE to binding
|
||||
static inline void BindingsAddPositiveControllerCode(std::string targetBindingName,
|
||||
SH_CONTROLLERCODE toAdd) noexcept
|
||||
{
|
||||
bindings[targetBindingName].positiveControllerCodes.insert(toAdd);
|
||||
}
|
||||
|
||||
//Remove positive SH_CONTROLLERCODE from binding
|
||||
//If toRemove found and removed, returns 1. Otherwise, 0.
|
||||
static inline size_t BindingsRemovePositiveControllerCode(std::string targetBindingName,
|
||||
SH_CONTROLLERCODE toRemove) noexcept
|
||||
{
|
||||
return bindings[targetBindingName].positiveControllerCodes.erase(toRemove);
|
||||
}
|
||||
|
||||
//Check negative controllercodes to binding
|
||||
static inline std::set<SH_CONTROLLERCODE> const& BindingsGetNegativeControllerCodes(std::string bindingName) noexcept
|
||||
{
|
||||
return bindings[bindingName].negativeControllerCodes;
|
||||
}
|
||||
|
||||
//Add negative SH_CONTROLLERCODE to binding
|
||||
static inline void BindingsAddNegativeControllerCode(std::string targetBindingName,
|
||||
SH_CONTROLLERCODE toAdd) noexcept
|
||||
{
|
||||
bindings[targetBindingName].negativeControllerCodes.insert(toAdd);
|
||||
}
|
||||
|
||||
//Remove negative SH_CONTROLLERCODE from binding
|
||||
//If toRemove found and removed, returns 1. Otherwise, 0.
|
||||
static inline size_t BindingsRemoveNegativeControllerCode(std::string targetBindingName,
|
||||
SH_CONTROLLERCODE toRemove) noexcept
|
||||
{
|
||||
return bindings[targetBindingName].negativeControllerCodes.erase(toRemove);
|
||||
}
|
||||
|
||||
//Mouse movement bindings
|
||||
|
||||
static inline double const BindingsGetMouseXPositiveMultiplier(std::string bindingName) noexcept
|
||||
{
|
||||
return bindings[bindingName].mouseXPositiveMultiplier;
|
||||
}
|
||||
|
||||
static inline void BindingsSetMouseXPositiveMultiplier(std::string bindingName, double newValue) noexcept
|
||||
{
|
||||
bindings[bindingName].mouseXPositiveMultiplier = newValue;
|
||||
}
|
||||
|
||||
static inline double const BindingsGetMouseYPositiveMultiplier(std::string bindingName) noexcept
|
||||
{
|
||||
return bindings[bindingName].mouseXPositiveMultiplier;
|
||||
}
|
||||
|
||||
static inline void BindingsSetMouseYPositiveMultiplier(std::string bindingName, double newValue) noexcept
|
||||
{
|
||||
bindings[bindingName].mouseXPositiveMultiplier = newValue;
|
||||
}
|
||||
|
||||
//Get the axis value of binding, between -1 and 1
|
||||
static double GetBindingAxis(std::string bindingName, size_t controllerNumber = 0) noexcept;
|
||||
|
||||
//Whether binding is being held or not
|
||||
//Does not work for mouse movement
|
||||
static bool GetBindingPositiveButton(std::string bindingName, size_t controllerNumber = 0) noexcept;
|
||||
static bool GetBindingNegativeButton(std::string bindingName, size_t controllerNumber = 0) noexcept;
|
||||
|
||||
//Whether binding is pressed down IN THIS FRAME ONLY
|
||||
//Does not work for mouse movement
|
||||
static bool GetBindingPositiveButtonDown(std::string bindingName, size_t controllerNumber = 0) noexcept;
|
||||
static bool GetBindingNegativeButtonDown(std::string bindingName, size_t controllerNumber = 0) noexcept;
|
||||
|
||||
//Whether binding is released IN THIS FRAME ONLY
|
||||
//Does not work for mouse movement
|
||||
static bool GetBindingPositiveButtonUp(std::string bindingName, size_t controllerNumber = 0) noexcept;
|
||||
static bool GetBindingNegativeButtonUp(std::string bindingName, size_t controllerNumber = 0) noexcept;
|
||||
|
||||
//Binding times
|
||||
|
||||
//Does not work for mouse movement
|
||||
static double GetBindingPositiveHeldTime(std::string bindingName, size_t controllerNumber = 0) noexcept;
|
||||
static double GetBindingNegativeHeldTime(std::string bindingName, size_t controllerNumber = 0) noexcept;
|
||||
|
||||
//Does not work for mouse movement
|
||||
static double GetBindingPositiveReleasedTime(std::string bindingName, size_t controllerNumber = 0) noexcept;
|
||||
static double GetBindingNegativeReleasedTime(std::string bindingName, size_t controllerNumber = 0) noexcept;
|
||||
|
||||
//Binding mouse velocity
|
||||
//Only for mouse movement
|
||||
static double GetBindingMouseVelocity(std::string bindingName, size_t controllerNumber = 0) noexcept;
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Other Functions */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
@ -482,10 +810,36 @@ namespace SHADE
|
|||
/*------------------------------------------------------------------------*/
|
||||
static constexpr size_t MAX_KEYS = UCHAR_MAX + 1;
|
||||
|
||||
//How many recognised controller inputs there are
|
||||
//To see the list, see the enum class in this file
|
||||
static constexpr size_t MAX_CONTROLLER_INPUT = 20;
|
||||
|
||||
//On/off button count
|
||||
static constexpr size_t NUM_CONTROLLER_BUTTON = 14;
|
||||
|
||||
//8-bit trigger values
|
||||
static constexpr size_t NUM_CONTROLLER_TRIGGER = 2;
|
||||
|
||||
//16-bit thumbstick values
|
||||
static constexpr size_t NUM_CONTROLLER_THUMBSTICK = 4;
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Data Members */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
//If the last input is from controller(s) or KB/M
|
||||
//True if from controller(s), False if from KB/M
|
||||
//Useful for switching control hints between controllers and KB/M
|
||||
static bool controllerInUse;
|
||||
|
||||
//BINDINGS//////////////////////////////////////////////////////////////////
|
||||
|
||||
//Key is for binding names, they must be unique
|
||||
//Multiple physical inputs per virtual/logical input are to be added to
|
||||
//sets inside the logicalBinding values
|
||||
//TODO make this an array of 4 / 5 users for multiplayer support
|
||||
static std::map<std::string, SHLogicalBindingData> bindings;
|
||||
|
||||
//KEYBOARD AND MOUSE BUTTONS////////////////////////////////////////////////
|
||||
|
||||
//How many keys are presently being pressed
|
||||
|
@ -558,15 +912,48 @@ namespace SHADE
|
|||
|
||||
//CONTROLLER VARIABLES//////////////////////////////////////////////////////
|
||||
|
||||
//OTHER VARIABLES///////////////////////////////////////////////////////////
|
||||
//Count how many controllers are presently connected
|
||||
//Useful for if the game is to decide to take in controller or KB/M input
|
||||
//Between 0 and 4 (inclusive)
|
||||
static unsigned char controllersConnectedCount;
|
||||
|
||||
//Axis bindings
|
||||
//X
|
||||
//How many inputs (of any kind) on the controller are being used now
|
||||
//Includes analog triggers and thumbsticks
|
||||
static unsigned controllersInputCount[XUSER_MAX_COUNT];
|
||||
|
||||
//Y
|
||||
//How many DIGITAL buttons on the controller are being pressed now
|
||||
static unsigned controllersButtonCount[XUSER_MAX_COUNT];
|
||||
|
||||
//Other mappings
|
||||
//Current state of controllers
|
||||
//First index is for controller number
|
||||
//Second index is for input type
|
||||
static short controllers[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT];
|
||||
|
||||
//Buffer
|
||||
//State of controllers in the last frame
|
||||
//First index is for controller number
|
||||
//Second index is for input type
|
||||
static short controllersLast[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT];
|
||||
|
||||
//Held and released times
|
||||
|
||||
//Controller held durations
|
||||
//Stops ticking up when released
|
||||
//Will be reset when held again
|
||||
static double controllersHeldTime[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT];
|
||||
|
||||
//Key released durations
|
||||
//Stops ticking up when held
|
||||
//Will be reset when off again
|
||||
static double controllersReleasedTime[XUSER_MAX_COUNT][MAX_CONTROLLER_INPUT];
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Internal Helper Functions */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
//Internal helper function for checking if input is considered held or not
|
||||
static bool controllerConsideredHeld(size_t inputIdx, short value) noexcept;
|
||||
|
||||
//Internal helper function for getting normalised controller value
|
||||
static double controllerNormalisedValue(size_t inputIdx, short value) noexcept;
|
||||
};
|
||||
}
|
|
@ -8,6 +8,7 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
/* Forward Declarations */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
class SHResourceLibraryBase;
|
||||
template<typename T>
|
||||
class SHResourceLibrary;
|
||||
|
||||
|
@ -25,6 +26,20 @@ namespace SHADE
|
|||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Exception thrown when a generic Handle is being casted to the wrong type.
|
||||
/// </summary>
|
||||
class BadHandleCastException : std::runtime_error
|
||||
{
|
||||
public:
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Constructors */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
BadHandleCastException()
|
||||
: std::runtime_error("Attempted to cast a generic Handle to the wrong type. ")
|
||||
{}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Base implementation of the Handle that is not templated to allow for holding
|
||||
/// generic non-type-specific Handles.
|
||||
|
@ -80,7 +95,7 @@ namespace SHADE
|
|||
/// Generic implementation of a Handle object
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the handle.</typeparam>
|
||||
template<typename T>
|
||||
template<typename T = void>
|
||||
class Handle : public HandleBase
|
||||
{
|
||||
public:
|
||||
|
@ -88,6 +103,16 @@ namespace SHADE
|
|||
/* Constructors */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
Handle() = default;
|
||||
/// <summary>
|
||||
/// Converts a generic/void Handle to a specific type.
|
||||
/// Runtime type checking is enabled to ensure that Handles are only being casted
|
||||
/// to the correct type.
|
||||
/// </summary>
|
||||
/// <param name="genericHandle">Generic handle to convert.</param>
|
||||
/// <exception cref="std::bad_cast">
|
||||
/// Thrown if an invalid conversion is made.
|
||||
/// </exception>
|
||||
explicit Handle(const Handle<void>& genericHandle);
|
||||
~Handle() = default;
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
|
@ -146,6 +171,41 @@ namespace SHADE
|
|||
/* Friend Declarations */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
friend class SHResourceLibrary<T>;
|
||||
friend class Handle<void>;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Template Specialization for Handle that represents a type-less Handle.
|
||||
/// </summary>
|
||||
template<>
|
||||
class Handle<void> : public HandleBase
|
||||
{
|
||||
public:
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Constructors */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
Handle() = default;
|
||||
template<typename T>
|
||||
explicit Handle(const Handle<T>& handle);
|
||||
~Handle() = default;
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Overloaded Operators */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
template<typename T>
|
||||
inline bool operator==(const Handle<T>& rhs) const noexcept;
|
||||
|
||||
protected:
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Data Members */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
SHResourceLibraryBase* library = nullptr;
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Friend Declarations */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
template<typename T>
|
||||
friend class Handle;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -21,6 +21,20 @@ namespace SHADE
|
|||
return id.Raw != INVALID_ID.Raw;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Handle<T> - Constructors */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
template<typename T>
|
||||
Handle<T>::Handle(const Handle<void>& genericHandle)
|
||||
: library { reinterpret_cast<SHResourceLibrary<T>*>(genericHandle.library) }
|
||||
{
|
||||
id = genericHandle.id;
|
||||
|
||||
// Check if valid
|
||||
if (library != nullptr && library->GetType() != typeid(T))
|
||||
throw BadHandleCastException();
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Handle<T> - Usage Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
@ -63,6 +77,28 @@ namespace SHADE
|
|||
return &library->Get(*this);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Handle<void> - Constructors */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
template<typename T>
|
||||
Handle<void>::Handle(const Handle<T>& handle)
|
||||
: library{ static_cast<SHResourceLibraryBase*>(handle.library) }
|
||||
{
|
||||
id = handle.id;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Handle<void> - Overloaded Operators */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
template<typename T>
|
||||
bool SHADE::Handle<void>::operator==(const Handle<T>& rhs) const noexcept
|
||||
{
|
||||
return id.Raw == rhs.id.Raw && library == static_cast<void*>(rhs.library);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* ISelfHandle<T> - Constructors */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
template<typename T>
|
||||
inline ISelfHandle<T>::ISelfHandle(const ISelfHandle& rhs)
|
||||
: handle { rhs.handle }
|
||||
|
@ -73,6 +109,9 @@ namespace SHADE
|
|||
: handle { rhs.handle }
|
||||
{}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* ISelfHandle<T> - Overloaded Operators */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
template<typename T>
|
||||
inline ISelfHandle<T>& ISelfHandle<T>::operator=(const ISelfHandle& rhs)
|
||||
{
|
||||
|
|
|
@ -11,13 +11,31 @@
|
|||
|
||||
namespace SHADE
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for SHResourceLibrary that holds information about the library type.
|
||||
/// </summary>
|
||||
class SHResourceLibraryBase
|
||||
{
|
||||
public:
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Getter Functions */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
inline std::type_index GetType() { return libraryType; }
|
||||
|
||||
protected:
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Data Members */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
std::type_index libraryType = typeid(void);
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Generic Resource Library for a specified type of Resource. This object will own
|
||||
/// any resources created using it.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of resources that this library stores.</typeparam>
|
||||
template<typename T>
|
||||
class SHResourceLibrary
|
||||
class SHResourceLibrary : public SHResourceLibraryBase
|
||||
{
|
||||
public:
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
|
|
|
@ -13,10 +13,11 @@ namespace SHADE
|
|||
SHResourceLibrary<T>::SHResourceLibrary()
|
||||
{
|
||||
// Type Checking
|
||||
//static_assert(std::is_copy_assignable_v<T>, "Resource Library's resources must be copy assignable.");
|
||||
//static_assert(std::is_copy_constructible_v<T>, "Resource Library's resources must be copy constructible.");
|
||||
static_assert(std::is_move_assignable_v<T>, "Resource Library's resources must be move assignable.");
|
||||
static_assert(std::is_move_constructible_v<T>, "Resource Library's resources must be move constructible.");
|
||||
|
||||
// Keep track of the type for conversions
|
||||
libraryType = typeid(T);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/************************************************************************************//*!
|
||||
\file SHResourceManager.cpp
|
||||
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||
\par email: kahwei.tng\@digipen.edu
|
||||
\date Oct 21, 2022
|
||||
\brief Contains the definition of the functions of the SHResourceManager static
|
||||
class.
|
||||
|
||||
Copyright (C) 2022 DigiPen Institute of Technology.
|
||||
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||
of DigiPen Institute of Technology is prohibited.
|
||||
*//*************************************************************************************/
|
||||
#include "SHpch.h"
|
||||
// Primary Include
|
||||
#include "SHResourceManager.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Static Data Member Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
SHResourceHub SHResourceManager::resourceHub;
|
||||
std::unordered_map<std::type_index, std::unordered_map<AssetID, Handle<void>>> SHResourceManager::handlesMap;
|
||||
std::unordered_map<std::type_index, SHADE::SHResourceManager::HandleAssetMap> SHResourceManager::assetIdMap;
|
||||
std::unordered_map<std::type_index, std::function<void(AssetID)>> SHResourceManager::typedFreeFuncMap;
|
||||
std::vector<AssetID> SHResourceManager::loadedAssetData;
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Function Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void SHResourceManager::Unload(AssetID assetId)
|
||||
{
|
||||
// Search each library for the asset ID and try to free it
|
||||
Handle handle;
|
||||
for (auto& typedHandleMap : handlesMap)
|
||||
{
|
||||
if (typedHandleMap.second.contains(assetId))
|
||||
{
|
||||
// Save handle for later
|
||||
handle = typedHandleMap.second[assetId];
|
||||
// Dispose
|
||||
typedFreeFuncMap[typedHandleMap.first](assetId);
|
||||
typedHandleMap.second.erase(assetId);
|
||||
}
|
||||
}
|
||||
|
||||
// No handles were found
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
for (auto& typedAssetIdsMap : assetIdMap)
|
||||
{
|
||||
if (typedAssetIdsMap.second.contains(handle))
|
||||
{
|
||||
// Dispose
|
||||
typedAssetIdsMap.second.erase(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SHResourceManager::FinaliseChanges()
|
||||
{
|
||||
SHGraphicsSystem* gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
|
||||
if (gfxSystem == nullptr)
|
||||
throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed.");
|
||||
gfxSystem->BuildMeshBuffers();
|
||||
gfxSystem->BuildTextures();
|
||||
|
||||
// Free CPU Resources
|
||||
for (auto assetId : loadedAssetData)
|
||||
{
|
||||
SHAssetManager::Unload(assetId);
|
||||
}
|
||||
loadedAssetData.clear();
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Query Functions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
std::optional<AssetID> SHResourceManager::GetAssetID(Handle<void> handle)
|
||||
{
|
||||
const Handle GENERIC_HANDLE = Handle(handle);
|
||||
|
||||
// Search each library for the asset ID and try to free it
|
||||
for (auto& typedAssetIdsMap : assetIdMap)
|
||||
{
|
||||
if (typedAssetIdsMap.second.contains(GENERIC_HANDLE))
|
||||
{
|
||||
return typedAssetIdsMap.second[GENERIC_HANDLE];
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
/************************************************************************************//*!
|
||||
\file SHResourceManager.h
|
||||
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||
\par email: kahwei.tng\@digipen.edu
|
||||
\date Oct 21, 2022
|
||||
\brief Contains the definition of the SHResourceManager static class.
|
||||
|
||||
Copyright (C) 2022 DigiPen Institute of Technology.
|
||||
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||
of DigiPen Institute of Technology is prohibited.
|
||||
*//*************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
// STL Includes
|
||||
#include <unordered_map>
|
||||
// Project Includes
|
||||
#include "SH_API.h"
|
||||
#include "SHResourceLibrary.h"
|
||||
#include "Assets/SHAssetMacros.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class responsible for loading and caching runtime resources from their
|
||||
/// serialised Asset IDs.
|
||||
/// </summary>
|
||||
class SH_API SHResourceManager
|
||||
{
|
||||
public:
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Loading Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Loads or retrieves an existing loaded object of the specified type with the
|
||||
/// specified asset ID.
|
||||
/// Note that for specific types, the retrieved Handle may not be valid until after
|
||||
/// FinaliseChanges() is called.
|
||||
/// </summary>
|
||||
/// <typeparam name="ResourceType">
|
||||
/// Type of resource to load.
|
||||
/// </typeparam>
|
||||
/// <param name="assetId">Asset ID of the resource to load.</param>
|
||||
/// <returns>Handle to a loaded runtime asset.</returns>
|
||||
template<typename ResourceType>
|
||||
static Handle<ResourceType> LoadOrGet(AssetID assetId);
|
||||
/// <summary>
|
||||
/// Unloads an existing loaded asset. Attempting to unload an invalid Handle will
|
||||
/// simply do nothing except emit a warning.
|
||||
/// Faster than the untemplated version.
|
||||
/// </summary>
|
||||
/// <typeparam name="ResourceType">Type of resource to unload.</typeparam>
|
||||
/// <param name="assetId">Handle to the resource to unload.</param>
|
||||
template<typename ResourceType>
|
||||
static void Unload(Handle<ResourceType> assetId);
|
||||
/// <summary>
|
||||
/// Unloads an existing loaded asset. Attempting to unload an invalid Handle will
|
||||
/// simply do nothing except emit a warning.
|
||||
/// Compared to the templated version, this function is slower as it requires
|
||||
/// searching through the storage of all resource types.
|
||||
/// </summary>
|
||||
/// <param name="assetId">Handle to the resource to unload.</param>
|
||||
static void Unload(AssetID assetId);
|
||||
/// <summary>
|
||||
/// Needs to be called to finalise all changes to loads.
|
||||
/// </summary>
|
||||
static void FinaliseChanges();
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Query Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Retrieves the AssetID associated with a specified Handle.
|
||||
/// Faster than the untemplated version.
|
||||
/// </summary>
|
||||
/// <typeparam name="ResourceType">Type of resource to get the ID of.</typeparam>
|
||||
/// <param name="handle">Handle to get the AssetID of.</param>
|
||||
/// <return>
|
||||
/// AssetID for the specified Handle. If the Handle is invalid, there will be no
|
||||
/// value.
|
||||
/// </return>
|
||||
template<typename T>
|
||||
static std::optional<AssetID> GetAssetID(Handle<T> handle);
|
||||
/// <summary>
|
||||
/// Retrieves the AssetID associated with a specified Handle.
|
||||
/// Compared to the templated version, this function is slower as it requires
|
||||
/// searching through the storage of all resource types.
|
||||
/// </summary>
|
||||
/// <param name="handle">Handle to get the AssetID of.</param>
|
||||
/// <return>
|
||||
/// AssetID for the specified Handle. If the Handle is invalid, there will be no
|
||||
/// value.
|
||||
/// </return>
|
||||
static std::optional<AssetID> GetAssetID(Handle<void> handle);
|
||||
|
||||
private:
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Type Definitions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
using AssetHandleMap = std::unordered_map<AssetID, Handle<void>>;
|
||||
using HandleAssetMap = std::unordered_map<Handle<void>, AssetID>;
|
||||
using AssetHandleMapRef = std::reference_wrapper<AssetHandleMap>;
|
||||
using HandleAssetMapRef = std::reference_wrapper<HandleAssetMap>;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Data Members */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
// Handles
|
||||
static SHResourceHub resourceHub;
|
||||
static std::unordered_map<std::type_index, AssetHandleMap> handlesMap;
|
||||
static std::unordered_map<std::type_index, HandleAssetMap> assetIdMap;
|
||||
static std::unordered_map<std::type_index, std::function<void(AssetID)>> typedFreeFuncMap;
|
||||
// Pointers to temp CPU resources
|
||||
static std::vector<AssetID> loadedAssetData;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Helper Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Retrieves or creates the AssetHandleMap for the specific type if it doesn't exist
|
||||
/// </summary>
|
||||
/// <typeparam name="ResourceType">
|
||||
/// The type of AssetHandleMap to retrieve.
|
||||
/// </typeparam>
|
||||
/// <returns>Reference to the AssetHandleMap of the specified type.</returns>
|
||||
template<typename ResourceType>
|
||||
static std::pair<AssetHandleMapRef, HandleAssetMapRef> getAssetHandleMap();
|
||||
};
|
||||
}
|
||||
|
||||
#include "SHResourceManager.hpp"
|
|
@ -0,0 +1,171 @@
|
|||
/************************************************************************************//*!
|
||||
\file SHResourceManager.hpp
|
||||
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||
\par email: kahwei.tng\@digipen.edu
|
||||
\date Oct 21, 2022
|
||||
\brief Contains the definition of the function templates of the
|
||||
SHResourceManager static class.
|
||||
|
||||
Copyright (C) 2022 DigiPen Institute of Technology.
|
||||
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||
of DigiPen Institute of Technology is prohibited.
|
||||
*//*************************************************************************************/
|
||||
#pragma once
|
||||
// Primary Include
|
||||
#include "SHResourceManager.h"
|
||||
// Project Includes
|
||||
#include "Assets/SHAssetManager.h"
|
||||
#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h"
|
||||
#include "ECS_Base/Managers/SHSystemManager.h"
|
||||
#include "Tools/SHLog.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Loading Functions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
template<typename ResourceType>
|
||||
Handle<ResourceType> SHResourceManager::LoadOrGet(AssetID assetId)
|
||||
{
|
||||
// Check if it is an unsupported type
|
||||
if (!std::is_same_v<ResourceType, SHMesh> && !std::is_same_v<ResourceType, SHTexture>)
|
||||
{
|
||||
static_assert(true, "Unsupported Resource Type specified for SHResourceManager.");
|
||||
}
|
||||
|
||||
/* Attempt to get existing loaded asset */
|
||||
auto [typedHandleMap, typedAssetIdMap] = getAssetHandleMap<ResourceType>();
|
||||
if (typedHandleMap.get().contains(assetId))
|
||||
return Handle<ResourceType>(typedHandleMap.get()[assetId]);
|
||||
|
||||
/* Otherwise, we need to load it! */
|
||||
// Meshes
|
||||
if constexpr (std::is_same_v<ResourceType, SHMesh>)
|
||||
{
|
||||
// Get system
|
||||
SHGraphicsSystem* gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
|
||||
if (gfxSystem == nullptr)
|
||||
throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed.");
|
||||
|
||||
// Load
|
||||
const SHMeshAsset* assetData = SHAssetManager::GetMesh(assetId);
|
||||
if (assetData == nullptr)
|
||||
{
|
||||
SHLog::Warning("[SHResourceManager] Attempted to load an asset with an invalid Asset ID.");
|
||||
return {};
|
||||
}
|
||||
loadedAssetData.emplace_back(assetId);
|
||||
|
||||
Handle<SHMesh> meshHandle = gfxSystem->AddMesh
|
||||
(
|
||||
assetData->vertexPosition.size(),
|
||||
assetData->vertexPosition.data(),
|
||||
assetData->texCoords.data(),
|
||||
assetData->vertexTangent.data(),
|
||||
assetData->vertexNormal.data(),
|
||||
assetData->indices.size(),
|
||||
assetData->indices.data()
|
||||
);
|
||||
Handle genericHandle = Handle(meshHandle);
|
||||
typedHandleMap.get().emplace(assetId, genericHandle);
|
||||
typedAssetIdMap.get().emplace(genericHandle, assetId);
|
||||
return meshHandle;
|
||||
}
|
||||
// Textures
|
||||
else if constexpr (std::is_same_v<ResourceType, SHTexture>)
|
||||
{
|
||||
// Get system
|
||||
SHGraphicsSystem* gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
|
||||
if (gfxSystem == nullptr)
|
||||
throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed.");
|
||||
|
||||
// Load
|
||||
const SHTextureAsset* assetData = SHAssetManager::GetTexture(assetId);
|
||||
if (assetData == nullptr)
|
||||
{
|
||||
SHLog::Warning("[SHResourceManager] Attempted to load an asset with an invalid Asset ID.");
|
||||
return {};
|
||||
}
|
||||
loadedAssetData.emplace_back(assetId);
|
||||
|
||||
Handle<SHTexture> texHandle = gfxSystem->AddTexture
|
||||
(
|
||||
assetData->numBytes,
|
||||
assetData->pixelData,
|
||||
assetData->width,
|
||||
assetData->height,
|
||||
assetData->format,
|
||||
assetData->mipOffsets
|
||||
);
|
||||
typedHandleMap.get().emplace(assetId, Handle(texHandle));
|
||||
return texHandle;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ResourceType>
|
||||
void SHResourceManager::Unload(Handle<ResourceType> assetId)
|
||||
{
|
||||
// Check if it is an unsupported type
|
||||
if (!std::is_same_v<ResourceType, SHMesh> && !std::is_same_v<ResourceType, SHTexture>)
|
||||
{
|
||||
static_assert(true, "Unsupported Resource Type specified for SHResourceManager.");
|
||||
}
|
||||
|
||||
/* Attempt to get existing loaded asset */
|
||||
auto [typedHandleMap, typedAssetIdMap] = getAssetHandleMap<ResourceType>();
|
||||
if (typedHandleMap.get().contains(assetId))
|
||||
{
|
||||
// Dispose
|
||||
Handle handle = typedHandleMap.get()[assetId];
|
||||
Handle<ResourceType> typedHandle = static_cast<Handle<ResourceType>>(handle);
|
||||
typedHandle.Free();
|
||||
typedAssetIdMap.get().erase(handle);
|
||||
typedHandleMap.get().erase(assetId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// There's nothing to remove
|
||||
SHLog::Warning("[SHResourceManager] Attempted to unload an invalid resource. Ignoring.");
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Query Functions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
template<typename T>
|
||||
static std::optional<AssetID> SHResourceManager::GetAssetID(Handle<T> handle)
|
||||
{
|
||||
const Handle GENERIC_HANDLE = Handle(handle);
|
||||
auto [typedHandleMap, typedAssetIdMap] = getAssetHandleMap<T>();
|
||||
if (typedAssetIdMap.get().contains(GENERIC_HANDLE))
|
||||
{
|
||||
return typedAssetIdMap.GetId()[GENERIC_HANDLE];
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Helper Functions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
template<typename ResourceType>
|
||||
std::pair<SHResourceManager::AssetHandleMapRef, SHResourceManager::HandleAssetMapRef> SHResourceManager::getAssetHandleMap()
|
||||
{
|
||||
const std::type_index TYPE = typeid(ResourceType);
|
||||
|
||||
if (!handlesMap.contains(TYPE))
|
||||
{
|
||||
handlesMap.emplace(TYPE, AssetHandleMap{});
|
||||
assetIdMap.emplace(TYPE, HandleAssetMap{});
|
||||
typedFreeFuncMap.emplace
|
||||
(
|
||||
TYPE,
|
||||
[TYPE](AssetID assetId)
|
||||
{
|
||||
static_cast<Handle<ResourceType>>(SHResourceManager::handlesMap[TYPE][assetId]).Free();
|
||||
}
|
||||
);
|
||||
}
|
||||
return std::make_pair(std::ref(handlesMap[TYPE]), std::ref(assetIdMap[TYPE]));
|
||||
}
|
||||
}
|
|
@ -54,11 +54,13 @@ namespace SHADE
|
|||
out << YAML::EndSeq;
|
||||
}
|
||||
|
||||
static void DeserializeEntity(YAML::iterator& it, YAML::Node const& node, std::vector<EntityID>& createdEntities, EntityID parentEID = MAX_EID)
|
||||
static EntityID DeserializeEntity(YAML::iterator& it, YAML::Node const& node, std::vector<EntityID>& createdEntities, EntityID parentEID = MAX_EID)
|
||||
{
|
||||
if (!node[EIDNode])
|
||||
return;
|
||||
EntityID eid = node[EIDNode].as<EntityID>();
|
||||
EntityID eid = MAX_EID;
|
||||
if(!node)
|
||||
return eid;
|
||||
if (node[EIDNode])
|
||||
eid = node[EIDNode].as<EntityID>();
|
||||
std::string name = "Default";
|
||||
if (node[EntityNameNode])
|
||||
name = node[EntityNameNode].as<std::string>();
|
||||
|
@ -117,7 +119,11 @@ namespace SHADE
|
|||
{
|
||||
DeserializeEntity(it, (*it), createdEntities);
|
||||
}
|
||||
|
||||
if(createdEntities.empty())
|
||||
{
|
||||
SHLOG_ERROR("Failed to create entities from deserializaiton")
|
||||
return;
|
||||
}
|
||||
//Initialize Entity
|
||||
auto entityVecIt = createdEntities.begin();
|
||||
for (auto it = entities.begin(); it != entities.end(); ++it)
|
||||
|
@ -136,17 +142,19 @@ namespace SHADE
|
|||
}
|
||||
}
|
||||
|
||||
std::string SHSerialization::SerializeEntitiesToString(std::vector<EntityID> const& entities)
|
||||
std::string SHSerialization::SerializeEntitiesToString(std::vector<EntityID> const& entities) noexcept
|
||||
{
|
||||
YAML::Emitter out;
|
||||
YAML::Node node;
|
||||
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
|
||||
out << YAML::BeginSeq;
|
||||
for (auto const& eid : entities)
|
||||
{
|
||||
auto entityNode = sceneGraph.GetNode(eid);
|
||||
EmitEntity(entityNode, out);
|
||||
}
|
||||
return std::basic_string<char>(out.c_str());
|
||||
out << YAML::EndSeq;
|
||||
return std::string(out.c_str());
|
||||
}
|
||||
|
||||
void SHSerialization::SerializeEntityToFile(std::filesystem::path const& path)
|
||||
|
@ -193,6 +201,30 @@ namespace SHADE
|
|||
return node;
|
||||
}
|
||||
|
||||
EntityID SHSerialization::DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID) noexcept
|
||||
{
|
||||
if(data.empty())
|
||||
return MAX_EID;
|
||||
YAML::Node entities = YAML::Load(data.c_str());
|
||||
EntityID eid{MAX_EID};
|
||||
std::vector<EntityID> createdEntities;
|
||||
for(auto it = entities.begin(); it != entities.end(); ++it)
|
||||
{
|
||||
eid = DeserializeEntity(it, *it, createdEntities, parentEID);
|
||||
}
|
||||
if(createdEntities.empty())
|
||||
{
|
||||
SHLOG_ERROR("Failed to create entities from deserializaiton")
|
||||
return MAX_EID;
|
||||
}
|
||||
auto entityVecIt = createdEntities.begin();
|
||||
for(auto it = entities.begin(); it != entities.end(); ++it)
|
||||
{
|
||||
InitializeEntity(*it, *entityVecIt++);
|
||||
}
|
||||
return eid;
|
||||
}
|
||||
|
||||
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
|
||||
std::optional<ComponentTypeID> GetComponentID(YAML::Node const& componentNode)
|
||||
{
|
||||
|
|
|
@ -29,14 +29,18 @@ namespace SHADE
|
|||
static void SerializeSceneToFile(std::filesystem::path const& path);
|
||||
static std::string SerializeSceneToString();
|
||||
static void SerializeSceneToEmitter(YAML::Emitter& out);
|
||||
|
||||
static void DeserializeSceneFromFile(std::filesystem::path const& path);
|
||||
|
||||
|
||||
static void EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out);
|
||||
static std::string SerializeEntitiesToString(std::vector<EntityID> const& entities);
|
||||
|
||||
static std::string SerializeEntitiesToString(std::vector<EntityID> const& entities) noexcept;
|
||||
static void SerializeEntityToFile(std::filesystem::path const& path);
|
||||
static YAML::Node SerializeEntityToNode(SHSceneNode* sceneNode);
|
||||
|
||||
static EntityID DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID = MAX_EID) noexcept;
|
||||
|
||||
static std::vector<ComponentTypeID> GetComponentIDList(YAML::Node const& componentsNode);
|
||||
private:
|
||||
static void InitializeEntity(YAML::Node const& entityNode, EntityID const& eid);
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
#include "SHpch.h"
|
||||
#include "SHClipboardUtilities.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
void SHClipboardUtilities::WriteToClipboard(std::string const& str) noexcept
|
||||
{
|
||||
if(str.empty())
|
||||
return;
|
||||
HWND const hwnd = GetDesktopWindow();
|
||||
OpenClipboard(hwnd);
|
||||
EmptyClipboard();
|
||||
|
||||
auto const size = str.size() + 1;
|
||||
const HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, size);
|
||||
if(hGlobal)
|
||||
{
|
||||
std::memcpy(GlobalLock(hGlobal), str.c_str(), size);
|
||||
GlobalUnlock(hGlobal);
|
||||
SetClipboardData(CF_TEXT, hGlobal);
|
||||
}
|
||||
else
|
||||
{
|
||||
SHLOG_ERROR("Failed to write to clipboard: {}", str.c_str())
|
||||
}
|
||||
CloseClipboard();
|
||||
GlobalFree(hGlobal);
|
||||
}
|
||||
|
||||
std::string const SHClipboardUtilities::GetDataFromClipboard() noexcept
|
||||
{
|
||||
HWND const hwnd = GetDesktopWindow();
|
||||
if(!OpenClipboard(hwnd))
|
||||
{
|
||||
SHLOG_ERROR("Failed to open clipboard")
|
||||
return std::string();
|
||||
}
|
||||
|
||||
if(HANDLE const dataHandle = GetClipboardData(CF_TEXT); dataHandle)
|
||||
{
|
||||
std::string data(static_cast<char*>(GlobalLock(dataHandle)));
|
||||
GlobalUnlock(dataHandle);
|
||||
CloseClipboard();
|
||||
return data;
|
||||
}
|
||||
CloseClipboard();
|
||||
return std::string();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
class SHClipboardUtilities
|
||||
{
|
||||
public:
|
||||
static void WriteToClipboard(std::string const& str) noexcept;
|
||||
static std::string const GetDataFromClipboard() noexcept;
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue