diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index e777fb09..c6da6f1f 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -145,6 +145,9 @@ namespace Sandbox SHADE::SHSystemManager::RunRoutines(false, 0.016f); } + + // Finish all graphics jobs first + graphicsSystem->AwaitGraphicsExecution(); } diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index ffecdf95..3b277e6c 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -118,7 +118,7 @@ namespace Sandbox renderable.SetMaterial(customMat); renderable.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f)); renderable.GetModifiableMaterial()->SetProperty("data.alpha", 1.0f); - renderable.GetModifiableMaterial()->SetProperty("data.textureIndex", 1); + renderable.GetModifiableMaterial()->SetProperty("data.textureIndex", 0); transform.SetWorldPosition({ -3.0f, -1.0f, -1.0f }); transform.SetLocalScale({ 5.0f, 5.0f, 5.0f }); @@ -159,7 +159,7 @@ namespace Sandbox renderableShowcase.SetMaterial(customMat); renderableShowcase.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f)); renderableShowcase.GetModifiableMaterial()->SetProperty("data.alpha", 1.0f); - renderableShowcase.GetModifiableMaterial()->SetProperty("data.textureIndex", 1); + renderableShowcase.GetModifiableMaterial()->SetProperty("data.textureIndex", 0); transformShowcase.SetWorldPosition({ 3.0f, -1.0f, -1.0f }); transformShowcase.SetLocalScale({ 5.0f, 5.0f, 5.0f }); diff --git a/SHADE_Engine/premake5.lua b/SHADE_Engine/premake5.lua index ef22b2c4..18920194 100644 --- a/SHADE_Engine/premake5.lua +++ b/SHADE_Engine/premake5.lua @@ -163,8 +163,8 @@ project "SHADE_Engine" 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", +-- "%{prj.location}/src/Editor/**.cpp", +-- "%{prj.location}/src/Editor/**.h", +-- "%{prj.location}/src/Editor/**.hpp", } links{"fmodstudio_vc.lib", "fmod_vc.lib"} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h index 634d9a9a..07cebea9 100644 --- a/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h +++ b/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h @@ -17,7 +17,8 @@ namespace SHADE SHTexture::PixelChannel const * pixelData; SHTextureAsset() - : numBytes{ 0 }, + : compiled{ false }, + numBytes{ 0 }, width{ 0 }, height{ 0 }, format{ SHTexture::TextureFormat::eUndefined }, @@ -25,7 +26,8 @@ namespace SHADE {} SHTextureAsset(SHTextureAsset const& rhs) - : numBytes{ rhs.numBytes }, + : compiled{ false }, + numBytes{ rhs.numBytes }, width{ rhs.width }, height{ rhs.height }, format{ rhs.format }, diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp index b77d429d..3a5fb9ec 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp +++ b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp @@ -91,8 +91,8 @@ namespace SHADE } } - result.header.vertexCount = result.vertexPosition.size(); - result.header.indexCount = result.indices.size(); + result.header.vertexCount = static_cast(result.vertexPosition.size()); + result.header.indexCount = static_cast(result.indices.size()); result.header.meshName = mesh.mName.C_Str(); return result; diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp index 1047cdc6..47501d42 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp +++ b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp @@ -83,10 +83,10 @@ namespace SHADE std::vector mipOff(file.GetMipCount()); - for (auto i{0}; i < file.GetMipCount(); ++i) + for (size_t i{0}; i < file.GetMipCount(); ++i) { - mipOff[i] = totalBytes; - totalBytes += file.GetImageData(i, 0)->m_memSlicePitch; + mipOff[i] = static_cast(totalBytes); + totalBytes += file.GetImageData(static_cast(i), 0)->m_memSlicePitch; } SHTexture::PixelChannel* pixel = new SHTexture::PixelChannel[totalBytes]; @@ -94,7 +94,7 @@ namespace SHADE //pixel = std::move(reinterpret_cast(file.GetDDSData())); asset.compiled = false; - asset.numBytes = totalBytes; + asset.numBytes = static_cast(totalBytes); asset.width = file.GetWidth(); asset.height = file.GetHeight(); asset.format = ddsLoaderToVkFormat(file.GetFormat(), true); diff --git a/SHADE_Engine/src/Assets/SHAssetManager.cpp b/SHADE_Engine/src/Assets/SHAssetManager.cpp index 989cd2ad..430b8c79 100644 --- a/SHADE_Engine/src/Assets/SHAssetManager.cpp +++ b/SHADE_Engine/src/Assets/SHAssetManager.cpp @@ -72,12 +72,13 @@ namespace SHADE AssetType type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string().c_str()); std::string folder; - switch (type) - { - default: - //TODO:ASSERT UNSUPPORTED FILE TYPE - return std::filesystem::path(); - } + //TODO Implement asset type generation + //switch (type) + //{ + //default: + // //TODO:ASSERT UNSUPPORTED FILE TYPE + // return std::filesystem::path(); + //} return std::filesystem::path(ASSET_ROOT + folder + path.filename().string()); } @@ -108,12 +109,13 @@ namespace SHADE meta.type = type; std::string folder; - switch (type) - { - default: - folder = ""; - break; - } + //TODO implement folder choosing + //switch (type) + //{ + //default: + // folder = ""; + // break; + //} AssetPath path{ ASSET_ROOT + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) }; SHAssetMetaHandler::WriteMetaData(meta); diff --git a/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp b/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp index 35d167d2..6554a3e4 100644 --- a/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp +++ b/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp @@ -122,7 +122,7 @@ namespace SHADE break; default: - void; + break; } metaFile.close(); diff --git a/SHADE_Engine/src/Editor/Command/SHCommand.hpp b/SHADE_Engine/src/Editor/Command/SHCommand.hpp index ae8834e9..7a526506 100644 --- a/SHADE_Engine/src/Editor/Command/SHCommand.hpp +++ b/SHADE_Engine/src/Editor/Command/SHCommand.hpp @@ -5,9 +5,13 @@ //#==============================================================# #include +#include "SH_API.h" +#include "Scripting/SHScriptEngine.h" +#include "ECS_Base/Managers/SHSystemManager.h" + namespace SHADE { - class SHBaseCommand + class SH_API SHBaseCommand { public: virtual ~SHBaseCommand() = default; @@ -48,4 +52,20 @@ namespace SHADE T newValue; SetterFunction set; }; + + class SH_API SHCLICommand : SHBaseCommand + { + public: + SHCLICommand() = default; + void Execute() override + { + SHScriptEngine* scriptEngine = static_cast(SHSystemManager::GetSystem()); + scriptEngine->RedoScriptInspectorChanges(); + } + void Undo() override + { + SHScriptEngine* scriptEngine = static_cast(SHSystemManager::GetSystem()); + scriptEngine->UndoScriptInspectorChanges(); + } + }; }//namespace SHADE diff --git a/SHADE_Engine/src/Editor/Command/SHCommandManager.cpp b/SHADE_Engine/src/Editor/Command/SHCommandManager.cpp index 67d6c2ee..ee2d316d 100644 --- a/SHADE_Engine/src/Editor/Command/SHCommandManager.cpp +++ b/SHADE_Engine/src/Editor/Command/SHCommandManager.cpp @@ -27,6 +27,11 @@ namespace SHADE } } + void SHCommandManager::RegisterCommand(CommandPtr commandPtr) + { + undoStack.push(commandPtr); + } + void SHCommandManager::UndoCommand() { if (undoStack.empty()) diff --git a/SHADE_Engine/src/Editor/Command/SHCommandManager.h b/SHADE_Engine/src/Editor/Command/SHCommandManager.h index 3ea42740..9152c3cb 100644 --- a/SHADE_Engine/src/Editor/Command/SHCommandManager.h +++ b/SHADE_Engine/src/Editor/Command/SHCommandManager.h @@ -9,10 +9,11 @@ //|| SHADE Includes || //#==============================================================# #include "SHCommand.hpp" +#include "SH_API.h" namespace SHADE { - class SHCommandManager + class SH_API SHCommandManager { public: //#==============================================================# @@ -22,6 +23,7 @@ namespace SHADE using CommandStack = std::stack; static void PerformCommand(CommandPtr commandPtr, bool const& overrideValue = false); + static void RegisterCommand(CommandPtr commandPtr); static void UndoCommand(); static void RedoCommand(); static std::size_t GetUndoStackSize(); diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index 35836dc2..3d00ac4b 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -18,6 +18,8 @@ #include "ECS_Base/Managers/SHSystemManager.h" #include "AudioSystem/SHAudioSystem.h" +#include "Physics/Components/SHRigidBodyComponent.h" +#include "Physics/Components/SHColliderComponent.h" namespace SHADE { @@ -70,23 +72,28 @@ namespace SHADE { DrawComponent(renderableComponent); } - if(auto testComponent = SHComponentManager::GetComponent_s(eid)) + if(auto colliderComponent = SHComponentManager::GetComponent_s(eid)) { - DrawComponent(testComponent); + DrawComponent(colliderComponent); } + if(auto rigidbodyComponent = SHComponentManager::GetComponent_s(eid)) + { + DrawComponent(rigidbodyComponent); + } + ImGui::Separator(); + // Render Scripts + SHScriptEngine* scriptEngine = static_cast(SHSystemManager::GetSystem()); + scriptEngine->RenderScriptsInInspector(eid); ImGui::Separator(); if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data())) { DrawAddComponentButton(eid); DrawAddComponentButton(eid); - DrawAddComponentButton(eid); + DrawAddComponentButton(eid); + DrawAddComponentButton(eid); ImGui::EndMenu(); } - // Render Scripts - SHScriptEngine* scriptEngine = static_cast(SHSystemManager::GetSystem()); - scriptEngine->RenderScriptsInInspector(eid); - } ImGui::End(); } diff --git a/SHADE_Engine/src/Filesystem/SHFileSystem.cpp b/SHADE_Engine/src/Filesystem/SHFileSystem.cpp index 16175578..bd34ed71 100644 --- a/SHADE_Engine/src/Filesystem/SHFileSystem.cpp +++ b/SHADE_Engine/src/Filesystem/SHFileSystem.cpp @@ -2,7 +2,6 @@ #include "SHFileSystem.h" #include "fileapi.h" #include -#include #include namespace SHADE @@ -27,8 +26,11 @@ namespace SHADE } auto const count = static_cast(folders[here]->subFolders.size()); - - assert(count < FOLDER_MAX_COUNT, "Max subfolders reached\n"); + + if (count >= FOLDER_MAX_COUNT) + { + SHLOG_ERROR("Max subfolder reached: {}\n", name); + } auto const location = static_cast(count); @@ -37,7 +39,10 @@ namespace SHADE return location; } - assert(folders.contains(here), "Folder creation location does not exist/invalid\n"); + if (!folders.contains(here)) + { + SHLOG_ERROR("Folder creation location does not exist/invalid: {}\n", here); + } auto const count = static_cast(folders[here]->subFolders.size()); @@ -45,7 +50,11 @@ namespace SHADE location <<= FOLDER_BIT_ALLOCATE; location |= count; - assert(count < FOLDER_MAX_COUNT, "Max subfolders reached\n"); + if (count >= FOLDER_MAX_COUNT) + { + SHLOG_ERROR("Max subfolder reached: {}\n", name); + } + CreateFolder(folders[0]->path, here, location, name); return location; @@ -53,7 +62,10 @@ namespace SHADE bool SHFileSystem::DeleteFolder(FolderPointer location) noexcept { - assert(folders.contains(location->id), "Delete target does not exist/invalid.\n"); + if (!folders.contains(location->id)) + { + SHLOG_ERROR("Delete target does not exist/invalid: {}\n", location->name); + } for (auto const& subFolder : folders[location->id]->subFolders) { @@ -116,10 +128,11 @@ namespace SHADE FolderPointer SHFileSystem::CreateFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept { - assert( - CreateDirectoryA(path.c_str(), nullptr), - "Failed to create folder\n" - ); + + if (!CreateDirectoryA(path.c_str(), nullptr)) + { + SHLOG_ERROR("Failed to create folder: {}\n", path); + } folders[location] = std::make_unique(location, name); folders[location]->path = path; diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp index eb65598c..9ebbd227 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp @@ -24,7 +24,7 @@ namespace SHADE /***************************************************************************/ SHVkCommandBuffer::~SHVkCommandBuffer(void) noexcept { - if (vkCommandBuffer) + if (vkCommandBuffer && parentPool) parentPool->GetLogicalDevice()->GetVkLogicalDevice().freeCommandBuffers(parentPool->GetVkCommandPool(), commandBufferCount, &vkCommandBuffer); } diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.cpp b/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.cpp index 881ee998..e1470898 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.cpp +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.cpp @@ -102,8 +102,6 @@ namespace SHADE logicalDeviceHdl = rhs.logicalDeviceHdl; transient = rhs.transient; - static_cast&>(*this) = static_cast&>(rhs); - rhs.vkCommandPool = VK_NULL_HANDLE; return *this; diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp index e50e717f..e842df47 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp @@ -208,7 +208,7 @@ namespace SHADE BindingAndSetHash bsHash = SHVkUtil::GenBindingSetHash(set, binding); // to index a set - uint32_t setIndex = setIndexing[bsHash]; + uint32_t setIndex = setIndexing[set]; // to index a write for a binding uint32_t writeInfoIndex = updater.writeHashMap[bsHash]; @@ -233,7 +233,7 @@ namespace SHADE BindingAndSetHash bsHash = SHVkUtil::GenBindingSetHash(set, binding); // to index a set - uint32_t setIndex = setIndexing[bsHash]; + uint32_t setIndex = setIndexing[set]; // to index a write for a binding uint32_t writeInfoIndex = updater.writeHashMap[bsHash]; diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp index 3fa797bf..4f4f94a4 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp @@ -92,7 +92,7 @@ namespace SHADE //uint32_t minBuffer if (alignmentSize > 0) { - alignedSize = (alignedSize + alignmentSize - 1) & ~(alignmentSize - 1); + alignedSize = (alignedSize + static_cast(alignmentSize) - 1) & ~(alignmentSize - 1); } return alignedSize; } @@ -195,6 +195,8 @@ namespace SHADE vk::PhysicalDeviceDescriptorIndexingFeatures descIndexingFeature{}; descIndexingFeature.descriptorBindingVariableDescriptorCount = true; + descIndexingFeature.shaderSampledImageArrayNonUniformIndexing = true; + descIndexingFeature.runtimeDescriptorArray = true; // Prepare to create the device vk::DeviceCreateInfo deviceCreateInfo @@ -249,6 +251,22 @@ namespace SHADE vkLogicalDevice.destroy(nullptr); } + SHVkLogicalDevice& SHVkLogicalDevice::operator=(SHVkLogicalDevice&& rhs) noexcept + { + if (this == &rhs) + return *this; + + vkLogicalDevice = std::move (rhs.vkLogicalDevice); + queueFamilyIndices = std::move (rhs.queueFamilyIndices); + vmaAllocator = rhs.vmaAllocator; + nonDedicatedBestIndex = 0; + parentPhysicalDeviceHdl = rhs.parentPhysicalDeviceHdl; + + rhs.vkLogicalDevice = VK_NULL_HANDLE; + + return *this; + } + /***************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h index 1272f68f..5c400e02 100644 --- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h +++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h @@ -115,7 +115,7 @@ namespace SHADE ~SHVkLogicalDevice (void) noexcept; SHVkLogicalDevice& operator= (SHVkLogicalDevice const& rhs) noexcept = default; - SHVkLogicalDevice& operator= (SHVkLogicalDevice&& rhs) noexcept = default; + SHVkLogicalDevice& operator= (SHVkLogicalDevice&& rhs) noexcept; /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER VARIABLES */ diff --git a/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.cpp b/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.cpp index 1386134f..76e627d3 100644 --- a/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.cpp +++ b/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.cpp @@ -98,6 +98,51 @@ namespace SHADE return *this; } + void SHVkFramebuffer::HandleResize(Handle const& renderpassHdl, std::vector> const& attachments, uint32_t inWidth, uint32_t inHeight) noexcept + { + width = inWidth; + height = inHeight; + + for (auto& attachment : attachments) + { + // Not sure if its an error to pass in diff dimension images. + if (attachment->GetParentImage()->GetWidth() != (*attachments.begin())->GetParentImage()->GetWidth() || attachment->GetParentImage()->GetHeight() != (*attachments.begin())->GetParentImage()->GetHeight()) + { + SHLOG_ERROR("Dimensions of images not same as each other. Cannot create framebuffer."); + return; + } + } + + std::vector vkAttachments(attachments.size()); + + uint32_t i = 0; + for(auto const& attachment : attachments) + { + vkAttachments[i] = attachment->GetImageView(); + ++i; + } + + vk::FramebufferCreateInfo createInfo + { + .renderPass = renderpassHdl->GetVkRenderpass(), + .attachmentCount = static_cast(vkAttachments.size()), + .pAttachments = vkAttachments.data(), + .width = width, + .height = height, + .layers = 1 // TODO: Find out why this is 1 + }; + + if (auto result = logicalDeviceHdl->GetVkLogicalDevice().createFramebuffer(&createInfo, nullptr, &vkFramebuffer); result != vk::Result::eSuccess) + { + SHVulkanDebugUtil::ReportVkError(result, "Failed to create framebuffer. "); + return; + } + else + { + SHVulkanDebugUtil::ReportVkSuccess("Successfully created framebuffer. "); + } + } + /***************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.h b/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.h index fa9161e8..47bfcf99 100644 --- a/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.h +++ b/SHADE_Engine/src/Graphics/Framebuffer/SHVkFramebuffer.h @@ -37,6 +37,8 @@ namespace SHADE SHVkFramebuffer(SHVkFramebuffer&& rhs) noexcept; SHVkFramebuffer& operator=(SHVkFramebuffer&& rhs) noexcept; + void HandleResize (Handle const& renderpassHdl, std::vector> const& attachments, uint32_t inWidth, uint32_t inHeight) noexcept; + /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp b/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp index b6f20af4..00cc31bf 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp +++ b/SHADE_Engine/src/Graphics/Images/SHVkImage.cpp @@ -79,6 +79,41 @@ namespace SHADE vmaUnmapMemory(*vmaAllocator, stagingAlloc); } + void SHVkImage::CreateFramebufferImage(void) noexcept + { + vk::ImageCreateInfo imageCreateInfo{}; + imageCreateInfo.imageType = vk::ImageType::e2D; + imageCreateInfo.extent.width = width; + imageCreateInfo.extent.height = height; + imageCreateInfo.extent.depth = depth; + imageCreateInfo.mipLevels = mipLevelCount; + imageCreateInfo.arrayLayers = layerCount; + imageCreateInfo.format = imageFormat; + imageCreateInfo.tiling = vk::ImageTiling::eOptimal; + imageCreateInfo.initialLayout = vk::ImageLayout::eUndefined; + imageCreateInfo.usage = usageFlags; + imageCreateInfo.sharingMode = vk::SharingMode::eExclusive; + imageCreateInfo.samples = vk::SampleCountFlagBits::e1; + imageCreateInfo.flags = createFlags; + + + // Prepare allocation parameters for call to create images later + VmaAllocationCreateInfo allocCreateInfo{}; + allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; + allocCreateInfo.flags = {}; // TODO: Make sure the vk::MemoryPropertyFlags returned from vmaGetAllocationMemoryProperties has the device local bit set + + VmaAllocationInfo allocInfo{}; + + VkImage tempImage; + auto result = vmaCreateImage(*vmaAllocator, &imageCreateInfo.operator VkImageCreateInfo & (), &allocCreateInfo, &tempImage, &alloc, &allocInfo); + vkImage = tempImage; + + if (result != VK_SUCCESS) + SHVulkanDebugUtil::ReportVkError(vk::Result(result), "Failed to create vulkan image. "); + else + SHVulkanDebugUtil::ReportVkSuccess("Successfully created image. "); + } + SHVkImage::SHVkImage( VmaAllocator const* allocator, SHImageCreateParams const& imageDetails, @@ -196,37 +231,7 @@ namespace SHADE , createFlags {create} , vmaAllocator {allocator} { - vk::ImageCreateInfo imageCreateInfo{}; - imageCreateInfo.imageType = vk::ImageType::e2D; - imageCreateInfo.extent.width = width; - imageCreateInfo.extent.height = height; - imageCreateInfo.extent.depth = depth; - imageCreateInfo.mipLevels = mipLevelCount; - imageCreateInfo.arrayLayers = layerCount; - imageCreateInfo.format = imageFormat; - imageCreateInfo.tiling = vk::ImageTiling::eOptimal; - imageCreateInfo.initialLayout = vk::ImageLayout::eUndefined; - imageCreateInfo.usage = usageFlags; - imageCreateInfo.sharingMode = vk::SharingMode::eExclusive; - imageCreateInfo.samples = vk::SampleCountFlagBits::e1; - imageCreateInfo.flags = createFlags; - - - // Prepare allocation parameters for call to create images later - VmaAllocationCreateInfo allocCreateInfo{}; - allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; - allocCreateInfo.flags = {}; // TODO: Make sure the vk::MemoryPropertyFlags returned from vmaGetAllocationMemoryProperties has the device local bit set - - VmaAllocationInfo allocInfo{}; - - VkImage tempImage; - auto result = vmaCreateImage(*vmaAllocator, &imageCreateInfo.operator VkImageCreateInfo & (), &allocCreateInfo, &tempImage, &alloc, &allocInfo); - vkImage = tempImage; - - if (result != VK_SUCCESS) - SHVulkanDebugUtil::ReportVkError(vk::Result(result), "Failed to create vulkan image. "); - else - SHVulkanDebugUtil::ReportVkSuccess("Successfully created image. "); + CreateFramebufferImage(); } Handle SHVkImage::CreateImageView(Handle const& inLogicalDeviceHdl, Handle const& parent, SHImageViewDetails const& createParams) const noexcept @@ -288,6 +293,16 @@ namespace SHADE barrier.subresourceRange.layerCount = layerCount; } + void SHVkImage::HandleResizeFramebufferImage(uint32_t newWidth, uint32_t newHeight) noexcept + { + vmaDestroyImage(*vmaAllocator, vkImage, alloc); + + width = newWidth; + height = newHeight; + + CreateFramebufferImage(); + } + void SHVkImage::LinkWithExteriorImage(vk::Image inVkImage, vk::ImageType type, uint32_t inWidth, uint32_t inHeight, uint32_t inDepth, uint32_t layers, uint8_t levels, vk::Format format, vk::ImageUsageFlags flags) noexcept { vkImage = inVkImage; diff --git a/SHADE_Engine/src/Graphics/Images/SHVkImage.h b/SHADE_Engine/src/Graphics/Images/SHVkImage.h index 39e695a5..51b71b26 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkImage.h +++ b/SHADE_Engine/src/Graphics/Images/SHVkImage.h @@ -108,7 +108,7 @@ namespace SHADE /* PRIVATE MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ void PrepStagingBuffer(const void* data, uint32_t srcSize) noexcept; - + void CreateFramebufferImage (void) noexcept; public: /*-----------------------------------------------------------------------*/ @@ -137,7 +137,8 @@ namespace SHADE Handle CreateImageView (Handle const& inLogicalDeviceHdl, Handle const& parent, SHImageViewDetails const& createParams) const noexcept; void TransferToDeviceResource (Handle cmdBufferHdl) noexcept; void PrepareImageTransitionInfo (vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::ImageMemoryBarrier& barrier) noexcept; - + void HandleResizeFramebufferImage(uint32_t newWidth, uint32_t newHeight) noexcept; + /*-----------------------------------------------------------------------*/ /* GETTERS AND SETTERS */ /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/Images/SHVkImageView.cpp b/SHADE_Engine/src/Graphics/Images/SHVkImageView.cpp index 9d12d7cd..44b5718c 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkImageView.cpp +++ b/SHADE_Engine/src/Graphics/Images/SHVkImageView.cpp @@ -6,6 +6,67 @@ namespace SHADE { + + void SHVkImageView::Create(void) noexcept + { + auto parentImageCreateFlags = parentImage->GetImageeCreateFlags(); + + // 2D array image type means parent image must be 2D array compatible + if (imageViewDetails.viewType == vk::ImageViewType::e2DArray) + { + if (!(parentImageCreateFlags & vk::ImageCreateFlagBits::e2DArrayCompatible)) + { + SHLOG_ERROR("Failed to create image view. Parent image not 2D array compatible. "); + return; + } + } + + // Check if its possible for the image view to have different format than parent image + if (imageViewDetails.format != parentImage->GetImageFormat()) + { + if (!(parentImageCreateFlags & vk::ImageCreateFlagBits::eMutableFormat)) + { + SHLOG_ERROR("Failed to create image view. Format for image view not same as image but image not initialized with mutable format bit. "); + return; + } + } + + + vk::ImageViewCreateInfo viewCreateInfo + { + .pNext = nullptr, // Can be used to override with a VkImageViewUsageCreateInfo to override usage. See Vulkan spec page 877 for more information + .image = parentImage->GetVkImage(), + .viewType = imageViewDetails.viewType, + .format = imageViewDetails.format, + .components + { + .r = vk::ComponentSwizzle::eR, + .g = vk::ComponentSwizzle::eG, + .b = vk::ComponentSwizzle::eB, + .a = vk::ComponentSwizzle::eA, + }, + .subresourceRange + { + .aspectMask = imageViewDetails.imageAspectFlags, + .baseMipLevel = imageViewDetails.baseMipLevel, + .levelCount = imageViewDetails.mipLevelCount, + .baseArrayLayer = imageViewDetails.baseArrayLayer, + .layerCount = imageViewDetails.layerCount, + }, + }; + + if (auto result = logicalDeviceHdl->GetVkLogicalDevice().createImageView(&viewCreateInfo, nullptr, &vkImageView); result != vk::Result::eSuccess) + { + SHVulkanDebugUtil::ReportVkError(result, "Failed to create image view! "); + return; + } + else + { + SHVulkanDebugUtil::ReportVkSuccess("Successfully created image view. "); + } + + } + /***************************************************************************/ /*! @@ -18,70 +79,12 @@ namespace SHADE */ /***************************************************************************/ SHVkImageView::SHVkImageView(Handle const& inLogicalDeviceHdl, Handle const& parent, SHImageViewDetails const& createParams) noexcept - : parentImage{ } + : parentImage{ parent } , vkImageView{} - , imageViewDetails{} + , imageViewDetails{createParams} , logicalDeviceHdl {inLogicalDeviceHdl} { - auto parentImageCreateFlags = parent->GetImageeCreateFlags(); - - // 2D array image type means parent image must be 2D array compatible - if (createParams.viewType == vk::ImageViewType::e2DArray) - { - if (!(parentImageCreateFlags & vk::ImageCreateFlagBits::e2DArrayCompatible)) - { - SHLOG_ERROR("Failed to create image view. Parent image not 2D array compatible. "); - return; - } - } - - // Check if its possible for the image view to have different format than parent image - if (createParams.format != parent->GetImageFormat()) - { - if (!(parentImageCreateFlags & vk::ImageCreateFlagBits::eMutableFormat)) - { - SHLOG_ERROR("Failed to create image view. Format for image view not same as image but image not initialized with mutable format bit. "); - return; - } - } - - - vk::ImageViewCreateInfo viewCreateInfo - { - .pNext = nullptr, // Can be used to override with a VkImageViewUsageCreateInfo to override usage. See Vulkan spec page 877 for more information - .image = parent->GetVkImage(), - .viewType = createParams.viewType, - .format = createParams.format, - .components - { - .r = vk::ComponentSwizzle::eR, - .g = vk::ComponentSwizzle::eG, - .b = vk::ComponentSwizzle::eB, - .a = vk::ComponentSwizzle::eA, - }, - .subresourceRange - { - .aspectMask = createParams.imageAspectFlags, - .baseMipLevel = createParams.baseMipLevel, - .levelCount = createParams.mipLevelCount, - .baseArrayLayer = createParams.baseArrayLayer, - .layerCount = createParams.layerCount, - }, - }; - - if (auto result = inLogicalDeviceHdl->GetVkLogicalDevice().createImageView(&viewCreateInfo, nullptr, &vkImageView); result != vk::Result::eSuccess) - { - SHVulkanDebugUtil::ReportVkError(result, "Failed to create image view! "); - return; - } - else - { - SHVulkanDebugUtil::ReportVkSuccess("Successfully created image view. "); - } - - // After success, THEN assign variables - parentImage = parent; - imageViewDetails = createParams; + Create(); } SHVkImageView::SHVkImageView(SHVkImageView&& rhs) noexcept @@ -94,6 +97,17 @@ namespace SHADE } + void SHVkImageView::ViewNewImage(Handle const& parent, SHImageViewDetails const& createParams) noexcept + { + imageViewDetails = createParams; + parentImage = parent; + + if (vkImageView) + logicalDeviceHdl->GetVkLogicalDevice().destroyImageView(vkImageView, nullptr); + + Create(); + } + Handle const& SHVkImageView::GetParentImage(void) const noexcept { return parentImage; diff --git a/SHADE_Engine/src/Graphics/Images/SHVkImageView.h b/SHADE_Engine/src/Graphics/Images/SHVkImageView.h index afa357ef..ae23d7a7 100644 --- a/SHADE_Engine/src/Graphics/Images/SHVkImageView.h +++ b/SHADE_Engine/src/Graphics/Images/SHVkImageView.h @@ -25,12 +25,17 @@ namespace SHADE //! Logical Device needed for creation and destruction Handle logicalDeviceHdl; + //! Create new image view + void Create (void) noexcept; + public: SHVkImageView(Handle const& inLogicalDeviceHdl, Handle const& parent, SHImageViewDetails const& createParams) noexcept; ~SHVkImageView(void) noexcept; SHVkImageView(SHVkImageView&& rhs) noexcept; SHVkImageView& operator=(SHVkImageView&& rhs) noexcept; + void ViewNewImage (Handle const& parent, SHImageViewDetails const& createParams) noexcept; + /*-----------------------------------------------------------------------*/ /* GETTERS AND SETTERS */ /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp index b1cd2cd3..181c1f22 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp @@ -249,7 +249,7 @@ namespace SHADE if (!EMPTY_MAT_PROPS) { singleMatPropSize = SHADER_INFO->GetBytesRequired(); - singleMatPropAlignedSize = device->PadSSBOSize(singleMatPropSize); + singleMatPropAlignedSize = device->PadSSBOSize(static_cast(singleMatPropSize)); matPropTotalBytes = numTotalElements * singleMatPropAlignedSize; if (matPropsDataSize < matPropTotalBytes) { @@ -386,7 +386,7 @@ namespace SHADE SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA, bufferList, - 0, matPropsDataSize + 0, static_cast(matPropsDataSize) ); matPropsDescSet[frameIndex]->UpdateDescriptorSetBuffer ( diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.h index c54f29ed..3a945109 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHCamera.h @@ -69,7 +69,7 @@ namespace SHADE SHMatrix inverseViewMatrix; SHMatrix inverseProjMatrix; SHMatrix inverseVpMatrix; - bool isDirty; + bool isDirty = true; /*-----------------------------------------------------------------------------*/ /* Helper Functions */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 40e24979..6957aa93 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -67,9 +67,17 @@ namespace SHADE // Register callback to notify render context upon a window resize window->RegisterWindowSizeCallback([&]([[maybe_unused]] uint32_t width, [[maybe_unused]] uint32_t height) { + if (width == 0 || height == 0) + return; + renderContext.SetIsResized(true); }); + window->RegisterWindowCloseCallback([&](void) + { + renderContext.SetWindowIsDead(true); + } + ); // Create graphics queue graphicsQueue = device->GetQueue(SH_Q_FAM::GRAPHICS, 0); transferQueue = device->GetQueue(SH_Q_FAM::TRANSFER, 0); @@ -116,8 +124,8 @@ namespace SHADE screenCamera = resourceManager.Create(); screenCamera->SetLookAt(SHVec3(0.0f, 0.0f, -1.0f), SHVec3(0.0f, 0.0f, 1.0f), SHVec3(0.0f, 1.0f, 0.0f)); screenCamera->SetOrthographic(static_cast(windowDims.first), static_cast(windowDims.second), 0.01f, 100.0f); + worldCamera = resourceManager.Create(); - //worldCamera->SetLookAt(SHVec3(1.0f, 0.0f, -1.0f), SHVec3(0.0f, 0.0f, 2.0f), SHVec3(0.0f, 1.0f, 0.0f)); worldCamera->SetLookAt(SHVec3(0.0f, 0.0f, 0.0f), SHVec3(0.0f, 0.0f, -2.0f), SHVec3(0.0f, 1.0f, 0.0f)); worldCamera->SetPerspective(90.0f, static_cast(windowDims.first), static_cast(windowDims.second), 0.0f, 100.0f); @@ -125,7 +133,7 @@ namespace SHADE defaultViewport = AddViewport(vk::Viewport(0.0f, 0.0f, static_cast(window->GetWindowSize().first), static_cast(window->GetWindowSize().second), 0.0f, 1.0f)); // Get render graph from default viewport world renderer - auto worldRenderGraph = resourceManager.Create(); + worldRenderGraph = resourceManager.Create(); std::vector> renderContextCmdPools{swapchain->GetNumImages()}; for (uint32_t i = 0; i < renderContextCmdPools.size(); ++i) @@ -210,6 +218,15 @@ namespace SHADE /***************************************************************************/ void SHGraphicsSystem::Run(double) noexcept { + if (window->IsMinimized() || renderContext.GetWindowIsDead()) + return; + + if (renderContext.GetResized()) + { + return; + } + + // Frame data for the current frame auto const& frameData = renderContext.GetCurrentFrameData(); uint32_t frameIndex = renderContext.GetCurrentFrame(); @@ -249,6 +266,10 @@ namespace SHADE // Begin recording the command buffer currentCmdBuffer->BeginRecording(); + uint32_t w = static_cast(viewports[vpIndex]->GetWidth()); + uint32_t h = static_cast(viewports[vpIndex]->GetHeight()); + currentCmdBuffer->SetViewportScissor (static_cast(w), static_cast(h), w, h); + currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout()); // Bind all the buffers required for meshes @@ -304,13 +325,6 @@ namespace SHADE void SHGraphicsSystem::Exit(void) { - renderContext.Destroy(); - graphicsQueue.Free(); - swapchain.Free(); - surface.Free(); - device.Free(); - - SHVkInstance::Destroy(); } /*---------------------------------------------------------------------------------*/ @@ -328,6 +342,9 @@ namespace SHADE /***************************************************************************/ void SHGraphicsSystem::BeginRender() { + if (window->IsMinimized() || renderContext.GetWindowIsDead()) + return; + // Finalise all batches for (auto vp : viewports) for (auto renderer : vp->GetRenderers()) @@ -341,10 +358,7 @@ namespace SHADE { device->WaitIdle(); - // Resize the swapchain - swapchain->Resize(surface, windowDims.first, windowDims.second); - - renderContext.HandleResize(); + HandleResize(); } const uint32_t CURR_FRAME_IDX = renderContext.GetCurrentFrame(); @@ -377,6 +391,16 @@ namespace SHADE /***************************************************************************/ void SHGraphicsSystem::EndRender() { + if (window->IsMinimized() || renderContext.GetWindowIsDead()) + return; + + if (renderContext.GetResized()) + { + return; + } + + + const uint32_t CURR_FRAME_IDX = renderContext.GetCurrentFrame(); auto& currFrameData = renderContext.GetCurrentFrameData(); @@ -387,10 +411,8 @@ namespace SHADE // If swapchain is incompatible/outdated if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR) { - auto windowDims = window->GetWindowSize(); - swapchain->Resize(surface, windowDims.first, windowDims.second); - renderContext.HandleResize(); + HandleResize(); } } @@ -509,25 +531,79 @@ namespace SHADE ); } + void SHGraphicsSystem::HandleResize(void) noexcept + { + if (window->IsMinimized() || renderContext.GetWindowIsDead()) + return; + + auto windowDims = window->GetWindowSize(); + + // Resize the swapchain + swapchain->Resize(surface, windowDims.first, windowDims.second); + + renderContext.HandleResize(); + + worldRenderGraph->HandleResize(windowDims.first, windowDims.second); + + defaultViewport->SetWidth(static_cast(windowDims.first)); + defaultViewport->SetHeight(static_cast(windowDims.second)); + + worldCamera->SetPerspective(90.0f, static_cast(windowDims.first), static_cast(windowDims.second), 0.0f, 100.0f); + } + + void SHGraphicsSystem::AwaitGraphicsExecution() + { + device->WaitIdle(); + } + void SHGraphicsSystem::SetWindow(SHWindow* wind) noexcept { window = wind; } + /*-----------------------------------------------------------------------------------*/ + /* System Routine Functions - BeginRoutine */ + /*-----------------------------------------------------------------------------------*/ + SHGraphicsSystem::BeginRoutine::BeginRoutine() + : SHSystemRoutine("Graphics System Frame Set Up", false) + {} + void SHGraphicsSystem::BeginRoutine::Execute(double) noexcept { reinterpret_cast(system)->BeginRender(); } + + /*-----------------------------------------------------------------------------------*/ + /* System Routine Functions - RenderRoutine */ + /*-----------------------------------------------------------------------------------*/ + SHGraphicsSystem::RenderRoutine::RenderRoutine() + : SHSystemRoutine("Graphics System Render", false) + {} void SHGraphicsSystem::RenderRoutine::Execute(double dt) noexcept { reinterpret_cast(system)->Run(dt); } + /*-----------------------------------------------------------------------------------*/ + /* System Routine Functions - EndRoutine */ + /*-----------------------------------------------------------------------------------*/ + SHGraphicsSystem::EndRoutine::EndRoutine() + : SHSystemRoutine("Graphics System Frame Clean Up", false) + {} + void SHGraphicsSystem::EndRoutine::Execute(double) noexcept { reinterpret_cast(system)->EndRender(); } + + /*-----------------------------------------------------------------------------------*/ + /* System Routine Functions - BatcherDispatcherRoutine */ + /*-----------------------------------------------------------------------------------*/ + SHGraphicsSystem::BatcherDispatcherRoutine::BatcherDispatcherRoutine() + : SHSystemRoutine("Graphics System Batcher Dispatcher", false) + {} + void SHGraphicsSystem::BatcherDispatcherRoutine::Execute(double) noexcept { auto& renderables = SHComponentManager::GetDense(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 84dc39cd..c89e6ebc 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -69,21 +69,25 @@ namespace SHADE class SH_API BeginRoutine final : public SHSystemRoutine { public: + BeginRoutine(); virtual void Execute(double dt) noexcept override final; }; class SH_API RenderRoutine final : public SHSystemRoutine { public: + RenderRoutine(); virtual void Execute(double dt) noexcept override final; }; class SH_API EndRoutine final : public SHSystemRoutine { public: + EndRoutine(); virtual void Execute(double dt) noexcept override final; }; class SH_API BatcherDispatcherRoutine final : public SHSystemRoutine { public: + BatcherDispatcherRoutine(); virtual void Execute(double dt) noexcept override final; }; @@ -246,6 +250,9 @@ namespace SHADE /***************************************************************************/ void BuildTextures(); + void HandleResize(void) noexcept; + void AwaitGraphicsExecution(); + /*-----------------------------------------------------------------------------*/ /* Setters */ /*-----------------------------------------------------------------------------*/ @@ -279,7 +286,6 @@ namespace SHADE Handle transferQueue; Handle descPool; Handle graphicsCmdPool; - Handle transferCmdPool; Handle transferCmdBuffer; Handle graphicsTexCmdBuffer; SHRenderContext renderContext; @@ -314,5 +320,7 @@ namespace SHADE // Temp Materials Handle defaultMaterial; + + Handle worldRenderGraph; }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h index 692d857f..348efb07 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterial.h @@ -63,7 +63,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ Handle pipeline; std::unique_ptr propMemory; - Byte propMemorySize; + Byte propMemorySize = 0; /*-----------------------------------------------------------------------------*/ /* Helper Functions */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp index 84ac3ee2..14af56ee 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp @@ -49,6 +49,14 @@ namespace SHADE cameraDescriptorSet->UpdateDescriptorSetBuffer(SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, SHGraphicsConstants::DescriptorSetBindings::CAMERA_DATA); } + SHRenderer::~SHRenderer(void) + { + //for (auto& cmdBuffer : commandBuffers) + //{ + // cmdBuffer.Free(); + //} + } + /*-----------------------------------------------------------------------------------*/ /* Camera Registration */ /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h index 5e72da85..0feea840 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h @@ -65,6 +65,7 @@ namespace SHADE /* Constructor/Destructors */ /*-----------------------------------------------------------------------------*/ SHRenderer(Handle logicalDevice, uint32_t numFrames, std::vector>& cmdPools, Handle descriptorPool, Handle cameraDescLayout, Handle viewport, Handle renderGraph); + ~SHRenderer(void); /*-----------------------------------------------------------------------------*/ /* Camera Registration */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.cpp index 25c5bca2..dc534a49 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.cpp @@ -73,4 +73,16 @@ namespace SHADE iter->Free(); renderers.erase(iter); } + + void SHViewport::SetWidth(float w) noexcept + { + viewport.width = w; + } + + void SHViewport::SetHeight(float h) noexcept + { + viewport.height = h; + + } + } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.h index d97d62ce..221dbe7e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHViewport.h @@ -62,6 +62,12 @@ namespace SHADE Handle AddRenderer(ResourceManager& resourceManager, uint32_t numFrames, std::vector>& cmdPools, Handle descriptorPool, Handle cameraDescLayout, Handle renderGraph); void RemoveRenderer(Handle renderer); + /*-----------------------------------------------------------------------------*/ + /* Setters */ + /*-----------------------------------------------------------------------------*/ + void SetWidth(float w) noexcept; + void SetHeight (float h) noexcept; + /*-----------------------------------------------------------------------------*/ /* Getters */ /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp index 2080265b..be181beb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.cpp @@ -196,12 +196,12 @@ namespace SHADE static SHMeshData meshData = Cube(); return meshLibrary.AddMesh ( - meshData.VertexPositions.size(), + static_cast(meshData.VertexPositions.size()), meshData.VertexPositions.data(), meshData.VertexTexCoords.data(), meshData.VertexTangents.data(), meshData.VertexNormals.data(), - meshData.Indices.size(), + static_cast(meshData.Indices.size()), meshData.Indices.data() ); } @@ -211,12 +211,12 @@ namespace SHADE static SHMeshData meshData = Cube(); return gfxSystem.AddMesh ( - meshData.VertexPositions.size(), + static_cast(meshData.VertexPositions.size()), meshData.VertexPositions.data(), meshData.VertexTexCoords.data(), meshData.VertexTangents.data(), meshData.VertexNormals.data(), - meshData.Indices.size(), + static_cast(meshData.Indices.size()), meshData.Indices.data() ); } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.cpp index f31653a8..0ac7013a 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.cpp @@ -168,6 +168,11 @@ namespace SHADE isResized = resized; } + void SHRenderContext::SetWindowIsDead(bool dead) noexcept + { + windowIsDead = dead; + } + /***************************************************************************/ /*! @@ -197,6 +202,11 @@ namespace SHADE return currentFrame; } + bool SHRenderContext::GetResized(void) noexcept + { + return isResized; + } + bool SHRenderContext::GetResizeAndReset(void) noexcept { bool b = isResized; @@ -204,4 +214,9 @@ namespace SHADE return b; } + bool SHRenderContext::GetWindowIsDead(void) const noexcept + { + return windowIsDead; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.h b/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.h index 04cea4e4..bf186922 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/PerFrame/SHRenderContext.h @@ -36,6 +36,7 @@ namespace SHADE uint32_t currentFrame; bool isResized{ false }; + bool windowIsDead {false}; public: SHRenderContext(void) noexcept; @@ -51,12 +52,15 @@ namespace SHADE bool WaitForFence (void) noexcept; void ResetFence (void) noexcept; - void SetIsResized (bool resized) noexcept; + void SetIsResized (bool resized) noexcept; + void SetWindowIsDead (bool dead) noexcept; SHPerFrameData& GetCurrentFrameData(void) noexcept; SHPerFrameData& GetFrameData (uint32_t index) noexcept; uint32_t GetCurrentFrame (void) const noexcept; + bool GetResized (void) noexcept; bool GetResizeAndReset (void) noexcept; + bool GetWindowIsDead (void) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp index 6a7439e5..5c315ff6 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp @@ -149,7 +149,7 @@ namespace SHADE { 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; + job.TextureHandle->TextureArrayIndex = static_cast(texOrder.size()) - 1U; } addJobs.clear(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h index 660d93eb..c2eb85ec 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.h @@ -37,7 +37,7 @@ namespace SHADE class SHVkDescriptorSetLayout; class SHVkDescriptorSetGroup; class SHVkSampler; - class SHTextureAsset; + struct SHTextureAsset; /*---------------------------------------------------------------------------------*/ /* Type Definitions */ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index 828a83f1..cad6a78e 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -46,7 +46,7 @@ namespace SHADE if (w == static_cast(-1) && h == static_cast(-1)) { w = swapchainHdl->GetSwapchainImage(0)->GetWidth(); - w = swapchainHdl->GetSwapchainImage(0)->GetHeight(); + h = swapchainHdl->GetSwapchainImage(0)->GetHeight(); format = swapchainHdl->GetSurfaceFormatKHR().format; } @@ -465,9 +465,6 @@ namespace SHADE // better way to manage these void SHRenderGraph::Execute(uint32_t frameIndex, Handle cmdBuffer, Handle descPool) noexcept { - // TODO: DON'T HARDCODE THIS - cmdBuffer->SetViewportScissor(1920.0f, 1080.0f, 1920, 1080); - for (auto& node : nodes) node->Execute(cmdBuffer, descPool, frameIndex); } @@ -480,6 +477,18 @@ namespace SHADE } } + void SHRenderGraph::HandleResize(uint32_t newWidth, uint32_t newHeight) noexcept + { + // resize resources + for (auto& [name, resource]: graphResources) + resource->HandleResize(newWidth, newHeight); + + for (auto& node : nodes) + { + node->HandleResize(); + } + } + Handle SHRenderGraph::GetNode(std::string const& nodeName) const noexcept { if (nodeIndexing.contains(nodeName)) diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index 8b5b2212..a3140a4f 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -80,6 +80,7 @@ namespace SHADE void Generate (void) noexcept; void Execute (uint32_t frameIndex, Handle cmdBuffer, Handle descPool) noexcept; void FinaliseBatch(uint32_t frameIndex, Handle descPool); + void HandleResize (uint32_t newWidth, uint32_t newHeight) noexcept; /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index b981225a..05232af3 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -3,6 +3,7 @@ #include "Graphics/Devices/SHVkLogicalDevice.h" #include "Graphics/Images/SHVkImageView.h" #include "Graphics/Swapchain/SHVkSwapchain.h" +#include "Graphics/Framebuffer/SHVkFramebuffer.h" #include "SHRenderGraphResource.h" #include "SHSubpass.h" @@ -56,6 +57,33 @@ namespace SHADE } } + void SHRenderGraphNode::HandleResize(void) noexcept + { + renderpass->HandleResize(); + + for (uint32_t i = 0; i < framebuffers.size(); ++i) + { + std::vector> imageViews(attResources.size()); + uint32_t fbWidth = std::numeric_limits::max(); + uint32_t fbHeight = std::numeric_limits::max(); + + for (uint32_t j = 0; j < attResources.size(); ++j) + { + uint32_t imageViewIndex = (attResources[j]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) ? i : 0; + imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + + // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's + if (fbWidth > attResources[j]->width) + fbWidth = attResources[j]->width; + if (fbHeight > attResources[j]->height) + fbHeight = attResources[j]->height; + } + + + framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight); + } + } + /***************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index 59b20271..c713f402 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -81,6 +81,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ void CreateRenderpass(void) noexcept; void CreateFramebuffer(void) noexcept; + void HandleResize (void) noexcept; public: /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp index eb873b16..cc881867 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp @@ -2,9 +2,11 @@ #include "SHRenderGraphResource.h" #include "Graphics/Devices/SHVkLogicalDevice.h" #include "Graphics/Swapchain/SHVkSwapchain.h" +#include "Graphics/Images/SHVkImageView.h" namespace SHADE { + /***************************************************************************/ /*! @@ -42,7 +44,9 @@ namespace SHADE */ /***************************************************************************/ SHRenderGraphResource::SHRenderGraphResource(Handle const& logicalDevice, Handle const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept - : resourceType{ type } + : logicalDevice {logicalDevice} + , swapchain{ swapchain } + , resourceType{ type } , resourceFormat{ format } , images{} , imageViews{} @@ -52,10 +56,10 @@ namespace SHADE , resourceName{ name } { // If the resource type is an arbitrary image and not swapchain image - if (type != SH_ATT_DESC_TYPE::COLOR_PRESENT) + if (resourceType != SH_ATT_DESC_TYPE::COLOR_PRESENT) { - vk::ImageAspectFlags imageAspectFlags; - vk::ImageUsageFlags usage = {}; + imageAspectFlags = vk::ImageAspectFlags{}; + usage = {}; // Check the resource type and set image usage flags and image aspect flags accordingly switch (resourceType) @@ -142,6 +146,7 @@ namespace SHADE , width{ rhs.width } , height{ rhs.height } , mipLevels{ rhs.mipLevels } + , imageAspectFlags{ rhs.imageAspectFlags } { } @@ -172,6 +177,7 @@ namespace SHADE width = rhs.width; height = rhs.height; mipLevels = rhs.mipLevels; + imageAspectFlags = rhs.imageAspectFlags; return *this; } @@ -189,4 +195,51 @@ namespace SHADE } + void SHRenderGraphResource::HandleResize(uint32_t newWidth, uint32_t newHeight) noexcept + { + width = newWidth; + height = newHeight; + + if (resourceType != SH_ATT_DESC_TYPE::COLOR_PRESENT) + { + // prepare image view details + SHImageViewDetails viewDetails + { + .viewType = vk::ImageViewType::e2D, + .format = images[0]->GetImageFormat(), + .imageAspectFlags = imageAspectFlags, + .baseMipLevel = 0, + .mipLevelCount = mipLevels, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + for (uint32_t i = 0; i < images.size(); ++i) + { + images[i]->HandleResizeFramebufferImage(width, height); + imageViews[i]->ViewNewImage(images[i], viewDetails); + } + } + else + { + // Prepare image view details + SHImageViewDetails viewDetails + { + .viewType = vk::ImageViewType::e2D, + .format = swapchain->GetSurfaceFormatKHR().format, + .imageAspectFlags = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .mipLevelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i) + { + images[i] = swapchain->GetSwapchainImage(i); + imageViews[i]->ViewNewImage(images[i], viewDetails); + } + } + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h index fcb16601..ebb699d8 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h @@ -20,6 +20,12 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PRIVATE MEMBER VARIABLES */ /*-----------------------------------------------------------------------*/ + // for creation/recreation + Handle logicalDevice; + + // for creation/recreation + Handle swapchain; + //! Name of the resource std::string resourceName; @@ -47,6 +53,14 @@ namespace SHADE //! Number of mipmap levels uint8_t mipLevels; + + //! image aspect flags + vk::ImageAspectFlags imageAspectFlags; + + //! usage flags + vk::ImageUsageFlags usage = {}; + + public: /*-----------------------------------------------------------------------*/ /* CTORS AND DTORS */ @@ -56,6 +70,8 @@ namespace SHADE SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept; ~SHRenderGraphResource(void) noexcept; + void HandleResize (uint32_t newWidth, uint32_t newHeight) noexcept; + friend class SHRenderGraphNode; friend class SHRenderGraph; }; diff --git a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.cpp b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.cpp index 29de5954..fee23f13 100644 --- a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.cpp +++ b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.cpp @@ -30,7 +30,10 @@ namespace SHADE SHVkRenderpass::SHVkRenderpass(Handle const& inLogicalDeviceHdl, std::span const vkDescriptions, std::vector const& subpasses) noexcept : logicalDeviceHdl {inLogicalDeviceHdl} , numAttDescs {static_cast(vkDescriptions.size())} + , vkSubpassDescriptions{} + , vkSubpassDeps{} , clearColors{} + , vkAttachmentDescriptions{} { for (uint32_t i = 0; i < vkDescriptions.size(); ++i) { @@ -42,7 +45,6 @@ namespace SHADE vk::RenderPassCreateInfo renderPassCreateInfo{}; - std::vector subpassDeps; // For validating the depth ref auto isValidDepthRef = [&](vk::AttachmentReference const& depthRef) -> bool @@ -50,13 +52,16 @@ namespace SHADE return !(depthRef.attachment == static_cast (-1) && depthRef.layout == vk::ImageLayout::eUndefined); }; + for (uint32_t i = 0; i < vkDescriptions.size(); ++i) + vkAttachmentDescriptions[i] = vkDescriptions[i]; + uint32_t subpassIndex = 0; if (!subpasses.empty()) { for (auto& subpass : subpasses) { - subpassDescriptions.emplace_back(); - auto& spDesc = subpassDescriptions.back(); + vkSubpassDescriptions.emplace_back(); + auto& spDesc = vkSubpassDescriptions.back(); spDesc.pColorAttachments = subpass.colorRefs.data(); spDesc.colorAttachmentCount = static_cast(subpass.colorRefs.size()); @@ -88,18 +93,18 @@ namespace SHADE }; // Push a new dependency - subpassDeps.push_back(dependency); + vkSubpassDeps.push_back(dependency); ++subpassIndex; } // Renderpass create info for render pass creation - renderPassCreateInfo.attachmentCount = static_cast(vkDescriptions.size()); - renderPassCreateInfo.pAttachments = vkDescriptions.data(); - renderPassCreateInfo.subpassCount = static_cast(subpassDescriptions.size()); - renderPassCreateInfo.pSubpasses = subpassDescriptions.data(); - renderPassCreateInfo.dependencyCount = static_cast(subpassDeps.size()); - renderPassCreateInfo.pDependencies = subpassDeps.data(); + renderPassCreateInfo.attachmentCount = static_cast(vkAttachmentDescriptions.size()); + renderPassCreateInfo.pAttachments = vkAttachmentDescriptions.data(); + renderPassCreateInfo.subpassCount = static_cast(vkSubpassDescriptions.size()); + renderPassCreateInfo.pSubpasses = vkSubpassDescriptions.data(); + renderPassCreateInfo.dependencyCount = static_cast(vkSubpassDeps.size()); + renderPassCreateInfo.pDependencies = vkSubpassDeps.data(); } // No subpasses passed in, create a default one. @@ -172,6 +177,8 @@ namespace SHADE : logicalDeviceHdl{ inLogicalDeviceHdl } , numAttDescs{ static_cast(vkDescriptions.size()) } , clearColors{} + , vkSubpassDescriptions{ } + , vkSubpassDeps{ } { for (uint32_t i = 0; i < vkDescriptions.size(); ++i) { @@ -181,18 +188,24 @@ namespace SHADE clearColors[i].color = { {{0.0f, 0.0f, 0.0f, 1.0f}} }; } - subpassDescriptions.resize (spDescs.size()); - for (uint32_t i = 0; i < subpassDescriptions.size(); ++i) - { - subpassDescriptions[i] = spDescs[i]; - } + vkAttachmentDescriptions.resize(vkDescriptions.size()); + for (uint32_t i = 0; i < vkDescriptions.size(); ++i) + vkAttachmentDescriptions[i] = vkDescriptions[i]; + + vkSubpassDescriptions.resize (spDescs.size()); + for (uint32_t i = 0; i < vkSubpassDescriptions.size(); ++i) + vkSubpassDescriptions[i] = spDescs[i]; + + vkSubpassDeps.resize(spDeps.size()); + for (uint32_t i = 0; i < vkSubpassDeps.size(); ++i) + vkSubpassDeps[i] = spDeps[i]; vk::RenderPassCreateInfo renderPassCreateInfo{}; renderPassCreateInfo.attachmentCount = static_cast(vkDescriptions.size()); renderPassCreateInfo.pAttachments = vkDescriptions.data(); - renderPassCreateInfo.subpassCount = static_cast(subpassDescriptions.size()); - renderPassCreateInfo.pSubpasses = subpassDescriptions.data(); + renderPassCreateInfo.subpassCount = static_cast(vkSubpassDescriptions.size()); + renderPassCreateInfo.pSubpasses = vkSubpassDescriptions.data(); renderPassCreateInfo.dependencyCount = static_cast(spDeps.size()); renderPassCreateInfo.pDependencies = spDeps.data(); @@ -210,8 +223,11 @@ namespace SHADE SHVkRenderpass::SHVkRenderpass(SHVkRenderpass&& rhs) noexcept : vkRenderpass {rhs.vkRenderpass} , logicalDeviceHdl {rhs.logicalDeviceHdl} - , subpassDescriptions {std::move (rhs.subpassDescriptions)} - , clearColors {std::move (rhs.clearColors)} + , vkSubpassDescriptions{ std::move(rhs.vkSubpassDescriptions) } + , vkSubpassDeps{ std::move(rhs.vkSubpassDeps) } + , clearColors{ std::move(rhs.clearColors) } + , vkAttachmentDescriptions{ std::move(rhs.vkAttachmentDescriptions) } + , numAttDescs{rhs.numAttDescs} { rhs.vkRenderpass = VK_NULL_HANDLE; } @@ -224,8 +240,11 @@ namespace SHADE vkRenderpass = rhs.vkRenderpass; logicalDeviceHdl = rhs.logicalDeviceHdl; - subpassDescriptions = std::move(rhs.subpassDescriptions); + vkSubpassDescriptions = std::move(rhs.vkSubpassDescriptions); + vkSubpassDeps = std::move(rhs.vkSubpassDeps); clearColors = std::move(rhs.clearColors); + vkAttachmentDescriptions = std::move(rhs.vkAttachmentDescriptions); + numAttDescs = std::move(rhs.numAttDescs); rhs.vkRenderpass = VK_NULL_HANDLE; @@ -238,6 +257,31 @@ namespace SHADE } + void SHVkRenderpass::HandleResize(void) noexcept + { + logicalDeviceHdl->GetVkLogicalDevice().destroyRenderPass(vkRenderpass, nullptr); + + vk::RenderPassCreateInfo renderPassCreateInfo{}; + + renderPassCreateInfo.attachmentCount = static_cast(vkAttachmentDescriptions.size()); + renderPassCreateInfo.pAttachments = vkAttachmentDescriptions.data(); + renderPassCreateInfo.subpassCount = static_cast(vkSubpassDescriptions.size()); + renderPassCreateInfo.pSubpasses = vkSubpassDescriptions.data(); + renderPassCreateInfo.dependencyCount = static_cast(vkSubpassDeps.size()); + renderPassCreateInfo.pDependencies = vkSubpassDeps.data(); + + + if (auto result = logicalDeviceHdl->GetVkLogicalDevice().createRenderPass(&renderPassCreateInfo, nullptr, &vkRenderpass); result != vk::Result::eSuccess) + { + SHVulkanDebugUtil::ReportVkError(result, "Failed to create Renderpass. "); + } + else + { + SHVulkanDebugUtil::ReportVkSuccess("Successfully created Renderpass. "); + } + + } + vk::RenderPass SHVkRenderpass::GetVkRenderpass(void) const noexcept { return vkRenderpass; diff --git a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h index b0ae7445..70a04bbf 100644 --- a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h +++ b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h @@ -29,7 +29,13 @@ namespace SHADE Handle logicalDeviceHdl; //! Container of subpass information used to construct subpasses - std::vector subpassDescriptions; + std::vector vkSubpassDescriptions; + + //! Container of subpass dependencies used to create renderpass + std::vector vkSubpassDeps; + + //! Attachment descriptions + std::vector vkAttachmentDescriptions; //! Clear colors for the color and depth std::array clearColors; @@ -49,6 +55,8 @@ namespace SHADE SHVkRenderpass(SHVkRenderpass&& rhs) noexcept; SHVkRenderpass& operator=(SHVkRenderpass&& rhs) noexcept; + void HandleResize (void) noexcept; + /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/Windowing/SHWindow.cpp b/SHADE_Engine/src/Graphics/Windowing/SHWindow.cpp index 3a1deb00..44a1cb0e 100644 --- a/SHADE_Engine/src/Graphics/Windowing/SHWindow.cpp +++ b/SHADE_Engine/src/Graphics/Windowing/SHWindow.cpp @@ -272,6 +272,17 @@ namespace SHADE windowResizeCallbacks.erase(callbackid); } + SHWindow::CALLBACKID SHWindow::RegisterWindowCloseCallback(WindowCloseCallbackFn windowCloseCallback) + { + windowCloseCallbacks.try_emplace(windowResizeCallbackCount, windowCloseCallback); + return windowCloseCallbackCount++; + } + + void SHWindow::UnregisterWindowCloseCallback(CALLBACKID const& callbackid) + { + windowCloseCallbacks.erase(callbackid); + } + LRESULT SHWindow::WndProcStatic(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { auto window = windowMap.GetWindow(hwnd); @@ -307,6 +318,8 @@ namespace SHADE case WM_CREATE: OnCreate(hwnd, reinterpret_cast(wparam)); break; + case WM_CLOSE: + case WM_DESTROY: OnDestroy(); return 0; @@ -362,8 +375,17 @@ namespace SHADE } + void SHADE::SHWindow::OnClose() + { + for (const auto& callbackFn : windowCloseCallbacks | std::views::values) + { + callbackFn(); + } + } + void SHWindow::OnDestroy() { + OnClose(); this->Destroy(); } @@ -375,6 +397,14 @@ namespace SHADE { wndData.width = static_cast(size.cx); wndData.height = static_cast(size.cy); + + if (type == SIZE_MINIMIZED) + { + wndData.isMinimised = true; + } + else + wndData.isMinimised = false; + for (auto const& entry : windowResizeCallbacks) { entry.second(static_cast(wndData.width), static_cast(wndData.height)); diff --git a/SHADE_Engine/src/Graphics/Windowing/SHWindow.h b/SHADE_Engine/src/Graphics/Windowing/SHWindow.h index 1e08dcb0..0a180285 100644 --- a/SHADE_Engine/src/Graphics/Windowing/SHWindow.h +++ b/SHADE_Engine/src/Graphics/Windowing/SHWindow.h @@ -18,7 +18,7 @@ namespace SHADE }; struct WindowData - { + { unsigned x = 0; unsigned y = 0; @@ -42,7 +42,7 @@ namespace SHADE bool closable = true; bool minimizable = true; - + bool maximizable = true; //bool canFullscreen = true; @@ -56,11 +56,13 @@ namespace SHADE bool shadowEnabled = true; bool isVisible = true; - + bool isFullscreen = false; bool modal = false; + bool isMinimised = false; + std::wstring title = L"SHADE ENGINE"; std::wstring name = L"SHADEEngineApp"; @@ -73,6 +75,7 @@ namespace SHADE public: using SHVec2 = std::pair; typedef std::function WindowResizeCallbackFn; + typedef std::function WindowCloseCallbackFn; typedef uint16_t CALLBACKID; SHWindow(); @@ -103,7 +106,7 @@ namespace SHADE void SetMousePosition(unsigned x, unsigned y); //unsigned GetBGColor(); - + void SetBGColor(unsigned color); void Minimize(); @@ -123,6 +126,9 @@ namespace SHADE CALLBACKID RegisterWindowSizeCallback(WindowResizeCallbackFn); void UnregisterWindowSizeCallback(CALLBACKID const& callbackid); + CALLBACKID RegisterWindowCloseCallback(WindowCloseCallbackFn); + void UnregisterWindowCloseCallback(CALLBACKID const& callbackid); + bool IsMinimized() const { return wndData.isMinimised; } protected: static LRESULT CALLBACK WndProcStatic(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); @@ -154,10 +160,13 @@ namespace SHADE HFONT font; std::unordered_map windowResizeCallbacks; + std::unordered_map windowCloseCallbacks; CALLBACKID windowResizeCallbackCount{}; + CALLBACKID windowCloseCallbackCount{}; //TODO: Shift to events abstraction void OnCreate(HWND hwnd, LPCREATESTRUCT create_struct); + void OnClose(); void OnDestroy(); //void OnFileDrop(HDROP drop); void OnSize(UINT msg, UINT type, SIZE size); diff --git a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp index e2cd1e4b..5f961de4 100644 --- a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp +++ b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp @@ -390,6 +390,13 @@ RTTR_REGISTRATION using namespace SHADE; using namespace rttr; + registration::enumeration("RigidBody Type") + ( + value("Static", SHRigidBodyComponent::Type::STATIC), + value("Dynamic", SHRigidBodyComponent::Type::DYNAMIC), + value("Kinematic", SHRigidBodyComponent::Type::KINEMATIC) + ); + registration::class_("RigidBody Component") .property("Type" , &SHRigidBodyComponent::GetType , &SHRigidBodyComponent::SetType ) .property("Mass" , &SHRigidBodyComponent::GetMass , &SHRigidBodyComponent::SetMass ) diff --git a/SHADE_Engine/src/Resource/ResourceLibrary.cpp b/SHADE_Engine/src/Resource/ResourceLibrary.cpp index 5a3ad9fe..b215b591 100644 --- a/SHADE_Engine/src/Resource/ResourceLibrary.cpp +++ b/SHADE_Engine/src/Resource/ResourceLibrary.cpp @@ -8,9 +8,9 @@ namespace SHADE ResourceManager::~ResourceManager() { // Delete all resources libraries - for (const auto& deleter : deleters) + for (auto iter = deleters.rbegin(); iter != deleters.rend(); ++iter) { - deleter(); + (*iter)(); } deleters.clear(); } diff --git a/SHADE_Engine/src/Resource/ResourceLibrary.h b/SHADE_Engine/src/Resource/ResourceLibrary.h index 4588b9fe..a5bf0a67 100644 --- a/SHADE_Engine/src/Resource/ResourceLibrary.h +++ b/SHADE_Engine/src/Resource/ResourceLibrary.h @@ -118,7 +118,7 @@ namespace SHADE /// Handle to the resource object. /// Read-only reference to the resource object. template - const T& Get(Handle handle) const; + const T& Get(Handle handle) const; private: /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.cpp b/SHADE_Engine/src/Scene/SHSceneGraph.cpp index da2dcffd..3fe85809 100644 --- a/SHADE_Engine/src/Scene/SHSceneGraph.cpp +++ b/SHADE_Engine/src/Scene/SHSceneGraph.cpp @@ -90,10 +90,15 @@ namespace SHADE #endif // Go through the map and release all the nodes - for (auto* node : entityNodeMap | std::views::values) - ReleaseNode(node); + for (auto*& node : entityNodeMap | std::views::values) + { + delete node; + node = nullptr; + } - delete root; + entityNodeMap.clear(); + + //delete root; #ifdef _DEBUG SHLOG_INFO("Scene Graph Destroyed Successfully!") diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index d65eaf64..65f445a6 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -153,6 +153,16 @@ namespace SHADE csEditorRenderScripts(entity); } + void SHScriptEngine::UndoScriptInspectorChanges() const + { + csEditorUndo(); + } + + void SHScriptEngine::RedoScriptInspectorChanges() const + { + csEditorRedo(); + } + /*-----------------------------------------------------------------------------------*/ /* Static Utility Functions */ /*-----------------------------------------------------------------------------------*/ @@ -400,6 +410,18 @@ namespace SHADE DEFAULT_CSHARP_NAMESPACE + ".Editor", "RenderScriptsInInspector" ); + csEditorUndo = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".Editor", + "Undo" + ); + csEditorRedo = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".Editor", + "Redo" + ); } void SHScriptEngine::registerEvents() diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.h b/SHADE_Engine/src/Scripting/SHScriptEngine.h index 710421e8..239d6b90 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.h +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.h @@ -171,6 +171,14 @@ namespace SHADE /// /// The Entity to render the Scripts of. void RenderScriptsInInspector(EntityID entity) const; + /// + /// Performs an undo for script inspector changes if it exists. + /// + void UndoScriptInspectorChanges() const; + /// + /// Performs a redo for script inspector changes if it exists. + /// + void RedoScriptInspectorChanges() const; /*-----------------------------------------------------------------------------*/ /* Static Utility Functions */ @@ -243,9 +251,8 @@ namespace SHADE CsScriptSerialiseYamlFuncPtr csScriptDeserialiseYaml = nullptr; // - Editor CsScriptEditorFuncPtr csEditorRenderScripts = nullptr; - // Delegates - /*ECS::EntityEvent::Delegate onEntityCreate; - ECS::EntityEvent::Delegate onEntityDestroy;*/ + CsFuncPtr csEditorUndo = nullptr; + CsFuncPtr csEditorRedo = nullptr; /*-----------------------------------------------------------------------------*/ /* Event Handler Functions */ diff --git a/SHADE_Managed/premake5.lua b/SHADE_Managed/premake5.lua index 9724c296..052be24a 100644 --- a/SHADE_Managed/premake5.lua +++ b/SHADE_Managed/premake5.lua @@ -30,7 +30,8 @@ project "SHADE_Managed" "%{IncludeDir.imguizmo}", "%{IncludeDir.imnodes}", "%{IncludeDir.yamlcpp}", - "%{IncludeDir.RTTR}/include", + "%{IncludeDir.RTTR}/include", + "%{IncludeDir.dotnet}\\include", "%{wks.location}/SHADE_Engine/src" } @@ -85,3 +86,8 @@ project "SHADE_Managed" optimize "On" defines{"_RELEASE"} links{"librttr_core.lib"} + + filter "configurations:Publish" + optimize "On" + defines{"_RELEASE"} + links{"librttr_core.lib"} diff --git a/SHADE_Managed/src/Editor/Editor.cxx b/SHADE_Managed/src/Editor/Editor.cxx index 629c9e65..735f8c2c 100644 --- a/SHADE_Managed/src/Editor/Editor.cxx +++ b/SHADE_Managed/src/Editor/Editor.cxx @@ -3,7 +3,7 @@ \author Tng Kah Wei, kahwei.tng, 390009620 \par email: kahwei.tng\@digipen.edu \date Sep 27, 2022 -\brief Contains the definition of the functions for the ScriptStore managed +\brief Contains the definition of the functions for the Editor managed static class. Note: This file is written in C++17/CLI. @@ -16,6 +16,8 @@ of DigiPen Institute of Technology is prohibited. #include "SHpch.h" // Primary Header #include "Editor/Editor.hxx" +// STL Includes +#include // External Dependencies #include "Editor/SHEditorUI.h" // Project Headers @@ -25,6 +27,8 @@ of DigiPen Institute of Technology is prohibited. #include "Utility/Debug.hxx" #include "Serialisation/ReflectionUtilities.hxx" #include "Editor/IconsMaterialDesign.h" +#include "Editor/Command/SHCommandManager.h" +#include "Editor/Command/SHCommand.hpp" // Using Directives using namespace System; @@ -48,9 +52,11 @@ using namespace System::Collections::Generic; (field->FieldType == MANAGED_TYPE::typeid) \ { \ NATIVE_TYPE val = safe_cast(field->GetValue(object)); \ + NATIVE_TYPE oldVal = val; \ if (SHEditorUI::FUNC(Convert::ToNative(field->Name), val)) \ { \ field->SetValue(object, val); \ + registerUndoAction(object, field, val, oldVal); \ } \ } \ /// @@ -69,9 +75,11 @@ using namespace System::Collections::Generic; (field->FieldType == MANAGED_TYPE::typeid) \ { \ NATIVE_TYPE val = Convert::ToNative(safe_cast(field->GetValue(object))); \ + NATIVE_TYPE oldVal = val; \ if (SHEditorUI::FUNC(Convert::ToNative(field->Name), val)) \ { \ field->SetValue(object, Convert::ToCLI(val)); \ + registerUndoAction(object, field, Convert::ToCLI(val), Convert::ToCLI(oldVal)); \ } \ } \ @@ -105,26 +113,43 @@ namespace SHADE SAFE_NATIVE_CALL_END_N("SHADE_Managed.Editor.RenderScriptsInInspector") } - void Editor::RenderScriptAddButton(Entity entity) - { - // Get list of Scripts - auto scriptTypes = ScriptStore::GetAvailableScriptList(); + void Editor::RenderScriptAddButton(Entity entity) + { + // Get list of Scripts + auto scriptTypes = ScriptStore::GetAvailableScriptList(); - // Define pop up - if (SHEditorUI::BeginMenu("Add Script", ICON_MD_LIBRARY_ADD)) - { - for each (Type ^ type in scriptTypes) - { - if (SHEditorUI::Selectable(Convert::ToNative(type->Name))) - { - // Add the script - ScriptStore::AddScriptViaName(entity, type->Name); - } - } + // Define pop up + if (SHEditorUI::BeginMenu("Add Script", ICON_MD_LIBRARY_ADD)) + { + for each (Type ^ type in scriptTypes) + { + if (SHEditorUI::Selectable(Convert::ToNative(type->Name))) + { + // Add the script + ScriptStore::AddScriptViaName(entity, type->Name); + } + } - SHEditorUI::EndMenu(); - } - } + SHEditorUI::EndMenu(); + } + } + + /*---------------------------------------------------------------------------------*/ + /* UndoRedoStack Functions */ + /*---------------------------------------------------------------------------------*/ + void Editor::Undo() + { + SAFE_NATIVE_CALL_BEGIN + actionStack.Undo(); + SAFE_NATIVE_CALL_END_N("SHADE_Managed.Editor.Undo") + } + + void Editor::Redo() + { + SAFE_NATIVE_CALL_BEGIN + actionStack.Redo(); + SAFE_NATIVE_CALL_END_N("SHADE_Managed.Editor.Redo") + } /*---------------------------------------------------------------------------------*/ /* Helper Functions */ @@ -192,9 +217,11 @@ namespace SHADE } int val = safe_cast(field->GetValue(object)); + int oldVal = val; if (SHEditorUI::InputEnumCombo(Convert::ToNative(field->Name), val, nativeEnumNames)) { field->SetValue(object, val); + registerUndoAction(object, field, val, oldVal); } } else if RENDER_FIELD_CASTED(Vector2, SHVec2, InputVec2) @@ -210,9 +237,11 @@ namespace SHADE // Actual Field std::string val = Convert::ToNative(stringVal); + std::string oldVal = val; if (SHEditorUI::InputTextField(Convert::ToNative(field->Name), val)) { field->SetValue(object, Convert::ToCLI(val)); + registerUndoAction(object, field, Convert::ToCLI(val), Convert::ToCLI(oldVal)); } } } @@ -231,4 +260,18 @@ namespace SHADE } } + void Editor::registerUndoAction(System::Object^ object, System::Reflection::FieldInfo^ field, System::Object^ newData, System::Object^ oldData) + { + // Create command and add it into the undo stack + UndoRedoStack::Command cmd; + cmd.Field = field; + cmd.Object = object; + cmd.NewData = newData; + cmd.OldData = oldData; + actionStack.Add(cmd); + + // Inform the C++ Undo-Redo stack + SHCommandManager::RegisterCommand(std::reinterpret_pointer_cast(std::make_shared())); + } + } diff --git a/SHADE_Managed/src/Editor/Editor.hxx b/SHADE_Managed/src/Editor/Editor.hxx index 188da660..c4800645 100644 --- a/SHADE_Managed/src/Editor/Editor.hxx +++ b/SHADE_Managed/src/Editor/Editor.hxx @@ -16,6 +16,7 @@ of DigiPen Institute of Technology is prohibited. // Project Includes #include "Engine/Entity.hxx" #include "Scripts/Script.hxx" +#include "UndoRedoStack.hxx" namespace SHADE { @@ -36,15 +37,26 @@ namespace SHADE /// rendering code. /// /// The Entity to render the Scripts of. - static void RenderScriptsInInspector(Entity entity); - /// - /// Renders a dropdown button that allows for the addition of PlushieScripts - /// onto the specified Entity. - /// - /// The Entity to add PlushieScripts to. - static void RenderScriptAddButton(Entity entity); + static void RenderScriptsInInspector(Entity entity); + /// + /// Renders a dropdown button that allows for the addition of PlushieScripts + /// onto the specified Entity. + /// + /// The Entity to add PlushieScripts to. + static void RenderScriptAddButton(Entity entity); + + /*-----------------------------------------------------------------------------*/ + /* UndoRedoStack Functions */ + /*-----------------------------------------------------------------------------*/ + static void Undo(); + static void Redo(); + + private: + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + static UndoRedoStack actionStack; - private: /*-----------------------------------------------------------------------------*/ /* Helper Functions */ /*-----------------------------------------------------------------------------*/ @@ -73,5 +85,6 @@ namespace SHADE /// The Entity to render the Scripts of. /// The Script to render the inspector for. static void renderScriptContextMenu(Entity entity, Script^ script); + static void registerUndoAction(System::Object^ object, System::Reflection::FieldInfo^ field, System::Object^ newData, System::Object^ oldData); }; } diff --git a/SHADE_Managed/src/Editor/UndoRedoStack.cxx b/SHADE_Managed/src/Editor/UndoRedoStack.cxx new file mode 100644 index 00000000..08e289cc --- /dev/null +++ b/SHADE_Managed/src/Editor/UndoRedoStack.cxx @@ -0,0 +1,69 @@ +/************************************************************************************//*! +\file UndoRedoStack.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 29, 2022 +\brief Contains the definition of the functions for the UndoRedoStack managed + class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "UndoRedoStack.hxx" +// External Dependencies +#include "Editor/SHEditorUI.h" +// Project Headers + +namespace SHADE +{ + bool UndoRedoStack::UndoActionPresent::get() + { + return commandStack->Count > 0 && latestActionIndex >= 0; + } + + bool UndoRedoStack::RedoActionPresent::get() + { + return latestActionIndex >= 0 && latestActionIndex < commandStack->Count - 1; + } + + void UndoRedoStack::Add(Command command) + { + // Erase any other actions ahead of the current action + if (latestActionIndex >= 0 && latestActionIndex < commandStack->Count - 1) + { + commandStack->RemoveRange(latestActionIndex, commandStack->Count - latestActionIndex); + } + + // Add the command + commandStack->Add(command); + + // Set the latest command + latestActionIndex = commandStack->Count - 1; + } + + void UndoRedoStack::Undo() + { + if (!UndoActionPresent) + return; + + Command cmd = commandStack[latestActionIndex]; + cmd.Field->SetValue(cmd.Object, cmd.OldData); + --latestActionIndex; + } + + void UndoRedoStack::Redo() + { + if (!RedoActionPresent) + return; + + Command cmd = commandStack[latestActionIndex]; + cmd.Field->SetValue(cmd.Object, cmd.NewData); + ++latestActionIndex; + } +} diff --git a/SHADE_Managed/src/Editor/UndoRedoStack.hxx b/SHADE_Managed/src/Editor/UndoRedoStack.hxx new file mode 100644 index 00000000..4c525228 --- /dev/null +++ b/SHADE_Managed/src/Editor/UndoRedoStack.hxx @@ -0,0 +1,75 @@ +/************************************************************************************//*! +\file UndoRedoStack.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 29, 2022 +\brief Contains the definition of the managed UndoRedoStack class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +namespace SHADE +{ + /// + /// Class that is able to store a stack of actions that can be done and redone. + /// + private ref class UndoRedoStack sealed + { + public: + /*-----------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Command for the stack that represents a data modification. + /// + value struct Command + { + public: + System::Object^ Object; + System::Reflection::FieldInfo^ Field; + System::Object^ NewData; + System::Object^ OldData; + }; + + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ + /// + /// True if there is an undoable action in the stack. + /// + property bool UndoActionPresent { bool get(); } + /// + /// True if there is a redoable action in the stack. + /// + property bool RedoActionPresent { bool get(); } + + /*-----------------------------------------------------------------------------*/ + /* Usage Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Adds a command onto the stack. + /// + /// + void Add(Command command); + /// + /// Undos the last added command if it exists. + /// + void Undo(); + /// + /// Redoes the last undo-ed command if it exists. + /// + void Redo(); + + private: + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + int latestActionIndex = -1; + System::Collections::Generic::List^ commandStack = gcnew System::Collections::Generic::List(); + }; +}