Wise&mystical  1.0
Project about Europe
Loading...
Searching...
No Matches
rmodels.c
Go to the documentation of this file.
1
43#include "raylib.h" // Declares module functions
44
45// Check if config flags have been externally provided on compilation line
46#if !defined(EXTERNAL_CONFIG_FLAGS)
47 #include "config.h" // Defines module configuration flags
48#endif
49
50#if defined(SUPPORT_MODULE_RMODELS)
51
52#include "utils.h" // Required for: TRACELOG(), LoadFileData(), LoadFileText(), SaveFileText()
53#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
54#include "raymath.h" // Required for: Vector3, Quaternion and Matrix functionality
55
56#include <stdio.h> // Required for: sprintf()
57#include <stdlib.h> // Required for: malloc(), free()
58#include <string.h> // Required for: memcmp(), strlen()
59#include <math.h> // Required for: sinf(), cosf(), sqrtf(), fabsf()
60
61#if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL)
62 #define TINYOBJ_MALLOC RL_MALLOC
63 #define TINYOBJ_CALLOC RL_CALLOC
64 #define TINYOBJ_REALLOC RL_REALLOC
65 #define TINYOBJ_FREE RL_FREE
66
67 #define TINYOBJ_LOADER_C_IMPLEMENTATION
68 #include "external/tinyobj_loader_c.h" // OBJ/MTL file formats loading
69#endif
70
71#if defined(SUPPORT_FILEFORMAT_GLTF)
72 #define CGLTF_MALLOC RL_MALLOC
73 #define CGLTF_FREE RL_FREE
74
75 #define CGLTF_IMPLEMENTATION
76 #include "external/cgltf.h" // glTF file format loading
77#endif
78
79#if defined(SUPPORT_FILEFORMAT_VOX)
80 #define VOX_MALLOC RL_MALLOC
81 #define VOX_CALLOC RL_CALLOC
82 #define VOX_REALLOC RL_REALLOC
83 #define VOX_FREE RL_FREE
84
85 #define VOX_LOADER_IMPLEMENTATION
86 #include "external/vox_loader.h" // VOX file format loading (MagikaVoxel)
87#endif
88
89#if defined(SUPPORT_MESH_GENERATION)
90 #define PAR_MALLOC(T, N) ((T*)RL_MALLOC(N*sizeof(T)))
91 #define PAR_CALLOC(T, N) ((T*)RL_CALLOC(N*sizeof(T), 1))
92 #define PAR_REALLOC(T, BUF, N) ((T*)RL_REALLOC(BUF, sizeof(T)*(N)))
93 #define PAR_FREE RL_FREE
94
95 #define PAR_SHAPES_IMPLEMENTATION
96 #include "external/par_shapes.h" // Shapes 3d parametric generation
97#endif
98
99#if defined(_WIN32)
100 #include <direct.h> // Required for: _chdir() [Used in LoadOBJ()]
101 #define CHDIR _chdir
102#else
103 #include <unistd.h> // Required for: chdir() (POSIX) [Used in LoadOBJ()]
104 #define CHDIR chdir
105#endif
106
107//----------------------------------------------------------------------------------
108// Defines and Macros
109//----------------------------------------------------------------------------------
110#ifndef MAX_MATERIAL_MAPS
111 #define MAX_MATERIAL_MAPS 12 // Maximum number of maps supported
112#endif
113#ifndef MAX_MESH_VERTEX_BUFFERS
114 #define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh
115#endif
116
117//----------------------------------------------------------------------------------
118// Types and Structures Definition
119//----------------------------------------------------------------------------------
120// ...
121
122//----------------------------------------------------------------------------------
123// Global Variables Definition
124//----------------------------------------------------------------------------------
125// ...
126
127//----------------------------------------------------------------------------------
128// Module specific Functions Declaration
129//----------------------------------------------------------------------------------
130#if defined(SUPPORT_FILEFORMAT_OBJ)
131static Model LoadOBJ(const char *fileName); // Load OBJ mesh data
132#endif
133#if defined(SUPPORT_FILEFORMAT_IQM)
134static Model LoadIQM(const char *fileName); // Load IQM mesh data
135static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, unsigned int *animCount); // Load IQM animation data
136#endif
137#if defined(SUPPORT_FILEFORMAT_GLTF)
138static Model LoadGLTF(const char *fileName); // Load GLTF mesh data
139//static ModelAnimation *LoadModelAnimationGLTF(const char *fileName, unsigned int *animCount); // Load GLTF animation data
140#endif
141#if defined(SUPPORT_FILEFORMAT_VOX)
142static Model LoadVOX(const char *filename); // Load VOX mesh data
143#endif
144
145//----------------------------------------------------------------------------------
146// Module Functions Definition
147//----------------------------------------------------------------------------------
148
149// Draw a line in 3D world space
150void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color)
151{
152 // WARNING: Be careful with internal buffer vertex alignment
153 // when using RL_LINES or RL_TRIANGLES, data is aligned to fit
154 // lines-triangles-quads in the same indexed buffers!!!
156
158 rlColor4ub(color.r, color.g, color.b, color.a);
159 rlVertex3f(startPos.x, startPos.y, startPos.z);
160 rlVertex3f(endPos.x, endPos.y, endPos.z);
161 rlEnd();
162}
163
164// Draw a point in 3D space, actually a small line
165void DrawPoint3D(Vector3 position, Color color)
166{
168
169 rlPushMatrix();
170 rlTranslatef(position.x, position.y, position.z);
172 rlColor4ub(color.r, color.g, color.b, color.a);
173 rlVertex3f(0.0f, 0.0f, 0.0f);
174 rlVertex3f(0.0f, 0.0f, 0.1f);
175 rlEnd();
176 rlPopMatrix();
177}
178
179// Draw a circle in 3D world space
180void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color)
181{
183
184 rlPushMatrix();
185 rlTranslatef(center.x, center.y, center.z);
186 rlRotatef(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
187
189 for (int i = 0; i < 360; i += 10)
190 {
191 rlColor4ub(color.r, color.g, color.b, color.a);
192
193 rlVertex3f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius, 0.0f);
194 rlVertex3f(sinf(DEG2RAD*(i + 10))*radius, cosf(DEG2RAD*(i + 10))*radius, 0.0f);
195 }
196 rlEnd();
197 rlPopMatrix();
198}
199
200// Draw a color-filled triangle (vertex in counter-clockwise order!)
202{
204
206 rlColor4ub(color.r, color.g, color.b, color.a);
207 rlVertex3f(v1.x, v1.y, v1.z);
208 rlVertex3f(v2.x, v2.y, v2.z);
209 rlVertex3f(v3.x, v3.y, v3.z);
210 rlEnd();
211}
212
213// Draw a triangle strip defined by points
214void DrawTriangleStrip3D(Vector3 *points, int pointCount, Color color)
215{
216 if (pointCount >= 3)
217 {
218 rlCheckRenderBatchLimit(3*(pointCount - 2));
219
221 rlColor4ub(color.r, color.g, color.b, color.a);
222
223 for (int i = 2; i < pointCount; i++)
224 {
225 if ((i%2) == 0)
226 {
227 rlVertex3f(points[i].x, points[i].y, points[i].z);
228 rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z);
229 rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z);
230 }
231 else
232 {
233 rlVertex3f(points[i].x, points[i].y, points[i].z);
234 rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z);
235 rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z);
236 }
237 }
238 rlEnd();
239 }
240}
241
242// Draw cube
243// NOTE: Cube position is the center position
244void DrawCube(Vector3 position, float width, float height, float length, Color color)
245{
246 float x = 0.0f;
247 float y = 0.0f;
248 float z = 0.0f;
249
251
252 rlPushMatrix();
253 // NOTE: Transformation is applied in inverse order (scale -> rotate -> translate)
254 rlTranslatef(position.x, position.y, position.z);
255 //rlRotatef(45, 0, 1, 0);
256 //rlScalef(1.0f, 1.0f, 1.0f); // NOTE: Vertices are directly scaled on definition
257
259 rlColor4ub(color.r, color.g, color.b, color.a);
260
261 // Front face
262 rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left
263 rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right
264 rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left
265
266 rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Right
267 rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left
268 rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right
269
270 // Back face
271 rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Left
272 rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left
273 rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right
274
275 rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right
276 rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right
277 rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left
278
279 // Top face
280 rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left
281 rlVertex3f(x - width/2, y + height/2, z + length/2); // Bottom Left
282 rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right
283
284 rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right
285 rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left
286 rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right
287
288 // Bottom face
289 rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left
290 rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right
291 rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left
292
293 rlVertex3f(x + width/2, y - height/2, z - length/2); // Top Right
294 rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right
295 rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left
296
297 // Right face
298 rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right
299 rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right
300 rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left
301
302 rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Left
303 rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right
304 rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left
305
306 // Left face
307 rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right
308 rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left
309 rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Right
310
311 rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left
312 rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left
313 rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right
314 rlEnd();
315 rlPopMatrix();
316}
317
318// Draw cube (Vector version)
319void DrawCubeV(Vector3 position, Vector3 size, Color color)
320{
321 DrawCube(position, size.x, size.y, size.z, color);
322}
323
324// Draw cube wires
325void DrawCubeWires(Vector3 position, float width, float height, float length, Color color)
326{
327 float x = 0.0f;
328 float y = 0.0f;
329 float z = 0.0f;
330
332
333 rlPushMatrix();
334 rlTranslatef(position.x, position.y, position.z);
335
337 rlColor4ub(color.r, color.g, color.b, color.a);
338
339 // Front face -----------------------------------------------------
340 // Bottom line
341 rlVertex3f(x-width/2, y-height/2, z+length/2); // Bottom left
342 rlVertex3f(x+width/2, y-height/2, z+length/2); // Bottom right
343
344 // Left line
345 rlVertex3f(x+width/2, y-height/2, z+length/2); // Bottom right
346 rlVertex3f(x+width/2, y+height/2, z+length/2); // Top right
347
348 // Top line
349 rlVertex3f(x+width/2, y+height/2, z+length/2); // Top right
350 rlVertex3f(x-width/2, y+height/2, z+length/2); // Top left
351
352 // Right line
353 rlVertex3f(x-width/2, y+height/2, z+length/2); // Top left
354 rlVertex3f(x-width/2, y-height/2, z+length/2); // Bottom left
355
356 // Back face ------------------------------------------------------
357 // Bottom line
358 rlVertex3f(x-width/2, y-height/2, z-length/2); // Bottom left
359 rlVertex3f(x+width/2, y-height/2, z-length/2); // Bottom right
360
361 // Left line
362 rlVertex3f(x+width/2, y-height/2, z-length/2); // Bottom right
363 rlVertex3f(x+width/2, y+height/2, z-length/2); // Top right
364
365 // Top line
366 rlVertex3f(x+width/2, y+height/2, z-length/2); // Top right
367 rlVertex3f(x-width/2, y+height/2, z-length/2); // Top left
368
369 // Right line
370 rlVertex3f(x-width/2, y+height/2, z-length/2); // Top left
371 rlVertex3f(x-width/2, y-height/2, z-length/2); // Bottom left
372
373 // Top face -------------------------------------------------------
374 // Left line
375 rlVertex3f(x-width/2, y+height/2, z+length/2); // Top left front
376 rlVertex3f(x-width/2, y+height/2, z-length/2); // Top left back
377
378 // Right line
379 rlVertex3f(x+width/2, y+height/2, z+length/2); // Top right front
380 rlVertex3f(x+width/2, y+height/2, z-length/2); // Top right back
381
382 // Bottom face ---------------------------------------------------
383 // Left line
384 rlVertex3f(x-width/2, y-height/2, z+length/2); // Top left front
385 rlVertex3f(x-width/2, y-height/2, z-length/2); // Top left back
386
387 // Right line
388 rlVertex3f(x+width/2, y-height/2, z+length/2); // Top right front
389 rlVertex3f(x+width/2, y-height/2, z-length/2); // Top right back
390 rlEnd();
391 rlPopMatrix();
392}
393
394// Draw cube wires (vector version)
395void DrawCubeWiresV(Vector3 position, Vector3 size, Color color)
396{
397 DrawCubeWires(position, size.x, size.y, size.z, color);
398}
399
400// Draw cube
401// NOTE: Cube position is the center position
402void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float length, Color color)
403{
404 float x = position.x;
405 float y = position.y;
406 float z = position.z;
407
409
410 rlSetTexture(texture.id);
411
412 //rlPushMatrix();
413 // NOTE: Transformation is applied in inverse order (scale -> rotate -> translate)
414 //rlTranslatef(2.0f, 0.0f, 0.0f);
415 //rlRotatef(45, 0, 1, 0);
416 //rlScalef(2.0f, 2.0f, 2.0f);
417
419 rlColor4ub(color.r, color.g, color.b, color.a);
420 // Front Face
421 rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer
422 rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left Of The Texture and Quad
423 rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right Of The Texture and Quad
424 rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Right Of The Texture and Quad
425 rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left Of The Texture and Quad
426 // Back Face
427 rlNormal3f(0.0f, 0.0f, - 1.0f); // Normal Pointing Away From Viewer
428 rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right Of The Texture and Quad
429 rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Right Of The Texture and Quad
430 rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Left Of The Texture and Quad
431 rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Left Of The Texture and Quad
432 // Top Face
433 rlNormal3f(0.0f, 1.0f, 0.0f); // Normal Pointing Up
434 rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left Of The Texture and Quad
435 rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - width/2, y + height/2, z + length/2); // Bottom Left Of The Texture and Quad
436 rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right Of The Texture and Quad
437 rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right Of The Texture and Quad
438 // Bottom Face
439 rlNormal3f(0.0f, - 1.0f, 0.0f); // Normal Pointing Down
440 rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Right Of The Texture and Quad
441 rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + width/2, y - height/2, z - length/2); // Top Left Of The Texture and Quad
442 rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Left Of The Texture and Quad
443 rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Right Of The Texture and Quad
444 // Right face
445 rlNormal3f(1.0f, 0.0f, 0.0f); // Normal Pointing Right
446 rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right Of The Texture and Quad
447 rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right Of The Texture and Quad
448 rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left Of The Texture and Quad
449 rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Left Of The Texture and Quad
450 // Left Face
451 rlNormal3f( - 1.0f, 0.0f, 0.0f); // Normal Pointing Left
452 rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Left Of The Texture and Quad
453 rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Right Of The Texture and Quad
454 rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Right Of The Texture and Quad
455 rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left Of The Texture and Quad
456 rlEnd();
457 //rlPopMatrix();
458
459 rlSetTexture(0);
460}
461
462// Draw cube with texture piece applied to all faces
463void DrawCubeTextureRec(Texture2D texture, Rectangle source, Vector3 position, float width, float height, float length, Color color)
464{
465 float x = position.x;
466 float y = position.y;
467 float z = position.z;
468 float texWidth = (float)texture.width;
469 float texHeight = (float)texture.height;
470
472
473 rlSetTexture(texture.id);
474
476 rlColor4ub(color.r, color.g, color.b, color.a);
477
478 // Front face
479 rlNormal3f(0.0f, 0.0f, 1.0f);
480 rlTexCoord2f(source.x/texWidth, (source.y + source.height)/texHeight);
481 rlVertex3f(x - width/2, y - height/2, z + length/2);
482 rlTexCoord2f((source.x + source.width)/texWidth, (source.y + source.height)/texHeight);
483 rlVertex3f(x + width/2, y - height/2, z + length/2);
484 rlTexCoord2f((source.x + source.width)/texWidth, source.y/texHeight);
485 rlVertex3f(x + width/2, y + height/2, z + length/2);
486 rlTexCoord2f(source.x/texWidth, source.y/texHeight);
487 rlVertex3f(x - width/2, y + height/2, z + length/2);
488
489 // Back face
490 rlNormal3f(0.0f, 0.0f, - 1.0f);
491 rlTexCoord2f((source.x + source.width)/texWidth, (source.y + source.height)/texHeight);
492 rlVertex3f(x - width/2, y - height/2, z - length/2);
493 rlTexCoord2f((source.x + source.width)/texWidth, source.y/texHeight);
494 rlVertex3f(x - width/2, y + height/2, z - length/2);
495 rlTexCoord2f(source.x/texWidth, source.y/texHeight);
496 rlVertex3f(x + width/2, y + height/2, z - length/2);
497 rlTexCoord2f(source.x/texWidth, (source.y + source.height)/texHeight);
498 rlVertex3f(x + width/2, y - height/2, z - length/2);
499
500 // Top face
501 rlNormal3f(0.0f, 1.0f, 0.0f);
502 rlTexCoord2f(source.x/texWidth, source.y/texHeight);
503 rlVertex3f(x - width/2, y + height/2, z - length/2);
504 rlTexCoord2f(source.x/texWidth, (source.y + source.height)/texHeight);
505 rlVertex3f(x - width/2, y + height/2, z + length/2);
506 rlTexCoord2f((source.x + source.width)/texWidth, (source.y + source.height)/texHeight);
507 rlVertex3f(x + width/2, y + height/2, z + length/2);
508 rlTexCoord2f((source.x + source.width)/texWidth, source.y/texHeight);
509 rlVertex3f(x + width/2, y + height/2, z - length/2);
510
511 // Bottom face
512 rlNormal3f(0.0f, - 1.0f, 0.0f);
513 rlTexCoord2f((source.x + source.width)/texWidth, source.y/texHeight);
514 rlVertex3f(x - width/2, y - height/2, z - length/2);
515 rlTexCoord2f(source.x/texWidth, source.y/texHeight);
516 rlVertex3f(x + width/2, y - height/2, z - length/2);
517 rlTexCoord2f(source.x/texWidth, (source.y + source.height)/texHeight);
518 rlVertex3f(x + width/2, y - height/2, z + length/2);
519 rlTexCoord2f((source.x + source.width)/texWidth, (source.y + source.height)/texHeight);
520 rlVertex3f(x - width/2, y - height/2, z + length/2);
521
522 // Right face
523 rlNormal3f(1.0f, 0.0f, 0.0f);
524 rlTexCoord2f((source.x + source.width)/texWidth, (source.y + source.height)/texHeight);
525 rlVertex3f(x + width/2, y - height/2, z - length/2);
526 rlTexCoord2f((source.x + source.width)/texWidth, source.y/texHeight);
527 rlVertex3f(x + width/2, y + height/2, z - length/2);
528 rlTexCoord2f(source.x/texWidth, source.y/texHeight);
529 rlVertex3f(x + width/2, y + height/2, z + length/2);
530 rlTexCoord2f(source.x/texWidth, (source.y + source.height)/texHeight);
531 rlVertex3f(x + width/2, y - height/2, z + length/2);
532
533 // Left face
534 rlNormal3f( - 1.0f, 0.0f, 0.0f);
535 rlTexCoord2f(source.x/texWidth, (source.y + source.height)/texHeight);
536 rlVertex3f(x - width/2, y - height/2, z - length/2);
537 rlTexCoord2f((source.x + source.width)/texWidth, (source.y + source.height)/texHeight);
538 rlVertex3f(x - width/2, y - height/2, z + length/2);
539 rlTexCoord2f((source.x + source.width)/texWidth, source.y/texHeight);
540 rlVertex3f(x - width/2, y + height/2, z + length/2);
541 rlTexCoord2f(source.x/texWidth, source.y/texHeight);
542 rlVertex3f(x - width/2, y + height/2, z - length/2);
543
544 rlEnd();
545
546 rlSetTexture(0);
547}
548
549// Draw sphere
550void DrawSphere(Vector3 centerPos, float radius, Color color)
551{
552 DrawSphereEx(centerPos, radius, 16, 16, color);
553}
554
555// Draw sphere with extended parameters
556void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color)
557{
558 int numVertex = (rings + 2)*slices*6;
559 rlCheckRenderBatchLimit(numVertex);
560
561 rlPushMatrix();
562 // NOTE: Transformation is applied in inverse order (scale -> translate)
563 rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
564 rlScalef(radius, radius, radius);
565
567 rlColor4ub(color.r, color.g, color.b, color.a);
568
569 for (int i = 0; i < (rings + 2); i++)
570 {
571 for (int j = 0; j < slices; j++)
572 {
573 rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)),
574 sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)),
575 cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices)));
576 rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)),
577 sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
578 cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices)));
579 rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)),
580 sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
581 cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices)));
582
583 rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)),
584 sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)),
585 cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices)));
586 rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)),
587 sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i))),
588 cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices)));
589 rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)),
590 sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
591 cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices)));
592 }
593 }
594 rlEnd();
595 rlPopMatrix();
596}
597
598// Draw sphere wires
599void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color)
600{
601 int numVertex = (rings + 2)*slices*6;
602 rlCheckRenderBatchLimit(numVertex);
603
604 rlPushMatrix();
605 // NOTE: Transformation is applied in inverse order (scale -> translate)
606 rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
607 rlScalef(radius, radius, radius);
608
610 rlColor4ub(color.r, color.g, color.b, color.a);
611
612 for (int i = 0; i < (rings + 2); i++)
613 {
614 for (int j = 0; j < slices; j++)
615 {
616 rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)),
617 sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)),
618 cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices)));
619 rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)),
620 sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
621 cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices)));
622
623 rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)),
624 sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
625 cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices)));
626 rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)),
627 sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
628 cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices)));
629
630 rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)),
631 sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
632 cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices)));
633 rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)),
634 sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)),
635 cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices)));
636 }
637 }
638 rlEnd();
639 rlPopMatrix();
640}
641
642// Draw a cylinder
643// NOTE: It could be also used for pyramid and cone
644void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
645{
646 if (sides < 3) sides = 3;
647
648 int numVertex = sides*6;
649 rlCheckRenderBatchLimit(numVertex);
650
651 rlPushMatrix();
652 rlTranslatef(position.x, position.y, position.z);
653
655 rlColor4ub(color.r, color.g, color.b, color.a);
656
657 if (radiusTop > 0)
658 {
659 // Draw Body -------------------------------------------------------------------------------------
660 for (int i = 0; i < 360; i += 360/sides)
661 {
662 rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); //Bottom Left
663 rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360.0f/sides))*radiusBottom); //Bottom Right
664 rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360.0f/sides))*radiusTop); //Top Right
665
666 rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); //Top Left
667 rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); //Bottom Left
668 rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360.0f/sides))*radiusTop); //Top Right
669 }
670
671 // Draw Cap --------------------------------------------------------------------------------------
672 for (int i = 0; i < 360; i += 360/sides)
673 {
674 rlVertex3f(0, height, 0);
675 rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop);
676 rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360.0f/sides))*radiusTop);
677 }
678 }
679 else
680 {
681 // Draw Cone -------------------------------------------------------------------------------------
682 for (int i = 0; i < 360; i += 360/sides)
683 {
684 rlVertex3f(0, height, 0);
685 rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom);
686 rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360.0f/sides))*radiusBottom);
687 }
688 }
689
690 // Draw Base -----------------------------------------------------------------------------------------
691 for (int i = 0; i < 360; i += 360/sides)
692 {
693 rlVertex3f(0, 0, 0);
694 rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360.0f/sides))*radiusBottom);
695 rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom);
696 }
697 rlEnd();
698 rlPopMatrix();
699}
700
701// Draw a cylinder with base at startPos and top at endPos
702// NOTE: It could be also used for pyramid and cone
703void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color)
704{
705 if (sides < 3) sides = 3;
706
707 int numVertex = sides*6;
708 rlCheckRenderBatchLimit(numVertex);
709
710 Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
711 if ((direction.x == 0) && (direction.y == 0) && (direction.z == 0)) return;
712
713 // Construct a basis of the base and the top face:
715 Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
716
717 float baseAngle = (2.0f*PI)/sides;
718
720 rlColor4ub(color.r, color.g, color.b, color.a);
721
722 for (int i = 0; i < sides; i++) {
723 // compute the four vertices
724 float s1 = sinf(baseAngle*(i + 0))*startRadius;
725 float c1 = cosf(baseAngle*(i + 0))*startRadius;
726 Vector3 w1 = { startPos.x + s1*b1.x + c1*b2.x, startPos.y + s1*b1.y + c1*b2.y, startPos.z + s1*b1.z + c1*b2.z };
727 float s2 = sinf(baseAngle*(i + 1))*startRadius;
728 float c2 = cosf(baseAngle*(i + 1))*startRadius;
729 Vector3 w2 = { startPos.x + s2*b1.x + c2*b2.x, startPos.y + s2*b1.y + c2*b2.y, startPos.z + s2*b1.z + c2*b2.z };
730 float s3 = sinf(baseAngle*(i + 0))*endRadius;
731 float c3 = cosf(baseAngle*(i + 0))*endRadius;
732 Vector3 w3 = { endPos.x + s3*b1.x + c3*b2.x, endPos.y + s3*b1.y + c3*b2.y, endPos.z + s3*b1.z + c3*b2.z };
733 float s4 = sinf(baseAngle*(i + 1))*endRadius;
734 float c4 = cosf(baseAngle*(i + 1))*endRadius;
735 Vector3 w4 = { endPos.x + s4*b1.x + c4*b2.x, endPos.y + s4*b1.y + c4*b2.y, endPos.z + s4*b1.z + c4*b2.z };
736
737 if (startRadius > 0) { //
738 rlVertex3f(startPos.x, startPos.y, startPos.z); // |
739 rlVertex3f(w2.x, w2.y, w2.z); // T0
740 rlVertex3f(w1.x, w1.y, w1.z); // |
741 } //
742 // w2 x.-----------x startPos
743 rlVertex3f(w1.x, w1.y, w1.z); // | |\'. T0 /
744 rlVertex3f(w2.x, w2.y, w2.z); // T1 | \ '. /
745 rlVertex3f(w3.x, w3.y, w3.z); // | |T \ '. /
746 // | 2 \ T 'x w1
747 rlVertex3f(w2.x, w2.y, w2.z); // | w4 x.---\-1-|---x endPos
748 rlVertex3f(w4.x, w4.y, w4.z); // T2 '. \ |T3/
749 rlVertex3f(w3.x, w3.y, w3.z); // | '. \ | /
750 // '.\|/
751 if (endRadius > 0) { // 'x w3
752 rlVertex3f(endPos.x, endPos.y, endPos.z); // |
753 rlVertex3f(w3.x, w3.y, w3.z); // T3
754 rlVertex3f(w4.x, w4.y, w4.z); // |
755 } //
756 }
757 rlEnd();
758}
759
760// Draw a wired cylinder
761// NOTE: It could be also used for pyramid and cone
762void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
763{
764 if (sides < 3) sides = 3;
765
766 int numVertex = sides*8;
767 rlCheckRenderBatchLimit(numVertex);
768
769 rlPushMatrix();
770 rlTranslatef(position.x, position.y, position.z);
771
773 rlColor4ub(color.r, color.g, color.b, color.a);
774
775 for (int i = 0; i < 360; i += 360/sides)
776 {
777 rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom);
778 rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360.0f/sides))*radiusBottom);
779
780 rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360.0f/sides))*radiusBottom);
781 rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360.0f/sides))*radiusTop);
782
783 rlVertex3f(sinf(DEG2RAD*(i + 360.0f/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360.0f/sides))*radiusTop);
784 rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop);
785
786 rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop);
787 rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom);
788 }
789 rlEnd();
790 rlPopMatrix();
791}
792
793
794// Draw a wired cylinder with base at startPos and top at endPos
795// NOTE: It could be also used for pyramid and cone
796void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color)
797{
798 if (sides < 3) sides = 3;
799
800 int numVertex = sides*6;
801 rlCheckRenderBatchLimit(numVertex);
802
803 Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
804 if ((direction.x == 0) && (direction.y == 0) && (direction.z == 0))return;
805
806 // Construct a basis of the base and the top face:
808 Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
809
810 float baseAngle = (2.0f*PI)/sides;
811
813 rlColor4ub(color.r, color.g, color.b, color.a);
814
815 for (int i = 0; i < sides; i++) {
816 // compute the four vertices
817 float s1 = sinf(baseAngle*(i + 0))*startRadius;
818 float c1 = cosf(baseAngle*(i + 0))*startRadius;
819 Vector3 w1 = { startPos.x + s1*b1.x + c1*b2.x, startPos.y + s1*b1.y + c1*b2.y, startPos.z + s1*b1.z + c1*b2.z };
820 float s2 = sinf(baseAngle*(i + 1))*startRadius;
821 float c2 = cosf(baseAngle*(i + 1))*startRadius;
822 Vector3 w2 = { startPos.x + s2*b1.x + c2*b2.x, startPos.y + s2*b1.y + c2*b2.y, startPos.z + s2*b1.z + c2*b2.z };
823 float s3 = sinf(baseAngle*(i + 0))*endRadius;
824 float c3 = cosf(baseAngle*(i + 0))*endRadius;
825 Vector3 w3 = { endPos.x + s3*b1.x + c3*b2.x, endPos.y + s3*b1.y + c3*b2.y, endPos.z + s3*b1.z + c3*b2.z };
826 float s4 = sinf(baseAngle*(i + 1))*endRadius;
827 float c4 = cosf(baseAngle*(i + 1))*endRadius;
828 Vector3 w4 = { endPos.x + s4*b1.x + c4*b2.x, endPos.y + s4*b1.y + c4*b2.y, endPos.z + s4*b1.z + c4*b2.z };
829
830 rlVertex3f(w1.x, w1.y, w1.z);
831 rlVertex3f(w2.x, w2.y, w2.z);
832
833 rlVertex3f(w1.x, w1.y, w1.z);
834 rlVertex3f(w3.x, w3.y, w3.z);
835
836 rlVertex3f(w3.x, w3.y, w3.z);
837 rlVertex3f(w4.x, w4.y, w4.z);
838 }
839 rlEnd();
840}
841
842
843// Draw a plane
844void DrawPlane(Vector3 centerPos, Vector2 size, Color color)
845{
847
848 // NOTE: Plane is always created on XZ ground
849 rlPushMatrix();
850 rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
851 rlScalef(size.x, 1.0f, size.y);
852
854 rlColor4ub(color.r, color.g, color.b, color.a);
855 rlNormal3f(0.0f, 1.0f, 0.0f);
856
857 rlVertex3f(-0.5f, 0.0f, -0.5f);
858 rlVertex3f(-0.5f, 0.0f, 0.5f);
859 rlVertex3f(0.5f, 0.0f, 0.5f);
860 rlVertex3f(0.5f, 0.0f, -0.5f);
861 rlEnd();
862 rlPopMatrix();
863}
864
865// Draw a ray line
866void DrawRay(Ray ray, Color color)
867{
868 float scale = 10000;
869
871 rlColor4ub(color.r, color.g, color.b, color.a);
872 rlColor4ub(color.r, color.g, color.b, color.a);
873
874 rlVertex3f(ray.position.x, ray.position.y, ray.position.z);
875 rlVertex3f(ray.position.x + ray.direction.x*scale, ray.position.y + ray.direction.y*scale, ray.position.z + ray.direction.z*scale);
876 rlEnd();
877}
878
879// Draw a grid centered at (0, 0, 0)
880void DrawGrid(int slices, float spacing)
881{
882 int halfSlices = slices/2;
883
884 rlCheckRenderBatchLimit((slices + 2)*4);
885
887 for (int i = -halfSlices; i <= halfSlices; i++)
888 {
889 if (i == 0)
890 {
891 rlColor3f(0.5f, 0.5f, 0.5f);
892 rlColor3f(0.5f, 0.5f, 0.5f);
893 rlColor3f(0.5f, 0.5f, 0.5f);
894 rlColor3f(0.5f, 0.5f, 0.5f);
895 }
896 else
897 {
898 rlColor3f(0.75f, 0.75f, 0.75f);
899 rlColor3f(0.75f, 0.75f, 0.75f);
900 rlColor3f(0.75f, 0.75f, 0.75f);
901 rlColor3f(0.75f, 0.75f, 0.75f);
902 }
903
904 rlVertex3f((float)i*spacing, 0.0f, (float)-halfSlices*spacing);
905 rlVertex3f((float)i*spacing, 0.0f, (float)halfSlices*spacing);
906
907 rlVertex3f((float)-halfSlices*spacing, 0.0f, (float)i*spacing);
908 rlVertex3f((float)halfSlices*spacing, 0.0f, (float)i*spacing);
909 }
910 rlEnd();
911}
912
913// Load model from files (mesh and material)
914Model LoadModel(const char *fileName)
915{
916 Model model = { 0 };
917
918#if defined(SUPPORT_FILEFORMAT_OBJ)
919 if (IsFileExtension(fileName, ".obj")) model = LoadOBJ(fileName);
920#endif
921#if defined(SUPPORT_FILEFORMAT_IQM)
922 if (IsFileExtension(fileName, ".iqm")) model = LoadIQM(fileName);
923#endif
924#if defined(SUPPORT_FILEFORMAT_GLTF)
925 if (IsFileExtension(fileName, ".gltf") || IsFileExtension(fileName, ".glb")) model = LoadGLTF(fileName);
926#endif
927#if defined(SUPPORT_FILEFORMAT_VOX)
928 if (IsFileExtension(fileName, ".vox")) model = LoadVOX(fileName);
929#endif
930
931 // Make sure model transform is set to identity matrix!
932 model.transform = MatrixIdentity();
933
934 if (model.meshCount == 0)
935 {
936 model.meshCount = 1;
937 model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
938#if defined(SUPPORT_MESH_GENERATION)
939 TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load mesh data, default to cube mesh", fileName);
940 model.meshes[0] = GenMeshCube(1.0f, 1.0f, 1.0f);
941#else
942 TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load mesh data", fileName);
943#endif
944 }
945 else
946 {
947 // Upload vertex data to GPU (static mesh)
948 for (int i = 0; i < model.meshCount; i++) UploadMesh(&model.meshes[i], false);
949 }
950
951 if (model.materialCount == 0)
952 {
953 TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to load material data, default to white material", fileName);
954
955 model.materialCount = 1;
956 model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
957 model.materials[0] = LoadMaterialDefault();
958
959 if (model.meshMaterial == NULL) model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
960 }
961
962 return model;
963}
964
965// Load model from generated mesh
966// WARNING: A shallow copy of mesh is generated, passed by value,
967// as long as struct contains pointers to data and some values, we get a copy
968// of mesh pointing to same data as original version... be careful!
970{
971 Model model = { 0 };
972
973 model.transform = MatrixIdentity();
974
975 model.meshCount = 1;
976 model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
977 model.meshes[0] = mesh;
978
979 model.materialCount = 1;
980 model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
981 model.materials[0] = LoadMaterialDefault();
982
983 model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
984 model.meshMaterial[0] = 0; // First material index
985
986 return model;
987}
988
989// Unload model (meshes/materials) from memory (RAM and/or VRAM)
990// NOTE: This function takes care of all model elements, for a detailed control
991// over them, use UnloadMesh() and UnloadMaterial()
993{
994 // Unload meshes
995 for (int i = 0; i < model.meshCount; i++) UnloadMesh(model.meshes[i]);
996
997 // Unload materials maps
998 // NOTE: As the user could be sharing shaders and textures between models,
999 // we don't unload the material but just free it's maps,
1000 // the user is responsible for freeing models shaders and textures
1001 for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps);
1002
1003 // Unload arrays
1004 RL_FREE(model.meshes);
1005 RL_FREE(model.materials);
1006 RL_FREE(model.meshMaterial);
1007
1008 // Unload animation data
1009 RL_FREE(model.bones);
1010 RL_FREE(model.bindPose);
1011
1012 TRACELOG(LOG_INFO, "MODEL: Unloaded model (and meshes) from RAM and VRAM");
1013}
1014
1015// Unload model (but not meshes) from memory (RAM and/or VRAM)
1017{
1018 // Unload materials maps
1019 // NOTE: As the user could be sharing shaders and textures between models,
1020 // we don't unload the material but just free it's maps,
1021 // the user is responsible for freeing models shaders and textures
1022 for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps);
1023
1024 // Unload arrays
1025 RL_FREE(model.meshes);
1026 RL_FREE(model.materials);
1027 RL_FREE(model.meshMaterial);
1028
1029 // Unload animation data
1030 RL_FREE(model.bones);
1031 RL_FREE(model.bindPose);
1032
1033 TRACELOG(LOG_INFO, "MODEL: Unloaded model (but not meshes) from RAM and VRAM");
1034}
1035
1036// Compute model bounding box limits (considers all meshes)
1038{
1039 BoundingBox bounds = { 0 };
1040
1041 if (model.meshCount > 0)
1042 {
1043 Vector3 temp = { 0 };
1044 bounds = GetMeshBoundingBox(model.meshes[0]);
1045
1046 for (int i = 1; i < model.meshCount; i++)
1047 {
1048 BoundingBox tempBounds = GetMeshBoundingBox(model.meshes[i]);
1049
1050 temp.x = (bounds.min.x < tempBounds.min.x)? bounds.min.x : tempBounds.min.x;
1051 temp.y = (bounds.min.y < tempBounds.min.y)? bounds.min.y : tempBounds.min.y;
1052 temp.z = (bounds.min.z < tempBounds.min.z)? bounds.min.z : tempBounds.min.z;
1053 bounds.min = temp;
1054
1055 temp.x = (bounds.max.x > tempBounds.max.x)? bounds.max.x : tempBounds.max.x;
1056 temp.y = (bounds.max.y > tempBounds.max.y)? bounds.max.y : tempBounds.max.y;
1057 temp.z = (bounds.max.z > tempBounds.max.z)? bounds.max.z : tempBounds.max.z;
1058 bounds.max = temp;
1059 }
1060 }
1061
1062 return bounds;
1063}
1064
1065// Upload vertex data into a VAO (if supported) and VBO
1066void UploadMesh(Mesh *mesh, bool dynamic)
1067{
1068 if (mesh->vaoId > 0)
1069 {
1070 // Check if mesh has already been loaded in GPU
1071 TRACELOG(LOG_WARNING, "VAO: [ID %i] Trying to re-load an already loaded mesh", mesh->vaoId);
1072 return;
1073 }
1074
1075 mesh->vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VERTEX_BUFFERS, sizeof(unsigned int));
1076
1077 mesh->vaoId = 0; // Vertex Array Object
1078 mesh->vboId[0] = 0; // Vertex buffer: positions
1079 mesh->vboId[1] = 0; // Vertex buffer: texcoords
1080 mesh->vboId[2] = 0; // Vertex buffer: normals
1081 mesh->vboId[3] = 0; // Vertex buffer: colors
1082 mesh->vboId[4] = 0; // Vertex buffer: tangents
1083 mesh->vboId[5] = 0; // Vertex buffer: texcoords2
1084 mesh->vboId[6] = 0; // Vertex buffer: indices
1085
1086#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1087 mesh->vaoId = rlLoadVertexArray();
1089
1090 // NOTE: Attributes must be uploaded considering default locations points
1091
1092 // Enable vertex attributes: position (shader-location = 0)
1093 void *vertices = mesh->animVertices != NULL ? mesh->animVertices : mesh->vertices;
1094 mesh->vboId[0] = rlLoadVertexBuffer(vertices, mesh->vertexCount*3*sizeof(float), dynamic);
1095 rlSetVertexAttribute(0, 3, RL_FLOAT, 0, 0, 0);
1097
1098 // Enable vertex attributes: texcoords (shader-location = 1)
1099 mesh->vboId[1] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic);
1100 rlSetVertexAttribute(1, 2, RL_FLOAT, 0, 0, 0);
1102
1103 if (mesh->normals != NULL)
1104 {
1105 // Enable vertex attributes: normals (shader-location = 2)
1106 void *normals = mesh->animNormals != NULL ? mesh->animNormals : mesh->normals;
1107 mesh->vboId[2] = rlLoadVertexBuffer(normals, mesh->vertexCount*3*sizeof(float), dynamic);
1108 rlSetVertexAttribute(2, 3, RL_FLOAT, 0, 0, 0);
1110 }
1111 else
1112 {
1113 // Default color vertex attribute set to WHITE
1114 float value[3] = { 1.0f, 1.0f, 1.0f };
1117 }
1118
1119 if (mesh->colors != NULL)
1120 {
1121 // Enable vertex attribute: color (shader-location = 3)
1122 mesh->vboId[3] = rlLoadVertexBuffer(mesh->colors, mesh->vertexCount*4*sizeof(unsigned char), dynamic);
1123 rlSetVertexAttribute(3, 4, RL_UNSIGNED_BYTE, 1, 0, 0);
1125 }
1126 else
1127 {
1128 // Default color vertex attribute set to WHITE
1129 float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
1132 }
1133
1134 if (mesh->tangents != NULL)
1135 {
1136 // Enable vertex attribute: tangent (shader-location = 4)
1137 mesh->vboId[4] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), dynamic);
1138 rlSetVertexAttribute(4, 4, RL_FLOAT, 0, 0, 0);
1140 }
1141 else
1142 {
1143 // Default tangents vertex attribute
1144 float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1147 }
1148
1149 if (mesh->texcoords2 != NULL)
1150 {
1151 // Enable vertex attribute: texcoord2 (shader-location = 5)
1152 mesh->vboId[5] = rlLoadVertexBuffer(mesh->texcoords2, mesh->vertexCount*2*sizeof(float), dynamic);
1153 rlSetVertexAttribute(5, 2, RL_FLOAT, 0, 0, 0);
1155 }
1156 else
1157 {
1158 // Default texcoord2 vertex attribute
1159 float value[2] = { 0.0f, 0.0f };
1162 }
1163
1164 if (mesh->indices != NULL)
1165 {
1166 mesh->vboId[6] = rlLoadVertexBufferElement(mesh->indices, mesh->triangleCount*3*sizeof(unsigned short), dynamic);
1167 }
1168
1169 if (mesh->vaoId > 0) TRACELOG(LOG_INFO, "VAO: [ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vaoId);
1170 else TRACELOG(LOG_INFO, "VBO: Mesh uploaded successfully to VRAM (GPU)");
1171
1173#endif
1174}
1175
1176// Update mesh vertex data in GPU for a specific buffer index
1177void UpdateMeshBuffer(Mesh mesh, int index, const void *data, int dataSize, int offset)
1178{
1179 rlUpdateVertexBuffer(mesh.vboId[index], data, dataSize, offset);
1180}
1181
1182// Draw a 3d mesh with material and transform
1183void DrawMesh(Mesh mesh, Material material, Matrix transform)
1184{
1185#if defined(GRAPHICS_API_OPENGL_11)
1186 #define GL_VERTEX_ARRAY 0x8074
1187 #define GL_NORMAL_ARRAY 0x8075
1188 #define GL_COLOR_ARRAY 0x8076
1189 #define GL_TEXTURE_COORD_ARRAY 0x8078
1190
1192
1193 rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices);
1194 rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords);
1195 rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals);
1196 rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors);
1197
1198 rlPushMatrix();
1199 rlMultMatrixf(MatrixToFloat(transform));
1201 material.maps[MATERIAL_MAP_DIFFUSE].color.g,
1202 material.maps[MATERIAL_MAP_DIFFUSE].color.b,
1203 material.maps[MATERIAL_MAP_DIFFUSE].color.a);
1204
1205 if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, mesh.indices);
1206 else rlDrawVertexArray(0, mesh.vertexCount);
1207 rlPopMatrix();
1208
1209 rlDisableStatePointer(GL_VERTEX_ARRAY);
1210 rlDisableStatePointer(GL_TEXTURE_COORD_ARRAY);
1211 rlDisableStatePointer(GL_NORMAL_ARRAY);
1212 rlDisableStatePointer(GL_COLOR_ARRAY);
1213
1215#endif
1216
1217#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1218 // Bind shader program
1219 rlEnableShader(material.shader.id);
1220
1221 // Send required data to shader (matrices, values)
1222 //-----------------------------------------------------
1223 // Upload to shader material.colDiffuse
1224 if (material.shader.locs[SHADER_LOC_COLOR_DIFFUSE] != -1)
1225 {
1226 float values[4] = {
1227 (float)material.maps[MATERIAL_MAP_DIFFUSE].color.r/255.0f,
1228 (float)material.maps[MATERIAL_MAP_DIFFUSE].color.g/255.0f,
1229 (float)material.maps[MATERIAL_MAP_DIFFUSE].color.b/255.0f,
1230 (float)material.maps[MATERIAL_MAP_DIFFUSE].color.a/255.0f
1231 };
1232
1234 }
1235
1236 // Upload to shader material.colSpecular (if location available)
1237 if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1)
1238 {
1239 float values[4] = {
1240 (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.r/255.0f,
1241 (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.g/255.0f,
1242 (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.b/255.0f,
1243 (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.a/255.0f
1244 };
1245
1247 }
1248
1249 // Get a copy of current matrices to work with,
1250 // just in case stereo render is required and we need to modify them
1251 // NOTE: At this point the modelview matrix just contains the view matrix (camera)
1252 // That's because BeginMode3D() sets it and there is no model-drawing function
1253 // that modifies it, all use rlPushMatrix() and rlPopMatrix()
1254 Matrix matModel = MatrixIdentity();
1255 Matrix matView = rlGetMatrixModelview();
1256 Matrix matModelView = MatrixIdentity();
1257 Matrix matProjection = rlGetMatrixProjection();
1258
1259 // Upload view and projection matrices (if locations available)
1262
1263 // Model transformation matrix is send to shader uniform location: SHADER_LOC_MATRIX_MODEL
1264 if (material.shader.locs[SHADER_LOC_MATRIX_MODEL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MODEL], transform);
1265
1266 // Accumulate several model transformations:
1267 // transform: model transformation provided (includes DrawModel() params combined with model.transform)
1268 // rlGetMatrixTransform(): rlgl internal transform matrix due to push/pop matrix stack
1269 matModel = MatrixMultiply(transform, rlGetMatrixTransform());
1270
1271 // Get model-view matrix
1272 matModelView = MatrixMultiply(matModel, matView);
1273
1274 // Upload model normal matrix (if locations available)
1276 //-----------------------------------------------------
1277
1278 // Bind active texture maps (if available)
1279 for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
1280 {
1281 if (material.maps[i].texture.id > 0)
1282 {
1283 // Select current shader texture slot
1285
1286 // Enable texture for active slot
1287 if ((i == MATERIAL_MAP_IRRADIANCE) ||
1288 (i == MATERIAL_MAP_PREFILTER) ||
1290 else rlEnableTexture(material.maps[i].texture.id);
1291
1293 }
1294 }
1295
1296 // Try binding vertex array objects (VAO)
1297 // or use VBOs if not possible
1298 if (!rlEnableVertexArray(mesh.vaoId))
1299 {
1300 // Bind mesh VBO data: vertex position (shader-location = 0)
1301 rlEnableVertexBuffer(mesh.vboId[0]);
1304
1305 // Bind mesh VBO data: vertex texcoords (shader-location = 1)
1306 rlEnableVertexBuffer(mesh.vboId[1]);
1309
1310 if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1)
1311 {
1312 // Bind mesh VBO data: vertex normals (shader-location = 2)
1313 rlEnableVertexBuffer(mesh.vboId[2]);
1316 }
1317
1318 // Bind mesh VBO data: vertex colors (shader-location = 3, if available)
1319 if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1)
1320 {
1321 if (mesh.vboId[3] != 0)
1322 {
1323 rlEnableVertexBuffer(mesh.vboId[3]);
1326 }
1327 else
1328 {
1329 // Set default value for unused attribute
1330 // NOTE: Required when using default shader and no VAO support
1331 float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
1334 }
1335 }
1336
1337 // Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
1338 if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1)
1339 {
1340 rlEnableVertexBuffer(mesh.vboId[4]);
1343 }
1344
1345 // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
1346 if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1)
1347 {
1348 rlEnableVertexBuffer(mesh.vboId[5]);
1351 }
1352
1353 if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]);
1354 }
1355
1356 int eyeCount = 1;
1357 if (rlIsStereoRenderEnabled()) eyeCount = 2;
1358
1359 for (int eye = 0; eye < eyeCount; eye++)
1360 {
1361 // Calculate model-view-projection matrix (MVP)
1362 Matrix matModelViewProjection = MatrixIdentity();
1363 if (eyeCount == 1) matModelViewProjection = MatrixMultiply(matModelView, matProjection);
1364 else
1365 {
1366 // Setup current eye viewport (half screen width)
1368 matModelViewProjection = MatrixMultiply(MatrixMultiply(matModelView, rlGetMatrixViewOffsetStereo(eye)), rlGetMatrixProjectionStereo(eye));
1369 }
1370
1371 // Send combined model-view-projection matrix to shader
1372 rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MVP], matModelViewProjection);
1373
1374 // Draw mesh
1375 if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, 0);
1376 else rlDrawVertexArray(0, mesh.vertexCount);
1377 }
1378
1379 // Unbind all binded texture maps
1380 for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
1381 {
1382 // Select current shader texture slot
1384
1385 // Disable texture for active slot
1386 if ((i == MATERIAL_MAP_IRRADIANCE) ||
1387 (i == MATERIAL_MAP_PREFILTER) ||
1389 else rlDisableTexture();
1390 }
1391
1392 // Disable all possible vertex array objects (or VBOs)
1396
1397 // Disable shader program
1399
1400 // Restore rlgl internal modelview and projection matrices
1401 rlSetMatrixModelview(matView);
1402 rlSetMatrixProjection(matProjection);
1403#endif
1404}
1405
1406// Draw multiple mesh instances with material and different transforms
1407void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, int instances)
1408{
1409#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1410 // Instancing required variables
1411 float16 *instanceTransforms = NULL;
1412 unsigned int instancesVboId = 0;
1413
1414 // Bind shader program
1415 rlEnableShader(material.shader.id);
1416
1417 // Send required data to shader (matrices, values)
1418 //-----------------------------------------------------
1419 // Upload to shader material.colDiffuse
1420 if (material.shader.locs[SHADER_LOC_COLOR_DIFFUSE] != -1)
1421 {
1422 float values[4] = {
1423 (float)material.maps[MATERIAL_MAP_DIFFUSE].color.r/255.0f,
1424 (float)material.maps[MATERIAL_MAP_DIFFUSE].color.g/255.0f,
1425 (float)material.maps[MATERIAL_MAP_DIFFUSE].color.b/255.0f,
1426 (float)material.maps[MATERIAL_MAP_DIFFUSE].color.a/255.0f
1427 };
1428
1430 }
1431
1432 // Upload to shader material.colSpecular (if location available)
1433 if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1)
1434 {
1435 float values[4] = {
1436 (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.r/255.0f,
1437 (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.g/255.0f,
1438 (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.b/255.0f,
1439 (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.a/255.0f
1440 };
1441
1443 }
1444
1445 // Get a copy of current matrices to work with,
1446 // just in case stereo render is required and we need to modify them
1447 // NOTE: At this point the modelview matrix just contains the view matrix (camera)
1448 // That's because BeginMode3D() sets it and there is no model-drawing function
1449 // that modifies it, all use rlPushMatrix() and rlPopMatrix()
1450 Matrix matModel = MatrixIdentity();
1451 Matrix matView = rlGetMatrixModelview();
1452 Matrix matModelView = MatrixIdentity();
1453 Matrix matProjection = rlGetMatrixProjection();
1454
1455 // Upload view and projection matrices (if locations available)
1458
1459 // Create instances buffer
1460 instanceTransforms = (float16 *)RL_MALLOC(instances*sizeof(float16));
1461
1462 // Fill buffer with instances transformations as float16 arrays
1463 for (int i = 0; i < instances; i++) instanceTransforms[i] = MatrixToFloatV(transforms[i]);
1464
1465 // Enable mesh VAO to attach new buffer
1467
1468 // This could alternatively use a static VBO and either glMapBuffer() or glBufferSubData().
1469 // It isn't clear which would be reliably faster in all cases and on all platforms,
1470 // anecdotally glMapBuffer() seems very slow (syncs) while glBufferSubData() seems
1471 // no faster, since we're transferring all the transform matrices anyway
1472 instancesVboId = rlLoadVertexBuffer(instanceTransforms, instances*sizeof(float16), false);
1473
1474 // Instances transformation matrices are send to shader attribute location: SHADER_LOC_MATRIX_MODEL
1475 for (unsigned int i = 0; i < 4; i++)
1476 {
1478 rlSetVertexAttribute(material.shader.locs[SHADER_LOC_MATRIX_MODEL] + i, 4, RL_FLOAT, 0, sizeof(Matrix), (void *)(i*sizeof(Vector4)));
1480 }
1481
1484
1485 // Accumulate internal matrix transform (push/pop) and view matrix
1486 // NOTE: In this case, model instance transformation must be computed in the shader
1487 matModelView = MatrixMultiply(rlGetMatrixTransform(), matView);
1488
1489 // Upload model normal matrix (if locations available)
1491 //-----------------------------------------------------
1492
1493 // Bind active texture maps (if available)
1494 for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
1495 {
1496 if (material.maps[i].texture.id > 0)
1497 {
1498 // Select current shader texture slot
1500
1501 // Enable texture for active slot
1502 if ((i == MATERIAL_MAP_IRRADIANCE) ||
1503 (i == MATERIAL_MAP_PREFILTER) ||
1505 else rlEnableTexture(material.maps[i].texture.id);
1506
1508 }
1509 }
1510
1511 // Try binding vertex array objects (VAO)
1512 // or use VBOs if not possible
1513 if (!rlEnableVertexArray(mesh.vaoId))
1514 {
1515 // Bind mesh VBO data: vertex position (shader-location = 0)
1516 rlEnableVertexBuffer(mesh.vboId[0]);
1519
1520 // Bind mesh VBO data: vertex texcoords (shader-location = 1)
1521 rlEnableVertexBuffer(mesh.vboId[1]);
1524
1525 if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1)
1526 {
1527 // Bind mesh VBO data: vertex normals (shader-location = 2)
1528 rlEnableVertexBuffer(mesh.vboId[2]);
1531 }
1532
1533 // Bind mesh VBO data: vertex colors (shader-location = 3, if available)
1534 if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1)
1535 {
1536 if (mesh.vboId[3] != 0)
1537 {
1538 rlEnableVertexBuffer(mesh.vboId[3]);
1541 }
1542 else
1543 {
1544 // Set default value for unused attribute
1545 // NOTE: Required when using default shader and no VAO support
1546 float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
1549 }
1550 }
1551
1552 // Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
1553 if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1)
1554 {
1555 rlEnableVertexBuffer(mesh.vboId[4]);
1558 }
1559
1560 // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
1561 if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1)
1562 {
1563 rlEnableVertexBuffer(mesh.vboId[5]);
1566 }
1567
1568 if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]);
1569 }
1570
1571 int eyeCount = 1;
1572 if (rlIsStereoRenderEnabled()) eyeCount = 2;
1573
1574 for (int eye = 0; eye < eyeCount; eye++)
1575 {
1576 // Calculate model-view-projection matrix (MVP)
1577 Matrix matModelViewProjection = MatrixIdentity();
1578 if (eyeCount == 1) matModelViewProjection = MatrixMultiply(matModelView, matProjection);
1579 else
1580 {
1581 // Setup current eye viewport (half screen width)
1583 matModelViewProjection = MatrixMultiply(MatrixMultiply(matModelView, rlGetMatrixViewOffsetStereo(eye)), rlGetMatrixProjectionStereo(eye));
1584 }
1585
1586 // Send combined model-view-projection matrix to shader
1587 rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MVP], matModelViewProjection);
1588
1589 // Draw mesh instanced
1590 if (mesh.indices != NULL) rlDrawVertexArrayElementsInstanced(0, mesh.triangleCount*3, 0, instances);
1591 else rlDrawVertexArrayInstanced(0, mesh.vertexCount, instances);
1592 }
1593
1594 // Unbind all binded texture maps
1595 for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
1596 {
1597 // Select current shader texture slot
1599
1600 // Disable texture for active slot
1601 if ((i == MATERIAL_MAP_IRRADIANCE) ||
1602 (i == MATERIAL_MAP_PREFILTER) ||
1604 else rlDisableTexture();
1605 }
1606
1607 // Disable all possible vertex array objects (or VBOs)
1611
1612 // Disable shader program
1614
1615 // Remove instance transforms buffer
1616 rlUnloadVertexBuffer(instancesVboId);
1617 RL_FREE(instanceTransforms);
1618#endif
1619}
1620
1621// Unload mesh from memory (RAM and VRAM)
1623{
1624 // Unload rlgl mesh vboId data
1626
1627 if (mesh.vboId != NULL) for (int i = 0; i < MAX_MESH_VERTEX_BUFFERS; i++) rlUnloadVertexBuffer(mesh.vboId[i]);
1628 RL_FREE(mesh.vboId);
1629
1630 RL_FREE(mesh.vertices);
1631 RL_FREE(mesh.texcoords);
1632 RL_FREE(mesh.normals);
1633 RL_FREE(mesh.colors);
1634 RL_FREE(mesh.tangents);
1635 RL_FREE(mesh.texcoords2);
1636 RL_FREE(mesh.indices);
1637
1638 RL_FREE(mesh.animVertices);
1639 RL_FREE(mesh.animNormals);
1640 RL_FREE(mesh.boneWeights);
1641 RL_FREE(mesh.boneIds);
1642}
1643
1644// Export mesh data to file
1645bool ExportMesh(Mesh mesh, const char *fileName)
1646{
1647 bool success = false;
1648
1649 if (IsFileExtension(fileName, ".obj"))
1650 {
1651 // Estimated data size, it should be enough...
1652 int dataSize = mesh.vertexCount*(int)strlen("v 0000.00f 0000.00f 0000.00f") +
1653 mesh.vertexCount*(int)strlen("vt 0.000f 0.00f") +
1654 mesh.vertexCount*(int)strlen("vn 0.000f 0.00f 0.00f") +
1655 mesh.triangleCount*(int)strlen("f 00000/00000/00000 00000/00000/00000 00000/00000/00000");
1656
1657 // NOTE: Text data buffer size is estimated considering mesh data size
1658 char *txtData = (char *)RL_CALLOC(dataSize*2 + 2000, sizeof(char));
1659
1660 int byteCount = 0;
1661 byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n");
1662 byteCount += sprintf(txtData + byteCount, "# // //\n");
1663 byteCount += sprintf(txtData + byteCount, "# // rMeshOBJ exporter v1.0 - Mesh exported as triangle faces and not optimized //\n");
1664 byteCount += sprintf(txtData + byteCount, "# // //\n");
1665 byteCount += sprintf(txtData + byteCount, "# // more info and bugs-report: github.com/raysan5/raylib //\n");
1666 byteCount += sprintf(txtData + byteCount, "# // feedback and support: ray[at]raylib.com //\n");
1667 byteCount += sprintf(txtData + byteCount, "# // //\n");
1668 byteCount += sprintf(txtData + byteCount, "# // Copyright (c) 2018-2022 Ramon Santamaria (@raysan5) //\n");
1669 byteCount += sprintf(txtData + byteCount, "# // //\n");
1670 byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n\n");
1671 byteCount += sprintf(txtData + byteCount, "# Vertex Count: %i\n", mesh.vertexCount);
1672 byteCount += sprintf(txtData + byteCount, "# Triangle Count: %i\n\n", mesh.triangleCount);
1673
1674 byteCount += sprintf(txtData + byteCount, "g mesh\n");
1675
1676 for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3)
1677 {
1678 byteCount += sprintf(txtData + byteCount, "v %.2f %.2f %.2f\n", mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]);
1679 }
1680
1681 for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 2)
1682 {
1683 byteCount += sprintf(txtData + byteCount, "vt %.3f %.3f\n", mesh.texcoords[v], mesh.texcoords[v + 1]);
1684 }
1685
1686 for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3)
1687 {
1688 byteCount += sprintf(txtData + byteCount, "vn %.3f %.3f %.3f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]);
1689 }
1690
1691 if (mesh.indices != NULL)
1692 {
1693 for (int i = 0, v = 0; i < mesh.triangleCount; i++, v += 3)
1694 {
1695 byteCount += sprintf(txtData + byteCount, "f %i/%i/%i %i/%i/%i %i/%i/%i\n",
1696 mesh.indices[v] + 1, mesh.indices[v] + 1, mesh.indices[v] + 1,
1697 mesh.indices[v + 1] + 1, mesh.indices[v + 1] + 1, mesh.indices[v + 1] + 1,
1698 mesh.indices[v + 2] + 1, mesh.indices[v + 2] + 1, mesh.indices[v + 2] + 1);
1699 }
1700 }
1701 else
1702 {
1703 for (int i = 0, v = 1; i < mesh.triangleCount; i++, v += 3)
1704 {
1705 byteCount += sprintf(txtData + byteCount, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", v, v, v, v + 1, v + 1, v + 1, v + 2, v + 2, v + 2);
1706 }
1707 }
1708
1709 byteCount += sprintf(txtData + byteCount, "\n");
1710
1711 // NOTE: Text data length exported is determined by '\0' (NULL) character
1712 success = SaveFileText(fileName, txtData);
1713
1714 RL_FREE(txtData);
1715 }
1716 else if (IsFileExtension(fileName, ".raw"))
1717 {
1718 // TODO: Support additional file formats to export mesh vertex data
1719 }
1720
1721 return success;
1722}
1723
1724// Load materials from model file
1725Material *LoadMaterials(const char *fileName, int *materialCount)
1726{
1727 Material *materials = NULL;
1728 unsigned int count = 0;
1729
1730 // TODO: Support IQM and GLTF for materials parsing
1731
1732#if defined(SUPPORT_FILEFORMAT_MTL)
1733 if (IsFileExtension(fileName, ".mtl"))
1734 {
1735 tinyobj_material_t *mats = NULL;
1736
1737 int result = tinyobj_parse_mtl_file(&mats, &count, fileName);
1738 if (result != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName);
1739
1740 // TODO: Process materials to return
1741
1742 tinyobj_materials_free(mats, count);
1743 }
1744#else
1745 TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load material file", fileName);
1746#endif
1747
1748 // Set materials shader to default (DIFFUSE, SPECULAR, NORMAL)
1749 if (materials != NULL)
1750 {
1751 for (unsigned int i = 0; i < count; i++)
1752 {
1753 materials[i].shader.id = rlGetShaderIdDefault();
1754 materials[i].shader.locs = rlGetShaderLocsDefault();
1755 }
1756 }
1757
1758 *materialCount = count;
1759 return materials;
1760}
1761
1762// Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)
1764{
1765 Material material = { 0 };
1766 material.maps = (MaterialMap *)RL_CALLOC(MAX_MATERIAL_MAPS, sizeof(MaterialMap));
1767
1768 // Using rlgl default shader
1769 material.shader.id = rlGetShaderIdDefault();
1770 material.shader.locs = rlGetShaderLocsDefault();
1771
1772 // Using rlgl default texture (1x1 pixel, UNCOMPRESSED_R8G8B8A8, 1 mipmap)
1774 //material.maps[MATERIAL_MAP_NORMAL].texture; // NOTE: By default, not set
1775 //material.maps[MATERIAL_MAP_SPECULAR].texture; // NOTE: By default, not set
1776
1777 material.maps[MATERIAL_MAP_DIFFUSE].color = WHITE; // Diffuse color
1778 material.maps[MATERIAL_MAP_SPECULAR].color = WHITE; // Specular color
1779
1780 return material;
1781}
1782
1783// Unload material from memory
1785{
1786 // Unload material shader (avoid unloading default shader, managed by raylib)
1787 if (material.shader.id != rlGetShaderIdDefault()) UnloadShader(material.shader);
1788
1789 // Unload loaded texture maps (avoid unloading default texture, managed by raylib)
1790 if (material.maps != NULL)
1791 {
1792 for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
1793 {
1794 if (material.maps[i].texture.id != rlGetTextureIdDefault()) rlUnloadTexture(material.maps[i].texture.id);
1795 }
1796 }
1797
1798 RL_FREE(material.maps);
1799}
1800
1801// Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...)
1802// NOTE: Previous texture should be manually unloaded
1803void SetMaterialTexture(Material *material, int mapType, Texture2D texture)
1804{
1805 material->maps[mapType].texture = texture;
1806}
1807
1808// Set the material for a mesh
1809void SetModelMeshMaterial(Model *model, int meshId, int materialId)
1810{
1811 if (meshId >= model->meshCount) TRACELOG(LOG_WARNING, "MESH: Id greater than mesh count");
1812 else if (materialId >= model->materialCount) TRACELOG(LOG_WARNING, "MATERIAL: Id greater than material count");
1813 else model->meshMaterial[meshId] = materialId;
1814}
1815
1816// Load model animations from file
1817ModelAnimation *LoadModelAnimations(const char *fileName, unsigned int *animCount)
1818{
1819 ModelAnimation *animations = NULL;
1820
1821#if defined(SUPPORT_FILEFORMAT_IQM)
1822 if (IsFileExtension(fileName, ".iqm")) animations = LoadModelAnimationsIQM(fileName, animCount);
1823#endif
1824#if defined(SUPPORT_FILEFORMAT_GLTF)
1825 //if (IsFileExtension(fileName, ".gltf;.glb")) animations = LoadModelAnimationGLTF(fileName, animCount);
1826#endif
1827
1828 return animations;
1829}
1830
1831// Update model animated vertex data (positions and normals) for a given frame
1832// NOTE: Updated data is uploaded to GPU
1833void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
1834{
1835 if ((anim.frameCount > 0) && (anim.bones != NULL) && (anim.framePoses != NULL))
1836 {
1837 if (frame >= anim.frameCount) frame = frame%anim.frameCount;
1838
1839 for (int m = 0; m < model.meshCount; m++)
1840 {
1841 Mesh mesh = model.meshes[m];
1842 if (mesh.boneIds == NULL || mesh.boneWeights == NULL)
1843 {
1844 TRACELOG(LOG_WARNING, "MODEL: UpdateModelAnimation Mesh %i has no connection to bones",m);
1845 continue;
1846 }
1847
1848 bool updated = false; // set to true when anim vertex information is updated
1849 Vector3 animVertex = { 0 };
1850 Vector3 animNormal = { 0 };
1851
1852 Vector3 inTranslation = { 0 };
1853 Quaternion inRotation = { 0 };
1854 // Vector3 inScale = { 0 };
1855
1856 Vector3 outTranslation = { 0 };
1857 Quaternion outRotation = { 0 };
1858 Vector3 outScale = { 0 };
1859
1860 int boneId = 0;
1861 int boneCounter = 0;
1862 float boneWeight = 0.0;
1863
1864 const int vValues = mesh.vertexCount*3;
1865 for (int vCounter = 0; vCounter < vValues; vCounter+=3)
1866 {
1867 mesh.animVertices[vCounter] = 0;
1868 mesh.animVertices[vCounter + 1] = 0;
1869 mesh.animVertices[vCounter + 2] = 0;
1870
1871 if (mesh.animNormals!=NULL)
1872 {
1873 mesh.animNormals[vCounter] = 0;
1874 mesh.animNormals[vCounter + 1] = 0;
1875 mesh.animNormals[vCounter + 2] = 0;
1876 }
1877
1878 // Iterates over 4 bones per vertex
1879 for (int j = 0; j < 4; j++, boneCounter++)
1880 {
1881 boneWeight = mesh.boneWeights[boneCounter];
1882 // early stop when no transformation will be applied
1883 if (boneWeight == 0.0f)
1884 {
1885 continue;
1886 }
1887 boneId = mesh.boneIds[boneCounter];
1888 //int boneIdParent = model.bones[boneId].parent;
1889 inTranslation = model.bindPose[boneId].translation;
1890 inRotation = model.bindPose[boneId].rotation;
1891 // inScale = model.bindPose[boneId].scale;
1892 outTranslation = anim.framePoses[frame][boneId].translation;
1893 outRotation = anim.framePoses[frame][boneId].rotation;
1894 outScale = anim.framePoses[frame][boneId].scale;
1895
1896 // Vertices processing
1897 // NOTE: We use meshes.vertices (default vertex position) to calculate meshes.animVertices (animated vertex position)
1898 animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] };
1899 animVertex = Vector3Multiply(animVertex, outScale);
1900 animVertex = Vector3Subtract(animVertex, inTranslation);
1901 animVertex = Vector3RotateByQuaternion(animVertex, QuaternionMultiply(outRotation, QuaternionInvert(inRotation)));
1902 animVertex = Vector3Add(animVertex, outTranslation);
1903// animVertex = Vector3Transform(animVertex, model.transform);
1904 mesh.animVertices[vCounter] += animVertex.x*boneWeight;
1905 mesh.animVertices[vCounter + 1] += animVertex.y*boneWeight;
1906 mesh.animVertices[vCounter + 2] += animVertex.z*boneWeight;
1907 updated = true;
1908
1909 // Normals processing
1910 // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
1911 if (mesh.normals != NULL)
1912 {
1913 animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] };
1914 animNormal = Vector3RotateByQuaternion(animNormal, QuaternionMultiply(outRotation, QuaternionInvert(inRotation)));
1915 mesh.animNormals[vCounter] += animNormal.x*boneWeight;
1916 mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight;
1917 mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight;
1918 }
1919 }
1920 }
1921
1922 // Upload new vertex data to GPU for model drawing
1923 // Only update data when values changed.
1924 if (updated){
1925 rlUpdateVertexBuffer(mesh.vboId[0], mesh.animVertices, mesh.vertexCount*3*sizeof(float), 0); // Update vertex position
1926 rlUpdateVertexBuffer(mesh.vboId[2], mesh.animNormals, mesh.vertexCount*3*sizeof(float), 0); // Update vertex normals
1927 }
1928 }
1929 }
1930}
1931
1932// Unload animation array data
1933void UnloadModelAnimations(ModelAnimation *animations, unsigned int count)
1934{
1935 for (unsigned int i = 0; i < count; i++) UnloadModelAnimation(animations[i]);
1936 RL_FREE(animations);
1937}
1938
1939// Unload animation data
1941{
1942 for (int i = 0; i < anim.frameCount; i++) RL_FREE(anim.framePoses[i]);
1943
1944 RL_FREE(anim.bones);
1945 RL_FREE(anim.framePoses);
1946}
1947
1948// Check model animation skeleton match
1949// NOTE: Only number of bones and parent connections are checked
1951{
1952 int result = true;
1953
1954 if (model.boneCount != anim.boneCount) result = false;
1955 else
1956 {
1957 for (int i = 0; i < model.boneCount; i++)
1958 {
1959 if (model.bones[i].parent != anim.bones[i].parent) { result = false; break; }
1960 }
1961 }
1962
1963 return result;
1964}
1965
1966#if defined(SUPPORT_MESH_GENERATION)
1967// Generate polygonal mesh
1968Mesh GenMeshPoly(int sides, float radius)
1969{
1970 Mesh mesh = { 0 };
1971
1972 if (sides < 3) return mesh;
1973
1974 int vertexCount = sides*3;
1975
1976 // Vertices definition
1977 Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
1978
1979 float d = 0.0f, dStep = 360.0f/sides;
1980 for (int v = 0; v < vertexCount; v += 3)
1981 {
1982 vertices[v] = (Vector3){ 0.0f, 0.0f, 0.0f };
1983 vertices[v + 1] = (Vector3){ sinf(DEG2RAD*d)*radius, 0.0f, cosf(DEG2RAD*d)*radius };
1984 vertices[v + 2] = (Vector3){sinf(DEG2RAD*(d+dStep))*radius, 0.0f, cosf(DEG2RAD*(d+dStep))*radius };
1985 d += dStep;
1986 }
1987
1988 // Normals definition
1989 Vector3 *normals = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
1990 for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f }; // Vector3.up;
1991
1992 // TexCoords definition
1993 Vector2 *texcoords = (Vector2 *)RL_MALLOC(vertexCount*sizeof(Vector2));
1994 for (int n = 0; n < vertexCount; n++) texcoords[n] = (Vector2){ 0.0f, 0.0f };
1995
1996 mesh.vertexCount = vertexCount;
1997 mesh.triangleCount = sides;
1998 mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
1999 mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
2000 mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
2001
2002 // Mesh vertices position array
2003 for (int i = 0; i < mesh.vertexCount; i++)
2004 {
2005 mesh.vertices[3*i] = vertices[i].x;
2006 mesh.vertices[3*i + 1] = vertices[i].y;
2007 mesh.vertices[3*i + 2] = vertices[i].z;
2008 }
2009
2010 // Mesh texcoords array
2011 for (int i = 0; i < mesh.vertexCount; i++)
2012 {
2013 mesh.texcoords[2*i] = texcoords[i].x;
2014 mesh.texcoords[2*i + 1] = texcoords[i].y;
2015 }
2016
2017 // Mesh normals array
2018 for (int i = 0; i < mesh.vertexCount; i++)
2019 {
2020 mesh.normals[3*i] = normals[i].x;
2021 mesh.normals[3*i + 1] = normals[i].y;
2022 mesh.normals[3*i + 2] = normals[i].z;
2023 }
2024
2025 RL_FREE(vertices);
2026 RL_FREE(normals);
2027 RL_FREE(texcoords);
2028
2029 // Upload vertex data to GPU (static mesh)
2030 // NOTE: mesh.vboId array is allocated inside UploadMesh()
2031 UploadMesh(&mesh, false);
2032
2033 return mesh;
2034}
2035
2036// Generate plane mesh (with subdivisions)
2037Mesh GenMeshPlane(float width, float length, int resX, int resZ)
2038{
2039 Mesh mesh = { 0 };
2040
2041#define CUSTOM_MESH_GEN_PLANE
2042#if defined(CUSTOM_MESH_GEN_PLANE)
2043 resX++;
2044 resZ++;
2045
2046 // Vertices definition
2047 int vertexCount = resX*resZ; // vertices get reused for the faces
2048
2049 Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
2050 for (int z = 0; z < resZ; z++)
2051 {
2052 // [-length/2, length/2]
2053 float zPos = ((float)z/(resZ - 1) - 0.5f)*length;
2054 for (int x = 0; x < resX; x++)
2055 {
2056 // [-width/2, width/2]
2057 float xPos = ((float)x/(resX - 1) - 0.5f)*width;
2058 vertices[x + z*resX] = (Vector3){ xPos, 0.0f, zPos };
2059 }
2060 }
2061
2062 // Normals definition
2063 Vector3 *normals = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
2064 for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f }; // Vector3.up;
2065
2066 // TexCoords definition
2067 Vector2 *texcoords = (Vector2 *)RL_MALLOC(vertexCount*sizeof(Vector2));
2068 for (int v = 0; v < resZ; v++)
2069 {
2070 for (int u = 0; u < resX; u++)
2071 {
2072 texcoords[u + v*resX] = (Vector2){ (float)u/(resX - 1), (float)v/(resZ - 1) };
2073 }
2074 }
2075
2076 // Triangles definition (indices)
2077 int numFaces = (resX - 1)*(resZ - 1);
2078 int *triangles = (int *)RL_MALLOC(numFaces*6*sizeof(int));
2079 int t = 0;
2080 for (int face = 0; face < numFaces; face++)
2081 {
2082 // Retrieve lower left corner from face ind
2083 int i = face % (resX - 1) + (face/(resZ - 1)*resX);
2084
2085 triangles[t++] = i + resX;
2086 triangles[t++] = i + 1;
2087 triangles[t++] = i;
2088
2089 triangles[t++] = i + resX;
2090 triangles[t++] = i + resX + 1;
2091 triangles[t++] = i + 1;
2092 }
2093
2094 mesh.vertexCount = vertexCount;
2095 mesh.triangleCount = numFaces*2;
2096 mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
2097 mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
2098 mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
2099 mesh.indices = (unsigned short *)RL_MALLOC(mesh.triangleCount*3*sizeof(unsigned short));
2100
2101 // Mesh vertices position array
2102 for (int i = 0; i < mesh.vertexCount; i++)
2103 {
2104 mesh.vertices[3*i] = vertices[i].x;
2105 mesh.vertices[3*i + 1] = vertices[i].y;
2106 mesh.vertices[3*i + 2] = vertices[i].z;
2107 }
2108
2109 // Mesh texcoords array
2110 for (int i = 0; i < mesh.vertexCount; i++)
2111 {
2112 mesh.texcoords[2*i] = texcoords[i].x;
2113 mesh.texcoords[2*i + 1] = texcoords[i].y;
2114 }
2115
2116 // Mesh normals array
2117 for (int i = 0; i < mesh.vertexCount; i++)
2118 {
2119 mesh.normals[3*i] = normals[i].x;
2120 mesh.normals[3*i + 1] = normals[i].y;
2121 mesh.normals[3*i + 2] = normals[i].z;
2122 }
2123
2124 // Mesh indices array initialization
2125 for (int i = 0; i < mesh.triangleCount*3; i++) mesh.indices[i] = triangles[i];
2126
2127 RL_FREE(vertices);
2128 RL_FREE(normals);
2129 RL_FREE(texcoords);
2130 RL_FREE(triangles);
2131
2132#else // Use par_shapes library to generate plane mesh
2133
2134 par_shapes_mesh *plane = par_shapes_create_plane(resX, resZ); // No normals/texcoords generated!!!
2135 par_shapes_scale(plane, width, length, 1.0f);
2136 par_shapes_rotate(plane, -PI/2.0f, (float[]){ 1, 0, 0 });
2137 par_shapes_translate(plane, -width/2, 0.0f, length/2);
2138
2139 mesh.vertices = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float));
2140 mesh.texcoords = (float *)RL_MALLOC(plane->ntriangles*3*2*sizeof(float));
2141 mesh.normals = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float));
2142
2143 mesh.vertexCount = plane->ntriangles*3;
2144 mesh.triangleCount = plane->ntriangles;
2145
2146 for (int k = 0; k < mesh.vertexCount; k++)
2147 {
2148 mesh.vertices[k*3] = plane->points[plane->triangles[k]*3];
2149 mesh.vertices[k*3 + 1] = plane->points[plane->triangles[k]*3 + 1];
2150 mesh.vertices[k*3 + 2] = plane->points[plane->triangles[k]*3 + 2];
2151
2152 mesh.normals[k*3] = plane->normals[plane->triangles[k]*3];
2153 mesh.normals[k*3 + 1] = plane->normals[plane->triangles[k]*3 + 1];
2154 mesh.normals[k*3 + 2] = plane->normals[plane->triangles[k]*3 + 2];
2155
2156 mesh.texcoords[k*2] = plane->tcoords[plane->triangles[k]*2];
2157 mesh.texcoords[k*2 + 1] = plane->tcoords[plane->triangles[k]*2 + 1];
2158 }
2159
2160 par_shapes_free_mesh(plane);
2161#endif
2162
2163 // Upload vertex data to GPU (static mesh)
2164 UploadMesh(&mesh, false);
2165
2166 return mesh;
2167}
2168
2169// Generated cuboid mesh
2170Mesh GenMeshCube(float width, float height, float length)
2171{
2172 Mesh mesh = { 0 };
2173
2174#define CUSTOM_MESH_GEN_CUBE
2175#if defined(CUSTOM_MESH_GEN_CUBE)
2176 float vertices[] = {
2177 -width/2, -height/2, length/2,
2178 width/2, -height/2, length/2,
2179 width/2, height/2, length/2,
2180 -width/2, height/2, length/2,
2181 -width/2, -height/2, -length/2,
2182 -width/2, height/2, -length/2,
2183 width/2, height/2, -length/2,
2184 width/2, -height/2, -length/2,
2185 -width/2, height/2, -length/2,
2186 -width/2, height/2, length/2,
2187 width/2, height/2, length/2,
2188 width/2, height/2, -length/2,
2189 -width/2, -height/2, -length/2,
2190 width/2, -height/2, -length/2,
2191 width/2, -height/2, length/2,
2192 -width/2, -height/2, length/2,
2193 width/2, -height/2, -length/2,
2194 width/2, height/2, -length/2,
2195 width/2, height/2, length/2,
2196 width/2, -height/2, length/2,
2197 -width/2, -height/2, -length/2,
2198 -width/2, -height/2, length/2,
2199 -width/2, height/2, length/2,
2200 -width/2, height/2, -length/2
2201 };
2202
2203 float texcoords[] = {
2204 0.0f, 0.0f,
2205 1.0f, 0.0f,
2206 1.0f, 1.0f,
2207 0.0f, 1.0f,
2208 1.0f, 0.0f,
2209 1.0f, 1.0f,
2210 0.0f, 1.0f,
2211 0.0f, 0.0f,
2212 0.0f, 1.0f,
2213 0.0f, 0.0f,
2214 1.0f, 0.0f,
2215 1.0f, 1.0f,
2216 1.0f, 1.0f,
2217 0.0f, 1.0f,
2218 0.0f, 0.0f,
2219 1.0f, 0.0f,
2220 1.0f, 0.0f,
2221 1.0f, 1.0f,
2222 0.0f, 1.0f,
2223 0.0f, 0.0f,
2224 0.0f, 0.0f,
2225 1.0f, 0.0f,
2226 1.0f, 1.0f,
2227 0.0f, 1.0f
2228 };
2229
2230 float normals[] = {
2231 0.0f, 0.0f, 1.0f,
2232 0.0f, 0.0f, 1.0f,
2233 0.0f, 0.0f, 1.0f,
2234 0.0f, 0.0f, 1.0f,
2235 0.0f, 0.0f,-1.0f,
2236 0.0f, 0.0f,-1.0f,
2237 0.0f, 0.0f,-1.0f,
2238 0.0f, 0.0f,-1.0f,
2239 0.0f, 1.0f, 0.0f,
2240 0.0f, 1.0f, 0.0f,
2241 0.0f, 1.0f, 0.0f,
2242 0.0f, 1.0f, 0.0f,
2243 0.0f,-1.0f, 0.0f,
2244 0.0f,-1.0f, 0.0f,
2245 0.0f,-1.0f, 0.0f,
2246 0.0f,-1.0f, 0.0f,
2247 1.0f, 0.0f, 0.0f,
2248 1.0f, 0.0f, 0.0f,
2249 1.0f, 0.0f, 0.0f,
2250 1.0f, 0.0f, 0.0f,
2251 -1.0f, 0.0f, 0.0f,
2252 -1.0f, 0.0f, 0.0f,
2253 -1.0f, 0.0f, 0.0f,
2254 -1.0f, 0.0f, 0.0f
2255 };
2256
2257 mesh.vertices = (float *)RL_MALLOC(24*3*sizeof(float));
2258 memcpy(mesh.vertices, vertices, 24*3*sizeof(float));
2259
2260 mesh.texcoords = (float *)RL_MALLOC(24*2*sizeof(float));
2261 memcpy(mesh.texcoords, texcoords, 24*2*sizeof(float));
2262
2263 mesh.normals = (float *)RL_MALLOC(24*3*sizeof(float));
2264 memcpy(mesh.normals, normals, 24*3*sizeof(float));
2265
2266 mesh.indices = (unsigned short *)RL_MALLOC(36*sizeof(unsigned short));
2267
2268 int k = 0;
2269
2270 // Indices can be initialized right now
2271 for (int i = 0; i < 36; i += 6)
2272 {
2273 mesh.indices[i] = 4*k;
2274 mesh.indices[i + 1] = 4*k + 1;
2275 mesh.indices[i + 2] = 4*k + 2;
2276 mesh.indices[i + 3] = 4*k;
2277 mesh.indices[i + 4] = 4*k + 2;
2278 mesh.indices[i + 5] = 4*k + 3;
2279
2280 k++;
2281 }
2282
2283 mesh.vertexCount = 24;
2284 mesh.triangleCount = 12;
2285
2286#else // Use par_shapes library to generate cube mesh
2287/*
2288// Platonic solids:
2289par_shapes_mesh* par_shapes_create_tetrahedron(); // 4 sides polyhedron (pyramid)
2290par_shapes_mesh* par_shapes_create_cube(); // 6 sides polyhedron (cube)
2291par_shapes_mesh* par_shapes_create_octahedron(); // 8 sides polyhedron (dyamond)
2292par_shapes_mesh* par_shapes_create_dodecahedron(); // 12 sides polyhedron
2293par_shapes_mesh* par_shapes_create_icosahedron(); // 20 sides polyhedron
2294*/
2295 // Platonic solid generation: cube (6 sides)
2296 // NOTE: No normals/texcoords generated by default
2298 cube->tcoords = PAR_MALLOC(float, 2*cube->npoints);
2299 for (int i = 0; i < 2*cube->npoints; i++) cube->tcoords[i] = 0.0f;
2300 par_shapes_scale(cube, width, height, length);
2301 par_shapes_translate(cube, -width/2, 0.0f, -length/2);
2303
2304 mesh.vertices = (float *)RL_MALLOC(cube->ntriangles*3*3*sizeof(float));
2305 mesh.texcoords = (float *)RL_MALLOC(cube->ntriangles*3*2*sizeof(float));
2306 mesh.normals = (float *)RL_MALLOC(cube->ntriangles*3*3*sizeof(float));
2307
2308 mesh.vertexCount = cube->ntriangles*3;
2309 mesh.triangleCount = cube->ntriangles;
2310
2311 for (int k = 0; k < mesh.vertexCount; k++)
2312 {
2313 mesh.vertices[k*3] = cube->points[cube->triangles[k]*3];
2314 mesh.vertices[k*3 + 1] = cube->points[cube->triangles[k]*3 + 1];
2315 mesh.vertices[k*3 + 2] = cube->points[cube->triangles[k]*3 + 2];
2316
2317 mesh.normals[k*3] = cube->normals[cube->triangles[k]*3];
2318 mesh.normals[k*3 + 1] = cube->normals[cube->triangles[k]*3 + 1];
2319 mesh.normals[k*3 + 2] = cube->normals[cube->triangles[k]*3 + 2];
2320
2321 mesh.texcoords[k*2] = cube->tcoords[cube->triangles[k]*2];
2322 mesh.texcoords[k*2 + 1] = cube->tcoords[cube->triangles[k]*2 + 1];
2323 }
2324
2326#endif
2327
2328 // Upload vertex data to GPU (static mesh)
2329 UploadMesh(&mesh, false);
2330
2331 return mesh;
2332}
2333
2334// Generate sphere mesh (standard sphere)
2335Mesh GenMeshSphere(float radius, int rings, int slices)
2336{
2337 Mesh mesh = { 0 };
2338
2339 if ((rings >= 3) && (slices >= 3))
2340 {
2342 par_shapes_scale(sphere, radius, radius, radius);
2343 // NOTE: Soft normals are computed internally
2344
2345 mesh.vertices = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
2346 mesh.texcoords = (float *)RL_MALLOC(sphere->ntriangles*3*2*sizeof(float));
2347 mesh.normals = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
2348
2349 mesh.vertexCount = sphere->ntriangles*3;
2350 mesh.triangleCount = sphere->ntriangles;
2351
2352 for (int k = 0; k < mesh.vertexCount; k++)
2353 {
2354 mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3];
2355 mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1];
2356 mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2];
2357
2358 mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3];
2359 mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1];
2360 mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2];
2361
2362 mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2];
2363 mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1];
2364 }
2365
2366 par_shapes_free_mesh(sphere);
2367
2368 // Upload vertex data to GPU (static mesh)
2369 UploadMesh(&mesh, false);
2370 }
2371 else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: sphere");
2372
2373 return mesh;
2374}
2375
2376// Generate hemi-sphere mesh (half sphere, no bottom cap)
2377Mesh GenMeshHemiSphere(float radius, int rings, int slices)
2378{
2379 Mesh mesh = { 0 };
2380
2381 if ((rings >= 3) && (slices >= 3))
2382 {
2383 if (radius < 0.0f) radius = 0.0f;
2384
2385 par_shapes_mesh *sphere = par_shapes_create_hemisphere(slices, rings);
2386 par_shapes_scale(sphere, radius, radius, radius);
2387 // NOTE: Soft normals are computed internally
2388
2389 mesh.vertices = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
2390 mesh.texcoords = (float *)RL_MALLOC(sphere->ntriangles*3*2*sizeof(float));
2391 mesh.normals = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
2392
2393 mesh.vertexCount = sphere->ntriangles*3;
2394 mesh.triangleCount = sphere->ntriangles;
2395
2396 for (int k = 0; k < mesh.vertexCount; k++)
2397 {
2398 mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3];
2399 mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1];
2400 mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2];
2401
2402 mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3];
2403 mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1];
2404 mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2];
2405
2406 mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2];
2407 mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1];
2408 }
2409
2410 par_shapes_free_mesh(sphere);
2411
2412 // Upload vertex data to GPU (static mesh)
2413 UploadMesh(&mesh, false);
2414 }
2415 else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: hemisphere");
2416
2417 return mesh;
2418}
2419
2420// Generate cylinder mesh
2421Mesh GenMeshCylinder(float radius, float height, int slices)
2422{
2423 Mesh mesh = { 0 };
2424
2425 if (slices >= 3)
2426 {
2427 // Instance a cylinder that sits on the Z=0 plane using the given tessellation
2428 // levels across the UV domain. Think of "slices" like a number of pizza
2429 // slices, and "stacks" like a number of stacked rings.
2430 // Height and radius are both 1.0, but they can easily be changed with par_shapes_scale
2431 par_shapes_mesh *cylinder = par_shapes_create_cylinder(slices, 8);
2432 par_shapes_scale(cylinder, radius, radius, height);
2433 par_shapes_rotate(cylinder, -PI/2.0f, (float[]){ 1, 0, 0 });
2434
2435 // Generate an orientable disk shape (top cap)
2436 par_shapes_mesh *capTop = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, 1 });
2437 capTop->tcoords = PAR_MALLOC(float, 2*capTop->npoints);
2438 for (int i = 0; i < 2*capTop->npoints; i++) capTop->tcoords[i] = 0.0f;
2439 par_shapes_rotate(capTop, -PI/2.0f, (float[]){ 1, 0, 0 });
2440 par_shapes_rotate(capTop, 90*DEG2RAD, (float[]){ 0, 1, 0 });
2441 par_shapes_translate(capTop, 0, height, 0);
2442
2443 // Generate an orientable disk shape (bottom cap)
2444 par_shapes_mesh *capBottom = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, -1 });
2445 capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints);
2446 for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f;
2447 par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 });
2448 par_shapes_rotate(capBottom, -90*DEG2RAD, (float[]){ 0, 1, 0 });
2449
2450 par_shapes_merge_and_free(cylinder, capTop);
2451 par_shapes_merge_and_free(cylinder, capBottom);
2452
2453 mesh.vertices = (float *)RL_MALLOC(cylinder->ntriangles*3*3*sizeof(float));
2454 mesh.texcoords = (float *)RL_MALLOC(cylinder->ntriangles*3*2*sizeof(float));
2455 mesh.normals = (float *)RL_MALLOC(cylinder->ntriangles*3*3*sizeof(float));
2456
2457 mesh.vertexCount = cylinder->ntriangles*3;
2458 mesh.triangleCount = cylinder->ntriangles;
2459
2460 for (int k = 0; k < mesh.vertexCount; k++)
2461 {
2462 mesh.vertices[k*3] = cylinder->points[cylinder->triangles[k]*3];
2463 mesh.vertices[k*3 + 1] = cylinder->points[cylinder->triangles[k]*3 + 1];
2464 mesh.vertices[k*3 + 2] = cylinder->points[cylinder->triangles[k]*3 + 2];
2465
2466 mesh.normals[k*3] = cylinder->normals[cylinder->triangles[k]*3];
2467 mesh.normals[k*3 + 1] = cylinder->normals[cylinder->triangles[k]*3 + 1];
2468 mesh.normals[k*3 + 2] = cylinder->normals[cylinder->triangles[k]*3 + 2];
2469
2470 mesh.texcoords[k*2] = cylinder->tcoords[cylinder->triangles[k]*2];
2471 mesh.texcoords[k*2 + 1] = cylinder->tcoords[cylinder->triangles[k]*2 + 1];
2472 }
2473
2474 par_shapes_free_mesh(cylinder);
2475
2476 // Upload vertex data to GPU (static mesh)
2477 UploadMesh(&mesh, false);
2478 }
2479 else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: cylinder");
2480
2481 return mesh;
2482}
2483
2484// Generate cone/pyramid mesh
2485Mesh GenMeshCone(float radius, float height, int slices)
2486{
2487 Mesh mesh = { 0 };
2488
2489 if (slices >= 3)
2490 {
2491 // Instance a cone that sits on the Z=0 plane using the given tessellation
2492 // levels across the UV domain. Think of "slices" like a number of pizza
2493 // slices, and "stacks" like a number of stacked rings.
2494 // Height and radius are both 1.0, but they can easily be changed with par_shapes_scale
2495 par_shapes_mesh *cone = par_shapes_create_cone(slices, 8);
2496 par_shapes_scale(cone, radius, radius, height);
2497 par_shapes_rotate(cone, -PI/2.0f, (float[]){ 1, 0, 0 });
2498 par_shapes_rotate(cone, PI/2.0f, (float[]){ 0, 1, 0 });
2499
2500 // Generate an orientable disk shape (bottom cap)
2501 par_shapes_mesh *capBottom = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, -1 });
2502 capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints);
2503 for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f;
2504 par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 });
2505
2506 par_shapes_merge_and_free(cone, capBottom);
2507
2508 mesh.vertices = (float *)RL_MALLOC(cone->ntriangles*3*3*sizeof(float));
2509 mesh.texcoords = (float *)RL_MALLOC(cone->ntriangles*3*2*sizeof(float));
2510 mesh.normals = (float *)RL_MALLOC(cone->ntriangles*3*3*sizeof(float));
2511
2512 mesh.vertexCount = cone->ntriangles*3;
2513 mesh.triangleCount = cone->ntriangles;
2514
2515 for (int k = 0; k < mesh.vertexCount; k++)
2516 {
2517 mesh.vertices[k*3] = cone->points[cone->triangles[k]*3];
2518 mesh.vertices[k*3 + 1] = cone->points[cone->triangles[k]*3 + 1];
2519 mesh.vertices[k*3 + 2] = cone->points[cone->triangles[k]*3 + 2];
2520
2521 mesh.normals[k*3] = cone->normals[cone->triangles[k]*3];
2522 mesh.normals[k*3 + 1] = cone->normals[cone->triangles[k]*3 + 1];
2523 mesh.normals[k*3 + 2] = cone->normals[cone->triangles[k]*3 + 2];
2524
2525 mesh.texcoords[k*2] = cone->tcoords[cone->triangles[k]*2];
2526 mesh.texcoords[k*2 + 1] = cone->tcoords[cone->triangles[k]*2 + 1];
2527 }
2528
2530
2531 // Upload vertex data to GPU (static mesh)
2532 UploadMesh(&mesh, false);
2533 }
2534 else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: cone");
2535
2536 return mesh;
2537}
2538
2539// Generate torus mesh
2540Mesh GenMeshTorus(float radius, float size, int radSeg, int sides)
2541{
2542 Mesh mesh = { 0 };
2543
2544 if ((sides >= 3) && (radSeg >= 3))
2545 {
2546 if (radius > 1.0f) radius = 1.0f;
2547 else if (radius < 0.1f) radius = 0.1f;
2548
2549 // Create a donut that sits on the Z=0 plane with the specified inner radius
2550 // The outer radius can be controlled with par_shapes_scale
2551 par_shapes_mesh *torus = par_shapes_create_torus(radSeg, sides, radius);
2552 par_shapes_scale(torus, size/2, size/2, size/2);
2553
2554 mesh.vertices = (float *)RL_MALLOC(torus->ntriangles*3*3*sizeof(float));
2555 mesh.texcoords = (float *)RL_MALLOC(torus->ntriangles*3*2*sizeof(float));
2556 mesh.normals = (float *)RL_MALLOC(torus->ntriangles*3*3*sizeof(float));
2557
2558 mesh.vertexCount = torus->ntriangles*3;
2559 mesh.triangleCount = torus->ntriangles;
2560
2561 for (int k = 0; k < mesh.vertexCount; k++)
2562 {
2563 mesh.vertices[k*3] = torus->points[torus->triangles[k]*3];
2564 mesh.vertices[k*3 + 1] = torus->points[torus->triangles[k]*3 + 1];
2565 mesh.vertices[k*3 + 2] = torus->points[torus->triangles[k]*3 + 2];
2566
2567 mesh.normals[k*3] = torus->normals[torus->triangles[k]*3];
2568 mesh.normals[k*3 + 1] = torus->normals[torus->triangles[k]*3 + 1];
2569 mesh.normals[k*3 + 2] = torus->normals[torus->triangles[k]*3 + 2];
2570
2571 mesh.texcoords[k*2] = torus->tcoords[torus->triangles[k]*2];
2572 mesh.texcoords[k*2 + 1] = torus->tcoords[torus->triangles[k]*2 + 1];
2573 }
2574
2575 par_shapes_free_mesh(torus);
2576
2577 // Upload vertex data to GPU (static mesh)
2578 UploadMesh(&mesh, false);
2579 }
2580 else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: torus");
2581
2582 return mesh;
2583}
2584
2585// Generate trefoil knot mesh
2586Mesh GenMeshKnot(float radius, float size, int radSeg, int sides)
2587{
2588 Mesh mesh = { 0 };
2589
2590 if ((sides >= 3) && (radSeg >= 3))
2591 {
2592 if (radius > 3.0f) radius = 3.0f;
2593 else if (radius < 0.5f) radius = 0.5f;
2594
2595 par_shapes_mesh *knot = par_shapes_create_trefoil_knot(radSeg, sides, radius);
2596 par_shapes_scale(knot, size, size, size);
2597
2598 mesh.vertices = (float *)RL_MALLOC(knot->ntriangles*3*3*sizeof(float));
2599 mesh.texcoords = (float *)RL_MALLOC(knot->ntriangles*3*2*sizeof(float));
2600 mesh.normals = (float *)RL_MALLOC(knot->ntriangles*3*3*sizeof(float));
2601
2602 mesh.vertexCount = knot->ntriangles*3;
2603 mesh.triangleCount = knot->ntriangles;
2604
2605 for (int k = 0; k < mesh.vertexCount; k++)
2606 {
2607 mesh.vertices[k*3] = knot->points[knot->triangles[k]*3];
2608 mesh.vertices[k*3 + 1] = knot->points[knot->triangles[k]*3 + 1];
2609 mesh.vertices[k*3 + 2] = knot->points[knot->triangles[k]*3 + 2];
2610
2611 mesh.normals[k*3] = knot->normals[knot->triangles[k]*3];
2612 mesh.normals[k*3 + 1] = knot->normals[knot->triangles[k]*3 + 1];
2613 mesh.normals[k*3 + 2] = knot->normals[knot->triangles[k]*3 + 2];
2614
2615 mesh.texcoords[k*2] = knot->tcoords[knot->triangles[k]*2];
2616 mesh.texcoords[k*2 + 1] = knot->tcoords[knot->triangles[k]*2 + 1];
2617 }
2618
2620
2621 // Upload vertex data to GPU (static mesh)
2622 UploadMesh(&mesh, false);
2623 }
2624 else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: knot");
2625
2626 return mesh;
2627}
2628
2629// Generate a mesh from heightmap
2630// NOTE: Vertex data is uploaded to GPU
2632{
2633 #define GRAY_VALUE(c) ((c.r+c.g+c.b)/3)
2634
2635 Mesh mesh = { 0 };
2636
2637 int mapX = heightmap.width;
2638 int mapZ = heightmap.height;
2639
2640 Color *pixels = LoadImageColors(heightmap);
2641
2642 // NOTE: One vertex per pixel
2643 mesh.triangleCount = (mapX-1)*(mapZ-1)*2; // One quad every four pixels
2644
2645 mesh.vertexCount = mesh.triangleCount*3;
2646
2647 mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
2648 mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
2649 mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
2650 mesh.colors = NULL;
2651
2652 int vCounter = 0; // Used to count vertices float by float
2653 int tcCounter = 0; // Used to count texcoords float by float
2654 int nCounter = 0; // Used to count normals float by float
2655
2656 int trisCounter = 0;
2657
2658 Vector3 scaleFactor = { size.x/mapX, size.y/255.0f, size.z/mapZ };
2659
2660 Vector3 vA = { 0 };
2661 Vector3 vB = { 0 };
2662 Vector3 vC = { 0 };
2663 Vector3 vN = { 0 };
2664
2665 for (int z = 0; z < mapZ-1; z++)
2666 {
2667 for (int x = 0; x < mapX-1; x++)
2668 {
2669 // Fill vertices array with data
2670 //----------------------------------------------------------
2671
2672 // one triangle - 3 vertex
2673 mesh.vertices[vCounter] = (float)x*scaleFactor.x;
2674 mesh.vertices[vCounter + 1] = (float)GRAY_VALUE(pixels[x + z*mapX])*scaleFactor.y;
2675 mesh.vertices[vCounter + 2] = (float)z*scaleFactor.z;
2676
2677 mesh.vertices[vCounter + 3] = (float)x*scaleFactor.x;
2678 mesh.vertices[vCounter + 4] = (float)GRAY_VALUE(pixels[x + (z + 1)*mapX])*scaleFactor.y;
2679 mesh.vertices[vCounter + 5] = (float)(z + 1)*scaleFactor.z;
2680
2681 mesh.vertices[vCounter + 6] = (float)(x + 1)*scaleFactor.x;
2682 mesh.vertices[vCounter + 7] = (float)GRAY_VALUE(pixels[(x + 1) + z*mapX])*scaleFactor.y;
2683 mesh.vertices[vCounter + 8] = (float)z*scaleFactor.z;
2684
2685 // another triangle - 3 vertex
2686 mesh.vertices[vCounter + 9] = mesh.vertices[vCounter + 6];
2687 mesh.vertices[vCounter + 10] = mesh.vertices[vCounter + 7];
2688 mesh.vertices[vCounter + 11] = mesh.vertices[vCounter + 8];
2689
2690 mesh.vertices[vCounter + 12] = mesh.vertices[vCounter + 3];
2691 mesh.vertices[vCounter + 13] = mesh.vertices[vCounter + 4];
2692 mesh.vertices[vCounter + 14] = mesh.vertices[vCounter + 5];
2693
2694 mesh.vertices[vCounter + 15] = (float)(x + 1)*scaleFactor.x;
2695 mesh.vertices[vCounter + 16] = (float)GRAY_VALUE(pixels[(x + 1) + (z + 1)*mapX])*scaleFactor.y;
2696 mesh.vertices[vCounter + 17] = (float)(z + 1)*scaleFactor.z;
2697 vCounter += 18; // 6 vertex, 18 floats
2698
2699 // Fill texcoords array with data
2700 //--------------------------------------------------------------
2701 mesh.texcoords[tcCounter] = (float)x/(mapX - 1);
2702 mesh.texcoords[tcCounter + 1] = (float)z/(mapZ - 1);
2703
2704 mesh.texcoords[tcCounter + 2] = (float)x/(mapX - 1);
2705 mesh.texcoords[tcCounter + 3] = (float)(z + 1)/(mapZ - 1);
2706
2707 mesh.texcoords[tcCounter + 4] = (float)(x + 1)/(mapX - 1);
2708 mesh.texcoords[tcCounter + 5] = (float)z/(mapZ - 1);
2709
2710 mesh.texcoords[tcCounter + 6] = mesh.texcoords[tcCounter + 4];
2711 mesh.texcoords[tcCounter + 7] = mesh.texcoords[tcCounter + 5];
2712
2713 mesh.texcoords[tcCounter + 8] = mesh.texcoords[tcCounter + 2];
2714 mesh.texcoords[tcCounter + 9] = mesh.texcoords[tcCounter + 3];
2715
2716 mesh.texcoords[tcCounter + 10] = (float)(x + 1)/(mapX - 1);
2717 mesh.texcoords[tcCounter + 11] = (float)(z + 1)/(mapZ - 1);
2718 tcCounter += 12; // 6 texcoords, 12 floats
2719
2720 // Fill normals array with data
2721 //--------------------------------------------------------------
2722 for (int i = 0; i < 18; i += 9)
2723 {
2724 vA.x = mesh.vertices[nCounter + i];
2725 vA.y = mesh.vertices[nCounter + i + 1];
2726 vA.z = mesh.vertices[nCounter + i + 2];
2727
2728 vB.x = mesh.vertices[nCounter + i + 3];
2729 vB.y = mesh.vertices[nCounter + i + 4];
2730 vB.z = mesh.vertices[nCounter + i + 5];
2731
2732 vC.x = mesh.vertices[nCounter + i + 6];
2733 vC.y = mesh.vertices[nCounter + i + 7];
2734 vC.z = mesh.vertices[nCounter + i + 8];
2735
2737
2738 mesh.normals[nCounter + i] = vN.x;
2739 mesh.normals[nCounter + i + 1] = vN.y;
2740 mesh.normals[nCounter + i + 2] = vN.z;
2741
2742 mesh.normals[nCounter + i + 3] = vN.x;
2743 mesh.normals[nCounter + i + 4] = vN.y;
2744 mesh.normals[nCounter + i + 5] = vN.z;
2745
2746 mesh.normals[nCounter + i + 6] = vN.x;
2747 mesh.normals[nCounter + i + 7] = vN.y;
2748 mesh.normals[nCounter + i + 8] = vN.z;
2749 }
2750
2751 nCounter += 18; // 6 vertex, 18 floats
2752 trisCounter += 2;
2753 }
2754 }
2755
2756 UnloadImageColors(pixels); // Unload pixels color data
2757
2758 // Upload vertex data to GPU (static mesh)
2759 UploadMesh(&mesh, false);
2760
2761 return mesh;
2762}
2763
2764// Generate a cubes mesh from pixel data
2765// NOTE: Vertex data is uploaded to GPU
2767{
2768 #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a))
2769
2770 Mesh mesh = { 0 };
2771
2772 Color *pixels = LoadImageColors(cubicmap);
2773
2774 int mapWidth = cubicmap.width;
2775 int mapHeight = cubicmap.height;
2776
2777 // NOTE: Max possible number of triangles numCubes*(12 triangles by cube)
2778 int maxTriangles = cubicmap.width*cubicmap.height*12;
2779
2780 int vCounter = 0; // Used to count vertices
2781 int tcCounter = 0; // Used to count texcoords
2782 int nCounter = 0; // Used to count normals
2783
2784 float w = cubeSize.x;
2785 float h = cubeSize.z;
2786 float h2 = cubeSize.y;
2787
2788 Vector3 *mapVertices = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3));
2789 Vector2 *mapTexcoords = (Vector2 *)RL_MALLOC(maxTriangles*3*sizeof(Vector2));
2790 Vector3 *mapNormals = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3));
2791
2792 // Define the 6 normals of the cube, we will combine them accordingly later...
2793 Vector3 n1 = { 1.0f, 0.0f, 0.0f };
2794 Vector3 n2 = { -1.0f, 0.0f, 0.0f };
2795 Vector3 n3 = { 0.0f, 1.0f, 0.0f };
2796 Vector3 n4 = { 0.0f, -1.0f, 0.0f };
2797 Vector3 n5 = { 0.0f, 0.0f, -1.0f };
2798 Vector3 n6 = { 0.0f, 0.0f, 1.0f };
2799
2800 // NOTE: We use texture rectangles to define different textures for top-bottom-front-back-right-left (6)
2801 typedef struct RectangleF {
2802 float x;
2803 float y;
2804 float width;
2805 float height;
2806 } RectangleF;
2807
2808 RectangleF rightTexUV = { 0.0f, 0.0f, 0.5f, 0.5f };
2809 RectangleF leftTexUV = { 0.5f, 0.0f, 0.5f, 0.5f };
2810 RectangleF frontTexUV = { 0.0f, 0.0f, 0.5f, 0.5f };
2811 RectangleF backTexUV = { 0.5f, 0.0f, 0.5f, 0.5f };
2812 RectangleF topTexUV = { 0.0f, 0.5f, 0.5f, 0.5f };
2813 RectangleF bottomTexUV = { 0.5f, 0.5f, 0.5f, 0.5f };
2814
2815 for (int z = 0; z < mapHeight; ++z)
2816 {
2817 for (int x = 0; x < mapWidth; ++x)
2818 {
2819 // Define the 8 vertex of the cube, we will combine them accordingly later...
2820 Vector3 v1 = { w*(x - 0.5f), h2, h*(z - 0.5f) };
2821 Vector3 v2 = { w*(x - 0.5f), h2, h*(z + 0.5f) };
2822 Vector3 v3 = { w*(x + 0.5f), h2, h*(z + 0.5f) };
2823 Vector3 v4 = { w*(x + 0.5f), h2, h*(z - 0.5f) };
2824 Vector3 v5 = { w*(x + 0.5f), 0, h*(z - 0.5f) };
2825 Vector3 v6 = { w*(x - 0.5f), 0, h*(z - 0.5f) };
2826 Vector3 v7 = { w*(x - 0.5f), 0, h*(z + 0.5f) };
2827 Vector3 v8 = { w*(x + 0.5f), 0, h*(z + 0.5f) };
2828
2829 // We check pixel color to be WHITE -> draw full cube
2830 if (COLOR_EQUAL(pixels[z*cubicmap.width + x], WHITE))
2831 {
2832 // Define triangles and checking collateral cubes
2833 //------------------------------------------------
2834
2835 // Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
2836 // WARNING: Not required for a WHITE cubes, created to allow seeing the map from outside
2837 mapVertices[vCounter] = v1;
2838 mapVertices[vCounter + 1] = v2;
2839 mapVertices[vCounter + 2] = v3;
2840 mapVertices[vCounter + 3] = v1;
2841 mapVertices[vCounter + 4] = v3;
2842 mapVertices[vCounter + 5] = v4;
2843 vCounter += 6;
2844
2845 mapNormals[nCounter] = n3;
2846 mapNormals[nCounter + 1] = n3;
2847 mapNormals[nCounter + 2] = n3;
2848 mapNormals[nCounter + 3] = n3;
2849 mapNormals[nCounter + 4] = n3;
2850 mapNormals[nCounter + 5] = n3;
2851 nCounter += 6;
2852
2853 mapTexcoords[tcCounter] = (Vector2){ topTexUV.x, topTexUV.y };
2854 mapTexcoords[tcCounter + 1] = (Vector2){ topTexUV.x, topTexUV.y + topTexUV.height };
2855 mapTexcoords[tcCounter + 2] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
2856 mapTexcoords[tcCounter + 3] = (Vector2){ topTexUV.x, topTexUV.y };
2857 mapTexcoords[tcCounter + 4] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
2858 mapTexcoords[tcCounter + 5] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y };
2859 tcCounter += 6;
2860
2861 // Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8)
2862 mapVertices[vCounter] = v6;
2863 mapVertices[vCounter + 1] = v8;
2864 mapVertices[vCounter + 2] = v7;
2865 mapVertices[vCounter + 3] = v6;
2866 mapVertices[vCounter + 4] = v5;
2867 mapVertices[vCounter + 5] = v8;
2868 vCounter += 6;
2869
2870 mapNormals[nCounter] = n4;
2871 mapNormals[nCounter + 1] = n4;
2872 mapNormals[nCounter + 2] = n4;
2873 mapNormals[nCounter + 3] = n4;
2874 mapNormals[nCounter + 4] = n4;
2875 mapNormals[nCounter + 5] = n4;
2876 nCounter += 6;
2877
2878 mapTexcoords[tcCounter] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
2879 mapTexcoords[tcCounter + 1] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
2880 mapTexcoords[tcCounter + 2] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y + bottomTexUV.height };
2881 mapTexcoords[tcCounter + 3] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
2882 mapTexcoords[tcCounter + 4] = (Vector2){ bottomTexUV.x, bottomTexUV.y };
2883 mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
2884 tcCounter += 6;
2885
2886 // Checking cube on bottom of current cube
2887 if (((z < cubicmap.height - 1) && COLOR_EQUAL(pixels[(z + 1)*cubicmap.width + x], BLACK)) || (z == cubicmap.height - 1))
2888 {
2889 // Define front triangles (2 tris, 6 vertex) --> v2 v7 v3, v3 v7 v8
2890 // NOTE: Collateral occluded faces are not generated
2891 mapVertices[vCounter] = v2;
2892 mapVertices[vCounter + 1] = v7;
2893 mapVertices[vCounter + 2] = v3;
2894 mapVertices[vCounter + 3] = v3;
2895 mapVertices[vCounter + 4] = v7;
2896 mapVertices[vCounter + 5] = v8;
2897 vCounter += 6;
2898
2899 mapNormals[nCounter] = n6;
2900 mapNormals[nCounter + 1] = n6;
2901 mapNormals[nCounter + 2] = n6;
2902 mapNormals[nCounter + 3] = n6;
2903 mapNormals[nCounter + 4] = n6;
2904 mapNormals[nCounter + 5] = n6;
2905 nCounter += 6;
2906
2907 mapTexcoords[tcCounter] = (Vector2){ frontTexUV.x, frontTexUV.y };
2908 mapTexcoords[tcCounter + 1] = (Vector2){ frontTexUV.x, frontTexUV.y + frontTexUV.height };
2909 mapTexcoords[tcCounter + 2] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y };
2910 mapTexcoords[tcCounter + 3] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y };
2911 mapTexcoords[tcCounter + 4] = (Vector2){ frontTexUV.x, frontTexUV.y + frontTexUV.height };
2912 mapTexcoords[tcCounter + 5] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y + frontTexUV.height };
2913 tcCounter += 6;
2914 }
2915
2916 // Checking cube on top of current cube
2917 if (((z > 0) && COLOR_EQUAL(pixels[(z - 1)*cubicmap.width + x], BLACK)) || (z == 0))
2918 {
2919 // Define back triangles (2 tris, 6 vertex) --> v1 v5 v6, v1 v4 v5
2920 // NOTE: Collateral occluded faces are not generated
2921 mapVertices[vCounter] = v1;
2922 mapVertices[vCounter + 1] = v5;
2923 mapVertices[vCounter + 2] = v6;
2924 mapVertices[vCounter + 3] = v1;
2925 mapVertices[vCounter + 4] = v4;
2926 mapVertices[vCounter + 5] = v5;
2927 vCounter += 6;
2928
2929 mapNormals[nCounter] = n5;
2930 mapNormals[nCounter + 1] = n5;
2931 mapNormals[nCounter + 2] = n5;
2932 mapNormals[nCounter + 3] = n5;
2933 mapNormals[nCounter + 4] = n5;
2934 mapNormals[nCounter + 5] = n5;
2935 nCounter += 6;
2936
2937 mapTexcoords[tcCounter] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y };
2938 mapTexcoords[tcCounter + 1] = (Vector2){ backTexUV.x, backTexUV.y + backTexUV.height };
2939 mapTexcoords[tcCounter + 2] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y + backTexUV.height };
2940 mapTexcoords[tcCounter + 3] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y };
2941 mapTexcoords[tcCounter + 4] = (Vector2){ backTexUV.x, backTexUV.y };
2942 mapTexcoords[tcCounter + 5] = (Vector2){ backTexUV.x, backTexUV.y + backTexUV.height };
2943 tcCounter += 6;
2944 }
2945
2946 // Checking cube on right of current cube
2947 if (((x < cubicmap.width - 1) && COLOR_EQUAL(pixels[z*cubicmap.width + (x + 1)], BLACK)) || (x == cubicmap.width - 1))
2948 {
2949 // Define right triangles (2 tris, 6 vertex) --> v3 v8 v4, v4 v8 v5
2950 // NOTE: Collateral occluded faces are not generated
2951 mapVertices[vCounter] = v3;
2952 mapVertices[vCounter + 1] = v8;
2953 mapVertices[vCounter + 2] = v4;
2954 mapVertices[vCounter + 3] = v4;
2955 mapVertices[vCounter + 4] = v8;
2956 mapVertices[vCounter + 5] = v5;
2957 vCounter += 6;
2958
2959 mapNormals[nCounter] = n1;
2960 mapNormals[nCounter + 1] = n1;
2961 mapNormals[nCounter + 2] = n1;
2962 mapNormals[nCounter + 3] = n1;
2963 mapNormals[nCounter + 4] = n1;
2964 mapNormals[nCounter + 5] = n1;
2965 nCounter += 6;
2966
2967 mapTexcoords[tcCounter] = (Vector2){ rightTexUV.x, rightTexUV.y };
2968 mapTexcoords[tcCounter + 1] = (Vector2){ rightTexUV.x, rightTexUV.y + rightTexUV.height };
2969 mapTexcoords[tcCounter + 2] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y };
2970 mapTexcoords[tcCounter + 3] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y };
2971 mapTexcoords[tcCounter + 4] = (Vector2){ rightTexUV.x, rightTexUV.y + rightTexUV.height };
2972 mapTexcoords[tcCounter + 5] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y + rightTexUV.height };
2973 tcCounter += 6;
2974 }
2975
2976 // Checking cube on left of current cube
2977 if (((x > 0) && COLOR_EQUAL(pixels[z*cubicmap.width + (x - 1)], BLACK)) || (x == 0))
2978 {
2979 // Define left triangles (2 tris, 6 vertex) --> v1 v7 v2, v1 v6 v7
2980 // NOTE: Collateral occluded faces are not generated
2981 mapVertices[vCounter] = v1;
2982 mapVertices[vCounter + 1] = v7;
2983 mapVertices[vCounter + 2] = v2;
2984 mapVertices[vCounter + 3] = v1;
2985 mapVertices[vCounter + 4] = v6;
2986 mapVertices[vCounter + 5] = v7;
2987 vCounter += 6;
2988
2989 mapNormals[nCounter] = n2;
2990 mapNormals[nCounter + 1] = n2;
2991 mapNormals[nCounter + 2] = n2;
2992 mapNormals[nCounter + 3] = n2;
2993 mapNormals[nCounter + 4] = n2;
2994 mapNormals[nCounter + 5] = n2;
2995 nCounter += 6;
2996
2997 mapTexcoords[tcCounter] = (Vector2){ leftTexUV.x, leftTexUV.y };
2998 mapTexcoords[tcCounter + 1] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y + leftTexUV.height };
2999 mapTexcoords[tcCounter + 2] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y };
3000 mapTexcoords[tcCounter + 3] = (Vector2){ leftTexUV.x, leftTexUV.y };
3001 mapTexcoords[tcCounter + 4] = (Vector2){ leftTexUV.x, leftTexUV.y + leftTexUV.height };
3002 mapTexcoords[tcCounter + 5] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y + leftTexUV.height };
3003 tcCounter += 6;
3004 }
3005 }
3006 // We check pixel color to be BLACK, we will only draw floor and roof
3007 else if (COLOR_EQUAL(pixels[z*cubicmap.width + x], BLACK))
3008 {
3009 // Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
3010 mapVertices[vCounter] = v1;
3011 mapVertices[vCounter + 1] = v3;
3012 mapVertices[vCounter + 2] = v2;
3013 mapVertices[vCounter + 3] = v1;
3014 mapVertices[vCounter + 4] = v4;
3015 mapVertices[vCounter + 5] = v3;
3016 vCounter += 6;
3017
3018 mapNormals[nCounter] = n4;
3019 mapNormals[nCounter + 1] = n4;
3020 mapNormals[nCounter + 2] = n4;
3021 mapNormals[nCounter + 3] = n4;
3022 mapNormals[nCounter + 4] = n4;
3023 mapNormals[nCounter + 5] = n4;
3024 nCounter += 6;
3025
3026 mapTexcoords[tcCounter] = (Vector2){ topTexUV.x, topTexUV.y };
3027 mapTexcoords[tcCounter + 1] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
3028 mapTexcoords[tcCounter + 2] = (Vector2){ topTexUV.x, topTexUV.y + topTexUV.height };
3029 mapTexcoords[tcCounter + 3] = (Vector2){ topTexUV.x, topTexUV.y };
3030 mapTexcoords[tcCounter + 4] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y };
3031 mapTexcoords[tcCounter + 5] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
3032 tcCounter += 6;
3033
3034 // Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8)
3035 mapVertices[vCounter] = v6;
3036 mapVertices[vCounter + 1] = v7;
3037 mapVertices[vCounter + 2] = v8;
3038 mapVertices[vCounter + 3] = v6;
3039 mapVertices[vCounter + 4] = v8;
3040 mapVertices[vCounter + 5] = v5;
3041 vCounter += 6;
3042
3043 mapNormals[nCounter] = n3;
3044 mapNormals[nCounter + 1] = n3;
3045 mapNormals[nCounter + 2] = n3;
3046 mapNormals[nCounter + 3] = n3;
3047 mapNormals[nCounter + 4] = n3;
3048 mapNormals[nCounter + 5] = n3;
3049 nCounter += 6;
3050
3051 mapTexcoords[tcCounter] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
3052 mapTexcoords[tcCounter + 1] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y + bottomTexUV.height };
3053 mapTexcoords[tcCounter + 2] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
3054 mapTexcoords[tcCounter + 3] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
3055 mapTexcoords[tcCounter + 4] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
3056 mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y };
3057 tcCounter += 6;
3058 }
3059 }
3060 }
3061
3062 // Move data from mapVertices temp arays to vertices float array
3063 mesh.vertexCount = vCounter;
3064 mesh.triangleCount = vCounter/3;
3065
3066 mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
3067 mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
3068 mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
3069 mesh.colors = NULL;
3070
3071 int fCounter = 0;
3072
3073 // Move vertices data
3074 for (int i = 0; i < vCounter; i++)
3075 {
3076 mesh.vertices[fCounter] = mapVertices[i].x;
3077 mesh.vertices[fCounter + 1] = mapVertices[i].y;
3078 mesh.vertices[fCounter + 2] = mapVertices[i].z;
3079 fCounter += 3;
3080 }
3081
3082 fCounter = 0;
3083
3084 // Move normals data
3085 for (int i = 0; i < nCounter; i++)
3086 {
3087 mesh.normals[fCounter] = mapNormals[i].x;
3088 mesh.normals[fCounter + 1] = mapNormals[i].y;
3089 mesh.normals[fCounter + 2] = mapNormals[i].z;
3090 fCounter += 3;
3091 }
3092
3093 fCounter = 0;
3094
3095 // Move texcoords data
3096 for (int i = 0; i < tcCounter; i++)
3097 {
3098 mesh.texcoords[fCounter] = mapTexcoords[i].x;
3099 mesh.texcoords[fCounter + 1] = mapTexcoords[i].y;
3100 fCounter += 2;
3101 }
3102
3103 RL_FREE(mapVertices);
3104 RL_FREE(mapNormals);
3105 RL_FREE(mapTexcoords);
3106
3107 UnloadImageColors(pixels); // Unload pixels color data
3108
3109 // Upload vertex data to GPU (static mesh)
3110 UploadMesh(&mesh, false);
3111
3112 return mesh;
3113}
3114#endif // SUPPORT_MESH_GENERATION
3115
3116// Compute mesh bounding box limits
3117// NOTE: minVertex and maxVertex should be transformed by model transform matrix
3119{
3120 // Get min and max vertex to construct bounds (AABB)
3121 Vector3 minVertex = { 0 };
3122 Vector3 maxVertex = { 0 };
3123
3124 if (mesh.vertices != NULL)
3125 {
3126 minVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] };
3127 maxVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] };
3128
3129 for (int i = 1; i < mesh.vertexCount; i++)
3130 {
3131 minVertex = Vector3Min(minVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] });
3132 maxVertex = Vector3Max(maxVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] });
3133 }
3134 }
3135
3136 // Create the bounding box
3137 BoundingBox box = { 0 };
3138 box.min = minVertex;
3139 box.max = maxVertex;
3140
3141 return box;
3142}
3143
3144// Compute mesh tangents
3145// NOTE: To calculate mesh tangents and binormals we need mesh vertex positions and texture coordinates
3146// Implementation base don: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html
3148{
3149 if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
3150 else
3151 {
3152 RL_FREE(mesh->tangents);
3153 mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
3154 }
3155
3156 Vector3 *tan1 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
3157 Vector3 *tan2 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
3158
3159 for (int i = 0; i < mesh->vertexCount; i += 3)
3160 {
3161 // Get triangle vertices
3162 Vector3 v1 = { mesh->vertices[(i + 0)*3 + 0], mesh->vertices[(i + 0)*3 + 1], mesh->vertices[(i + 0)*3 + 2] };
3163 Vector3 v2 = { mesh->vertices[(i + 1)*3 + 0], mesh->vertices[(i + 1)*3 + 1], mesh->vertices[(i + 1)*3 + 2] };
3164 Vector3 v3 = { mesh->vertices[(i + 2)*3 + 0], mesh->vertices[(i + 2)*3 + 1], mesh->vertices[(i + 2)*3 + 2] };
3165
3166 // Get triangle texcoords
3167 Vector2 uv1 = { mesh->texcoords[(i + 0)*2 + 0], mesh->texcoords[(i + 0)*2 + 1] };
3168 Vector2 uv2 = { mesh->texcoords[(i + 1)*2 + 0], mesh->texcoords[(i + 1)*2 + 1] };
3169 Vector2 uv3 = { mesh->texcoords[(i + 2)*2 + 0], mesh->texcoords[(i + 2)*2 + 1] };
3170
3171 float x1 = v2.x - v1.x;
3172 float y1 = v2.y - v1.y;
3173 float z1 = v2.z - v1.z;
3174 float x2 = v3.x - v1.x;
3175 float y2 = v3.y - v1.y;
3176 float z2 = v3.z - v1.z;
3177
3178 float s1 = uv2.x - uv1.x;
3179 float t1 = uv2.y - uv1.y;
3180 float s2 = uv3.x - uv1.x;
3181 float t2 = uv3.y - uv1.y;
3182
3183 float div = s1*t2 - s2*t1;
3184 float r = (div == 0.0f)? 0.0f : 1.0f/div;
3185
3186 Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r };
3187 Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r };
3188
3189 tan1[i + 0] = sdir;
3190 tan1[i + 1] = sdir;
3191 tan1[i + 2] = sdir;
3192
3193 tan2[i + 0] = tdir;
3194 tan2[i + 1] = tdir;
3195 tan2[i + 2] = tdir;
3196 }
3197
3198 // Compute tangents considering normals
3199 for (int i = 0; i < mesh->vertexCount; i++)
3200 {
3201 Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
3202 Vector3 tangent = tan1[i];
3203
3204 // TODO: Review, not sure if tangent computation is right, just used reference proposed maths...
3205#if defined(COMPUTE_TANGENTS_METHOD_01)
3206 Vector3 tmp = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent)));
3207 tmp = Vector3Normalize(tmp);
3208 mesh->tangents[i*4 + 0] = tmp.x;
3209 mesh->tangents[i*4 + 1] = tmp.y;
3210 mesh->tangents[i*4 + 2] = tmp.z;
3211 mesh->tangents[i*4 + 3] = 1.0f;
3212#else
3213 Vector3OrthoNormalize(&normal, &tangent);
3214 mesh->tangents[i*4 + 0] = tangent.x;
3215 mesh->tangents[i*4 + 1] = tangent.y;
3216 mesh->tangents[i*4 + 2] = tangent.z;
3217 mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f)? -1.0f : 1.0f;
3218#endif
3219 }
3220
3221 RL_FREE(tan1);
3222 RL_FREE(tan2);
3223
3224 if (mesh->vboId != NULL)
3225 {
3226 if (mesh->vboId[SHADER_LOC_VERTEX_TANGENT] != 0)
3227 {
3228 // Upate existing vertex buffer
3229 rlUpdateVertexBuffer(mesh->vboId[SHADER_LOC_VERTEX_TANGENT], mesh->tangents, mesh->vertexCount*4*sizeof(float), 0);
3230 }
3231 else
3232 {
3233 // Load a new tangent attributes buffer
3234 mesh->vboId[SHADER_LOC_VERTEX_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), false);
3235 }
3236
3238 rlSetVertexAttribute(4, 4, RL_FLOAT, 0, 0, 0);
3241 }
3242
3243 TRACELOG(LOG_INFO, "MESH: Tangents data computed and uploaded for provided mesh");
3244}
3245
3246// Compute mesh binormals (aka bitangent)
3248{
3249 for (int i = 0; i < mesh->vertexCount; i++)
3250 {
3251 //Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
3252 //Vector3 tangent = { mesh->tangents[i*4 + 0], mesh->tangents[i*4 + 1], mesh->tangents[i*4 + 2] };
3253 //Vector3 binormal = Vector3Scale(Vector3CrossProduct(normal, tangent), mesh->tangents[i*4 + 3]);
3254
3255 // TODO: Register computed binormal in mesh->binormal?
3256 }
3257}
3258
3259// Draw a model (with texture if set)
3260void DrawModel(Model model, Vector3 position, float scale, Color tint)
3261{
3262 Vector3 vScale = { scale, scale, scale };
3263 Vector3 rotationAxis = { 0.0f, 1.0f, 0.0f };
3264
3265 DrawModelEx(model, position, rotationAxis, 0.0f, vScale, tint);
3266}
3267
3268// Draw a model with extended parameters
3269void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
3270{
3271 // Calculate transformation matrix from function parameters
3272 // Get transform matrix (rotation -> scale -> translation)
3273 Matrix matScale = MatrixScale(scale.x, scale.y, scale.z);
3274 Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD);
3275 Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
3276
3277 Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
3278
3279 // Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform)
3280 model.transform = MatrixMultiply(model.transform, matTransform);
3281
3282 for (int i = 0; i < model.meshCount; i++)
3283 {
3284 Color color = model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color;
3285
3286 Color colorTint = WHITE;
3287 colorTint.r = (unsigned char)((((float)color.r/255.0f)*((float)tint.r/255.0f))*255.0f);
3288 colorTint.g = (unsigned char)((((float)color.g/255.0f)*((float)tint.g/255.0f))*255.0f);
3289 colorTint.b = (unsigned char)((((float)color.b/255.0f)*((float)tint.b/255.0f))*255.0f);
3290 colorTint.a = (unsigned char)((((float)color.a/255.0f)*((float)tint.a/255.0f))*255.0f);
3291
3292 model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = colorTint;
3293 DrawMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform);
3294 model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = color;
3295 }
3296}
3297
3298// Draw a model wires (with texture if set)
3299void DrawModelWires(Model model, Vector3 position, float scale, Color tint)
3300{
3302
3303 DrawModel(model, position, scale, tint);
3304
3306}
3307
3308// Draw a model wires (with texture if set) with extended parameters
3309void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
3310{
3312
3313 DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);
3314
3316}
3317
3318// Draw a billboard
3319void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float size, Color tint)
3320{
3321 Rectangle source = { 0.0f, 0.0f, (float)texture.width, (float)texture.height };
3322
3323 DrawBillboardRec(camera, texture, source, position, (Vector2){ size, size }, tint);
3324}
3325
3326// Draw a billboard (part of a texture defined by a rectangle)
3327void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint)
3328{
3329 // NOTE: Billboard locked on axis-Y
3330 Vector3 up = { 0.0f, 1.0f, 0.0f };
3331
3332 DrawBillboardPro(camera, texture, source, position, up, size, Vector2Zero(), 0.0f, tint);
3333}
3334
3335void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint)
3336{
3337 // NOTE: Billboard size will maintain source rectangle aspect ratio, size will represent billboard width
3338 Vector2 sizeRatio = { size.y, size.x*(float)source.height/source.width };
3339
3340 Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
3341
3342 Vector3 right = { matView.m0, matView.m4, matView.m8 };
3343 //Vector3 up = { matView.m1, matView.m5, matView.m9 };
3344
3345 Vector3 rightScaled = Vector3Scale(right, sizeRatio.x/2);
3346 Vector3 upScaled = Vector3Scale(up, sizeRatio.y/2);
3347
3348 Vector3 p1 = Vector3Add(rightScaled, upScaled);
3349 Vector3 p2 = Vector3Subtract(rightScaled, upScaled);
3350
3351 Vector3 topLeft = Vector3Scale(p2, -1);
3352 Vector3 topRight = p1;
3353 Vector3 bottomRight = p2;
3354 Vector3 bottomLeft = Vector3Scale(p1, -1);
3355
3356 if (rotation != 0.0f)
3357 {
3358 float sinRotation = sinf(rotation*DEG2RAD);
3359 float cosRotation = cosf(rotation*DEG2RAD);
3360
3361 // NOTE: (-1, 1) is the range where origin.x, origin.y is inside the texture
3362 float rotateAboutX = sizeRatio.x*origin.x/2;
3363 float rotateAboutY = sizeRatio.y*origin.y/2;
3364
3365 float xtvalue, ytvalue;
3366 float rotatedX, rotatedY;
3367
3368 xtvalue = Vector3DotProduct(right, topLeft) - rotateAboutX; // Project points to x and y coordinates on the billboard plane
3369 ytvalue = Vector3DotProduct(up, topLeft) - rotateAboutY;
3370 rotatedX = xtvalue*cosRotation - ytvalue*sinRotation + rotateAboutX; // Rotate about the point origin
3371 rotatedY = xtvalue*sinRotation + ytvalue*cosRotation + rotateAboutY;
3372 topLeft = Vector3Add(Vector3Scale(up, rotatedY), Vector3Scale(right, rotatedX)); // Translate back to cartesian coordinates
3373
3374 xtvalue = Vector3DotProduct(right, topRight) - rotateAboutX;
3375 ytvalue = Vector3DotProduct(up, topRight) - rotateAboutY;
3376 rotatedX = xtvalue*cosRotation - ytvalue*sinRotation + rotateAboutX;
3377 rotatedY = xtvalue*sinRotation + ytvalue*cosRotation + rotateAboutY;
3378 topRight = Vector3Add(Vector3Scale(up, rotatedY), Vector3Scale(right, rotatedX));
3379
3380 xtvalue = Vector3DotProduct(right, bottomRight) - rotateAboutX;
3381 ytvalue = Vector3DotProduct(up, bottomRight) - rotateAboutY;
3382 rotatedX = xtvalue*cosRotation - ytvalue*sinRotation + rotateAboutX;
3383 rotatedY = xtvalue*sinRotation + ytvalue*cosRotation + rotateAboutY;
3384 bottomRight = Vector3Add(Vector3Scale(up, rotatedY), Vector3Scale(right, rotatedX));
3385
3386 xtvalue = Vector3DotProduct(right, bottomLeft)-rotateAboutX;
3387 ytvalue = Vector3DotProduct(up, bottomLeft)-rotateAboutY;
3388 rotatedX = xtvalue*cosRotation - ytvalue*sinRotation + rotateAboutX;
3389 rotatedY = xtvalue*sinRotation + ytvalue*cosRotation + rotateAboutY;
3390 bottomLeft = Vector3Add(Vector3Scale(up, rotatedY), Vector3Scale(right, rotatedX));
3391 }
3392
3393 // Translate points to the draw center (position)
3394 topLeft = Vector3Add(topLeft, position);
3395 topRight = Vector3Add(topRight, position);
3396 bottomRight = Vector3Add(bottomRight, position);
3397 bottomLeft = Vector3Add(bottomLeft, position);
3398
3400
3401 rlSetTexture(texture.id);
3402
3404 rlColor4ub(tint.r, tint.g, tint.b, tint.a);
3405
3406 // Bottom-left corner for texture and quad
3407 rlTexCoord2f((float)source.x/texture.width, (float)source.y/texture.height);
3408 rlVertex3f(topLeft.x, topLeft.y, topLeft.z);
3409
3410 // Top-left corner for texture and quad
3411 rlTexCoord2f((float)source.x/texture.width, (float)(source.y + source.height)/texture.height);
3412 rlVertex3f(bottomLeft.x, bottomLeft.y, bottomLeft.z);
3413
3414 // Top-right corner for texture and quad
3415 rlTexCoord2f((float)(source.x + source.width)/texture.width, (float)(source.y + source.height)/texture.height);
3416 rlVertex3f(bottomRight.x, bottomRight.y, bottomRight.z);
3417
3418 // Bottom-right corner for texture and quad
3419 rlTexCoord2f((float)(source.x + source.width)/texture.width, (float)source.y/texture.height);
3420 rlVertex3f(topRight.x, topRight.y, topRight.z);
3421 rlEnd();
3422
3423 rlSetTexture(0);
3424}
3425
3426// Draw a bounding box with wires
3428{
3429 Vector3 size = { 0 };
3430
3431 size.x = fabsf(box.max.x - box.min.x);
3432 size.y = fabsf(box.max.y - box.min.y);
3433 size.z = fabsf(box.max.z - box.min.z);
3434
3435 Vector3 center = { box.min.x + size.x/2.0f, box.min.y + size.y/2.0f, box.min.z + size.z/2.0f };
3436
3437 DrawCubeWires(center, size.x, size.y, size.z, color);
3438}
3439
3440// Check collision between two spheres
3441bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2)
3442{
3443 bool collision = false;
3444
3445 // Simple way to check for collision, just checking distance between two points
3446 // Unfortunately, sqrtf() is a costly operation, so we avoid it with following solution
3447 /*
3448 float dx = center1.x - center2.x; // X distance between centers
3449 float dy = center1.y - center2.y; // Y distance between centers
3450 float dz = center1.z - center2.z; // Z distance between centers
3451
3452 float distance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance between centers
3453
3454 if (distance <= (radius1 + radius2)) collision = true;
3455 */
3456
3457 // Check for distances squared to avoid sqrtf()
3458 if (Vector3DotProduct(Vector3Subtract(center2, center1), Vector3Subtract(center2, center1)) <= (radius1 + radius2)*(radius1 + radius2)) collision = true;
3459
3460 return collision;
3461}
3462
3463// Check collision between two boxes
3464// NOTE: Boxes are defined by two points minimum and maximum
3466{
3467 bool collision = true;
3468
3469 if ((box1.max.x >= box2.min.x) && (box1.min.x <= box2.max.x))
3470 {
3471 if ((box1.max.y < box2.min.y) || (box1.min.y > box2.max.y)) collision = false;
3472 if ((box1.max.z < box2.min.z) || (box1.min.z > box2.max.z)) collision = false;
3473 }
3474 else collision = false;
3475
3476 return collision;
3477}
3478
3479// Check collision between box and sphere
3480bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius)
3481{
3482 bool collision = false;
3483
3484 float dmin = 0;
3485
3486 if (center.x < box.min.x) dmin += powf(center.x - box.min.x, 2);
3487 else if (center.x > box.max.x) dmin += powf(center.x - box.max.x, 2);
3488
3489 if (center.y < box.min.y) dmin += powf(center.y - box.min.y, 2);
3490 else if (center.y > box.max.y) dmin += powf(center.y - box.max.y, 2);
3491
3492 if (center.z < box.min.z) dmin += powf(center.z - box.min.z, 2);
3493 else if (center.z > box.max.z) dmin += powf(center.z - box.max.z, 2);
3494
3495 if (dmin <= (radius*radius)) collision = true;
3496
3497 return collision;
3498}
3499
3500// Get collision info between ray and sphere
3502{
3503 RayCollision collision = { 0 };
3504
3505 Vector3 raySpherePos = Vector3Subtract(center, ray.position);
3506 float vector = Vector3DotProduct(raySpherePos, ray.direction);
3507 float distance = Vector3Length(raySpherePos);
3508 float d = radius*radius - (distance*distance - vector*vector);
3509
3510 collision.hit = d >= 0.0f;
3511
3512 // Check if ray origin is inside the sphere to calculate the correct collision point
3513 if (distance < radius)
3514 {
3515 collision.distance = vector + sqrtf(d);
3516
3517 // Calculate collision point
3518 collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance));
3519
3520 // Calculate collision normal (pointing outwards)
3521 collision.normal = Vector3Negate(Vector3Normalize(Vector3Subtract(collision.point, center)));
3522 }
3523 else
3524 {
3525 collision.distance = vector - sqrtf(d);
3526
3527 // Calculate collision point
3528 collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance));
3529
3530 // Calculate collision normal (pointing inwards)
3531 collision.normal = Vector3Normalize(Vector3Subtract(collision.point, center));
3532 }
3533
3534 return collision;
3535}
3536
3537// Get collision info between ray and box
3539{
3540 RayCollision collision = { 0 };
3541
3542 // Note: If ray.position is inside the box, the distance is negative (as if the ray was reversed)
3543 // Reversing ray.direction will give use the correct result.
3544 bool insideBox = (ray.position.x > box.min.x) && (ray.position.x < box.max.x) &&
3545 (ray.position.y > box.min.y) && (ray.position.y < box.max.y) &&
3546 (ray.position.z > box.min.z) && (ray.position.z < box.max.z);
3547
3548 if (insideBox) ray.direction = Vector3Negate(ray.direction);
3549
3550 float t[11] = { 0 };
3551
3552 t[8] = 1.0f/ray.direction.x;
3553 t[9] = 1.0f/ray.direction.y;
3554 t[10] = 1.0f/ray.direction.z;
3555
3556 t[0] = (box.min.x - ray.position.x)*t[8];
3557 t[1] = (box.max.x - ray.position.x)*t[8];
3558 t[2] = (box.min.y - ray.position.y)*t[9];
3559 t[3] = (box.max.y - ray.position.y)*t[9];
3560 t[4] = (box.min.z - ray.position.z)*t[10];
3561 t[5] = (box.max.z - ray.position.z)*t[10];
3562 t[6] = (float)fmax(fmax(fmin(t[0], t[1]), fmin(t[2], t[3])), fmin(t[4], t[5]));
3563 t[7] = (float)fmin(fmin(fmax(t[0], t[1]), fmax(t[2], t[3])), fmax(t[4], t[5]));
3564
3565 collision.hit = !((t[7] < 0) || (t[6] > t[7]));
3566 collision.distance = t[6];
3567 collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance));
3568
3569 // Get box center point
3570 collision.normal = Vector3Lerp(box.min, box.max, 0.5f);
3571 // Get vector center point->hit point
3572 collision.normal = Vector3Subtract(collision.point, collision.normal);
3573 // Scale vector to unit cube
3574 // NOTE: We use an additional .01 to fix numerical errors
3575 collision.normal = Vector3Scale(collision.normal, 2.01f);
3576 collision.normal = Vector3Divide(collision.normal, Vector3Subtract(box.max, box.min));
3577 // The relevant elemets of the vector are now slightly larger than 1.0f (or smaller than -1.0f)
3578 // and the others are somewhere between -1.0 and 1.0 casting to int is exactly our wanted normal!
3579 collision.normal.x = (float)((int)collision.normal.x);
3580 collision.normal.y = (float)((int)collision.normal.y);
3581 collision.normal.z = (float)((int)collision.normal.z);
3582
3583 collision.normal = Vector3Normalize(collision.normal);
3584
3585 if (insideBox)
3586 {
3587 // Reset ray.direction
3589 // Fix result
3590 collision.distance *= -1.0f;
3591 collision.normal = Vector3Negate(collision.normal);
3592 }
3593
3594 return collision;
3595}
3596
3597// Get collision info between ray and mesh
3599{
3600 RayCollision collision = { 0 };
3601
3602 // Check if mesh vertex data on CPU for testing
3603 if (mesh.vertices != NULL)
3604 {
3605 int triangleCount = mesh.triangleCount;
3606
3607 // Test against all triangles in mesh
3608 for (int i = 0; i < triangleCount; i++)
3609 {
3610 Vector3 a, b, c;
3611 Vector3* vertdata = (Vector3*)mesh.vertices;
3612
3613 if (mesh.indices)
3614 {
3615 a = vertdata[mesh.indices[i*3 + 0]];
3616 b = vertdata[mesh.indices[i*3 + 1]];
3617 c = vertdata[mesh.indices[i*3 + 2]];
3618 }
3619 else
3620 {
3621 a = vertdata[i*3 + 0];
3622 b = vertdata[i*3 + 1];
3623 c = vertdata[i*3 + 2];
3624 }
3625
3626 a = Vector3Transform(a, transform);
3627 b = Vector3Transform(b, transform);
3628 c = Vector3Transform(c, transform);
3629
3630 RayCollision triHitInfo = GetRayCollisionTriangle(ray, a, b, c);
3631
3632 if (triHitInfo.hit)
3633 {
3634 // Save the closest hit triangle
3635 if ((!collision.hit) || (collision.distance > triHitInfo.distance)) collision = triHitInfo;
3636 }
3637 }
3638 }
3639
3640 return collision;
3641}
3642
3643// Get collision info between ray and triangle
3644// NOTE: The points are expected to be in counter-clockwise winding
3645// NOTE: Based on https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
3647{
3648 #define EPSILON 0.000001f // A small number
3649
3650 RayCollision collision = { 0 };
3651 Vector3 edge1 = { 0 };
3652 Vector3 edge2 = { 0 };
3653 Vector3 p, q, tv;
3654 float det, invDet, u, v, t;
3655
3656 // Find vectors for two edges sharing V1
3657 edge1 = Vector3Subtract(p2, p1);
3658 edge2 = Vector3Subtract(p3, p1);
3659
3660 // Begin calculating determinant - also used to calculate u parameter
3661 p = Vector3CrossProduct(ray.direction, edge2);
3662
3663 // If determinant is near zero, ray lies in plane of triangle or ray is parallel to plane of triangle
3664 det = Vector3DotProduct(edge1, p);
3665
3666 // Avoid culling!
3667 if ((det > -EPSILON) && (det < EPSILON)) return collision;
3668
3669 invDet = 1.0f/det;
3670
3671 // Calculate distance from V1 to ray origin
3672 tv = Vector3Subtract(ray.position, p1);
3673
3674 // Calculate u parameter and test bound
3675 u = Vector3DotProduct(tv, p)*invDet;
3676
3677 // The intersection lies outside of the triangle
3678 if ((u < 0.0f) || (u > 1.0f)) return collision;
3679
3680 // Prepare to test v parameter
3681 q = Vector3CrossProduct(tv, edge1);
3682
3683 // Calculate V parameter and test bound
3684 v = Vector3DotProduct(ray.direction, q)*invDet;
3685
3686 // The intersection lies outside of the triangle
3687 if ((v < 0.0f) || ((u + v) > 1.0f)) return collision;
3688
3689 t = Vector3DotProduct(edge2, q)*invDet;
3690
3691 if (t > EPSILON)
3692 {
3693 // Ray hit, get hit point and normal
3694 collision.hit = true;
3695 collision.distance = t;
3696 collision.normal = Vector3Normalize(Vector3CrossProduct(edge1, edge2));
3697 collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, t));
3698 }
3699
3700 return collision;
3701}
3702
3703// Get collision info between ray and quad
3704// NOTE: The points are expected to be in counter-clockwise winding
3706{
3707 RayCollision collision = { 0 };
3708
3709 collision = GetRayCollisionTriangle(ray, p1, p2, p4);
3710
3711 if (!collision.hit) collision = GetRayCollisionTriangle(ray, p2, p3, p4);
3712
3713 return collision;
3714}
3715
3716//----------------------------------------------------------------------------------
3717// Module specific Functions Definition
3718//----------------------------------------------------------------------------------
3719#if defined(SUPPORT_FILEFORMAT_OBJ)
3720// Load OBJ mesh data
3721//
3722// Keep the following information in mind when reading this
3723// - A mesh is created for every material present in the obj file
3724// - the model.meshCount is therefore the materialCount returned from tinyobj
3725// - the mesh is automatically triangulated by tinyobj
3726static Model LoadOBJ(const char *fileName)
3727{
3728 Model model = { 0 };
3729
3730 tinyobj_attrib_t attrib = { 0 };
3731 tinyobj_shape_t *meshes = NULL;
3732 unsigned int meshCount = 0;
3733
3734 tinyobj_material_t *materials = NULL;
3735 unsigned int materialCount = 0;
3736
3737 char *fileText = LoadFileText(fileName);
3738
3739 if (fileText != NULL)
3740 {
3741 unsigned int dataSize = (unsigned int)strlen(fileText);
3742 char currentDir[1024] = { 0 };
3743 strcpy(currentDir, GetWorkingDirectory());
3744 const char *workingDir = GetDirectoryPath(fileName);
3745 if (CHDIR(workingDir) != 0)
3746 {
3747 TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir);
3748 }
3749
3750 unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;
3751 int ret = tinyobj_parse_obj(&attrib, &meshes, &meshCount, &materials, &materialCount, fileText, dataSize, flags);
3752
3753 if (ret != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load OBJ data", fileName);
3754 else TRACELOG(LOG_INFO, "MODEL: [%s] OBJ data loaded successfully: %i meshes/%i materials", fileName, meshCount, materialCount);
3755
3756 model.meshCount = materialCount;
3757
3758 // Init model materials array
3759 if (materialCount > 0)
3760 {
3761 model.materialCount = materialCount;
3762 model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
3763 TraceLog(LOG_INFO, "MODEL: model has %i material meshes", materialCount);
3764 }
3765 else
3766 {
3767 model.meshCount = 1;
3768 TraceLog(LOG_INFO, "MODEL: No materials, putting all meshes in a default material");
3769 }
3770
3771 model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
3772 model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
3773
3774 // Count the faces for each material
3775 int *matFaces = RL_CALLOC(model.meshCount, sizeof(int));
3776
3777 // iff no materials are present use all faces on one mesh
3778 if (materialCount > 0)
3779 {
3780 for (unsigned int fi = 0; fi < attrib.num_faces; fi++)
3781 {
3782 //tinyobj_vertex_index_t face = attrib.faces[fi];
3783 int idx = attrib.material_ids[fi];
3784 matFaces[idx]++;
3785 }
3786
3787 }
3788 else
3789 {
3790 matFaces[0] = attrib.num_faces;
3791 }
3792
3793 //--------------------------------------
3794 // Create the material meshes
3795
3796 // Running counts/indexes for each material mesh as we are
3797 // building them at the same time
3798 int *vCount = RL_CALLOC(model.meshCount, sizeof(int));
3799 int *vtCount = RL_CALLOC(model.meshCount, sizeof(int));
3800 int *vnCount = RL_CALLOC(model.meshCount, sizeof(int));
3801 int *faceCount = RL_CALLOC(model.meshCount, sizeof(int));
3802
3803 // Allocate space for each of the material meshes
3804 for (int mi = 0; mi < model.meshCount; mi++)
3805 {
3806 model.meshes[mi].vertexCount = matFaces[mi]*3;
3807 model.meshes[mi].triangleCount = matFaces[mi];
3808 model.meshes[mi].vertices = (float *)RL_CALLOC(model.meshes[mi].vertexCount*3, sizeof(float));
3809 model.meshes[mi].texcoords = (float *)RL_CALLOC(model.meshes[mi].vertexCount*2, sizeof(float));
3810 model.meshes[mi].normals = (float *)RL_CALLOC(model.meshes[mi].vertexCount*3, sizeof(float));
3811 model.meshMaterial[mi] = mi;
3812 }
3813
3814 // Scan through the combined sub meshes and pick out each material mesh
3815 for (unsigned int af = 0; af < attrib.num_faces; af++)
3816 {
3817 int mm = attrib.material_ids[af]; // mesh material for this face
3818 if (mm == -1) { mm = 0; } // no material object..
3819
3820 // Get indices for the face
3821 tinyobj_vertex_index_t idx0 = attrib.faces[3*af + 0];
3822 tinyobj_vertex_index_t idx1 = attrib.faces[3*af + 1];
3823 tinyobj_vertex_index_t idx2 = attrib.faces[3*af + 2];
3824
3825 // Fill vertices buffer (float) using vertex index of the face
3826 for (int v = 0; v < 3; v++) { model.meshes[mm].vertices[vCount[mm] + v] = attrib.vertices[idx0.v_idx*3 + v]; } vCount[mm] +=3;
3827 for (int v = 0; v < 3; v++) { model.meshes[mm].vertices[vCount[mm] + v] = attrib.vertices[idx1.v_idx*3 + v]; } vCount[mm] +=3;
3828 for (int v = 0; v < 3; v++) { model.meshes[mm].vertices[vCount[mm] + v] = attrib.vertices[idx2.v_idx*3 + v]; } vCount[mm] +=3;
3829
3830 if (attrib.num_texcoords > 0)
3831 {
3832 // Fill texcoords buffer (float) using vertex index of the face
3833 // NOTE: Y-coordinate must be flipped upside-down to account for
3834 // raylib's upside down textures...
3835 model.meshes[mm].texcoords[vtCount[mm] + 0] = attrib.texcoords[idx0.vt_idx*2 + 0];
3836 model.meshes[mm].texcoords[vtCount[mm] + 1] = 1.0f - attrib.texcoords[idx0.vt_idx*2 + 1]; vtCount[mm] += 2;
3837 model.meshes[mm].texcoords[vtCount[mm] + 0] = attrib.texcoords[idx1.vt_idx*2 + 0];
3838 model.meshes[mm].texcoords[vtCount[mm] + 1] = 1.0f - attrib.texcoords[idx1.vt_idx*2 + 1]; vtCount[mm] += 2;
3839 model.meshes[mm].texcoords[vtCount[mm] + 0] = attrib.texcoords[idx2.vt_idx*2 + 0];
3840 model.meshes[mm].texcoords[vtCount[mm] + 1] = 1.0f - attrib.texcoords[idx2.vt_idx*2 + 1]; vtCount[mm] += 2;
3841 }
3842
3843 if (attrib.num_normals > 0)
3844 {
3845 // Fill normals buffer (float) using vertex index of the face
3846 for (int v = 0; v < 3; v++) { model.meshes[mm].normals[vnCount[mm] + v] = attrib.normals[idx0.vn_idx*3 + v]; } vnCount[mm] +=3;
3847 for (int v = 0; v < 3; v++) { model.meshes[mm].normals[vnCount[mm] + v] = attrib.normals[idx1.vn_idx*3 + v]; } vnCount[mm] +=3;
3848 for (int v = 0; v < 3; v++) { model.meshes[mm].normals[vnCount[mm] + v] = attrib.normals[idx2.vn_idx*3 + v]; } vnCount[mm] +=3;
3849 }
3850 }
3851
3852 // Init model materials
3853 for (unsigned int m = 0; m < materialCount; m++)
3854 {
3855 // Init material to default
3856 // NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE
3857 model.materials[m] = LoadMaterialDefault();
3858
3859 // Get default texture, in case no texture is defined
3860 // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
3862
3863 if (materials[m].diffuse_texname != NULL) model.materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture(materials[m].diffuse_texname); //char *diffuse_texname; // map_Kd
3864
3865 model.materials[m].maps[MATERIAL_MAP_DIFFUSE].color = (Color){ (unsigned char)(materials[m].diffuse[0]*255.0f), (unsigned char)(materials[m].diffuse[1]*255.0f), (unsigned char)(materials[m].diffuse[2]*255.0f), 255 }; //float diffuse[3];
3866 model.materials[m].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f;
3867
3868 if (materials[m].specular_texname != NULL) model.materials[m].maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture(materials[m].specular_texname); //char *specular_texname; // map_Ks
3869 model.materials[m].maps[MATERIAL_MAP_SPECULAR].color = (Color){ (unsigned char)(materials[m].specular[0]*255.0f), (unsigned char)(materials[m].specular[1]*255.0f), (unsigned char)(materials[m].specular[2]*255.0f), 255 }; //float specular[3];
3870 model.materials[m].maps[MATERIAL_MAP_SPECULAR].value = 0.0f;
3871
3872 if (materials[m].bump_texname != NULL) model.materials[m].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture(materials[m].bump_texname); //char *bump_texname; // map_bump, bump
3874 model.materials[m].maps[MATERIAL_MAP_NORMAL].value = materials[m].shininess;
3875
3876 model.materials[m].maps[MATERIAL_MAP_EMISSION].color = (Color){ (unsigned char)(materials[m].emission[0]*255.0f), (unsigned char)(materials[m].emission[1]*255.0f), (unsigned char)(materials[m].emission[2]*255.0f), 255 }; //float emission[3];
3877
3878 if (materials[m].displacement_texname != NULL) model.materials[m].maps[MATERIAL_MAP_HEIGHT].texture = LoadTexture(materials[m].displacement_texname); //char *displacement_texname; // disp
3879 }
3880
3881 tinyobj_attrib_free(&attrib);
3882 tinyobj_shapes_free(meshes, meshCount);
3883 tinyobj_materials_free(materials, materialCount);
3884
3885 UnloadFileText(fileText);
3886
3887 RL_FREE(matFaces);
3888 RL_FREE(vCount);
3889 RL_FREE(vtCount);
3890 RL_FREE(vnCount);
3891 RL_FREE(faceCount);
3892
3893 if (CHDIR(currentDir) != 0)
3894 {
3895 TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", currentDir);
3896 }
3897 }
3898
3899 return model;
3900}
3901#endif
3902
3903#if defined(SUPPORT_FILEFORMAT_IQM)
3904// Load IQM mesh data
3905static Model LoadIQM(const char *fileName)
3906{
3907 #define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number
3908 #define IQM_VERSION 2 // only IQM version 2 supported
3909
3910 #define BONE_NAME_LENGTH 32 // BoneInfo name string length
3911 #define MESH_NAME_LENGTH 32 // Mesh name string length
3912 #define MATERIAL_NAME_LENGTH 32 // Material name string length
3913
3914 unsigned int fileSize = 0;
3915 unsigned char *fileData = LoadFileData(fileName, &fileSize);
3916 unsigned char *fileDataPtr = fileData;
3917
3918 // IQM file structs
3919 //-----------------------------------------------------------------------------------
3920 typedef struct IQMHeader {
3921 char magic[16];
3922 unsigned int version;
3923 unsigned int filesize;
3924 unsigned int flags;
3925 unsigned int num_text, ofs_text;
3926 unsigned int num_meshes, ofs_meshes;
3927 unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
3928 unsigned int num_triangles, ofs_triangles, ofs_adjacency;
3929 unsigned int num_joints, ofs_joints;
3930 unsigned int num_poses, ofs_poses;
3931 unsigned int num_anims, ofs_anims;
3932 unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
3933 unsigned int num_comment, ofs_comment;
3934 unsigned int num_extensions, ofs_extensions;
3935 } IQMHeader;
3936
3937 typedef struct IQMMesh {
3938 unsigned int name;
3939 unsigned int material;
3940 unsigned int first_vertex, num_vertexes;
3941 unsigned int first_triangle, num_triangles;
3942 } IQMMesh;
3943
3944 typedef struct IQMTriangle {
3945 unsigned int vertex[3];
3946 } IQMTriangle;
3947
3948 typedef struct IQMJoint {
3949 unsigned int name;
3950 int parent;
3951 float translate[3], rotate[4], scale[3];
3952 } IQMJoint;
3953
3954 typedef struct IQMVertexArray {
3955 unsigned int type;
3956 unsigned int flags;
3957 unsigned int format;
3958 unsigned int size;
3959 unsigned int offset;
3960 } IQMVertexArray;
3961
3962 // NOTE: Below IQM structures are not used but listed for reference
3963 /*
3964 typedef struct IQMAdjacency {
3965 unsigned int triangle[3];
3966 } IQMAdjacency;
3967
3968 typedef struct IQMPose {
3969 int parent;
3970 unsigned int mask;
3971 float channeloffset[10];
3972 float channelscale[10];
3973 } IQMPose;
3974
3975 typedef struct IQMAnim {
3976 unsigned int name;
3977 unsigned int first_frame, num_frames;
3978 float framerate;
3979 unsigned int flags;
3980 } IQMAnim;
3981
3982 typedef struct IQMBounds {
3983 float bbmin[3], bbmax[3];
3984 float xyradius, radius;
3985 } IQMBounds;
3986 */
3987 //-----------------------------------------------------------------------------------
3988
3989 // IQM vertex data types
3990 enum {
3991 IQM_POSITION = 0,
3992 IQM_TEXCOORD = 1,
3993 IQM_NORMAL = 2,
3994 IQM_TANGENT = 3, // NOTE: Tangents unused by default
3995 IQM_BLENDINDEXES = 4,
3996 IQM_BLENDWEIGHTS = 5,
3997 IQM_COLOR = 6,
3998 IQM_CUSTOM = 0x10 // NOTE: Custom vertex values unused by default
3999 };
4000
4001 Model model = { 0 };
4002
4003 IQMMesh *imesh = NULL;
4004 IQMTriangle *tri = NULL;
4005 IQMVertexArray *va = NULL;
4006 IQMJoint *ijoint = NULL;
4007
4008 float *vertex = NULL;
4009 float *normal = NULL;
4010 float *text = NULL;
4011 char *blendi = NULL;
4012 unsigned char *blendw = NULL;
4013 unsigned char *color = NULL;
4014
4015 // In case file can not be read, return an empty model
4016 if (fileDataPtr == NULL) return model;
4017
4018 // Read IQM header
4019 IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr;
4020
4021 if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0)
4022 {
4023 TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
4024 return model;
4025 }
4026
4027 if (iqmHeader->version != IQM_VERSION)
4028 {
4029 TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version);
4030 return model;
4031 }
4032
4033 //fileDataPtr += sizeof(IQMHeader); // Move file data pointer
4034
4035 // Meshes data processing
4036 imesh = RL_MALLOC(iqmHeader->num_meshes*sizeof(IQMMesh));
4037 //fseek(iqmFile, iqmHeader->ofs_meshes, SEEK_SET);
4038 //fread(imesh, sizeof(IQMMesh)*iqmHeader->num_meshes, 1, iqmFile);
4039 memcpy(imesh, fileDataPtr + iqmHeader->ofs_meshes, iqmHeader->num_meshes*sizeof(IQMMesh));
4040
4041 model.meshCount = iqmHeader->num_meshes;
4042 model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
4043
4044 model.materialCount = model.meshCount;
4045 model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
4046 model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
4047
4048 char name[MESH_NAME_LENGTH] = { 0 };
4049 char material[MATERIAL_NAME_LENGTH] = { 0 };
4050
4051 for (int i = 0; i < model.meshCount; i++)
4052 {
4053 //fseek(iqmFile, iqmHeader->ofs_text + imesh[i].name, SEEK_SET);
4054 //fread(name, sizeof(char)*MESH_NAME_LENGTH, 1, iqmFile);
4055 memcpy(name, fileDataPtr + iqmHeader->ofs_text + imesh[i].name, MESH_NAME_LENGTH*sizeof(char));
4056
4057 //fseek(iqmFile, iqmHeader->ofs_text + imesh[i].material, SEEK_SET);
4058 //fread(material, sizeof(char)*MATERIAL_NAME_LENGTH, 1, iqmFile);
4059 memcpy(material, fileDataPtr + iqmHeader->ofs_text + imesh[i].material, MATERIAL_NAME_LENGTH*sizeof(char));
4060
4061 model.materials[i] = LoadMaterialDefault();
4062
4063 TRACELOG(LOG_DEBUG, "MODEL: [%s] mesh name (%s), material (%s)", fileName, name, material);
4064
4065 model.meshes[i].vertexCount = imesh[i].num_vertexes;
4066
4067 model.meshes[i].vertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex positions
4068 model.meshes[i].normals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex normals
4069 model.meshes[i].texcoords = RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float)); // Default vertex texcoords
4070
4071 model.meshes[i].boneIds = RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(unsigned char)); // Up-to 4 bones supported!
4072 model.meshes[i].boneWeights = RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float)); // Up-to 4 bones supported!
4073
4074 model.meshes[i].triangleCount = imesh[i].num_triangles;
4075 model.meshes[i].indices = RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short));
4076
4077 // Animated verted data, what we actually process for rendering
4078 // NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning)
4079 model.meshes[i].animVertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
4080 model.meshes[i].animNormals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
4081 }
4082
4083 // Triangles data processing
4084 tri = RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle));
4085 //fseek(iqmFile, iqmHeader->ofs_triangles, SEEK_SET);
4086 //fread(tri, iqmHeader->num_triangles*sizeof(IQMTriangle), 1, iqmFile);
4087 memcpy(tri, fileDataPtr + iqmHeader->ofs_triangles, iqmHeader->num_triangles*sizeof(IQMTriangle));
4088
4089 for (int m = 0; m < model.meshCount; m++)
4090 {
4091 int tcounter = 0;
4092
4093 for (unsigned int i = imesh[m].first_triangle; i < (imesh[m].first_triangle + imesh[m].num_triangles); i++)
4094 {
4095 // IQM triangles indexes are stored in counter-clockwise, but raylib processes the index in linear order,
4096 // expecting they point to the counter-clockwise vertex triangle, so we need to reverse triangle indexes
4097 // NOTE: raylib renders vertex data in counter-clockwise order (standard convention) by default
4098 model.meshes[m].indices[tcounter + 2] = tri[i].vertex[0] - imesh[m].first_vertex;
4099 model.meshes[m].indices[tcounter + 1] = tri[i].vertex[1] - imesh[m].first_vertex;
4100 model.meshes[m].indices[tcounter] = tri[i].vertex[2] - imesh[m].first_vertex;
4101 tcounter += 3;
4102 }
4103 }
4104
4105 // Vertex arrays data processing
4106 va = RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
4107 //fseek(iqmFile, iqmHeader->ofs_vertexarrays, SEEK_SET);
4108 //fread(va, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray), 1, iqmFile);
4109 memcpy(va, fileDataPtr + iqmHeader->ofs_vertexarrays, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
4110
4111 for (unsigned int i = 0; i < iqmHeader->num_vertexarrays; i++)
4112 {
4113 switch (va[i].type)
4114 {
4115 case IQM_POSITION:
4116 {
4117 vertex = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
4118 //fseek(iqmFile, va[i].offset, SEEK_SET);
4119 //fread(vertex, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
4120 memcpy(vertex, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
4121
4122 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
4123 {
4124 int vCounter = 0;
4125 for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
4126 {
4127 model.meshes[m].vertices[vCounter] = vertex[i];
4128 model.meshes[m].animVertices[vCounter] = vertex[i];
4129 vCounter++;
4130 }
4131 }
4132 } break;
4133 case IQM_NORMAL:
4134 {
4135 normal = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
4136 //fseek(iqmFile, va[i].offset, SEEK_SET);
4137 //fread(normal, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
4138 memcpy(normal, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
4139
4140 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
4141 {
4142 int vCounter = 0;
4143 for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
4144 {
4145 model.meshes[m].normals[vCounter] = normal[i];
4146 model.meshes[m].animNormals[vCounter] = normal[i];
4147 vCounter++;
4148 }
4149 }
4150 } break;
4151 case IQM_TEXCOORD:
4152 {
4153 text = RL_MALLOC(iqmHeader->num_vertexes*2*sizeof(float));
4154 //fseek(iqmFile, va[i].offset, SEEK_SET);
4155 //fread(text, iqmHeader->num_vertexes*2*sizeof(float), 1, iqmFile);
4156 memcpy(text, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*2*sizeof(float));
4157
4158 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
4159 {
4160 int vCounter = 0;
4161 for (unsigned int i = imesh[m].first_vertex*2; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*2; i++)
4162 {
4163 model.meshes[m].texcoords[vCounter] = text[i];
4164 vCounter++;
4165 }
4166 }
4167 } break;
4168 case IQM_BLENDINDEXES:
4169 {
4170 blendi = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(char));
4171 //fseek(iqmFile, va[i].offset, SEEK_SET);
4172 //fread(blendi, iqmHeader->num_vertexes*4*sizeof(char), 1, iqmFile);
4173 memcpy(blendi, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(char));
4174
4175 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
4176 {
4177 int boneCounter = 0;
4178 for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
4179 {
4180 model.meshes[m].boneIds[boneCounter] = blendi[i];
4181 boneCounter++;
4182 }
4183 }
4184 } break;
4185 case IQM_BLENDWEIGHTS:
4186 {
4187 blendw = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
4188 //fseek(iqmFile, va[i].offset, SEEK_SET);
4189 //fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
4190 memcpy(blendw, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
4191
4192 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
4193 {
4194 int boneCounter = 0;
4195 for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
4196 {
4197 model.meshes[m].boneWeights[boneCounter] = blendw[i]/255.0f;
4198 boneCounter++;
4199 }
4200 }
4201 } break;
4202 case IQM_COLOR:
4203 {
4204 color = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
4205 //fseek(iqmFile, va[i].offset, SEEK_SET);
4206 //fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
4207 memcpy(color, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
4208
4209 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
4210 {
4211 model.meshes[m].colors = RL_CALLOC(model.meshes[m].vertexCount*4, sizeof(unsigned char));
4212
4213 int vCounter = 0;
4214 for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
4215 {
4216 model.meshes[m].colors[vCounter] = color[i];
4217 vCounter++;
4218 }
4219 }
4220 } break;
4221 }
4222 }
4223
4224 // Bones (joints) data processing
4225 ijoint = RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
4226 //fseek(iqmFile, iqmHeader->ofs_joints, SEEK_SET);
4227 //fread(ijoint, iqmHeader->num_joints*sizeof(IQMJoint), 1, iqmFile);
4228 memcpy(ijoint, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
4229
4230 model.boneCount = iqmHeader->num_joints;
4231 model.bones = RL_MALLOC(iqmHeader->num_joints*sizeof(BoneInfo));
4232 model.bindPose = RL_MALLOC(iqmHeader->num_joints*sizeof(Transform));
4233
4234 for (unsigned int i = 0; i < iqmHeader->num_joints; i++)
4235 {
4236 // Bones
4237 model.bones[i].parent = ijoint[i].parent;
4238 //fseek(iqmFile, iqmHeader->ofs_text + ijoint[i].name, SEEK_SET);
4239 //fread(model.bones[i].name, BONE_NAME_LENGTH*sizeof(char), 1, iqmFile);
4240 memcpy(model.bones[i].name, fileDataPtr + iqmHeader->ofs_text + ijoint[i].name, BONE_NAME_LENGTH*sizeof(char));
4241
4242 // Bind pose (base pose)
4243 model.bindPose[i].translation.x = ijoint[i].translate[0];
4244 model.bindPose[i].translation.y = ijoint[i].translate[1];
4245 model.bindPose[i].translation.z = ijoint[i].translate[2];
4246
4247 model.bindPose[i].rotation.x = ijoint[i].rotate[0];
4248 model.bindPose[i].rotation.y = ijoint[i].rotate[1];
4249 model.bindPose[i].rotation.z = ijoint[i].rotate[2];
4250 model.bindPose[i].rotation.w = ijoint[i].rotate[3];
4251
4252 model.bindPose[i].scale.x = ijoint[i].scale[0];
4253 model.bindPose[i].scale.y = ijoint[i].scale[1];
4254 model.bindPose[i].scale.z = ijoint[i].scale[2];
4255 }
4256
4257 // Build bind pose from parent joints
4258 for (int i = 0; i < model.boneCount; i++)
4259 {
4260 if (model.bones[i].parent >= 0)
4261 {
4262 model.bindPose[i].rotation = QuaternionMultiply(model.bindPose[model.bones[i].parent].rotation, model.bindPose[i].rotation);
4264 model.bindPose[i].translation = Vector3Add(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].translation);
4265 model.bindPose[i].scale = Vector3Multiply(model.bindPose[i].scale, model.bindPose[model.bones[i].parent].scale);
4266 }
4267 }
4268
4269 RL_FREE(fileData);
4270
4271 RL_FREE(imesh);
4272 RL_FREE(tri);
4273 RL_FREE(va);
4274 RL_FREE(vertex);
4275 RL_FREE(normal);
4276 RL_FREE(text);
4277 RL_FREE(blendi);
4278 RL_FREE(blendw);
4279 RL_FREE(ijoint);
4280
4281 return model;
4282}
4283
4284// Load IQM animation data
4285static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, unsigned int *animCount)
4286{
4287 #define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number
4288 #define IQM_VERSION 2 // only IQM version 2 supported
4289
4290 unsigned int fileSize = 0;
4291 unsigned char *fileData = LoadFileData(fileName, &fileSize);
4292 unsigned char *fileDataPtr = fileData;
4293
4294 typedef struct IQMHeader {
4295 char magic[16];
4296 unsigned int version;
4297 unsigned int filesize;
4298 unsigned int flags;
4299 unsigned int num_text, ofs_text;
4300 unsigned int num_meshes, ofs_meshes;
4301 unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
4302 unsigned int num_triangles, ofs_triangles, ofs_adjacency;
4303 unsigned int num_joints, ofs_joints;
4304 unsigned int num_poses, ofs_poses;
4305 unsigned int num_anims, ofs_anims;
4306 unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
4307 unsigned int num_comment, ofs_comment;
4308 unsigned int num_extensions, ofs_extensions;
4309 } IQMHeader;
4310
4311 typedef struct IQMPose {
4312 int parent;
4313 unsigned int mask;
4314 float channeloffset[10];
4315 float channelscale[10];
4316 } IQMPose;
4317
4318 typedef struct IQMAnim {
4319 unsigned int name;
4320 unsigned int first_frame, num_frames;
4321 float framerate;
4322 unsigned int flags;
4323 } IQMAnim;
4324
4325 // In case file can not be read, return an empty model
4326 if (fileDataPtr == NULL) return NULL;
4327
4328 // Read IQM header
4329 IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr;
4330
4331 if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0)
4332 {
4333 TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
4334 return NULL;
4335 }
4336
4337 if (iqmHeader->version != IQM_VERSION)
4338 {
4339 TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version);
4340 return NULL;
4341 }
4342
4343 // Get bones data
4344 IQMPose *poses = RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose));
4345 //fseek(iqmFile, iqmHeader->ofs_poses, SEEK_SET);
4346 //fread(poses, iqmHeader->num_poses*sizeof(IQMPose), 1, iqmFile);
4347 memcpy(poses, fileDataPtr + iqmHeader->ofs_poses, iqmHeader->num_poses*sizeof(IQMPose));
4348
4349 // Get animations data
4350 *animCount = iqmHeader->num_anims;
4351 IQMAnim *anim = RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim));
4352 //fseek(iqmFile, iqmHeader->ofs_anims, SEEK_SET);
4353 //fread(anim, iqmHeader->num_anims*sizeof(IQMAnim), 1, iqmFile);
4354 memcpy(anim, fileDataPtr + iqmHeader->ofs_anims, iqmHeader->num_anims*sizeof(IQMAnim));
4355
4356 ModelAnimation *animations = RL_MALLOC(iqmHeader->num_anims*sizeof(ModelAnimation));
4357
4358 // frameposes
4359 unsigned short *framedata = RL_MALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
4360 //fseek(iqmFile, iqmHeader->ofs_frames, SEEK_SET);
4361 //fread(framedata, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short), 1, iqmFile);
4362 memcpy(framedata, fileDataPtr + iqmHeader->ofs_frames, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
4363
4364 for (unsigned int a = 0; a < iqmHeader->num_anims; a++)
4365 {
4366 animations[a].frameCount = anim[a].num_frames;
4367 animations[a].boneCount = iqmHeader->num_poses;
4368 animations[a].bones = RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo));
4369 animations[a].framePoses = RL_MALLOC(anim[a].num_frames*sizeof(Transform *));
4370 // animations[a].framerate = anim.framerate; // TODO: Use framerate?
4371
4372 for (unsigned int j = 0; j < iqmHeader->num_poses; j++)
4373 {
4374 strcpy(animations[a].bones[j].name, "ANIMJOINTNAME");
4375 animations[a].bones[j].parent = poses[j].parent;
4376 }
4377
4378 for (unsigned int j = 0; j < anim[a].num_frames; j++) animations[a].framePoses[j] = RL_MALLOC(iqmHeader->num_poses*sizeof(Transform));
4379
4380 int dcounter = anim[a].first_frame*iqmHeader->num_framechannels;
4381
4382 for (unsigned int frame = 0; frame < anim[a].num_frames; frame++)
4383 {
4384 for (unsigned int i = 0; i < iqmHeader->num_poses; i++)
4385 {
4386 animations[a].framePoses[frame][i].translation.x = poses[i].channeloffset[0];
4387
4388 if (poses[i].mask & 0x01)
4389 {
4390 animations[a].framePoses[frame][i].translation.x += framedata[dcounter]*poses[i].channelscale[0];
4391 dcounter++;
4392 }
4393
4394 animations[a].framePoses[frame][i].translation.y = poses[i].channeloffset[1];
4395
4396 if (poses[i].mask & 0x02)
4397 {
4398 animations[a].framePoses[frame][i].translation.y += framedata[dcounter]*poses[i].channelscale[1];
4399 dcounter++;
4400 }
4401
4402 animations[a].framePoses[frame][i].translation.z = poses[i].channeloffset[2];
4403
4404 if (poses[i].mask & 0x04)
4405 {
4406 animations[a].framePoses[frame][i].translation.z += framedata[dcounter]*poses[i].channelscale[2];
4407 dcounter++;
4408 }
4409
4410 animations[a].framePoses[frame][i].rotation.x = poses[i].channeloffset[3];
4411
4412 if (poses[i].mask & 0x08)
4413 {
4414 animations[a].framePoses[frame][i].rotation.x += framedata[dcounter]*poses[i].channelscale[3];
4415 dcounter++;
4416 }
4417
4418 animations[a].framePoses[frame][i].rotation.y = poses[i].channeloffset[4];
4419
4420 if (poses[i].mask & 0x10)
4421 {
4422 animations[a].framePoses[frame][i].rotation.y += framedata[dcounter]*poses[i].channelscale[4];
4423 dcounter++;
4424 }
4425
4426 animations[a].framePoses[frame][i].rotation.z = poses[i].channeloffset[5];
4427
4428 if (poses[i].mask & 0x20)
4429 {
4430 animations[a].framePoses[frame][i].rotation.z += framedata[dcounter]*poses[i].channelscale[5];
4431 dcounter++;
4432 }
4433
4434 animations[a].framePoses[frame][i].rotation.w = poses[i].channeloffset[6];
4435
4436 if (poses[i].mask & 0x40)
4437 {
4438 animations[a].framePoses[frame][i].rotation.w += framedata[dcounter]*poses[i].channelscale[6];
4439 dcounter++;
4440 }
4441
4442 animations[a].framePoses[frame][i].scale.x = poses[i].channeloffset[7];
4443
4444 if (poses[i].mask & 0x80)
4445 {
4446 animations[a].framePoses[frame][i].scale.x += framedata[dcounter]*poses[i].channelscale[7];
4447 dcounter++;
4448 }
4449
4450 animations[a].framePoses[frame][i].scale.y = poses[i].channeloffset[8];
4451
4452 if (poses[i].mask & 0x100)
4453 {
4454 animations[a].framePoses[frame][i].scale.y += framedata[dcounter]*poses[i].channelscale[8];
4455 dcounter++;
4456 }
4457
4458 animations[a].framePoses[frame][i].scale.z = poses[i].channeloffset[9];
4459
4460 if (poses[i].mask & 0x200)
4461 {
4462 animations[a].framePoses[frame][i].scale.z += framedata[dcounter]*poses[i].channelscale[9];
4463 dcounter++;
4464 }
4465
4466 animations[a].framePoses[frame][i].rotation = QuaternionNormalize(animations[a].framePoses[frame][i].rotation);
4467 }
4468 }
4469
4470 // Build frameposes
4471 for (unsigned int frame = 0; frame < anim[a].num_frames; frame++)
4472 {
4473 for (int i = 0; i < animations[a].boneCount; i++)
4474 {
4475 if (animations[a].bones[i].parent >= 0)
4476 {
4477 animations[a].framePoses[frame][i].rotation = QuaternionMultiply(animations[a].framePoses[frame][animations[a].bones[i].parent].rotation, animations[a].framePoses[frame][i].rotation);
4478 animations[a].framePoses[frame][i].translation = Vector3RotateByQuaternion(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].rotation);
4479 animations[a].framePoses[frame][i].translation = Vector3Add(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].translation);
4480 animations[a].framePoses[frame][i].scale = Vector3Multiply(animations[a].framePoses[frame][i].scale, animations[a].framePoses[frame][animations[a].bones[i].parent].scale);
4481 }
4482 }
4483 }
4484 }
4485
4486 RL_FREE(fileData);
4487
4488 RL_FREE(framedata);
4489 RL_FREE(poses);
4490 RL_FREE(anim);
4491
4492 return animations;
4493}
4494
4495#endif
4496
4497#if defined(SUPPORT_FILEFORMAT_GLTF)
4498// Load image from different glTF provided methods (uri, path, buffer_view)
4499static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPath)
4500{
4501 Image image = { 0 };
4502
4503 if (cgltfImage->uri != NULL) // Check if image data is provided as a uri (base64 or path)
4504 {
4505 if ((strlen(cgltfImage->uri) > 5) &&
4506 (cgltfImage->uri[0] == 'd') &&
4507 (cgltfImage->uri[1] == 'a') &&
4508 (cgltfImage->uri[2] == 't') &&
4509 (cgltfImage->uri[3] == 'a') &&
4510 (cgltfImage->uri[4] == ':')) // Check if image is provided as base64 text data
4511 {
4512 // Data URI Format: data:<mediatype>;base64,<data>
4513
4514 // Find the comma
4515 int i = 0;
4516 while ((cgltfImage->uri[i] != ',') && (cgltfImage->uri[i] != 0)) i++;
4517
4518 if (cgltfImage->uri[i] == 0) TRACELOG(LOG_WARNING, "IMAGE: glTF data URI is not a valid image");
4519 else
4520 {
4521 int base64Size = (int)strlen(cgltfImage->uri + i + 1);
4522 int outSize = 3*(base64Size/4); // TODO: Consider padding (-numberOfPaddingCharacters)
4523 void *data = NULL;
4524
4525 cgltf_options options = { 0 };
4526 cgltf_result result = cgltf_load_buffer_base64(&options, outSize, cgltfImage->uri + i + 1, &data);
4527
4528 if (result == cgltf_result_success)
4529 {
4530 image = LoadImageFromMemory(".png", (unsigned char *)data, outSize);
4531 cgltf_free((cgltf_data*)data);
4532 }
4533 }
4534 }
4535 else // Check if image is provided as image path
4536 {
4537 image = LoadImage(TextFormat("%s/%s", texPath, cgltfImage->uri));
4538 }
4539 }
4540 else if (cgltfImage->buffer_view->buffer->data != NULL) // Check if image is provided as data buffer
4541 {
4542 unsigned char *data = RL_MALLOC(cgltfImage->buffer_view->size);
4543 int offset = (int)cgltfImage->buffer_view->offset;
4544 int stride = (int)cgltfImage->buffer_view->stride? (int)cgltfImage->buffer_view->stride : 1;
4545
4546 // Copy buffer data to memory for loading
4547 for (unsigned int i = 0; i < cgltfImage->buffer_view->size; i++)
4548 {
4549 data[i] = ((unsigned char *)cgltfImage->buffer_view->buffer->data)[offset];
4550 offset += stride;
4551 }
4552
4553 // Check mime_type for image: (cgltfImage->mime_type == "image/png")
4554 // NOTE: Detected that some models define mime_type as "image\\/png"
4555 if ((strcmp(cgltfImage->mime_type, "image\\/png") == 0) ||
4556 (strcmp(cgltfImage->mime_type, "image/png") == 0)) image = LoadImageFromMemory(".png", data, (int)cgltfImage->buffer_view->size);
4557 else if ((strcmp(cgltfImage->mime_type, "image\\/jpeg") == 0) ||
4558 (strcmp(cgltfImage->mime_type, "image/jpeg") == 0)) image = LoadImageFromMemory(".jpg", data, (int)cgltfImage->buffer_view->size);
4559 else TRACELOG(LOG_WARNING, "MODEL: glTF image data MIME type not recognized", TextFormat("%s/%s", texPath, cgltfImage->uri));
4560
4561 RL_FREE(data);
4562 }
4563
4564 return image;
4565}
4566
4567// Load glTF file into model struct, .gltf and .glb supported
4568static Model LoadGLTF(const char *fileName)
4569{
4570
4594 // Macro to simplify attributes loading code
4595 #define LOAD_ATTRIBUTE(accesor, numComp, dataType, dstPtr) \
4596 { \
4597 int n = 0; \
4598 dataType *buffer = (dataType *)accesor->buffer_view->buffer->data + accesor->buffer_view->offset/sizeof(dataType) + accesor->offset/sizeof(dataType); \
4599 for (unsigned int k = 0; k < accesor->count; k++) \
4600 {\
4601 for (int l = 0; l < numComp; l++) \
4602 {\
4603 dstPtr[numComp*k + l] = buffer[n + l];\
4604 }\
4605 n += (int)(accesor->stride/sizeof(dataType));\
4606 }\
4607 }
4608
4609 Model model = { 0 };
4610
4611 // glTF file loading
4612 unsigned int dataSize = 0;
4613 unsigned char *fileData = LoadFileData(fileName, &dataSize);
4614
4615 if (fileData == NULL) return model;
4616
4617 // glTF data loading
4618 cgltf_options options = { 0 };
4619 cgltf_data *data = NULL;
4620 cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data);
4621
4622 if (result == cgltf_result_success)
4623 {
4624 if (data->file_type == cgltf_file_type_glb) TRACELOG(LOG_INFO, "MODEL: [%s] Model basic data (glb) loaded successfully", fileName);
4625 else if (data->file_type == cgltf_file_type_gltf) TRACELOG(LOG_INFO, "MODEL: [%s] Model basic data (glTF) loaded successfully", fileName);
4626 else TRACELOG(LOG_WARNING, "MODEL: [%s] Model format not recognized", fileName);
4627
4628 TRACELOG(LOG_INFO, " > Meshes count: %i", data->meshes_count);
4629 TRACELOG(LOG_INFO, " > Materials count: %i (+1 default)", data->materials_count);
4630 TRACELOG(LOG_DEBUG, " > Buffers count: %i", data->buffers_count);
4631 TRACELOG(LOG_DEBUG, " > Images count: %i", data->images_count);
4632 TRACELOG(LOG_DEBUG, " > Textures count: %i", data->textures_count);
4633
4634 // Force reading data buffers (fills buffer_view->buffer->data)
4635 // NOTE: If an uri is defined to base64 data or external path, it's automatically loaded -> TODO: Verify this assumption
4636 result = cgltf_load_buffers(&options, data, fileName);
4637 if (result != cgltf_result_success) TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load mesh/material buffers", fileName);
4638
4639 int primitivesCount = 0;
4640 // NOTE: We will load every primitive in the glTF as a separate raylib mesh
4641 for (unsigned int i = 0; i < data->meshes_count; i++) primitivesCount += (int)data->meshes[i].primitives_count;
4642
4643 // Load our model data: meshes and materials
4644 model.meshCount = primitivesCount;
4645 model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
4646
4647 // NOTE: We keep an extra slot for default material, in case some mesh requires it
4648 model.materialCount = (int)data->materials_count + 1;
4649 model.materials = RL_CALLOC(model.materialCount, sizeof(Material));
4650 model.materials[0] = LoadMaterialDefault(); // Load default material (index: 0)
4651
4652 // Load mesh-material indices, by default all meshes are mapped to material index: 0
4653 model.meshMaterial = RL_CALLOC(model.meshCount, sizeof(int));
4654
4655 // Load materials data
4656 //----------------------------------------------------------------------------------------------------
4657 for (unsigned int i = 0, j = 1; i < data->materials_count; i++, j++)
4658 {
4659 model.materials[j] = LoadMaterialDefault();
4660 const char *texPath = GetDirectoryPath(fileName);
4661
4662 // Check glTF material flow: PBR metallic/roughness flow
4663 // NOTE: Alternatively, materials can follow PBR specular/glossiness flow
4665 {
4666 // Load base color texture (albedo)
4668 {
4669 Image imAlbedo = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath);
4670 if (imAlbedo.data != NULL)
4671 {
4673 UnloadImage(imAlbedo);
4674 }
4675 }
4676 // Load base color factor (tint)
4677 model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255);
4678 model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255);
4679 model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255);
4680 model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255);
4681
4682 // Load metallic/roughness texture
4684 {
4685 Image imMetallicRoughness = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath);
4686 if (imMetallicRoughness.data != NULL)
4687 {
4688 model.materials[j].maps[MATERIAL_MAP_ROUGHNESS].texture = LoadTextureFromImage(imMetallicRoughness);
4689 UnloadImage(imMetallicRoughness);
4690 }
4691
4692 // Load metallic/roughness material properties
4693 float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor;
4694 model.materials[j].maps[MATERIAL_MAP_ROUGHNESS].value = roughness;
4695
4696 float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor;
4697 model.materials[j].maps[MATERIAL_MAP_METALNESS].value = metallic;
4698 }
4699
4700 // Load normal texture
4701 if (data->materials[i].normal_texture.texture)
4702 {
4703 Image imNormal = LoadImageFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath);
4704 if (imNormal.data != NULL)
4705 {
4707 UnloadImage(imNormal);
4708 }
4709 }
4710
4711 // Load ambient occlusion texture
4712 if (data->materials[i].occlusion_texture.texture)
4713 {
4714 Image imOcclusion = LoadImageFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath);
4715 if (imOcclusion.data != NULL)
4716 {
4718 UnloadImage(imOcclusion);
4719 }
4720 }
4721
4722 // Load emissive texture
4723 if (data->materials[i].emissive_texture.texture)
4724 {
4725 Image imEmissive = LoadImageFromCgltfImage(data->materials[i].emissive_texture.texture->image, texPath);
4726 if (imEmissive.data != NULL)
4727 {
4729 UnloadImage(imEmissive);
4730 }
4731
4732 // Load emissive color factor
4733 model.materials[j].maps[MATERIAL_MAP_EMISSION].color.r = (unsigned char)(data->materials[i].emissive_factor[0]*255);
4734 model.materials[j].maps[MATERIAL_MAP_EMISSION].color.g = (unsigned char)(data->materials[i].emissive_factor[1]*255);
4735 model.materials[j].maps[MATERIAL_MAP_EMISSION].color.b = (unsigned char)(data->materials[i].emissive_factor[2]*255);
4736 model.materials[j].maps[MATERIAL_MAP_EMISSION].color.a = 255;
4737 }
4738 }
4739
4740 // Other possible materials not supported by raylib pipeline:
4741 // has_clearcoat, has_transmission, has_volume, has_ior, has specular, has_sheen
4742 }
4743
4744 // Load meshes data
4745 //----------------------------------------------------------------------------------------------------
4746 for (unsigned int i = 0, meshIndex = 0; i < data->meshes_count; i++)
4747 {
4748 // NOTE: meshIndex accumulates primitives
4749
4750 for (unsigned int p = 0; p < data->meshes[i].primitives_count; p++)
4751 {
4752 // NOTE: We only support primitives defined by triangles
4753 // Other alternatives: points, lines, line_strip, triangle_strip
4754 if (data->meshes[i].primitives[p].type != cgltf_primitive_type_triangles) continue;
4755
4756 // NOTE: Attributes data could be provided in several data formats (8, 8u, 16u, 32...),
4757 // Only some formats for each attribute type are supported, read info at the top of this function!
4758
4759 for (unsigned int j = 0; j < data->meshes[i].primitives[p].attributes_count; j++)
4760 {
4761 // Check the different attributes for every pimitive
4762 if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_position) // POSITION
4763 {
4764 cgltf_accessor *attribute = data->meshes[i].primitives[p].attributes[j].data;
4765
4766 // WARNING: SPECS: POSITION accessor MUST have its min and max properties defined.
4767
4768 if ((attribute->component_type == cgltf_component_type_r_32f) && (attribute->type == cgltf_type_vec3))
4769 {
4770 // Init raylib mesh vertices to copy glTF attribute data
4771 model.meshes[meshIndex].vertexCount = (int)attribute->count;
4772 model.meshes[meshIndex].vertices = RL_MALLOC(attribute->count*3*sizeof(float));
4773
4774 // Load 3 components of float data type into mesh.vertices
4775 LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].vertices)
4776 }
4777 else TRACELOG(LOG_WARNING, "MODEL: [%s] Vertices attribute data format not supported, use vec3 float", fileName);
4778 }
4779 else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_normal) // NORMAL
4780 {
4781 cgltf_accessor *attribute = data->meshes[i].primitives[p].attributes[j].data;
4782
4783 if ((attribute->component_type == cgltf_component_type_r_32f) && (attribute->type == cgltf_type_vec3))
4784 {
4785 // Init raylib mesh normals to copy glTF attribute data
4786 model.meshes[meshIndex].normals = RL_MALLOC(attribute->count*3*sizeof(float));
4787
4788 // Load 3 components of float data type into mesh.normals
4789 LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].normals)
4790 }
4791 else TRACELOG(LOG_WARNING, "MODEL: [%s] Normal attribute data format not supported, use vec3 float", fileName);
4792 }
4793 else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_tangent) // TANGENT
4794 {
4795 cgltf_accessor *attribute = data->meshes[i].primitives[p].attributes[j].data;
4796
4797 if ((attribute->component_type == cgltf_component_type_r_32f) && (attribute->type == cgltf_type_vec4))
4798 {
4799 // Init raylib mesh tangent to copy glTF attribute data
4800 model.meshes[meshIndex].tangents = RL_MALLOC(attribute->count*4*sizeof(float));
4801
4802 // Load 4 components of float data type into mesh.tangents
4803 LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].tangents)
4804 }
4805 else TRACELOG(LOG_WARNING, "MODEL: [%s] Tangent attribute data format not supported, use vec4 float", fileName);
4806 }
4807 else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_texcoord) // TEXCOORD_0
4808 {
4809 // TODO: Support additional texture coordinates: TEXCOORD_1 -> mesh.texcoords2
4810
4811 cgltf_accessor *attribute = data->meshes[i].primitives[p].attributes[j].data;
4812
4813 if ((attribute->component_type == cgltf_component_type_r_32f) && (attribute->type == cgltf_type_vec2))
4814 {
4815 // Init raylib mesh texcoords to copy glTF attribute data
4816 model.meshes[meshIndex].texcoords = RL_MALLOC(attribute->count*2*sizeof(float));
4817
4818 // Load 3 components of float data type into mesh.texcoords
4819 LOAD_ATTRIBUTE(attribute, 2, float, model.meshes[meshIndex].texcoords)
4820 }
4821 else TRACELOG(LOG_WARNING, "MODEL: [%s] Texcoords attribute data format not supported, use vec2 float", fileName);
4822 }
4823 else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_color) // COLOR_0
4824 {
4825 cgltf_accessor *attribute = data->meshes[i].primitives[p].attributes[j].data;
4826
4827 // WARNING: SPECS: All components of each COLOR_n accessor element MUST be clamped to [0.0, 1.0] range.
4828
4829 if ((attribute->component_type == cgltf_component_type_r_8u) && (attribute->type == cgltf_type_vec4))
4830 {
4831 // Init raylib mesh color to copy glTF attribute data
4832 model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
4833
4834 // Load 4 components of unsigned char data type into mesh.colors
4835 LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].colors)
4836 }
4837 else if ((attribute->component_type == cgltf_component_type_r_16u) && (attribute->type == cgltf_type_vec4))
4838 {
4839 // Init raylib mesh color to copy glTF attribute data
4840 model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
4841
4842 // Load data into a temp buffer to be converted to raylib data type
4843 unsigned short *temp = RL_MALLOC(attribute->count*4*sizeof(unsigned short));
4844 LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
4845
4846 // Convert data to raylib color data type (4 bytes)
4847 for (int c = 0; c < attribute->count*4; c++) model.meshes[meshIndex].colors[c] = (unsigned char)(((float)temp[c]/65535.0f)*255.0f);
4848
4849 RL_FREE(temp);
4850 }
4851 else if ((attribute->component_type == cgltf_component_type_r_32f) && (attribute->type == cgltf_type_vec4))
4852 {
4853 // Init raylib mesh color to copy glTF attribute data
4854 model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
4855
4856 // Load data into a temp buffer to be converted to raylib data type
4857 float *temp = RL_MALLOC(attribute->count*4*sizeof(float));
4858 LOAD_ATTRIBUTE(attribute, 4, float, temp);
4859
4860 // Convert data to raylib color data type (4 bytes), we expect the color data normalized
4861 for (int c = 0; c < attribute->count*4; c++) model.meshes[meshIndex].colors[c] = (unsigned char)(temp[c]*255.0f);
4862
4863 RL_FREE(temp);
4864 }
4865 else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName);
4866 }
4867
4868 // NOTE: Attributes related to animations are processed separately
4869 }
4870
4871 // Load primitive indices data (if provided)
4872 if (data->meshes[i].primitives[p].indices != NULL)
4873 {
4874 cgltf_accessor *attribute = data->meshes[i].primitives[p].indices;
4875
4876 model.meshes[meshIndex].triangleCount = (int)attribute->count/3;
4877
4879 {
4880 // Init raylib mesh indices to copy glTF attribute data
4881 model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short));
4882
4883 // Load unsigned short data type into mesh.indices
4884 LOAD_ATTRIBUTE(attribute, 1, unsigned short, model.meshes[meshIndex].indices)
4885 }
4886 else if (attribute->component_type == cgltf_component_type_r_32u)
4887 {
4888 // Init raylib mesh indices to copy glTF attribute data
4889 model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short));
4890
4891 // Load data into a temp buffer to be converted to raylib data type
4892 unsigned int *temp = RL_MALLOC(attribute->count*sizeof(unsigned int));
4893 LOAD_ATTRIBUTE(attribute, 1, unsigned int, temp);
4894
4895 // Convert data to raylib indices data type (unsigned short)
4896 for (int d = 0; d < attribute->count; d++) model.meshes[meshIndex].indices[d] = (unsigned short)temp[d];
4897
4898 TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data converted from u32 to u16, possible loss of data", fileName);
4899
4900 RL_FREE(temp);
4901 }
4902 else TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data format not supported, use u16", fileName);
4903 }
4904 else model.meshes[meshIndex].triangleCount = model.meshes[meshIndex].vertexCount/3; // Unindexed mesh
4905
4906 // Assign to the primitive mesh the corresponding material index
4907 // NOTE: If no material defined, mesh uses the already assigned default material (index: 0)
4908 for (int m = 0; m < data->materials_count; m++)
4909 {
4910 // The primitive actually keeps the pointer to the corresponding material,
4911 // raylib instead assigns to the mesh the by its index, as loaded in model.materials array
4912 // To get the index, we check if material pointers match and we assign the corresponding index,
4913 // skipping index 0, the default material
4914 if (&data->materials[m] == data->meshes[i].primitives[p].material)
4915 {
4916 model.meshMaterial[meshIndex] = m + 1;
4917 break;
4918 }
4919 }
4920
4921 meshIndex++; // Move to next mesh
4922 }
4923 }
4924
4925/*
4926 // TODO: Load glTF meshes animation data
4927 // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skins
4928 // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skinned-mesh-attributes
4929 //----------------------------------------------------------------------------------------------------
4930 for (unsigned int i = 0, meshIndex = 0; i < data->meshes_count; i++)
4931 {
4932 for (unsigned int p = 0; p < data->meshes[i].primitives_count; p++)
4933 {
4934 // NOTE: We only support primitives defined by triangles
4935 if (data->meshes[i].primitives[p].type != cgltf_primitive_type_triangles) continue;
4936
4937 for (unsigned int j = 0; j < data->meshes[i].primitives[p].attributes_count; j++)
4938 {
4939 // NOTE: JOINTS_1 + WEIGHT_1 will be used for +4 joints influencing a vertex -> Not supported by raylib
4940
4941 if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_joints) // JOINTS_n (vec4: 4 bones max per vertex / u8, u16)
4942 {
4943 cgltf_accessor *attribute = data->meshes[i].primitives[p].attributes[j].data;
4944
4945 if ((attribute->component_type == cgltf_component_type_r_8u) && (attribute->type == cgltf_type_vec4))
4946 {
4947 // Init raylib mesh bone ids to copy glTF attribute data
4948 model.meshes[meshIndex].boneIds = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
4949
4950 // Load 4 components of unsigned char data type into mesh.boneIds
4951 LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].boneIds)
4952 }
4953 else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint attribute data format not supported, use vec4 u8", fileName);
4954 }
4955 else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_weights) // WEIGHTS_n (vec4 / u8, u16, f32)
4956 {
4957 cgltf_accessor *attribute = data->meshes[i].primitives[p].attributes[j].data;
4958
4959 if ((attribute->component_type == cgltf_component_type_r_32f) && (attribute->type == cgltf_type_vec4))
4960 {
4961 // Init raylib mesh bone weight to copy glTF attribute data
4962 model.meshes[meshIndex].boneWeights = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
4963
4964 // Load 4 components of float data type into mesh.boneWeights
4965 LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].boneWeights)
4966 }
4967 else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint weight attribute data format not supported, use vec4 float", fileName);
4968 }
4969 }
4970
4971 meshIndex++; // Move to next mesh
4972 }
4973 }
4974*/
4975 // Free all cgltf loaded data
4976 cgltf_free(data);
4977 }
4978 else TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName);
4979
4980 // WARNING: cgltf requires the file pointer available while reading data
4981 UnloadFileData(fileData);
4982
4983 return model;
4984}
4985#endif
4986
4987#if defined(SUPPORT_FILEFORMAT_VOX)
4988// Load VOX (MagicaVoxel) mesh data
4989static Model LoadVOX(const char *fileName)
4990{
4991 Model model = { 0 };
4992
4993 int nbvertices = 0;
4994 int meshescount = 0;
4995 unsigned int fileSize = 0;
4996 unsigned char *fileData = NULL;
4997
4998 // Read vox file into buffer
4999 fileData = LoadFileData(fileName, &fileSize);
5000 if (fileData == 0)
5001 {
5002 TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load VOX file", fileName);
5003 return model;
5004 }
5005
5006 // Read and build voxarray description
5007 VoxArray3D voxarray = { 0 };
5008 int ret = Vox_LoadFromMemory(fileData, fileSize, &voxarray);
5009
5010 if (ret != VOX_SUCCESS)
5011 {
5012 // Error
5013 UnloadFileData(fileData);
5014
5015 TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load VOX data", fileName);
5016 return model;
5017 }
5018 else
5019 {
5020 // Success: Compute meshes count
5021 nbvertices = voxarray.vertices.used;
5022 meshescount = 1 + (nbvertices/65536);
5023
5024 TRACELOG(LOG_INFO, "MODEL: [%s] VOX data loaded successfully : %i vertices/%i meshes", fileName, nbvertices, meshescount);
5025 }
5026
5027 // Build models from meshes
5028 model.transform = MatrixIdentity();
5029
5030 model.meshCount = meshescount;
5031 model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
5032
5033 model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
5034
5035 model.materialCount = 1;
5036 model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
5037 model.materials[0] = LoadMaterialDefault();
5038
5039 // Init model meshes
5040 int verticesRemain = voxarray.vertices.used;
5041 int verticesMax = 65532; // 5461 voxels x 12 vertices per voxel -> 65532 (must be inf 65536)
5042
5043 // 6*4 = 12 vertices per voxel
5044 Vector3 *pvertices = (Vector3 *)voxarray.vertices.array;
5045 Color *pcolors = (Color *)voxarray.colors.array;
5046
5047 unsigned short *pindices = voxarray.indices.array; // 5461*6*6 = 196596 indices max per mesh
5048
5049 int size = 0;
5050
5051 for (int i = 0; i < meshescount; i++)
5052 {
5053 Mesh *pmesh = &model.meshes[i];
5054 memset(pmesh, 0, sizeof(Mesh));
5055
5056 // Copy vertices
5057 pmesh->vertexCount = (int)fmin(verticesMax, verticesRemain);
5058
5059 size = pmesh->vertexCount*sizeof(float)*3;
5060 pmesh->vertices = RL_MALLOC(size);
5061 memcpy(pmesh->vertices, pvertices, size);
5062
5063 // Copy indices
5064 // TODO: Compute globals indices array
5065 size = voxarray.indices.used*sizeof(unsigned short);
5066 pmesh->indices = RL_MALLOC(size);
5067 memcpy(pmesh->indices, pindices, size);
5068
5069 pmesh->triangleCount = (pmesh->vertexCount/4)*2;
5070
5071 // Copy colors
5072 size = pmesh->vertexCount*sizeof(Color);
5073 pmesh->colors = RL_MALLOC(size);
5074 memcpy(pmesh->colors, pcolors, size);
5075
5076 // First material index
5077 model.meshMaterial[i] = 0;
5078
5079 verticesRemain -= verticesMax;
5080 pvertices += verticesMax;
5081 pcolors += verticesMax;
5082 }
5083
5084 // Free buffers
5085 Vox_FreeArrays(&voxarray);
5086 UnloadFileData(fileData);
5087
5088 return model;
5089}
5090#endif
5091
5092#endif // SUPPORT_MODULE_RMODELS
@ cgltf_primitive_type_triangles
Definition: cgltf.h:198
cgltf_result cgltf_parse(const cgltf_options *options, const void *data, cgltf_size size, cgltf_data **out_data)
void cgltf_free(cgltf_data *data)
@ cgltf_attribute_type_color
Definition: cgltf.h:164
@ cgltf_attribute_type_texcoord
Definition: cgltf.h:163
@ cgltf_attribute_type_position
Definition: cgltf.h:160
@ cgltf_attribute_type_tangent
Definition: cgltf.h:162
@ cgltf_attribute_type_normal
Definition: cgltf.h:161
cgltf_result cgltf_load_buffer_base64(const cgltf_options *options, cgltf_size size, const char *base64, void **out_data)
cgltf_result cgltf_load_buffers(const cgltf_options *options, cgltf_data *data, const char *gltf_path)
@ cgltf_type_vec4
Definition: cgltf.h:186
@ cgltf_type_vec2
Definition: cgltf.h:184
@ cgltf_type_vec3
Definition: cgltf.h:185
@ cgltf_component_type_r_32f
Definition: cgltf.h:177
@ cgltf_component_type_r_8u
Definition: cgltf.h:173
@ cgltf_component_type_r_32u
Definition: cgltf.h:176
@ cgltf_component_type_r_16u
Definition: cgltf.h:175
cgltf_result
Definition: cgltf.h:115
@ cgltf_result_success
Definition: cgltf.h:116
@ cgltf_file_type_glb
Definition: cgltf.h:111
@ cgltf_file_type_gltf
Definition: cgltf.h:110
#define MAX_MATERIAL_MAPS
Definition: config.h:210
#define MAX_MESH_VERTEX_BUFFERS
Definition: config.h:211
#define PI
Definition: easings.h:96
#define GL_TEXTURE_COORD_ARRAY
Definition: gl.h:1279
#define GL_COLOR_ARRAY
Definition: gl.h:284
#define GL_NORMAL_ARRAY
Definition: gl.h:832
#define GL_VERTEX_ARRAY
Definition: glad.h:1916
#define NULL
Definition: miniaudio.h:3718
void par_shapes_merge_and_free(par_shapes_mesh *dst, par_shapes_mesh *src)
par_shapes_mesh * par_shapes_create_parametric_sphere(int slices, int stacks)
par_shapes_mesh * par_shapes_create_cube()
void par_shapes_scale(par_shapes_mesh *, float x, float y, float z)
par_shapes_mesh * par_shapes_create_cone(int slices, int stacks)
void par_shapes_free_mesh(par_shapes_mesh *)
par_shapes_mesh * par_shapes_create_cylinder(int slices, int stacks)
par_shapes_mesh * par_shapes_create_torus(int slices, int stacks, float radius)
par_shapes_mesh * par_shapes_create_plane(int slices, int stacks)
par_shapes_mesh * par_shapes_create_disk(float radius, int slices, float const *center, float const *normal)
par_shapes_mesh * par_shapes_create_trefoil_knot(int slices, int stacks, float radius)
void par_shapes_compute_normals(par_shapes_mesh *m)
void par_shapes_translate(par_shapes_mesh *, float x, float y, float z)
par_shapes_mesh * par_shapes_create_hemisphere(int slices, int stacks)
void par_shapes_rotate(par_shapes_mesh *, float radians, float const *axis)
#define RL_FREE(p)
Definition: raudio.h:67
#define RL_MALLOC(sz)
raudio v1.0 - A simple and easy-to-use audio library based on miniaudio
Definition: raudio.h:61
#define RL_CALLOC(n, sz)
Definition: raudio.h:64
#define TRACELOG(level,...)
Definition: raygui.h:222
@ SHADER_LOC_MATRIX_MODEL
Definition: raylib.h:733
@ SHADER_LOC_COLOR_DIFFUSE
Definition: raylib.h:736
@ SHADER_LOC_MATRIX_MVP
Definition: raylib.h:730
@ SHADER_LOC_VERTEX_COLOR
Definition: raylib.h:729
@ SHADER_LOC_COLOR_SPECULAR
Definition: raylib.h:737
@ SHADER_LOC_VERTEX_TANGENT
Definition: raylib.h:728
@ SHADER_LOC_MATRIX_PROJECTION
Definition: raylib.h:732
@ SHADER_LOC_VERTEX_TEXCOORD01
Definition: raylib.h:725
@ SHADER_LOC_MATRIX_VIEW
Definition: raylib.h:731
@ SHADER_LOC_VERTEX_POSITION
Definition: raylib.h:724
@ SHADER_LOC_VERTEX_TEXCOORD02
Definition: raylib.h:726
@ SHADER_LOC_MATRIX_NORMAL
Definition: raylib.h:734
@ SHADER_LOC_VERTEX_NORMAL
Definition: raylib.h:727
RLAPI const char * TextFormat(const char *text,...)
Definition: rtext.c:1278
@ SHADER_UNIFORM_INT
Definition: raylib.h:761
@ SHADER_UNIFORM_VEC4
Definition: raylib.h:760
RLAPI Color * LoadImageColors(Image image)
Definition: rtextures.c:2080
RLAPI const char * GetWorkingDirectory(void)
Definition: rcore.c:3006
Texture Texture2D
Definition: raylib.h:254
RLAPI Texture2D LoadTexture(const char *fileName)
Definition: rtextures.c:2874
RLAPI void UnloadFileData(unsigned char *data)
Definition: utils.c:231
@ MATERIAL_MAP_NORMAL
Definition: raylib.h:708
@ MATERIAL_MAP_IRRADIANCE
Definition: raylib.h:714
@ MATERIAL_MAP_HEIGHT
Definition: raylib.h:712
@ MATERIAL_MAP_ROUGHNESS
Definition: raylib.h:709
@ MATERIAL_MAP_ALBEDO
Definition: raylib.h:706
@ MATERIAL_MAP_CUBEMAP
Definition: raylib.h:713
@ MATERIAL_MAP_PREFILTER
Definition: raylib.h:715
@ MATERIAL_MAP_METALNESS
Definition: raylib.h:707
@ MATERIAL_MAP_OCCLUSION
Definition: raylib.h:710
@ MATERIAL_MAP_EMISSION
Definition: raylib.h:711
@ LOG_INFO
Definition: raylib.h:514
@ LOG_WARNING
Definition: raylib.h:515
@ LOG_DEBUG
Definition: raylib.h:513
@ PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
Definition: raylib.h:785
RLAPI unsigned char * LoadFileData(const char *fileName, unsigned int *bytesRead)
Definition: utils.c:182
RLAPI void UnloadShader(Shader shader)
Definition: rcore.c:2464
#define BLACK
Definition: raylib.h:171
RLAPI void TraceLog(int logLevel, const char *text,...)
Definition: utils.c:107
RLAPI void UnloadImageColors(Color *colors)
Definition: rtextures.c:2253
#define WHITE
Definition: raylib.h:170
RLAPI Image LoadImage(const char *fileName)
Definition: rtextures.c:207
@ SHADER_ATTRIB_VEC2
Definition: raylib.h:771
@ SHADER_ATTRIB_VEC3
Definition: raylib.h:772
@ SHADER_ATTRIB_VEC4
Definition: raylib.h:773
RLAPI bool SaveFileText(const char *fileName, char *text)
Definition: utils.c:376
#define MATERIAL_MAP_SPECULAR
Definition: raylib.h:720
RLAPI void UnloadImage(Image image)
Definition: rtextures.c:457
RLAPI const char * GetDirectoryPath(const char *filePath)
Definition: rcore.c:2936
RLAPI void UnloadFileText(char *text)
Definition: utils.c:370
RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize)
Definition: rtextures.c:305
#define MATERIAL_MAP_DIFFUSE
Definition: raylib.h:719
RLAPI Texture2D LoadTextureFromImage(Image image)
Definition: rtextures.c:2891
RLAPI bool IsFileExtension(const char *fileName, const char *ext)
Definition: rcore.c:2818
RLAPI char * LoadFileText(const char *fileName)
Definition: utils.c:318
#define DEG2RAD
Definition: raylib.h:106
#define SHADER_LOC_MAP_DIFFUSE
Definition: raylib.h:752
RMAPI Vector3 Vector3Normalize(Vector3 v)
Definition: raymath.h:670
RMAPI Vector3 Vector3Transform(Vector3 v, Matrix mat)
Definition: raymath.h:721
RMAPI Vector3 Vector3RotateByQuaternion(Vector3 v, Quaternion q)
Definition: raymath.h:737
#define MatrixToFloat(mat)
Definition: raymath.h:94
RMAPI Vector2 Vector2Zero(void)
Definition: raymath.h:214
RMAPI Matrix MatrixRotate(Vector3 axis, float angle)
Definition: raymath.h:1213
RMAPI Quaternion QuaternionNormalize(Quaternion q)
Definition: raymath.h:1611
RMAPI Quaternion QuaternionInvert(Quaternion q)
Definition: raymath.h:1628
RMAPI Vector3 Vector3Min(Vector3 v1, Vector3 v2)
Definition: raymath.h:779
RMAPI Vector3 Vector3Perpendicular(Vector3 v)
Definition: raymath.h:562
RMAPI float Vector3DotProduct(Vector3 v1, Vector3 v2)
Definition: raymath.h:607
RMAPI Matrix MatrixScale(float x, float y, float z)
Definition: raymath.h:1380
RMAPI Vector3 Vector3Add(Vector3 v1, Vector3 v2)
Definition: raymath.h:506
RMAPI Matrix MatrixIdentity(void)
Definition: raymath.h:1114
RMAPI Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)
Definition: raymath.h:522
RMAPI Matrix MatrixTranslate(float x, float y, float z)
Definition: raymath.h:1201
RMAPI Vector3 Vector3Multiply(Vector3 v1, Vector3 v2)
Definition: raymath.h:546
RMAPI float16 MatrixToFloatV(Matrix mat)
Definition: raymath.h:1534
RMAPI Vector3 Vector3Negate(Vector3 v)
Definition: raymath.h:654
RMAPI Vector3 Vector3Divide(Vector3 v1, Vector3 v2)
Definition: raymath.h:662
RMAPI Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount)
Definition: raymath.h:749
RMAPI Matrix MatrixInvert(Matrix mat)
Definition: raymath.h:1067
RMAPI void Vector3OrthoNormalize(Vector3 *v1, Vector3 *v2)
Definition: raymath.h:688
RMAPI float Vector3Length(const Vector3 v)
Definition: raymath.h:591
RMAPI Vector3 Vector3CrossProduct(Vector3 v1, Vector3 v2)
Definition: raymath.h:554
RMAPI Vector3 Vector3Max(Vector3 v1, Vector3 v2)
Definition: raymath.h:791
RMAPI Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2)
Definition: raymath.h:1648
RMAPI Vector3 Vector3Scale(Vector3 v, float scalar)
Definition: raymath.h:538
RMAPI Matrix MatrixTranspose(Matrix mat)
Definition: raymath.h:1042
RMAPI Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up)
Definition: raymath.h:1479
RMAPI Matrix MatrixMultiply(Matrix left, Matrix right)
Definition: raymath.h:1176
RLAPI int * rlGetShaderLocsDefault(void)
RLAPI void rlNormal3f(float x, float y, float z)
RLAPI Matrix rlGetMatrixProjection(void)
RLAPI void rlDisableTextureCubemap(void)
RLAPI void rlDisableVertexBuffer(void)
RLAPI void rlSetUniform(int locIndex, const void *value, int uniformType, int count)
#define RL_QUADS
Definition: rlgl.h:260
RLAPI void rlEnd(void)
RLAPI int rlGetFramebufferHeight(void)
RLAPI void rlDrawVertexArray(int offset, int count)
RLAPI bool rlIsStereoRenderEnabled(void)
RLAPI void rlEnableTexture(unsigned int id)
RLAPI unsigned int rlLoadVertexArray(void)
RLAPI void rlColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
RLAPI void rlEnableTextureCubemap(unsigned int id)
RLAPI Matrix rlGetMatrixModelview(void)
RLAPI unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic)
RLAPI void rlDrawVertexArrayElementsInstanced(int offset, int count, const void *buffer, int instances)
#define RL_TRIANGLES
Definition: rlgl.h:259
RLAPI void rlSetVertexAttributeDivisor(unsigned int index, int divisor)
RLAPI void rlDisableTexture(void)
RLAPI unsigned int rlGetShaderIdDefault(void)
RLAPI void rlVertex3f(float x, float y, float z)
RLAPI void rlDisableVertexArray(void)
RLAPI void rlDisableVertexAttribute(unsigned int index)
RLAPI void rlSetUniformMatrix(int locIndex, Matrix mat)
RLAPI void rlSetVertexAttribute(unsigned int index, int compSize, int type, bool normalized, int stride, const void *pointer)
RLAPI void rlPushMatrix(void)
RLAPI void rlUpdateVertexBuffer(unsigned int bufferId, const void *data, int dataSize, int offset)
RLAPI unsigned int rlLoadVertexBufferElement(const void *buffer, int size, bool dynamic)
RLAPI unsigned int rlGetTextureIdDefault(void)
RLAPI void rlSetMatrixModelview(Matrix view)
RLAPI void rlViewport(int x, int y, int width, int height)
RLAPI bool rlEnableVertexArray(unsigned int vaoId)
RLAPI Matrix rlGetMatrixViewOffsetStereo(int eye)
RLAPI void rlScalef(float x, float y, float z)
RLAPI Matrix rlGetMatrixTransform(void)
RLAPI void rlDisableWireMode(void)
RLAPI void rlActiveTextureSlot(int slot)
RLAPI void rlEnableShader(unsigned int id)
RLAPI int rlGetFramebufferWidth(void)
RLAPI void rlMultMatrixf(float *matf)
RLAPI void rlBegin(int mode)
RLAPI void rlDisableVertexBufferElement(void)
RLAPI void rlTexCoord2f(float x, float y)
RLAPI void rlDrawVertexArrayInstanced(int offset, int count, int instances)
#define RL_UNSIGNED_BYTE
Definition: rlgl.h:263
RLAPI void rlEnableVertexAttribute(unsigned int index)
RLAPI void rlSetVertexAttributeDefault(int locIndex, const void *value, int attribType, int count)
RLAPI void rlColor3f(float x, float y, float z)
RLAPI void rlUnloadVertexArray(unsigned int vaoId)
RLAPI void rlEnableWireMode(void)
RLAPI void rlRotatef(float angle, float x, float y, float z)
RLAPI void rlEnableVertexBuffer(unsigned int id)
RLAPI void rlDisableShader(void)
RLAPI void rlUnloadTexture(unsigned int id)
RLAPI void rlSetMatrixProjection(Matrix proj)
RLAPI void rlPopMatrix(void)
RLAPI void rlSetTexture(unsigned int id)
RLAPI void rlEnableVertexBufferElement(unsigned int id)
RLAPI void rlDrawVertexArrayElements(int offset, int count, const void *buffer)
RLAPI bool rlCheckRenderBatchLimit(int vCount)
#define RL_FLOAT
Definition: rlgl.h:264
#define RL_LINES
Definition: rlgl.h:258
RLAPI void rlTranslatef(float x, float y, float z)
RLAPI Matrix rlGetMatrixProjectionStereo(int eye)
RLAPI void rlUnloadVertexBuffer(unsigned int vboId)
#define EPSILON
Mesh GenMeshSphere(float radius, int rings, int slices)
Definition: rmodels.c:2335
#define MESH_NAME_LENGTH
#define IQM_MAGIC
void UnloadModel(Model model)
Definition: rmodels.c:992
void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint)
Definition: rmodels.c:3327
bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2)
Definition: rmodels.c:3465
BoundingBox GetModelBoundingBox(Model model)
Definition: rmodels.c:1037
void UnloadModelKeepMeshes(Model model)
Definition: rmodels.c:1016
void DrawCubeWires(Vector3 position, float width, float height, float length, Color color)
Definition: rmodels.c:325
void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color)
Definition: rmodels.c:703
void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
Definition: rmodels.c:762
void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, int instances)
Definition: rmodels.c:1407
void UnloadMesh(Mesh mesh)
Definition: rmodels.c:1622
#define GRAY_VALUE(c)
void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color)
Definition: rmodels.c:201
void DrawRay(Ray ray, Color color)
Definition: rmodels.c:866
Mesh GenMeshPoly(int sides, float radius)
Definition: rmodels.c:1968
ModelAnimation * LoadModelAnimations(const char *fileName, unsigned int *animCount)
Definition: rmodels.c:1817
void GenMeshTangents(Mesh *mesh)
Definition: rmodels.c:3147
void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color)
Definition: rmodels.c:796
RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3)
Definition: rmodels.c:3646
void DrawMesh(Mesh mesh, Material material, Matrix transform)
Definition: rmodels.c:1183
void DrawPlane(Vector3 centerPos, Vector2 size, Color color)
Definition: rmodels.c:844
void SetModelMeshMaterial(Model *model, int meshId, int materialId)
Definition: rmodels.c:1809
void UnloadModelAnimations(ModelAnimation *animations, unsigned int count)
Definition: rmodels.c:1933
void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color)
Definition: rmodels.c:180
bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2)
Definition: rmodels.c:3441
Model LoadModelFromMesh(Mesh mesh)
Definition: rmodels.c:969
BoundingBox GetMeshBoundingBox(Mesh mesh)
Definition: rmodels.c:3118
#define COLOR_EQUAL(col1, col2)
Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
Definition: rmodels.c:2766
Mesh GenMeshKnot(float radius, float size, int radSeg, int sides)
Definition: rmodels.c:2586
void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint)
Definition: rmodels.c:3335
RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform)
Definition: rmodels.c:3598
bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius)
Definition: rmodels.c:3480
bool IsModelAnimationValid(Model model, ModelAnimation anim)
Definition: rmodels.c:1950
Mesh GenMeshPlane(float width, float length, int resX, int resZ)
Definition: rmodels.c:2037
RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius)
Definition: rmodels.c:3501
void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
Definition: rmodels.c:1833
void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color)
Definition: rmodels.c:150
Mesh GenMeshTorus(float radius, float size, int radSeg, int sides)
Definition: rmodels.c:2540
Mesh GenMeshCylinder(float radius, float height, int slices)
Definition: rmodels.c:2421
void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float size, Color tint)
Definition: rmodels.c:3319
void DrawCubeWiresV(Vector3 position, Vector3 size, Color color)
Definition: rmodels.c:395
void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
Definition: rmodels.c:3269
Mesh GenMeshHemiSphere(float radius, int rings, int slices)
Definition: rmodels.c:2377
void DrawCube(Vector3 position, float width, float height, float length, Color color)
Definition: rmodels.c:244
Model LoadModel(const char *fileName)
Definition: rmodels.c:914
void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float length, Color color)
Definition: rmodels.c:402
Mesh GenMeshCone(float radius, float height, int slices)
Definition: rmodels.c:2485
void DrawBoundingBox(BoundingBox box, Color color)
Definition: rmodels.c:3427
void DrawModelWires(Model model, Vector3 position, float scale, Color tint)
Definition: rmodels.c:3299
Mesh GenMeshCube(float width, float height, float length)
Definition: rmodels.c:2170
void UploadMesh(Mesh *mesh, bool dynamic)
Definition: rmodels.c:1066
void UnloadModelAnimation(ModelAnimation anim)
Definition: rmodels.c:1940
#define IQM_VERSION
#define CHDIR
Definition: rmodels.c:104
#define PAR_MALLOC(T, N)
Definition: rmodels.c:90
Material LoadMaterialDefault(void)
Definition: rmodels.c:1763
#define BONE_NAME_LENGTH
void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color)
Definition: rmodels.c:556
void DrawSphere(Vector3 centerPos, float radius, Color color)
Definition: rmodels.c:550
Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
Definition: rmodels.c:2631
RayCollision GetRayCollisionBox(Ray ray, BoundingBox box)
Definition: rmodels.c:3538
void UnloadMaterial(Material material)
Definition: rmodels.c:1784
Material * LoadMaterials(const char *fileName, int *materialCount)
Definition: rmodels.c:1725
void DrawPoint3D(Vector3 position, Color color)
Definition: rmodels.c:165
void UpdateMeshBuffer(Mesh mesh, int index, const void *data, int dataSize, int offset)
Definition: rmodels.c:1177
RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4)
Definition: rmodels.c:3705
void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color)
Definition: rmodels.c:599
void DrawTriangleStrip3D(Vector3 *points, int pointCount, Color color)
Definition: rmodels.c:214
bool ExportMesh(Mesh mesh, const char *fileName)
Definition: rmodels.c:1645
void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
Definition: rmodels.c:3309
void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
Definition: rmodels.c:644
void DrawCubeV(Vector3 position, Vector3 size, Color color)
Definition: rmodels.c:319
#define MATERIAL_NAME_LENGTH
void DrawGrid(int slices, float spacing)
Definition: rmodels.c:880
void SetMaterialTexture(Material *material, int mapType, Texture2D texture)
Definition: rmodels.c:1803
#define LOAD_ATTRIBUTE(accesor, numComp, dataType, dstPtr)
void DrawCubeTextureRec(Texture2D texture, Rectangle source, Vector3 position, float width, float height, float length, Color color)
Definition: rmodels.c:463
void GenMeshBinormals(Mesh *mesh)
Definition: rmodels.c:3247
void DrawModel(Model model, Vector3 position, float scale, Color tint)
Definition: rmodels.c:3260
VoxColor * array
Definition: vox_loader.h:88
unsigned short * array
Definition: vox_loader.h:93
VoxVector3 * array
Definition: vox_loader.h:83
int parent
Definition: raylib.h:372
char name[32]
Definition: raylib.h:371
Vector3 max
Definition: raylib.h:416
Vector3 min
Definition: raylib.h:415
Vector3 up
Definition: raylib.h:302
Vector3 position
Definition: raylib.h:300
Vector3 target
Definition: raylib.h:301
Definition: raylib.h:220
unsigned char a
Definition: raylib.h:224
unsigned char b
Definition: raylib.h:223
unsigned char r
Definition: raylib.h:221
unsigned char g
Definition: raylib.h:222
Definition: raylib.h:236
void * data
Definition: raylib.h:237
int height
Definition: raylib.h:239
int width
Definition: raylib.h:238
Shader shader
Definition: raylib.h:357
MaterialMap * maps
Definition: raylib.h:358
Color color
Definition: raylib.h:351
float value
Definition: raylib.h:352
Texture2D texture
Definition: raylib.h:350
Definition: raylib.h:212
float m0
Definition: raylib.h:213
float m4
Definition: raylib.h:213
float m8
Definition: raylib.h:213
Definition: raylib.h:318
unsigned char * boneIds
Definition: raylib.h:334
unsigned int * vboId
Definition: raylib.h:339
int vertexCount
Definition: raylib.h:319
float * boneWeights
Definition: raylib.h:335
float * texcoords2
Definition: raylib.h:325
float * tangents
Definition: raylib.h:327
unsigned int vaoId
Definition: raylib.h:338
float * vertices
Definition: raylib.h:323
unsigned short * indices
Definition: raylib.h:329
float * animVertices
Definition: raylib.h:332
float * animNormals
Definition: raylib.h:333
float * normals
Definition: raylib.h:326
int triangleCount
Definition: raylib.h:320
float * texcoords
Definition: raylib.h:324
unsigned char * colors
Definition: raylib.h:328
int frameCount
Definition: raylib.h:394
Transform ** framePoses
Definition: raylib.h:396
int boneCount
Definition: raylib.h:393
BoneInfo * bones
Definition: raylib.h:395
Definition: raylib.h:376
Material * materials
Definition: raylib.h:382
int * meshMaterial
Definition: raylib.h:383
int meshCount
Definition: raylib.h:379
Mesh * meshes
Definition: raylib.h:381
int materialCount
Definition: raylib.h:380
Matrix transform
Definition: raylib.h:377
int boneCount
Definition: raylib.h:386
BoneInfo * bones
Definition: raylib.h:387
Transform * bindPose
Definition: raylib.h:388
float distance
Definition: raylib.h:408
Vector3 normal
Definition: raylib.h:410
Vector3 point
Definition: raylib.h:409
bool hit
Definition: raylib.h:407
Definition: raylib.h:400
Vector3 position
Definition: raylib.h:401
Vector3 direction
Definition: raylib.h:402
float height
Definition: raylib.h:232
float x
Definition: raylib.h:229
float y
Definition: raylib.h:230
float width
Definition: raylib.h:231
int * locs
Definition: raylib.h:345
unsigned int id
Definition: raylib.h:344
int width
Definition: raylib.h:247
int height
Definition: raylib.h:248
unsigned int id
Definition: raylib.h:246
Quaternion rotation
Definition: raylib.h:365
Vector3 scale
Definition: raylib.h:366
Vector3 translation
Definition: raylib.h:364
float x
Definition: physac.h:130
float y
Definition: physac.h:131
float x
Definition: raylib.h:195
float y
Definition: raylib.h:196
float z
Definition: raylib.h:197
float x
Definition: raylib.h:202
float y
Definition: raylib.h:203
float w
Definition: raylib.h:205
float z
Definition: raylib.h:204
ArrayVector3 vertices
Definition: vox_loader.h:125
ArrayUShort indices
Definition: vox_loader.h:126
ArrayColor colors
Definition: vox_loader.h:127
cgltf_size count
Definition: cgltf.h:332
cgltf_type type
Definition: cgltf.h:330
cgltf_component_type component_type
Definition: cgltf.h:328
cgltf_attribute_type type
Definition: cgltf.h:349
cgltf_accessor * data
Definition: cgltf.h:351
cgltf_size size
Definition: cgltf.h:295
cgltf_buffer * buffer
Definition: cgltf.h:293
cgltf_size stride
Definition: cgltf.h:296
cgltf_size offset
Definition: cgltf.h:294
void * data
Definition: cgltf.h:258
cgltf_mesh * meshes
Definition: cgltf.h:696
cgltf_size buffers_count
Definition: cgltf.h:709
cgltf_size images_count
Definition: cgltf.h:712
cgltf_material * materials
Definition: cgltf.h:699
cgltf_size textures_count
Definition: cgltf.h:715
cgltf_file_type file_type
Definition: cgltf.h:691
cgltf_size meshes_count
Definition: cgltf.h:697
cgltf_size materials_count
Definition: cgltf.h:700
char * uri
Definition: cgltf.h:357
char * mime_type
Definition: cgltf.h:359
cgltf_buffer_view * buffer_view
Definition: cgltf.h:358
cgltf_pbr_metallic_roughness pbr_metallic_roughness
Definition: cgltf.h:488
cgltf_float emissive_factor[3]
Definition: cgltf.h:499
cgltf_bool has_pbr_metallic_roughness
Definition: cgltf.h:480
cgltf_texture_view emissive_texture
Definition: cgltf.h:498
cgltf_texture_view occlusion_texture
Definition: cgltf.h:497
cgltf_texture_view normal_texture
Definition: cgltf.h:496
cgltf_primitive * primitives
Definition: cgltf.h:546
cgltf_size primitives_count
Definition: cgltf.h:547
cgltf_float metallic_factor
Definition: cgltf.h:416
cgltf_texture_view metallic_roughness_texture
Definition: cgltf.h:413
cgltf_texture_view base_color_texture
Definition: cgltf.h:412
cgltf_float roughness_factor
Definition: cgltf.h:417
cgltf_float base_color_factor[4]
Definition: cgltf.h:415
cgltf_size attributes_count
Definition: cgltf.h:532
cgltf_accessor * indices
Definition: cgltf.h:529
cgltf_attribute * attributes
Definition: cgltf.h:531
cgltf_primitive_type type
Definition: cgltf.h:528
cgltf_material * material
Definition: cgltf.h:530
cgltf_texture * texture
Definition: cgltf.h:400
cgltf_image * image
Definition: cgltf.h:380
PAR_SHAPES_T * triangles
Definition: par_shapes.h:56
unsigned int num_faces
tinyobj_vertex_index_t * faces
unsigned int num_texcoords
unsigned int num_normals
int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, unsigned int *num_shapes, tinyobj_material_t **materials, unsigned int *num_materials, const char *buf, unsigned int len, unsigned int flags)
int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out, unsigned int *num_materials_out, const char *filename)
void tinyobj_attrib_free(tinyobj_attrib_t *attrib)
#define TINYOBJ_SUCCESS
#define TINYOBJ_FLAG_TRIANGULATE
void tinyobj_shapes_free(tinyobj_shape_t *shapes, unsigned int num_shapes)
void tinyobj_materials_free(tinyobj_material_t *materials, unsigned int num_materials)
#define VOX_SUCCESS
Definition: vox_loader.h:67
int Vox_LoadFromMemory(unsigned char *pvoxData, unsigned int voxDataSize, VoxArray3D *pvoxarray)
void Vox_FreeArrays(VoxArray3D *voxarray)