#pragma once #include "terminal.h" #include "sdl2Window.h" const std::string MODEL_PATH = "/home/nathan/Projects/terminal/assets/viking_room.obj"; const std::string TEXTURE_PATH = "/home/nathan/Pictures/Mountain.png"; struct QueueFamilyIndices { std::optional graphicsFamily; std::optional presentFamily; bool isComplete() { return graphicsFamily.has_value() && presentFamily.has_value(); } }; struct SwapChainSupportDetails { VkSurfaceCapabilitiesKHR capabilities; std::vector formats; std::vector presentModes; }; static std::vector readFile(const std::string& filename) { std::ifstream file(filename, std::ios::ate | std::ios::binary); if (!file.is_open()) { throw std::runtime_error("failed to open file!"); } size_t fileSize = (size_t) file.tellg(); std::vector buffer(fileSize); file.seekg(0); file.read(buffer.data(), fileSize); file.close(); return buffer; } struct Vertex { glm::vec3 pos; glm::vec3 color; glm::vec2 texCoord; static VkVertexInputBindingDescription getBindingDescription() { VkVertexInputBindingDescription bindingDescription{}; bindingDescription.binding = 0; bindingDescription.stride = sizeof(Vertex); bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; return bindingDescription; } static std::array getAttributeDescriptions() { std::array attributeDescriptions{}; attributeDescriptions[0].binding = 0; attributeDescriptions[0].location = 0; attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT; attributeDescriptions[0].offset = offsetof(Vertex, pos); attributeDescriptions[1].binding = 0; attributeDescriptions[1].location = 1; attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; attributeDescriptions[1].offset = offsetof(Vertex, color); attributeDescriptions[2].binding = 0; attributeDescriptions[2].location = 2; attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT; attributeDescriptions[2].offset = offsetof(Vertex, texCoord); return attributeDescriptions; } }; struct UniformBufferObject { alignas(16) glm::mat4 model; alignas(16) glm::mat4 view; alignas(16) glm::mat4 proj; }; const std::vector vertices = { {{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}, {{0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}}, {{0.5f, 0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}, {{-0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}, {{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}, {{0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}}, {{0.5f, 0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}, {{-0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}} }; const std::vector indices = { 0, 1, 2, 2, 3, 0, 4, 5, 6, 6, 7, 4 }; class Renderer { public: Renderer(); ~Renderer(); inline VkInstance getInstance() { return instance; } inline VkPhysicalDevice getPhysicalDevice() { return physicalDevice; } inline VkDevice getDevice() { return device; } uint32_t getQueueFamily(); inline VkQueue getGraphicsQueue() { return graphicsQueue; } inline VkQueue getPresentQueue() { return presentQueue; } inline VkSurfaceKHR getSurface() { return surface; } inline VkRenderPass getRenderPass() { return renderPass; } inline VkDescriptorPool getDescriptorPool() { return descriptorPool; } inline VkCommandBuffer getCommandBuffer(int frame) { return commandBuffers[frame]; } inline VkPipeline getPipeline() { return graphicsPipeline; } inline int getNumImages() { return MAX_FRAMES_IN_FLIGHT; } inline int getFrame() { return currentFrame; } inline VkSampleCountFlagBits getMSAASamples() { return msaaSamples; } private: const int MAX_FRAMES_IN_FLIGHT = 2; VkInstance instance; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; VkSurfaceKHR surface; VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; VkRenderPass renderPass; VkDescriptorPool descriptorPool; std::vector descriptorSets; VkDescriptorSetLayout descriptorSetLayout; VkPipelineLayout pipelineLayout; VkPipeline graphicsPipeline; std::vector swapChainFramebuffers; std::vector swapChainImageViews; VkCommandPool commandPool; std::vector commandBuffers; std::vector imageAvailableSemaphores; std::vector renderFinishedSemaphores; std::vector inFlightFences; uint32_t currentFrame = 0; VkBuffer vertexBuffer; VkDeviceMemory vertexBufferMemory; VkBuffer indexBuffer; VkDeviceMemory indexBufferMemory; std::vector uniformBuffers; std::vector uniformBuffersMemory; std::vector uniformBuffersMapped; VkImage textureImage; VkDeviceMemory textureImageMemory; VkImageView textureImageView; VkSampler textureSampler; VkImage depthImage; VkDeviceMemory depthImageMemory; VkImageView depthImageView; VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; VkImage colorImage; VkDeviceMemory colorImageMemory; VkImageView colorImageView; VkResult err; bool enableValidationLayers = false; const std::vector deviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; public: void init(); void shutdown(); void draw(); void createInstance(); void pickPhysicalDevice(); void createLogicalDevice(); void createSurface(); void createSwapChain(); void createImageViews(); void createDescriptorPool(); void createDescriptorSets(); void createDescriptorSetLayout(); void createGraphicsPipeline(); void createRenderPass(); void createFramebuffers(); void createCommandPool(); void createVertexBuffer(); void createIndexBuffer(); void createUniformBuffers(); void updateUniformBuffer(uint32_t); void createBuffer(VkDeviceSize, VkBufferUsageFlags, VkMemoryPropertyFlags, VkBuffer&, VkDeviceMemory&); void createCommandBuffer(); void recordCommandBuffer(VkCommandBuffer, uint32_t); void createSyncObjects(); void loadModel(); bool hasStencilComponent(VkFormat); VkFormat findDepthFormat(); VkFormat findSupportedFormat(const std::vector&, VkImageTiling, VkFormatFeatureFlags); void createDepthResources(); VkImageView createImageView(VkImage, VkFormat, VkImageAspectFlags); void copyBufferToImage(VkBuffer, VkImage, uint32_t, uint32_t); void createTextureSampler(); void createTextureImageView(); void transitionImageLayout(VkImage, VkFormat, VkImageLayout, VkImageLayout); VkCommandBuffer beginSingleTimeCommands(); void endSingleTimeCommands(VkCommandBuffer); void createImage(uint32_t, uint32_t, VkFormat, VkImageTiling, VkImageUsageFlags, VkMemoryPropertyFlags, VkImage&, VkDeviceMemory&); void createTextureImage(); VkSampleCountFlagBits getMaxUsableSampleCount(); void copyBuffer(VkBuffer, VkBuffer, VkDeviceSize); uint32_t findMemoryType(uint32_t, VkMemoryPropertyFlags); void recreateSwapChain(); void cleanupSwapChain(); VkShaderModule createShaderModule(const std::vector&); VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR&); VkPresentModeKHR chooseSwapPresentMode(const std::vector&); VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector&); SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice); bool checkDeviceExtensionSupport(VkPhysicalDevice); QueueFamilyIndices findQueueFamilies(VkPhysicalDevice); bool isDeviceSuitable(VkPhysicalDevice); bool isExtensionAvailable(const std::vector&, const char*); void check_vk_result(); };