1 /**********************************************************************************************
3 * raylib.models - Basic functions to deal with 3d shapes and 3d models
7 * #define SUPPORT_FILEFORMAT_OBJ
8 * #define SUPPORT_FILEFORMAT_MTL
9 * #define SUPPORT_FILEFORMAT_IQM
10 * #define SUPPORT_FILEFORMAT_GLTF
11 * Selected desired fileformats to be supported for model data loading.
13 * #define SUPPORT_MESH_GENERATION
14 * Support procedural mesh generation functions, uses external par_shapes.h library
15 * NOTE: Some generated meshes DO NOT include generated texture coordinates
18 * LICENSE: zlib/libpng
20 * Copyright (c) 2013-2021 Ramon Santamaria (@raysan5)
22 * This software is provided "as-is", without any express or implied warranty. In no event
23 * will the authors be held liable for any damages arising from the use of this software.
25 * Permission is granted to anyone to use this software for any purpose, including commercial
26 * applications, and to alter it and redistribute it freely, subject to the following restrictions:
28 * 1. The origin of this software must not be misrepresented; you must not claim that you
29 * wrote the original software. If you use this software in a product, an acknowledgment
30 * in the product documentation would be appreciated but is not required.
32 * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
33 * as being the original software.
35 * 3. This notice may not be removed or altered from any source distribution.
37 **********************************************************************************************/
39 #include "raylib.h" // Declares module functions
41 // Check if config flags have been externally provided on compilation line
42 #if !defined(EXTERNAL_CONFIG_FLAGS)
43 #include "config.h" // Defines module configuration flags
46 #include "utils.h" // Required for: LoadFileData(), LoadFileText(), SaveFileText()
48 #include <stdio.h> // Required for: sprintf()
49 #include <stdlib.h> // Required for: malloc(), free()
50 #include <string.h> // Required for: memcmp(), strlen()
51 #include <math.h> // Required for: sinf(), cosf(), sqrtf(), fabsf()
54 #include <direct.h> // Required for: _chdir() [Used in LoadOBJ()]
57 #include <unistd.h> // Required for: chdir() (POSIX) [Used in LoadOBJ()]
61 #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
63 #if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL)
64 #define TINYOBJ_MALLOC RL_MALLOC
65 #define TINYOBJ_CALLOC RL_CALLOC
66 #define TINYOBJ_REALLOC RL_REALLOC
67 #define TINYOBJ_FREE RL_FREE
69 #define TINYOBJ_LOADER_C_IMPLEMENTATION
70 #include "external/tinyobj_loader_c.h" // OBJ/MTL file formats loading
73 #if defined(SUPPORT_FILEFORMAT_GLTF)
74 #define CGLTF_MALLOC RL_MALLOC
75 #define CGLTF_FREE RL_FREE
77 #define CGLTF_IMPLEMENTATION
78 #include "external/cgltf.h" // glTF file format loading
79 #include "external/stb_image.h" // glTF texture images loading
82 #if defined(SUPPORT_MESH_GENERATION)
83 #define PAR_MALLOC(T, N) ((T*)RL_MALLOC(N*sizeof(T)))
84 #define PAR_CALLOC(T, N) ((T*)RL_CALLOC(N*sizeof(T), 1))
85 #define PAR_REALLOC(T, BUF, N) ((T*)RL_REALLOC(BUF, sizeof(T)*(N)))
86 #define PAR_FREE RL_FREE
88 #define PAR_SHAPES_IMPLEMENTATION
89 #include "external/par_shapes.h" // Shapes 3d parametric generation
92 //----------------------------------------------------------------------------------
94 //----------------------------------------------------------------------------------
97 //----------------------------------------------------------------------------------
98 // Types and Structures Definition
99 //----------------------------------------------------------------------------------
102 //----------------------------------------------------------------------------------
103 // Global Variables Definition
104 //----------------------------------------------------------------------------------
107 //----------------------------------------------------------------------------------
108 // Module specific Functions Declaration
109 //----------------------------------------------------------------------------------
110 #if defined(SUPPORT_FILEFORMAT_OBJ)
111 static Model LoadOBJ(const char *fileName); // Load OBJ mesh data
113 #if defined(SUPPORT_FILEFORMAT_IQM)
114 static Model LoadIQM(const char *fileName); // Load IQM mesh data
115 static ModelAnimation *LoadIQMModelAnimations(const char *fileName, int *animCount); // Load IQM animation data
117 #if defined(SUPPORT_FILEFORMAT_GLTF)
118 static Model LoadGLTF(const char *fileName); // Load GLTF mesh data
119 static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCount); // Load GLTF animation data
120 static void LoadGLTFModelIndices(Model* model, cgltf_accessor* indexAccessor, int primitiveIndex);
121 static void BindGLTFPrimitiveToBones(Model* model, const cgltf_data* data, int primitiveIndex);
122 static void LoadGLTFBoneAttribute(Model* model, cgltf_accessor* jointsAccessor, const cgltf_data* data, int primitiveIndex);
123 static void LoadGLTFMaterial(Model* model, const char* fileName, const cgltf_data* data);
124 static void InitGLTFBones(Model* model, const cgltf_data* data);
127 //----------------------------------------------------------------------------------
128 // Module Functions Definition
129 //----------------------------------------------------------------------------------
131 // Draw a line in 3D world space
132 void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color)
134 // WARNING: Be careful with internal buffer vertex alignment
135 // when using RL_LINES or RL_TRIANGLES, data is aligned to fit
136 // lines-triangles-quads in the same indexed buffers!!!
137 rlCheckRenderBatchLimit(8);
140 rlColor4ub(color.r, color.g, color.b, color.a);
141 rlVertex3f(startPos.x, startPos.y, startPos.z);
142 rlVertex3f(endPos.x, endPos.y, endPos.z);
146 // Draw a point in 3D space, actually a small line
147 void DrawPoint3D(Vector3 position, Color color)
149 rlCheckRenderBatchLimit(8);
152 rlTranslatef(position.x, position.y, position.z);
154 rlColor4ub(color.r, color.g, color.b, color.a);
155 rlVertex3f(0.0f, 0.0f, 0.0f);
156 rlVertex3f(0.0f, 0.0f, 0.1f);
161 // Draw a circle in 3D world space
162 void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color)
164 rlCheckRenderBatchLimit(2*36);
167 rlTranslatef(center.x, center.y, center.z);
168 rlRotatef(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
171 for (int i = 0; i < 360; i += 10)
173 rlColor4ub(color.r, color.g, color.b, color.a);
175 rlVertex3f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius, 0.0f);
176 rlVertex3f(sinf(DEG2RAD*(i + 10))*radius, cosf(DEG2RAD*(i + 10))*radius, 0.0f);
182 // Draw a color-filled triangle (vertex in counter-clockwise order!)
183 void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color)
185 rlCheckRenderBatchLimit(3);
187 rlBegin(RL_TRIANGLES);
188 rlColor4ub(color.r, color.g, color.b, color.a);
189 rlVertex3f(v1.x, v1.y, v1.z);
190 rlVertex3f(v2.x, v2.y, v2.z);
191 rlVertex3f(v3.x, v3.y, v3.z);
195 // Draw a triangle strip defined by points
196 void DrawTriangleStrip3D(Vector3 *points, int pointsCount, Color color)
198 if (pointsCount >= 3)
200 rlCheckRenderBatchLimit(3*(pointsCount - 2));
202 rlBegin(RL_TRIANGLES);
203 rlColor4ub(color.r, color.g, color.b, color.a);
205 for (int i = 2; i < pointsCount; i++)
209 rlVertex3f(points[i].x, points[i].y, points[i].z);
210 rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z);
211 rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z);
215 rlVertex3f(points[i].x, points[i].y, points[i].z);
216 rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z);
217 rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z);
225 // NOTE: Cube position is the center position
226 void DrawCube(Vector3 position, float width, float height, float length, Color color)
232 rlCheckRenderBatchLimit(36);
235 // NOTE: Transformation is applied in inverse order (scale -> rotate -> translate)
236 rlTranslatef(position.x, position.y, position.z);
237 //rlRotatef(45, 0, 1, 0);
238 //rlScalef(1.0f, 1.0f, 1.0f); // NOTE: Vertices are directly scaled on definition
240 rlBegin(RL_TRIANGLES);
241 rlColor4ub(color.r, color.g, color.b, color.a);
244 rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left
245 rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right
246 rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left
248 rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Right
249 rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left
250 rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right
253 rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Left
254 rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left
255 rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right
257 rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right
258 rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right
259 rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left
262 rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left
263 rlVertex3f(x - width/2, y + height/2, z + length/2); // Bottom Left
264 rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right
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
271 rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left
272 rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right
273 rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left
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
280 rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right
281 rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right
282 rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left
284 rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Left
285 rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right
286 rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left
289 rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right
290 rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left
291 rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Right
293 rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left
294 rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left
295 rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right
300 // Draw cube (Vector version)
301 void DrawCubeV(Vector3 position, Vector3 size, Color color)
303 DrawCube(position, size.x, size.y, size.z, color);
307 void DrawCubeWires(Vector3 position, float width, float height, float length, Color color)
313 rlCheckRenderBatchLimit(36);
316 rlTranslatef(position.x, position.y, position.z);
319 rlColor4ub(color.r, color.g, color.b, color.a);
321 // Front Face -----------------------------------------------------
323 rlVertex3f(x-width/2, y-height/2, z+length/2); // Bottom Left
324 rlVertex3f(x+width/2, y-height/2, z+length/2); // Bottom Right
327 rlVertex3f(x+width/2, y-height/2, z+length/2); // Bottom Right
328 rlVertex3f(x+width/2, y+height/2, z+length/2); // Top Right
331 rlVertex3f(x+width/2, y+height/2, z+length/2); // Top Right
332 rlVertex3f(x-width/2, y+height/2, z+length/2); // Top Left
335 rlVertex3f(x-width/2, y+height/2, z+length/2); // Top Left
336 rlVertex3f(x-width/2, y-height/2, z+length/2); // Bottom Left
338 // Back Face ------------------------------------------------------
340 rlVertex3f(x-width/2, y-height/2, z-length/2); // Bottom Left
341 rlVertex3f(x+width/2, y-height/2, z-length/2); // Bottom Right
344 rlVertex3f(x+width/2, y-height/2, z-length/2); // Bottom Right
345 rlVertex3f(x+width/2, y+height/2, z-length/2); // Top Right
348 rlVertex3f(x+width/2, y+height/2, z-length/2); // Top Right
349 rlVertex3f(x-width/2, y+height/2, z-length/2); // Top Left
352 rlVertex3f(x-width/2, y+height/2, z-length/2); // Top Left
353 rlVertex3f(x-width/2, y-height/2, z-length/2); // Bottom Left
355 // Top Face -------------------------------------------------------
357 rlVertex3f(x-width/2, y+height/2, z+length/2); // Top Left Front
358 rlVertex3f(x-width/2, y+height/2, z-length/2); // Top Left Back
361 rlVertex3f(x+width/2, y+height/2, z+length/2); // Top Right Front
362 rlVertex3f(x+width/2, y+height/2, z-length/2); // Top Right Back
364 // Bottom Face ---------------------------------------------------
366 rlVertex3f(x-width/2, y-height/2, z+length/2); // Top Left Front
367 rlVertex3f(x-width/2, y-height/2, z-length/2); // Top Left Back
370 rlVertex3f(x+width/2, y-height/2, z+length/2); // Top Right Front
371 rlVertex3f(x+width/2, y-height/2, z-length/2); // Top Right Back
376 // Draw cube wires (vector version)
377 void DrawCubeWiresV(Vector3 position, Vector3 size, Color color)
379 DrawCubeWires(position, size.x, size.y, size.z, color);
383 // NOTE: Cube position is the center position
384 void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float length, Color color)
386 float x = position.x;
387 float y = position.y;
388 float z = position.z;
390 rlCheckRenderBatchLimit(36);
392 rlSetTexture(texture.id);
395 // NOTE: Transformation is applied in inverse order (scale -> rotate -> translate)
396 //rlTranslatef(2.0f, 0.0f, 0.0f);
397 //rlRotatef(45, 0, 1, 0);
398 //rlScalef(2.0f, 2.0f, 2.0f);
401 rlColor4ub(color.r, color.g, color.b, color.a);
403 rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer
404 rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left Of The Texture and Quad
405 rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right Of The Texture and Quad
406 rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Right Of The Texture and Quad
407 rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left Of The Texture and Quad
409 rlNormal3f(0.0f, 0.0f, - 1.0f); // Normal Pointing Away From Viewer
410 rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right Of The Texture and Quad
411 rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Right Of The Texture and Quad
412 rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Left Of The Texture and Quad
413 rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Left Of The Texture and Quad
415 rlNormal3f(0.0f, 1.0f, 0.0f); // Normal Pointing Up
416 rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left Of The Texture and Quad
417 rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - width/2, y + height/2, z + length/2); // Bottom Left Of The Texture and Quad
418 rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right Of The Texture and Quad
419 rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right Of The Texture and Quad
421 rlNormal3f(0.0f, - 1.0f, 0.0f); // Normal Pointing Down
422 rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Right Of The Texture and Quad
423 rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + width/2, y - height/2, z - length/2); // Top Left Of The Texture and Quad
424 rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Left Of The Texture and Quad
425 rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Right Of The Texture and Quad
427 rlNormal3f(1.0f, 0.0f, 0.0f); // Normal Pointing Right
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
433 rlNormal3f( - 1.0f, 0.0f, 0.0f); // Normal Pointing Left
434 rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Left Of The Texture and Quad
435 rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Right Of The Texture and Quad
436 rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Right Of The Texture and Quad
437 rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left Of The Texture and Quad
445 void DrawSphere(Vector3 centerPos, float radius, Color color)
447 DrawSphereEx(centerPos, radius, 16, 16, color);
450 // Draw sphere with extended parameters
451 void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color)
453 int numVertex = (rings + 2)*slices*6;
454 rlCheckRenderBatchLimit(numVertex);
457 // NOTE: Transformation is applied in inverse order (scale -> translate)
458 rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
459 rlScalef(radius, radius, radius);
461 rlBegin(RL_TRIANGLES);
462 rlColor4ub(color.r, color.g, color.b, color.a);
464 for (int i = 0; i < (rings + 2); i++)
466 for (int j = 0; j < slices; j++)
468 rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)),
469 sinf(DEG2RAD*(270+(180/(rings + 1))*i)),
470 cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices)));
471 rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)),
472 sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))),
473 cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices)));
474 rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)),
475 sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))),
476 cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices)));
478 rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)),
479 sinf(DEG2RAD*(270+(180/(rings + 1))*i)),
480 cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices)));
481 rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*sinf(DEG2RAD*((j+1)*360/slices)),
482 sinf(DEG2RAD*(270+(180/(rings + 1))*(i))),
483 cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*cosf(DEG2RAD*((j+1)*360/slices)));
484 rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)),
485 sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))),
486 cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices)));
494 void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color)
496 int numVertex = (rings + 2)*slices*6;
497 rlCheckRenderBatchLimit(numVertex);
500 // NOTE: Transformation is applied in inverse order (scale -> translate)
501 rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
502 rlScalef(radius, radius, radius);
505 rlColor4ub(color.r, color.g, color.b, color.a);
507 for (int i = 0; i < (rings + 2); i++)
509 for (int j = 0; j < slices; j++)
511 rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)),
512 sinf(DEG2RAD*(270+(180/(rings + 1))*i)),
513 cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices)));
514 rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)),
515 sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))),
516 cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices)));
518 rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)),
519 sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))),
520 cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices)));
521 rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)),
522 sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))),
523 cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices)));
525 rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)),
526 sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))),
527 cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices)));
528 rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)),
529 sinf(DEG2RAD*(270+(180/(rings + 1))*i)),
530 cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices)));
538 // NOTE: It could be also used for pyramid and cone
539 void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
541 if (sides < 3) sides = 3;
543 int numVertex = sides*6;
544 rlCheckRenderBatchLimit(numVertex);
547 rlTranslatef(position.x, position.y, position.z);
549 rlBegin(RL_TRIANGLES);
550 rlColor4ub(color.r, color.g, color.b, color.a);
554 // Draw Body -------------------------------------------------------------------------------------
555 for (int i = 0; i < 360; i += 360/sides)
557 rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); //Bottom Left
558 rlVertex3f(sinf(DEG2RAD*(i + 360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360/sides))*radiusBottom); //Bottom Right
559 rlVertex3f(sinf(DEG2RAD*(i + 360/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360/sides))*radiusTop); //Top Right
561 rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); //Top Left
562 rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); //Bottom Left
563 rlVertex3f(sinf(DEG2RAD*(i + 360/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360/sides))*radiusTop); //Top Right
566 // Draw Cap --------------------------------------------------------------------------------------
567 for (int i = 0; i < 360; i += 360/sides)
569 rlVertex3f(0, height, 0);
570 rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop);
571 rlVertex3f(sinf(DEG2RAD*(i + 360/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360/sides))*radiusTop);
576 // Draw Cone -------------------------------------------------------------------------------------
577 for (int i = 0; i < 360; i += 360/sides)
579 rlVertex3f(0, height, 0);
580 rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom);
581 rlVertex3f(sinf(DEG2RAD*(i + 360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360/sides))*radiusBottom);
585 // Draw Base -----------------------------------------------------------------------------------------
586 for (int i = 0; i < 360; i += 360/sides)
589 rlVertex3f(sinf(DEG2RAD*(i + 360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360/sides))*radiusBottom);
590 rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom);
596 // Draw a wired cylinder
597 // NOTE: It could be also used for pyramid and cone
598 void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
600 if (sides < 3) sides = 3;
602 int numVertex = sides*8;
603 rlCheckRenderBatchLimit(numVertex);
606 rlTranslatef(position.x, position.y, position.z);
609 rlColor4ub(color.r, color.g, color.b, color.a);
611 for (int i = 0; i < 360; i += 360/sides)
613 rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom);
614 rlVertex3f(sinf(DEG2RAD*(i + 360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360/sides))*radiusBottom);
616 rlVertex3f(sinf(DEG2RAD*(i + 360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360/sides))*radiusBottom);
617 rlVertex3f(sinf(DEG2RAD*(i + 360/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360/sides))*radiusTop);
619 rlVertex3f(sinf(DEG2RAD*(i + 360/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360/sides))*radiusTop);
620 rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop);
622 rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop);
623 rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom);
630 void DrawPlane(Vector3 centerPos, Vector2 size, Color color)
632 rlCheckRenderBatchLimit(4);
634 // NOTE: Plane is always created on XZ ground
636 rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
637 rlScalef(size.x, 1.0f, size.y);
640 rlColor4ub(color.r, color.g, color.b, color.a);
641 rlNormal3f(0.0f, 1.0f, 0.0f);
643 rlVertex3f(-0.5f, 0.0f, -0.5f);
644 rlVertex3f(-0.5f, 0.0f, 0.5f);
645 rlVertex3f(0.5f, 0.0f, 0.5f);
646 rlVertex3f(0.5f, 0.0f, -0.5f);
652 void DrawRay(Ray ray, Color color)
657 rlColor4ub(color.r, color.g, color.b, color.a);
658 rlColor4ub(color.r, color.g, color.b, color.a);
660 rlVertex3f(ray.position.x, ray.position.y, ray.position.z);
661 rlVertex3f(ray.position.x + ray.direction.x*scale, ray.position.y + ray.direction.y*scale, ray.position.z + ray.direction.z*scale);
665 // Draw a grid centered at (0, 0, 0)
666 void DrawGrid(int slices, float spacing)
668 int halfSlices = slices/2;
670 rlCheckRenderBatchLimit((slices + 2)*4);
673 for (int i = -halfSlices; i <= halfSlices; i++)
677 rlColor3f(0.5f, 0.5f, 0.5f);
678 rlColor3f(0.5f, 0.5f, 0.5f);
679 rlColor3f(0.5f, 0.5f, 0.5f);
680 rlColor3f(0.5f, 0.5f, 0.5f);
684 rlColor3f(0.75f, 0.75f, 0.75f);
685 rlColor3f(0.75f, 0.75f, 0.75f);
686 rlColor3f(0.75f, 0.75f, 0.75f);
687 rlColor3f(0.75f, 0.75f, 0.75f);
690 rlVertex3f((float)i*spacing, 0.0f, (float)-halfSlices*spacing);
691 rlVertex3f((float)i*spacing, 0.0f, (float)halfSlices*spacing);
693 rlVertex3f((float)-halfSlices*spacing, 0.0f, (float)i*spacing);
694 rlVertex3f((float)halfSlices*spacing, 0.0f, (float)i*spacing);
699 // Load model from files (mesh and material)
700 Model LoadModel(const char *fileName)
704 #if defined(SUPPORT_FILEFORMAT_OBJ)
705 if (IsFileExtension(fileName, ".obj")) model = LoadOBJ(fileName);
707 #if defined(SUPPORT_FILEFORMAT_IQM)
708 if (IsFileExtension(fileName, ".iqm")) model = LoadIQM(fileName);
710 #if defined(SUPPORT_FILEFORMAT_GLTF)
711 if (IsFileExtension(fileName, ".gltf;.glb")) model = LoadGLTF(fileName);
714 // Make sure model transform is set to identity matrix!
715 model.transform = MatrixIdentity();
717 if (model.meshCount == 0)
720 model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
721 #if defined(SUPPORT_MESH_GENERATION)
722 TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load mesh data, default to cube mesh", fileName);
723 model.meshes[0] = GenMeshCube(1.0f, 1.0f, 1.0f);
725 TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load mesh data", fileName);
730 // Upload vertex data to GPU (static mesh)
731 for (int i = 0; i < model.meshCount; i++) UploadMesh(&model.meshes[i], false);
734 if (model.materialCount == 0)
736 TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to load material data, default to white material", fileName);
738 model.materialCount = 1;
739 model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
740 model.materials[0] = LoadMaterialDefault();
742 if (model.meshMaterial == NULL) model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
748 // Load model from generated mesh
749 // WARNING: A shallow copy of mesh is generated, passed by value,
750 // as long as struct contains pointers to data and some values, we get a copy
751 // of mesh pointing to same data as original version... be careful!
752 Model LoadModelFromMesh(Mesh mesh)
756 model.transform = MatrixIdentity();
759 model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
760 model.meshes[0] = mesh;
762 model.materialCount = 1;
763 model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
764 model.materials[0] = LoadMaterialDefault();
766 model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
767 model.meshMaterial[0] = 0; // First material index
772 // Unload model (meshes/materials) from memory (RAM and/or VRAM)
773 // NOTE: This function takes care of all model elements, for a detailed control
774 // over them, use UnloadMesh() and UnloadMaterial()
775 void UnloadModel(Model model)
778 for (int i = 0; i < model.meshCount; i++) UnloadMesh(model.meshes[i]);
780 // Unload materials maps
781 // NOTE: As the user could be sharing shaders and textures between models,
782 // we don't unload the material but just free it's maps,
783 // the user is responsible for freeing models shaders and textures
784 for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps);
787 RL_FREE(model.meshes);
788 RL_FREE(model.materials);
789 RL_FREE(model.meshMaterial);
791 // Unload animation data
792 RL_FREE(model.bones);
793 RL_FREE(model.bindPose);
795 TRACELOG(LOG_INFO, "MODEL: Unloaded model (and meshes) from RAM and VRAM");
798 // Unload model (but not meshes) from memory (RAM and/or VRAM)
799 void UnloadModelKeepMeshes(Model model)
801 // Unload materials maps
802 // NOTE: As the user could be sharing shaders and textures between models,
803 // we don't unload the material but just free it's maps,
804 // the user is responsible for freeing models shaders and textures
805 for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps);
808 RL_FREE(model.meshes);
809 RL_FREE(model.materials);
810 RL_FREE(model.meshMaterial);
812 // Unload animation data
813 RL_FREE(model.bones);
814 RL_FREE(model.bindPose);
816 TRACELOG(LOG_INFO, "MODEL: Unloaded model (but not meshes) from RAM and VRAM");
819 // Upload vertex data into a VAO (if supported) and VBO
820 void UploadMesh(Mesh *mesh, bool dynamic)
824 // Check if mesh has already been loaded in GPU
825 TRACELOG(LOG_WARNING, "VAO: [ID %i] Trying to re-load an already loaded mesh", mesh->vaoId);
829 mesh->vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VERTEX_BUFFERS, sizeof(unsigned int));
831 mesh->vaoId = 0; // Vertex Array Object
832 mesh->vboId[0] = 0; // Vertex buffer: positions
833 mesh->vboId[1] = 0; // Vertex buffer: texcoords
834 mesh->vboId[2] = 0; // Vertex buffer: normals
835 mesh->vboId[3] = 0; // Vertex buffer: colors
836 mesh->vboId[4] = 0; // Vertex buffer: tangents
837 mesh->vboId[5] = 0; // Vertex buffer: texcoords2
838 mesh->vboId[6] = 0; // Vertex buffer: indices
840 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
841 mesh->vaoId = rlLoadVertexArray();
842 rlEnableVertexArray(mesh->vaoId);
844 // NOTE: Attributes must be uploaded considering default locations points
846 // Enable vertex attributes: position (shader-location = 0)
847 mesh->vboId[0] = rlLoadVertexBuffer(mesh->vertices, mesh->vertexCount*3*sizeof(float), dynamic);
848 rlSetVertexAttribute(0, 3, RL_FLOAT, 0, 0, 0);
849 rlEnableVertexAttribute(0);
851 // Enable vertex attributes: texcoords (shader-location = 1)
852 mesh->vboId[1] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic);
853 rlSetVertexAttribute(1, 2, RL_FLOAT, 0, 0, 0);
854 rlEnableVertexAttribute(1);
856 if (mesh->normals != NULL)
858 // Enable vertex attributes: normals (shader-location = 2)
859 mesh->vboId[2] = rlLoadVertexBuffer(mesh->normals, mesh->vertexCount*3*sizeof(float), dynamic);
860 rlSetVertexAttribute(2, 3, RL_FLOAT, 0, 0, 0);
861 rlEnableVertexAttribute(2);
865 // Default color vertex attribute set to WHITE
866 float value[3] = { 1.0f, 1.0f, 1.0f };
867 rlSetVertexAttributeDefault(2, value, SHADER_ATTRIB_VEC3, 3);
868 rlDisableVertexAttribute(2);
871 if (mesh->colors != NULL)
873 // Enable vertex attribute: color (shader-location = 3)
874 mesh->vboId[3] = rlLoadVertexBuffer(mesh->colors, mesh->vertexCount*4*sizeof(unsigned char), dynamic);
875 rlSetVertexAttribute(3, 4, RL_UNSIGNED_BYTE, 1, 0, 0);
876 rlEnableVertexAttribute(3);
880 // Default color vertex attribute set to WHITE
881 float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
882 rlSetVertexAttributeDefault(3, value, SHADER_ATTRIB_VEC4, 4);
883 rlDisableVertexAttribute(3);
886 if (mesh->tangents != NULL)
888 // Enable vertex attribute: tangent (shader-location = 4)
889 mesh->vboId[4] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), dynamic);
890 rlSetVertexAttribute(4, 4, RL_FLOAT, 0, 0, 0);
891 rlEnableVertexAttribute(4);
895 // Default tangents vertex attribute
896 float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
897 rlSetVertexAttributeDefault(4, value, SHADER_ATTRIB_VEC4, 4);
898 rlDisableVertexAttribute(4);
901 if (mesh->texcoords2 != NULL)
903 // Enable vertex attribute: texcoord2 (shader-location = 5)
904 mesh->vboId[5] = rlLoadVertexBuffer(mesh->texcoords2, mesh->vertexCount*2*sizeof(float), dynamic);
905 rlSetVertexAttribute(5, 2, RL_FLOAT, 0, 0, 0);
906 rlEnableVertexAttribute(5);
910 // Default texcoord2 vertex attribute
911 float value[2] = { 0.0f, 0.0f };
912 rlSetVertexAttributeDefault(5, value, SHADER_ATTRIB_VEC2, 2);
913 rlDisableVertexAttribute(5);
916 if (mesh->indices != NULL)
918 mesh->vboId[6] = rlLoadVertexBufferElement(mesh->indices, mesh->triangleCount*3*sizeof(unsigned short), dynamic);
921 if (mesh->vaoId > 0) TRACELOG(LOG_INFO, "VAO: [ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vaoId);
922 else TRACELOG(LOG_INFO, "VBO: Mesh uploaded successfully to VRAM (GPU)");
924 rlDisableVertexArray();
928 // Update mesh vertex data in GPU for a specific buffer index
929 void UpdateMeshBuffer(Mesh mesh, int index, void *data, int dataSize, int offset)
931 rlUpdateVertexBuffer(mesh.vboId[index], data, dataSize, offset);
934 // Draw a 3d mesh with material and transform
935 void DrawMesh(Mesh mesh, Material material, Matrix transform)
937 DrawMeshInstanced(mesh, material, &transform, 1);
940 // Draw multiple mesh instances with material and different transforms
941 void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int instances)
943 #if defined(GRAPHICS_API_OPENGL_11)
944 #define GL_VERTEX_ARRAY 0x8074
945 #define GL_NORMAL_ARRAY 0x8075
946 #define GL_COLOR_ARRAY 0x8076
947 #define GL_TEXTURE_COORD_ARRAY 0x8078
949 rlEnableTexture(material.maps[MATERIAL_MAP_DIFFUSE].texture.id);
951 rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices);
952 rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords);
953 rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals);
954 rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors);
957 rlMultMatrixf(MatrixToFloat(transforms[0]));
958 rlColor4ub(material.maps[MATERIAL_MAP_DIFFUSE].color.r,
959 material.maps[MATERIAL_MAP_DIFFUSE].color.g,
960 material.maps[MATERIAL_MAP_DIFFUSE].color.b,
961 material.maps[MATERIAL_MAP_DIFFUSE].color.a);
963 if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, mesh.indices);
964 else rlDrawVertexArray(0, mesh.vertexCount);
967 rlDisableStatePointer(GL_VERTEX_ARRAY);
968 rlDisableStatePointer(GL_TEXTURE_COORD_ARRAY);
969 rlDisableStatePointer(GL_NORMAL_ARRAY);
970 rlDisableStatePointer(GL_COLOR_ARRAY);
975 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
977 bool instancing = false;
978 if (instances < 1) return;
979 else if (instances > 1) instancing = true;
980 float16 *instanceTransforms = NULL;
981 unsigned int instancesVboId = 0;
983 // Bind shader program
984 rlEnableShader(material.shader.id);
986 // Send required data to shader (matrices, values)
987 //-----------------------------------------------------
988 // Upload to shader material.colDiffuse
989 if (material.shader.locs[SHADER_LOC_COLOR_DIFFUSE] != -1)
992 (float)material.maps[MATERIAL_MAP_DIFFUSE].color.r/255.0f,
993 (float)material.maps[MATERIAL_MAP_DIFFUSE].color.g/255.0f,
994 (float)material.maps[MATERIAL_MAP_DIFFUSE].color.b/255.0f,
995 (float)material.maps[MATERIAL_MAP_DIFFUSE].color.a/255.0f
998 rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_DIFFUSE], values, SHADER_UNIFORM_VEC4, 1);
1001 // Upload to shader material.colSpecular (if location available)
1002 if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1)
1005 (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.r/255.0f,
1006 (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.g/255.0f,
1007 (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.b/255.0f,
1008 (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.a/255.0f
1011 rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_SPECULAR], values, SHADER_UNIFORM_VEC4, 1);
1014 // Get a copy of current matrices to work with,
1015 // just in case stereo render is required and we need to modify them
1016 // NOTE: At this point the modelview matrix just contains the view matrix (camera)
1017 // That's because BeginMode3D() sets it and there is no model-drawing function
1018 // that modifies it, all use rlPushMatrix() and rlPopMatrix()
1019 Matrix matView = rlGetMatrixModelview();
1020 Matrix matModelView = matView;
1021 Matrix matProjection = rlGetMatrixProjection();
1023 // Upload view and projection matrices (if locations available)
1024 if (material.shader.locs[SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_VIEW], matView);
1025 if (material.shader.locs[SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_PROJECTION], matProjection);
1029 // Create instances buffer
1030 instanceTransforms = RL_MALLOC(instances*sizeof(float16));
1032 // Fill buffer with instances transformations as float16 arrays
1033 for (int i = 0; i < instances; i++) instanceTransforms[i] = MatrixToFloatV(transforms[i]);
1035 // Enable mesh VAO to attach new buffer
1036 rlEnableVertexArray(mesh.vaoId);
1038 // This could alternatively use a static VBO and either glMapBuffer() or glBufferSubData().
1039 // It isn't clear which would be reliably faster in all cases and on all platforms,
1040 // anecdotally glMapBuffer() seems very slow (syncs) while glBufferSubData() seems
1041 // no faster, since we're transferring all the transform matrices anyway
1042 instancesVboId = rlLoadVertexBuffer(instanceTransforms, instances*sizeof(float16), false);
1044 // Instances transformation matrices are send to shader attribute location: SHADER_LOC_MATRIX_MODEL
1045 for (unsigned int i = 0; i < 4; i++)
1047 rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_MATRIX_MODEL] + i);
1048 rlSetVertexAttribute(material.shader.locs[SHADER_LOC_MATRIX_MODEL] + i, 4, RL_FLOAT, 0, sizeof(Matrix), (void *)(i*sizeof(Vector4)));
1049 rlSetVertexAttributeDivisor(material.shader.locs[SHADER_LOC_MATRIX_MODEL] + i, 1);
1052 rlDisableVertexBuffer();
1053 rlDisableVertexArray();
1055 // Accumulate internal matrix transform (push/pop) and view matrix
1056 // NOTE: In this case, model instance transformation must be computed in the shader
1057 matModelView = MatrixMultiply(rlGetMatrixTransform(), matView);
1061 // Model transformation matrix is send to shader uniform location: SHADER_LOC_MATRIX_MODEL
1062 if (material.shader.locs[SHADER_LOC_MATRIX_MODEL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MODEL], transforms[0]);
1064 // Accumulate several transformations:
1065 // matView: rlgl internal modelview matrix (actually, just view matrix)
1066 // rlGetMatrixTransform(): rlgl internal transform matrix due to push/pop matrix stack
1067 // transform: function parameter transformation
1068 matModelView = MatrixMultiply(transforms[0], MatrixMultiply(rlGetMatrixTransform(), matView));
1071 // Upload model normal matrix (if locations available)
1072 if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModelView)));
1073 //-----------------------------------------------------
1075 // Bind active texture maps (if available)
1076 for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
1078 if (material.maps[i].texture.id > 0)
1080 // Select current shader texture slot
1081 rlActiveTextureSlot(i);
1083 // Enable texture for active slot
1084 if ((i == MATERIAL_MAP_IRRADIANCE) ||
1085 (i == MATERIAL_MAP_PREFILTER) ||
1086 (i == MATERIAL_MAP_CUBEMAP)) rlEnableTextureCubemap(material.maps[i].texture.id);
1087 else rlEnableTexture(material.maps[i].texture.id);
1089 rlSetUniform(material.shader.locs[SHADER_LOC_MAP_DIFFUSE + i], &i, SHADER_UNIFORM_INT, 1);
1093 // Try binding vertex array objects (VAO)
1094 // or use VBOs if not possible
1095 if (!rlEnableVertexArray(mesh.vaoId))
1097 // Bind mesh VBO data: vertex position (shader-location = 0)
1098 rlEnableVertexBuffer(mesh.vboId[0]);
1099 rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0);
1100 rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]);
1102 rlEnableVertexBuffer(mesh.vboId[0]);
1103 rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0);
1104 rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]);
1106 // Bind mesh VBO data: vertex texcoords (shader-location = 1)
1107 rlEnableVertexBuffer(mesh.vboId[1]);
1108 rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0);
1109 rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]);
1111 if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1)
1113 // Bind mesh VBO data: vertex normals (shader-location = 2)
1114 rlEnableVertexBuffer(mesh.vboId[2]);
1115 rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0);
1116 rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]);
1119 // Bind mesh VBO data: vertex colors (shader-location = 3, if available)
1120 if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1)
1122 if (mesh.vboId[3] != 0)
1124 rlEnableVertexBuffer(mesh.vboId[3]);
1125 rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0);
1126 rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
1130 // Set default value for unused attribute
1131 // NOTE: Required when using default shader and no VAO support
1132 float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
1133 rlSetVertexAttributeDefault(material.shader.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC2, 4);
1134 rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
1138 // Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
1139 if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1)
1141 rlEnableVertexBuffer(mesh.vboId[4]);
1142 rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0);
1143 rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]);
1146 // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
1147 if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1)
1149 rlEnableVertexBuffer(mesh.vboId[5]);
1150 rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0);
1151 rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]);
1154 if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]);
1158 if (rlIsStereoRenderEnabled()) eyesCount = 2;
1160 for (int eye = 0; eye < eyesCount; eye++)
1162 // Calculate model-view-projection matrix (MVP)
1163 Matrix matMVP = MatrixIdentity();
1164 if (eyesCount == 1) matMVP = MatrixMultiply(matModelView, matProjection);
1167 // Setup current eye viewport (half screen width)
1168 rlViewport(eye*rlGetFramebufferWidth()/2, 0, rlGetFramebufferWidth()/2, rlGetFramebufferHeight());
1169 matMVP = MatrixMultiply(MatrixMultiply(matModelView, rlGetMatrixViewOffsetStereo(eye)), rlGetMatrixProjectionStereo(eye));
1172 // Send combined model-view-projection matrix to shader
1173 rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MVP], matMVP);
1175 if (instancing) // Draw mesh instanced
1177 if (mesh.indices != NULL) rlDrawVertexArrayElementsInstanced(0, mesh.triangleCount*3, 0, instances);
1178 else rlDrawVertexArrayInstanced(0, mesh.vertexCount, instances);
1182 if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, 0);
1183 else rlDrawVertexArray(0, mesh.vertexCount);
1187 // Unbind all binded texture maps
1188 for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
1190 // Select current shader texture slot
1191 rlActiveTextureSlot(i);
1193 // Disable texture for active slot
1194 if ((i == MATERIAL_MAP_IRRADIANCE) ||
1195 (i == MATERIAL_MAP_PREFILTER) ||
1196 (i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap();
1197 else rlDisableTexture();
1200 // Disable all possible vertex array objects (or VBOs)
1201 rlDisableVertexArray();
1202 rlDisableVertexBuffer();
1203 rlDisableVertexBufferElement();
1205 // Disable shader program
1210 // Remove instance transforms buffer
1211 rlUnloadVertexBuffer(instancesVboId);
1212 RL_FREE(instanceTransforms);
1216 // Restore rlgl internal modelview and projection matrices
1217 rlSetMatrixModelview(matView);
1218 rlSetMatrixProjection(matProjection);
1223 // Unload mesh from memory (RAM and VRAM)
1224 void UnloadMesh(Mesh mesh)
1226 // Unload rlgl mesh vboId data
1227 rlUnloadVertexArray(mesh.vaoId);
1229 for (int i = 0; i < MAX_MESH_VERTEX_BUFFERS; i++) rlUnloadVertexBuffer(mesh.vboId[i]);
1230 RL_FREE(mesh.vboId);
1232 RL_FREE(mesh.vertices);
1233 RL_FREE(mesh.texcoords);
1234 RL_FREE(mesh.normals);
1235 RL_FREE(mesh.colors);
1236 RL_FREE(mesh.tangents);
1237 RL_FREE(mesh.texcoords2);
1238 RL_FREE(mesh.indices);
1240 RL_FREE(mesh.animVertices);
1241 RL_FREE(mesh.animNormals);
1242 RL_FREE(mesh.boneWeights);
1243 RL_FREE(mesh.boneIds);
1246 // Export mesh data to file
1247 bool ExportMesh(Mesh mesh, const char *fileName)
1249 bool success = false;
1251 if (IsFileExtension(fileName, ".obj"))
1253 // Estimated data size, it should be enough...
1254 int dataSize = mesh.vertexCount/3* (int)strlen("v 0000.00f 0000.00f 0000.00f") +
1255 mesh.vertexCount/2* (int)strlen("vt 0.000f 0.00f") +
1256 mesh.vertexCount/3* (int)strlen("vn 0.000f 0.00f 0.00f") +
1257 mesh.triangleCount/3* (int)strlen("f 00000/00000/00000 00000/00000/00000 00000/00000/00000");
1259 // NOTE: Text data buffer size is estimated considering mesh data size
1260 char *txtData = (char *)RL_CALLOC(dataSize + 2000, sizeof(char));
1263 bytesCount += sprintf(txtData + bytesCount, "# //////////////////////////////////////////////////////////////////////////////////\n");
1264 bytesCount += sprintf(txtData + bytesCount, "# // //\n");
1265 bytesCount += sprintf(txtData + bytesCount, "# // rMeshOBJ exporter v1.0 - Mesh exported as triangle faces and not optimized //\n");
1266 bytesCount += sprintf(txtData + bytesCount, "# // //\n");
1267 bytesCount += sprintf(txtData + bytesCount, "# // more info and bugs-report: github.com/raysan5/raylib //\n");
1268 bytesCount += sprintf(txtData + bytesCount, "# // feedback and support: ray[at]raylib.com //\n");
1269 bytesCount += sprintf(txtData + bytesCount, "# // //\n");
1270 bytesCount += sprintf(txtData + bytesCount, "# // Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n");
1271 bytesCount += sprintf(txtData + bytesCount, "# // //\n");
1272 bytesCount += sprintf(txtData + bytesCount, "# //////////////////////////////////////////////////////////////////////////////////\n\n");
1273 bytesCount += sprintf(txtData + bytesCount, "# Vertex Count: %i\n", mesh.vertexCount);
1274 bytesCount += sprintf(txtData + bytesCount, "# Triangle Count: %i\n\n", mesh.triangleCount);
1276 bytesCount += sprintf(txtData + bytesCount, "g mesh\n");
1278 for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3)
1280 bytesCount += sprintf(txtData + bytesCount, "v %.2f %.2f %.2f\n", mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]);
1283 for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 2)
1285 bytesCount += sprintf(txtData + bytesCount, "vt %.3f %.3f\n", mesh.texcoords[v], mesh.texcoords[v + 1]);
1288 for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3)
1290 bytesCount += sprintf(txtData + bytesCount, "vn %.3f %.3f %.3f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]);
1293 for (int i = 0; i < mesh.triangleCount; i += 3)
1295 bytesCount += sprintf(txtData + bytesCount, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", i, i, i, i + 1, i + 1, i + 1, i + 2, i + 2, i + 2);
1298 bytesCount += sprintf(txtData + bytesCount, "\n");
1300 // NOTE: Text data length exported is determined by '\0' (NULL) character
1301 success = SaveFileText(fileName, txtData);
1305 else if (IsFileExtension(fileName, ".raw"))
1307 // TODO: Support additional file formats to export mesh vertex data
1314 // Load materials from model file
1315 Material *LoadMaterials(const char *fileName, int *materialCount)
1317 Material *materials = NULL;
1318 unsigned int count = 0;
1320 // TODO: Support IQM and GLTF for materials parsing
1322 #if defined(SUPPORT_FILEFORMAT_MTL)
1323 if (IsFileExtension(fileName, ".mtl"))
1325 tinyobj_material_t *mats = NULL;
1327 int result = tinyobj_parse_mtl_file(&mats, &count, fileName);
1328 if (result != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName);
1330 // TODO: Process materials to return
1332 tinyobj_materials_free(mats, count);
1335 TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load material file", fileName);
1338 // Set materials shader to default (DIFFUSE, SPECULAR, NORMAL)
1339 if (materials != NULL)
1341 for (unsigned int i = 0; i < count; i++) materials[i].shader = rlGetShaderDefault();
1344 *materialCount = count;
1348 // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)
1349 Material LoadMaterialDefault(void)
1351 Material material = { 0 };
1352 material.maps = (MaterialMap *)RL_CALLOC(MAX_MATERIAL_MAPS, sizeof(MaterialMap));
1354 material.shader = rlGetShaderDefault();
1355 material.maps[MATERIAL_MAP_DIFFUSE].texture = rlGetTextureDefault(); // White texture (1x1 pixel)
1356 //material.maps[MATERIAL_MAP_NORMAL].texture; // NOTE: By default, not set
1357 //material.maps[MATERIAL_MAP_SPECULAR].texture; // NOTE: By default, not set
1359 material.maps[MATERIAL_MAP_DIFFUSE].color = WHITE; // Diffuse color
1360 material.maps[MATERIAL_MAP_SPECULAR].color = WHITE; // Specular color
1365 // Unload material from memory
1366 void UnloadMaterial(Material material)
1368 // Unload material shader (avoid unloading default shader, managed by raylib)
1369 if (material.shader.id != rlGetShaderDefault().id) UnloadShader(material.shader);
1371 // Unload loaded texture maps (avoid unloading default texture, managed by raylib)
1372 for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
1374 if (material.maps[i].texture.id != rlGetTextureDefault().id) rlUnloadTexture(material.maps[i].texture.id);
1377 RL_FREE(material.maps);
1380 // Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...)
1381 // NOTE: Previous texture should be manually unloaded
1382 void SetMaterialTexture(Material *material, int mapType, Texture2D texture)
1384 material->maps[mapType].texture = texture;
1387 // Set the material for a mesh
1388 void SetModelMeshMaterial(Model *model, int meshId, int materialId)
1390 if (meshId >= model->meshCount) TRACELOG(LOG_WARNING, "MESH: Id greater than mesh count");
1391 else if (materialId >= model->materialCount) TRACELOG(LOG_WARNING, "MATERIAL: Id greater than material count");
1392 else model->meshMaterial[meshId] = materialId;
1395 // Load model animations from file
1396 ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount)
1398 ModelAnimation *animations = NULL;
1400 #if defined(SUPPORT_FILEFORMAT_IQM)
1401 if (IsFileExtension(fileName, ".iqm")) animations = LoadIQMModelAnimations(fileName, animCount);
1403 #if defined(SUPPORT_FILEFORMAT_GLTF)
1404 if (IsFileExtension(fileName, ".gltf;.glb")) animations = LoadGLTFModelAnimations(fileName, animCount);
1410 // Update model animated vertex data (positions and normals) for a given frame
1411 // NOTE: Updated data is uploaded to GPU
1412 void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
1414 if ((anim.frameCount > 0) && (anim.bones != NULL) && (anim.framePoses != NULL))
1416 if (frame >= anim.frameCount) frame = frame%anim.frameCount;
1418 for (int m = 0; m < model.meshCount; m++)
1420 Vector3 animVertex = { 0 };
1421 Vector3 animNormal = { 0 };
1423 Vector3 inTranslation = { 0 };
1424 Quaternion inRotation = { 0 };
1425 //Vector3 inScale = { 0 }; // Not used...
1427 Vector3 outTranslation = { 0 };
1428 Quaternion outRotation = { 0 };
1429 Vector3 outScale = { 0 };
1432 int boneCounter = 0;
1434 float boneWeight = 0.0;
1436 for (int i = 0; i < model.meshes[m].vertexCount; i++)
1438 model.meshes[m].animVertices[vCounter] = 0;
1439 model.meshes[m].animVertices[vCounter + 1] = 0;
1440 model.meshes[m].animVertices[vCounter + 2] = 0;
1442 model.meshes[m].animNormals[vCounter] = 0;
1443 model.meshes[m].animNormals[vCounter + 1] = 0;
1444 model.meshes[m].animNormals[vCounter + 2] = 0;
1446 for (int j = 0; j < 4; j++)
1448 boneId = model.meshes[m].boneIds[boneCounter];
1449 boneWeight = model.meshes[m].boneWeights[boneCounter];
1450 inTranslation = model.bindPose[boneId].translation;
1451 inRotation = model.bindPose[boneId].rotation;
1452 //inScale = model.bindPose[boneId].scale;
1453 outTranslation = anim.framePoses[frame][boneId].translation;
1454 outRotation = anim.framePoses[frame][boneId].rotation;
1455 outScale = anim.framePoses[frame][boneId].scale;
1457 // Vertices processing
1458 // NOTE: We use meshes.vertices (default vertex position) to calculate meshes.animVertices (animated vertex position)
1459 animVertex = (Vector3){ model.meshes[m].vertices[vCounter], model.meshes[m].vertices[vCounter + 1], model.meshes[m].vertices[vCounter + 2] };
1460 animVertex = Vector3Multiply(animVertex, outScale);
1461 animVertex = Vector3Subtract(animVertex, inTranslation);
1462 animVertex = Vector3RotateByQuaternion(animVertex, QuaternionMultiply(outRotation, QuaternionInvert(inRotation)));
1463 animVertex = Vector3Add(animVertex, outTranslation);
1464 model.meshes[m].animVertices[vCounter] += animVertex.x * boneWeight;
1465 model.meshes[m].animVertices[vCounter + 1] += animVertex.y * boneWeight;
1466 model.meshes[m].animVertices[vCounter + 2] += animVertex.z * boneWeight;
1468 // Normals processing
1469 // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
1470 if (model.meshes[m].normals != NULL)
1472 animNormal = (Vector3){ model.meshes[m].normals[vCounter], model.meshes[m].normals[vCounter + 1], model.meshes[m].normals[vCounter + 2] };
1473 animNormal = Vector3RotateByQuaternion(animNormal, QuaternionMultiply(outRotation, QuaternionInvert(inRotation)));
1474 model.meshes[m].animNormals[vCounter] += animNormal.x * boneWeight;
1475 model.meshes[m].animNormals[vCounter + 1] += animNormal.y * boneWeight;
1476 model.meshes[m].animNormals[vCounter + 2] += animNormal.z * boneWeight;
1483 // Upload new vertex data to GPU for model drawing
1484 rlUpdateVertexBuffer(model.meshes[m].vboId[0], model.meshes[m].animVertices, model.meshes[m].vertexCount*3*sizeof(float), 0); // Update vertex position
1485 rlUpdateVertexBuffer(model.meshes[m].vboId[2], model.meshes[m].animNormals, model.meshes[m].vertexCount*3*sizeof(float), 0); // Update vertex normals
1490 // Unload animation array data
1491 void UnloadModelAnimations(ModelAnimation* animations, unsigned int count)
1493 for (unsigned int i = 0; i < count; i++) UnloadModelAnimation(animations[i]);
1494 RL_FREE(animations);
1497 // Unload animation data
1498 void UnloadModelAnimation(ModelAnimation anim)
1500 for (int i = 0; i < anim.frameCount; i++) RL_FREE(anim.framePoses[i]);
1502 RL_FREE(anim.bones);
1503 RL_FREE(anim.framePoses);
1506 // Check model animation skeleton match
1507 // NOTE: Only number of bones and parent connections are checked
1508 bool IsModelAnimationValid(Model model, ModelAnimation anim)
1512 if (model.boneCount != anim.boneCount) result = false;
1515 for (int i = 0; i < model.boneCount; i++)
1517 if (model.bones[i].parent != anim.bones[i].parent) { result = false; break; }
1524 #if defined(SUPPORT_MESH_GENERATION)
1525 // Generate polygonal mesh
1526 Mesh GenMeshPoly(int sides, float radius)
1530 if (sides < 3) return mesh;
1532 int vertexCount = sides*3;
1534 // Vertices definition
1535 Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
1537 float d = 0.0f, dStep = 360.0f/sides;
1538 for (int v = 0; v < vertexCount; v += 3)
1540 vertices[v] = (Vector3){ 0.0f, 0.0f, 0.0f };
1541 vertices[v + 1] = (Vector3){ sinf(DEG2RAD*d)*radius, 0.0f, cosf(DEG2RAD*d)*radius };
1542 vertices[v + 2] = (Vector3){sinf(DEG2RAD*(d+dStep))*radius, 0.0f, cosf(DEG2RAD*(d+dStep))*radius };
1546 // Normals definition
1547 Vector3 *normals = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
1548 for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f }; // Vector3.up;
1550 // TexCoords definition
1551 Vector2 *texcoords = (Vector2 *)RL_MALLOC(vertexCount*sizeof(Vector2));
1552 for (int n = 0; n < vertexCount; n++) texcoords[n] = (Vector2){ 0.0f, 0.0f };
1554 mesh.vertexCount = vertexCount;
1555 mesh.triangleCount = sides;
1556 mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
1557 mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
1558 mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
1560 // Mesh vertices position array
1561 for (int i = 0; i < mesh.vertexCount; i++)
1563 mesh.vertices[3*i] = vertices[i].x;
1564 mesh.vertices[3*i + 1] = vertices[i].y;
1565 mesh.vertices[3*i + 2] = vertices[i].z;
1568 // Mesh texcoords array
1569 for (int i = 0; i < mesh.vertexCount; i++)
1571 mesh.texcoords[2*i] = texcoords[i].x;
1572 mesh.texcoords[2*i + 1] = texcoords[i].y;
1575 // Mesh normals array
1576 for (int i = 0; i < mesh.vertexCount; i++)
1578 mesh.normals[3*i] = normals[i].x;
1579 mesh.normals[3*i + 1] = normals[i].y;
1580 mesh.normals[3*i + 2] = normals[i].z;
1587 // Upload vertex data to GPU (static mesh)
1588 // NOTE: mesh.vboId array is allocated inside UploadMesh()
1589 UploadMesh(&mesh, false);
1594 // Generate plane mesh (with subdivisions)
1595 Mesh GenMeshPlane(float width, float length, int resX, int resZ)
1599 #define CUSTOM_MESH_GEN_PLANE
1600 #if defined(CUSTOM_MESH_GEN_PLANE)
1604 // Vertices definition
1605 int vertexCount = resX*resZ; // vertices get reused for the faces
1607 Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
1608 for (int z = 0; z < resZ; z++)
1610 // [-length/2, length/2]
1611 float zPos = ((float)z/(resZ - 1) - 0.5f)*length;
1612 for (int x = 0; x < resX; x++)
1614 // [-width/2, width/2]
1615 float xPos = ((float)x/(resX - 1) - 0.5f)*width;
1616 vertices[x + z*resX] = (Vector3){ xPos, 0.0f, zPos };
1620 // Normals definition
1621 Vector3 *normals = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
1622 for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f }; // Vector3.up;
1624 // TexCoords definition
1625 Vector2 *texcoords = (Vector2 *)RL_MALLOC(vertexCount*sizeof(Vector2));
1626 for (int v = 0; v < resZ; v++)
1628 for (int u = 0; u < resX; u++)
1630 texcoords[u + v*resX] = (Vector2){ (float)u/(resX - 1), (float)v/(resZ - 1) };
1634 // Triangles definition (indices)
1635 int numFaces = (resX - 1)*(resZ - 1);
1636 int *triangles = (int *)RL_MALLOC(numFaces*6*sizeof(int));
1638 for (int face = 0; face < numFaces; face++)
1640 // Retrieve lower left corner from face ind
1641 int i = face % (resX - 1) + (face/(resZ - 1)*resX);
1643 triangles[t++] = i + resX;
1644 triangles[t++] = i + 1;
1647 triangles[t++] = i + resX;
1648 triangles[t++] = i + resX + 1;
1649 triangles[t++] = i + 1;
1652 mesh.vertexCount = vertexCount;
1653 mesh.triangleCount = numFaces*2;
1654 mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
1655 mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
1656 mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
1657 mesh.indices = (unsigned short *)RL_MALLOC(mesh.triangleCount*3*sizeof(unsigned short));
1659 // Mesh vertices position array
1660 for (int i = 0; i < mesh.vertexCount; i++)
1662 mesh.vertices[3*i] = vertices[i].x;
1663 mesh.vertices[3*i + 1] = vertices[i].y;
1664 mesh.vertices[3*i + 2] = vertices[i].z;
1667 // Mesh texcoords array
1668 for (int i = 0; i < mesh.vertexCount; i++)
1670 mesh.texcoords[2*i] = texcoords[i].x;
1671 mesh.texcoords[2*i + 1] = texcoords[i].y;
1674 // Mesh normals array
1675 for (int i = 0; i < mesh.vertexCount; i++)
1677 mesh.normals[3*i] = normals[i].x;
1678 mesh.normals[3*i + 1] = normals[i].y;
1679 mesh.normals[3*i + 2] = normals[i].z;
1682 // Mesh indices array initialization
1683 for (int i = 0; i < mesh.triangleCount*3; i++) mesh.indices[i] = triangles[i];
1690 #else // Use par_shapes library to generate plane mesh
1692 par_shapes_mesh *plane = par_shapes_create_plane(resX, resZ); // No normals/texcoords generated!!!
1693 par_shapes_scale(plane, width, length, 1.0f);
1694 par_shapes_rotate(plane, -PI/2.0f, (float[]){ 1, 0, 0 });
1695 par_shapes_translate(plane, -width/2, 0.0f, length/2);
1697 mesh.vertices = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float));
1698 mesh.texcoords = (float *)RL_MALLOC(plane->ntriangles*3*2*sizeof(float));
1699 mesh.normals = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float));
1701 mesh.vertexCount = plane->ntriangles*3;
1702 mesh.triangleCount = plane->ntriangles;
1704 for (int k = 0; k < mesh.vertexCount; k++)
1706 mesh.vertices[k*3] = plane->points[plane->triangles[k]*3];
1707 mesh.vertices[k*3 + 1] = plane->points[plane->triangles[k]*3 + 1];
1708 mesh.vertices[k*3 + 2] = plane->points[plane->triangles[k]*3 + 2];
1710 mesh.normals[k*3] = plane->normals[plane->triangles[k]*3];
1711 mesh.normals[k*3 + 1] = plane->normals[plane->triangles[k]*3 + 1];
1712 mesh.normals[k*3 + 2] = plane->normals[plane->triangles[k]*3 + 2];
1714 mesh.texcoords[k*2] = plane->tcoords[plane->triangles[k]*2];
1715 mesh.texcoords[k*2 + 1] = plane->tcoords[plane->triangles[k]*2 + 1];
1718 par_shapes_free_mesh(plane);
1721 // Upload vertex data to GPU (static mesh)
1722 UploadMesh(&mesh, false);
1727 // Generated cuboid mesh
1728 Mesh GenMeshCube(float width, float height, float length)
1732 #define CUSTOM_MESH_GEN_CUBE
1733 #if defined(CUSTOM_MESH_GEN_CUBE)
1734 float vertices[] = {
1735 -width/2, -height/2, length/2,
1736 width/2, -height/2, length/2,
1737 width/2, height/2, length/2,
1738 -width/2, height/2, length/2,
1739 -width/2, -height/2, -length/2,
1740 -width/2, height/2, -length/2,
1741 width/2, height/2, -length/2,
1742 width/2, -height/2, -length/2,
1743 -width/2, height/2, -length/2,
1744 -width/2, height/2, length/2,
1745 width/2, height/2, length/2,
1746 width/2, height/2, -length/2,
1747 -width/2, -height/2, -length/2,
1748 width/2, -height/2, -length/2,
1749 width/2, -height/2, length/2,
1750 -width/2, -height/2, length/2,
1751 width/2, -height/2, -length/2,
1752 width/2, height/2, -length/2,
1753 width/2, height/2, length/2,
1754 width/2, -height/2, length/2,
1755 -width/2, -height/2, -length/2,
1756 -width/2, -height/2, length/2,
1757 -width/2, height/2, length/2,
1758 -width/2, height/2, -length/2
1761 float texcoords[] = {
1815 mesh.vertices = (float *)RL_MALLOC(24*3*sizeof(float));
1816 memcpy(mesh.vertices, vertices, 24*3*sizeof(float));
1818 mesh.texcoords = (float *)RL_MALLOC(24*2*sizeof(float));
1819 memcpy(mesh.texcoords, texcoords, 24*2*sizeof(float));
1821 mesh.normals = (float *)RL_MALLOC(24*3*sizeof(float));
1822 memcpy(mesh.normals, normals, 24*3*sizeof(float));
1824 mesh.indices = (unsigned short *)RL_MALLOC(36*sizeof(unsigned short));
1828 // Indices can be initialized right now
1829 for (int i = 0; i < 36; i+=6)
1831 mesh.indices[i] = 4*k;
1832 mesh.indices[i+1] = 4*k+1;
1833 mesh.indices[i+2] = 4*k+2;
1834 mesh.indices[i+3] = 4*k;
1835 mesh.indices[i+4] = 4*k+2;
1836 mesh.indices[i+5] = 4*k+3;
1841 mesh.vertexCount = 24;
1842 mesh.triangleCount = 12;
1844 #else // Use par_shapes library to generate cube mesh
1847 par_shapes_mesh* par_shapes_create_tetrahedron(); // 4 sides polyhedron (pyramid)
1848 par_shapes_mesh* par_shapes_create_cube(); // 6 sides polyhedron (cube)
1849 par_shapes_mesh* par_shapes_create_octahedron(); // 8 sides polyhedron (dyamond)
1850 par_shapes_mesh* par_shapes_create_dodecahedron(); // 12 sides polyhedron
1851 par_shapes_mesh* par_shapes_create_icosahedron(); // 20 sides polyhedron
1853 // Platonic solid generation: cube (6 sides)
1854 // NOTE: No normals/texcoords generated by default
1855 par_shapes_mesh *cube = par_shapes_create_cube();
1856 cube->tcoords = PAR_MALLOC(float, 2*cube->npoints);
1857 for (int i = 0; i < 2*cube->npoints; i++) cube->tcoords[i] = 0.0f;
1858 par_shapes_scale(cube, width, height, length);
1859 par_shapes_translate(cube, -width/2, 0.0f, -length/2);
1860 par_shapes_compute_normals(cube);
1862 mesh.vertices = (float *)RL_MALLOC(cube->ntriangles*3*3*sizeof(float));
1863 mesh.texcoords = (float *)RL_MALLOC(cube->ntriangles*3*2*sizeof(float));
1864 mesh.normals = (float *)RL_MALLOC(cube->ntriangles*3*3*sizeof(float));
1866 mesh.vertexCount = cube->ntriangles*3;
1867 mesh.triangleCount = cube->ntriangles;
1869 for (int k = 0; k < mesh.vertexCount; k++)
1871 mesh.vertices[k*3] = cube->points[cube->triangles[k]*3];
1872 mesh.vertices[k*3 + 1] = cube->points[cube->triangles[k]*3 + 1];
1873 mesh.vertices[k*3 + 2] = cube->points[cube->triangles[k]*3 + 2];
1875 mesh.normals[k*3] = cube->normals[cube->triangles[k]*3];
1876 mesh.normals[k*3 + 1] = cube->normals[cube->triangles[k]*3 + 1];
1877 mesh.normals[k*3 + 2] = cube->normals[cube->triangles[k]*3 + 2];
1879 mesh.texcoords[k*2] = cube->tcoords[cube->triangles[k]*2];
1880 mesh.texcoords[k*2 + 1] = cube->tcoords[cube->triangles[k]*2 + 1];
1883 par_shapes_free_mesh(cube);
1886 // Upload vertex data to GPU (static mesh)
1887 UploadMesh(&mesh, false);
1892 // Generate sphere mesh (standard sphere)
1893 Mesh GenMeshSphere(float radius, int rings, int slices)
1897 if ((rings >= 3) && (slices >= 3))
1899 par_shapes_mesh *sphere = par_shapes_create_parametric_sphere(slices, rings);
1900 par_shapes_scale(sphere, radius, radius, radius);
1901 // NOTE: Soft normals are computed internally
1903 mesh.vertices = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
1904 mesh.texcoords = (float *)RL_MALLOC(sphere->ntriangles*3*2*sizeof(float));
1905 mesh.normals = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
1907 mesh.vertexCount = sphere->ntriangles*3;
1908 mesh.triangleCount = sphere->ntriangles;
1910 for (int k = 0; k < mesh.vertexCount; k++)
1912 mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3];
1913 mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1];
1914 mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2];
1916 mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3];
1917 mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1];
1918 mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2];
1920 mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2];
1921 mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1];
1924 par_shapes_free_mesh(sphere);
1926 // Upload vertex data to GPU (static mesh)
1927 UploadMesh(&mesh, false);
1929 else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: sphere");
1934 // Generate hemi-sphere mesh (half sphere, no bottom cap)
1935 Mesh GenMeshHemiSphere(float radius, int rings, int slices)
1939 if ((rings >= 3) && (slices >= 3))
1941 if (radius < 0.0f) radius = 0.0f;
1943 par_shapes_mesh *sphere = par_shapes_create_hemisphere(slices, rings);
1944 par_shapes_scale(sphere, radius, radius, radius);
1945 // NOTE: Soft normals are computed internally
1947 mesh.vertices = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
1948 mesh.texcoords = (float *)RL_MALLOC(sphere->ntriangles*3*2*sizeof(float));
1949 mesh.normals = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
1951 mesh.vertexCount = sphere->ntriangles*3;
1952 mesh.triangleCount = sphere->ntriangles;
1954 for (int k = 0; k < mesh.vertexCount; k++)
1956 mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3];
1957 mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1];
1958 mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2];
1960 mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3];
1961 mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1];
1962 mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2];
1964 mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2];
1965 mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1];
1968 par_shapes_free_mesh(sphere);
1970 // Upload vertex data to GPU (static mesh)
1971 UploadMesh(&mesh, false);
1973 else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: hemisphere");
1978 // Generate cylinder mesh
1979 Mesh GenMeshCylinder(float radius, float height, int slices)
1985 // Instance a cylinder that sits on the Z=0 plane using the given tessellation
1986 // levels across the UV domain. Think of "slices" like a number of pizza
1987 // slices, and "stacks" like a number of stacked rings.
1988 // Height and radius are both 1.0, but they can easily be changed with par_shapes_scale
1989 par_shapes_mesh *cylinder = par_shapes_create_cylinder(slices, 8);
1990 par_shapes_scale(cylinder, radius, radius, height);
1991 par_shapes_rotate(cylinder, -PI/2.0f, (float[]){ 1, 0, 0 });
1992 par_shapes_rotate(cylinder, PI/2.0f, (float[]){ 0, 1, 0 });
1994 // Generate an orientable disk shape (top cap)
1995 par_shapes_mesh *capTop = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, 1 });
1996 capTop->tcoords = PAR_MALLOC(float, 2*capTop->npoints);
1997 for (int i = 0; i < 2*capTop->npoints; i++) capTop->tcoords[i] = 0.0f;
1998 par_shapes_rotate(capTop, -PI/2.0f, (float[]){ 1, 0, 0 });
1999 par_shapes_translate(capTop, 0, height, 0);
2001 // Generate an orientable disk shape (bottom cap)
2002 par_shapes_mesh *capBottom = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, -1 });
2003 capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints);
2004 for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f;
2005 par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 });
2007 par_shapes_merge_and_free(cylinder, capTop);
2008 par_shapes_merge_and_free(cylinder, capBottom);
2010 mesh.vertices = (float *)RL_MALLOC(cylinder->ntriangles*3*3*sizeof(float));
2011 mesh.texcoords = (float *)RL_MALLOC(cylinder->ntriangles*3*2*sizeof(float));
2012 mesh.normals = (float *)RL_MALLOC(cylinder->ntriangles*3*3*sizeof(float));
2014 mesh.vertexCount = cylinder->ntriangles*3;
2015 mesh.triangleCount = cylinder->ntriangles;
2017 for (int k = 0; k < mesh.vertexCount; k++)
2019 mesh.vertices[k*3] = cylinder->points[cylinder->triangles[k]*3];
2020 mesh.vertices[k*3 + 1] = cylinder->points[cylinder->triangles[k]*3 + 1];
2021 mesh.vertices[k*3 + 2] = cylinder->points[cylinder->triangles[k]*3 + 2];
2023 mesh.normals[k*3] = cylinder->normals[cylinder->triangles[k]*3];
2024 mesh.normals[k*3 + 1] = cylinder->normals[cylinder->triangles[k]*3 + 1];
2025 mesh.normals[k*3 + 2] = cylinder->normals[cylinder->triangles[k]*3 + 2];
2027 mesh.texcoords[k*2] = cylinder->tcoords[cylinder->triangles[k]*2];
2028 mesh.texcoords[k*2 + 1] = cylinder->tcoords[cylinder->triangles[k]*2 + 1];
2031 par_shapes_free_mesh(cylinder);
2033 // Upload vertex data to GPU (static mesh)
2034 UploadMesh(&mesh, false);
2036 else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: cylinder");
2041 // Generate torus mesh
2042 Mesh GenMeshTorus(float radius, float size, int radSeg, int sides)
2046 if ((sides >= 3) && (radSeg >= 3))
2048 if (radius > 1.0f) radius = 1.0f;
2049 else if (radius < 0.1f) radius = 0.1f;
2051 // Create a donut that sits on the Z=0 plane with the specified inner radius
2052 // The outer radius can be controlled with par_shapes_scale
2053 par_shapes_mesh *torus = par_shapes_create_torus(radSeg, sides, radius);
2054 par_shapes_scale(torus, size/2, size/2, size/2);
2056 mesh.vertices = (float *)RL_MALLOC(torus->ntriangles*3*3*sizeof(float));
2057 mesh.texcoords = (float *)RL_MALLOC(torus->ntriangles*3*2*sizeof(float));
2058 mesh.normals = (float *)RL_MALLOC(torus->ntriangles*3*3*sizeof(float));
2060 mesh.vertexCount = torus->ntriangles*3;
2061 mesh.triangleCount = torus->ntriangles;
2063 for (int k = 0; k < mesh.vertexCount; k++)
2065 mesh.vertices[k*3] = torus->points[torus->triangles[k]*3];
2066 mesh.vertices[k*3 + 1] = torus->points[torus->triangles[k]*3 + 1];
2067 mesh.vertices[k*3 + 2] = torus->points[torus->triangles[k]*3 + 2];
2069 mesh.normals[k*3] = torus->normals[torus->triangles[k]*3];
2070 mesh.normals[k*3 + 1] = torus->normals[torus->triangles[k]*3 + 1];
2071 mesh.normals[k*3 + 2] = torus->normals[torus->triangles[k]*3 + 2];
2073 mesh.texcoords[k*2] = torus->tcoords[torus->triangles[k]*2];
2074 mesh.texcoords[k*2 + 1] = torus->tcoords[torus->triangles[k]*2 + 1];
2077 par_shapes_free_mesh(torus);
2079 // Upload vertex data to GPU (static mesh)
2080 UploadMesh(&mesh, false);
2082 else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: torus");
2087 // Generate trefoil knot mesh
2088 Mesh GenMeshKnot(float radius, float size, int radSeg, int sides)
2092 if ((sides >= 3) && (radSeg >= 3))
2094 if (radius > 3.0f) radius = 3.0f;
2095 else if (radius < 0.5f) radius = 0.5f;
2097 par_shapes_mesh *knot = par_shapes_create_trefoil_knot(radSeg, sides, radius);
2098 par_shapes_scale(knot, size, size, size);
2100 mesh.vertices = (float *)RL_MALLOC(knot->ntriangles*3*3*sizeof(float));
2101 mesh.texcoords = (float *)RL_MALLOC(knot->ntriangles*3*2*sizeof(float));
2102 mesh.normals = (float *)RL_MALLOC(knot->ntriangles*3*3*sizeof(float));
2104 mesh.vertexCount = knot->ntriangles*3;
2105 mesh.triangleCount = knot->ntriangles;
2107 for (int k = 0; k < mesh.vertexCount; k++)
2109 mesh.vertices[k*3] = knot->points[knot->triangles[k]*3];
2110 mesh.vertices[k*3 + 1] = knot->points[knot->triangles[k]*3 + 1];
2111 mesh.vertices[k*3 + 2] = knot->points[knot->triangles[k]*3 + 2];
2113 mesh.normals[k*3] = knot->normals[knot->triangles[k]*3];
2114 mesh.normals[k*3 + 1] = knot->normals[knot->triangles[k]*3 + 1];
2115 mesh.normals[k*3 + 2] = knot->normals[knot->triangles[k]*3 + 2];
2117 mesh.texcoords[k*2] = knot->tcoords[knot->triangles[k]*2];
2118 mesh.texcoords[k*2 + 1] = knot->tcoords[knot->triangles[k]*2 + 1];
2121 par_shapes_free_mesh(knot);
2123 // Upload vertex data to GPU (static mesh)
2124 UploadMesh(&mesh, false);
2126 else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: knot");
2131 // Generate a mesh from heightmap
2132 // NOTE: Vertex data is uploaded to GPU
2133 Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
2135 #define GRAY_VALUE(c) ((c.r+c.g+c.b)/3)
2139 int mapX = heightmap.width;
2140 int mapZ = heightmap.height;
2142 Color *pixels = LoadImageColors(heightmap);
2144 // NOTE: One vertex per pixel
2145 mesh.triangleCount = (mapX-1)*(mapZ-1)*2; // One quad every four pixels
2147 mesh.vertexCount = mesh.triangleCount*3;
2149 mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
2150 mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
2151 mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
2154 int vCounter = 0; // Used to count vertices float by float
2155 int tcCounter = 0; // Used to count texcoords float by float
2156 int nCounter = 0; // Used to count normals float by float
2158 int trisCounter = 0;
2160 Vector3 scaleFactor = { size.x/mapX, size.y/255.0f, size.z/mapZ };
2167 for (int z = 0; z < mapZ-1; z++)
2169 for (int x = 0; x < mapX-1; x++)
2171 // Fill vertices array with data
2172 //----------------------------------------------------------
2174 // one triangle - 3 vertex
2175 mesh.vertices[vCounter] = (float)x*scaleFactor.x;
2176 mesh.vertices[vCounter + 1] = (float)GRAY_VALUE(pixels[x + z*mapX])*scaleFactor.y;
2177 mesh.vertices[vCounter + 2] = (float)z*scaleFactor.z;
2179 mesh.vertices[vCounter + 3] = (float)x*scaleFactor.x;
2180 mesh.vertices[vCounter + 4] = (float)GRAY_VALUE(pixels[x + (z + 1)*mapX])*scaleFactor.y;
2181 mesh.vertices[vCounter + 5] = (float)(z + 1)*scaleFactor.z;
2183 mesh.vertices[vCounter + 6] = (float)(x + 1)*scaleFactor.x;
2184 mesh.vertices[vCounter + 7] = (float)GRAY_VALUE(pixels[(x + 1) + z*mapX])*scaleFactor.y;
2185 mesh.vertices[vCounter + 8] = (float)z*scaleFactor.z;
2187 // another triangle - 3 vertex
2188 mesh.vertices[vCounter + 9] = mesh.vertices[vCounter + 6];
2189 mesh.vertices[vCounter + 10] = mesh.vertices[vCounter + 7];
2190 mesh.vertices[vCounter + 11] = mesh.vertices[vCounter + 8];
2192 mesh.vertices[vCounter + 12] = mesh.vertices[vCounter + 3];
2193 mesh.vertices[vCounter + 13] = mesh.vertices[vCounter + 4];
2194 mesh.vertices[vCounter + 14] = mesh.vertices[vCounter + 5];
2196 mesh.vertices[vCounter + 15] = (float)(x + 1)*scaleFactor.x;
2197 mesh.vertices[vCounter + 16] = (float)GRAY_VALUE(pixels[(x + 1) + (z + 1)*mapX])*scaleFactor.y;
2198 mesh.vertices[vCounter + 17] = (float)(z + 1)*scaleFactor.z;
2199 vCounter += 18; // 6 vertex, 18 floats
2201 // Fill texcoords array with data
2202 //--------------------------------------------------------------
2203 mesh.texcoords[tcCounter] = (float)x/(mapX - 1);
2204 mesh.texcoords[tcCounter + 1] = (float)z/(mapZ - 1);
2206 mesh.texcoords[tcCounter + 2] = (float)x/(mapX - 1);
2207 mesh.texcoords[tcCounter + 3] = (float)(z + 1)/(mapZ - 1);
2209 mesh.texcoords[tcCounter + 4] = (float)(x + 1)/(mapX - 1);
2210 mesh.texcoords[tcCounter + 5] = (float)z/(mapZ - 1);
2212 mesh.texcoords[tcCounter + 6] = mesh.texcoords[tcCounter + 4];
2213 mesh.texcoords[tcCounter + 7] = mesh.texcoords[tcCounter + 5];
2215 mesh.texcoords[tcCounter + 8] = mesh.texcoords[tcCounter + 2];
2216 mesh.texcoords[tcCounter + 9] = mesh.texcoords[tcCounter + 3];
2218 mesh.texcoords[tcCounter + 10] = (float)(x + 1)/(mapX - 1);
2219 mesh.texcoords[tcCounter + 11] = (float)(z + 1)/(mapZ - 1);
2220 tcCounter += 12; // 6 texcoords, 12 floats
2222 // Fill normals array with data
2223 //--------------------------------------------------------------
2224 for (int i = 0; i < 18; i += 9)
2226 vA.x = mesh.vertices[nCounter + i];
2227 vA.y = mesh.vertices[nCounter + i + 1];
2228 vA.z = mesh.vertices[nCounter + i + 2];
2230 vB.x = mesh.vertices[nCounter + i + 3];
2231 vB.y = mesh.vertices[nCounter + i + 4];
2232 vB.z = mesh.vertices[nCounter + i + 5];
2234 vC.x = mesh.vertices[nCounter + i + 6];
2235 vC.y = mesh.vertices[nCounter + i + 7];
2236 vC.z = mesh.vertices[nCounter + i + 8];
2238 vN = Vector3Normalize(Vector3CrossProduct(Vector3Subtract(vB, vA), Vector3Subtract(vC, vA)));
2240 mesh.normals[nCounter + i] = vN.x;
2241 mesh.normals[nCounter + i + 1] = vN.y;
2242 mesh.normals[nCounter + i + 2] = vN.z;
2244 mesh.normals[nCounter + i + 3] = vN.x;
2245 mesh.normals[nCounter + i + 4] = vN.y;
2246 mesh.normals[nCounter + i + 5] = vN.z;
2248 mesh.normals[nCounter + i + 6] = vN.x;
2249 mesh.normals[nCounter + i + 7] = vN.y;
2250 mesh.normals[nCounter + i + 8] = vN.z;
2253 nCounter += 18; // 6 vertex, 18 floats
2258 UnloadImageColors(pixels); // Unload pixels color data
2260 // Upload vertex data to GPU (static mesh)
2261 UploadMesh(&mesh, false);
2266 // Generate a cubes mesh from pixel data
2267 // NOTE: Vertex data is uploaded to GPU
2268 Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
2270 #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a))
2274 Color *pixels = LoadImageColors(cubicmap);
2276 int mapWidth = cubicmap.width;
2277 int mapHeight = cubicmap.height;
2279 // NOTE: Max possible number of triangles numCubes*(12 triangles by cube)
2280 int maxTriangles = cubicmap.width*cubicmap.height*12;
2282 int vCounter = 0; // Used to count vertices
2283 int tcCounter = 0; // Used to count texcoords
2284 int nCounter = 0; // Used to count normals
2286 float w = cubeSize.x;
2287 float h = cubeSize.z;
2288 float h2 = cubeSize.y;
2290 Vector3 *mapVertices = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3));
2291 Vector2 *mapTexcoords = (Vector2 *)RL_MALLOC(maxTriangles*3*sizeof(Vector2));
2292 Vector3 *mapNormals = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3));
2294 // Define the 6 normals of the cube, we will combine them accordingly later...
2295 Vector3 n1 = { 1.0f, 0.0f, 0.0f };
2296 Vector3 n2 = { -1.0f, 0.0f, 0.0f };
2297 Vector3 n3 = { 0.0f, 1.0f, 0.0f };
2298 Vector3 n4 = { 0.0f, -1.0f, 0.0f };
2299 Vector3 n5 = { 0.0f, 0.0f, -1.0f };
2300 Vector3 n6 = { 0.0f, 0.0f, 1.0f };
2302 // NOTE: We use texture rectangles to define different textures for top-bottom-front-back-right-left (6)
2303 typedef struct RectangleF {
2310 RectangleF rightTexUV = { 0.0f, 0.0f, 0.5f, 0.5f };
2311 RectangleF leftTexUV = { 0.5f, 0.0f, 0.5f, 0.5f };
2312 RectangleF frontTexUV = { 0.0f, 0.0f, 0.5f, 0.5f };
2313 RectangleF backTexUV = { 0.5f, 0.0f, 0.5f, 0.5f };
2314 RectangleF topTexUV = { 0.0f, 0.5f, 0.5f, 0.5f };
2315 RectangleF bottomTexUV = { 0.5f, 0.5f, 0.5f, 0.5f };
2317 for (int z = 0; z < mapHeight; ++z)
2319 for (int x = 0; x < mapWidth; ++x)
2321 // Define the 8 vertex of the cube, we will combine them accordingly later...
2322 Vector3 v1 = { w*(x - 0.5f), h2, h*(z - 0.5f) };
2323 Vector3 v2 = { w*(x - 0.5f), h2, h*(z + 0.5f) };
2324 Vector3 v3 = { w*(x + 0.5f), h2, h*(z + 0.5f) };
2325 Vector3 v4 = { w*(x + 0.5f), h2, h*(z - 0.5f) };
2326 Vector3 v5 = { w*(x + 0.5f), 0, h*(z - 0.5f) };
2327 Vector3 v6 = { w*(x - 0.5f), 0, h*(z - 0.5f) };
2328 Vector3 v7 = { w*(x - 0.5f), 0, h*(z + 0.5f) };
2329 Vector3 v8 = { w*(x + 0.5f), 0, h*(z + 0.5f) };
2331 // We check pixel color to be WHITE -> draw full cube
2332 if (COLOR_EQUAL(pixels[z*cubicmap.width + x], WHITE))
2334 // Define triangles and checking collateral cubes
2335 //------------------------------------------------
2337 // Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
2338 // WARNING: Not required for a WHITE cubes, created to allow seeing the map from outside
2339 mapVertices[vCounter] = v1;
2340 mapVertices[vCounter + 1] = v2;
2341 mapVertices[vCounter + 2] = v3;
2342 mapVertices[vCounter + 3] = v1;
2343 mapVertices[vCounter + 4] = v3;
2344 mapVertices[vCounter + 5] = v4;
2347 mapNormals[nCounter] = n3;
2348 mapNormals[nCounter + 1] = n3;
2349 mapNormals[nCounter + 2] = n3;
2350 mapNormals[nCounter + 3] = n3;
2351 mapNormals[nCounter + 4] = n3;
2352 mapNormals[nCounter + 5] = n3;
2355 mapTexcoords[tcCounter] = (Vector2){ topTexUV.x, topTexUV.y };
2356 mapTexcoords[tcCounter + 1] = (Vector2){ topTexUV.x, topTexUV.y + topTexUV.height };
2357 mapTexcoords[tcCounter + 2] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
2358 mapTexcoords[tcCounter + 3] = (Vector2){ topTexUV.x, topTexUV.y };
2359 mapTexcoords[tcCounter + 4] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
2360 mapTexcoords[tcCounter + 5] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y };
2363 // Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8)
2364 mapVertices[vCounter] = v6;
2365 mapVertices[vCounter + 1] = v8;
2366 mapVertices[vCounter + 2] = v7;
2367 mapVertices[vCounter + 3] = v6;
2368 mapVertices[vCounter + 4] = v5;
2369 mapVertices[vCounter + 5] = v8;
2372 mapNormals[nCounter] = n4;
2373 mapNormals[nCounter + 1] = n4;
2374 mapNormals[nCounter + 2] = n4;
2375 mapNormals[nCounter + 3] = n4;
2376 mapNormals[nCounter + 4] = n4;
2377 mapNormals[nCounter + 5] = n4;
2380 mapTexcoords[tcCounter] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
2381 mapTexcoords[tcCounter + 1] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
2382 mapTexcoords[tcCounter + 2] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y + bottomTexUV.height };
2383 mapTexcoords[tcCounter + 3] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
2384 mapTexcoords[tcCounter + 4] = (Vector2){ bottomTexUV.x, bottomTexUV.y };
2385 mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
2388 // Checking cube on bottom of current cube
2389 if (((z < cubicmap.height - 1) && COLOR_EQUAL(pixels[(z + 1)*cubicmap.width + x], BLACK)) || (z == cubicmap.height - 1))
2391 // Define front triangles (2 tris, 6 vertex) --> v2 v7 v3, v3 v7 v8
2392 // NOTE: Collateral occluded faces are not generated
2393 mapVertices[vCounter] = v2;
2394 mapVertices[vCounter + 1] = v7;
2395 mapVertices[vCounter + 2] = v3;
2396 mapVertices[vCounter + 3] = v3;
2397 mapVertices[vCounter + 4] = v7;
2398 mapVertices[vCounter + 5] = v8;
2401 mapNormals[nCounter] = n6;
2402 mapNormals[nCounter + 1] = n6;
2403 mapNormals[nCounter + 2] = n6;
2404 mapNormals[nCounter + 3] = n6;
2405 mapNormals[nCounter + 4] = n6;
2406 mapNormals[nCounter + 5] = n6;
2409 mapTexcoords[tcCounter] = (Vector2){ frontTexUV.x, frontTexUV.y };
2410 mapTexcoords[tcCounter + 1] = (Vector2){ frontTexUV.x, frontTexUV.y + frontTexUV.height };
2411 mapTexcoords[tcCounter + 2] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y };
2412 mapTexcoords[tcCounter + 3] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y };
2413 mapTexcoords[tcCounter + 4] = (Vector2){ frontTexUV.x, frontTexUV.y + frontTexUV.height };
2414 mapTexcoords[tcCounter + 5] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y + frontTexUV.height };
2418 // Checking cube on top of current cube
2419 if (((z > 0) && COLOR_EQUAL(pixels[(z - 1)*cubicmap.width + x], BLACK)) || (z == 0))
2421 // Define back triangles (2 tris, 6 vertex) --> v1 v5 v6, v1 v4 v5
2422 // NOTE: Collateral occluded faces are not generated
2423 mapVertices[vCounter] = v1;
2424 mapVertices[vCounter + 1] = v5;
2425 mapVertices[vCounter + 2] = v6;
2426 mapVertices[vCounter + 3] = v1;
2427 mapVertices[vCounter + 4] = v4;
2428 mapVertices[vCounter + 5] = v5;
2431 mapNormals[nCounter] = n5;
2432 mapNormals[nCounter + 1] = n5;
2433 mapNormals[nCounter + 2] = n5;
2434 mapNormals[nCounter + 3] = n5;
2435 mapNormals[nCounter + 4] = n5;
2436 mapNormals[nCounter + 5] = n5;
2439 mapTexcoords[tcCounter] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y };
2440 mapTexcoords[tcCounter + 1] = (Vector2){ backTexUV.x, backTexUV.y + backTexUV.height };
2441 mapTexcoords[tcCounter + 2] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y + backTexUV.height };
2442 mapTexcoords[tcCounter + 3] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y };
2443 mapTexcoords[tcCounter + 4] = (Vector2){ backTexUV.x, backTexUV.y };
2444 mapTexcoords[tcCounter + 5] = (Vector2){ backTexUV.x, backTexUV.y + backTexUV.height };
2448 // Checking cube on right of current cube
2449 if (((x < cubicmap.width - 1) && COLOR_EQUAL(pixels[z*cubicmap.width + (x + 1)], BLACK)) || (x == cubicmap.width - 1))
2451 // Define right triangles (2 tris, 6 vertex) --> v3 v8 v4, v4 v8 v5
2452 // NOTE: Collateral occluded faces are not generated
2453 mapVertices[vCounter] = v3;
2454 mapVertices[vCounter + 1] = v8;
2455 mapVertices[vCounter + 2] = v4;
2456 mapVertices[vCounter + 3] = v4;
2457 mapVertices[vCounter + 4] = v8;
2458 mapVertices[vCounter + 5] = v5;
2461 mapNormals[nCounter] = n1;
2462 mapNormals[nCounter + 1] = n1;
2463 mapNormals[nCounter + 2] = n1;
2464 mapNormals[nCounter + 3] = n1;
2465 mapNormals[nCounter + 4] = n1;
2466 mapNormals[nCounter + 5] = n1;
2469 mapTexcoords[tcCounter] = (Vector2){ rightTexUV.x, rightTexUV.y };
2470 mapTexcoords[tcCounter + 1] = (Vector2){ rightTexUV.x, rightTexUV.y + rightTexUV.height };
2471 mapTexcoords[tcCounter + 2] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y };
2472 mapTexcoords[tcCounter + 3] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y };
2473 mapTexcoords[tcCounter + 4] = (Vector2){ rightTexUV.x, rightTexUV.y + rightTexUV.height };
2474 mapTexcoords[tcCounter + 5] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y + rightTexUV.height };
2478 // Checking cube on left of current cube
2479 if (((x > 0) && COLOR_EQUAL(pixels[z*cubicmap.width + (x - 1)], BLACK)) || (x == 0))
2481 // Define left triangles (2 tris, 6 vertex) --> v1 v7 v2, v1 v6 v7
2482 // NOTE: Collateral occluded faces are not generated
2483 mapVertices[vCounter] = v1;
2484 mapVertices[vCounter + 1] = v7;
2485 mapVertices[vCounter + 2] = v2;
2486 mapVertices[vCounter + 3] = v1;
2487 mapVertices[vCounter + 4] = v6;
2488 mapVertices[vCounter + 5] = v7;
2491 mapNormals[nCounter] = n2;
2492 mapNormals[nCounter + 1] = n2;
2493 mapNormals[nCounter + 2] = n2;
2494 mapNormals[nCounter + 3] = n2;
2495 mapNormals[nCounter + 4] = n2;
2496 mapNormals[nCounter + 5] = n2;
2499 mapTexcoords[tcCounter] = (Vector2){ leftTexUV.x, leftTexUV.y };
2500 mapTexcoords[tcCounter + 1] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y + leftTexUV.height };
2501 mapTexcoords[tcCounter + 2] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y };
2502 mapTexcoords[tcCounter + 3] = (Vector2){ leftTexUV.x, leftTexUV.y };
2503 mapTexcoords[tcCounter + 4] = (Vector2){ leftTexUV.x, leftTexUV.y + leftTexUV.height };
2504 mapTexcoords[tcCounter + 5] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y + leftTexUV.height };
2508 // We check pixel color to be BLACK, we will only draw floor and roof
2509 else if (COLOR_EQUAL(pixels[z*cubicmap.width + x], BLACK))
2511 // Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
2512 mapVertices[vCounter] = v1;
2513 mapVertices[vCounter + 1] = v3;
2514 mapVertices[vCounter + 2] = v2;
2515 mapVertices[vCounter + 3] = v1;
2516 mapVertices[vCounter + 4] = v4;
2517 mapVertices[vCounter + 5] = v3;
2520 mapNormals[nCounter] = n4;
2521 mapNormals[nCounter + 1] = n4;
2522 mapNormals[nCounter + 2] = n4;
2523 mapNormals[nCounter + 3] = n4;
2524 mapNormals[nCounter + 4] = n4;
2525 mapNormals[nCounter + 5] = n4;
2528 mapTexcoords[tcCounter] = (Vector2){ topTexUV.x, topTexUV.y };
2529 mapTexcoords[tcCounter + 1] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
2530 mapTexcoords[tcCounter + 2] = (Vector2){ topTexUV.x, topTexUV.y + topTexUV.height };
2531 mapTexcoords[tcCounter + 3] = (Vector2){ topTexUV.x, topTexUV.y };
2532 mapTexcoords[tcCounter + 4] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y };
2533 mapTexcoords[tcCounter + 5] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
2536 // Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8)
2537 mapVertices[vCounter] = v6;
2538 mapVertices[vCounter + 1] = v7;
2539 mapVertices[vCounter + 2] = v8;
2540 mapVertices[vCounter + 3] = v6;
2541 mapVertices[vCounter + 4] = v8;
2542 mapVertices[vCounter + 5] = v5;
2545 mapNormals[nCounter] = n3;
2546 mapNormals[nCounter + 1] = n3;
2547 mapNormals[nCounter + 2] = n3;
2548 mapNormals[nCounter + 3] = n3;
2549 mapNormals[nCounter + 4] = n3;
2550 mapNormals[nCounter + 5] = n3;
2553 mapTexcoords[tcCounter] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
2554 mapTexcoords[tcCounter + 1] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y + bottomTexUV.height };
2555 mapTexcoords[tcCounter + 2] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
2556 mapTexcoords[tcCounter + 3] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
2557 mapTexcoords[tcCounter + 4] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
2558 mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y };
2564 // Move data from mapVertices temp arays to vertices float array
2565 mesh.vertexCount = vCounter;
2566 mesh.triangleCount = vCounter/3;
2568 mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
2569 mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
2570 mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
2575 // Move vertices data
2576 for (int i = 0; i < vCounter; i++)
2578 mesh.vertices[fCounter] = mapVertices[i].x;
2579 mesh.vertices[fCounter + 1] = mapVertices[i].y;
2580 mesh.vertices[fCounter + 2] = mapVertices[i].z;
2586 // Move normals data
2587 for (int i = 0; i < nCounter; i++)
2589 mesh.normals[fCounter] = mapNormals[i].x;
2590 mesh.normals[fCounter + 1] = mapNormals[i].y;
2591 mesh.normals[fCounter + 2] = mapNormals[i].z;
2597 // Move texcoords data
2598 for (int i = 0; i < tcCounter; i++)
2600 mesh.texcoords[fCounter] = mapTexcoords[i].x;
2601 mesh.texcoords[fCounter + 1] = mapTexcoords[i].y;
2605 RL_FREE(mapVertices);
2606 RL_FREE(mapNormals);
2607 RL_FREE(mapTexcoords);
2609 UnloadImageColors(pixels); // Unload pixels color data
2611 // Upload vertex data to GPU (static mesh)
2612 UploadMesh(&mesh, false);
2616 #endif // SUPPORT_MESH_GENERATION
2618 // Compute mesh bounding box limits
2619 // NOTE: minVertex and maxVertex should be transformed by model transform matrix
2620 BoundingBox MeshBoundingBox(Mesh mesh)
2622 // Get min and max vertex to construct bounds (AABB)
2623 Vector3 minVertex = { 0 };
2624 Vector3 maxVertex = { 0 };
2626 if (mesh.vertices != NULL)
2628 minVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] };
2629 maxVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] };
2631 for (int i = 1; i < mesh.vertexCount; i++)
2633 minVertex = Vector3Min(minVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] });
2634 maxVertex = Vector3Max(maxVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] });
2638 // Create the bounding box
2639 BoundingBox box = { 0 };
2640 box.min = minVertex;
2641 box.max = maxVertex;
2646 // Compute mesh tangents
2647 // NOTE: To calculate mesh tangents and binormals we need mesh vertex positions and texture coordinates
2648 // Implementation base don: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html
2649 void MeshTangents(Mesh *mesh)
2651 if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
2652 else TRACELOG(LOG_WARNING, "MESH: Tangents data already available, re-writting");
2654 Vector3 *tan1 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
2655 Vector3 *tan2 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
2657 for (int i = 0; i < mesh->vertexCount; i += 3)
2659 // Get triangle vertices
2660 Vector3 v1 = { mesh->vertices[(i + 0)*3 + 0], mesh->vertices[(i + 0)*3 + 1], mesh->vertices[(i + 0)*3 + 2] };
2661 Vector3 v2 = { mesh->vertices[(i + 1)*3 + 0], mesh->vertices[(i + 1)*3 + 1], mesh->vertices[(i + 1)*3 + 2] };
2662 Vector3 v3 = { mesh->vertices[(i + 2)*3 + 0], mesh->vertices[(i + 2)*3 + 1], mesh->vertices[(i + 2)*3 + 2] };
2664 // Get triangle texcoords
2665 Vector2 uv1 = { mesh->texcoords[(i + 0)*2 + 0], mesh->texcoords[(i + 0)*2 + 1] };
2666 Vector2 uv2 = { mesh->texcoords[(i + 1)*2 + 0], mesh->texcoords[(i + 1)*2 + 1] };
2667 Vector2 uv3 = { mesh->texcoords[(i + 2)*2 + 0], mesh->texcoords[(i + 2)*2 + 1] };
2669 float x1 = v2.x - v1.x;
2670 float y1 = v2.y - v1.y;
2671 float z1 = v2.z - v1.z;
2672 float x2 = v3.x - v1.x;
2673 float y2 = v3.y - v1.y;
2674 float z2 = v3.z - v1.z;
2676 float s1 = uv2.x - uv1.x;
2677 float t1 = uv2.y - uv1.y;
2678 float s2 = uv3.x - uv1.x;
2679 float t2 = uv3.y - uv1.y;
2681 float div = s1*t2 - s2*t1;
2682 float r = (div == 0.0f)? 0.0f : 1.0f/div;
2684 Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r };
2685 Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r };
2696 // Compute tangents considering normals
2697 for (int i = 0; i < mesh->vertexCount; ++i)
2699 Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
2700 Vector3 tangent = tan1[i];
2702 // TODO: Review, not sure if tangent computation is right, just used reference proposed maths...
2703 #if defined(COMPUTE_TANGENTS_METHOD_01)
2704 Vector3 tmp = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent)));
2705 tmp = Vector3Normalize(tmp);
2706 mesh->tangents[i*4 + 0] = tmp.x;
2707 mesh->tangents[i*4 + 1] = tmp.y;
2708 mesh->tangents[i*4 + 2] = tmp.z;
2709 mesh->tangents[i*4 + 3] = 1.0f;
2711 Vector3OrthoNormalize(&normal, &tangent);
2712 mesh->tangents[i*4 + 0] = tangent.x;
2713 mesh->tangents[i*4 + 1] = tangent.y;
2714 mesh->tangents[i*4 + 2] = tangent.z;
2715 mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f)? -1.0f : 1.0f;
2722 // Load a new tangent attributes buffer
2723 mesh->vboId[SHADER_LOC_VERTEX_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), false);
2725 TRACELOG(LOG_INFO, "MESH: Tangents data computed for provided mesh");
2728 // Compute mesh binormals (aka bitangent)
2729 void MeshBinormals(Mesh *mesh)
2731 for (int i = 0; i < mesh->vertexCount; i++)
2733 //Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
2734 //Vector3 tangent = { mesh->tangents[i*4 + 0], mesh->tangents[i*4 + 1], mesh->tangents[i*4 + 2] };
2735 //Vector3 binormal = Vector3Scale(Vector3CrossProduct(normal, tangent), mesh->tangents[i*4 + 3]);
2737 // TODO: Register computed binormal in mesh->binormal?
2741 // Draw a model (with texture if set)
2742 void DrawModel(Model model, Vector3 position, float scale, Color tint)
2744 Vector3 vScale = { scale, scale, scale };
2745 Vector3 rotationAxis = { 0.0f, 1.0f, 0.0f };
2747 DrawModelEx(model, position, rotationAxis, 0.0f, vScale, tint);
2750 // Draw a model with extended parameters
2751 void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
2753 // Calculate transformation matrix from function parameters
2754 // Get transform matrix (rotation -> scale -> translation)
2755 Matrix matScale = MatrixScale(scale.x, scale.y, scale.z);
2756 Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD);
2757 Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
2759 Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
2761 // Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform)
2762 model.transform = MatrixMultiply(model.transform, matTransform);
2764 for (int i = 0; i < model.meshCount; i++)
2766 Color color = model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color;
2768 Color colorTint = WHITE;
2769 colorTint.r = (unsigned char)((((float)color.r/255.0)*((float)tint.r/255.0))*255.0f);
2770 colorTint.g = (unsigned char)((((float)color.g/255.0)*((float)tint.g/255.0))*255.0f);
2771 colorTint.b = (unsigned char)((((float)color.b/255.0)*((float)tint.b/255.0))*255.0f);
2772 colorTint.a = (unsigned char)((((float)color.a/255.0)*((float)tint.a/255.0))*255.0f);
2774 model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = colorTint;
2775 DrawMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform);
2776 model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = color;
2780 // Draw a model wires (with texture if set)
2781 void DrawModelWires(Model model, Vector3 position, float scale, Color tint)
2785 DrawModel(model, position, scale, tint);
2787 rlDisableWireMode();
2790 // Draw a model wires (with texture if set) with extended parameters
2791 void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
2795 DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);
2797 rlDisableWireMode();
2801 void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint)
2803 Rectangle source = { 0.0f, 0.0f, (float)texture.width, (float)texture.height };
2805 DrawBillboardRec(camera, texture, source, center, size, tint);
2808 // Draw a billboard (part of a texture defined by a rectangle)
2809 void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 center, float size, Color tint)
2811 // NOTE: Billboard size will maintain source rectangle aspect ratio, size will represent billboard width
2812 Vector2 sizeRatio = { size, size*(float)source.height/source.width };
2814 Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
2816 Vector3 right = { matView.m0, matView.m4, matView.m8 };
2817 //Vector3 up = { matView.m1, matView.m5, matView.m9 };
2819 // NOTE: Billboard locked on axis-Y
2820 Vector3 up = { 0.0f, 1.0f, 0.0f };
2828 right = Vector3Scale(right, sizeRatio.x/2);
2829 up = Vector3Scale(up, sizeRatio.y/2);
2831 Vector3 p1 = Vector3Add(right, up);
2832 Vector3 p2 = Vector3Subtract(right, up);
2834 Vector3 a = Vector3Subtract(center, p2);
2835 Vector3 b = Vector3Add(center, p1);
2836 Vector3 c = Vector3Add(center, p2);
2837 Vector3 d = Vector3Subtract(center, p1);
2839 rlCheckRenderBatchLimit(4);
2841 rlSetTexture(texture.id);
2844 rlColor4ub(tint.r, tint.g, tint.b, tint.a);
2846 // Bottom-left corner for texture and quad
2847 rlTexCoord2f((float)source.x/texture.width, (float)source.y/texture.height);
2848 rlVertex3f(a.x, a.y, a.z);
2850 // Top-left corner for texture and quad
2851 rlTexCoord2f((float)source.x/texture.width, (float)(source.y + source.height)/texture.height);
2852 rlVertex3f(d.x, d.y, d.z);
2854 // Top-right corner for texture and quad
2855 rlTexCoord2f((float)(source.x + source.width)/texture.width, (float)(source.y + source.height)/texture.height);
2856 rlVertex3f(c.x, c.y, c.z);
2858 // Bottom-right corner for texture and quad
2859 rlTexCoord2f((float)(source.x + source.width)/texture.width, (float)source.y/texture.height);
2860 rlVertex3f(b.x, b.y, b.z);
2866 // Draw a bounding box with wires
2867 void DrawBoundingBox(BoundingBox box, Color color)
2871 size.x = fabsf(box.max.x - box.min.x);
2872 size.y = fabsf(box.max.y - box.min.y);
2873 size.z = fabsf(box.max.z - box.min.z);
2875 Vector3 center = { box.min.x + size.x/2.0f, box.min.y + size.y/2.0f, box.min.z + size.z/2.0f };
2877 DrawCubeWires(center, size.x, size.y, size.z, color);
2880 // Detect collision between two spheres
2881 bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2)
2883 bool collision = false;
2885 // Simple way to check for collision, just checking distance between two points
2886 // Unfortunately, sqrtf() is a costly operation, so we avoid it with following solution
2888 float dx = center1.x - center2.x; // X distance between centers
2889 float dy = center1.y - center2.y; // Y distance between centers
2890 float dz = center1.z - center2.z; // Z distance between centers
2892 float distance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance between centers
2894 if (distance <= (radius1 + radius2)) collision = true;
2897 // Check for distances squared to avoid sqrtf()
2898 if (Vector3DotProduct(Vector3Subtract(center2, center1), Vector3Subtract(center2, center1)) <= (radius1 + radius2)*(radius1 + radius2)) collision = true;
2903 // Detect collision between two boxes
2904 // NOTE: Boxes are defined by two points minimum and maximum
2905 bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2)
2907 bool collision = true;
2909 if ((box1.max.x >= box2.min.x) && (box1.min.x <= box2.max.x))
2911 if ((box1.max.y < box2.min.y) || (box1.min.y > box2.max.y)) collision = false;
2912 if ((box1.max.z < box2.min.z) || (box1.min.z > box2.max.z)) collision = false;
2914 else collision = false;
2919 // Detect collision between box and sphere
2920 bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius)
2922 bool collision = false;
2926 if (center.x < box.min.x) dmin += powf(center.x - box.min.x, 2);
2927 else if (center.x > box.max.x) dmin += powf(center.x - box.max.x, 2);
2929 if (center.y < box.min.y) dmin += powf(center.y - box.min.y, 2);
2930 else if (center.y > box.max.y) dmin += powf(center.y - box.max.y, 2);
2932 if (center.z < box.min.z) dmin += powf(center.z - box.min.z, 2);
2933 else if (center.z > box.max.z) dmin += powf(center.z - box.max.z, 2);
2935 if (dmin <= (radius*radius)) collision = true;
2940 // Detect collision between ray and sphere
2941 bool CheckCollisionRaySphere(Ray ray, Vector3 center, float radius)
2943 bool collision = false;
2945 Vector3 raySpherePos = Vector3Subtract(center, ray.position);
2946 float distance = Vector3Length(raySpherePos);
2947 float vector = Vector3DotProduct(raySpherePos, ray.direction);
2948 float d = radius*radius - (distance*distance - vector*vector);
2950 if (d >= 0.0f) collision = true;
2955 // Detect collision between ray and sphere with extended parameters and collision point detection
2956 bool CheckCollisionRaySphereEx(Ray ray, Vector3 center, float radius, Vector3 *collisionPoint)
2958 bool collision = false;
2960 Vector3 raySpherePos = Vector3Subtract(center, ray.position);
2961 float distance = Vector3Length(raySpherePos);
2962 float vector = Vector3DotProduct(raySpherePos, ray.direction);
2963 float d = radius*radius - (distance*distance - vector*vector);
2965 if (d >= 0.0f) collision = true;
2967 // Check if ray origin is inside the sphere to calculate the correct collision point
2968 float collisionDistance = 0;
2970 if (distance < radius) collisionDistance = vector + sqrtf(d);
2971 else collisionDistance = vector - sqrtf(d);
2973 // Calculate collision point
2974 Vector3 cPoint = Vector3Add(ray.position, Vector3Scale(ray.direction, collisionDistance));
2976 collisionPoint->x = cPoint.x;
2977 collisionPoint->y = cPoint.y;
2978 collisionPoint->z = cPoint.z;
2983 // Detect collision between ray and bounding box
2984 bool CheckCollisionRayBox(Ray ray, BoundingBox box)
2986 bool collision = false;
2989 t[0] = (box.min.x - ray.position.x)/ray.direction.x;
2990 t[1] = (box.max.x - ray.position.x)/ray.direction.x;
2991 t[2] = (box.min.y - ray.position.y)/ray.direction.y;
2992 t[3] = (box.max.y - ray.position.y)/ray.direction.y;
2993 t[4] = (box.min.z - ray.position.z)/ray.direction.z;
2994 t[5] = (box.max.z - ray.position.z)/ray.direction.z;
2995 t[6] = (float)fmax(fmax(fmin(t[0], t[1]), fmin(t[2], t[3])), fmin(t[4], t[5]));
2996 t[7] = (float)fmin(fmin(fmax(t[0], t[1]), fmax(t[2], t[3])), fmax(t[4], t[5]));
2998 collision = !(t[7] < 0 || t[6] > t[7]);
3002 // Get collision info between ray and mesh
3003 RayHitInfo GetCollisionRayMesh(Ray ray, Mesh mesh, Matrix transform)
3005 RayHitInfo result = { 0 };
3007 // Check if mesh vertex data on CPU for testing
3008 if (mesh.vertices != NULL)
3010 int triangleCount = mesh.triangleCount;
3012 // Test against all triangles in mesh
3013 for (int i = 0; i < triangleCount; i++)
3016 Vector3* vertdata = (Vector3*)mesh.vertices;
3020 a = vertdata[mesh.indices[i*3 + 0]];
3021 b = vertdata[mesh.indices[i*3 + 1]];
3022 c = vertdata[mesh.indices[i*3 + 2]];
3026 a = vertdata[i*3 + 0];
3027 b = vertdata[i*3 + 1];
3028 c = vertdata[i*3 + 2];
3031 a = Vector3Transform(a, transform);
3032 b = Vector3Transform(b, transform);
3033 c = Vector3Transform(c, transform);
3035 RayHitInfo triHitInfo = GetCollisionRayTriangle(ray, a, b, c);
3039 // Save the closest hit triangle
3040 if ((!result.hit) || (result.distance > triHitInfo.distance)) result = triHitInfo;
3047 // Get collision info between ray and model
3048 RayHitInfo GetCollisionRayModel(Ray ray, Model model)
3050 RayHitInfo result = { 0 };
3052 for (int m = 0; m < model.meshCount; m++)
3054 RayHitInfo meshHitInfo = GetCollisionRayMesh(ray, model.meshes[m], model.transform);
3056 if (meshHitInfo.hit)
3058 // Save the closest hit mesh
3059 if ((!result.hit) || (result.distance > meshHitInfo.distance)) result = meshHitInfo;
3066 // Get collision info between ray and triangle
3067 // NOTE: Based on https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
3068 RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3)
3070 #define EPSILON 0.000001 // A small number
3072 Vector3 edge1, edge2;
3074 float det, invDet, u, v, t;
3075 RayHitInfo result = {0};
3077 // Find vectors for two edges sharing V1
3078 edge1 = Vector3Subtract(p2, p1);
3079 edge2 = Vector3Subtract(p3, p1);
3081 // Begin calculating determinant - also used to calculate u parameter
3082 p = Vector3CrossProduct(ray.direction, edge2);
3084 // If determinant is near zero, ray lies in plane of triangle or ray is parallel to plane of triangle
3085 det = Vector3DotProduct(edge1, p);
3088 if ((det > -EPSILON) && (det < EPSILON)) return result;
3092 // Calculate distance from V1 to ray origin
3093 tv = Vector3Subtract(ray.position, p1);
3095 // Calculate u parameter and test bound
3096 u = Vector3DotProduct(tv, p)*invDet;
3098 // The intersection lies outside of the triangle
3099 if ((u < 0.0f) || (u > 1.0f)) return result;
3101 // Prepare to test v parameter
3102 q = Vector3CrossProduct(tv, edge1);
3104 // Calculate V parameter and test bound
3105 v = Vector3DotProduct(ray.direction, q)*invDet;
3107 // The intersection lies outside of the triangle
3108 if ((v < 0.0f) || ((u + v) > 1.0f)) return result;
3110 t = Vector3DotProduct(edge2, q)*invDet;
3114 // Ray hit, get hit point and normal
3116 result.distance = t;
3118 result.normal = Vector3Normalize(Vector3CrossProduct(edge1, edge2));
3119 result.position = Vector3Add(ray.position, Vector3Scale(ray.direction, t));
3125 // Get collision info between ray and ground plane (Y-normal plane)
3126 RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight)
3128 #define EPSILON 0.000001 // A small number
3130 RayHitInfo result = { 0 };
3132 if (fabsf(ray.direction.y) > EPSILON)
3134 float distance = (ray.position.y - groundHeight)/-ray.direction.y;
3136 if (distance >= 0.0)
3139 result.distance = distance;
3140 result.normal = (Vector3){ 0.0, 1.0, 0.0 };
3141 result.position = Vector3Add(ray.position, Vector3Scale(ray.direction, distance));
3142 result.position.y = groundHeight;
3149 //----------------------------------------------------------------------------------
3150 // Module specific Functions Definition
3151 //----------------------------------------------------------------------------------
3153 #if defined(SUPPORT_FILEFORMAT_OBJ)
3154 // Load OBJ mesh data
3155 static Model LoadOBJ(const char *fileName)
3157 Model model = { 0 };
3159 tinyobj_attrib_t attrib = { 0 };
3160 tinyobj_shape_t *meshes = NULL;
3161 unsigned int meshCount = 0;
3163 tinyobj_material_t *materials = NULL;
3164 unsigned int materialCount = 0;
3166 char *fileData = LoadFileText(fileName);
3168 if (fileData != NULL)
3170 unsigned int dataSize = (unsigned int)strlen(fileData);
3171 char currentDir[1024] = { 0 };
3172 strcpy(currentDir, GetWorkingDirectory());
3173 const char *workingDir = GetDirectoryPath(fileName);
3174 if (CHDIR(workingDir) != 0)
3176 TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir);
3179 unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;
3180 int ret = tinyobj_parse_obj(&attrib, &meshes, &meshCount, &materials, &materialCount, fileData, dataSize, flags);
3182 if (ret != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load OBJ data", fileName);
3183 else TRACELOG(LOG_INFO, "MODEL: [%s] OBJ data loaded successfully: %i meshes / %i materials", fileName, meshCount, materialCount);
3185 model.meshCount = materialCount;
3187 // Init model materials array
3188 if (materialCount > 0)
3190 model.materialCount = materialCount;
3191 model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
3192 TraceLog(LOG_INFO, "MODEL: model has %i material meshes", materialCount);
3196 model.meshCount = 1;
3197 TraceLog(LOG_INFO, "MODEL: No materials, putting all meshes in a default material");
3200 model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
3201 model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
3203 // count the faces for each material
3204 int *matFaces = RL_CALLOC(meshCount, sizeof(int));
3206 for (unsigned int mi = 0; mi < meshCount; mi++)
3208 for (unsigned int fi = 0; fi < meshes[mi].length; fi++)
3210 int idx = attrib.material_ids[meshes[mi].face_offset + fi];
3211 if (idx == -1) idx = 0; // for no material face (which could be the whole model)
3216 //--------------------------------------
3217 // create the material meshes
3219 // running counts / indexes for each material mesh as we are
3220 // building them at the same time
3221 int *vCount = RL_CALLOC(model.meshCount, sizeof(int));
3222 int *vtCount = RL_CALLOC(model.meshCount, sizeof(int));
3223 int *vnCount = RL_CALLOC(model.meshCount, sizeof(int));
3224 int *faceCount = RL_CALLOC(model.meshCount, sizeof(int));
3226 // allocate space for each of the material meshes
3227 for (int mi = 0; mi < model.meshCount; mi++)
3229 model.meshes[mi].vertexCount = matFaces[mi]*3;
3230 model.meshes[mi].triangleCount = matFaces[mi];
3231 model.meshes[mi].vertices = (float *)RL_CALLOC(model.meshes[mi].vertexCount*3, sizeof(float));
3232 model.meshes[mi].texcoords = (float *)RL_CALLOC(model.meshes[mi].vertexCount*2, sizeof(float));
3233 model.meshes[mi].normals = (float *)RL_CALLOC(model.meshes[mi].vertexCount*3, sizeof(float));
3234 model.meshMaterial[mi] = mi;
3237 // scan through the combined sub meshes and pick out each material mesh
3238 for (unsigned int af = 0; af < attrib.num_faces; af++)
3240 int mm = attrib.material_ids[af]; // mesh material for this face
3241 if (mm == -1) { mm = 0; } // no material object..
3243 // Get indices for the face
3244 tinyobj_vertex_index_t idx0 = attrib.faces[3*af + 0];
3245 tinyobj_vertex_index_t idx1 = attrib.faces[3*af + 1];
3246 tinyobj_vertex_index_t idx2 = attrib.faces[3*af + 2];
3248 // Fill vertices buffer (float) using vertex index of the face
3249 for (int v = 0; v < 3; v++) { model.meshes[mm].vertices[vCount[mm] + v] = attrib.vertices[idx0.v_idx*3 + v]; } vCount[mm] +=3;
3250 for (int v = 0; v < 3; v++) { model.meshes[mm].vertices[vCount[mm] + v] = attrib.vertices[idx1.v_idx*3 + v]; } vCount[mm] +=3;
3251 for (int v = 0; v < 3; v++) { model.meshes[mm].vertices[vCount[mm] + v] = attrib.vertices[idx2.v_idx*3 + v]; } vCount[mm] +=3;
3253 if (attrib.num_texcoords > 0)
3255 // Fill texcoords buffer (float) using vertex index of the face
3256 // NOTE: Y-coordinate must be flipped upside-down to account for
3257 // raylib's upside down textures...
3258 model.meshes[mm].texcoords[vtCount[mm] + 0] = attrib.texcoords[idx0.vt_idx*2 + 0];
3259 model.meshes[mm].texcoords[vtCount[mm] + 1] = 1.0f - attrib.texcoords[idx0.vt_idx*2 + 1]; vtCount[mm] += 2;
3260 model.meshes[mm].texcoords[vtCount[mm] + 0] = attrib.texcoords[idx1.vt_idx*2 + 0];
3261 model.meshes[mm].texcoords[vtCount[mm] + 1] = 1.0f - attrib.texcoords[idx1.vt_idx*2 + 1]; vtCount[mm] += 2;
3262 model.meshes[mm].texcoords[vtCount[mm] + 0] = attrib.texcoords[idx2.vt_idx*2 + 0];
3263 model.meshes[mm].texcoords[vtCount[mm] + 1] = 1.0f - attrib.texcoords[idx2.vt_idx*2 + 1]; vtCount[mm] += 2;
3266 if (attrib.num_normals > 0)
3268 // Fill normals buffer (float) using vertex index of the face
3269 for (int v = 0; v < 3; v++) { model.meshes[mm].normals[vnCount[mm] + v] = attrib.normals[idx0.vn_idx*3 + v]; } vnCount[mm] +=3;
3270 for (int v = 0; v < 3; v++) { model.meshes[mm].normals[vnCount[mm] + v] = attrib.normals[idx1.vn_idx*3 + v]; } vnCount[mm] +=3;
3271 for (int v = 0; v < 3; v++) { model.meshes[mm].normals[vnCount[mm] + v] = attrib.normals[idx2.vn_idx*3 + v]; } vnCount[mm] +=3;
3275 // Init model materials
3276 for (unsigned int m = 0; m < materialCount; m++)
3278 // Init material to default
3279 // NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE
3280 model.materials[m] = LoadMaterialDefault();
3282 model.materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = rlGetTextureDefault(); // Get default texture, in case no texture is defined
3284 if (materials[m].diffuse_texname != NULL) model.materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture(materials[m].diffuse_texname); //char *diffuse_texname; // map_Kd
3285 else model.materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = rlGetTextureDefault();
3287 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];
3288 model.materials[m].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f;
3290 if (materials[m].specular_texname != NULL) model.materials[m].maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture(materials[m].specular_texname); //char *specular_texname; // map_Ks
3291 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];
3292 model.materials[m].maps[MATERIAL_MAP_SPECULAR].value = 0.0f;
3294 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
3295 model.materials[m].maps[MATERIAL_MAP_NORMAL].color = WHITE;
3296 model.materials[m].maps[MATERIAL_MAP_NORMAL].value = materials[m].shininess;
3298 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];
3300 if (materials[m].displacement_texname != NULL) model.materials[m].maps[MATERIAL_MAP_HEIGHT].texture = LoadTexture(materials[m].displacement_texname); //char *displacement_texname; // disp
3303 tinyobj_attrib_free(&attrib);
3304 tinyobj_shapes_free(meshes, meshCount);
3305 tinyobj_materials_free(materials, materialCount);
3315 if (CHDIR(currentDir) != 0)
3317 TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", currentDir);
3325 #if defined(SUPPORT_FILEFORMAT_IQM)
3326 // Load IQM mesh data
3327 static Model LoadIQM(const char *fileName)
3329 #define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number
3330 #define IQM_VERSION 2 // only IQM version 2 supported
3332 #define BONE_NAME_LENGTH 32 // BoneInfo name string length
3333 #define MESH_NAME_LENGTH 32 // Mesh name string length
3334 #define MATERIAL_NAME_LENGTH 32 // Material name string length
3336 unsigned int fileSize = 0;
3337 unsigned char *fileData = LoadFileData(fileName, &fileSize);
3338 unsigned char *fileDataPtr = fileData;
3341 //-----------------------------------------------------------------------------------
3342 typedef struct IQMHeader {
3344 unsigned int version;
3345 unsigned int filesize;
3347 unsigned int num_text, ofs_text;
3348 unsigned int num_meshes, ofs_meshes;
3349 unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
3350 unsigned int num_triangles, ofs_triangles, ofs_adjacency;
3351 unsigned int num_joints, ofs_joints;
3352 unsigned int num_poses, ofs_poses;
3353 unsigned int num_anims, ofs_anims;
3354 unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
3355 unsigned int num_comment, ofs_comment;
3356 unsigned int num_extensions, ofs_extensions;
3359 typedef struct IQMMesh {
3361 unsigned int material;
3362 unsigned int first_vertex, num_vertexes;
3363 unsigned int first_triangle, num_triangles;
3366 typedef struct IQMTriangle {
3367 unsigned int vertex[3];
3370 typedef struct IQMJoint {
3373 float translate[3], rotate[4], scale[3];
3376 typedef struct IQMVertexArray {
3379 unsigned int format;
3381 unsigned int offset;
3384 // NOTE: Below IQM structures are not used but listed for reference
3386 typedef struct IQMAdjacency {
3387 unsigned int triangle[3];
3390 typedef struct IQMPose {
3393 float channeloffset[10];
3394 float channelscale[10];
3397 typedef struct IQMAnim {
3399 unsigned int first_frame, num_frames;
3404 typedef struct IQMBounds {
3405 float bbmin[3], bbmax[3];
3406 float xyradius, radius;
3409 //-----------------------------------------------------------------------------------
3411 // IQM vertex data types
3416 IQM_TANGENT = 3, // NOTE: Tangents unused by default
3417 IQM_BLENDINDEXES = 4,
3418 IQM_BLENDWEIGHTS = 5,
3419 IQM_COLOR = 6, // NOTE: Vertex colors unused by default
3420 IQM_CUSTOM = 0x10 // NOTE: Custom vertex values unused by default
3423 Model model = { 0 };
3425 IQMMesh *imesh = NULL;
3426 IQMTriangle *tri = NULL;
3427 IQMVertexArray *va = NULL;
3428 IQMJoint *ijoint = NULL;
3430 float *vertex = NULL;
3431 float *normal = NULL;
3433 char *blendi = NULL;
3434 unsigned char *blendw = NULL;
3436 // In case file can not be read, return an empty model
3437 if (fileDataPtr == NULL) return model;
3440 IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr;
3442 if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0)
3444 TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
3448 if (iqmHeader->version != IQM_VERSION)
3450 TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version);
3454 //fileDataPtr += sizeof(IQMHeader); // Move file data pointer
3456 // Meshes data processing
3457 imesh = RL_MALLOC(sizeof(IQMMesh)*iqmHeader->num_meshes);
3458 //fseek(iqmFile, iqmHeader->ofs_meshes, SEEK_SET);
3459 //fread(imesh, sizeof(IQMMesh)*iqmHeader->num_meshes, 1, iqmFile);
3460 memcpy(imesh, fileDataPtr + iqmHeader->ofs_meshes, iqmHeader->num_meshes*sizeof(IQMMesh));
3462 model.meshCount = iqmHeader->num_meshes;
3463 model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
3465 model.materialCount = model.meshCount;
3466 model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
3467 model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
3469 char name[MESH_NAME_LENGTH] = { 0 };
3470 char material[MATERIAL_NAME_LENGTH] = { 0 };
3472 for (int i = 0; i < model.meshCount; i++)
3474 //fseek(iqmFile, iqmHeader->ofs_text + imesh[i].name, SEEK_SET);
3475 //fread(name, sizeof(char)*MESH_NAME_LENGTH, 1, iqmFile);
3476 memcpy(name, fileDataPtr + iqmHeader->ofs_text + imesh[i].name, MESH_NAME_LENGTH*sizeof(char));
3478 //fseek(iqmFile, iqmHeader->ofs_text + imesh[i].material, SEEK_SET);
3479 //fread(material, sizeof(char)*MATERIAL_NAME_LENGTH, 1, iqmFile);
3480 memcpy(material, fileDataPtr + iqmHeader->ofs_text + imesh[i].material, MATERIAL_NAME_LENGTH*sizeof(char));
3482 model.materials[i] = LoadMaterialDefault();
3484 TRACELOG(LOG_DEBUG, "MODEL: [%s] mesh name (%s), material (%s)", fileName, name, material);
3486 model.meshes[i].vertexCount = imesh[i].num_vertexes;
3488 model.meshes[i].vertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex positions
3489 model.meshes[i].normals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex normals
3490 model.meshes[i].texcoords = RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float)); // Default vertex texcoords
3492 model.meshes[i].boneIds = RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float)); // Up-to 4 bones supported!
3493 model.meshes[i].boneWeights = RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float)); // Up-to 4 bones supported!
3495 model.meshes[i].triangleCount = imesh[i].num_triangles;
3496 model.meshes[i].indices = RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short));
3498 // Animated verted data, what we actually process for rendering
3499 // NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning)
3500 model.meshes[i].animVertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
3501 model.meshes[i].animNormals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
3504 // Triangles data processing
3505 tri = RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle));
3506 //fseek(iqmFile, iqmHeader->ofs_triangles, SEEK_SET);
3507 //fread(tri, iqmHeader->num_triangles*sizeof(IQMTriangle), 1, iqmFile);
3508 memcpy(tri, fileDataPtr + iqmHeader->ofs_triangles, iqmHeader->num_triangles*sizeof(IQMTriangle));
3510 for (int m = 0; m < model.meshCount; m++)
3514 for (unsigned int i = imesh[m].first_triangle; i < (imesh[m].first_triangle + imesh[m].num_triangles); i++)
3516 // IQM triangles indexes are stored in counter-clockwise, but raylib processes the index in linear order,
3517 // expecting they point to the counter-clockwise vertex triangle, so we need to reverse triangle indexes
3518 // NOTE: raylib renders vertex data in counter-clockwise order (standard convention) by default
3519 model.meshes[m].indices[tcounter + 2] = tri[i].vertex[0] - imesh[m].first_vertex;
3520 model.meshes[m].indices[tcounter + 1] = tri[i].vertex[1] - imesh[m].first_vertex;
3521 model.meshes[m].indices[tcounter] = tri[i].vertex[2] - imesh[m].first_vertex;
3526 // Vertex arrays data processing
3527 va = RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
3528 //fseek(iqmFile, iqmHeader->ofs_vertexarrays, SEEK_SET);
3529 //fread(va, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray), 1, iqmFile);
3530 memcpy(va, fileDataPtr + iqmHeader->ofs_vertexarrays, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
3532 for (unsigned int i = 0; i < iqmHeader->num_vertexarrays; i++)
3538 vertex = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
3539 //fseek(iqmFile, va[i].offset, SEEK_SET);
3540 //fread(vertex, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
3541 memcpy(vertex, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
3543 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
3546 for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
3548 model.meshes[m].vertices[vCounter] = vertex[i];
3549 model.meshes[m].animVertices[vCounter] = vertex[i];
3556 normal = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
3557 //fseek(iqmFile, va[i].offset, SEEK_SET);
3558 //fread(normal, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
3559 memcpy(normal, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
3561 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
3564 for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
3566 model.meshes[m].normals[vCounter] = normal[i];
3567 model.meshes[m].animNormals[vCounter] = normal[i];
3574 text = RL_MALLOC(iqmHeader->num_vertexes*2*sizeof(float));
3575 //fseek(iqmFile, va[i].offset, SEEK_SET);
3576 //fread(text, iqmHeader->num_vertexes*2*sizeof(float), 1, iqmFile);
3577 memcpy(text, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*2*sizeof(float));
3579 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
3582 for (unsigned int i = imesh[m].first_vertex*2; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*2; i++)
3584 model.meshes[m].texcoords[vCounter] = text[i];
3589 case IQM_BLENDINDEXES:
3591 blendi = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(char));
3592 //fseek(iqmFile, va[i].offset, SEEK_SET);
3593 //fread(blendi, iqmHeader->num_vertexes*4*sizeof(char), 1, iqmFile);
3594 memcpy(blendi, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(char));
3596 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
3598 int boneCounter = 0;
3599 for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
3601 model.meshes[m].boneIds[boneCounter] = blendi[i];
3606 case IQM_BLENDWEIGHTS:
3608 blendw = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
3609 //fseek(iqmFile, va[i].offset, SEEK_SET);
3610 //fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
3611 memcpy(blendw, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
3613 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
3615 int boneCounter = 0;
3616 for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
3618 model.meshes[m].boneWeights[boneCounter] = blendw[i]/255.0f;
3626 // Bones (joints) data processing
3627 ijoint = RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
3628 //fseek(iqmFile, iqmHeader->ofs_joints, SEEK_SET);
3629 //fread(ijoint, iqmHeader->num_joints*sizeof(IQMJoint), 1, iqmFile);
3630 memcpy(ijoint, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
3632 model.boneCount = iqmHeader->num_joints;
3633 model.bones = RL_MALLOC(iqmHeader->num_joints*sizeof(BoneInfo));
3634 model.bindPose = RL_MALLOC(iqmHeader->num_joints*sizeof(Transform));
3636 for (unsigned int i = 0; i < iqmHeader->num_joints; i++)
3639 model.bones[i].parent = ijoint[i].parent;
3640 //fseek(iqmFile, iqmHeader->ofs_text + ijoint[i].name, SEEK_SET);
3641 //fread(model.bones[i].name, BONE_NAME_LENGTH*sizeof(char), 1, iqmFile);
3642 memcpy(model.bones[i].name, fileDataPtr + iqmHeader->ofs_text + ijoint[i].name, BONE_NAME_LENGTH*sizeof(char));
3644 // Bind pose (base pose)
3645 model.bindPose[i].translation.x = ijoint[i].translate[0];
3646 model.bindPose[i].translation.y = ijoint[i].translate[1];
3647 model.bindPose[i].translation.z = ijoint[i].translate[2];
3649 model.bindPose[i].rotation.x = ijoint[i].rotate[0];
3650 model.bindPose[i].rotation.y = ijoint[i].rotate[1];
3651 model.bindPose[i].rotation.z = ijoint[i].rotate[2];
3652 model.bindPose[i].rotation.w = ijoint[i].rotate[3];
3654 model.bindPose[i].scale.x = ijoint[i].scale[0];
3655 model.bindPose[i].scale.y = ijoint[i].scale[1];
3656 model.bindPose[i].scale.z = ijoint[i].scale[2];
3659 // Build bind pose from parent joints
3660 for (int i = 0; i < model.boneCount; i++)
3662 if (model.bones[i].parent >= 0)
3664 model.bindPose[i].rotation = QuaternionMultiply(model.bindPose[model.bones[i].parent].rotation, model.bindPose[i].rotation);
3665 model.bindPose[i].translation = Vector3RotateByQuaternion(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].rotation);
3666 model.bindPose[i].translation = Vector3Add(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].translation);
3667 model.bindPose[i].scale = Vector3Multiply(model.bindPose[i].scale, model.bindPose[model.bones[i].parent].scale);
3686 // Load IQM animation data
3687 static ModelAnimation* LoadIQMModelAnimations(const char* fileName, int* animCount)
3689 #define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number
3690 #define IQM_VERSION 2 // only IQM version 2 supported
3692 unsigned int fileSize = 0;
3693 unsigned char *fileData = LoadFileData(fileName, &fileSize);
3694 unsigned char *fileDataPtr = fileData;
3696 typedef struct IQMHeader {
3698 unsigned int version;
3699 unsigned int filesize;
3701 unsigned int num_text, ofs_text;
3702 unsigned int num_meshes, ofs_meshes;
3703 unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
3704 unsigned int num_triangles, ofs_triangles, ofs_adjacency;
3705 unsigned int num_joints, ofs_joints;
3706 unsigned int num_poses, ofs_poses;
3707 unsigned int num_anims, ofs_anims;
3708 unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
3709 unsigned int num_comment, ofs_comment;
3710 unsigned int num_extensions, ofs_extensions;
3713 typedef struct IQMPose {
3716 float channeloffset[10];
3717 float channelscale[10];
3720 typedef struct IQMAnim {
3722 unsigned int first_frame, num_frames;
3727 // In case file can not be read, return an empty model
3728 if (fileDataPtr == NULL) return NULL;
3731 IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr;
3733 if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0)
3735 TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
3739 if (iqmHeader->version != IQM_VERSION)
3741 TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version);
3746 IQMPose *poses = RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose));
3747 //fseek(iqmFile, iqmHeader->ofs_poses, SEEK_SET);
3748 //fread(poses, iqmHeader->num_poses*sizeof(IQMPose), 1, iqmFile);
3749 memcpy(poses, fileDataPtr + iqmHeader->ofs_poses, iqmHeader->num_poses*sizeof(IQMPose));
3751 // Get animations data
3752 *animCount = iqmHeader->num_anims;
3753 IQMAnim *anim = RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim));
3754 //fseek(iqmFile, iqmHeader->ofs_anims, SEEK_SET);
3755 //fread(anim, iqmHeader->num_anims*sizeof(IQMAnim), 1, iqmFile);
3756 memcpy(anim, fileDataPtr + iqmHeader->ofs_anims, iqmHeader->num_anims*sizeof(IQMAnim));
3758 ModelAnimation *animations = RL_MALLOC(iqmHeader->num_anims*sizeof(ModelAnimation));
3761 unsigned short *framedata = RL_MALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
3762 //fseek(iqmFile, iqmHeader->ofs_frames, SEEK_SET);
3763 //fread(framedata, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short), 1, iqmFile);
3764 memcpy(framedata, fileDataPtr + iqmHeader->ofs_frames, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
3766 for (unsigned int a = 0; a < iqmHeader->num_anims; a++)
3768 animations[a].frameCount = anim[a].num_frames;
3769 animations[a].boneCount = iqmHeader->num_poses;
3770 animations[a].bones = RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo));
3771 animations[a].framePoses = RL_MALLOC(anim[a].num_frames*sizeof(Transform *));
3772 // animations[a].framerate = anim.framerate; // TODO: Use framerate?
3774 for (unsigned int j = 0; j < iqmHeader->num_poses; j++)
3776 strcpy(animations[a].bones[j].name, "ANIMJOINTNAME");
3777 animations[a].bones[j].parent = poses[j].parent;
3780 for (unsigned int j = 0; j < anim[a].num_frames; j++) animations[a].framePoses[j] = RL_MALLOC(iqmHeader->num_poses*sizeof(Transform));
3782 int dcounter = anim[a].first_frame*iqmHeader->num_framechannels;
3784 for (unsigned int frame = 0; frame < anim[a].num_frames; frame++)
3786 for (unsigned int i = 0; i < iqmHeader->num_poses; i++)
3788 animations[a].framePoses[frame][i].translation.x = poses[i].channeloffset[0];
3790 if (poses[i].mask & 0x01)
3792 animations[a].framePoses[frame][i].translation.x += framedata[dcounter]*poses[i].channelscale[0];
3796 animations[a].framePoses[frame][i].translation.y = poses[i].channeloffset[1];
3798 if (poses[i].mask & 0x02)
3800 animations[a].framePoses[frame][i].translation.y += framedata[dcounter]*poses[i].channelscale[1];
3804 animations[a].framePoses[frame][i].translation.z = poses[i].channeloffset[2];
3806 if (poses[i].mask & 0x04)
3808 animations[a].framePoses[frame][i].translation.z += framedata[dcounter]*poses[i].channelscale[2];
3812 animations[a].framePoses[frame][i].rotation.x = poses[i].channeloffset[3];
3814 if (poses[i].mask & 0x08)
3816 animations[a].framePoses[frame][i].rotation.x += framedata[dcounter]*poses[i].channelscale[3];
3820 animations[a].framePoses[frame][i].rotation.y = poses[i].channeloffset[4];
3822 if (poses[i].mask & 0x10)
3824 animations[a].framePoses[frame][i].rotation.y += framedata[dcounter]*poses[i].channelscale[4];
3828 animations[a].framePoses[frame][i].rotation.z = poses[i].channeloffset[5];
3830 if (poses[i].mask & 0x20)
3832 animations[a].framePoses[frame][i].rotation.z += framedata[dcounter]*poses[i].channelscale[5];
3836 animations[a].framePoses[frame][i].rotation.w = poses[i].channeloffset[6];
3838 if (poses[i].mask & 0x40)
3840 animations[a].framePoses[frame][i].rotation.w += framedata[dcounter]*poses[i].channelscale[6];
3844 animations[a].framePoses[frame][i].scale.x = poses[i].channeloffset[7];
3846 if (poses[i].mask & 0x80)
3848 animations[a].framePoses[frame][i].scale.x += framedata[dcounter]*poses[i].channelscale[7];
3852 animations[a].framePoses[frame][i].scale.y = poses[i].channeloffset[8];
3854 if (poses[i].mask & 0x100)
3856 animations[a].framePoses[frame][i].scale.y += framedata[dcounter]*poses[i].channelscale[8];
3860 animations[a].framePoses[frame][i].scale.z = poses[i].channeloffset[9];
3862 if (poses[i].mask & 0x200)
3864 animations[a].framePoses[frame][i].scale.z += framedata[dcounter]*poses[i].channelscale[9];
3868 animations[a].framePoses[frame][i].rotation = QuaternionNormalize(animations[a].framePoses[frame][i].rotation);
3873 for (unsigned int frame = 0; frame < anim[a].num_frames; frame++)
3875 for (int i = 0; i < animations[a].boneCount; i++)
3877 if (animations[a].bones[i].parent >= 0)
3879 animations[a].framePoses[frame][i].rotation = QuaternionMultiply(animations[a].framePoses[frame][animations[a].bones[i].parent].rotation, animations[a].framePoses[frame][i].rotation);
3880 animations[a].framePoses[frame][i].translation = Vector3RotateByQuaternion(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].rotation);
3881 animations[a].framePoses[frame][i].translation = Vector3Add(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].translation);
3882 animations[a].framePoses[frame][i].scale = Vector3Multiply(animations[a].framePoses[frame][i].scale, animations[a].framePoses[frame][animations[a].bones[i].parent].scale);
3899 #if defined(SUPPORT_FILEFORMAT_GLTF)
3901 static const unsigned char base64Table[] = {
3902 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3903 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3904 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3905 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3906 0, 0, 0, 62, 0, 0, 0, 63, 52, 53,
3907 54, 55, 56, 57, 58, 59, 60, 61, 0, 0,
3908 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
3909 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
3910 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
3911 25, 0, 0, 0, 0, 0, 0, 26, 27, 28,
3912 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
3913 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
3917 static int GetSizeBase64(char *input)
3921 for (int i = 0; input[4*i] != 0; i++)
3923 if (input[4*i + 3] == '=')
3925 if (input[4*i + 2] == '=') size += 1;
3934 static unsigned char *DecodeBase64(char *input, int *size)
3936 *size = GetSizeBase64(input);
3938 unsigned char *buf = (unsigned char *)RL_MALLOC(*size);
3939 for (int i = 0; i < *size/3; i++)
3941 unsigned char a = base64Table[(int)input[4*i]];
3942 unsigned char b = base64Table[(int)input[4*i + 1]];
3943 unsigned char c = base64Table[(int)input[4*i + 2]];
3944 unsigned char d = base64Table[(int)input[4*i + 3]];
3946 buf[3*i] = (a << 2) | (b >> 4);
3947 buf[3*i + 1] = (b << 4) | (c >> 2);
3948 buf[3*i + 2] = (c << 6) | d;
3954 unsigned char a = base64Table[(int)input[4*n]];
3955 unsigned char b = base64Table[(int)input[4*n + 1]];
3956 buf[*size - 1] = (a << 2) | (b >> 4);
3958 else if (*size%3 == 2)
3961 unsigned char a = base64Table[(int)input[4*n]];
3962 unsigned char b = base64Table[(int)input[4*n + 1]];
3963 unsigned char c = base64Table[(int)input[4*n + 2]];
3964 buf[*size - 2] = (a << 2) | (b >> 4);
3965 buf[*size - 1] = (b << 4) | (c >> 2);
3970 // Load texture from cgltf_image
3971 static Image LoadImageFromCgltfImage(cgltf_image *image, const char *texPath, Color tint)
3973 Image rimage = { 0 };
3977 if ((strlen(image->uri) > 5) &&
3978 (image->uri[0] == 'd') &&
3979 (image->uri[1] == 'a') &&
3980 (image->uri[2] == 't') &&
3981 (image->uri[3] == 'a') &&
3982 (image->uri[4] == ':'))
3985 // Format: data:<mediatype>;base64,<data>
3989 while ((image->uri[i] != ',') && (image->uri[i] != 0)) i++;
3991 if (image->uri[i] == 0) TRACELOG(LOG_WARNING, "IMAGE: glTF data URI is not a valid image");
3995 unsigned char *data = DecodeBase64(image->uri + i + 1, &size);
3998 unsigned char *raw = stbi_load_from_memory(data, size, &width, &height, NULL, 4);
4002 rimage.width = width;
4003 rimage.height = height;
4004 rimage.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
4007 // TODO: Tint shouldn't be applied here!
4008 ImageColorTint(&rimage, tint);
4013 rimage = LoadImage(TextFormat("%s/%s", texPath, image->uri));
4015 // TODO: Tint shouldn't be applied here!
4016 ImageColorTint(&rimage, tint);
4019 else if (image->buffer_view)
4021 unsigned char *data = RL_MALLOC(image->buffer_view->size);
4022 int n = (int)image->buffer_view->offset;
4023 int stride = (int)image->buffer_view->stride ? (int)image->buffer_view->stride : 1;
4025 for (unsigned int i = 0; i < image->buffer_view->size; i++)
4027 data[i] = ((unsigned char *)image->buffer_view->buffer->data)[n];
4032 unsigned char *raw = stbi_load_from_memory(data, (int)image->buffer_view->size, &width, &height, NULL, 4);
4036 rimage.width = width;
4037 rimage.height = height;
4038 rimage.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
4041 // TODO: Tint shouldn't be applied here!
4042 ImageColorTint(&rimage, tint);
4044 else rimage = GenImageColor(1, 1, tint);
4050 static bool GLTFReadValue(cgltf_accessor* acc, unsigned int index, void *variable, unsigned int elements, unsigned int size)
4052 if (acc->count == 2)
4054 if (index > 1) return false;
4056 memcpy(variable, index == 0 ? acc->min : acc->max, elements*size);
4060 unsigned int stride = size*elements;
4061 memset(variable, 0, stride);
4063 if (acc->buffer_view == NULL || acc->buffer_view->buffer == NULL || acc->buffer_view->buffer->data == NULL) return false;
4065 void* readPosition = ((char *)acc->buffer_view->buffer->data) + (index*stride) + acc->buffer_view->offset + acc->offset;
4066 memcpy(variable, readPosition, stride);
4070 // LoadGLTF loads in model data from given filename, supporting both .gltf and .glb
4071 static Model LoadGLTF(const char *fileName)
4073 /***********************************************************************************
4075 Function implemented by Wilhem Barbier(@wbrbr), with modifications by Tyler Bezera(@gamerfiend) and Hristo Stamenov(@object71)
4078 - Supports .gltf and .glb files
4079 - Supports embedded (base64) or external textures
4080 - Loads all raylib supported material textures, values and colors
4081 - Supports multiple mesh per model and multiple primitives per model
4083 Some restrictions (not exhaustive):
4084 - Triangle-only meshes
4085 - Not supported node hierarchies or transforms
4086 - Only supports unsigned short indices (no byte/unsigned int)
4087 - Only supports float for texture coordinates (no byte/unsigned short)
4089 *************************************************************************************/
4091 Model model = { 0 };
4093 // glTF file loading
4094 unsigned int dataSize = 0;
4095 unsigned char *fileData = LoadFileData(fileName, &dataSize);
4097 if (fileData == NULL) return model;
4099 // glTF data loading
4100 cgltf_options options = { 0 };
4101 cgltf_data *data = NULL;
4102 cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data);
4104 if (result == cgltf_result_success)
4106 TRACELOG(LOG_INFO, "MODEL: [%s] glTF meshes (%s) count: %i", fileName, (data->file_type == 2)? "glb" : "gltf", data->meshes_count);
4107 TRACELOG(LOG_INFO, "MODEL: [%s] glTF materials (%s) count: %i", fileName, (data->file_type == 2)? "glb" : "gltf", data->materials_count);
4109 // Read data buffers
4110 result = cgltf_load_buffers(&options, data, fileName);
4111 if (result != cgltf_result_success) TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load mesh/material buffers", fileName);
4113 int primitivesCount = 0;
4115 for (unsigned int i = 0; i < data->meshes_count; i++)
4116 primitivesCount += (int)data->meshes[i].primitives_count;
4118 // Process glTF data and map to model
4119 model.meshCount = primitivesCount;
4120 model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
4121 model.materialCount = (int)data->materials_count + 1;
4122 model.materials = RL_MALLOC(model.materialCount*sizeof(Material));
4123 model.meshMaterial = RL_MALLOC(model.meshCount*sizeof(int));
4124 model.boneCount = (int)data->nodes_count;
4125 model.bones = RL_CALLOC(model.boneCount, sizeof(BoneInfo));
4126 model.bindPose = RL_CALLOC(model.boneCount, sizeof(Transform));
4128 InitGLTFBones(&model, data);
4129 LoadGLTFMaterial(&model, fileName, data);
4131 int primitiveIndex = 0;
4133 for (unsigned int i = 0; i < data->meshes_count; i++)
4135 for (unsigned int p = 0; p < data->meshes[i].primitives_count; p++)
4137 for (unsigned int j = 0; j < data->meshes[i].primitives[p].attributes_count; j++)
4139 if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_position)
4141 cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data;
4142 model.meshes[primitiveIndex].vertexCount = (int)acc->count;
4143 int bufferSize = model.meshes[primitiveIndex].vertexCount*3*sizeof(float);
4144 model.meshes[primitiveIndex].vertices = RL_MALLOC(bufferSize);
4145 model.meshes[primitiveIndex].animVertices = RL_MALLOC(bufferSize);
4147 if (acc->component_type == cgltf_component_type_r_32f)
4149 for (int a = 0; a < acc->count; a++)
4151 GLTFReadValue(acc, a, model.meshes[primitiveIndex].vertices + (a*3), 3, sizeof(float));
4154 else if (acc->component_type == cgltf_component_type_r_32u)
4157 for (int a = 0; a < acc->count; a++)
4159 GLTFReadValue(acc, a, readValue, 3, sizeof(int));
4160 model.meshes[primitiveIndex].vertices[(a*3) + 0] = (float)readValue[0];
4161 model.meshes[primitiveIndex].vertices[(a*3) + 1] = (float)readValue[1];
4162 model.meshes[primitiveIndex].vertices[(a*3) + 2] = (float)readValue[2];
4167 // TODO: Support normalized unsigned byte/unsigned short vertices
4168 TRACELOG(LOG_WARNING, "MODEL: [%s] glTF vertices must be float or int", fileName);
4171 memcpy(model.meshes[primitiveIndex].animVertices, model.meshes[primitiveIndex].vertices, bufferSize);
4173 else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_normal)
4175 cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data;
4177 int bufferSize = (int)(acc->count*3*sizeof(float));
4178 model.meshes[primitiveIndex].normals = RL_MALLOC(bufferSize);
4179 model.meshes[primitiveIndex].animNormals = RL_MALLOC(bufferSize);
4181 if (acc->component_type == cgltf_component_type_r_32f)
4183 for (int a = 0; a < acc->count; a++)
4185 GLTFReadValue(acc, a, model.meshes[primitiveIndex].normals + (a*3), 3, sizeof(float));
4188 else if (acc->component_type == cgltf_component_type_r_32u)
4191 for (int a = 0; a < acc->count; a++)
4193 GLTFReadValue(acc, a, readValue, 3, sizeof(int));
4194 model.meshes[primitiveIndex].normals[(a*3) + 0] = (float)readValue[0];
4195 model.meshes[primitiveIndex].normals[(a*3) + 1] = (float)readValue[1];
4196 model.meshes[primitiveIndex].normals[(a*3) + 2] = (float)readValue[2];
4201 // TODO: Support normalized unsigned byte/unsigned short normals
4202 TRACELOG(LOG_WARNING, "MODEL: [%s] glTF normals must be float or int", fileName);
4205 memcpy(model.meshes[primitiveIndex].animNormals, model.meshes[primitiveIndex].normals, bufferSize);
4207 else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_texcoord)
4209 cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data;
4211 if (acc->component_type == cgltf_component_type_r_32f)
4213 model.meshes[primitiveIndex].texcoords = RL_MALLOC(acc->count*2*sizeof(float));
4215 for (int a = 0; a < acc->count; a++)
4217 GLTFReadValue(acc, a, model.meshes[primitiveIndex].texcoords + (a*2), 2, sizeof(float));
4222 // TODO: Support normalized unsigned byte/unsigned short texture coordinates
4223 TRACELOG(LOG_WARNING, "MODEL: [%s] glTF texture coordinates must be float", fileName);
4226 else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_joints)
4228 cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data;
4229 LoadGLTFBoneAttribute(&model, acc, data, primitiveIndex);
4231 else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_weights)
4233 cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data;
4235 model.meshes[primitiveIndex].boneWeights = RL_MALLOC(acc->count*4*sizeof(float));
4237 if (acc->component_type == cgltf_component_type_r_32f)
4239 for (int a = 0; a < acc->count; a++)
4241 GLTFReadValue(acc, a, model.meshes[primitiveIndex].boneWeights + (a*4), 4, sizeof(float));
4244 else if (acc->component_type == cgltf_component_type_r_32u)
4246 unsigned int readValue[4];
4247 for (int a = 0; a < acc->count; a++)
4249 GLTFReadValue(acc, a, readValue, 4, sizeof(unsigned int));
4250 model.meshes[primitiveIndex].normals[(a*4) + 0] = (float)readValue[0];
4251 model.meshes[primitiveIndex].normals[(a*4) + 1] = (float)readValue[1];
4252 model.meshes[primitiveIndex].normals[(a*4) + 2] = (float)readValue[2];
4253 model.meshes[primitiveIndex].normals[(a*4) + 3] = (float)readValue[3];
4258 // TODO: Support normalized unsigned byte/unsigned short weights
4259 TRACELOG(LOG_WARNING, "MODEL: [%s] glTF normals must be float or int", fileName);
4264 cgltf_accessor *acc = data->meshes[i].primitives[p].indices;
4265 LoadGLTFModelIndices(&model, acc, primitiveIndex);
4267 if (data->meshes[i].primitives[p].material)
4269 // Compute the offset
4270 model.meshMaterial[primitiveIndex] = (int)(data->meshes[i].primitives[p].material - data->materials);
4274 model.meshMaterial[primitiveIndex] = model.materialCount - 1;
4277 BindGLTFPrimitiveToBones(&model, data, primitiveIndex);
4286 else TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName);
4293 static void InitGLTFBones(Model* model, const cgltf_data* data)
4295 for (unsigned int j = 0; j < data->nodes_count; j++)
4297 strcpy(model->bones[j].name, data->nodes[j].name == 0 ? "ANIMJOINT" : data->nodes[j].name);
4298 model->bones[j].parent = (data->nodes[j].parent != NULL) ? (int)(data->nodes[j].parent - data->nodes) : -1;
4301 for (unsigned int i = 0; i < data->nodes_count; i++)
4303 if (data->nodes[i].has_translation) memcpy(&model->bindPose[i].translation, data->nodes[i].translation, 3*sizeof(float));
4304 else model->bindPose[i].translation = Vector3Zero();
4306 if (data->nodes[i].has_rotation) memcpy(&model->bindPose[i].rotation, data->nodes[i].rotation, 4*sizeof(float));
4307 else model->bindPose[i].rotation = QuaternionIdentity();
4309 model->bindPose[i].rotation = QuaternionNormalize(model->bindPose[i].rotation);
4311 if (data->nodes[i].has_scale) memcpy(&model->bindPose[i].scale, data->nodes[i].scale, 3*sizeof(float));
4312 else model->bindPose[i].scale = Vector3One();
4316 bool* completedBones = RL_CALLOC(model->boneCount, sizeof(bool));
4317 int numberCompletedBones = 0;
4319 while (numberCompletedBones < model->boneCount) {
4320 for (int i = 0; i < model->boneCount; i++)
4322 if (completedBones[i]) continue;
4324 if (model->bones[i].parent < 0) {
4325 completedBones[i] = true;
4326 numberCompletedBones++;
4330 if (!completedBones[model->bones[i].parent]) continue;
4332 Transform* currentTransform = &model->bindPose[i];
4333 BoneInfo* currentBone = &model->bones[i];
4334 int root = currentBone->parent;
4335 if (root >= model->boneCount)
4337 Transform* parentTransform = &model->bindPose[root];
4339 currentTransform->rotation = QuaternionMultiply(parentTransform->rotation, currentTransform->rotation);
4340 currentTransform->translation = Vector3RotateByQuaternion(currentTransform->translation, parentTransform->rotation);
4341 currentTransform->translation = Vector3Add(currentTransform->translation, parentTransform->translation);
4342 currentTransform->scale = Vector3Multiply(currentTransform->scale, parentTransform->scale);
4343 completedBones[i] = true;
4344 numberCompletedBones++;
4348 RL_FREE(completedBones);
4352 static void LoadGLTFMaterial(Model* model, const char* fileName, const cgltf_data* data)
4354 for (int i = 0; i < model->materialCount - 1; i++)
4356 model->materials[i] = LoadMaterialDefault();
4357 Color tint = (Color){ 255, 255, 255, 255 };
4358 const char *texPath = GetDirectoryPath(fileName);
4360 // Ensure material follows raylib support for PBR (metallic/roughness flow)
4361 if (data->materials[i].has_pbr_metallic_roughness)
4363 tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255);
4364 tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255);
4365 tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255);
4366 tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255);
4368 model->materials[i].maps[MATERIAL_MAP_ALBEDO].color = tint;
4370 if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture)
4372 Image albedo = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath, tint);
4373 model->materials[i].maps[MATERIAL_MAP_ALBEDO].texture = LoadTextureFromImage(albedo);
4374 UnloadImage(albedo);
4377 tint = WHITE; // Set tint to white after it's been used by Albedo
4379 if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture)
4381 Image metallicRoughness = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath, tint);
4382 model->materials[i].maps[MATERIAL_MAP_ROUGHNESS].texture = LoadTextureFromImage(metallicRoughness);
4384 float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor;
4385 model->materials[i].maps[MATERIAL_MAP_ROUGHNESS].value = roughness;
4387 float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor;
4388 model->materials[i].maps[MATERIAL_MAP_METALNESS].value = metallic;
4390 UnloadImage(metallicRoughness);
4393 if (data->materials[i].normal_texture.texture)
4395 Image normalImage = LoadImageFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath, tint);
4396 model->materials[i].maps[MATERIAL_MAP_NORMAL].texture = LoadTextureFromImage(normalImage);
4397 UnloadImage(normalImage);
4400 if (data->materials[i].occlusion_texture.texture)
4402 Image occulsionImage = LoadImageFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath, tint);
4403 model->materials[i].maps[MATERIAL_MAP_OCCLUSION].texture = LoadTextureFromImage(occulsionImage);
4404 UnloadImage(occulsionImage);
4407 if (data->materials[i].emissive_texture.texture)
4409 Image emissiveImage = LoadImageFromCgltfImage(data->materials[i].emissive_texture.texture->image, texPath, tint);
4410 model->materials[i].maps[MATERIAL_MAP_EMISSION].texture = LoadTextureFromImage(emissiveImage);
4411 tint.r = (unsigned char)(data->materials[i].emissive_factor[0]*255);
4412 tint.g = (unsigned char)(data->materials[i].emissive_factor[1]*255);
4413 tint.b = (unsigned char)(data->materials[i].emissive_factor[2]*255);
4414 model->materials[i].maps[MATERIAL_MAP_EMISSION].color = tint;
4415 UnloadImage(emissiveImage);
4420 model->materials[model->materialCount - 1] = LoadMaterialDefault();
4423 static void LoadGLTFBoneAttribute(Model* model, cgltf_accessor* jointsAccessor, const cgltf_data* data, int primitiveIndex)
4425 if (jointsAccessor->component_type == cgltf_component_type_r_16u)
4427 model->meshes[primitiveIndex].boneIds = RL_MALLOC(sizeof(int)*jointsAccessor->count*4);
4428 short* bones = RL_MALLOC(sizeof(short)*jointsAccessor->count*4);
4430 for (int a = 0; a < jointsAccessor->count; a++)
4432 GLTFReadValue(jointsAccessor, a, bones + (a*4), 4, sizeof(short));
4435 for (unsigned int a = 0; a < jointsAccessor->count*4; a++)
4437 cgltf_node* skinJoint = data->skins->joints[bones[a]];
4439 for (unsigned int k = 0; k < data->nodes_count; k++)
4441 if (&(data->nodes[k]) == skinJoint)
4443 model->meshes[primitiveIndex].boneIds[a] = k;
4450 else if (jointsAccessor->component_type == cgltf_component_type_r_8u)
4452 model->meshes[primitiveIndex].boneIds = RL_MALLOC(sizeof(int)*jointsAccessor->count*4);
4453 unsigned char* bones = RL_MALLOC(sizeof(unsigned char)*jointsAccessor->count*4);
4455 for (int a = 0; a < jointsAccessor->count; a++)
4457 GLTFReadValue(jointsAccessor, a, bones + (a*4), 4, sizeof(unsigned char));
4460 for (unsigned int a = 0; a < jointsAccessor->count*4; a++)
4462 cgltf_node* skinJoint = data->skins->joints[bones[a]];
4464 for (unsigned int k = 0; k < data->nodes_count; k++)
4466 if (&(data->nodes[k]) == skinJoint)
4468 model->meshes[primitiveIndex].boneIds[a] = k;
4477 // TODO: Support other size of bone index?
4478 TRACELOG(LOG_WARNING, "MODEL: glTF bones in unexpected format");
4482 static void BindGLTFPrimitiveToBones(Model* model, const cgltf_data* data, int primitiveIndex)
4484 if (model->meshes[primitiveIndex].boneIds == NULL && data->nodes_count > 0)
4486 for (int nodeId = 0; nodeId < data->nodes_count; nodeId++)
4488 if (data->nodes[nodeId].mesh == &(data->meshes[primitiveIndex]))
4490 model->meshes[primitiveIndex].boneIds = RL_CALLOC(4*model->meshes[primitiveIndex].vertexCount, sizeof(int));
4491 model->meshes[primitiveIndex].boneWeights = RL_CALLOC(4*model->meshes[primitiveIndex].vertexCount, sizeof(float));
4493 for (int b = 0; b < 4*model->meshes[primitiveIndex].vertexCount; b++)
4497 model->meshes[primitiveIndex].boneIds[b] = nodeId;
4498 model->meshes[primitiveIndex].boneWeights[b] = 1.0f;
4502 model->meshes[primitiveIndex].boneIds[b] = 0;
4503 model->meshes[primitiveIndex].boneWeights[b] = 0.0f;
4508 Vector3 boundVertex = { 0 };
4509 Vector3 boundNormal = { 0 };
4511 Vector3 outTranslation = { 0 };
4512 Quaternion outRotation = { 0 };
4513 Vector3 outScale = { 0 };
4516 int boneCounter = 0;
4519 for (int i = 0; i < model->meshes[primitiveIndex].vertexCount; i++)
4521 boneId = model->meshes[primitiveIndex].boneIds[boneCounter];
4522 outTranslation = model->bindPose[boneId].translation;
4523 outRotation = model->bindPose[boneId].rotation;
4524 outScale = model->bindPose[boneId].scale;
4526 // Vertices processing
4527 boundVertex = (Vector3){ model->meshes[primitiveIndex].vertices[vCounter], model->meshes[primitiveIndex].vertices[vCounter + 1], model->meshes[primitiveIndex].vertices[vCounter + 2] };
4528 boundVertex = Vector3Multiply(boundVertex, outScale);
4529 boundVertex = Vector3RotateByQuaternion(boundVertex, outRotation);
4530 boundVertex = Vector3Add(boundVertex, outTranslation);
4531 model->meshes[primitiveIndex].vertices[vCounter] = boundVertex.x;
4532 model->meshes[primitiveIndex].vertices[vCounter + 1] = boundVertex.y;
4533 model->meshes[primitiveIndex].vertices[vCounter + 2] = boundVertex.z;
4535 // Normals processing
4536 if (model->meshes[primitiveIndex].normals != NULL)
4538 boundNormal = (Vector3){ model->meshes[primitiveIndex].normals[vCounter], model->meshes[primitiveIndex].normals[vCounter + 1], model->meshes[primitiveIndex].normals[vCounter + 2] };
4539 boundNormal = Vector3RotateByQuaternion(boundNormal, outRotation);
4540 model->meshes[primitiveIndex].normals[vCounter] = boundNormal.x;
4541 model->meshes[primitiveIndex].normals[vCounter + 1] = boundNormal.y;
4542 model->meshes[primitiveIndex].normals[vCounter + 2] = boundNormal.z;
4553 static void LoadGLTFModelIndices(Model* model, cgltf_accessor* indexAccessor, int primitiveIndex)
4557 if (indexAccessor->component_type == cgltf_component_type_r_16u || indexAccessor->component_type == cgltf_component_type_r_16)
4559 model->meshes[primitiveIndex].triangleCount = (int)indexAccessor->count/3;
4560 model->meshes[primitiveIndex].indices = RL_MALLOC(model->meshes[primitiveIndex].triangleCount*3*sizeof(unsigned short));
4562 unsigned short readValue = 0;
4563 for (int a = 0; a < indexAccessor->count; a++)
4565 GLTFReadValue(indexAccessor, a, &readValue, 1, sizeof(short));
4566 model->meshes[primitiveIndex].indices[a] = readValue;
4569 else if (indexAccessor->component_type == cgltf_component_type_r_8u || indexAccessor->component_type == cgltf_component_type_r_8)
4571 model->meshes[primitiveIndex].triangleCount = (int)indexAccessor->count/3;
4572 model->meshes[primitiveIndex].indices = RL_MALLOC(model->meshes[primitiveIndex].triangleCount*3*sizeof(unsigned short));
4574 unsigned char readValue = 0;
4575 for (int a = 0; a < indexAccessor->count; a++)
4577 GLTFReadValue(indexAccessor, a, &readValue, 1, sizeof(char));
4578 model->meshes[primitiveIndex].indices[a] = (unsigned short)readValue;
4581 else if (indexAccessor->component_type == cgltf_component_type_r_32u)
4583 model->meshes[primitiveIndex].triangleCount = (int)indexAccessor->count/3;
4584 model->meshes[primitiveIndex].indices = RL_MALLOC(model->meshes[primitiveIndex].triangleCount*3*sizeof(unsigned short));
4586 unsigned int readValue;
4587 for (int a = 0; a < indexAccessor->count; a++)
4589 GLTFReadValue(indexAccessor, a, &readValue, 1, sizeof(unsigned int));
4590 model->meshes[primitiveIndex].indices[a] = (unsigned short)readValue;
4597 model->meshes[primitiveIndex].triangleCount = model->meshes[primitiveIndex].vertexCount/3;
4601 // LoadGLTF loads in animation data from given filename
4602 static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCount)
4604 /***********************************************************************************
4606 Function implemented by Hristo Stamenov (@object71)
4609 - Supports .gltf and .glb files
4611 Some restrictions (not exhaustive):
4614 *************************************************************************************/
4616 // glTF file loading
4617 unsigned int dataSize = 0;
4618 unsigned char *fileData = LoadFileData(fileName, &dataSize);
4620 ModelAnimation *animations = NULL;
4622 if (fileData == NULL) return animations;
4624 // glTF data loading
4625 cgltf_options options = { 0 };
4626 cgltf_data *data = NULL;
4627 cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data);
4629 if (result == cgltf_result_success)
4631 TRACELOG(LOG_INFO, "MODEL: [%s] glTF animations (%s) count: %i", fileName, (data->file_type == 2)? "glb" :
4632 "gltf", data->animations_count);
4634 result = cgltf_load_buffers(&options, data, fileName);
4635 if (result != cgltf_result_success) TRACELOG(LOG_WARNING, "MODEL: [%s] unable to load glTF animations data", fileName);
4636 animations = RL_MALLOC(data->animations_count*sizeof(ModelAnimation));
4637 *animCount = (int)data->animations_count;
4639 for (unsigned int a = 0; a < data->animations_count; a++)
4641 // gltf animation consists of the following structures:
4643 // - channels - single transformation type on a single bone
4645 // - transformation type (path) - translation, rotation, scale
4646 // - sampler - animation samples
4647 // - input - points in time this transformation happens
4648 // - output - the transformation amount at the given input points in time
4649 // - interpolation - the type of interpolation to use between the frames
4651 cgltf_animation *animation = data->animations + a;
4653 ModelAnimation *output = animations + a;
4655 // 30 frames sampled per second
4656 const float timeStep = (1.0f/30.0f);
4657 float animationDuration = 0.0f;
4659 // Getting the max animation time to consider for animation duration
4660 for (unsigned int i = 0; i < animation->channels_count; i++)
4662 cgltf_animation_channel* channel = animation->channels + i;
4663 int frameCounts = (int)channel->sampler->input->count;
4664 float lastFrameTime = 0.0f;
4666 if (GLTFReadValue(channel->sampler->input, frameCounts - 1, &lastFrameTime, 1, sizeof(float)))
4668 animationDuration = fmaxf(lastFrameTime, animationDuration);
4672 output->frameCount = (int)(animationDuration / timeStep);
4673 output->boneCount = (int)data->nodes_count;
4674 output->bones = RL_MALLOC(output->boneCount*sizeof(BoneInfo));
4675 output->framePoses = RL_MALLOC(output->frameCount*sizeof(Transform *));
4676 // output->framerate = // TODO: Use framerate instead of const timestep
4678 // Name and parent bones
4679 for (unsigned int j = 0; j < data->nodes_count; j++)
4681 strcpy(output->bones[j].name, data->nodes[j].name == 0 ? "ANIMJOINT" : data->nodes[j].name);
4682 output->bones[j].parent = (data->nodes[j].parent != NULL) ? (int)(data->nodes[j].parent - data->nodes) : -1;
4685 // Allocate data for frames
4686 // Initiate with zero bone translations
4687 for (int frame = 0; frame < output->frameCount; frame++)
4689 output->framePoses[frame] = RL_MALLOC(output->frameCount*data->nodes_count*sizeof(Transform));
4691 for (unsigned int i = 0; i < data->nodes_count; i++)
4693 output->framePoses[frame][i].translation = Vector3Zero();
4694 output->framePoses[frame][i].rotation = QuaternionIdentity();
4695 output->framePoses[frame][i].rotation = QuaternionNormalize(output->framePoses[frame][i].rotation);
4696 output->framePoses[frame][i].scale = Vector3One();
4700 // for each single transformation type on single bone
4701 for (unsigned int channelId = 0; channelId < animation->channels_count; channelId++)
4703 cgltf_animation_channel* channel = animation->channels + channelId;
4704 cgltf_animation_sampler* sampler = channel->sampler;
4706 int boneId = (int)(channel->target_node - data->nodes);
4708 for (int frame = 0; frame < output->frameCount; frame++)
4710 bool shouldSkipFurtherTransformation = true;
4713 float frameTime = frame*timeStep;
4714 float lerpPercent = 0.0f;
4716 // For this transformation:
4717 // getting between which input values the current frame time position
4718 // and also what is the percent to use in the linear interpolation later
4719 for (unsigned int j = 0; j < sampler->input->count; j++)
4721 float inputFrameTime;
4722 if (GLTFReadValue(sampler->input, j, &inputFrameTime, 1, sizeof(float)))
4724 if (frameTime < inputFrameTime)
4726 shouldSkipFurtherTransformation = false;
4727 outputMin = (j == 0) ? 0 : j - 1;
4730 float previousInputTime = 0.0f;
4731 if (GLTFReadValue(sampler->input, outputMin, &previousInputTime, 1, sizeof(float)))
4733 if ((inputFrameTime - previousInputTime) != 0)
4735 lerpPercent = (frameTime - previousInputTime)/(inputFrameTime - previousInputTime);
4745 // If the current transformation has no information for the current frame time point
4746 if (shouldSkipFurtherTransformation) continue;
4748 if (channel->target_path == cgltf_animation_path_type_translation)
4750 Vector3 translationStart;
4751 Vector3 translationEnd;
4753 bool success = GLTFReadValue(sampler->output, outputMin, &translationStart, 3, sizeof(float));
4754 success = GLTFReadValue(sampler->output, outputMax, &translationEnd, 3, sizeof(float)) || success;
4756 if (success) output->framePoses[frame][boneId].translation = Vector3Lerp(translationStart, translationEnd, lerpPercent);
4758 if (channel->target_path == cgltf_animation_path_type_rotation)
4760 Quaternion rotationStart;
4761 Quaternion rotationEnd;
4763 bool success = GLTFReadValue(sampler->output, outputMin, &rotationStart, 4, sizeof(float));
4764 success = GLTFReadValue(sampler->output, outputMax, &rotationEnd, 4, sizeof(float)) || success;
4768 output->framePoses[frame][boneId].rotation = QuaternionLerp(rotationStart, rotationEnd, lerpPercent);
4769 output->framePoses[frame][boneId].rotation = QuaternionNormalize(output->framePoses[frame][boneId].rotation);
4772 if (channel->target_path == cgltf_animation_path_type_scale)
4777 bool success = GLTFReadValue(sampler->output, outputMin, &scaleStart, 3, sizeof(float));
4778 success = GLTFReadValue(sampler->output, outputMax, &scaleEnd, 3, sizeof(float)) || success;
4780 if (success) output->framePoses[frame][boneId].scale = Vector3Lerp(scaleStart, scaleEnd, lerpPercent);
4786 for (int frame = 0; frame < output->frameCount; frame++)
4788 bool *completedBones = RL_CALLOC(output->boneCount, sizeof(bool));
4789 int numberCompletedBones = 0;
4791 while (numberCompletedBones < output->boneCount)
4793 for (int i = 0; i < output->boneCount; i++)
4795 if (completedBones[i]) continue;
4797 if (output->bones[i].parent < 0)
4799 completedBones[i] = true;
4800 numberCompletedBones++;
4804 if (!completedBones[output->bones[i].parent]) continue;
4806 output->framePoses[frame][i].rotation = QuaternionMultiply(output->framePoses[frame][output->bones[i].parent].rotation, output->framePoses[frame][i].rotation);
4807 output->framePoses[frame][i].translation = Vector3RotateByQuaternion(output->framePoses[frame][i].translation, output->framePoses[frame][output->bones[i].parent].rotation);
4808 output->framePoses[frame][i].translation = Vector3Add(output->framePoses[frame][i].translation, output->framePoses[frame][output->bones[i].parent].translation);
4809 output->framePoses[frame][i].scale = Vector3Multiply(output->framePoses[frame][i].scale, output->framePoses[frame][output->bones[i].parent].scale);
4810 completedBones[i] = true;
4811 numberCompletedBones++;
4815 RL_FREE(completedBones);
4822 else TRACELOG(LOG_WARNING, ": [%s] Failed to load glTF data", fileName);