// // Created by timo on 03.04.25. // #ifndef VULKAN_APP_H #define VULKAN_APP_H #define GLFW_INCLUDE_VULKAN #include #define GLM_FORCE_RADIANS #define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES #define GLM_FORCE_DEPTH_ZERO_TO_ONE #include #include #define GLM_ENABLE_EXPERIMENTAL #include #include #include #include #include #include #include #include #include #include #include namespace vapp{ // Change here for other presentMode const VkPresentModeKHR WISHED_PRESENT_MODE = VK_PRESENT_MODE_MAILBOX_KHR; 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; } bool operator==(const Vertex &other) const{ return pos == other.pos && color == other.color && texCoord == other.texCoord; } }; /* const std::vector vertices = { {{-0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f}}, {{0.5f, -0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f}}, {{0.5f, 0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 1.0f}}, {{-0.5f, 0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}}, {{-0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f}}, {{0.5f, -0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f}}, {{0.5f, 0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 1.0f}}, {{-0.5f, 0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}} }; // uint16_t also possible -> change in vkCmdBindIndexBuffer also const std::vector indices = { 0, 1, 2, 2, 3, 0, 4, 5, 6, 6, 7, 4 }; */ // END Remove struct UniformBufferObject{ alignas(16) glm::mat4 model; alignas(16) glm::mat4 view; alignas(16) glm::mat4 proj; }; struct QueueFamilyIndices{ std::optional graphicsFamily; std::optional presentFamily; bool isComplete(){ return graphicsFamily.has_value(); } }; struct SwapChainSupportDetails{ VkSurfaceCapabilitiesKHR capabilities; std::vector formats; std::vector presentModes; }; static std::vector readFile(const std::string& filename); static std::array getAttributeDescription(); class Vulkan{ private: #pragma region PrivateFields GLFWwindow *window; uint32_t _width, _height; VkInstance instance; VkDebugUtilsMessengerEXT debugMessenger; VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; std::vector swapChainImageViews; VkRenderPass renderPass; VkDescriptorSetLayout descriptorSetLayout; VkPipelineLayout pipelineLayout; VkPipeline graphicsPipeline; VkCommandPool commandPool; std::vector commandBuffers; std::vector imageAvailableSemaphores, renderFinishedSemaphores; std::vector inFlightFences; std::vector swapChainFramebuffers; const int MAX_FRAMES_IN_FLIGHT = 2; uint32_t currentFrame = 0; std::vector vertices; std::vector indices; VkBuffer vertexBuffer; VkDeviceMemory vertexBufferMemory; VkBuffer indexBuffer; VkDeviceMemory indexBufferMemory; std::vector uniformBuffers; std::vector uniformBuffersMemory; std::vector uniformBuffersMapped; VkDescriptorPool descriptorPool; std::vector descriptorSets; int32_t mipLevels; VkImage textureImage; VkDeviceMemory textureImageMemory; VkImageView textureImageView; VkSampler textureSampler; VkImage depthImage; VkDeviceMemory depthImageMemory; VkImageView depthImageView; #pragma endregion #pragma region PrivateFunctions bool checkValidationLayerSupport(); std::vector getRequiredExtensions(); void createInstance(); void setupDebugMessenger(); void pickPhysicalDevice(); void createLogicalDevice(); QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device); bool checkDeviceExtensionSupport(VkPhysicalDevice device); bool isDeviceSuitable(VkPhysicalDevice device); void createSurface(); SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device); VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats); VkPresentModeKHR chooseSwapPresentMode(const std::vector availablePresentModes); VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities); void createSwapChain(); void createImageViews(); void createDescriptorSetLayout(); void createGraphicsPipeline(); VkShaderModule createShaderModule(const std::vector& code); void createRenderPass(); void createFramebuffers(); void createCommandPool(); VkFormat findSupportedFormat(const std::vector &candidates, VkImageTiling tiling, VkFormatFeatureFlags features); VkFormat findDepthFormat(); void createDepthResources(); VkCommandBuffer beginSingleTimeCommands(); void endSingleTimeCommands(VkCommandBuffer commandBuffer); void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels); void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height); void createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory &imageMemory); void generateMipmaps(VkImage image, VkFormat imageFormat, int32_t texWidth, int32_t texHeight, uint32_t mipLevels); void createTextureImage(); VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, uint32_t mipLevels); void createTextureImageView(); void createTextureSampler(); uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VkDeviceMemory &bufferMemory); void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size); void copyBufferOld(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size); void loadModel(); void createVertexBuffer(); void createIndexBuffer(); void createUniformBuffers(); void createDescriptorPool(); void createDescriptorSets(); void createCommandBuffers(); void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex); void createSyncObjects(); void updateUniformBuffer(uint32_t currentFrame); void drawFrame(); void cleanupSwapChain(); void recreateSwapChain(); void initWindow(const char *windowName); void initVulkan(); void mainLoop(); void cleanup(); #pragma endregion public: #pragma region PublicFields #ifdef DEBUG const bool enableValidationLayers = true; #else const bool enableValidationLayers = false; #endif bool framebufferResized = false; std::string MODEL_PATH; std::string TEXTURE_PATH; #pragma endregion #pragma region PublicFunctions void run(const char *windowName, const uint32_t width = 800, const uint32_t height = 600); #pragma endregion }; } // vapp namespace std{ template<> struct hash{ size_t operator()(vapp::Vertex const &vertex) const{ return ((hash()(vertex.pos) ^ (hash()(vertex.color) << 1)) >> 1) ^ (hash()(vertex.texCoord) << 1); } }; } #endif //VULKAN_APP_H