MXVK Vulkan Framework 0.24.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 {
30 return std::memcmp(this, &other, sizeof(VKVertex)) == 0;
31 }
32 };
33
34 /** @brief Hash functor for VKVertex. */
35 struct VKVertexHash {
36 std::size_t operator()(const VKVertex &v) const;
37 };
38
39 /**
40 * @struct SubMesh
41 * @brief One indexed sub-range that can reference a dedicated texture slot.
42 */
43 struct SubMesh {
44 uint32_t firstIndex = 0;
45 uint32_t indexCount = 0;
46 uint32_t textureIndex = 0;
47 std::string materialName;
48 };
49
50 /**
51 * @struct MXMaterial
52 * @brief Parsed subset of Wavefront MTL material fields.
53 */
54 struct MXMaterial {
55 std::string name;
56 float ka[3] = {0.2f, 0.2f, 0.2f};
57 float kd[3] = {0.8f, 0.8f, 0.8f};
58 float ks[3] = {0.0f, 0.0f, 0.0f};
59 float ns = 30.0f;
60 float d = 1.0f;
61 int illum = 2;
62 std::string map_kd;
63 };
64
65 /**
66 * @class MXModel
67 * @brief Loads OBJ/MXMOD meshes and uploads them to Vulkan buffers.
68 */
69 class MXModel {
70 public:
71 MXModel() = default;
72 ~MXModel() = default;
73
74 MXModel(const MXModel &) = delete;
75 MXModel &operator=(const MXModel &) = delete;
76 MXModel(MXModel &&other) noexcept;
77 MXModel &operator=(MXModel &&other) noexcept;
78
79 /**
80 * @brief Parse model data from disk into CPU-side arrays.
81 * @param path Path to .obj, .mxmod, or .mxmod.z model.
82 * @param positionScale Uniform scale applied to positions.
83 */
84 void load(const std::string &path, float positionScale = 1.0f);
85
86 /**
87 * @brief Parse model data and an optional texture manifest from disk.
88 * @param path Path to .obj, .mxmod, or .mxmod.z model.
89 * @param textureManifestPath Optional .txt/.tex or MTL-like texture manifest.
90 * @param textureBasePath Base path used to resolve relative texture paths.
91 * @param positionScale Uniform scale applied to positions.
92 */
93 void load(const std::string &path,
94 const std::string &textureManifestPath,
95 const std::string &textureBasePath,
96 float positionScale = 1.0f);
97
98 /**
99 * @brief Export the loaded model as Wavefront OBJ plus MTL.
100 * @param objPath Output .obj path.
101 * @param mtlPath Optional output .mtl path. Defaults to objPath with .mtl extension.
102 */
103 void exportOBJ(const std::string &objPath, const std::string &mtlPath = "") const;
104
105 /**
106 * @brief Load a model/manifest pair and export it as Wavefront OBJ plus MTL.
107 */
108 static void exportOBJ(const std::string &modelPath,
109 const std::string &textureManifestPath,
110 const std::string &textureBasePath,
111 const std::string &objPath,
112 float positionScale = 1.0f);
113
114 /**
115 * @brief Upload parsed geometry to device-local GPU buffers.
116 * @param device Logical Vulkan device.
117 * @param physicalDevice Physical Vulkan device.
118 * @param commandPool Command pool used for transfer command buffer allocation.
119 * @param graphicsQueue Queue used to submit transfer commands.
120 */
121 void upload(VkDevice device, VkPhysicalDevice physicalDevice,
122 VkCommandPool commandPool, VkQueue graphicsQueue);
123
124 /**
125 * @brief Release owned GPU buffers.
126 * @param device Logical Vulkan device that owns these resources.
127 */
128 void cleanup(VkDevice device);
129
130 /**
131 * @brief Record one indexed draw for the full mesh.
132 * @param cmd Active command buffer.
133 */
134 void draw(VkCommandBuffer cmd) const;
135
136 /**
137 * @brief Record one indexed draw for a sub-mesh.
138 * @param cmd Active command buffer.
139 * @param index Sub-mesh index.
140 */
141 void drawSubMesh(VkCommandBuffer cmd, size_t index) const;
142
143 /** @brief Remove duplicate vertices and remap indices. */
144 void compressIndices();
145
146 [[nodiscard]] const std::vector<VKVertex> &vertices() const { return verticesData; }
147 [[nodiscard]] const std::vector<uint32_t> &indices() const { return indicesData; }
148 [[nodiscard]] uint32_t indexCount() const { return static_cast<uint32_t>(indicesData.size()); }
149
150 [[nodiscard]] VkBuffer vertexBuffer() const { return vertexBufferHandle; }
151 [[nodiscard]] VkBuffer indexBuffer() const { return indexBufferHandle; }
152
153 [[nodiscard]] size_t subMeshCount() const { return subMeshList.size(); }
154 [[nodiscard]] const SubMesh &subMesh(size_t i) const { return subMeshList[i]; }
155 [[nodiscard]] const std::vector<SubMesh> &subMeshes() const { return subMeshList; }
156
157 [[nodiscard]] const std::vector<MXMaterial> &materials() const { return materialList; }
158 [[nodiscard]] const std::string &mtlLibPath() const { return mtlLibraryPath; }
159
160 private:
161 std::vector<VKVertex> verticesData{};
162 std::vector<uint32_t> indicesData{};
163 std::vector<SubMesh> subMeshList{};
164 std::vector<MXMaterial> materialList{};
165 std::string mtlLibraryPath{};
166
167 VkBuffer vertexBufferHandle = VK_NULL_HANDLE;
168 VkDeviceMemory vertexBufferMemory = VK_NULL_HANDLE;
169 VkBuffer indexBufferHandle = VK_NULL_HANDLE;
170 VkDeviceMemory indexBufferMemory = VK_NULL_HANDLE;
171
172 static void createBuffer(VkDevice device, VkPhysicalDevice physicalDevice,
173 VkDeviceSize size, VkBufferUsageFlags usage,
174 VkMemoryPropertyFlags properties,
175 VkBuffer &buffer, VkDeviceMemory &bufferMemory);
176
177 static uint32_t findMemoryType(VkPhysicalDevice physicalDevice,
178 uint32_t typeFilter, VkMemoryPropertyFlags properties);
179
180 static void copyBuffer(VkDevice device, VkCommandPool commandPool,
181 VkQueue graphicsQueue,
182 VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size);
183
184 void loadOBJ(const std::string &path, float positionScale);
185 void loadMXMOD(const std::string &path, float positionScale);
186 void loadMXMODZ(const std::string &path, float positionScale);
187 void loadMTL(const std::string &path);
188 void loadTextureManifest(const std::string &path, const std::string &textureBasePath);
189 };
190
191} // 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:30
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]