MXVK Vulkan Framework 0.35.0
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
mxvk_model.hpp
Go to the documentation of this file.
1/**
2 * @file mxvk_model.hpp
3 * @brief Vulkan mesh loader and GPU buffer manager for MXVK.
4 */
5#pragma once
6
7#include <volk/volk.h>
8
9#include "mxvk_exception.hpp"
10
11#include <cstdint>
12#include <cstring>
13#include <string>
14#include <unordered_map>
15#include <vector>
16
17namespace mxvk {
18
19 /**
20 * @struct VKVertex
21 * @brief Vertex payload consumed by MXVK model shaders.
22 */
23 struct VKVertex {
24 float pos[3]{};
25 float texCoord[2]{};
26 float normal[3]{};
27
28 /** @brief Byte-wise equality used for index compression. */
29 bool operator==(const VKVertex &other) const { return std::memcmp(this, &other, sizeof(VKVertex)) == 0; }
30 };
31
32 /** @brief Hash functor for VKVertex. */
33 struct VKVertexHash {
34 std::size_t operator()(const VKVertex &v) const;
35 };
36
37 /**
38 * @struct SubMesh
39 * @brief One indexed sub-range that can reference a dedicated texture slot.
40 */
41 struct SubMesh {
42 uint32_t firstIndex = 0;
43 uint32_t indexCount = 0;
44 uint32_t textureIndex = 0;
45 std::string materialName;
46 };
47
48 /**
49 * @struct MXMaterial
50 * @brief Parsed subset of Wavefront MTL material fields.
51 */
52 struct MXMaterial {
53 std::string name;
54 float ka[3] = {0.2f, 0.2f, 0.2f};
55 float kd[3] = {0.8f, 0.8f, 0.8f};
56 float ks[3] = {0.0f, 0.0f, 0.0f};
57 float ns = 30.0f;
58 float d = 1.0f;
59 int illum = 2;
60 std::string map_kd;
61 };
62
63 /**
64 * @class MXModel
65 * @brief Loads OBJ/MXMOD meshes and uploads them to Vulkan buffers.
66 */
67 class MXModel {
68 public:
69 MXModel() = default;
70 ~MXModel() = default;
71
72 MXModel(const MXModel &) = delete;
73 MXModel &operator=(const MXModel &) = delete;
74 MXModel(MXModel &&other) noexcept;
75 MXModel &operator=(MXModel &&other) noexcept;
76
77 /**
78 * @brief Parse model data from disk into CPU-side arrays.
79 * @param path Path to .obj, .mxmod, or .mxmod.z model.
80 * @param positionScale Uniform scale applied to positions.
81 */
82 void load(const std::string &path, float positionScale = 1.0f);
83
84 /**
85 * @brief Parse model data and an optional texture manifest from disk.
86 * @param path Path to .obj, .mxmod, or .mxmod.z model.
87 * @param textureManifestPath Optional .txt/.tex or MTL-like texture manifest.
88 * @param textureBasePath Base path used to resolve relative texture paths.
89 * @param positionScale Uniform scale applied to positions.
90 */
91 void load(const std::string &path, const std::string &textureManifestPath, const std::string &textureBasePath, float positionScale = 1.0f);
92
93 /**
94 * @brief Export the loaded model as Wavefront OBJ plus MTL.
95 * @param objPath Output .obj path.
96 * @param mtlPath Optional output .mtl path. Defaults to objPath with .mtl extension.
97 */
98 void exportOBJ(const std::string &objPath, const std::string &mtlPath = "") const;
99
100 /**
101 * @brief Load a model/manifest pair and export it as Wavefront OBJ plus MTL.
102 */
103 static void exportOBJ(const std::string &modelPath, const std::string &textureManifestPath, const std::string &textureBasePath, const std::string &objPath, float positionScale = 1.0f);
104
105 /**
106 * @brief Upload parsed geometry to device-local GPU buffers.
107 * @param device Logical Vulkan device.
108 * @param physicalDevice Physical Vulkan device.
109 * @param commandPool Command pool used for transfer command buffer allocation.
110 * @param graphicsQueue Queue used to submit transfer commands.
111 */
112 void upload(VkDevice device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool, VkQueue graphicsQueue);
113
114 /**
115 * @brief Release owned GPU buffers.
116 * @param device Logical Vulkan device that owns these resources.
117 */
118 void cleanup(VkDevice device);
119
120 /**
121 * @brief Record one indexed draw for the full mesh.
122 * @param cmd Active command buffer.
123 */
124 void draw(VkCommandBuffer cmd) const;
125
126 /**
127 * @brief Record one indexed draw for a sub-mesh.
128 * @param cmd Active command buffer.
129 * @param index Sub-mesh index.
130 */
131 void drawSubMesh(VkCommandBuffer cmd, size_t index) const;
132
133 /** @brief Remove duplicate vertices and remap indices. */
134 void compressIndices();
135
136 [[nodiscard]] const std::vector<VKVertex> &vertices() const { return verticesData; }
137 [[nodiscard]] const std::vector<uint32_t> &indices() const { return indicesData; }
138 [[nodiscard]] uint32_t indexCount() const { return static_cast<uint32_t>(indicesData.size()); }
139
140 [[nodiscard]] VkBuffer vertexBuffer() const { return vertexBufferHandle; }
141 [[nodiscard]] VkBuffer indexBuffer() const { return indexBufferHandle; }
142
143 [[nodiscard]] size_t subMeshCount() const { return subMeshList.size(); }
144 [[nodiscard]] const SubMesh &subMesh(size_t i) const { return subMeshList[i]; }
145 [[nodiscard]] const std::vector<SubMesh> &subMeshes() const { return subMeshList; }
146
147 [[nodiscard]] const std::vector<MXMaterial> &materials() const { return materialList; }
148 [[nodiscard]] const std::string &mtlLibPath() const { return mtlLibraryPath; }
149
150 private:
151 std::vector<VKVertex> verticesData{};
152 std::vector<uint32_t> indicesData{};
153 std::vector<SubMesh> subMeshList{};
154 std::vector<MXMaterial> materialList{};
155 std::string mtlLibraryPath{};
156
157 VkBuffer vertexBufferHandle = VK_NULL_HANDLE;
158 VkDeviceMemory vertexBufferMemory = VK_NULL_HANDLE;
159 VkBuffer indexBufferHandle = VK_NULL_HANDLE;
160 VkDeviceMemory indexBufferMemory = VK_NULL_HANDLE;
161
162 static void createBuffer(VkDevice device, VkPhysicalDevice physicalDevice, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VkDeviceMemory &bufferMemory);
163
164 static uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties);
165
166 static void copyBuffer(VkDevice device, VkCommandPool commandPool, VkQueue graphicsQueue, VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size);
167
168 void loadOBJ(const std::string &path, float positionScale);
169 void loadMXMOD(const std::string &path, float positionScale);
170 void loadMXMODZ(const std::string &path, float positionScale);
171 void loadMTL(const std::string &path);
172 void loadTextureManifest(const std::string &path, const std::string &textureBasePath);
173 };
174
175} // namespace mxvk
const SubMesh & subMesh(size_t i) const
const std::vector< MXMaterial > & materials() const
MXModel()=default
uint32_t indexCount() const
const std::vector< VKVertex > & vertices() const
void draw(VkCommandBuffer cmd) const
Record one indexed draw for the full mesh.
MXModel(const MXModel &)=delete
void cleanup(VkDevice device)
Release owned GPU buffers.
const std::string & mtlLibPath() const
VkBuffer vertexBuffer() const
VkBuffer indexBuffer() const
void upload(VkDevice device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool, VkQueue graphicsQueue)
Upload parsed geometry to device-local GPU buffers.
MXModel & operator=(const MXModel &)=delete
void compressIndices()
Remove duplicate vertices and remap indices.
void drawSubMesh(VkCommandBuffer cmd, size_t index) const
Record one indexed draw for a sub-mesh.
size_t subMeshCount() const
const std::vector< uint32_t > & indices() const
void load(const std::string &path, float positionScale=1.0f)
Parse model data from disk into CPU-side arrays.
const std::vector< SubMesh > & subMeshes() const
void exportOBJ(const std::string &objPath, const std::string &mtlPath="") const
Export the loaded model as Wavefront OBJ plus MTL.
~MXModel()=default
Utilities for loading and saving PNG images.
Definition mxvk.hpp:31
Parsed subset of Wavefront MTL material fields.
std::string map_kd
std::string name
One indexed sub-range that can reference a dedicated texture slot.
uint32_t indexCount
uint32_t textureIndex
std::string materialName
uint32_t firstIndex
Hash functor for VKVertex.
std::size_t operator()(const VKVertex &v) const
Vertex payload consumed by MXVK model shaders.
bool operator==(const VKVertex &other) const
Byte-wise equality used for index compression.
float normal[3]
float texCoord[2]