Gama C Library
Gama C API Documentation
mesh.h
Go to the documentation of this file.
1#pragma once
2
3#include "mtl.h"
4#include "position.h"
5#include <float.h>
6
7/**
8 * @brief Represents a single face (triangle) in a 3D mesh.
9 */
10typedef struct {
11 size_t vertices[3]; /**< Indices to the mesh's vertex array (3 per triangle). */
12 long uvs[3]; /**< Indices to the mesh's texture coordinate array (3 per triangle). */
13 int material; /**< Index to the material within the associated material library. */
14 int material_file; /**< Index to the material library within the mesh's mtllibs array. */
15 gm3Pos normal; /**< The calculated geometric normal of this face. */
17
18/**
19 * @brief Represents a 2D texture coordinate.
20 */
21typedef struct {
22 double u, v; /**< The U and V texture coordinates. */
23} gm3Tex;
24
25/**
26 * @brief Represents a 3D mesh composed of vertices, faces, normals, and texture coordinates.
27 *
28 * This struct stores all geometric and material data for a 3D model.
29 */
30typedef struct {
31 gm3Pos *vertices; /**< Array of vertex positions. */
32 size_t n_vertices; /**< Number of vertices in the mesh. */
33
34 gm3MeshFace *faces; /**< Array of mesh faces (triangles). */
35 size_t n_faces; /**< Number of faces in the mesh. */
36
37 gm3Pos *normals; /**< Array of vertex normals. */
38 size_t n_normals; /**< Number of vertex normals in the mesh. */
39
40 gm3Tex *texs; /**< Array of texture coordinates. */
41 size_t n_texs; /**< Number of texture coordinates in the mesh. */
42
43 gm3MtlLib *mtllibs; /**< Array of material libraries. */
44 size_t n_mtllibs; /**< Number of material libraries. */
45} gm3Mesh;
46
47/**
48 * @brief Frees all dynamically allocated memory associated with a `gm3Mesh` struct.
49 * @param m A pointer to the `gm3Mesh` to free.
50 */
52 if (m->vertices)
53 free(m->vertices);
54 if (m->faces)
55 free(m->faces);
56 if (m->normals)
57 free(m->normals);
58 if (m->texs)
59 free(m->texs);
60 if (m->mtllibs) {
61 for (size_t i = 0; i < m->n_mtllibs; ++i) {
62 if (m->mtllibs[i].materials) free(m->mtllibs[i].materials);
63 if (m->mtllibs[i].textures) {
64 for (size_t j = 0; j < m->mtllibs[i].n_textures; ++j) {
65 if (m->mtllibs[i].textures[j].data.data) {
66 free(m->mtllibs[i].textures[j].data.data);
67 }
68 }
69 free(m->mtllibs[i].textures);
70 }
71 }
72 free(m->mtllibs);
73 }
74 memset(m, 0, sizeof(gm3Mesh));
75}
76
77/**
78 * @brief Centers the mesh geometry around the origin (0,0,0).
79 *
80 * This function calculates the bounding box of the mesh and translates
81 * all vertices so that the center of the bounding box is at the origin.
82 *
83 * @param m A pointer to the `gm3Mesh` to center.
84 * @return 0 on success, -1 if the mesh is NULL.
85 */
87 if (!m)
88 return -1;
89 gm3Pos max = {DBL_MIN, DBL_MIN, DBL_MIN};
90 gm3Pos min = {DBL_MAX, DBL_MAX, DBL_MAX};
91
92 for (size_t v = 0; v < m->n_vertices; v++) {
93 gm3Pos p = m->vertices[v];
94 min.x = fmin(p.x, min.x);
95 max.x = fmax(p.x, max.x);
96
97 min.y = fmin(p.y, min.y);
98 max.y = fmax(p.y, max.y);
99
100 min.z = fmin(p.z, min.z);
101 max.z = fmax(p.z, max.z);
102 }
103
104 gm3Pos center;
105 gm3_pos_center(&center, &max, &min);
106
107 for (size_t v = 0; v < m->n_vertices; v++)
108 gm3_pos_substract(&m->vertices[v], &center);
109 return 0;
110}
111
112/**
113 * @brief Serializes a `gm3Mesh` into a binary buffer.
114 *
115 * This function converts the mesh data into a compact binary format, suitable
116 * for baking into a file or memory. The caller is responsible for freeing `*data`.
117 *
118 * @param mesh A pointer to the `gm3Mesh` to serialize.
119 * @param data A pointer to a `void*` that will be allocated and filled with the serialized data.
120 * @param size A pointer to a `size_t` that will store the size of the serialized data.
121 * @return 0 on success, -1 on memory allocation failure.
122 */
123int gm3_mesh_serialize(const gm3Mesh *mesh, void **data, size_t *size);
124/**
125 * @brief Deserializes a `gm3Mesh` from a binary buffer.
126 *
127 * This function reconstructs a `gm3Mesh` from a binary buffer created by `gm3_mesh_serialize`.
128 * The deserialized mesh will have its internal arrays dynamically allocated.
129 *
130 * @param mesh A pointer to the `gm3Mesh` to fill with deserialized data.
131 * @param data A pointer to the binary buffer containing the serialized data.
132 * @param size The size of the binary buffer.
133 * @return 0 on success, -1 on failure (e.g., invalid magic, buffer too small, memory allocation failure).
134 */
135int gm3_mesh_deserialize(gm3Mesh *mesh, const void *data, size_t size);
136
137// --- Serialization ---
138/**
139 * @brief Header for the baked mesh binary format.
140 */
141typedef struct {
142 uint32_t magic; /**< Magic number to identify the baked mesh format ("GM3M"). */
143 size_t n_vertices; /**< Number of vertices. */
144 size_t n_faces; /**< Number of faces. */
145 size_t n_normals; /**< Number of normals. */
146 size_t n_texs; /**< Number of texture coordinates. */
147 size_t n_mtllibs; /**< Number of material libraries. */
149/**
150 * @brief Magic number for the baked mesh binary format: "GM3M".
151 */
152#define GM3_BAKED_MESH_MAGIC 0x474D334D // "GM3M"
153
154int gm3_mesh_serialize(const gm3Mesh *mesh, void **data, size_t *size) {
155 // Calculate total size for all textures and their metadata
156 size_t total_textures_size = 0;
157 for (size_t i = 0; i < mesh->n_mtllibs; i++) {
158 gm3MtlLib *lib = &mesh->mtllibs[i];
159 total_textures_size += sizeof(size_t); // n_textures
160 for (size_t j = 0; j < lib->n_textures; j++) {
161 gm3Texture *tex = &lib->textures[j];
162 size_t data_size = tex->data.width * tex->data.height * 4;
163 total_textures_size += sizeof(int32_t) * 2; // width, height
164 total_textures_size += sizeof(size_t); // size of pixel data
165 total_textures_size += data_size; // pixel data itself
166 total_textures_size += 256; // path
167 }
168 }
169
170 // Calculate total size for all material libraries and their materials
171 size_t mtllibs_size = 0;
172 for (size_t i = 0; i < mesh->n_mtllibs; i++) {
173 mtllibs_size += 256; // name
174 mtllibs_size += sizeof(size_t); // n_materials
175 mtllibs_size += sizeof(size_t); // n_textures
176 mtllibs_size += sizeof(gm3Material) * mesh->mtllibs[i].n_materials;
177 }
178
179 *size = sizeof(gm3BakedMeshHeader) + sizeof(gm3Pos) * mesh->n_vertices +
180 sizeof(gm3MeshFace) * mesh->n_faces +
181 sizeof(gm3Pos) * mesh->n_normals + sizeof(gm3Tex) * mesh->n_texs +
182 mtllibs_size + total_textures_size;
183
184 *data = malloc(*size);
185 if (!*data)
186 return -1;
187
188 char *p = (char *)*data;
189
190 // Header
191 gm3BakedMeshHeader header = {
192 .magic = GM3_BAKED_MESH_MAGIC,
193 .n_vertices = mesh->n_vertices,
194 .n_faces = mesh->n_faces,
195 .n_normals = mesh->n_normals,
196 .n_texs = mesh->n_texs,
197 .n_mtllibs = mesh->n_mtllibs,
198 };
199 memcpy(p, &header, sizeof(header));
200 p += sizeof(header);
201
202 // Main data blocks
203 if (mesh->n_vertices > 0) {
204 memcpy(p, mesh->vertices, sizeof(gm3Pos) * mesh->n_vertices);
205 p += sizeof(gm3Pos) * mesh->n_vertices;
206 }
207 if (mesh->n_faces > 0) {
208 memcpy(p, mesh->faces, sizeof(gm3MeshFace) * mesh->n_faces);
209 p += sizeof(gm3MeshFace) * mesh->n_faces;
210 }
211 if (mesh->n_normals > 0) {
212 memcpy(p, mesh->normals, sizeof(gm3Pos) * mesh->n_normals);
213 p += sizeof(gm3Pos) * mesh->n_normals;
214 }
215 if (mesh->n_texs > 0) {
216 memcpy(p, mesh->texs, sizeof(gm3Tex) * mesh->n_texs);
217 p += sizeof(gm3Tex) * mesh->n_texs;
218 }
219
220 // Material Libs and Textures
221 for (size_t i = 0; i < mesh->n_mtllibs; i++) {
222 gm3MtlLib *lib = &mesh->mtllibs[i];
223 // Lib metadata
224 memcpy(p, lib->name, 256);
225 p += 256;
226 memcpy(p, &lib->n_materials, sizeof(size_t));
227 p += sizeof(size_t);
228 memcpy(p, &lib->n_textures, sizeof(size_t));
229 p += sizeof(size_t);
230
231 // Materials
232 if (lib->n_materials > 0) {
233 memcpy(p, lib->materials, sizeof(gm3Material) * lib->n_materials);
234 p += sizeof(gm3Material) * lib->n_materials;
235 }
236
237 // Textures
238 for (size_t j = 0; j < lib->n_textures; j++) {
239 gm3Texture *tex = &lib->textures[j];
240 size_t data_size = tex->data.width * tex->data.height * 4;
241 memcpy(p, tex->path, 256);
242 p += 256;
243 memcpy(p, &tex->data.width, sizeof(int32_t));
244 p += sizeof(int32_t);
245 memcpy(p, &tex->data.height, sizeof(int32_t));
246 p += sizeof(int32_t);
247 memcpy(p, &data_size, sizeof(size_t));
248 p += sizeof(size_t);
249 memcpy(p, tex->data.data, data_size);
250 p += data_size;
251 }
252 }
253
254 return 0;
255}
256
257int gm3_mesh_deserialize(gm3Mesh *mesh, const void *data, size_t size) {
258 memset(mesh, 0, sizeof(gm3Mesh));
259 const char *p = (const char *)data;
260
261 if (size < sizeof(gm3BakedMeshHeader))
262 return -1;
263 const gm3BakedMeshHeader *header = (const gm3BakedMeshHeader *)p;
264 if (header->magic != GM3_BAKED_MESH_MAGIC)
265 return -1;
266 p += sizeof(gm3BakedMeshHeader);
267
268 // Allocate and copy main data blocks
269 mesh->n_vertices = header->n_vertices;
270 if (mesh->n_vertices > 0) {
271 mesh->vertices = malloc(sizeof(gm3Pos) * mesh->n_vertices);
272 memcpy(mesh->vertices, p, sizeof(gm3Pos) * mesh->n_vertices);
273 p += sizeof(gm3Pos) * mesh->n_vertices;
274 }
275
276 mesh->n_faces = header->n_faces;
277 if (mesh->n_faces > 0) {
278 mesh->faces = malloc(sizeof(gm3MeshFace) * mesh->n_faces);
279 memcpy(mesh->faces, p, sizeof(gm3MeshFace) * mesh->n_faces);
280 p += sizeof(gm3MeshFace) * mesh->n_faces;
281 }
282
283 mesh->n_normals = header->n_normals;
284 if (mesh->n_normals > 0) {
285 mesh->normals = malloc(sizeof(gm3Pos) * mesh->n_normals);
286 memcpy(mesh->normals, p, sizeof(gm3Pos) * mesh->n_normals);
287 p += sizeof(gm3Pos) * mesh->n_normals;
288 }
289
290 mesh->n_texs = header->n_texs;
291 if (mesh->n_texs > 0) {
292 mesh->texs = malloc(sizeof(gm3Tex) * mesh->n_texs);
293 memcpy(mesh->texs, p, sizeof(gm3Tex) * mesh->n_texs);
294 p += sizeof(gm3Tex) * mesh->n_texs;
295 }
296
297 // Allocate and copy material libs and textures
298 mesh->n_mtllibs = header->n_mtllibs;
299 if (mesh->n_mtllibs > 0) {
300 mesh->mtllibs = calloc(mesh->n_mtllibs, sizeof(gm3MtlLib));
301 for (size_t i = 0; i < mesh->n_mtllibs; i++) {
302 gm3MtlLib *lib = &mesh->mtllibs[i];
303 memcpy(lib->name, p, 256);
304 p += 256;
305 memcpy(&lib->n_materials, p, sizeof(size_t));
306 p += sizeof(size_t);
307 memcpy(&lib->n_textures, p, sizeof(size_t));
308 p += sizeof(size_t);
309
310 if (lib->n_materials > 0) {
311 lib->materials = malloc(sizeof(gm3Material) * lib->n_materials);
312 memcpy(lib->materials, p, sizeof(gm3Material) * lib->n_materials);
313 p += sizeof(gm3Material) * lib->n_materials;
314 }
315
316 if (lib->n_textures > 0) {
317 lib->textures = calloc(lib->n_textures, sizeof(gm3Texture));
318 for (size_t j = 0; j < lib->n_textures; j++) {
319 gm3Texture *tex = &lib->textures[j];
320 size_t data_size = 0;
321 memcpy(tex->path, p, 256);
322 p += 256;
323 memcpy(&tex->data.width, p, sizeof(int32_t));
324 p += sizeof(int32_t);
325 memcpy(&tex->data.height, p, sizeof(int32_t));
326 p += sizeof(int32_t);
327 memcpy(&data_size, p, sizeof(size_t));
328 p += sizeof(size_t);
329 tex->data.data = malloc(data_size);
330 memcpy(tex->data.data, p, data_size);
331 p += data_size;
332 }
333 }
334 }
335 }
336
337 // Check bounds
338 if ((size_t)(p - (const char *)data) > size) {
339 gm3_mesh_free(mesh);
340 return -1; // Data corruption / size mismatch
341 }
342
343 return 0;
344}
void * malloc(size_t size)
Custom implementation of malloc using a static memory pool.
Definition malloc.h:144
void * calloc(size_t count, size_t size)
Custom implementation of calloc using a static memory pool.
Definition malloc.h:215
void free(void *ptr)
Custom implementation of free for memory allocated by malloc (this custom version).
Definition malloc.h:189
double fmin(double a, double b)
Returns the smaller of two double values.
Definition math.h:413
double fmax(double a, double b)
Returns the larger of two double values.
Definition math.h:428
int min(int a, int b)
Returns the smaller of two integer values.
Definition math.h:406
int max(int a, int b)
Returns the larger of two integer values.
Definition math.h:421
int gm3_mesh_center(gm3Mesh *m)
Centers the mesh geometry around the origin (0,0,0).
Definition mesh.h:86
void gm3_mesh_free(gm3Mesh *m)
Frees all dynamically allocated memory associated with a gm3Mesh struct.
Definition mesh.h:51
int gm3_mesh_deserialize(gm3Mesh *mesh, const void *data, size_t size)
Deserializes a gm3Mesh from a binary buffer.
Definition mesh.h:257
int gm3_mesh_serialize(const gm3Mesh *mesh, void **data, size_t *size)
Serializes a gm3Mesh into a binary buffer.
Definition mesh.h:154
#define GM3_BAKED_MESH_MAGIC
Magic number for the baked mesh binary format: "GM3M".
Definition mesh.h:152
Defines structures for 3D materials and material libraries, and functions for loading MTL files.
Header for the baked mesh binary format.
Definition mesh.h:141
uint32_t magic
Definition mesh.h:142
size_t n_normals
Definition mesh.h:145
size_t n_vertices
Definition mesh.h:143
size_t n_faces
Definition mesh.h:144
size_t n_texs
Definition mesh.h:146
size_t n_mtllibs
Definition mesh.h:147
Represents a single 3D material with various rendering properties.
Definition mtl.h:26
Represents a single face (triangle) in a 3D mesh.
Definition mesh.h:10
int material
Definition mesh.h:13
int material_file
Definition mesh.h:14
size_t vertices[3]
Definition mesh.h:11
long uvs[3]
Definition mesh.h:12
gm3Pos normal
Definition mesh.h:15
Represents a 3D mesh composed of vertices, faces, normals, and texture coordinates.
Definition mesh.h:30
size_t n_mtllibs
Definition mesh.h:44
size_t n_normals
Definition mesh.h:38
gm3Tex * texs
Definition mesh.h:40
size_t n_texs
Definition mesh.h:41
gm3MeshFace * faces
Definition mesh.h:34
size_t n_vertices
Definition mesh.h:32
gm3Pos * vertices
Definition mesh.h:31
gm3MtlLib * mtllibs
Definition mesh.h:43
gm3Pos * normals
Definition mesh.h:37
size_t n_faces
Definition mesh.h:35
Represents a material library, typically loaded from an .mtl file.
Definition mtl.h:53
size_t n_textures
Definition mtl.h:60
gm3Material * materials
Definition mtl.h:56
char name[256]
Definition mtl.h:54
size_t n_materials
Definition mtl.h:57
gm3Texture * textures
Definition mtl.h:59
Represents a 3D position or vector.
Definition position.h:11
double y
Definition position.h:12
double z
Definition position.h:12
double x
Definition position.h:12
Represents a 2D texture coordinate.
Definition mesh.h:21
double v
Definition mesh.h:22
double u
Definition mesh.h:22
Represents a 3D texture, including its raw image data and file path.
Definition mtl.h:43
gmImageData data
Definition mtl.h:44
char path[256]
Definition mtl.h:45
int32_t width
Definition image.h:19
int32_t height
Definition image.h:19
unsigned char * data
Definition image.h:20