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

This commit is contained in:
Brandon Mak 2022-09-27 12:56:19 +08:00
commit 6f3c1ed97b
50 changed files with 4474 additions and 190 deletions

Binary file not shown.

Binary file not shown.

View File

@ -30,11 +30,12 @@ project "SHADE_Application"
externalincludedirs
{
"%{IncludeDir.spdlog}/include",
"%{IncludeDir.VULKAN}/include",
"%{IncludeDir.VMA}/include",
"%{IncludeDir.VULKAN}/Source/SPIRV-Reflect",
"%{IncludeDir.tinyddsloader}"
"%{IncludeDir.spdlog}/include",
"%{IncludeDir.VULKAN}/include",
"%{IncludeDir.VMA}/include",
"%{IncludeDir.VULKAN}/Source/SPIRV-Reflect",
"%{IncludeDir.RTTR}/include",
"%{IncludeDir.tinyddsloader}"
}
externalwarnings "Off"
@ -72,8 +73,12 @@ project "SHADE_Application"
filter "configurations:Debug"
symbols "On"
defines {"_DEBUG"}
defines {"_DEBUG", "SHEDITOR"}
filter "configurations:Release"
optimize "On"
defines{"_RELEASE", "SHEDITOR"}
filter "configurations:Publish"
optimize "On"
defines{"_RELEASE"}

View File

@ -4,7 +4,7 @@
//#define SHEDITOR
#ifdef SHEDITOR
#include "Editor/SHEditor.h"
#include "Editor/SHEditor.hpp"
//#include "Scenes/SBEditorScene.h"
#endif // SHEDITOR
@ -46,14 +46,13 @@ namespace Sandbox
// Set working directory
SHADE::SHFileUtilities::SetWorkDirToExecDir();
SDL_Init(SDL_INIT_EVERYTHING);
window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
// Create Systems
SHADE::SHSystemManager::CreateSystem<SHADE::SHGraphicsSystem>();
SHADE::SHSystemManager::CreateSystem<SHADE::SHScriptEngine>();
// TODO(Diren): Create Physics System here
SHADE::SHSystemManager::CreateSystem<SHADE::SHTransformSystem>();
SHADE::SHSystemManager::CreateSystem<SHADE::SHGraphicsSystem>();
SHADE::SHGraphicsSystem* graphicsSystem = static_cast<SHADE::SHGraphicsSystem*>(SHADE::SHSystemManager::GetSystem<SHADE::SHGraphicsSystem>());
SHADE::SHSystemManager::CreateSystem<SHADE::SHInputManagerSystem>();
@ -86,12 +85,11 @@ namespace Sandbox
// Set up graphics system and windows
graphicsSystem->SetWindow(&window);
sdlWindow = SDL_CreateWindowFrom(window.GetHWND());
//auto [w, h] = window.GetWindowSize();
//SDL_SetWindowSize(sdlWindow, w, h);
SHADE::SHSystemManager::Init();
#ifdef SHEDITOR
SDL_Init(SDL_INIT_VIDEO);
sdlWindow = SDL_CreateWindowFrom(window.GetHWND());
SHADE::SHEditor::Initialise(sdlWindow);
#else
#endif
@ -112,13 +110,9 @@ namespace Sandbox
graphicsSystem->BeginRender();
#ifdef SHEDITOR
SHADE::SHEditor::PreRender();
//SHADE::SHEditor::Render();
SHADE::SHEditor::Update(0.16f);
#endif
#ifdef SHEDITOR
SHADE::SHEditor::Render();
#endif
graphicsSystem->Run(1.0f);
graphicsSystem->EndRender();
@ -131,11 +125,12 @@ namespace Sandbox
{
#ifdef SHEDITOR
SHADE::SHEditor::Exit();
#endif
SHSceneManager::Exit();
SHADE::SHSystemManager::Exit();
SDL_DestroyWindow(sdlWindow);
SDL_Quit();
#endif
SHSceneManager::Exit();
SHADE::SHSystemManager::Exit();
}
}

View File

@ -54,6 +54,16 @@ namespace Sandbox
}
graphicsSystem->BuildMeshBuffers();
// Load Textures
auto textures = SHADE::SHAssetManager::GetAllDDS();
std::vector<Handle<SHTexture>> texHandles;
for (const auto& tex : textures)
{
auto texture = graphicsSystem->Add(tex);
texHandles.push_back(texture);
}
graphicsSystem->BuildTextures();
// Create Materials
auto matInst = graphicsSystem->AddOrGetBaseMaterialInstance();

View File

@ -117,12 +117,24 @@ project "SHADE_Engine"
filter "configurations:Debug"
symbols "On"
defines {"_DEBUG"}
defines {"_DEBUG", "SHEDITOR"}
links{"assimp-vc142-mtd.lib", "librttr_core_d.lib", "spdlogd.lib"}
--links{"fmodstudioL_vc.lib", "fmodL_vc.lib"}
filter "configurations:Release"
optimize "On"
defines{"_RELEASE", "SHEDITOR"}
links{"assimp-vc142-mt.lib", "librttr_core.lib", "spdlog.lib"}
--links{"fmodstudio_vc.lib", "fmod_vc.lib"}
filter "configurations:Publish"
optimize "On"
defines{"_RELEASE"}
links{"assimp-vc142-mt.lib", "librttr_core.lib", "spdlog.lib"}
excludes
{
"%{prj.location}/src/Editor/**.cpp",
"%{prj.location}/src/Editor/**.h",
"%{prj.location}/src/Editor/**.hpp",
}
--links{"fmodstudio_vc.lib", "fmod_vc.lib"}

View File

@ -2,16 +2,17 @@
#include <vector>
#include "Math/SHMath.h"
#include "SH_API.h"
namespace SHADE
{
struct SHMeshAssetHeader
struct SH_API SHMeshAssetHeader
{
uint32_t vertexCount;
uint32_t indexCount;
};
struct SHMeshAsset
struct SH_API SHMeshAsset
{
bool compiled;
bool changed;
@ -21,9 +22,9 @@ namespace SHADE
std::string meshName;
std::vector<SHVec3> vertexPosition;
std::vector<SHVec2> texCoords;
std::vector<SHVec3> vertexTangent;
std::vector<SHVec3> vertexNormal;
std::vector<SHVec2> texCoords;
std::vector<uint32_t> indices;
};
}

View File

@ -70,7 +70,8 @@ enum class AssetType : uint8_t
#define PREFAB_EXTENSION ".SHPrefab"
#define MATERIAL_EXTENSION ".SHMat"
#define TEXTURE_EXTENSION ".dds"
#define MESH_EXTENSION ".fbx"
#define FBX_EXTENSION ".fbx"
#define MESH_EXTENSION ".shmesh"
std::string const EXTENSIONS[] = {
AUDIO_EXTENSION,
@ -82,7 +83,8 @@ std::string const EXTENSIONS[] = {
SCRIPT_EXTENSION,
SCENE_EXTENSION,
PREFAB_EXTENSION,
AUDIO_WAV_EXTENSION
AUDIO_WAV_EXTENSION,
FBX_EXTENSION
};
// Error flags

View File

@ -199,7 +199,7 @@ namespace SHADE
{
AssetPath path{ p };
if (path.extension().string() == MESH_EXTENSION)
if (path.extension().string() == FBX_EXTENSION)
{
LoadGLTF(
{
@ -236,6 +236,17 @@ namespace SHADE
return result;
}
std::vector<SHDDSAsset> SHAssetManager::GetAllDDS() noexcept
{
std::vector<SHDDSAsset> result;
for (auto const& dds : ddsCollection)
{
result.push_back(dds.second);
}
return result;
}
/****************************************************************************
* \param Path for meta data file
* \param Path for asset file

View File

@ -73,6 +73,7 @@ namespace SHADE
//TODO: TEMPORARY FOR TESTING GLTF & DDS
static void LoadDataTemp(std::string path) noexcept;
static std::vector<SHMeshAsset> GetAllMeshes() noexcept;
static std::vector<SHDDSAsset> GetAllDDS() noexcept;
private:
/****************************************************************************

View File

@ -0,0 +1,51 @@
#pragma once
//#==============================================================#
//|| STL Includes ||
//#==============================================================#
#include <functional>
namespace SHADE
{
class SHBaseCommand
{
public:
virtual ~SHBaseCommand() = default;
virtual void Execute() {}
virtual void Undo() {}
virtual void Merge(std::shared_ptr<SHBaseCommand>) {}
};//struct SHBaseCommand
template <typename T>
class SHCommand : SHBaseCommand
{
public:
typedef std::function<void(T const&)> SetterFunction;
SHCommand(T const& oldVal, T const& value, SetterFunction setFnc)
: oldValue(oldVal), newValue(value), set(setFnc)
{
}
void Execute() override
{
set(newValue);
}
void Undo() override
{
set(oldValue);
}
void Merge(std::shared_ptr<SHBaseCommand> newCommand) override
{
newValue = std::reinterpret_pointer_cast<SHCommand>(newCommand)->newValue;
}
private:
T oldValue;
T newValue;
SetterFunction set;
};
}//namespace SHADE

View File

@ -0,0 +1,57 @@
//#==============================================================#
//|| PCH Include ||
//#==============================================================#
#include "SHpch.h"
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "SHCommandManager.h"
namespace SHADE
{
SHCommandManager::CommandStack SHCommandManager::undoStack{};
SHCommandManager::CommandStack SHCommandManager::redoStack{};
void SHCommandManager::PerformCommand(CommandPtr commandPtr, bool const& overrideValue)
{
redoStack = CommandStack();
commandPtr->Execute();
if (overrideValue && !undoStack.empty())
{
undoStack.top()->Merge(commandPtr);
}
else
{
undoStack.push(commandPtr);
}
}
void SHCommandManager::UndoCommand()
{
if (undoStack.empty())
return;
undoStack.top()->Undo();
redoStack.push(undoStack.top());
undoStack.pop();
}
void SHCommandManager::RedoCommand()
{
if (redoStack.empty())
return;
redoStack.top()->Execute();
undoStack.push(redoStack.top());
redoStack.pop();
}
std::size_t SHCommandManager::GetUndoStackSize()
{
return undoStack.size();
}
std::size_t SHCommandManager::GetRedoStackSize()
{
return redoStack.size();
}
}//namespace SHADE

View File

@ -0,0 +1,34 @@
#pragma once
//#==============================================================#
//|| STL Includes ||
//#==============================================================#
#include <stack>
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "SHCommand.hpp"
namespace SHADE
{
class SHCommandManager
{
public:
//#==============================================================#
//|| Type Aliases ||
//#==============================================================#
using CommandPtr = std::shared_ptr<SHBaseCommand>;
using CommandStack = std::stack<CommandPtr>;
static void PerformCommand(CommandPtr commandPtr, bool const& overrideValue = false);
static void UndoCommand();
static void RedoCommand();
static std::size_t GetUndoStackSize();
static std::size_t GetRedoStackSize();
private:
static CommandStack undoStack;
static CommandStack redoStack;
};
}//namespace SHADE

View File

@ -0,0 +1,21 @@
#include "SHpch.h"
#include "SHDragDrop.hpp"
namespace SHADE
{
bool SHDragDrop::hasDragDrop = false;
bool SHDragDrop::BeginSource(ImGuiDragDropFlags const flags)
{ return ImGui::BeginDragDropSource(flags); }
void SHDragDrop::EndSource()
{ ImGui::EndDragDropSource();}
bool SHDragDrop::BeginTarget()
{ return ImGui::BeginDragDropTarget(); }
void SHDragDrop::EndTarget()
{ ImGui::EndDragDropTarget(); hasDragDrop = false;}
}

View File

@ -0,0 +1,44 @@
#pragma once
#include <string_view>
#include <imgui.h>
namespace SHADE
{
//TODO: Convert to RTTR?
constexpr auto DRAG_EID = "DragEID";
constexpr auto DRAG_RESOURCE = "DragResource";
struct SHDragDrop
{
static bool BeginSource(ImGuiDragDropFlags const flags = 0);
/**
* \brief Ends the DragDrop Source. ONLY CALL IF BeginSource returns true
*/
static void EndSource();
template<typename T>
static bool SetPayload(std::string_view const type, T* object, ImGuiCond const cond = 0)
{
hasDragDrop = ImGui::SetDragDropPayload(type.data(), static_cast<void*>(object), sizeof(T), cond);
return hasDragDrop;
}
static bool BeginTarget();
/**
* \brief Ends the DragDrop Target. ONLY CALL IF BeginTarget returns true
*/
static void EndTarget();
template<typename T>
static T* AcceptPayload(std::string_view const type, ImGuiDragDropFlags const flags = 0)
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(type.data(), flags))
return static_cast<T*>(payload->Data);
return nullptr;
}
static bool hasDragDrop;
};
}

View File

@ -0,0 +1,212 @@
//#==============================================================#
//|| PCH Include ||
//#==============================================================#
#include "SHpch.h"
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "Editor/SHImGuiHelpers.hpp"
#include "Editor/SHEditorWidgets.hpp"
#include "SHHierarchyPanel.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Editor/SHEditor.hpp"
#include "Scene/SHSceneManager.h"
#include "Editor/DragDrop/SHDragDrop.hpp"
#include "Tools/SHException.h"
#include "Editor/IconsMaterialDesign.h"
//#==============================================================#
//|| Library Includes ||
//#==============================================================#
#include <imgui.h>
namespace SHADE
{
//#==============================================================#
//|| Public Member Functions ||
//#==============================================================#
SHHierarchyPanel::SHHierarchyPanel()
:SHEditorWindow("Hierarchy Panel", ImGuiWindowFlags_MenuBar)
{
}
void SHHierarchyPanel::Init()
{
SHEditorWindow::Init();
}
void SHHierarchyPanel::Update()
{
SHEditorWindow::Update();
isAnyNodeSelected = false;
if (Begin())
{
DrawMenuBar();
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
if(const auto root = sceneGraph.GetRoot())
{
auto const& children = root->GetChildren();
for (const auto child : children)
{
RecursivelyDrawEntityNode(child);
}
}
else
{
SHLOG_WARNING("Scene Graph root is null! Unable to render hierarchy.")
}
if(ImGui::IsWindowHovered() && !SHDragDrop::hasDragDrop && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
SHEditor::selectedEntities.clear();
}
ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal);
ImGui::End();
}
}
void SHHierarchyPanel::Exit()
{
SHEditorWindow::Exit();
}
//#==============================================================#
//|| Private Member Functions ||
//#==============================================================#
void SHHierarchyPanel::DrawMenuBar() const noexcept
{
if (ImGui::BeginMenuBar())
{
if (ImGui::SmallButton(ICON_MD_ADD))
{
SHEntityManager::CreateEntity();
}
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Add Entity");
ImGui::EndTooltip();
}
ImGui::EndMenuBar();
}
}
ImRect SHHierarchyPanel::RecursivelyDrawEntityNode(SHSceneNode* currentNode)
{
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
//Get node data (Children, eid, selected)
auto& children = currentNode->GetChildren();
EntityID eid = currentNode->GetEntityID();
const bool isSelected = (std::ranges::find(SHEditor::selectedEntities, eid) != SHEditor::selectedEntities.end());
const ImGuiTreeNodeFlags nodeFlags = ((isSelected) ? ImGuiTreeNodeFlags_Selected : 0) | ((children.empty()) ? ImGuiTreeNodeFlags_Leaf : ImGuiTreeNodeFlags_OpenOnArrow);
//bool highlighted = false;
//if(highlighted)
//{
// ImGui::PushStyleColor(ImGuiCol_Text, highlightedColor);
//}
auto* entity = SHEntityManager::GetEntityByID(currentNode->GetEntityID());
//Draw Node
bool isNodeOpen = ImGui::TreeNodeEx((void*)eid, nodeFlags, "%u: %s", EntityHandleGenerator::GetIndex(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);
SHDragDrop::EndSource();
}
else if (SHDragDrop::BeginTarget()) //If Received DragDrop
{
if (const EntityID* eidPayload = SHDragDrop::AcceptPayload<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)
SHDragDrop::EndTarget();
}
}
//Context menu
if(ImGui::BeginPopupContextItem(std::to_string(eid).c_str()))
{
if(!isSelected)
{
SHEditor::selectedEntities.clear();
SHEditor::selectedEntities.push_back(eid);
}
if(ImGui::Selectable(std::format("{} Delete", ICON_MD_DELETE).data()))
{
SHEntityManager::DestroyEntity(eid);
}
if((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data()))
{
sceneGraph.SetParent(currentNode->GetEntityID(), nullptr);
}
ImGui::EndPopup();
}
//Handle node selection
if (ImGui::IsItemHovered())
{
if (ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
if (!isSelected)
{
if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
SHEditor::selectedEntities.clear();
SHEditor::selectedEntities.push_back(eid);
}//if not selected
else
{
if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
{
auto it = std::ranges::remove(SHEditor::selectedEntities, eid).begin();
}//if mod ctrl is not pressed
else
{
SHEditor::selectedEntities.clear();
SHEditor::selectedEntities.push_back(eid);
}
}//if selected
}//if left mouse button released
}//if item hovered
if (isNodeOpen)
{
const ImColor treeLineColor = ImGui::GetColorU32(ImGuiCol_CheckMark);
const float horizontalOffset = 0.0f;
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 vertLineStart = ImGui::GetCursorScreenPos();
vertLineStart.x += horizontalOffset;
ImVec2 vertLineEnd = vertLineStart;
for (const auto child : children)
{
const float horizontalLineSize = 8.0f;
const ImRect childRect = RecursivelyDrawEntityNode(child);
const float midPoint = (childRect.Min.y + childRect.Max.y) * 0.5f;
drawList->AddLine(ImVec2(vertLineStart.x, midPoint), ImVec2(vertLineStart.x + horizontalLineSize, midPoint), treeLineColor, 2);
vertLineEnd.y = midPoint;
}
drawList->AddLine(vertLineStart, vertLineEnd, treeLineColor, 2);
ImGui::TreePop();
}
return nodeRect;
}
void SHHierarchyPanel::CreateChildEntity(EntityID parentEID) const noexcept
{
SHEntityManager::CreateEntity(MAX_EID, "DefaultChild", parentEID);
}
}//namespace SHADE

View File

@ -0,0 +1,33 @@
#pragma once
//#==============================================================#
//|| Library Includes ||
//#==============================================================#
#include <imgui.h>
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "imgui_internal.h"
#include "ECS_Base/SHECSMacros.h"
#include "Editor/EditorWindow/SHEditorWindow.h"
namespace SHADE
{
class SHSceneNode;
constexpr ImVec4 highlightedColor = ImVec4(0.f, 0.7f, 0.0f, 1.0f);
class SHHierarchyPanel final : public SHEditorWindow
{
public:
SHHierarchyPanel();
void Init() override;
void Update() override;
void Exit() override;
private:
void DrawMenuBar() const noexcept;
ImRect RecursivelyDrawEntityNode(SHSceneNode*);
void CreateChildEntity(EntityID parentEID) const noexcept;
std::string filter;
bool isAnyNodeSelected = false;
};//class SHHierarchyPanel
}//namespace SHADE

View File

@ -0,0 +1,70 @@
#pragma once
//#==============================================================#
//|| Library Includes ||
//#==============================================================#
#include <imgui.h>
#include <rttr/type>
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "Editor/IconsMaterialDesign.h"
#include "ECS_Base/Components/SHComponent.h"
#include "Editor/SHEditorWidgets.hpp"
namespace SHADE
{
template<typename T, std::enable_if_t<std::is_base_of<SHComponent, T>::value, bool> = true>
static void DrawContextMenu(T* component)
{
if(!component)
return;
rttr::string_view componentName = rttr::type::get<T>().get_name();
if (ImGui::BeginPopupContextItem(componentName.data()))
{
if (ImGui::Selectable(std::format("{} Copy {}", ICON_MD_CONTENT_COPY, componentName.data()).data()))
{
//SHClipboardUtil::WriteStringToClipboard(SHClipboardUtil::CFNAME::CFCOMPONENT, SHComponentToString(component));
}
if (ImGui::Selectable(std::format("{} Paste {}", ICON_MD_CONTENT_PASTE, componentName.data()).data()))
{
//SHStringToComponent(component, SHClipboardUtil::ReadStringFromClipboard(SHClipboardUtil::CFNAME::CFCOMPONENT));
}
if (ImGui::Selectable(std::format("{} Delete {}", ICON_MD_DELETE, componentName.data()).data()))
{
SHComponentManager::RemoveComponent<T>(component->GetEID());
}
ImGui::EndPopup();
}
}
template<typename T, std::enable_if_t<std::is_base_of_v<SHComponent, T>, bool> = true>
static void DrawComponent(T* component)
{
if (!component)
return;
auto componentType = rttr::type::get(*component);
CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; });
ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data()))
{
DrawContextMenu(component);
auto const& properties = componentType.get_properties();
for (auto const& property : properties)
{
auto const& type = property.get_type();
if (type == rttr::type::get<SHVec4>())
{
DragVec4(property.get_name().data(), { "X", "Y", "Z", "W" }, [component, property]() {return property.get_value(component).template convert<SHVec4>(); }, [component, property](SHVec4 vec) {return property.set_value(component, vec); });
}
else if (type == rttr::type::get<SHVec3>())
{
DragVec3(property.get_name().data(), { "X", "Y", "Z" }, [component, property]() {return property.get_value(component).template convert<SHVec3>(); }, [component, property](SHVec3 vec) {return property.set_value(component, vec); });
}
}
}
else DrawContextMenu(component);
}
}

View File

@ -0,0 +1,73 @@
#include "SHpch.h"
#include "SHEditorInspector.h"
#include "ECS_Base/SHECSMacros.h"
#include "ECS_Base/Entity/SHEntity.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Editor/SHEditor.hpp"
#include "Editor/SHImGuiHelpers.hpp"
#include "Editor/SHEditorWidgets.hpp"
#include "SHEditorComponentView.hpp"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h"
namespace SHADE
{
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
void DrawAddComponentButton(EntityID const& eid)
{
if(!SHComponentManager::HasComponent<ComponentType>(eid) && ImGui::Selectable(std::format("Add {}", rttr::type::get<ComponentType>().get_name().data()).data()))
{
SHComponentManager::AddComponent<ComponentType>(eid);
}
}
SHEditorInspector::SHEditorInspector()
:SHEditorWindow("Inspector", ImGuiWindowFlags_MenuBar)
{
}
void SHEditorInspector::Init()
{
SHEditorWindow::Init();
}
void SHEditorInspector::Update()
{
SHEditorWindow::Update();
if (Begin())
{
if (!SHEditor::selectedEntities.empty())
{
EntityID const& eid = SHEditor::selectedEntities[0];
SHEntity* entity = SHEntityManager::GetEntityByID(eid);
ImGui::TextColored(ImGuiColors::green, "EID: %zu", eid);
CheckBox("##IsActive", [entity]()->bool {return entity->GetActive(); }, [entity](bool const& active) {entity->SetActive(active); });
ImGui::SameLine();
ImGui::InputText("##EntityName", &entity->name);
if (auto transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(eid))
{
DrawComponent(transformComponent);
}
ImGui::Separator();
if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data()))
{
DrawAddComponentButton<SHTransformComponent>(eid);
DrawAddComponentButton<SHRenderable>(eid);
ImGui::EndMenu();
}
}
ImGui::End();
}
}
void SHEditorInspector::Exit()
{
SHEditorWindow::Exit();
}
}

View File

@ -0,0 +1,30 @@
#pragma once
//#==============================================================#
//|| Library Includes ||
//#==============================================================#
#include <imgui.h>
#include <rttr/type>
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "Editor/EditorWindow/SHEditorWindow.h"
namespace SHADE
{
class SHComponent;
class SHEditorInspector final : public SHEditorWindow
{
public:
SHEditorInspector();
void Init() override;
void Update() override;
void Exit() override;
private:
};
}

View File

@ -0,0 +1,130 @@
#include "SHpch.h"
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "SHEditorMenuBar.h"
#include "Editor/IconsMaterialDesign.h"
#include "Editor/Command/SHCommandManager.h"
//#==============================================================#
//|| Library Includes ||
//#==============================================================#
#include <imgui.h>
#include <imgui_internal.h>
#include <rttr/type>
#include "Editor/SHEditor.hpp"
namespace SHADE
{
constexpr ImGuiWindowFlags editorMenuBarFlags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDocking |
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
constexpr ImGuiWindowFlags dockspaceFlags = ImGuiDockNodeFlags_PassthruCentralNode;
//#==============================================================#
//|| Public Member Functions ||
//#==============================================================#
SHEditorMenuBar::SHEditorMenuBar()
:SHEditorWindow("SHEditorMenuBar", editorMenuBarFlags | ImGuiWindowFlags_NoBackground)
{
}
void SHEditorMenuBar::Init()
{
SHEditorWindow::Init();
}
void SHEditorMenuBar::Update()
{
SHEditorWindow::Update();
DrawMainMenuBar();
DrawSecondaryBar();
DrawStatusBar();
}
//#==============================================================#
//|| Private Member Functions ||
//#==============================================================#
void SHEditorMenuBar::DrawMainMenuBar() noexcept
{
const ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->WorkPos);
ImGui::SetNextWindowSize(viewport->WorkSize);
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { ImVec2(0.0f, 0.0f) });
if (Begin())
{
ImGui::PopStyleVar(3);
if (ImGui::BeginMainMenuBar())
{
if (ImGui::BeginMenu("File"))
{
ImGui::EndMenu();
}
if(ImGui::BeginMenu("Edit"))
{
ImGui::BeginDisabled(!SHCommandManager::GetUndoStackSize());
if(ImGui::Button(std::format("{} Undo", ICON_MD_UNDO).data()))
{
SHCommandManager::UndoCommand();
}
ImGui::EndDisabled();
ImGui::BeginDisabled(!SHCommandManager::GetRedoStackSize());
if(ImGui::Button(std::format("{} Redo", ICON_MD_REDO).data()))
{
SHCommandManager::RedoCommand();
}
ImGui::EndDisabled();
ImGui::EndMenu();
}
if(ImGui::BeginMenu("Theme"))
{
auto styles = rttr::type::get<SHEditor::Style>().get_enumeration();
auto values = styles.get_values();
for (auto style : values)
{
if(ImGui::Selectable(style.to_string().c_str()))
{
SHEditor::SetStyle(style.convert<SHEditor::Style>());
}
}
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
const ImGuiID dockspace_id = ImGui::GetID("DockSpace");
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspaceFlags);
ImGui::End();
}
}
void SHEditorMenuBar::DrawSecondaryBar() const noexcept
{
}
void SHEditorMenuBar::DrawStatusBar() const noexcept
{
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { ImVec2(0.0f, 0.0f) });
if (ImGui::BeginViewportSideBar("MainStatusBar", ImGui::GetMainViewport(), ImGuiDir_Down, menuBarHeight, editorMenuBarFlags))
{
ImGui::Text("Entity count: ");
ImGui::End();
}
ImGui::PopStyleVar(3);
}
}//namespace SHADE

View File

@ -0,0 +1,22 @@
#pragma once
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "Editor/EditorWindow/SHEditorWindow.h"
namespace SHADE
{
class SHEditorMenuBar final : public SHEditorWindow
{
public:
SHEditorMenuBar();
virtual void Init() override;
virtual void Update() override;
private:
void DrawMainMenuBar() noexcept;
void DrawSecondaryBar() const noexcept;
void DrawStatusBar() const noexcept;
float menuBarHeight = 20.0f;
};//class SHEditorMenuBar
}//namespace SHADE

View File

@ -0,0 +1,46 @@
//#==============================================================#
//|| PCH Include ||
//#==============================================================#
#include "SHpch.h"
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "SHEditorWindow.h"
//#==============================================================#
//|| Library Includes ||
//#==============================================================#
#include <imgui.h>
namespace SHADE
{
//#==============================================================#
//|| Public Member Functions ||
//#==============================================================#
SHEditorWindow::SHEditorWindow(std::string_view const& name, ImGuiWindowFlags const& inFlags)
: isOpen(true), windowName(name), windowFlags(inFlags), io(ImGui::GetIO())
{
}
void SHEditorWindow::Init()
{
}
void SHEditorWindow::Update()
{
}
void SHEditorWindow::Exit()
{
}
//#==============================================================#
//|| Protected Member Functions ||
//#==============================================================#
bool SHEditorWindow::Begin()
{
return ImGui::Begin(windowName.data(), &isOpen, windowFlags);
}
}//namespace SHADE

View File

@ -0,0 +1,31 @@
#pragma once
//#==============================================================#
//|| STL Includes ||
//#==============================================================#
#include <string>
//#==============================================================#
//|| Forward Declarations ||
//#==============================================================#
struct ImGuiIO;
typedef int ImGuiWindowFlags;
namespace SHADE
{
class SHEditorWindow
{
public:
SHEditorWindow(std::string_view const& name, ImGuiWindowFlags const& inFlags);
virtual ~SHEditorWindow() = default;
virtual void Init();
virtual void Update();
virtual void Exit();
bool isOpen = false;
std::string_view windowName;
protected:
virtual bool Begin();
ImGuiWindowFlags windowFlags = 0;
ImGuiIO& io;
};//class SHEditorWindow
}//namespace SHADE

View File

@ -0,0 +1,4 @@
#pragma once
#include "MenuBar/SHEditorMenuBar.h" //Menu Bar
#include "HierarchyPanel/SHHierarchyPanel.h" //Hierarchy Panel
#include "Inspector/SHEditorInspector.h" //Inspector

File diff suppressed because it is too large Load Diff

View File

@ -1,79 +1,125 @@
//#==============================================================#
//|| PCH Include ||
//#==============================================================#
#include "SHpch.h"
#include "SHEditor.h"
#include <imgui.h>
#include "IconsMaterialDesign.h"
#include "DragDrop/SHDragDrop.hpp"
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "Tools/SHLogger.h"
#include "Tools/SHException.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Graphics/Instance/SHVkInstance.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h"
#include "Graphics/Swapchain/SHVkSwapchain.h"
#include "Graphics/MiddleEnd/Interface/SHViewport.h"
#include "Graphics/MiddleEnd/Interface/SHRenderer.h"
//IMGUI Backend includes
#include "SHEditor.hpp"
#include "SHEditorWidgets.hpp"
//#==============================================================#
//|| Editor Window Includes ||
//#==============================================================#
#include "EditorWindow/SHEditorWindowIncludes.h"
//#==============================================================#
//|| Library Includes ||
//#==============================================================#
#include <imgui.h>
#include <SDL.h>
#include <rttr/registration>
//#==============================================================#
//|| ImGui Backend Includes ||
//#==============================================================#
#include <backends/imgui_impl_sdl.h>
#include <backends/imgui_impl_vulkan.h>
RTTR_REGISTRATION
{
using namespace SHADE;
using namespace rttr;
registration::enumeration<SHEditor::Style>("Style")
(
value("SHADE", SHEditor::Style::SHADE),
value("DARK", SHEditor::Style::DARK),
value("LIGHT", SHEditor::Style::LIGHT),
value("CLASSIC", SHEditor::Style::CLASSIC)
);
}
namespace SHADE
{
//#==============================================================#
//|| Initialise static members ||
//#==============================================================#
Handle<SHVkCommandPool> SHEditor::imguiCommandPool;
Handle<SHVkCommandBuffer> SHEditor::imguiCommandBuffer;
SHEditor::EditorWindowMap SHEditor::editorWindows{};
SHEditor::EditorWindowID SHEditor::windowCount{};
std::vector<EntityID> SHEditor::selectedEntities;
void SHEditor::Initialise(SDL_Window* sdlWindow)
//#==============================================================#
//|| Public Member Functions ||
//#==============================================================#
void SHEditor::Initialise(SDL_Window* const sdlWindow)
{
IMGUI_CHECKVERSION();
ImGui::CreateContext();
if(auto context = ImGui::CreateContext())
{
if(context == nullptr)
{
SHLOG_CRITICAL("Failed to create ImGui Context")
}
}
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; //Enable for Multi-Viewports
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; //Enable docking
ImGui_ImplSDL2_InitForVulkan(sdlWindow);
InitFonts();
InitBackend(sdlWindow);
auto* gfxSystem = reinterpret_cast<SHGraphicsSystem*>(SHSystemManager::GetSystem<SHGraphicsSystem>());
SetStyle(Style::SHADE);
//Add editor windows
CreateEditorWindow<SHEditorMenuBar>();
CreateEditorWindow<SHHierarchyPanel>();
CreateEditorWindow<SHEditorInspector>();
ImGui_ImplVulkan_InitInfo initInfo{};
initInfo.Instance = SHVkInstance::GetVkInstance();
initInfo.PhysicalDevice = gfxSystem->GetPhysicalDevice()->GetVkPhysicalDevice();
initInfo.Device = gfxSystem->GetDevice()->GetVkLogicalDevice();
initInfo.Queue = gfxSystem->GetQueue()->GetVkQueue();
initInfo.DescriptorPool = gfxSystem->GetDescriptorPool()->GetVkHandle();
initInfo.MinImageCount = initInfo.ImageCount = gfxSystem->GetSwapchain()->GetNumImages();
initInfo.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
imguiCommandPool = gfxSystem->GetDevice()->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true);
imguiCommandBuffer = imguiCommandPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
/*auto renderPass = gfxSystem->GetRenderGraph().GetNode("ImGui Node")->GetRenderpass();
ImGui_ImplVulkan_Init(&initInfo, renderPass->GetVkRenderpass());*/
imguiCommandBuffer->BeginRecording();
ImGui_ImplVulkan_CreateFontsTexture(imguiCommandBuffer->GetVkCommandBuffer());
imguiCommandBuffer->EndRecording();
gfxSystem->GetQueue()->SubmitCommandBuffer({imguiCommandBuffer}, {}, {}, vk::PipelineStageFlagBits::eNone, {});
ImGui_ImplVulkan_DestroyFontUploadObjects();
/*gfxSystem->GetRenderGraph().GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle<SHVkCommandBuffer>& cmd) {
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer());
});*/
//ImGuiIO& io = ImGui::GetIO();
//int w, h;
//SDL_GetWindowSize(sdlWindow, &w, &h);
//io.DisplaySize = { static_cast<float>(w),static_cast<float>(h)};
SHLOG_INFO("Successfully initialised SHADE Engine Editor")
}
void SHEditor::PreRender()
void SHEditor::Update(float const dt)
{
(void)dt;
NewFrame();
ImGui::ShowDemoWindow();
ImGui::Begin("Your mom");
if (ImGui::Button("OP"))
for (const auto& window : editorWindows | std::views::values)
{
std::cout << "HEHEHEOHEIOHIEOH\n";
window->Update();
}
ImGui::End();
if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z))
{
SHCommandManager::RedoCommand();
}
else if(ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z))
{
SHCommandManager::UndoCommand();
}
Render();
}
void SHEditor::Render()
@ -87,6 +133,18 @@ namespace SHADE
}
}
void SHEditor::InitFonts() noexcept
{
ImGuiIO& io = ImGui::GetIO();
ImFont* mainFont = io.Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/Segoe UI.ttf", 20.f);//TODO: Change to config based assets path
static const ImWchar icon_ranges[] = { ICON_MIN_MD, ICON_MAX_16_MD, 0 };
ImFontConfig icons_config{}; icons_config.MergeMode = true; icons_config.PixelSnapH = true;
ImFont* UIFont = io.Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/MaterialIcons-Regular.ttf", 20.f, &icons_config, icon_ranges); //TODO: Change to config based assets path
io.Fonts->Build();
}
void SHEditor::Exit()
{
ImGui_ImplVulkan_Shutdown();
@ -94,19 +152,164 @@ namespace SHADE
ImGui::DestroyContext();
}
void SHEditor::InitBackend()
void SHEditor::SetStyle(Style style)
{
switch (style)
{
default:
case Style::SHADE:
{
ImGuiStyle& imStyle = ImGui::GetStyle();
ImVec4* colors = imStyle.Colors;
colors[ImGuiCol_Text] = ImVec4(0.706f, 0.729f, 0.757f, 1.00f);
colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
colors[ImGuiCol_WindowBg] = ImVec4(0.172f, 0.184f, 0.203f, 1.f);
colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_PopupBg] = ImVec4(0.19f, 0.19f, 0.19f, 0.92f);
colors[ImGuiCol_Border] = ImVec4(0.19f, 0.19f, 0.19f, 0.29f);
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.24f);
colors[ImGuiCol_FrameBg] = ImVec4(0.05f, 0.05f, 0.05f, 0.54f);
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.19f, 0.19f, 0.19f, 0.54f);
colors[ImGuiCol_FrameBgActive] = ImVec4(0.20f, 0.22f, 0.23f, 1.00f);
colors[ImGuiCol_TitleBg] = colors[ImGuiCol_WindowBg];
colors[ImGuiCol_TitleBgActive] = colors[ImGuiCol_WindowBg];
colors[ImGuiCol_TitleBgCollapsed] = colors[ImGuiCol_WindowBg];
colors[ImGuiCol_MenuBarBg] = ImVec4(0.129f, 0.141f, 0.157f, 1.f);
colors[ImGuiCol_ScrollbarBg] = colors[ImGuiCol_WindowBg];
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.34f, 0.34f, 0.34f, 0.54f);
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.40f, 0.54f);
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.56f, 0.56f, 0.56f, 0.54f);
colors[ImGuiCol_CheckMark] = ImVec4(0.627f, 0.239f, 0.761f, 1.00f);
colors[ImGuiCol_SliderGrab] = ImVec4(0.34f, 0.34f, 0.34f, 0.54f);
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.56f, 0.56f, 0.56f, 0.54f);
colors[ImGuiCol_Button] = ImVec4(0.05f, 0.05f, 0.05f, 0.54f);
colors[ImGuiCol_ButtonHovered] = ImVec4(0.15f, 0.15f, 0.15f, 0.54f);
colors[ImGuiCol_ButtonActive] = ImVec4(0.20f, 0.22f, 0.23f, 1.00f);
colors[ImGuiCol_Header] = ImVec4(0.00f, 0.00f, 0.00f, 0.52f);
colors[ImGuiCol_HeaderHovered] = ImVec4(0.00f, 0.00f, 0.00f, 0.36f);
colors[ImGuiCol_HeaderActive] = ImVec4(0.20f, 0.22f, 0.23f, 0.33f);
colors[ImGuiCol_Separator] = colors[ImGuiCol_MenuBarBg];
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.44f, 0.44f, 0.44f, 0.29f);
colors[ImGuiCol_SeparatorActive] = ImVec4(0.40f, 0.44f, 0.47f, 1.00f);
colors[ImGuiCol_ResizeGrip] = ImVec4(0.28f, 0.28f, 0.28f, 0.29f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.44f, 0.44f, 0.44f, 0.29f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.40f, 0.44f, 0.47f, 1.00f);
colors[ImGuiCol_Tab] = colors[ImGuiCol_WindowBg];
colors[ImGuiCol_TabHovered] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
colors[ImGuiCol_TabActive] = ImVec4(0.14f, 0.14f, 0.14f, 0.8f);
colors[ImGuiCol_TabUnfocused] = colors[ImGuiCol_WindowBg];
colors[ImGuiCol_TabUnfocusedActive] = colors[ImGuiCol_WindowBg];
colors[ImGuiCol_DockingPreview] = ImVec4(0.627f, 0.239f, 0.761f, 1.00f);
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.855f, 0.6f, 0.941f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
colors[ImGuiCol_PlotHistogram] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
colors[ImGuiCol_TableHeaderBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.52f);
colors[ImGuiCol_TableBorderStrong] = ImVec4(0.00f, 0.00f, 0.00f, 0.52f);
colors[ImGuiCol_TableBorderLight] = ImVec4(0.28f, 0.28f, 0.28f, 0.29f);
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f);
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.20f, 0.22f, 0.23f, 1.00f);
colors[ImGuiCol_DragDropTarget] = ImVec4(0.33f, 0.67f, 0.86f, 1.00f);
colors[ImGuiCol_NavHighlight] = ImVec4(0.73f, 0.73f, 0.73f, 0.7f);
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.141f, 0.141f, 0.141f, 0.70f);
colors[ImGuiCol_NavWindowingDimBg] = colors[ImGuiCol_NavHighlight];
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.2f, 0.2f, 0.2f, 0.65f);
imStyle.WindowPadding = ImVec2(8.00f, 8.00f);
imStyle.FramePadding = ImVec2(5.00f, 2.00f);
imStyle.CellPadding = ImVec2(6.00f, 8.00f);
imStyle.ItemSpacing = ImVec2(6.00f, 6.00f);
imStyle.ItemInnerSpacing = ImVec2(6.00f, 6.00f);
imStyle.TouchExtraPadding = ImVec2(0.00f, 0.00f);
imStyle.IndentSpacing = 25;
imStyle.ScrollbarSize = 15;
imStyle.GrabMinSize = 10;
imStyle.WindowBorderSize = 0.6f;
imStyle.ChildBorderSize = 1;
imStyle.PopupBorderSize = 1;
imStyle.FrameBorderSize = 1;
imStyle.TabBorderSize = 1;
imStyle.WindowRounding = 7;
imStyle.ChildRounding = 4;
imStyle.FrameRounding = 3;
imStyle.PopupRounding = 4;
imStyle.ScrollbarRounding = 9;
imStyle.GrabRounding = 3;
imStyle.LogSliderDeadzone = 4;
imStyle.TabRounding = 4;
imStyle.WindowMenuButtonPosition = ImGuiDir_None;
}
break;
case Style::DARK: ImGui::StyleColorsDark(); break;
case Style::LIGHT: ImGui::StyleColorsLight(); break;
case Style::CLASSIC: ImGui::StyleColorsClassic(); break;
}
}
//#==============================================================#
//|| Private Member Functions ||
//#==============================================================#
void SHEditor::InitBackend(SDL_Window* sdlWindow)
{
if(ImGui_ImplSDL2_InitForVulkan(sdlWindow) == false)
{
SHLOG_CRITICAL("Editor backend initialisation; Failed to perform SDL initialisation for Vulkan")
}
const auto* gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
ImGui_ImplVulkan_InitInfo initInfo{};
initInfo.Instance = SHVkInstance::GetVkInstance();
initInfo.PhysicalDevice = gfxSystem->GetPhysicalDevice()->GetVkPhysicalDevice();
initInfo.Device = gfxSystem->GetDevice()->GetVkLogicalDevice();
initInfo.Queue = gfxSystem->GetQueue()->GetVkQueue();
initInfo.DescriptorPool = gfxSystem->GetDescriptorPool()->GetVkHandle();
initInfo.MinImageCount = initInfo.ImageCount = gfxSystem->GetSwapchain()->GetNumImages();
initInfo.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
imguiCommandPool = gfxSystem->GetDevice()->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true);
imguiCommandBuffer = imguiCommandPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers();
SHASSERT(!renderers.empty(), "No Renderers available")
auto renderGraph = renderers[0]->GetRenderGraph();
auto renderPass = renderGraph->GetNode("ImGui Node")->GetRenderpass();
if(ImGui_ImplVulkan_Init(&initInfo, renderPass->GetVkRenderpass()) == false)
{
SHLOG_CRITICAL("Editor backend initialisation; Failed to initialise Vulkan backend")
}
imguiCommandBuffer->BeginRecording();
if(ImGui_ImplVulkan_CreateFontsTexture(imguiCommandBuffer->GetVkCommandBuffer()) == false)
{
SHLOG_CRITICAL("Editor backend initialisation; Failed to create fonts texture for Vulkan backend")
}
imguiCommandBuffer->EndRecording();
gfxSystem->GetQueue()->SubmitCommandBuffer({ imguiCommandBuffer }, {}, {}, vk::PipelineStageFlagBits::eNone, {});
ImGui_ImplVulkan_DestroyFontUploadObjects();
renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle<SHVkCommandBuffer>& cmd) {
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer());
});
}
void SHEditor::NewFrame()
{
SDL_Event event;
while (SDL_PollEvent(&event) != 0)
{
ImGui_ImplSDL2_ProcessEvent(&event);
}
ImGui_ImplVulkan_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
}
void SHEditor::EndFrame()
{
}
}
}//namespace SHADE

View File

@ -1,29 +0,0 @@
#pragma once
#include "SH_API.h"
#include <SDL.h>
#include "Resource/Handle.h"
namespace SHADE
{
class SHVkCommandBuffer;
class SHVkCommandPool;
class SH_API SHEditor
{
public:
static void Initialise(SDL_Window* sdlWindow);
static void PreRender();
static void Render();
static void Exit();
private:
static void InitBackend();
static void NewFrame();
static void EndFrame();
static Handle<SHVkCommandPool> imguiCommandPool;
static Handle<SHVkCommandBuffer> imguiCommandBuffer;
};
}

View File

@ -0,0 +1,168 @@
#pragma once
//#==============================================================#
//|| STL Includes ||
//#==============================================================#
#include <vector>
#include <unordered_map>
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "SH_API.h"
#include "ECS_Base/SHECSMacros.h"
#include "Resource/Handle.h"
#include "EditorWindow/SHEditorWindow.h"
#include "Tools/SHLogger.h"
//#==============================================================#
//|| Library Includes ||
//#==============================================================#
#include <SDL_video.h>
namespace SHADE
{
//#==============================================================#
//|| Forward Declarations ||
//#==============================================================#
class SHVkCommandBuffer;
class SHVkCommandPool;
/**
* @brief SHEditor static class contains editor variables and implementation of editor functions.
*
*/
class SH_API SHEditor
{
public:
//#==============================================================#
//|| Type Aliases ||
//#==============================================================#
using EditorWindowID = uint8_t;
using EditorWindowPtr = std::unique_ptr<SHEditorWindow>;
using EditorWindowMap = std::unordered_map<EditorWindowID, EditorWindowPtr>;
/**
* @brief Style options
*
*/
enum class Style : uint8_t
{
SHADE,
DARK,
LIGHT,
CLASSIC
};
/**
* @brief Initialise the editor
*
* @param sdlWindow pointer to SDL_Window object created in application
*/
static void Initialise(SDL_Window* sdlWindow);
/**
* @brief Update the editor and add to ImGui DrawList
*
* @param dt Delta-time of the frame
*/
static void Update(float dt);
/**
* @brief Safely shutdown the editor
*
*/
static void Exit();
/**
* @brief Set the Style for the editor
*
* @param style Desired style
*/
static void SetStyle(Style style);
/**
* @brief Get ID for the Editor Window Type
*
* @tparam T Type of Editor Window
* @return EditorWindowID ID of Editor Window Type
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static EditorWindowID GetEditorWindowID()
{
static EditorWindowID id;
static bool idCreated = false;
if (!idCreated)
{
id = windowCount++;
idCreated = true;
}
return id;
}
/**
* @brief Get pointer to the Editor Window
*
* @tparam T Type of editor window to retrieve
* @return T* Pointer to the editor window
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static T* GetEditorWindow()
{
return reinterpret_cast<T*>(editorWindows[GetEditorWindowID<T>()].get());
}
// List of selected entities
static std::vector<EntityID> selectedEntities;
private:
/**
* @brief Initialise Backend for ImGui (SDL and Vulkan backend)
*
* @param sdlWindow Pointer to SDL_Window
*/
static void InitBackend(SDL_Window* sdlWindow);
/**
* @brief Start new frame for editor
*
*/
static void NewFrame();
/**
* @brief Perform ImGui and ImGui Backend Render
*
*/
static void Render();
/**
* @brief Create an Editor Window
*
* @tparam T Type of Editor Window to create
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static void CreateEditorWindow()
{
static bool isCreated = false;
if (!isCreated)
{
editorWindows[GetEditorWindowID<T>()] = std::make_unique<T>();
isCreated = true;
}
else
{
SHLOG_WARNING("Attempt to create duplicate of Editor window type")
}
}
static void InitFonts() noexcept;
// Handle to command pool used for ImGui Vulkan Backend
static Handle<SHVkCommandPool> imguiCommandPool;
// Handle to command buffer used for ImGui Vulkan Backend
static Handle<SHVkCommandBuffer> imguiCommandBuffer;
// Number of windows; used for Editor Window ID Generation
static EditorWindowID windowCount;
// Map of Editor Windows
static EditorWindowMap editorWindows;
};//class SHEditor
}//namespace SHADE

View File

@ -0,0 +1,187 @@
#pragma once
//#==============================================================#
//|| STL Includes ||
//#==============================================================#
#include <functional>
#include <string>
#include <iterator>
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "Math/SHMath.h"
#include "Command/SHCommandManager.h"
#include "SHImGuiHelpers.hpp"
//#==============================================================#
//|| Library Includes ||
//#==============================================================#
#include <imgui.h>
#include <imgui_internal.h>
#include <misc/cpp/imgui_stdlib.h>
#include <rttr/type.h>
namespace SHADE
{
//#==============================================================#
//|| Custom Widgets ||
//#==============================================================#
static bool Splitter(bool verticalSplit, float thickness, float* size1, float* size2, float minSize1, float minSize2, float splitterAxisSize = -1.0f)
{
ImGuiWindow* window = ImGui::GetCurrentWindow();
const ImGuiID id = window->GetID("##Splitter");
ImRect bb;
bb.Min = window->DC.CursorPos + (verticalSplit ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1));
bb.Max = bb.Min + (verticalSplit ? ImVec2(thickness, splitterAxisSize) : ImVec2(splitterAxisSize, thickness));
return ImGui::SplitterBehavior(bb, id, verticalSplit ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, minSize1, minSize2, 0.0f);
}
template <typename T, std::size_t N>
static bool DragN(const std::string& fieldLabel, std::vector<std::string>const& componentLabels,
std::vector<T*> values, float speed = 0.1f, const char* displayFormat = "", T valueMin = T(), T valueMax = T(),
ImGuiSliderFlags flags = 0)
{
const ImGuiWindow* const window = ImGui::GetCurrentWindow();
if (window->SkipItems)
return false;
const ImGuiContext& g = *GImGui;
bool valueChanged = false;
ImGui::BeginGroup();
ImGui::PushID(fieldLabel.c_str());
PushMultiItemsWidthsAndLabels(componentLabels, 0.0f);
ImGui::BeginColumns("DragVecCol", 2, ImGuiOldColumnFlags_NoBorder | ImGuiOldColumnFlags_NoResize);
ImGui::SetColumnWidth(-1, 80.0f);
ImGui::Text(fieldLabel.c_str());
ImGui::NextColumn();
for (std::size_t i = 0; i < N; ++i)
{
ImGui::PushID(static_cast<int>(i));
ImGui::TextUnformatted(componentLabels[i].c_str(), ImGui::FindRenderedTextEnd(componentLabels[i].c_str())); ImGui::SameLine();
ImGui::SetNextItemWidth(80.0f);
valueChanged |= ImGui::DragFloat("##v", values[i], speed, valueMin, valueMax, displayFormat, flags);
const ImVec2 min = ImGui::GetItemRectMin();
const ImVec2 max = ImGui::GetItemRectMax();
const float spacing = g.Style.FrameRounding;
const float halfSpacing = spacing / 2;
window->DrawList->AddLine({ min.x + spacing, max.y - halfSpacing }, { max.x - spacing, max.y - halfSpacing },
ImGuiColors::colors[i], 4);
ImGui::SameLine(0, g.Style.ItemInnerSpacing.x);
ImGui::PopID();
ImGui::PopItemWidth();
}
ImGui::EndColumns();
ImGui::PopID();
ImGui::EndGroup();
return valueChanged;
}
static bool DragVec2(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec2(void)> get,
std::function<void(SHVec2)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
ImGuiSliderFlags flags = 0)
{
SHVec2 values = get();
bool changed = false;
if (DragN<float, 2>(fieldLabel, componentLabels, {&values.x, &values.y}, speed, displayFormat, valueMin, valueMax, flags))
{
changed = true;
}
if (changed)
{
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false);
else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), true);
else if(ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false);
}
return changed;
}
static bool DragVec3(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec3(void)> get,
std::function<void(SHVec3)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
ImGuiSliderFlags flags = 0)
{
SHVec3 values = get();
bool changed = false;
if (DragN<float, 3>(fieldLabel, componentLabels, {&values.x, &values.y, &values.z}, speed, displayFormat, valueMin, valueMax, flags))
{
changed = true;
}
if (changed)
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false);
else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), true);
else if(ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false);
}
return changed;
}
static bool DragVec4(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec4(void)> get,
std::function<void(SHVec4)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
ImGuiSliderFlags flags = 0)
{
SHVec4 values = get();
bool changed = false;
if (DragN<float, 4>(fieldLabel, componentLabels, {&values.x, &values.y, &values.z, &values.w}, speed, displayFormat, valueMin, valueMax, flags))
{
changed = true;
}
if (changed)
{
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), false);
else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left))
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), true);
else if(ImGui::IsItemDeactivatedAfterEdit())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), false);
}
return changed;
}
//#==============================================================#
//|| Widget Extensions ||
//#==============================================================#
static bool CheckBox(std::string const& label, std::function<bool(void)> get, std::function<void(bool const&)> set)
{
bool value = get();
if (ImGui::Checkbox(label.c_str(), &value))
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<bool>>(get(), value, set)), false);
return true;
}
return false;
}
template<typename T>
static bool RadioButton(std::vector<std::string> const& listLabels, std::vector<T> const& listTypes, std::function<T(void)> get, std::function<void(T const&)> set)
{
T type = get();
for (size_t i = 0; i < listTypes.size(); i++)
{
if (ImGui::RadioButton(listLabels[i].c_str(), type == listTypes[i]))
{
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), listTypes[i], set)), false);
}
ImGui::SameLine();
}
return true;
}
}//namespace SHADE

View File

@ -0,0 +1,69 @@
#pragma once
//#==============================================================#
//|| STL Includes ||
//#==============================================================#
#include <string>
//#==============================================================#
//|| SHADE Includes ||
//#==============================================================#
#include "Math/SHMath.h"
//#==============================================================#
//|| SHADE-ImGui Math Conversions ||
//#==============================================================#
#ifndef SH_IM_MATH
#define IM_VEC2_CLASS_EXTRA \
ImVec2(const SHADE::SHVec2& vec) {x = vec.x; y = vec.y;} \
operator SHADE::SHVec2() const {return SHADE::SHVec2(x,y);}
#define IM_VEC3_CLASS_EXTRA \
ImVec3(const SHADE::SHVec3& vec) {x = vec.x; y = vec.y; z = vec.z;} \
operator SHADE::SHVec3() const {return SHADE::SHVec3(x,y,z);}
#define IM_VEC4_CLASS_EXTRA \
ImVec4(const SHADE::SHVec4& vec) {x = vec.x; y = vec.y; z = vec.z; w = vec.w;} \
operator SHADE::SHVec4() const {return SHADE::SHVec4(x,y,z,w);}
#endif
#define IMGUI_DEFINE_MATH_OPERATORS
//#==============================================================#
//|| Library Includes ||
//#==============================================================#
#include <imgui_internal.h>
#include <imgui.h>
namespace SHADE
{
namespace ImGuiColors
{
constexpr ImVec4 red = {1.0f, 0.0f, 0.0f, 1.f};
constexpr ImVec4 green = {0.0f, 1.0f, 0.0f, 1.f};
constexpr ImVec4 blue = {0.0f, 0.0f, 1.0f, 1.f};
constexpr ImVec4 white = {1.0f, 1.0f, 1.0f, 1.f};
constexpr ImU32 colors[] = {
0xBB0000FF, // red
0xBB00FF00, // green
0xBBFF0000, // blue
0xBBFFFFFF, // white
};
}
static void PushMultiItemsWidthsAndLabels(const std::vector<std::string>& labels, float wFull)
{
ImGuiWindow* window = ImGui::GetCurrentWindow();
const ImGuiStyle& style = GImGui->Style;
if (wFull <= 0.0f)
wFull = ImGui::GetContentRegionAvail().x;
const auto size = labels.size();
const float w_item_one =
ImMax(1.0f, (wFull - (static_cast<float>(size) - 1.0f) * (style.ItemInnerSpacing.x * 2.0f)) / static_cast<float>(
size)) -
style.ItemInnerSpacing.x;
for (int i = 0; i < size; i++)
window->DC.ItemWidthStack.push_back(w_item_one - ImGui::CalcTextSize(labels[i].c_str()).x);
window->DC.ItemWidth = window->DC.ItemWidthStack.back();
}
} //namespace SHADE

View File

@ -155,7 +155,7 @@ namespace SHADE
*/
/***************************************************************************/
void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<std::pair<Handle<SHVkImageView>, Handle<SHVkSampler>>> const& imageViewsAndSamplers) noexcept
void SHVkDescriptorSetGroup::ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept
{
// Find the target writeDescSet
BindingAndSetHash writeHash = binding;
@ -170,9 +170,10 @@ namespace SHADE
for (uint32_t i = 0; i < imageViewsAndSamplers.size(); ++i)
{
// write sampler and image view
auto& ivs = imageViewsAndSamplers[i];
writeInfo.descImageInfos[i].imageView = ivs.first->GetImageView();
writeInfo.descImageInfos[i].sampler = ivs.second->GetVkSampler();
auto& [view, sampler, layout] = imageViewsAndSamplers[i];
writeInfo.descImageInfos[i].imageView = view->GetImageView();
writeInfo.descImageInfos[i].sampler = sampler->GetVkSampler();
writeInfo.descImageInfos[i].imageLayout = layout;
}
}

View File

@ -1,5 +1,7 @@
#pragma once
#include <tuple>
// Project Includes
#include "Graphics/SHVulkanIncludes.h"
#include "Resource/Handle.h"
@ -63,7 +65,7 @@ namespace SHADE
void UpdateDescriptorSetImages(uint32_t set, uint32_t binding) noexcept;
void UpdateDescriptorSetBuffer(uint32_t set, uint32_t binding) noexcept;
void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<std::pair<Handle<SHVkImageView>, Handle<SHVkSampler>>> const& imageViewsAndSamplers) noexcept;
void ModifyWriteDescImage(uint32_t set, uint32_t binding, std::span<std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout>> const& imageViewsAndSamplers) noexcept;
void ModifyWriteDescBuffer (uint32_t set, uint32_t binding, std::span<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept;

View File

@ -16,6 +16,7 @@
#include "Graphics/Framebuffer/SHVkFramebuffer.h"
#include "Graphics/Images/SHVkImageView.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/Images/SHVkSampler.h"
namespace SHADE
{
@ -85,6 +86,17 @@ namespace SHADE
}
uint32_t SHVkLogicalDevice::ComputeAlignedBufferSize(uint32_t originalSize, size_t alignmentSize) const noexcept
{
uint32_t alignedSize = originalSize;
//uint32_t minBuffer
if (alignmentSize > 0)
{
alignedSize = (alignedSize + alignmentSize - 1) & ~(alignmentSize - 1);
}
return alignedSize;
}
/***************************************************************************/
/*!
@ -288,13 +300,12 @@ namespace SHADE
uint32_t SHVkLogicalDevice::PadUBOSize(uint32_t originalSize) const noexcept
{
uint32_t alignedSize = originalSize;
//uint32_t minBuffer
if (uboBufferMemoryAlignment > 0)
{
alignedSize = (alignedSize + uboBufferMemoryAlignment - 1) & ~(uboBufferMemoryAlignment - 1);
}
return alignedSize;
return ComputeAlignedBufferSize(originalSize, uboBufferMemoryAlignment);
}
uint32_t SHVkLogicalDevice::PadSSBOSize(uint32_t originalSize) const noexcept
{
return ComputeAlignedBufferSize(originalSize, ssboBufferMemoryAlignment);
}
/***************************************************************************/
@ -499,6 +510,11 @@ namespace SHADE
}
Handle<SHVkSampler> SHVkLogicalDevice::CreateSampler(const SHVkSamplerParams& params) noexcept
{
return SHVkInstance::GetResourceManager().Create <SHVkSampler>(GetHandle(), params);
}
Handle<SHVkRenderpass> SHVkLogicalDevice::CreateRenderpass(std::span<vk::AttachmentDescription> const vkDescriptions, std::vector<SHVkSubpassParams> const& subpasses) noexcept
{
return SHVkInstance::GetResourceManager().Create <SHVkRenderpass>(GetHandle(), vkDescriptions, subpasses);

View File

@ -21,7 +21,6 @@
#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
#include "Graphics/Images/SHVkImage.h"
namespace SHADE
{
/*-----------------------------------------------------------------------*/
@ -41,6 +40,8 @@ namespace SHADE
class SHShaderBlockInterface;
class SHVkDescriptorSetGroup;
class SHSubpass;
class SHVkSampler;
struct SHVkSamplerParams;
/***************************************************************************/
/*!
@ -102,6 +103,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
void InitializeVMA (void) noexcept;
void InitializeQueues (std::initializer_list<SHQueueParams> queueCreateParams) noexcept;
uint32_t ComputeAlignedBufferSize(uint32_t originalSize, size_t typeSize) const noexcept;
public:
/*-----------------------------------------------------------------------*/
@ -121,7 +123,8 @@ namespace SHADE
// Miscellaneous functions
void WaitIdle (void) noexcept;
uint32_t FindMemoryType (uint32_t typeFilter, vk::MemoryPropertyFlags properties);
uint32_t PadUBOSize (uint32_t originalSize) const noexcept;
uint32_t PadUBOSize(uint32_t originalSize) const noexcept;
uint32_t PadSSBOSize(uint32_t originalSize) const noexcept;
// creation functions
Handle<SHVkSurface> CreateSurface (HWND const& windowHandle) const noexcept;
@ -178,6 +181,7 @@ namespace SHADE
Handle<SHVkRenderpass> const& renderpassHdl,
Handle<SHSubpass> subpass
) noexcept;
Handle<SHVkSampler> CreateSampler (const SHVkSamplerParams& params) noexcept;
Handle<SHVkRenderpass> CreateRenderpass (std::span<vk::AttachmentDescription> const vkDescriptions, std::vector<SHVkSubpassParams> const& subpasses) noexcept;
Handle<SHVkRenderpass> CreateRenderpass (std::span<vk::AttachmentDescription> const vkDescriptions, std::span<vk::SubpassDescription> const spDescs, std::span<vk::SubpassDependency> const spDeps) noexcept;

View File

@ -26,7 +26,7 @@ namespace SHADE
*/
/***************************************************************************/
void SHVkImage::PrepStagingBuffer(void* data, uint32_t srcSize) noexcept
void SHVkImage::PrepStagingBuffer(const void* data, uint32_t srcSize) noexcept
{
// For creation of buffer
vk::BufferCreateInfo bufferInfo{};
@ -70,7 +70,7 @@ namespace SHADE
vmaMapMemory(*vmaAllocator, stagingAlloc, &stagingBufferMappedPtr);
if (stagingBufferMappedPtr)
std::memcpy(static_cast<uint8_t*>(stagingBufferMappedPtr), static_cast<uint8_t*>(data), srcSize);
std::memcpy(static_cast<uint8_t*>(stagingBufferMappedPtr), static_cast<const uint8_t*>(data), srcSize);
const VkDeviceSize offsets = 0;
const VkDeviceSize sizes = srcSize;
@ -82,7 +82,7 @@ namespace SHADE
SHVkImage::SHVkImage(
VmaAllocator const* allocator,
SHImageCreateParams const& imageDetails,
unsigned char* data,
const unsigned char* data,
uint32_t dataSize,
std::span<uint32_t> inMipOffsets,
VmaMemoryUsage memUsage,

View File

@ -107,7 +107,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void PrepStagingBuffer(void* data, uint32_t srcSize) noexcept;
void PrepStagingBuffer(const void* data, uint32_t srcSize) noexcept;
public:
@ -119,7 +119,7 @@ namespace SHADE
SHVkImage(
VmaAllocator const* allocator,
SHImageCreateParams const& imageDetails,
unsigned char* data,
const unsigned char* data,
uint32_t dataSize,
std::span<uint32_t> inMipOffsets,
VmaMemoryUsage memUsage,

View File

@ -1,12 +1,62 @@
/************************************************************************************//*!
\file SHVkSampler.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Sep 26, 2022
\brief Contains definitions for all of the functions of the SHVkSampler 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"
#include "SHVkSampler.h"
#include "Graphics/Devices/SHVkLogicalDevice.h"
namespace SHADE
{
vk::Sampler SHVkSampler::GetVkSampler(void) const noexcept
/*-----------------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------------*/
SHVkSampler::SHVkSampler(Handle<SHVkLogicalDevice> logicalDevice, const SHVkSamplerParams& params) noexcept
: device { logicalDevice }
{
return vkSampler;
const vk::SamplerCreateInfo SAMPLER_CREATE_INFO
{
.magFilter = params.magFilter,
.minFilter = params.minFilter,
.mipmapMode = params.mipmapMode,
.addressModeU = params.addressMode,
.addressModeV = params.addressMode,
.addressModeW = params.addressMode,
.minLod = params.minLod,
.maxLod = params.maxLod
};
// Create the sampler
vkSampler = device->GetVkLogicalDevice().createSampler(SAMPLER_CREATE_INFO);
}
SHVkSampler::SHVkSampler(SHVkSampler&& rhs) noexcept
: vkSampler { rhs.vkSampler }
{
rhs.vkSampler = nullptr;
}
SHVkSampler::~SHVkSampler() noexcept
{
if (vkSampler)
device->GetVkLogicalDevice().destroySampler();
}
/*-----------------------------------------------------------------------------------*/
/* Overloaded Operators */
/*-----------------------------------------------------------------------------------*/
SHADE::SHVkSampler& SHVkSampler::operator=(SHVkSampler&& rhs) noexcept
{
vkSampler = rhs.vkSampler;
rhs.vkSampler = nullptr;
return *this;
}
}

View File

@ -1,28 +1,80 @@
/************************************************************************************//*!
\file SHVkSampler.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Sep 26, 2022
\brief Contains definitions of the SHVkSampler 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 <vector>
// Project Includes
#include "Graphics/SHVulkanIncludes.h"
#include "Resource/Handle.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHVkLogicalDevice;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/*************************************************************************************/
/*!
\brief
Holds parameters for constructing the SHVkSampler.
*/
/*************************************************************************************/
struct SHVkSamplerParams
{
vk::Filter minFilter;
vk::Filter maxFilter;
//vk::Filter maxFilter;
vk::Filter minFilter = vk::Filter::eLinear;
vk::Filter magFilter = vk::Filter::eLinear;
vk::SamplerAddressMode addressMode = vk::SamplerAddressMode::eClampToEdge;
vk::SamplerMipmapMode mipmapMode = vk::SamplerMipmapMode::eLinear;
float minLod = 0;
float maxLod = 0;
};
/*************************************************************************************/
/*!
\brief
Wrapper for a VkSampler.
*/
/*************************************************************************************/
class SHVkSampler
{
private:
//! The vulkan sampler handler
vk::Sampler vkSampler;
public:
SHVkSampler () noexcept;
SHVkSampler (SHVkSampler&& rhs) noexcept;
SHVkSampler&& operator=(SHVkSampler&& rhs) noexcept;
public:
/*---------------------------------------------------------------------------------*/
/* Constructors */
/*---------------------------------------------------------------------------------*/
SHVkSampler(Handle<SHVkLogicalDevice> logicalDevice, const SHVkSamplerParams& params = {}) noexcept;
SHVkSampler(SHVkSampler&& rhs) noexcept;
~SHVkSampler() noexcept;
vk::Sampler GetVkSampler (void) const noexcept;
/*---------------------------------------------------------------------------------*/
/* Overloaded Operators */
/*---------------------------------------------------------------------------------*/
SHVkSampler& operator=(SHVkSampler&& rhs) noexcept;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
vk::Sampler GetVkSampler(void) const noexcept { return vkSampler; }
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
vk::Sampler vkSampler; //! The Vulkan sampler handler
Handle<SHVkLogicalDevice> device; //! Stored device for deallocating the object
};
}

View File

@ -30,6 +30,8 @@ of DigiPen Institute of Technology is prohibited.
#include "SHGraphicsConstants.h"
#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h"
#include "Graphics/Buffers/SHVkBuffer.h"
#include "Graphics/Images/SHVkSampler.h"
#include "Assets/Asset Types/SHDDSAsset.h"
namespace SHADE
{
@ -91,8 +93,10 @@ namespace SHADE
descPool = device->CreateDescriptorPools();
// Create generic command buffer
transferCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::TRANSFER, SH_CMD_POOL_RESET::POOL_BASED, true);
transferCmdBuffer = transferCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
//transferCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true);
graphicsCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true);
transferCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
@ -135,11 +139,13 @@ namespace SHADE
//worldRenderGraph->AddResource("Position", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat);
//worldRenderGraph->AddResource("Normals", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat);
//worldRenderGraph->AddResource("Composite", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eR16G16B16A16Sfloat);
worldRenderGraph->AddResource("Scene", SH_ATT_DESC_TYPE::COLOR, windowDims.first, windowDims.second, vk::Format::eB8G8R8A8Unorm);
worldRenderGraph->AddResource("Present", SH_ATT_DESC_TYPE::COLOR_PRESENT, windowDims.first, windowDims.second);
auto node = worldRenderGraph->AddNode("G-Buffer", { /*"Composite", "Position", "Normals",*/ "Present" }, {}); // no predecessors
auto node = worldRenderGraph->AddNode("G-Buffer", { /*"Composite", "Position", */"Present" }, {}); // no predecessors
//First subpass to write to G-Buffer
auto gBufferWriteSubpass = node->AddSubpass("G-Buffer Write");
//gBufferWriteSubpass->AddColorOutput("Scene");
gBufferWriteSubpass->AddColorOutput("Present");
//writeSubpass->AddColorOutput("Normals");
@ -222,6 +228,9 @@ namespace SHADE
renderContext.ResetFence();
// Bind textures
// For every viewport
for (int vpIndex = 0; vpIndex < static_cast<int>(viewports.size()); ++vpIndex)
{
@ -250,6 +259,17 @@ namespace SHADE
currentCmdBuffer->BindIndexBuffer(buffer, 0);
}
std::array<uint32_t, 1> texDynamicOffset {0};
// Bind textures
currentCmdBuffer->BindDescriptorSet
(
texLibrary.GetTextureDescriptorSetGroup(),
vk::PipelineBindPoint::eGraphics,
0,
std::span<uint32_t, 1>{texDynamicOffset.data(), texDynamicOffset.size()}
);
// bind camera data
renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
@ -453,9 +473,38 @@ namespace SHADE
transferCmdBuffer->BeginRecording();
meshLibrary.BuildBuffers(device, transferCmdBuffer);
transferCmdBuffer->EndRecording();
transferQueue->SubmitCommandBuffer({ transferCmdBuffer });
graphicsQueue->SubmitCommandBuffer({ transferCmdBuffer });
}
/*---------------------------------------------------------------------------------*/
/* Texture Registration Functions */
/*---------------------------------------------------------------------------------*/
Handle<SHTexture> SHGraphicsSystem::Add(const SHDDSAsset& ddsAsset)
{
auto sampler = samplerCache.GetSampler(device, SHVkSamplerParams { .maxLod = static_cast<float>(ddsAsset.image.GetMipCount()) });
return texLibrary.Add(ddsAsset, 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)
{
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)
{
texLibrary.Remove(tex);
}
void SHGraphicsSystem::BuildTextures()
{
texLibrary.BuildTextures
(
device, graphicsTexCmdBuffer, graphicsQueue, descPool,
globalData->GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS]
);
}
void SHGraphicsSystem::SetWindow(SHWindow* wind) noexcept
{
window = wind;

View File

@ -29,6 +29,8 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/MiddleEnd/Shaders/SHShaderModuleLibrary.h"
#include "SHMeshLibrary.h"
#include "Graphics/MiddleEnd/Materials/SHMaterialInstanceCache.h"
#include "../Textures/SHTextureLibrary.h"
#include "../Textures/SHVkSamplerCache.h"
namespace SHADE
{
@ -188,6 +190,62 @@ namespace SHADE
/***************************************************************************/
void BuildMeshBuffers();
/*-----------------------------------------------------------------------------*/
/* Texture Registration Functions */
/*-----------------------------------------------------------------------------*/
/*******************************************************************************/
/*!
\brief
Adds a texture to the Texture Library. But this does not mean that the
textures have been added yet. A call to "BuildTextures()" is required to
transfer all textures into the GPU.
\param pixelCount
Number of pixels in this Mesh.
\param positions
Pointer to the first in a contiguous array of SHMathVec3s that define vertex
positions.
\param format
Format of the texture loaded in.
\return
Handle to the created Texture. This is not valid to be used until a call to
BuildImages().
*/
/*******************************************************************************/
Handle<SHTexture> Add(const SHDDSAsset& ddsAsset);
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);
/*******************************************************************************/
/*!
\brief
Removes a mesh from the Texture Library. But this does not mean that the
textures have been removed yet. A call to "BuildTextures()" is required to
finalise all changes.
\param mesh
Handle to the Texture to remove.
*/
/*******************************************************************************/
void Remove(Handle<SHTexture> tex);
/***************************************************************************/
/*!
\brief
Finalises all changes to the Texture Library into the GPU buffers.
\param cmdBuffer
Command buffer used to set up transfers of data in the GPU memory. This
call must be preceded by calls to cmdBuffer's BeginRecording() and ended
with EndRecording(). Do recall to also submit the cmdBuffer to a transfer
queue.
*/
/***************************************************************************/
void BuildTextures();
/*-----------------------------------------------------------------------------*/
/* Setters */
/*-----------------------------------------------------------------------------*/
@ -202,6 +260,7 @@ namespace SHADE
Handle<SHVkPhysicalDevice> GetPhysicalDevice() const { return physicalDevice; }
Handle<SHVkQueue> GetQueue() const { return graphicsQueue; }
Handle<SHVkDescriptorPool> GetDescriptorPool() const { return descPool; }
Handle<SHViewport> GetDefaultViewport() const {return defaultViewport;}
//SHRenderGraph const& GetRenderGraph(void) const noexcept;
//Handle<SHVkRenderpass> GetRenderPass() const { return renderPass; }
@ -219,8 +278,10 @@ namespace SHADE
Handle<SHVkQueue> graphicsQueue;
Handle<SHVkQueue> transferQueue;
Handle<SHVkDescriptorPool> descPool;
Handle<SHVkCommandPool> graphicsCmdPool;
Handle<SHVkCommandPool> transferCmdPool;
Handle<SHVkCommandBuffer> transferCmdBuffer;
Handle<SHVkCommandBuffer> graphicsTexCmdBuffer;
SHRenderContext renderContext;
std::array<Handle<SHVkSemaphore>, 2> graphSemaphores;
// Not Owned Resources
@ -232,6 +293,8 @@ namespace SHADE
// Middle End Resources
ResourceManager resourceManager;
SHMeshLibrary meshLibrary;
SHTextureLibrary texLibrary;
SHSamplerCache samplerCache;
SHMaterialInstanceCache materialInstanceCache;
// Viewports
Handle<SHViewport> defaultViewport; // Whole screen

View File

@ -20,18 +20,51 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/Commands/SHVkCommandBuffer.h"
#include "Graphics/SHVkUtil.h"
#include "Tools/SHLogger.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Assets/Asset Types/SHDDSAsset.h"
#include "Graphics/Images/SHVkImage.h"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Usage Functions */
/*---------------------------------------------------------------------------------*/
Handle<SHTexture> SHTextureLibrary::Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, SHTexture::TextureFormat format, uint32_t mipLevels)
Handle<SHTexture> SHTextureLibrary::Add(const SHDDSAsset& ddsAsset, Handle<SHVkSampler> sampler)
{
// Define constants
const uint32_t IMG_WIDTH = ddsAsset.image.GetWidth();
const uint32_t IMG_HEIGHT = ddsAsset.image.GetHeight();
const uint32_t MIPMAP_LEVEL = ddsAsset.image.GetMipCount();
// Compute total texture size and create buffer image copy objects
std::vector<uint32_t> mipOffsets(MIPMAP_LEVEL);
uint32_t texBytes = 0;
for (uint32_t i = 0; i < MIPMAP_LEVEL; i++)
{
mipOffsets[i] = texBytes;
// Get ready for next mip
texBytes += ddsAsset.image.GetImageData(i)->m_memSlicePitch;
}
return Add
(
texBytes,
reinterpret_cast<const SHTexture::PixelChannel*>(ddsAsset.image.m_dds.data()),
IMG_WIDTH, IMG_HEIGHT,
ddsLoaderToVkFormat(ddsAsset.image.GetFormat(), true),
mipOffsets,
sampler
);
}
Handle<SHTexture> SHTextureLibrary::Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, uint32_t width, uint32_t height, SHTexture::TextureFormat format, std::vector<uint32_t> mipOffsets, Handle<SHVkSampler> sampler)
{
isDirty = true;
auto handle = resourceManager.Create<SHTexture>();
addJobs.emplace_back(AddJob { pixelCount, pixelData, format, mipLevels });
addJobs.emplace_back(AddJob { pixelCount, pixelData, format, sampler, mipOffsets, width, height, handle });
return handle;
}
@ -44,22 +77,48 @@ namespace SHADE
isDirty = true;
}
void SHTextureLibrary::BuildImages(Handle<SHVkLogicalDevice> device, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkQueue> graphicsQueue, Handle<SHVkDescriptorPool> descPool, Handle<SHVkDescriptorSetLayout> descLayout)
void SHTextureLibrary::BuildTextures(Handle<SHVkLogicalDevice> device, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkQueue> graphicsQueue, Handle<SHVkDescriptorPool> descPool, Handle<SHVkDescriptorSetLayout> descLayout)
{
// Don't do anything if there are no updates
if (!isDirty)
return;
/* Remove Textures */
std::vector<vk::ImageMemoryBarrier> pipelineBarriers(addJobs.size());
// TODO
/* Add Textures */
// Transition
// Load Textures - Transitions
std::vector<vk::ImageMemoryBarrier> pipelineBarriers(addJobs.size());
for (int i = 0; auto& job : addJobs)
{
job.Image = resourceManager.Create<SHVkImage>();
job.Image = resourceManager.Create<SHVkImage>
(
&device->GetVMAAllocator(),
SHImageCreateParams
{
.imageType = vk::ImageType::e2D,
.width = job.Width,
.height = job.Height,
.depth = 1,
.levels = static_cast<uint8_t>(job.MipOffsets.size()),
.arrayLayers = 1,
.imageFormat = job.TextureFormat,
.usageFlags = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst,
.createFlags = {}
},
job.PixelData,
job.PixelCount,
job.MipOffsets,
VmaMemoryUsage::VMA_MEMORY_USAGE_AUTO,
VmaAllocationCreateFlagBits {}
);
job.Image->PrepareImageTransitionInfo(vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, pipelineBarriers[i]);
++i;
}
vk::PipelineStageFlagBits srcStage = vk::PipelineStageFlagBits::eTopOfPipe;
vk::PipelineStageFlagBits dstStage = vk::PipelineStageFlagBits::eTopOfPipe;
preparePipelineBarriers(vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, srcStage, dstStage, pipelineBarriers);
cmdBuffer->BeginRecording();
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, pipelineBarriers);
// Copy
@ -73,13 +132,16 @@ namespace SHADE
{
// Transition
job.Image->PrepareImageTransitionInfo(vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, pipelineBarriers[i]);
++i;
}
preparePipelineBarriers(vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, srcStage, dstStage, pipelineBarriers);
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, pipelineBarriers);
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, pipelineBarriers);
// Execute Commands
cmdBuffer->EndRecording();
graphicsQueue->SubmitCommandBuffer({ cmdBuffer });
device->WaitIdle();
graphicsQueue->GetVkQueue().waitIdle();
// Create Image View
for (auto& job : addJobs)
@ -90,16 +152,39 @@ namespace SHADE
.format = job.TextureFormat,
.imageAspectFlags = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.mipLevelCount = job.MipLevels,
.mipLevelCount = static_cast<uint32_t>(job.MipOffsets.size()),
.baseArrayLayer = 0,
.layerCount = 0
.layerCount = 1
};
job.Handle->ImageView = job.Image->CreateImageView(device, job.Image, DETAILS);
job.TextureHandle->ImageView = job.Image->CreateImageView(device, job.Image, DETAILS);
}
// Build Descriptor
Handle<SHVkDescriptorSetGroup> descSetGroup = descPool->Allocate({ descLayout }, { 1 });
// Add Textures
for (auto& job : addJobs)
{
texOrder.emplace_back(job.TextureHandle);
combinedImageSamplers.emplace_back(std::make_tuple(job.TextureHandle->ImageView, job.Sampler, vk::ImageLayout::eShaderReadOnlyOptimal));
job.TextureHandle->TextureArrayIndex = texOrder.size() - 1;
}
addJobs.clear();
/* Build Descriptor Set with all the Textures */
if (!texDescriptors)
{
texDescriptors = descPool->Allocate({ descLayout }, { static_cast<uint32_t>(texOrder.size()) });
}
const auto ALIGNED_SIZE = device->PadSSBOSize(sizeof(uint32_t));
texDescriptors->ModifyWriteDescImage
(
SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS,
SHGraphicsConstants::DescriptorSetBindings::IMAGE_AND_SAMPLERS_DATA,
combinedImageSamplers
);
texDescriptors->UpdateDescriptorSetImages
(
SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS,
SHGraphicsConstants::DescriptorSetBindings::IMAGE_AND_SAMPLERS_DATA
);
isDirty = false;
}
@ -139,4 +224,35 @@ namespace SHADE
}
}
vk::Format SHTextureLibrary::ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear)
{
switch (format)
{
case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm_SRGB:
return isLinear ? vk::Format::eBc1RgbaUnormBlock : vk::Format::eBc1RgbaSrgbBlock;
case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm_SRGB:
return isLinear ? vk::Format::eBc2UnormBlock : vk::Format::eBc2SrgbBlock;
case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm_SRGB:
return isLinear ? vk::Format::eBc3UnormBlock : vk::Format::eBc3SrgbBlock;
case tinyddsloader::DDSFile::DXGIFormat::BC5_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::BC5_SNorm:
return isLinear ? vk::Format::eBc5UnormBlock : vk::Format::eBc5SnormBlock;
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm_SRGB:
return isLinear ? vk::Format::eR8G8B8A8Unorm : vk::Format::eR8G8B8A8Srgb;
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_SNorm:
return vk::Format::eR8G8B8A8Snorm;
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm_SRGB:
return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8A8Srgb;
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm:
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8X8_UNorm_SRGB:
return isLinear ? vk::Format::eB8G8R8A8Unorm : vk::Format::eB8G8R8Srgb;
default:
throw std::runtime_error("Unsupported DDS format.");
}
}
}

View File

@ -14,6 +14,8 @@ of DigiPen Institute of Technology is prohibited.
// STL Includes
#include <vector>
// External Dependencies
#include "tinyddsloader.h"
// Project Includes
#include "Resource/Handle.h"
#include "Resource/ResourceLibrary.h"
@ -33,6 +35,9 @@ namespace SHADE
class SHVkQueue;
class SHVkDescriptorPool;
class SHVkDescriptorSetLayout;
class SHVkDescriptorSetGroup;
class SHVkSampler;
struct SHDDSAsset;
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
@ -43,7 +48,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------*/
using PixelChannel = float;
using PixelChannel = unsigned char;
using TextureFormat = vk::Format; // TODO: Change
using Index = uint32_t;
@ -71,7 +76,7 @@ namespace SHADE
\brief
Adds a texture to the Texture Library. But this does not mean that the
textures have been added yet. A call to "BuildImages()" is required to
textures have been added yet. A call to "BuildTextures()" is required to
transfer all textures into the GPU.
\param pixelCount
@ -88,13 +93,15 @@ namespace SHADE
*/
/*******************************************************************************/
Handle<SHTexture> Add(uint32_t pixelCount, const SHTexture::PixelChannel* const pixelData, SHTexture::TextureFormat format, uint32_t mipLevels);
Handle<SHTexture> Add(const SHDDSAsset& ddsAsset, Handle<SHVkSampler> sampler);
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<SHVkSampler> sampler);
/*******************************************************************************/
/*!
\brief
Removes a mesh from the Texture Library. But this does not mean that the
textures have been removed yet. A call to "BuildImages()" is required to
textures have been removed yet. A call to "BuildTextures()" is required to
finalise all changes.
\param mesh
@ -118,12 +125,12 @@ namespace SHADE
queue.
*/
/***************************************************************************/
void BuildImages(Handle<SHVkLogicalDevice> device, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkQueue> graphicsQueue, Handle<SHVkDescriptorPool> descPool, Handle<SHVkDescriptorSetLayout> descLayout);
void BuildTextures(Handle<SHVkLogicalDevice> device, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkQueue> graphicsQueue, Handle<SHVkDescriptorPool> descPool, Handle<SHVkDescriptorSetLayout> descLayout);
/*-----------------------------------------------------------------------------*/
/* Getter Functions */
/*-----------------------------------------------------------------------------*/
Handle<SHVkBuffer> GetTextureBuffer() const noexcept { return texStorageBuffer; }
Handle<SHVkDescriptorSetGroup> GetTextureDescriptorSetGroup() const noexcept { return texDescriptors; }
private:
/*-----------------------------------------------------------------------------*/
@ -134,9 +141,12 @@ namespace SHADE
uint32_t PixelCount = 0;
const SHTexture::PixelChannel* PixelData = nullptr;
SHTexture::TextureFormat TextureFormat = {};
uint32_t MipLevels = 0;
Handle<SHVkSampler> Sampler;
std::vector<uint32_t> MipOffsets;
uint32_t Width;
uint32_t Height;
Handle<SHTexture> TextureHandle;
Handle<SHVkImage> Image;
Handle<SHTexture> Handle;
};
/*-----------------------------------------------------------------------------*/
@ -149,9 +159,9 @@ namespace SHADE
ResourceManager resourceManager;
std::vector<Handle<SHTexture>> texOrder;
// CPU Storage
std::vector<SHTexture::PixelChannel> texStorage;
std::vector<std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout>> combinedImageSamplers;
// GPU Storage
Handle<SHVkBuffer> texStorageBuffer{};
Handle<SHVkDescriptorSetGroup> texDescriptors;
// Flags
bool isDirty = true;
@ -159,5 +169,6 @@ namespace SHADE
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
void preparePipelineBarriers(vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::PipelineStageFlagBits& srcStage, vk::PipelineStageFlagBits& dstStage, std::vector<vk::ImageMemoryBarrier>& barriers);
vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear);
};
}

View File

@ -0,0 +1,75 @@
/************************************************************************************//*!
\file SHVkSamplerCache.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 16, 2022
\brief Contains the implementation for the SHVkSamplerCache 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"
#include "SHVkSamplerCache.h"
// Standard Library
#include <functional>
// Project Header
#include "Graphics/Images/SHVkSampler.h"
#include "Graphics/Devices/SHVkLogicalDevice.h"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Utility Functions */
/*---------------------------------------------------------------------------------*/
void SHSamplerCache::Clear()
{
samplersMap.clear();
}
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
Handle<SHVkSampler> SHSamplerCache::GetSampler(Handle<SHVkLogicalDevice> device, const SHVkSamplerParams& params)
{
// Get the hash to check if it was cached
const RawSamplerHash HASH = calcHash
(
params.minFilter,
params.magFilter,
params.addressMode,
params.mipmapMode,
params.minLod,
params.maxLod
);
// Check if it was cached
auto sampler = samplersMap.find(HASH);
if (sampler == samplersMap.end())
{
const auto BUILD_RESULT = samplersMap.emplace(HASH, device->CreateSampler(params));
sampler = BUILD_RESULT.first;
}
return sampler->second;
}
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
SHSamplerCache::RawSamplerHash SHSamplerCache::calcHash(vk::Filter minFilter, vk::Filter magFilter, vk::SamplerAddressMode addressMode, vk::SamplerMipmapMode mipmapMode, float minLod, float maxLod)
{
static auto charHasher = std::hash<uint8_t>{};
static auto floatHasher = std::hash<float>{};
const RawSamplerHash H1 = charHasher(static_cast<uint8_t>(minFilter));
const RawSamplerHash H2 = charHasher(static_cast<uint8_t>(magFilter));
const RawSamplerHash H3 = charHasher(static_cast<uint8_t>(addressMode));
const RawSamplerHash H4 = charHasher(static_cast<uint8_t>(mipmapMode));
const RawSamplerHash H5 = floatHasher(minLod);
const RawSamplerHash H6 = floatHasher(maxLod);
return H1 ^ (H2 << 1) ^ (H3 << 2) ^ (H4 << 3) ^ (H5 << 4) ^ (H6 << 5);
}
}

View File

@ -0,0 +1,80 @@
/************************************************************************************//*!
\file SHSamplerCache.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 16, 2022
\brief Contains the interface for the SHSamplerCache 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
// Standard Libraries
#include <unordered_map>
// External Dependencies
#include "Graphics/SHVulkanIncludes.h"
// Project Includes
#include "Resource/Handle.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHVkLogicalDevice;
class SHVkSampler;
struct SHVkSamplerParams;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/*************************************************************************************/
/*!
\brief
Class that is responsible for caching and providing Samplers to the user for
sampling textures.
*/
/*************************************************************************************/
class SHSamplerCache
{
public:
/*---------------------------------------------------------------------------------*/
/* Utility Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Clears the cache, destroying all created samplers.
/// </summary>
void Clear();
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Retrieves a Vulkan Sampler of the specified type. If this was retrieved
/// before, a cached copy of the Vulkan Sampler will be provided.
/// </summary>
/// <param name="device">Logical device to create the sampler with if needed.</param>
/// <param name="params">Describes the parameters for the sampler.</param>
/// <returns>Handle to the SHVkSampler object specified.</returns>
Handle<SHVkSampler> GetSampler(Handle<SHVkLogicalDevice> device, const SHVkSamplerParams& params);
private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using RawSamplerHash = size_t;
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
// Resources
std::unordered_map<RawSamplerHash, Handle<SHVkSampler>> samplersMap;
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
static RawSamplerHash calcHash(vk::Filter minFilter, vk::Filter magFilter, vk::SamplerAddressMode addressMode, vk::SamplerMipmapMode mipmapMode, float minLod, float maxLod);
};
}

View File

@ -73,6 +73,7 @@ namespace SHADE
SHRenderGraph(SHRenderGraph&& rhs) noexcept;
SHRenderGraph& operator=(SHRenderGraph&& rhs) noexcept;
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/

View File

@ -181,4 +181,15 @@ namespace SHADE
updateQueue.push({ UpdateCommandType::WORLD_SCALE, newWorldScale });
}
} // namespace SHADE
} // namespace SHADE
RTTR_REGISTRATION
{
using namespace SHADE;
using namespace rttr;
registration::class_<SHTransformComponent>("Transform Component")
.property("Translate", &SHTransformComponent::GetLocalPosition, &SHTransformComponent::SetLocalPosition)
.property("Rotate", &SHTransformComponent::GetLocalRotation, select_overload<void(SHVec3 const&)>(&SHTransformComponent::SetLocalRotation))
.property("Scale", &SHTransformComponent::GetLocalScale, &SHTransformComponent::SetLocalScale);
}

View File

@ -12,6 +12,7 @@
#include <queue>
#include <rttr/registration>
// Project Headers
#include "SH_API.h"
#include "ECS_Base/Components/SHComponent.h"
@ -116,6 +117,8 @@ namespace SHADE
SHTransform world;
UpdateQueue updateQueue;
RTTR_ENABLE()
};

View File

@ -66,27 +66,23 @@ namespace SHADE
for (const auto* child : node->GetChildren())
{
const bool HAS_TRANSFORM = SHComponentManager::HasComponent<SHTransformComponent>(child->GetEntityID());
if (!HAS_TRANSFORM)
continue;
auto* childTransform = SHComponentManager::GetComponent<SHTransformComponent>(child->GetEntityID());
// Only update if node in hierarchy and component are both active
const bool IS_NODE_ACTIVE = child->IsActive();
if (IS_NODE_ACTIVE && childTransform->isActive)
auto* childTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(child->GetEntityID());
if (childTransform)
{
if (childTransform->dirty || HAS_PARENT_CHANGED)
UpdateTransform(*childTransform, NODE_TRANSFORM);
// Only update if node in hierarchy and component are both active
const bool IS_NODE_ACTIVE = child->IsActive();
if (IS_NODE_ACTIVE && childTransform->isActive)
{
if (childTransform->dirty || HAS_PARENT_CHANGED)
UpdateTransform(*childTransform, NODE_TRANSFORM);
}
}
UpdateEntity(child);
// Clear dirty flag after all children are updated
childTransform->dirty = false;
if (childTransform)
childTransform->dirty = false;
}
}
@ -144,8 +140,8 @@ namespace SHADE
tf.world.ComputeTRS();
// Transpose TRS to column major
tf.local.trs.Transpose();
tf.world.trs.Transpose();
//tf.local.trs.Transpose();
//tf.world.trs.Transpose();
}
} // namespace SHADE

View File

@ -7,7 +7,8 @@ workspace "SHADE"
configurations
{
"Debug",
"Release"
"Release",
"Publish"
}
flags