text: /**
   * @package H2M
   * @author  Yan Chernikov (TheCherno)
   * @licence Apache License 2.0
   */
  
  #define _CRT_SECURE_NO_WARNINGS
  
  #pragma once
  
  #include "H2M/Core/BaseH2M.h"
  #include "H2M/Core/AssertH2M.h"
  
  #include "H2M/Platform/Vulkan/VulkanH2M.h"
  #include "H2M/Platform/Vulkan/VulkanDeviceH2M.h"
  #include "H2M/Platform/Vulkan/VulkanAllocatorH2M.h"
  
  #include "VulkanMemoryAllocator/vk_mem_alloc.h"
  
  #include <vector>
  
  struct GLFWwindow;
  
  
  namespace H2M
  {
  
  	class VulkanSwapChainH2M
  	{
  	public:
  		VulkanSwapChainH2M() = default;
  
  		void Init(VkInstance instance, const RefH2M<VulkanDeviceH2M>& device);
  		void InitSurface(GLFWwindow* windowHandle);
  		void Create(uint32_t* width, uint32_t* height, bool vsync = false);
  		
  		void OnResize(uint32_t width, uint32_t height);
  
  		void BeginFrame();
  		void Present();
  
  		uint32_t GetImageCount() const { return m_ImageCount; }
  
  		uint32_t GetWidth() const { return m_Width; }
  		uint32_t GetHeight() const { return m_Height; }
  
  		VkRenderPass GetRenderPass() { return m_RenderPass; }
  
  		VkFramebuffer GetCurrentFramebuffer() { return GetFramebuffer(m_CurrentBufferIndex); }
  		VkCommandBuffer GetCurrentDrawCommandBuffer() { return GetDrawCommandBuffer(m_CurrentBufferIndex); }
  
  		VkFormat GetColorFormat() { return m_ColorFormat; }
  
  		uint32_t GetCurrentBufferIndex() const { return m_CurrentBufferIndex; }
  		VkFramebuffer GetFramebuffer(uint32_t index)
  		{
  			H2M_CORE_ASSERT(index < m_ImageCount);
  			return m_Framebuffers[index];
  		}
  		VkCommandBuffer GetDrawCommandBuffer(uint32_t index)
  		{
  			H2M_CORE_ASSERT(index < m_ImageCount);
  			return m_DrawCommandBuffers[index];
  		}
  
  		void Cleanup();
  	private:
  		VkResult AcquireNextImage(VkSemaphore presentCompleteSemaphore, uint32_t* imageIndex);
  		VkResult QueuePresent(VkQueue queue, uint32_t imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE);
  
  		void CreateFramebuffer();
  		void CreateDepthStencil();
  		void CreateDrawBuffers();
  		void FindImageFormatAndColorSpace();
  
  	private:
  		VkInstance m_Instance;
  		RefH2M<VulkanDeviceH2M> m_Device;
  		VulkanAllocatorH2M m_Allocator;
  
  		bool m_VSync = false;
  
  		VkFormat m_ColorFormat;
  		VkColorSpaceKHR m_ColorSpace;
  
  		VkSwapchainKHR m_SwapChain = nullptr;
  		uint32_t m_ImageCount = 0;
  		std::vector<VkImage> m_Images;
  
  		struct SwapChainBuffer
  		{
  			VkImage image;
  			VkImageView view;
  		};
  		std::vector<SwapChainBuffer> m_Buffers;
  
  		VkFormat m_DepthBufferFormat;
  		struct
  		{
  			VkImage Image;
  			VkDeviceMemory DeviceMemory;
  			VmaAllocation MemoryAlloc;
  			VkImageView ImageView;
  		} m_DepthStencil;
  
  		std::vector<VkFramebuffer> m_Framebuffers;
  		VkCommandPool m_CommandPool;
  		std::vector<VkCommandBuffer> m_DrawCommandBuffers;
  
  		struct
  		{
  			// Swap chain
  			VkSemaphore PresentComplete;
  			// Command buffer
  			VkSemaphore RenderComplete;
  		} m_Semaphores;
  		VkSubmitInfo m_SubmitInfo;
  
  		std::vector<VkFence> m_WaitFences;
  
  		VkRenderPass m_RenderPass;
  		uint32_t m_CurrentBufferIndex = 0;
  
  		uint32_t m_QueueNodeIndex = UINT32_MAX;
  		uint32_t m_Width = 0, m_Height = 0;
  
  		VkSurfaceKHR m_Surface;
  
  		friend class VulkanContext;
  	};
  }
  