#ifndef _VK_MXMODEL_H__ #define _VK_MXMODEL_H__ #include "config.h" #ifndef WITH_MOLTEN #include "volk.h" #include <SDL_vulkan.h> #else #include <SDL_vulkan.h> #include <vulkan/vulkan.h> #endif #include "exception.hpp" #include "util.hpp" #include "vk_model.hpp" #include "vk_text.hpp" #include <algorithm> #include <array> #include <cmath> #include <cstdlib> #include <cstring> #include <format> #include <fstream> #include <glm/ext/matrix_clip_space.hpp> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <iostream> #include <optional> #include <set> #include <stdexcept> #include <vector> #ifndef VK_CHECK_RESULT #define VK_CHECK_RESULT(f) \ { \ VkResult res = (f); \ if (res != VK_SUCCESS) { \ throw mx::Exception(std::format("Fatal : VkResult is \"{}\" in {} at line {}", static_cast<int>(res), __FILE__, __LINE__)); \ } \ } #endif namespace mx { using Vertex = VKVertex; struct QueueFamilyIndices { std::optional<uint32_t> graphicsFamily; std::optional<uint32_t> presentFamily; bool isComplete() { return graphicsFamily.has_value() && presentFamily.has_value(); } }; struct SwapChainSupportDetails { VkSurfaceCapabilitiesKHR capabilities; std::vector<VkSurfaceFormatKHR> formats; std::vector<VkPresentModeKHR> presentModes; }; struct UniformBufferObject { alignas(16) glm::mat4 model; alignas(16) glm::mat4 view; alignas(16) glm::mat4 proj; alignas(16) glm::vec4 params; alignas(16) glm::vec4 color; }; class ModelViewer { public: ModelViewer() = default; ModelViewer(const std::string &title, int width, int height, bool full = false); virtual ~ModelViewer() {} void initWindow(const std::string &title, int width, int height, bool full = false); void initVulkan(); void setPath(const std::string &path); void setModelFile(const std::string &filename); void setTextureFile(const std::string &filename); void setTexturePath(const std::string &path); void loop(); void cleanup(); void event(SDL_Event &e); void draw(); void quit(); int w = 0, h = 0; mxUtil util; protected: bool active = true; bool wireframe = false; std::string modelFilename; std::string textureFilename; std::string textureDirPath; MXModel model; bool rotationEnabled = true; float frozenAutoAngle = 0.0f; float lastTime = 0.0f; VkInstance instance = VK_NULL_HANDLE; VkSurfaceKHR surface = VK_NULL_HANDLE; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; VkDevice device = VK_NULL_HANDLE; VkQueue graphicsQueue = VK_NULL_HANDLE; VkQueue presentQueue = VK_NULL_HANDLE; VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE; VkSwapchainKHR swapChain = VK_NULL_HANDLE; std::vector<VkImage> swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; std::vector<VkImageView> swapChainImageViews; std::vector<VkBuffer> uniformBuffers; std::vector<VkDeviceMemory> uniformBuffersMemory; std::vector<void *> uniformBuffersMapped; VkRenderPass renderPass = VK_NULL_HANDLE; VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; VkPipeline fillPipeline = VK_NULL_HANDLE; VkPipeline wirePipeline = VK_NULL_HANDLE; std::vector<VkFramebuffer> swapChainFramebuffers; VkCommandPool commandPool = VK_NULL_HANDLE; std::vector<VkCommandBuffer> commandBuffers; VkSemaphore imageAvailableSemaphore = VK_NULL_HANDLE; VkSemaphore renderFinishedSemaphore = VK_NULL_HANDLE; VkImage textureImage = VK_NULL_HANDLE; VkDeviceMemory textureImageMemory = VK_NULL_HANDLE; VkImageView textureImageView = VK_NULL_HANDLE; VkSampler textureSampler = VK_NULL_HANDLE; struct VkTexture { VkImage image = VK_NULL_HANDLE; VkDeviceMemory memory = VK_NULL_HANDLE; VkImageView view = VK_NULL_HANDLE; uint32_t w = 0, h = 0; }; std::vector<VkTexture> textures; VkDescriptorPool descriptorPool = VK_NULL_HANDLE; std::vector<VkDescriptorSet> descriptorSets; VkImage depthImage = VK_NULL_HANDLE; VkDeviceMemory depthImageMemory = VK_NULL_HANDLE; VkImageView depthImageView = VK_NULL_HANDLE; VkFormat depthFormat = VK_FORMAT_D32_SFLOAT; float cameraDistance = 5.0f; float rotationX = 0.0f; float rotationY = 0.0f; float modelRenderScale = 1.0f; glm::vec3 modelCenterOffset = glm::vec3(0.0f); bool mouseDown = false; int lastMouseX = 0, lastMouseY = 0; bool autoRotate = true; bool showHelp = true; uint32_t texWidth = 0, texHeight = 0; std::unique_ptr<VKText> textRenderer; VkPipeline textPipeline = VK_NULL_HANDLE; VkPipelineLayout textPipelineLayout = VK_NULL_HANDLE; VkDescriptorSetLayout textDescriptorSetLayout = VK_NULL_HANDLE; VkDescriptorPool textDescriptorPool = VK_NULL_HANDLE; SDL_Window *window = nullptr; void createInstance(); void createSurface(); void pickPhysicalDevice(); void createLogicalDevice(); void createSwapChain(); void createImageViews(); void createRenderPass(); void createDepthResources(); void createDescriptorSetLayout(); void createGraphicsPipelines(); VkPipeline buildPipeline(VkPolygonMode polyMode); void createFramebuffers(); void createCommandPool(); void createCommandBuffers(); void createSyncObjects(); void createUniformBuffers(); void loadModelData(); void loadTextureData(); void createTextureImageView(); void createTextureSampler(); void createDescriptorPool(); void createDescriptorSets(); void cleanupSwapChain(); void recreateSwapChain(); QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device); VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR> &availableFormats); VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR> &availablePresentModes); VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR &capabilities); bool isDeviceSuitable(VkPhysicalDevice device); SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device); VkShaderModule createShaderModule(const std::vector<char> &code); void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VkDeviceMemory &bufferMemory); uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size); void createImage(uint32_t w, uint32_t h, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage &image, VkDeviceMemory &imageMemory); void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout); void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t w, uint32_t h); VkCommandBuffer beginSingleTimeCommands(); void endSingleTimeCommands(VkCommandBuffer commandBuffer); VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags); VkFormat findSupportedFormat(const std::vector<VkFormat> &candidates, VkImageTiling tiling, VkFormatFeatureFlags features); VkFormat findDepthFormat(); void createTextDescriptorSetLayout(); void createTextPipeline(); void createTextDescriptorPool(); void printText(const std::string &text, int x, int y, const SDL_Color &col); void clearTextQueue(); }; } // namespace mx #endif