minesweeper

A minewseeper implementation to play around with Hare and Raylib
git clone https://git.tronto.net/minesweeper
Download | Log | Files | Refs | README | LICENSE

rmodels.c (307329B)


      1 /**********************************************************************************************
      2 *
      3 *   rmodels - Basic functions to draw 3d shapes and load and draw 3d models
      4 *
      5 *   CONFIGURATION:
      6 *       #define SUPPORT_MODULE_RMODELS
      7 *           rmodels module is included in the build
      8 *
      9 *       #define SUPPORT_FILEFORMAT_OBJ
     10 *       #define SUPPORT_FILEFORMAT_MTL
     11 *       #define SUPPORT_FILEFORMAT_IQM
     12 *       #define SUPPORT_FILEFORMAT_GLTF
     13 *       #define SUPPORT_FILEFORMAT_VOX
     14 *       #define SUPPORT_FILEFORMAT_M3D
     15 *           Selected desired fileformats to be supported for model data loading.
     16 *
     17 *       #define SUPPORT_MESH_GENERATION
     18 *           Support procedural mesh generation functions, uses external par_shapes.h library
     19 *           NOTE: Some generated meshes DO NOT include generated texture coordinates
     20 *
     21 *
     22 *   LICENSE: zlib/libpng
     23 *
     24 *   Copyright (c) 2013-2024 Ramon Santamaria (@raysan5)
     25 *
     26 *   This software is provided "as-is", without any express or implied warranty. In no event
     27 *   will the authors be held liable for any damages arising from the use of this software.
     28 *
     29 *   Permission is granted to anyone to use this software for any purpose, including commercial
     30 *   applications, and to alter it and redistribute it freely, subject to the following restrictions:
     31 *
     32 *     1. The origin of this software must not be misrepresented; you must not claim that you
     33 *     wrote the original software. If you use this software in a product, an acknowledgment
     34 *     in the product documentation would be appreciated but is not required.
     35 *
     36 *     2. Altered source versions must be plainly marked as such, and must not be misrepresented
     37 *     as being the original software.
     38 *
     39 *     3. This notice may not be removed or altered from any source distribution.
     40 *
     41 **********************************************************************************************/
     42 
     43 #include "raylib.h"         // Declares module functions
     44 
     45 // Check if config flags have been externally provided on compilation line
     46 #if !defined(EXTERNAL_CONFIG_FLAGS)
     47     #include "config.h"     // Defines module configuration flags
     48 #endif
     49 
     50 #if defined(SUPPORT_MODULE_RMODELS)
     51 
     52 #include "utils.h"          // Required for: TRACELOG(), LoadFileData(), LoadFileText(), SaveFileText()
     53 #include "rlgl.h"           // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
     54 #include "raymath.h"        // Required for: Vector3, Quaternion and Matrix functionality
     55 
     56 #include <stdio.h>          // Required for: sprintf()
     57 #include <stdlib.h>         // Required for: malloc(), calloc(), free()
     58 #include <string.h>         // Required for: memcmp(), strlen(), strncpy()
     59 #include <math.h>           // Required for: sinf(), cosf(), sqrtf(), fabsf()
     60 
     61 #if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL)
     62     #define TINYOBJ_MALLOC RL_MALLOC
     63     #define TINYOBJ_CALLOC RL_CALLOC
     64     #define TINYOBJ_REALLOC RL_REALLOC
     65     #define TINYOBJ_FREE RL_FREE
     66 
     67     #define TINYOBJ_LOADER_C_IMPLEMENTATION
     68     #include "external/tinyobj_loader_c.h"      // OBJ/MTL file formats loading
     69 #endif
     70 
     71 #if defined(SUPPORT_FILEFORMAT_GLTF)
     72     #define CGLTF_MALLOC RL_MALLOC
     73     #define CGLTF_FREE RL_FREE
     74 
     75     #define CGLTF_IMPLEMENTATION
     76     #include "external/cgltf.h"         // glTF file format loading
     77 #endif
     78 
     79 #if defined(SUPPORT_FILEFORMAT_VOX)
     80     #define VOX_MALLOC RL_MALLOC
     81     #define VOX_CALLOC RL_CALLOC
     82     #define VOX_REALLOC RL_REALLOC
     83     #define VOX_FREE RL_FREE
     84 
     85     #define VOX_LOADER_IMPLEMENTATION
     86     #include "external/vox_loader.h"    // VOX file format loading (MagikaVoxel)
     87 #endif
     88 
     89 #if defined(SUPPORT_FILEFORMAT_M3D)
     90     #define M3D_MALLOC RL_MALLOC
     91     #define M3D_REALLOC RL_REALLOC
     92     #define M3D_FREE RL_FREE
     93 
     94     #define M3D_IMPLEMENTATION
     95     #include "external/m3d.h"           // Model3D file format loading
     96 #endif
     97 
     98 #if defined(SUPPORT_MESH_GENERATION)
     99     #define PAR_MALLOC(T, N) ((T*)RL_MALLOC(N*sizeof(T)))
    100     #define PAR_CALLOC(T, N) ((T*)RL_CALLOC(N*sizeof(T), 1))
    101     #define PAR_REALLOC(T, BUF, N) ((T*)RL_REALLOC(BUF, sizeof(T)*(N)))
    102     #define PAR_FREE RL_FREE
    103 
    104     #if defined(_MSC_VER)           // Disable some MSVC warning
    105         #pragma warning(push)
    106         #pragma warning(disable : 4244)
    107         #pragma warning(disable : 4305)
    108     #endif
    109 
    110     #define PAR_SHAPES_IMPLEMENTATION
    111     #include "external/par_shapes.h"    // Shapes 3d parametric generation
    112 
    113     #if defined(_MSC_VER)
    114         #pragma warning(pop)        // Disable MSVC warning suppression
    115     #endif
    116 #endif
    117 
    118 #if defined(_WIN32)
    119     #include <direct.h>     // Required for: _chdir() [Used in LoadOBJ()]
    120     #define CHDIR _chdir
    121 #else
    122     #include <unistd.h>     // Required for: chdir() (POSIX) [Used in LoadOBJ()]
    123     #define CHDIR chdir
    124 #endif
    125 
    126 //----------------------------------------------------------------------------------
    127 // Defines and Macros
    128 //----------------------------------------------------------------------------------
    129 #ifndef MAX_MATERIAL_MAPS
    130     #define MAX_MATERIAL_MAPS       12    // Maximum number of maps supported
    131 #endif
    132 #ifndef MAX_MESH_VERTEX_BUFFERS
    133     #define MAX_MESH_VERTEX_BUFFERS  9    // Maximum vertex buffers (VBO) per mesh
    134 #endif
    135 
    136 //----------------------------------------------------------------------------------
    137 // Types and Structures Definition
    138 //----------------------------------------------------------------------------------
    139 // ...
    140 
    141 //----------------------------------------------------------------------------------
    142 // Global Variables Definition
    143 //----------------------------------------------------------------------------------
    144 // ...
    145 
    146 //----------------------------------------------------------------------------------
    147 // Module specific Functions Declaration
    148 //----------------------------------------------------------------------------------
    149 #if defined(SUPPORT_FILEFORMAT_OBJ)
    150 static Model LoadOBJ(const char *fileName);     // Load OBJ mesh data
    151 #endif
    152 #if defined(SUPPORT_FILEFORMAT_IQM)
    153 static Model LoadIQM(const char *fileName);     // Load IQM mesh data
    154 static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCount);   // Load IQM animation data
    155 #endif
    156 #if defined(SUPPORT_FILEFORMAT_GLTF)
    157 static Model LoadGLTF(const char *fileName);    // Load GLTF mesh data
    158 static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCount);  // Load GLTF animation data
    159 #endif
    160 #if defined(SUPPORT_FILEFORMAT_VOX)
    161 static Model LoadVOX(const char *filename);     // Load VOX mesh data
    162 #endif
    163 #if defined(SUPPORT_FILEFORMAT_M3D)
    164 static Model LoadM3D(const char *filename);     // Load M3D mesh data
    165 static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCount);   // Load M3D animation data
    166 #endif
    167 #if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL)
    168 static void ProcessMaterialsOBJ(Material *rayMaterials, tinyobj_material_t *materials, int materialCount);  // Process obj materials
    169 #endif
    170 
    171 //----------------------------------------------------------------------------------
    172 // Module Functions Definition
    173 //----------------------------------------------------------------------------------
    174 
    175 // Draw a line in 3D world space
    176 void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color)
    177 {
    178     rlBegin(RL_LINES);
    179         rlColor4ub(color.r, color.g, color.b, color.a);
    180         rlVertex3f(startPos.x, startPos.y, startPos.z);
    181         rlVertex3f(endPos.x, endPos.y, endPos.z);
    182     rlEnd();
    183 }
    184 
    185 // Draw a point in 3D space, actually a small line
    186 void DrawPoint3D(Vector3 position, Color color)
    187 {
    188     rlPushMatrix();
    189         rlTranslatef(position.x, position.y, position.z);
    190         rlBegin(RL_LINES);
    191             rlColor4ub(color.r, color.g, color.b, color.a);
    192             rlVertex3f(0.0f, 0.0f, 0.0f);
    193             rlVertex3f(0.0f, 0.0f, 0.1f);
    194         rlEnd();
    195     rlPopMatrix();
    196 }
    197 
    198 // Draw a circle in 3D world space
    199 void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color)
    200 {
    201     rlPushMatrix();
    202         rlTranslatef(center.x, center.y, center.z);
    203         rlRotatef(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
    204 
    205         rlBegin(RL_LINES);
    206             for (int i = 0; i < 360; i += 10)
    207             {
    208                 rlColor4ub(color.r, color.g, color.b, color.a);
    209 
    210                 rlVertex3f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius, 0.0f);
    211                 rlVertex3f(sinf(DEG2RAD*(i + 10))*radius, cosf(DEG2RAD*(i + 10))*radius, 0.0f);
    212             }
    213         rlEnd();
    214     rlPopMatrix();
    215 }
    216 
    217 // Draw a color-filled triangle (vertex in counter-clockwise order!)
    218 void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color)
    219 {
    220     rlBegin(RL_TRIANGLES);
    221         rlColor4ub(color.r, color.g, color.b, color.a);
    222         rlVertex3f(v1.x, v1.y, v1.z);
    223         rlVertex3f(v2.x, v2.y, v2.z);
    224         rlVertex3f(v3.x, v3.y, v3.z);
    225     rlEnd();
    226 }
    227 
    228 // Draw a triangle strip defined by points
    229 void DrawTriangleStrip3D(const Vector3 *points, int pointCount, Color color)
    230 {
    231     if (pointCount < 3) return; // Security check
    232 
    233     rlBegin(RL_TRIANGLES);
    234         rlColor4ub(color.r, color.g, color.b, color.a);
    235 
    236         for (int i = 2; i < pointCount; i++)
    237         {
    238             if ((i%2) == 0)
    239             {
    240                 rlVertex3f(points[i].x, points[i].y, points[i].z);
    241                 rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z);
    242                 rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z);
    243             }
    244             else
    245             {
    246                 rlVertex3f(points[i].x, points[i].y, points[i].z);
    247                 rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z);
    248                 rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z);
    249             }
    250         }
    251     rlEnd();
    252 }
    253 
    254 // Draw cube
    255 // NOTE: Cube position is the center position
    256 void DrawCube(Vector3 position, float width, float height, float length, Color color)
    257 {
    258     float x = 0.0f;
    259     float y = 0.0f;
    260     float z = 0.0f;
    261 
    262     rlPushMatrix();
    263         // NOTE: Transformation is applied in inverse order (scale -> rotate -> translate)
    264         rlTranslatef(position.x, position.y, position.z);
    265         //rlRotatef(45, 0, 1, 0);
    266         //rlScalef(1.0f, 1.0f, 1.0f);   // NOTE: Vertices are directly scaled on definition
    267 
    268         rlBegin(RL_TRIANGLES);
    269             rlColor4ub(color.r, color.g, color.b, color.a);
    270 
    271             // Front face
    272             rlNormal3f(0.0f, 0.0f, 1.0f);
    273             rlVertex3f(x - width/2, y - height/2, z + length/2);  // Bottom Left
    274             rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom Right
    275             rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top Left
    276 
    277             rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top Right
    278             rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top Left
    279             rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom Right
    280 
    281             // Back face
    282             rlNormal3f(0.0f, 0.0f, -1.0f);
    283             rlVertex3f(x - width/2, y - height/2, z - length/2);  // Bottom Left
    284             rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top Left
    285             rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom Right
    286 
    287             rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top Right
    288             rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom Right
    289             rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top Left
    290 
    291             // Top face
    292             rlNormal3f(0.0f, 1.0f, 0.0f);
    293             rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top Left
    294             rlVertex3f(x - width/2, y + height/2, z + length/2);  // Bottom Left
    295             rlVertex3f(x + width/2, y + height/2, z + length/2);  // Bottom Right
    296 
    297             rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top Right
    298             rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top Left
    299             rlVertex3f(x + width/2, y + height/2, z + length/2);  // Bottom Right
    300 
    301             // Bottom face
    302             rlNormal3f(0.0f, -1.0f, 0.0f);
    303             rlVertex3f(x - width/2, y - height/2, z - length/2);  // Top Left
    304             rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom Right
    305             rlVertex3f(x - width/2, y - height/2, z + length/2);  // Bottom Left
    306 
    307             rlVertex3f(x + width/2, y - height/2, z - length/2);  // Top Right
    308             rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom Right
    309             rlVertex3f(x - width/2, y - height/2, z - length/2);  // Top Left
    310 
    311             // Right face
    312             rlNormal3f(1.0f, 0.0f, 0.0f);
    313             rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom Right
    314             rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top Right
    315             rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top Left
    316 
    317             rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom Left
    318             rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom Right
    319             rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top Left
    320 
    321             // Left face
    322             rlNormal3f(-1.0f, 0.0f, 0.0f);
    323             rlVertex3f(x - width/2, y - height/2, z - length/2);  // Bottom Right
    324             rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top Left
    325             rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top Right
    326 
    327             rlVertex3f(x - width/2, y - height/2, z + length/2);  // Bottom Left
    328             rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top Left
    329             rlVertex3f(x - width/2, y - height/2, z - length/2);  // Bottom Right
    330         rlEnd();
    331     rlPopMatrix();
    332 }
    333 
    334 // Draw cube (Vector version)
    335 void DrawCubeV(Vector3 position, Vector3 size, Color color)
    336 {
    337     DrawCube(position, size.x, size.y, size.z, color);
    338 }
    339 
    340 // Draw cube wires
    341 void DrawCubeWires(Vector3 position, float width, float height, float length, Color color)
    342 {
    343     float x = 0.0f;
    344     float y = 0.0f;
    345     float z = 0.0f;
    346 
    347     rlPushMatrix();
    348         rlTranslatef(position.x, position.y, position.z);
    349 
    350         rlBegin(RL_LINES);
    351             rlColor4ub(color.r, color.g, color.b, color.a);
    352 
    353             // Front face
    354             //------------------------------------------------------------------
    355             // Bottom line
    356             rlVertex3f(x - width/2, y - height/2, z + length/2);  // Bottom left
    357             rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom right
    358 
    359             // Left line
    360             rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom right
    361             rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top right
    362 
    363             // Top line
    364             rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top right
    365             rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top left
    366 
    367             // Right line
    368             rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top left
    369             rlVertex3f(x - width/2, y - height/2, z + length/2);  // Bottom left
    370 
    371             // Back face
    372             //------------------------------------------------------------------
    373             // Bottom line
    374             rlVertex3f(x - width/2, y - height/2, z - length/2);  // Bottom left
    375             rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom right
    376 
    377             // Left line
    378             rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom right
    379             rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top right
    380 
    381             // Top line
    382             rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top right
    383             rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top left
    384 
    385             // Right line
    386             rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top left
    387             rlVertex3f(x - width/2, y - height/2, z - length/2);  // Bottom left
    388 
    389             // Top face
    390             //------------------------------------------------------------------
    391             // Left line
    392             rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top left front
    393             rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top left back
    394 
    395             // Right line
    396             rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top right front
    397             rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top right back
    398 
    399             // Bottom face
    400             //------------------------------------------------------------------
    401             // Left line
    402             rlVertex3f(x - width/2, y - height/2, z + length/2);  // Top left front
    403             rlVertex3f(x - width/2, y - height/2, z - length/2);  // Top left back
    404 
    405             // Right line
    406             rlVertex3f(x + width/2, y - height/2, z + length/2);  // Top right front
    407             rlVertex3f(x + width/2, y - height/2, z - length/2);  // Top right back
    408         rlEnd();
    409     rlPopMatrix();
    410 }
    411 
    412 // Draw cube wires (vector version)
    413 void DrawCubeWiresV(Vector3 position, Vector3 size, Color color)
    414 {
    415     DrawCubeWires(position, size.x, size.y, size.z, color);
    416 }
    417 
    418 // Draw sphere
    419 void DrawSphere(Vector3 centerPos, float radius, Color color)
    420 {
    421     DrawSphereEx(centerPos, radius, 16, 16, color);
    422 }
    423 
    424 // Draw sphere with extended parameters
    425 void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color)
    426 {
    427 #if 0
    428     // Basic implementation, do not use it!
    429     // For a sphere with 16 rings and 16 slices it requires 8640 cos()/sin() function calls!
    430     // New optimized version below only requires 4 cos()/sin() calls
    431 
    432     rlPushMatrix();
    433         // NOTE: Transformation is applied in inverse order (scale -> translate)
    434         rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
    435         rlScalef(radius, radius, radius);
    436 
    437         rlBegin(RL_TRIANGLES);
    438             rlColor4ub(color.r, color.g, color.b, color.a);
    439 
    440             for (int i = 0; i < (rings + 2); i++)
    441             {
    442                 for (int j = 0; j < slices; j++)
    443                 {
    444                     rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)),
    445                                sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)),
    446                                cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices)));
    447                     rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)),
    448                                sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
    449                                cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices)));
    450                     rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)),
    451                                sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
    452                                cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices)));
    453 
    454                     rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)),
    455                                sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)),
    456                                cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices)));
    457                     rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)),
    458                                sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i))),
    459                                cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices)));
    460                     rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)),
    461                                sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
    462                                cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices)));
    463                 }
    464             }
    465         rlEnd();
    466     rlPopMatrix();
    467 #endif
    468 
    469     rlPushMatrix();
    470         // NOTE: Transformation is applied in inverse order (scale -> translate)
    471         rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
    472         rlScalef(radius, radius, radius);
    473 
    474         rlBegin(RL_TRIANGLES);
    475             rlColor4ub(color.r, color.g, color.b, color.a);
    476 
    477             float ringangle = DEG2RAD*(180.0f/(rings + 1)); // Angle between latitudinal parallels
    478             float sliceangle = DEG2RAD*(360.0f/slices); // Angle between longitudinal meridians
    479 
    480             float cosring = cosf(ringangle);
    481             float sinring = sinf(ringangle);
    482             float cosslice = cosf(sliceangle);
    483             float sinslice = sinf(sliceangle);
    484 
    485             Vector3 vertices[4] = { 0 }; // Required to store face vertices
    486             vertices[2] = (Vector3){ 0, 1, 0 };
    487             vertices[3] = (Vector3){ sinring, cosring, 0 };
    488 
    489             for (int i = 0; i < rings + 1; i++)
    490             {
    491                 for (int j = 0; j < slices; j++)
    492                 {
    493                     vertices[0] = vertices[2]; // Rotate around y axis to set up vertices for next face
    494                     vertices[1] = vertices[3];
    495                     vertices[2] = (Vector3){ cosslice*vertices[2].x - sinslice*vertices[2].z, vertices[2].y, sinslice*vertices[2].x + cosslice*vertices[2].z }; // Rotation matrix around y axis
    496                     vertices[3] = (Vector3){ cosslice*vertices[3].x - sinslice*vertices[3].z, vertices[3].y, sinslice*vertices[3].x + cosslice*vertices[3].z };
    497 
    498                     rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
    499                     rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
    500                     rlVertex3f(vertices[1].x, vertices[1].y, vertices[1].z);
    501 
    502                     rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
    503                     rlVertex3f(vertices[2].x, vertices[2].y, vertices[2].z);
    504                     rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
    505                 }
    506 
    507                 vertices[2] = vertices[3]; // Rotate around z axis to set up  starting vertices for next ring
    508                 vertices[3] = (Vector3){ cosring*vertices[3].x + sinring*vertices[3].y, -sinring*vertices[3].x + cosring*vertices[3].y, vertices[3].z }; // Rotation matrix around z axis
    509             }
    510         rlEnd();
    511     rlPopMatrix();
    512 }
    513 
    514 // Draw sphere wires
    515 void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color)
    516 {
    517     rlPushMatrix();
    518         // NOTE: Transformation is applied in inverse order (scale -> translate)
    519         rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
    520         rlScalef(radius, radius, radius);
    521 
    522         rlBegin(RL_LINES);
    523             rlColor4ub(color.r, color.g, color.b, color.a);
    524 
    525             for (int i = 0; i < (rings + 2); i++)
    526             {
    527                 for (int j = 0; j < slices; j++)
    528                 {
    529                     rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)),
    530                                sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)),
    531                                cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices)));
    532                     rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)),
    533                                sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
    534                                cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices)));
    535 
    536                     rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)),
    537                                sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
    538                                cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices)));
    539                     rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)),
    540                                sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
    541                                cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices)));
    542 
    543                     rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)),
    544                                sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
    545                                cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices)));
    546                     rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)),
    547                                sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)),
    548                                cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices)));
    549                 }
    550             }
    551         rlEnd();
    552     rlPopMatrix();
    553 }
    554 
    555 // Draw a cylinder
    556 // NOTE: It could be also used for pyramid and cone
    557 void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
    558 {
    559     if (sides < 3) sides = 3;
    560 
    561     const float angleStep = 360.0f/sides;
    562 
    563     rlPushMatrix();
    564         rlTranslatef(position.x, position.y, position.z);
    565 
    566         rlBegin(RL_TRIANGLES);
    567             rlColor4ub(color.r, color.g, color.b, color.a);
    568 
    569             if (radiusTop > 0)
    570             {
    571                 // Draw Body -------------------------------------------------------------------------------------
    572                 for (int i = 0; i < sides; i++)
    573                 {
    574                     rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom); //Bottom Left
    575                     rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom); //Bottom Right
    576                     rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop); //Top Right
    577 
    578                     rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusTop, height, cosf(DEG2RAD*i*angleStep)*radiusTop); //Top Left
    579                     rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom); //Bottom Left
    580                     rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop); //Top Right
    581                 }
    582 
    583                 // Draw Cap --------------------------------------------------------------------------------------
    584                 for (int i = 0; i < sides; i++)
    585                 {
    586                     rlVertex3f(0, height, 0);
    587                     rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusTop, height, cosf(DEG2RAD*i*angleStep)*radiusTop);
    588                     rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop);
    589                 }
    590             }
    591             else
    592             {
    593                 // Draw Cone -------------------------------------------------------------------------------------
    594                 for (int i = 0; i < sides; i++)
    595                 {
    596                     rlVertex3f(0, height, 0);
    597                     rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom);
    598                     rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom);
    599                 }
    600             }
    601 
    602             // Draw Base -----------------------------------------------------------------------------------------
    603             for (int i = 0; i < sides; i++)
    604             {
    605                 rlVertex3f(0, 0, 0);
    606                 rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom);
    607                 rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom);
    608             }
    609 
    610         rlEnd();
    611     rlPopMatrix();
    612 }
    613 
    614 // Draw a cylinder with base at startPos and top at endPos
    615 // NOTE: It could be also used for pyramid and cone
    616 void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color)
    617 {
    618     if (sides < 3) sides = 3;
    619 
    620     Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
    621     if ((direction.x == 0) && (direction.y == 0) && (direction.z == 0)) return; // Security check
    622 
    623     // Construct a basis of the base and the top face:
    624     Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction));
    625     Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
    626 
    627     float baseAngle = (2.0f*PI)/sides;
    628 
    629     rlBegin(RL_TRIANGLES);
    630         rlColor4ub(color.r, color.g, color.b, color.a);
    631 
    632         for (int i = 0; i < sides; i++)
    633         {
    634             // Compute the four vertices
    635             float s1 = sinf(baseAngle*(i + 0))*startRadius;
    636             float c1 = cosf(baseAngle*(i + 0))*startRadius;
    637             Vector3 w1 = { startPos.x + s1*b1.x + c1*b2.x, startPos.y + s1*b1.y + c1*b2.y, startPos.z + s1*b1.z + c1*b2.z };
    638             float s2 = sinf(baseAngle*(i + 1))*startRadius;
    639             float c2 = cosf(baseAngle*(i + 1))*startRadius;
    640             Vector3 w2 = { startPos.x + s2*b1.x + c2*b2.x, startPos.y + s2*b1.y + c2*b2.y, startPos.z + s2*b1.z + c2*b2.z };
    641             float s3 = sinf(baseAngle*(i + 0))*endRadius;
    642             float c3 = cosf(baseAngle*(i + 0))*endRadius;
    643             Vector3 w3 = { endPos.x + s3*b1.x + c3*b2.x, endPos.y + s3*b1.y + c3*b2.y, endPos.z + s3*b1.z + c3*b2.z };
    644             float s4 = sinf(baseAngle*(i + 1))*endRadius;
    645             float c4 = cosf(baseAngle*(i + 1))*endRadius;
    646             Vector3 w4 = { endPos.x + s4*b1.x + c4*b2.x, endPos.y + s4*b1.y + c4*b2.y, endPos.z + s4*b1.z + c4*b2.z };
    647 
    648             if (startRadius > 0)
    649             {
    650                 rlVertex3f(startPos.x, startPos.y, startPos.z); // |
    651                 rlVertex3f(w2.x, w2.y, w2.z);                   // T0
    652                 rlVertex3f(w1.x, w1.y, w1.z);                   // |
    653             }
    654                                                                 //          w2 x.-----------x startPos
    655             rlVertex3f(w1.x, w1.y, w1.z);                       // |           |\'.  T0    /
    656             rlVertex3f(w2.x, w2.y, w2.z);                       // T1          | \ '.     /
    657             rlVertex3f(w3.x, w3.y, w3.z);                       // |           |T \  '.  /
    658                                                                 //             | 2 \ T 'x w1
    659             rlVertex3f(w2.x, w2.y, w2.z);                       // |        w4 x.---\-1-|---x endPos
    660             rlVertex3f(w4.x, w4.y, w4.z);                       // T2            '.  \  |T3/
    661             rlVertex3f(w3.x, w3.y, w3.z);                       // |               '. \ | /
    662                                                                 //                   '.\|/
    663             if (endRadius > 0)                                  //                     'x w3
    664             {
    665                 rlVertex3f(endPos.x, endPos.y, endPos.z);       // |
    666                 rlVertex3f(w3.x, w3.y, w3.z);                   // T3
    667                 rlVertex3f(w4.x, w4.y, w4.z);                   // |
    668             }                                                   //
    669         }
    670     rlEnd();
    671 }
    672 
    673 // Draw a wired cylinder
    674 // NOTE: It could be also used for pyramid and cone
    675 void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
    676 {
    677     if (sides < 3) sides = 3;
    678 
    679     const float angleStep = 360.0f/sides;
    680 
    681     rlPushMatrix();
    682         rlTranslatef(position.x, position.y, position.z);
    683 
    684         rlBegin(RL_LINES);
    685             rlColor4ub(color.r, color.g, color.b, color.a);
    686 
    687             for (int i = 0; i < sides; i++)
    688             {
    689                 rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom);
    690                 rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom);
    691 
    692                 rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom);
    693                 rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop);
    694 
    695                 rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop);
    696                 rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusTop, height, cosf(DEG2RAD*i*angleStep)*radiusTop);
    697 
    698                 rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusTop, height, cosf(DEG2RAD*i*angleStep)*radiusTop);
    699                 rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom);
    700             }
    701         rlEnd();
    702     rlPopMatrix();
    703 }
    704 
    705 // Draw a wired cylinder with base at startPos and top at endPos
    706 // NOTE: It could be also used for pyramid and cone
    707 void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color)
    708 {
    709     if (sides < 3) sides = 3;
    710 
    711     Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
    712     if ((direction.x == 0) && (direction.y == 0) && (direction.z == 0)) return; // Security check
    713 
    714     // Construct a basis of the base and the top face:
    715     Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction));
    716     Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
    717 
    718     float baseAngle = (2.0f*PI)/sides;
    719 
    720     rlBegin(RL_LINES);
    721         rlColor4ub(color.r, color.g, color.b, color.a);
    722 
    723         for (int i = 0; i < sides; i++)
    724         {
    725             // Compute the four vertices
    726             float s1 = sinf(baseAngle*(i + 0))*startRadius;
    727             float c1 = cosf(baseAngle*(i + 0))*startRadius;
    728             Vector3 w1 = { startPos.x + s1*b1.x + c1*b2.x, startPos.y + s1*b1.y + c1*b2.y, startPos.z + s1*b1.z + c1*b2.z };
    729             float s2 = sinf(baseAngle*(i + 1))*startRadius;
    730             float c2 = cosf(baseAngle*(i + 1))*startRadius;
    731             Vector3 w2 = { startPos.x + s2*b1.x + c2*b2.x, startPos.y + s2*b1.y + c2*b2.y, startPos.z + s2*b1.z + c2*b2.z };
    732             float s3 = sinf(baseAngle*(i + 0))*endRadius;
    733             float c3 = cosf(baseAngle*(i + 0))*endRadius;
    734             Vector3 w3 = { endPos.x + s3*b1.x + c3*b2.x, endPos.y + s3*b1.y + c3*b2.y, endPos.z + s3*b1.z + c3*b2.z };
    735             float s4 = sinf(baseAngle*(i + 1))*endRadius;
    736             float c4 = cosf(baseAngle*(i + 1))*endRadius;
    737             Vector3 w4 = { endPos.x + s4*b1.x + c4*b2.x, endPos.y + s4*b1.y + c4*b2.y, endPos.z + s4*b1.z + c4*b2.z };
    738 
    739             rlVertex3f(w1.x, w1.y, w1.z);
    740             rlVertex3f(w2.x, w2.y, w2.z);
    741 
    742             rlVertex3f(w1.x, w1.y, w1.z);
    743             rlVertex3f(w3.x, w3.y, w3.z);
    744 
    745             rlVertex3f(w3.x, w3.y, w3.z);
    746             rlVertex3f(w4.x, w4.y, w4.z);
    747         }
    748     rlEnd();
    749 }
    750 
    751 // Draw a capsule with the center of its sphere caps at startPos and endPos
    752 void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color)
    753 {
    754     if (slices < 3) slices = 3;
    755 
    756     Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
    757 
    758     // draw a sphere if start and end points are the same
    759     bool sphereCase = (direction.x == 0) && (direction.y == 0) && (direction.z == 0);
    760     if (sphereCase) direction = (Vector3){0.0f, 1.0f, 0.0f};
    761 
    762     // Construct a basis of the base and the caps:
    763     Vector3 b0 = Vector3Normalize(direction);
    764     Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction));
    765     Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
    766     Vector3 capCenter = endPos;
    767 
    768     float baseSliceAngle = (2.0f*PI)/slices;
    769     float baseRingAngle  = PI*0.5f/rings;
    770 
    771     rlBegin(RL_TRIANGLES);
    772         rlColor4ub(color.r, color.g, color.b, color.a);
    773 
    774         // render both caps
    775         for (int c = 0; c < 2; c++)
    776         {
    777             for (int i = 0; i < rings; i++)
    778             {
    779                 for (int j = 0; j < slices; j++)
    780                 {
    781 
    782                     // we build up the rings from capCenter in the direction of the 'direction' vector we computed earlier
    783 
    784                     // as we iterate through the rings they must be placed higher above the center, the height we need is sin(angle(i))
    785                     // as we iterate through the rings they must get smaller by the cos(angle(i))
    786 
    787                     // compute the four vertices
    788                     float ringSin1 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 ));
    789                     float ringCos1 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 ));
    790                     Vector3 w1 = (Vector3){
    791                         capCenter.x + (sinf(baseRingAngle*( i + 0 ))*b0.x + ringSin1*b1.x + ringCos1*b2.x)*radius,
    792                         capCenter.y + (sinf(baseRingAngle*( i + 0 ))*b0.y + ringSin1*b1.y + ringCos1*b2.y)*radius,
    793                         capCenter.z + (sinf(baseRingAngle*( i + 0 ))*b0.z + ringSin1*b1.z + ringCos1*b2.z)*radius
    794                     };
    795                     float ringSin2 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 0 ));
    796                     float ringCos2 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 0 ));
    797                     Vector3 w2 = (Vector3){
    798                         capCenter.x + (sinf(baseRingAngle*( i + 0 ))*b0.x + ringSin2*b1.x + ringCos2*b2.x)*radius,
    799                         capCenter.y + (sinf(baseRingAngle*( i + 0 ))*b0.y + ringSin2*b1.y + ringCos2*b2.y)*radius,
    800                         capCenter.z + (sinf(baseRingAngle*( i + 0 ))*b0.z + ringSin2*b1.z + ringCos2*b2.z)*radius
    801                     };
    802 
    803                     float ringSin3 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 1 ));
    804                     float ringCos3 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 1 ));
    805                     Vector3 w3 = (Vector3){
    806                         capCenter.x + (sinf(baseRingAngle*( i + 1 ))*b0.x + ringSin3*b1.x + ringCos3*b2.x)*radius,
    807                         capCenter.y + (sinf(baseRingAngle*( i + 1 ))*b0.y + ringSin3*b1.y + ringCos3*b2.y)*radius,
    808                         capCenter.z + (sinf(baseRingAngle*( i + 1 ))*b0.z + ringSin3*b1.z + ringCos3*b2.z)*radius
    809                     };
    810                     float ringSin4 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 1 ));
    811                     float ringCos4 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 1 ));
    812                     Vector3 w4 = (Vector3){
    813                         capCenter.x + (sinf(baseRingAngle*( i + 1 ))*b0.x + ringSin4*b1.x + ringCos4*b2.x)*radius,
    814                         capCenter.y + (sinf(baseRingAngle*( i + 1 ))*b0.y + ringSin4*b1.y + ringCos4*b2.y)*radius,
    815                         capCenter.z + (sinf(baseRingAngle*( i + 1 ))*b0.z + ringSin4*b1.z + ringCos4*b2.z)*radius
    816                     };
    817 
    818                     // Make sure cap triangle normals are facing outwards
    819                     if (c == 0)
    820                     {
    821                         rlVertex3f(w1.x, w1.y, w1.z);
    822                         rlVertex3f(w2.x, w2.y, w2.z);
    823                         rlVertex3f(w3.x, w3.y, w3.z);
    824 
    825                         rlVertex3f(w2.x, w2.y, w2.z);
    826                         rlVertex3f(w4.x, w4.y, w4.z);
    827                         rlVertex3f(w3.x, w3.y, w3.z);
    828                     }
    829                     else
    830                     {
    831                         rlVertex3f(w1.x, w1.y, w1.z);
    832                         rlVertex3f(w3.x, w3.y, w3.z);
    833                         rlVertex3f(w2.x, w2.y, w2.z);
    834 
    835                         rlVertex3f(w2.x, w2.y, w2.z);
    836                         rlVertex3f(w3.x, w3.y, w3.z);
    837                         rlVertex3f(w4.x, w4.y, w4.z);
    838                     }
    839                 }
    840             }
    841             capCenter = startPos;
    842             b0 = Vector3Scale(b0, -1.0f);
    843         }
    844         // render middle
    845         if (!sphereCase)
    846         {
    847             for (int j = 0; j < slices; j++)
    848             {
    849                 // compute the four vertices
    850                 float ringSin1 = sinf(baseSliceAngle*(j + 0))*radius;
    851                 float ringCos1 = cosf(baseSliceAngle*(j + 0))*radius;
    852                 Vector3 w1 = {
    853                     startPos.x + ringSin1*b1.x + ringCos1*b2.x,
    854                     startPos.y + ringSin1*b1.y + ringCos1*b2.y,
    855                     startPos.z + ringSin1*b1.z + ringCos1*b2.z
    856                 };
    857                 float ringSin2 = sinf(baseSliceAngle*(j + 1))*radius;
    858                 float ringCos2 = cosf(baseSliceAngle*(j + 1))*radius;
    859                 Vector3 w2 = {
    860                     startPos.x + ringSin2*b1.x + ringCos2*b2.x,
    861                     startPos.y + ringSin2*b1.y + ringCos2*b2.y,
    862                     startPos.z + ringSin2*b1.z + ringCos2*b2.z
    863                 };
    864 
    865                 float ringSin3 = sinf(baseSliceAngle*(j + 0))*radius;
    866                 float ringCos3 = cosf(baseSliceAngle*(j + 0))*radius;
    867                 Vector3 w3 = {
    868                     endPos.x + ringSin3*b1.x + ringCos3*b2.x,
    869                     endPos.y + ringSin3*b1.y + ringCos3*b2.y,
    870                     endPos.z + ringSin3*b1.z + ringCos3*b2.z
    871                 };
    872                 float ringSin4 = sinf(baseSliceAngle*(j + 1))*radius;
    873                 float ringCos4 = cosf(baseSliceAngle*(j + 1))*radius;
    874                 Vector3 w4 = {
    875                     endPos.x + ringSin4*b1.x + ringCos4*b2.x,
    876                     endPos.y + ringSin4*b1.y + ringCos4*b2.y,
    877                     endPos.z + ringSin4*b1.z + ringCos4*b2.z
    878                 };
    879                                                                         //          w2 x.-----------x startPos
    880                 rlVertex3f(w1.x, w1.y, w1.z);                         // |           |\'.  T0    /
    881                 rlVertex3f(w2.x, w2.y, w2.z);                         // T1          | \ '.     /
    882                 rlVertex3f(w3.x, w3.y, w3.z);                         // |           |T \  '.  /
    883                                                                         //             | 2 \ T 'x w1
    884                 rlVertex3f(w2.x, w2.y, w2.z);                         // |        w4 x.---\-1-|---x endPos
    885                 rlVertex3f(w4.x, w4.y, w4.z);                         // T2            '.  \  |T3/
    886                 rlVertex3f(w3.x, w3.y, w3.z);                         // |               '. \ | /
    887                                                                         //                   '.\|/
    888                                                                         //                   'x w3
    889             }
    890         }
    891     rlEnd();
    892 }
    893 
    894 // Draw capsule wires with the center of its sphere caps at startPos and endPos
    895 void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color)
    896 {
    897     if (slices < 3) slices = 3;
    898 
    899     Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
    900 
    901     // draw a sphere if start and end points are the same
    902     bool sphereCase = (direction.x == 0) && (direction.y == 0) && (direction.z == 0);
    903     if (sphereCase) direction = (Vector3){0.0f, 1.0f, 0.0f};
    904 
    905     // Construct a basis of the base and the caps:
    906     Vector3 b0 = Vector3Normalize(direction);
    907     Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction));
    908     Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
    909     Vector3 capCenter = endPos;
    910 
    911     float baseSliceAngle = (2.0f*PI)/slices;
    912     float baseRingAngle  = PI*0.5f/rings;
    913 
    914     rlBegin(RL_LINES);
    915         rlColor4ub(color.r, color.g, color.b, color.a);
    916 
    917         // render both caps
    918         for (int c = 0; c < 2; c++)
    919         {
    920             for (int i = 0; i < rings; i++)
    921             {
    922                 for (int j = 0; j < slices; j++)
    923                 {
    924 
    925                     // we build up the rings from capCenter in the direction of the 'direction' vector we computed earlier
    926 
    927                     // as we iterate through the rings they must be placed higher above the center, the height we need is sin(angle(i))
    928                     // as we iterate through the rings they must get smaller by the cos(angle(i))
    929 
    930                     // compute the four vertices
    931                     float ringSin1 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 ));
    932                     float ringCos1 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 ));
    933                     Vector3 w1 = (Vector3){
    934                         capCenter.x + (sinf(baseRingAngle*( i + 0 ))*b0.x + ringSin1*b1.x + ringCos1*b2.x)*radius,
    935                         capCenter.y + (sinf(baseRingAngle*( i + 0 ))*b0.y + ringSin1*b1.y + ringCos1*b2.y)*radius,
    936                         capCenter.z + (sinf(baseRingAngle*( i + 0 ))*b0.z + ringSin1*b1.z + ringCos1*b2.z)*radius
    937                     };
    938                     float ringSin2 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 0 ));
    939                     float ringCos2 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 0 ));
    940                     Vector3 w2 = (Vector3){
    941                         capCenter.x + (sinf(baseRingAngle*( i + 0 ))*b0.x + ringSin2*b1.x + ringCos2*b2.x)*radius,
    942                         capCenter.y + (sinf(baseRingAngle*( i + 0 ))*b0.y + ringSin2*b1.y + ringCos2*b2.y)*radius,
    943                         capCenter.z + (sinf(baseRingAngle*( i + 0 ))*b0.z + ringSin2*b1.z + ringCos2*b2.z)*radius
    944                     };
    945 
    946                     float ringSin3 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 1 ));
    947                     float ringCos3 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 1 ));
    948                     Vector3 w3 = (Vector3){
    949                         capCenter.x + (sinf(baseRingAngle*( i + 1 ))*b0.x + ringSin3*b1.x + ringCos3*b2.x)*radius,
    950                         capCenter.y + (sinf(baseRingAngle*( i + 1 ))*b0.y + ringSin3*b1.y + ringCos3*b2.y)*radius,
    951                         capCenter.z + (sinf(baseRingAngle*( i + 1 ))*b0.z + ringSin3*b1.z + ringCos3*b2.z)*radius
    952                     };
    953                     float ringSin4 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 1 ));
    954                     float ringCos4 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 1 ));
    955                     Vector3 w4 = (Vector3){
    956                         capCenter.x + (sinf(baseRingAngle*( i + 1 ))*b0.x + ringSin4*b1.x + ringCos4*b2.x)*radius,
    957                         capCenter.y + (sinf(baseRingAngle*( i + 1 ))*b0.y + ringSin4*b1.y + ringCos4*b2.y)*radius,
    958                         capCenter.z + (sinf(baseRingAngle*( i + 1 ))*b0.z + ringSin4*b1.z + ringCos4*b2.z)*radius
    959                     };
    960 
    961                     rlVertex3f(w1.x, w1.y, w1.z);
    962                     rlVertex3f(w2.x, w2.y, w2.z);
    963 
    964                     rlVertex3f(w2.x, w2.y, w2.z);
    965                     rlVertex3f(w3.x, w3.y, w3.z);
    966 
    967                     rlVertex3f(w1.x, w1.y, w1.z);
    968                     rlVertex3f(w3.x, w3.y, w3.z);
    969 
    970                     rlVertex3f(w2.x, w2.y, w2.z);
    971                     rlVertex3f(w4.x, w4.y, w4.z);
    972 
    973                     rlVertex3f(w3.x, w3.y, w3.z);
    974                     rlVertex3f(w4.x, w4.y, w4.z);
    975                 }
    976             }
    977             capCenter = startPos;
    978             b0 = Vector3Scale(b0, -1.0f);
    979         }
    980         // render middle
    981         if (!sphereCase)
    982         {
    983             for (int j = 0; j < slices; j++)
    984             {
    985                 // compute the four vertices
    986                 float ringSin1 = sinf(baseSliceAngle*(j + 0))*radius;
    987                 float ringCos1 = cosf(baseSliceAngle*(j + 0))*radius;
    988                 Vector3 w1 = {
    989                     startPos.x + ringSin1*b1.x + ringCos1*b2.x,
    990                     startPos.y + ringSin1*b1.y + ringCos1*b2.y,
    991                     startPos.z + ringSin1*b1.z + ringCos1*b2.z
    992                 };
    993                 float ringSin2 = sinf(baseSliceAngle*(j + 1))*radius;
    994                 float ringCos2 = cosf(baseSliceAngle*(j + 1))*radius;
    995                 Vector3 w2 = {
    996                     startPos.x + ringSin2*b1.x + ringCos2*b2.x,
    997                     startPos.y + ringSin2*b1.y + ringCos2*b2.y,
    998                     startPos.z + ringSin2*b1.z + ringCos2*b2.z
    999                 };
   1000 
   1001                 float ringSin3 = sinf(baseSliceAngle*(j + 0))*radius;
   1002                 float ringCos3 = cosf(baseSliceAngle*(j + 0))*radius;
   1003                 Vector3 w3 = {
   1004                     endPos.x + ringSin3*b1.x + ringCos3*b2.x,
   1005                     endPos.y + ringSin3*b1.y + ringCos3*b2.y,
   1006                     endPos.z + ringSin3*b1.z + ringCos3*b2.z
   1007                 };
   1008                 float ringSin4 = sinf(baseSliceAngle*(j + 1))*radius;
   1009                 float ringCos4 = cosf(baseSliceAngle*(j + 1))*radius;
   1010                 Vector3 w4 = {
   1011                     endPos.x + ringSin4*b1.x + ringCos4*b2.x,
   1012                     endPos.y + ringSin4*b1.y + ringCos4*b2.y,
   1013                     endPos.z + ringSin4*b1.z + ringCos4*b2.z
   1014                 };
   1015 
   1016                 rlVertex3f(w1.x, w1.y, w1.z);
   1017                 rlVertex3f(w3.x, w3.y, w3.z);
   1018 
   1019                 rlVertex3f(w2.x, w2.y, w2.z);
   1020                 rlVertex3f(w4.x, w4.y, w4.z);
   1021 
   1022                 rlVertex3f(w2.x, w2.y, w2.z);
   1023                 rlVertex3f(w3.x, w3.y, w3.z);
   1024             }
   1025         }
   1026     rlEnd();
   1027 }
   1028 
   1029 // Draw a plane
   1030 void DrawPlane(Vector3 centerPos, Vector2 size, Color color)
   1031 {
   1032     // NOTE: Plane is always created on XZ ground
   1033     rlPushMatrix();
   1034         rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
   1035         rlScalef(size.x, 1.0f, size.y);
   1036 
   1037         rlBegin(RL_QUADS);
   1038             rlColor4ub(color.r, color.g, color.b, color.a);
   1039             rlNormal3f(0.0f, 1.0f, 0.0f);
   1040 
   1041             rlVertex3f(-0.5f, 0.0f, -0.5f);
   1042             rlVertex3f(-0.5f, 0.0f, 0.5f);
   1043             rlVertex3f(0.5f, 0.0f, 0.5f);
   1044             rlVertex3f(0.5f, 0.0f, -0.5f);
   1045         rlEnd();
   1046     rlPopMatrix();
   1047 }
   1048 
   1049 // Draw a ray line
   1050 void DrawRay(Ray ray, Color color)
   1051 {
   1052     float scale = 10000;
   1053 
   1054     rlBegin(RL_LINES);
   1055         rlColor4ub(color.r, color.g, color.b, color.a);
   1056         rlColor4ub(color.r, color.g, color.b, color.a);
   1057 
   1058         rlVertex3f(ray.position.x, ray.position.y, ray.position.z);
   1059         rlVertex3f(ray.position.x + ray.direction.x*scale, ray.position.y + ray.direction.y*scale, ray.position.z + ray.direction.z*scale);
   1060     rlEnd();
   1061 }
   1062 
   1063 // Draw a grid centered at (0, 0, 0)
   1064 void DrawGrid(int slices, float spacing)
   1065 {
   1066     int halfSlices = slices/2;
   1067 
   1068     rlBegin(RL_LINES);
   1069         for (int i = -halfSlices; i <= halfSlices; i++)
   1070         {
   1071             if (i == 0)
   1072             {
   1073                 rlColor3f(0.5f, 0.5f, 0.5f);
   1074             }
   1075             else
   1076             {
   1077                 rlColor3f(0.75f, 0.75f, 0.75f);
   1078             }
   1079 
   1080             rlVertex3f((float)i*spacing, 0.0f, (float)-halfSlices*spacing);
   1081             rlVertex3f((float)i*spacing, 0.0f, (float)halfSlices*spacing);
   1082 
   1083             rlVertex3f((float)-halfSlices*spacing, 0.0f, (float)i*spacing);
   1084             rlVertex3f((float)halfSlices*spacing, 0.0f, (float)i*spacing);
   1085         }
   1086     rlEnd();
   1087 }
   1088 
   1089 // Load model from files (mesh and material)
   1090 Model LoadModel(const char *fileName)
   1091 {
   1092     Model model = { 0 };
   1093 
   1094 #if defined(SUPPORT_FILEFORMAT_OBJ)
   1095     if (IsFileExtension(fileName, ".obj")) model = LoadOBJ(fileName);
   1096 #endif
   1097 #if defined(SUPPORT_FILEFORMAT_IQM)
   1098     if (IsFileExtension(fileName, ".iqm")) model = LoadIQM(fileName);
   1099 #endif
   1100 #if defined(SUPPORT_FILEFORMAT_GLTF)
   1101     if (IsFileExtension(fileName, ".gltf") || IsFileExtension(fileName, ".glb")) model = LoadGLTF(fileName);
   1102 #endif
   1103 #if defined(SUPPORT_FILEFORMAT_VOX)
   1104     if (IsFileExtension(fileName, ".vox")) model = LoadVOX(fileName);
   1105 #endif
   1106 #if defined(SUPPORT_FILEFORMAT_M3D)
   1107     if (IsFileExtension(fileName, ".m3d")) model = LoadM3D(fileName);
   1108 #endif
   1109 
   1110     // Make sure model transform is set to identity matrix!
   1111     model.transform = MatrixIdentity();
   1112 
   1113     if ((model.meshCount != 0) && (model.meshes != NULL))
   1114     {
   1115         // Upload vertex data to GPU (static meshes)
   1116         for (int i = 0; i < model.meshCount; i++) UploadMesh(&model.meshes[i], false);
   1117     }
   1118     else TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load model mesh(es) data", fileName);
   1119 
   1120     if (model.materialCount == 0)
   1121     {
   1122         TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to load model material data, default to white material", fileName);
   1123 
   1124         model.materialCount = 1;
   1125         model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
   1126         model.materials[0] = LoadMaterialDefault();
   1127 
   1128         if (model.meshMaterial == NULL) model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
   1129     }
   1130 
   1131     return model;
   1132 }
   1133 
   1134 // Load model from generated mesh
   1135 // WARNING: A shallow copy of mesh is generated, passed by value,
   1136 // as long as struct contains pointers to data and some values, we get a copy
   1137 // of mesh pointing to same data as original version... be careful!
   1138 Model LoadModelFromMesh(Mesh mesh)
   1139 {
   1140     Model model = { 0 };
   1141 
   1142     model.transform = MatrixIdentity();
   1143 
   1144     model.meshCount = 1;
   1145     model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
   1146     model.meshes[0] = mesh;
   1147 
   1148     model.materialCount = 1;
   1149     model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
   1150     model.materials[0] = LoadMaterialDefault();
   1151 
   1152     model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
   1153     model.meshMaterial[0] = 0;  // First material index
   1154 
   1155     return model;
   1156 }
   1157 
   1158 // Check if a model is valid (loaded in GPU, VAO/VBOs)
   1159 bool IsModelValid(Model model)
   1160 {
   1161     bool result = false;
   1162 
   1163     if ((model.meshes != NULL) &&           // Validate model contains some mesh
   1164         (model.materials != NULL) &&        // Validate model contains some material (at least default one)
   1165         (model.meshMaterial != NULL) &&     // Validate mesh-material linkage
   1166         (model.meshCount > 0) &&            // Validate mesh count
   1167         (model.materialCount > 0)) result = true; // Validate material count
   1168 
   1169     // NOTE: Many elements could be validated from a model, including every model mesh VAO/VBOs
   1170     // but some VBOs could not be used, it depends on Mesh vertex data
   1171     for (int i = 0; i < model.meshCount; i++)
   1172     {
   1173         if ((model.meshes[i].vertices != NULL) && (model.meshes[i].vboId[0] == 0)) { result = false; break; }  // Vertex position buffer not uploaded to GPU
   1174         if ((model.meshes[i].texcoords != NULL) && (model.meshes[i].vboId[1] == 0)) { result = false; break; }  // Vertex textcoords buffer not uploaded to GPU
   1175         if ((model.meshes[i].normals != NULL) && (model.meshes[i].vboId[2] == 0)) { result = false; break; }  // Vertex normals buffer not uploaded to GPU
   1176         if ((model.meshes[i].colors != NULL) && (model.meshes[i].vboId[3] == 0)) { result = false; break; }  // Vertex colors buffer not uploaded to GPU
   1177         if ((model.meshes[i].tangents != NULL) && (model.meshes[i].vboId[4] == 0)) { result = false; break; }  // Vertex tangents buffer not uploaded to GPU
   1178         if ((model.meshes[i].texcoords2 != NULL) && (model.meshes[i].vboId[5] == 0)) { result = false; break; }  // Vertex texcoords2 buffer not uploaded to GPU
   1179         if ((model.meshes[i].indices != NULL) && (model.meshes[i].vboId[6] == 0)) { result = false; break; }  // Vertex indices buffer not uploaded to GPU
   1180         if ((model.meshes[i].boneIds != NULL) && (model.meshes[i].vboId[7] == 0)) { result = false; break; }  // Vertex boneIds buffer not uploaded to GPU
   1181         if ((model.meshes[i].boneWeights != NULL) && (model.meshes[i].vboId[8] == 0)) { result = false; break; }  // Vertex boneWeights buffer not uploaded to GPU
   1182 
   1183         // NOTE: Some OpenGL versions do not support VAO, so we don't check it
   1184         //if (model.meshes[i].vaoId == 0) { result = false; break }
   1185     }
   1186 
   1187     return result;
   1188 }
   1189 
   1190 // Unload model (meshes/materials) from memory (RAM and/or VRAM)
   1191 // NOTE: This function takes care of all model elements, for a detailed control
   1192 // over them, use UnloadMesh() and UnloadMaterial()
   1193 void UnloadModel(Model model)
   1194 {
   1195     // Unload meshes
   1196     for (int i = 0; i < model.meshCount; i++) UnloadMesh(model.meshes[i]);
   1197 
   1198     // Unload materials maps
   1199     // NOTE: As the user could be sharing shaders and textures between models,
   1200     // we don't unload the material but just free its maps,
   1201     // the user is responsible for freeing models shaders and textures
   1202     for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps);
   1203 
   1204     // Unload arrays
   1205     RL_FREE(model.meshes);
   1206     RL_FREE(model.materials);
   1207     RL_FREE(model.meshMaterial);
   1208 
   1209     // Unload animation data
   1210     RL_FREE(model.bones);
   1211     RL_FREE(model.bindPose);
   1212 
   1213     TRACELOG(LOG_INFO, "MODEL: Unloaded model (and meshes) from RAM and VRAM");
   1214 }
   1215 
   1216 // Compute model bounding box limits (considers all meshes)
   1217 BoundingBox GetModelBoundingBox(Model model)
   1218 {
   1219     BoundingBox bounds = { 0 };
   1220 
   1221     if (model.meshCount > 0)
   1222     {
   1223         Vector3 temp = { 0 };
   1224         bounds = GetMeshBoundingBox(model.meshes[0]);
   1225 
   1226         for (int i = 1; i < model.meshCount; i++)
   1227         {
   1228             BoundingBox tempBounds = GetMeshBoundingBox(model.meshes[i]);
   1229 
   1230             temp.x = (bounds.min.x < tempBounds.min.x)? bounds.min.x : tempBounds.min.x;
   1231             temp.y = (bounds.min.y < tempBounds.min.y)? bounds.min.y : tempBounds.min.y;
   1232             temp.z = (bounds.min.z < tempBounds.min.z)? bounds.min.z : tempBounds.min.z;
   1233             bounds.min = temp;
   1234 
   1235             temp.x = (bounds.max.x > tempBounds.max.x)? bounds.max.x : tempBounds.max.x;
   1236             temp.y = (bounds.max.y > tempBounds.max.y)? bounds.max.y : tempBounds.max.y;
   1237             temp.z = (bounds.max.z > tempBounds.max.z)? bounds.max.z : tempBounds.max.z;
   1238             bounds.max = temp;
   1239         }
   1240     }
   1241 
   1242     // Apply model.transform to bounding box
   1243     // WARNING: Current BoundingBox structure design does not support rotation transformations,
   1244     // in those cases is up to the user to calculate the proper box bounds (8 vertices transformed)
   1245     bounds.min = Vector3Transform(bounds.min, model.transform);
   1246     bounds.max = Vector3Transform(bounds.max, model.transform);
   1247 
   1248     return bounds;
   1249 }
   1250 
   1251 // Upload vertex data into a VAO (if supported) and VBO
   1252 void UploadMesh(Mesh *mesh, bool dynamic)
   1253 {
   1254     if (mesh->vaoId > 0)
   1255     {
   1256         // Check if mesh has already been loaded in GPU
   1257         TRACELOG(LOG_WARNING, "VAO: [ID %i] Trying to re-load an already loaded mesh", mesh->vaoId);
   1258         return;
   1259     }
   1260 
   1261     mesh->vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VERTEX_BUFFERS, sizeof(unsigned int));
   1262 
   1263     mesh->vaoId = 0;        // Vertex Array Object
   1264     mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = 0;     // Vertex buffer: positions
   1265     mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = 0;     // Vertex buffer: texcoords
   1266     mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = 0;       // Vertex buffer: normals
   1267     mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = 0;        // Vertex buffer: colors
   1268     mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = 0;      // Vertex buffer: tangents
   1269     mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = 0;    // Vertex buffer: texcoords2
   1270     mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = 0;      // Vertex buffer: indices
   1271 
   1272 #ifdef RL_SUPPORT_MESH_GPU_SKINNING
   1273     mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = 0;      // Vertex buffer: boneIds
   1274     mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = 0;  // Vertex buffer: boneWeights
   1275 #endif
   1276 
   1277 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
   1278     mesh->vaoId = rlLoadVertexArray();
   1279     rlEnableVertexArray(mesh->vaoId);
   1280 
   1281     // NOTE: Vertex attributes must be uploaded considering default locations points and available vertex data
   1282 
   1283     // Enable vertex attributes: position (shader-location = 0)
   1284     void *vertices = (mesh->animVertices != NULL)? mesh->animVertices : mesh->vertices;
   1285     mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = rlLoadVertexBuffer(vertices, mesh->vertexCount*3*sizeof(float), dynamic);
   1286     rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, 3, RL_FLOAT, 0, 0, 0);
   1287     rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION);
   1288 
   1289     // Enable vertex attributes: texcoords (shader-location = 1)
   1290     mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic);
   1291     rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, 2, RL_FLOAT, 0, 0, 0);
   1292     rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD);
   1293 
   1294     // WARNING: When setting default vertex attribute values, the values for each generic vertex attribute
   1295     // is part of current state, and it is maintained even if a different program object is used
   1296 
   1297     if (mesh->normals != NULL)
   1298     {
   1299         // Enable vertex attributes: normals (shader-location = 2)
   1300         void *normals = (mesh->animNormals != NULL)? mesh->animNormals : mesh->normals;
   1301         mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = rlLoadVertexBuffer(normals, mesh->vertexCount*3*sizeof(float), dynamic);
   1302         rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, 3, RL_FLOAT, 0, 0, 0);
   1303         rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL);
   1304     }
   1305     else
   1306     {
   1307         // Default vertex attribute: normal
   1308         // WARNING: Default value provided to shader if location available
   1309         float value[3] = { 1.0f, 1.0f, 1.0f };
   1310         rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, value, SHADER_ATTRIB_VEC3, 3);
   1311         rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL);
   1312     }
   1313 
   1314     if (mesh->colors != NULL)
   1315     {
   1316         // Enable vertex attribute: color (shader-location = 3)
   1317         mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = rlLoadVertexBuffer(mesh->colors, mesh->vertexCount*4*sizeof(unsigned char), dynamic);
   1318         rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, 4, RL_UNSIGNED_BYTE, 1, 0, 0);
   1319         rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR);
   1320     }
   1321     else
   1322     {
   1323         // Default vertex attribute: color
   1324         // WARNING: Default value provided to shader if location available
   1325         float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };    // WHITE
   1326         rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, value, SHADER_ATTRIB_VEC4, 4);
   1327         rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR);
   1328     }
   1329 
   1330     if (mesh->tangents != NULL)
   1331     {
   1332         // Enable vertex attribute: tangent (shader-location = 4)
   1333         mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), dynamic);
   1334         rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0);
   1335         rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT);
   1336     }
   1337     else
   1338     {
   1339         // Default vertex attribute: tangent
   1340         // WARNING: Default value provided to shader if location available
   1341         float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
   1342         rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, value, SHADER_ATTRIB_VEC4, 4);
   1343         rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT);
   1344     }
   1345 
   1346     if (mesh->texcoords2 != NULL)
   1347     {
   1348         // Enable vertex attribute: texcoord2 (shader-location = 5)
   1349         mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = rlLoadVertexBuffer(mesh->texcoords2, mesh->vertexCount*2*sizeof(float), dynamic);
   1350         rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, 2, RL_FLOAT, 0, 0, 0);
   1351         rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2);
   1352     }
   1353     else
   1354     {
   1355         // Default vertex attribute: texcoord2
   1356         // WARNING: Default value provided to shader if location available
   1357         float value[2] = { 0.0f, 0.0f };
   1358         rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, value, SHADER_ATTRIB_VEC2, 2);
   1359         rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2);
   1360     }
   1361 
   1362 #ifdef RL_SUPPORT_MESH_GPU_SKINNING
   1363     if (mesh->boneIds != NULL)
   1364     {
   1365         // Enable vertex attribute: boneIds (shader-location = 7)
   1366         mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = rlLoadVertexBuffer(mesh->boneIds, mesh->vertexCount*4*sizeof(unsigned char), dynamic);
   1367         rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, 4, RL_UNSIGNED_BYTE, 0, 0, 0);
   1368         rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS);
   1369     }
   1370     else
   1371     {
   1372         // Default vertex attribute: boneIds
   1373         // WARNING: Default value provided to shader if location available
   1374         float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
   1375         rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, value, SHADER_ATTRIB_VEC4, 4);
   1376         rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS);
   1377     }
   1378 
   1379     if (mesh->boneWeights != NULL)
   1380     {
   1381         // Enable vertex attribute: boneWeights (shader-location = 8)
   1382         mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = rlLoadVertexBuffer(mesh->boneWeights, mesh->vertexCount*4*sizeof(float), dynamic);
   1383         rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, 4, RL_FLOAT, 0, 0, 0);
   1384         rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS);
   1385     }
   1386     else
   1387     {
   1388         // Default vertex attribute: boneWeights
   1389         // WARNING: Default value provided to shader if location available
   1390         float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
   1391         rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, value, SHADER_ATTRIB_VEC4, 2);
   1392         rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS);
   1393     }
   1394 #endif
   1395 
   1396     if (mesh->indices != NULL)
   1397     {
   1398         mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = rlLoadVertexBufferElement(mesh->indices, mesh->triangleCount*3*sizeof(unsigned short), dynamic);
   1399     }
   1400 
   1401     if (mesh->vaoId > 0) TRACELOG(LOG_INFO, "VAO: [ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vaoId);
   1402     else TRACELOG(LOG_INFO, "VBO: Mesh uploaded successfully to VRAM (GPU)");
   1403 
   1404     rlDisableVertexArray();
   1405 #endif
   1406 }
   1407 
   1408 // Update mesh vertex data in GPU for a specific buffer index
   1409 void UpdateMeshBuffer(Mesh mesh, int index, const void *data, int dataSize, int offset)
   1410 {
   1411     rlUpdateVertexBuffer(mesh.vboId[index], data, dataSize, offset);
   1412 }
   1413 
   1414 // Draw a 3d mesh with material and transform
   1415 void DrawMesh(Mesh mesh, Material material, Matrix transform)
   1416 {
   1417 #if defined(GRAPHICS_API_OPENGL_11)
   1418     #define GL_VERTEX_ARRAY         0x8074
   1419     #define GL_NORMAL_ARRAY         0x8075
   1420     #define GL_COLOR_ARRAY          0x8076
   1421     #define GL_TEXTURE_COORD_ARRAY  0x8078
   1422 
   1423     rlEnableTexture(material.maps[MATERIAL_MAP_DIFFUSE].texture.id);
   1424 
   1425     rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices);
   1426     rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords);
   1427     rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals);
   1428     rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors);
   1429 
   1430     rlPushMatrix();
   1431         rlMultMatrixf(MatrixToFloat(transform));
   1432         rlColor4ub(material.maps[MATERIAL_MAP_DIFFUSE].color.r,
   1433                    material.maps[MATERIAL_MAP_DIFFUSE].color.g,
   1434                    material.maps[MATERIAL_MAP_DIFFUSE].color.b,
   1435                    material.maps[MATERIAL_MAP_DIFFUSE].color.a);
   1436 
   1437         if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, mesh.indices);
   1438         else rlDrawVertexArray(0, mesh.vertexCount);
   1439     rlPopMatrix();
   1440 
   1441     rlDisableStatePointer(GL_VERTEX_ARRAY);
   1442     rlDisableStatePointer(GL_TEXTURE_COORD_ARRAY);
   1443     rlDisableStatePointer(GL_NORMAL_ARRAY);
   1444     rlDisableStatePointer(GL_COLOR_ARRAY);
   1445 
   1446     rlDisableTexture();
   1447 #endif
   1448 
   1449 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
   1450     // Bind shader program
   1451     rlEnableShader(material.shader.id);
   1452 
   1453     // Send required data to shader (matrices, values)
   1454     //-----------------------------------------------------
   1455     // Upload to shader material.colDiffuse
   1456     if (material.shader.locs[SHADER_LOC_COLOR_DIFFUSE] != -1)
   1457     {
   1458         float values[4] = {
   1459             (float)material.maps[MATERIAL_MAP_DIFFUSE].color.r/255.0f,
   1460             (float)material.maps[MATERIAL_MAP_DIFFUSE].color.g/255.0f,
   1461             (float)material.maps[MATERIAL_MAP_DIFFUSE].color.b/255.0f,
   1462             (float)material.maps[MATERIAL_MAP_DIFFUSE].color.a/255.0f
   1463         };
   1464 
   1465         rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_DIFFUSE], values, SHADER_UNIFORM_VEC4, 1);
   1466     }
   1467 
   1468     // Upload to shader material.colSpecular (if location available)
   1469     if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1)
   1470     {
   1471         float values[4] = {
   1472             (float)material.maps[MATERIAL_MAP_SPECULAR].color.r/255.0f,
   1473             (float)material.maps[MATERIAL_MAP_SPECULAR].color.g/255.0f,
   1474             (float)material.maps[MATERIAL_MAP_SPECULAR].color.b/255.0f,
   1475             (float)material.maps[MATERIAL_MAP_SPECULAR].color.a/255.0f
   1476         };
   1477 
   1478         rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_SPECULAR], values, SHADER_UNIFORM_VEC4, 1);
   1479     }
   1480 
   1481     // Get a copy of current matrices to work with,
   1482     // just in case stereo render is required, and we need to modify them
   1483     // NOTE: At this point the modelview matrix just contains the view matrix (camera)
   1484     // That's because BeginMode3D() sets it and there is no model-drawing function
   1485     // that modifies it, all use rlPushMatrix() and rlPopMatrix()
   1486     Matrix matModel = MatrixIdentity();
   1487     Matrix matView = rlGetMatrixModelview();
   1488     Matrix matModelView = MatrixIdentity();
   1489     Matrix matProjection = rlGetMatrixProjection();
   1490 
   1491     // Upload view and projection matrices (if locations available)
   1492     if (material.shader.locs[SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_VIEW], matView);
   1493     if (material.shader.locs[SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_PROJECTION], matProjection);
   1494 
   1495     // Accumulate several model transformations:
   1496     //    transform: model transformation provided (includes DrawModel() params combined with model.transform)
   1497     //    rlGetMatrixTransform(): rlgl internal transform matrix due to push/pop matrix stack
   1498     matModel = MatrixMultiply(transform, rlGetMatrixTransform());
   1499 
   1500     // Model transformation matrix is sent to shader uniform location: SHADER_LOC_MATRIX_MODEL
   1501     if (material.shader.locs[SHADER_LOC_MATRIX_MODEL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MODEL], matModel);
   1502 
   1503     // Get model-view matrix
   1504     matModelView = MatrixMultiply(matModel, matView);
   1505 
   1506     // Upload model normal matrix (if locations available)
   1507     if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));
   1508 
   1509 #ifdef RL_SUPPORT_MESH_GPU_SKINNING
   1510     // Upload Bone Transforms
   1511     if ((material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1) && mesh.boneMatrices)
   1512     {
   1513         rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount);
   1514     }
   1515 #endif
   1516     //-----------------------------------------------------
   1517 
   1518     // Bind active texture maps (if available)
   1519     for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
   1520     {
   1521         if (material.maps[i].texture.id > 0)
   1522         {
   1523             // Select current shader texture slot
   1524             rlActiveTextureSlot(i);
   1525 
   1526             // Enable texture for active slot
   1527             if ((i == MATERIAL_MAP_IRRADIANCE) ||
   1528                 (i == MATERIAL_MAP_PREFILTER) ||
   1529                 (i == MATERIAL_MAP_CUBEMAP)) rlEnableTextureCubemap(material.maps[i].texture.id);
   1530             else rlEnableTexture(material.maps[i].texture.id);
   1531 
   1532             rlSetUniform(material.shader.locs[SHADER_LOC_MAP_DIFFUSE + i], &i, SHADER_UNIFORM_INT, 1);
   1533         }
   1534     }
   1535 
   1536     // Try binding vertex array objects (VAO) or use VBOs if not possible
   1537     // WARNING: UploadMesh() enables all vertex attributes available in mesh and sets default attribute values
   1538     // for shader expected vertex attributes that are not provided by the mesh (i.e. colors)
   1539     // This could be a dangerous approach because different meshes with different shaders can enable/disable some attributes
   1540     if (!rlEnableVertexArray(mesh.vaoId))
   1541     {
   1542         // Bind mesh VBO data: vertex position (shader-location = 0)
   1543         rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION]);
   1544         rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0);
   1545         rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]);
   1546 
   1547         // Bind mesh VBO data: vertex texcoords (shader-location = 1)
   1548         rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD]);
   1549         rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0);
   1550         rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]);
   1551 
   1552         if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1)
   1553         {
   1554             // Bind mesh VBO data: vertex normals (shader-location = 2)
   1555             rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL]);
   1556             rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0);
   1557             rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]);
   1558         }
   1559 
   1560         // Bind mesh VBO data: vertex colors (shader-location = 3, if available)
   1561         if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1)
   1562         {
   1563             if (mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] != 0)
   1564             {
   1565                 rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR]);
   1566                 rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0);
   1567                 rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
   1568             }
   1569             else
   1570             {
   1571                 // Set default value for defined vertex attribute in shader but not provided by mesh
   1572                 // WARNING: It could result in GPU undefined behaviour
   1573                 float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
   1574                 rlSetVertexAttributeDefault(material.shader.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC4, 4);
   1575                 rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
   1576             }
   1577         }
   1578 
   1579         // Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
   1580         if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1)
   1581         {
   1582             rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT]);
   1583             rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0);
   1584             rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]);
   1585         }
   1586 
   1587         // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
   1588         if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1)
   1589         {
   1590             rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2]);
   1591             rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0);
   1592             rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]);
   1593         }
   1594 
   1595 #ifdef RL_SUPPORT_MESH_GPU_SKINNING
   1596         // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available)
   1597         if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1)
   1598         {
   1599             rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS]);
   1600             rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0);
   1601             rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]);
   1602         }
   1603 
   1604         // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available)
   1605         if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1)
   1606         {
   1607             rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS]);
   1608             rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0);
   1609             rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]);
   1610         }
   1611 #endif
   1612 
   1613         if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]);
   1614     }
   1615 
   1616     int eyeCount = 1;
   1617     if (rlIsStereoRenderEnabled()) eyeCount = 2;
   1618 
   1619     for (int eye = 0; eye < eyeCount; eye++)
   1620     {
   1621         // Calculate model-view-projection matrix (MVP)
   1622         Matrix matModelViewProjection = MatrixIdentity();
   1623         if (eyeCount == 1) matModelViewProjection = MatrixMultiply(matModelView, matProjection);
   1624         else
   1625         {
   1626             // Setup current eye viewport (half screen width)
   1627             rlViewport(eye*rlGetFramebufferWidth()/2, 0, rlGetFramebufferWidth()/2, rlGetFramebufferHeight());
   1628             matModelViewProjection = MatrixMultiply(MatrixMultiply(matModelView, rlGetMatrixViewOffsetStereo(eye)), rlGetMatrixProjectionStereo(eye));
   1629         }
   1630 
   1631         // Send combined model-view-projection matrix to shader
   1632         rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MVP], matModelViewProjection);
   1633 
   1634         // Draw mesh
   1635         if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, 0);
   1636         else rlDrawVertexArray(0, mesh.vertexCount);
   1637     }
   1638 
   1639     // Unbind all bound texture maps
   1640     for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
   1641     {
   1642         if (material.maps[i].texture.id > 0)
   1643         {
   1644             // Select current shader texture slot
   1645             rlActiveTextureSlot(i);
   1646 
   1647             // Disable texture for active slot
   1648             if ((i == MATERIAL_MAP_IRRADIANCE) ||
   1649                 (i == MATERIAL_MAP_PREFILTER) ||
   1650                 (i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap();
   1651             else rlDisableTexture();
   1652         }
   1653     }
   1654 
   1655     // Disable all possible vertex array objects (or VBOs)
   1656     rlDisableVertexArray();
   1657     rlDisableVertexBuffer();
   1658     rlDisableVertexBufferElement();
   1659 
   1660     // Disable shader program
   1661     rlDisableShader();
   1662 
   1663     // Restore rlgl internal modelview and projection matrices
   1664     rlSetMatrixModelview(matView);
   1665     rlSetMatrixProjection(matProjection);
   1666 #endif
   1667 }
   1668 
   1669 // Draw multiple mesh instances with material and different transforms
   1670 void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, int instances)
   1671 {
   1672 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
   1673     // Instancing required variables
   1674     float16 *instanceTransforms = NULL;
   1675     unsigned int instancesVboId = 0;
   1676 
   1677     // Bind shader program
   1678     rlEnableShader(material.shader.id);
   1679 
   1680     // Send required data to shader (matrices, values)
   1681     //-----------------------------------------------------
   1682     // Upload to shader material.colDiffuse
   1683     if (material.shader.locs[SHADER_LOC_COLOR_DIFFUSE] != -1)
   1684     {
   1685         float values[4] = {
   1686             (float)material.maps[MATERIAL_MAP_DIFFUSE].color.r/255.0f,
   1687             (float)material.maps[MATERIAL_MAP_DIFFUSE].color.g/255.0f,
   1688             (float)material.maps[MATERIAL_MAP_DIFFUSE].color.b/255.0f,
   1689             (float)material.maps[MATERIAL_MAP_DIFFUSE].color.a/255.0f
   1690         };
   1691 
   1692         rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_DIFFUSE], values, SHADER_UNIFORM_VEC4, 1);
   1693     }
   1694 
   1695     // Upload to shader material.colSpecular (if location available)
   1696     if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1)
   1697     {
   1698         float values[4] = {
   1699             (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.r/255.0f,
   1700             (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.g/255.0f,
   1701             (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.b/255.0f,
   1702             (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.a/255.0f
   1703         };
   1704 
   1705         rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_SPECULAR], values, SHADER_UNIFORM_VEC4, 1);
   1706     }
   1707 
   1708     // Get a copy of current matrices to work with,
   1709     // just in case stereo render is required, and we need to modify them
   1710     // NOTE: At this point the modelview matrix just contains the view matrix (camera)
   1711     // That's because BeginMode3D() sets it and there is no model-drawing function
   1712     // that modifies it, all use rlPushMatrix() and rlPopMatrix()
   1713     Matrix matModel = MatrixIdentity();
   1714     Matrix matView = rlGetMatrixModelview();
   1715     Matrix matModelView = MatrixIdentity();
   1716     Matrix matProjection = rlGetMatrixProjection();
   1717 
   1718     // Upload view and projection matrices (if locations available)
   1719     if (material.shader.locs[SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_VIEW], matView);
   1720     if (material.shader.locs[SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_PROJECTION], matProjection);
   1721 
   1722     // Create instances buffer
   1723     instanceTransforms = (float16 *)RL_MALLOC(instances*sizeof(float16));
   1724 
   1725     // Fill buffer with instances transformations as float16 arrays
   1726     for (int i = 0; i < instances; i++) instanceTransforms[i] = MatrixToFloatV(transforms[i]);
   1727 
   1728     // Enable mesh VAO to attach new buffer
   1729     rlEnableVertexArray(mesh.vaoId);
   1730 
   1731     // This could alternatively use a static VBO and either glMapBuffer() or glBufferSubData()
   1732     // It isn't clear which would be reliably faster in all cases and on all platforms,
   1733     // anecdotally glMapBuffer() seems very slow (syncs) while glBufferSubData() seems
   1734     // no faster, since we're transferring all the transform matrices anyway
   1735     instancesVboId = rlLoadVertexBuffer(instanceTransforms, instances*sizeof(float16), false);
   1736 
   1737     // Instances transformation matrices are send to shader attribute location: SHADER_LOC_MATRIX_MODEL
   1738     for (unsigned int i = 0; i < 4; i++)
   1739     {
   1740         rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_MATRIX_MODEL] + i);
   1741         rlSetVertexAttribute(material.shader.locs[SHADER_LOC_MATRIX_MODEL] + i, 4, RL_FLOAT, 0, sizeof(Matrix), i*sizeof(Vector4));
   1742         rlSetVertexAttributeDivisor(material.shader.locs[SHADER_LOC_MATRIX_MODEL] + i, 1);
   1743     }
   1744 
   1745     rlDisableVertexBuffer();
   1746     rlDisableVertexArray();
   1747 
   1748     // Accumulate internal matrix transform (push/pop) and view matrix
   1749     // NOTE: In this case, model instance transformation must be computed in the shader
   1750     matModelView = MatrixMultiply(rlGetMatrixTransform(), matView);
   1751 
   1752     // Upload model normal matrix (if locations available)
   1753     if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));
   1754 
   1755 #ifdef RL_SUPPORT_MESH_GPU_SKINNING
   1756     // Upload Bone Transforms
   1757     if ((material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1) && mesh.boneMatrices)
   1758     {
   1759         rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount);
   1760     }
   1761 #endif
   1762 
   1763     //-----------------------------------------------------
   1764 
   1765     // Bind active texture maps (if available)
   1766     for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
   1767     {
   1768         if (material.maps[i].texture.id > 0)
   1769         {
   1770             // Select current shader texture slot
   1771             rlActiveTextureSlot(i);
   1772 
   1773             // Enable texture for active slot
   1774             if ((i == MATERIAL_MAP_IRRADIANCE) ||
   1775                 (i == MATERIAL_MAP_PREFILTER) ||
   1776                 (i == MATERIAL_MAP_CUBEMAP)) rlEnableTextureCubemap(material.maps[i].texture.id);
   1777             else rlEnableTexture(material.maps[i].texture.id);
   1778 
   1779             rlSetUniform(material.shader.locs[SHADER_LOC_MAP_DIFFUSE + i], &i, SHADER_UNIFORM_INT, 1);
   1780         }
   1781     }
   1782 
   1783     // Try binding vertex array objects (VAO)
   1784     // or use VBOs if not possible
   1785     if (!rlEnableVertexArray(mesh.vaoId))
   1786     {
   1787         // Bind mesh VBO data: vertex position (shader-location = 0)
   1788         rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION]);
   1789         rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0);
   1790         rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]);
   1791 
   1792         // Bind mesh VBO data: vertex texcoords (shader-location = 1)
   1793         rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD]);
   1794         rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0);
   1795         rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]);
   1796 
   1797         if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1)
   1798         {
   1799             // Bind mesh VBO data: vertex normals (shader-location = 2)
   1800             rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL]);
   1801             rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0);
   1802             rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]);
   1803         }
   1804 
   1805         // Bind mesh VBO data: vertex colors (shader-location = 3, if available)
   1806         if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1)
   1807         {
   1808             if (mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] != 0)
   1809             {
   1810                 rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR]);
   1811                 rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0);
   1812                 rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
   1813             }
   1814             else
   1815             {
   1816                 // Set default value for unused attribute
   1817                 // NOTE: Required when using default shader and no VAO support
   1818                 float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
   1819                 rlSetVertexAttributeDefault(material.shader.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC4, 4);
   1820                 rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
   1821             }
   1822         }
   1823 
   1824         // Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
   1825         if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1)
   1826         {
   1827             rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT]);
   1828             rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0);
   1829             rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]);
   1830         }
   1831 
   1832         // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
   1833         if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1)
   1834         {
   1835             rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2]);
   1836             rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0);
   1837             rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]);
   1838         }
   1839 
   1840 #ifdef RL_SUPPORT_MESH_GPU_SKINNING
   1841         // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available)
   1842         if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1)
   1843         {
   1844             rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS]);
   1845             rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0);
   1846             rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]);
   1847         }
   1848 
   1849         // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available)
   1850         if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1)
   1851         {
   1852             rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS]);
   1853             rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0);
   1854             rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]);
   1855         }
   1856 #endif
   1857 
   1858         if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]);
   1859     }
   1860 
   1861     int eyeCount = 1;
   1862     if (rlIsStereoRenderEnabled()) eyeCount = 2;
   1863 
   1864     for (int eye = 0; eye < eyeCount; eye++)
   1865     {
   1866         // Calculate model-view-projection matrix (MVP)
   1867         Matrix matModelViewProjection = MatrixIdentity();
   1868         if (eyeCount == 1) matModelViewProjection = MatrixMultiply(matModelView, matProjection);
   1869         else
   1870         {
   1871             // Setup current eye viewport (half screen width)
   1872             rlViewport(eye*rlGetFramebufferWidth()/2, 0, rlGetFramebufferWidth()/2, rlGetFramebufferHeight());
   1873             matModelViewProjection = MatrixMultiply(MatrixMultiply(matModelView, rlGetMatrixViewOffsetStereo(eye)), rlGetMatrixProjectionStereo(eye));
   1874         }
   1875 
   1876         // Send combined model-view-projection matrix to shader
   1877         rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MVP], matModelViewProjection);
   1878 
   1879         // Draw mesh instanced
   1880         if (mesh.indices != NULL) rlDrawVertexArrayElementsInstanced(0, mesh.triangleCount*3, 0, instances);
   1881         else rlDrawVertexArrayInstanced(0, mesh.vertexCount, instances);
   1882     }
   1883 
   1884     // Unbind all bound texture maps
   1885     for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
   1886     {
   1887         if (material.maps[i].texture.id > 0)
   1888         {
   1889             // Select current shader texture slot
   1890             rlActiveTextureSlot(i);
   1891 
   1892             // Disable texture for active slot
   1893             if ((i == MATERIAL_MAP_IRRADIANCE) ||
   1894                 (i == MATERIAL_MAP_PREFILTER) ||
   1895                 (i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap();
   1896             else rlDisableTexture();
   1897         }
   1898     }
   1899 
   1900     // Disable all possible vertex array objects (or VBOs)
   1901     rlDisableVertexArray();
   1902     rlDisableVertexBuffer();
   1903     rlDisableVertexBufferElement();
   1904 
   1905     // Disable shader program
   1906     rlDisableShader();
   1907 
   1908     // Remove instance transforms buffer
   1909     rlUnloadVertexBuffer(instancesVboId);
   1910     RL_FREE(instanceTransforms);
   1911 #endif
   1912 }
   1913 
   1914 // Unload mesh from memory (RAM and VRAM)
   1915 void UnloadMesh(Mesh mesh)
   1916 {
   1917     // Unload rlgl mesh vboId data
   1918     rlUnloadVertexArray(mesh.vaoId);
   1919 
   1920     if (mesh.vboId != NULL) for (int i = 0; i < MAX_MESH_VERTEX_BUFFERS; i++) rlUnloadVertexBuffer(mesh.vboId[i]);
   1921     RL_FREE(mesh.vboId);
   1922 
   1923     RL_FREE(mesh.vertices);
   1924     RL_FREE(mesh.texcoords);
   1925     RL_FREE(mesh.normals);
   1926     RL_FREE(mesh.colors);
   1927     RL_FREE(mesh.tangents);
   1928     RL_FREE(mesh.texcoords2);
   1929     RL_FREE(mesh.indices);
   1930 
   1931     RL_FREE(mesh.animVertices);
   1932     RL_FREE(mesh.animNormals);
   1933     RL_FREE(mesh.boneWeights);
   1934     RL_FREE(mesh.boneIds);
   1935     RL_FREE(mesh.boneMatrices);
   1936 }
   1937 
   1938 // Export mesh data to file
   1939 bool ExportMesh(Mesh mesh, const char *fileName)
   1940 {
   1941     bool success = false;
   1942 
   1943     if (IsFileExtension(fileName, ".obj"))
   1944     {
   1945         // Estimated data size, it should be enough...
   1946         int dataSize = mesh.vertexCount*(int)strlen("v 0000.00f 0000.00f 0000.00f") +
   1947                        mesh.vertexCount*(int)strlen("vt 0.000f 0.00f") +
   1948                        mesh.vertexCount*(int)strlen("vn 0.000f 0.00f 0.00f") +
   1949                        mesh.triangleCount*(int)strlen("f 00000/00000/00000 00000/00000/00000 00000/00000/00000");
   1950 
   1951         // NOTE: Text data buffer size is estimated considering mesh data size
   1952         char *txtData = (char *)RL_CALLOC(dataSize*2 + 2000, sizeof(char));
   1953 
   1954         int byteCount = 0;
   1955         byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n");
   1956         byteCount += sprintf(txtData + byteCount, "# //                                                                              //\n");
   1957         byteCount += sprintf(txtData + byteCount, "# // rMeshOBJ exporter v1.0 - Mesh exported as triangle faces and not optimized   //\n");
   1958         byteCount += sprintf(txtData + byteCount, "# //                                                                              //\n");
   1959         byteCount += sprintf(txtData + byteCount, "# // more info and bugs-report:  github.com/raysan5/raylib                        //\n");
   1960         byteCount += sprintf(txtData + byteCount, "# // feedback and support:       ray[at]raylib.com                                //\n");
   1961         byteCount += sprintf(txtData + byteCount, "# //                                                                              //\n");
   1962         byteCount += sprintf(txtData + byteCount, "# // Copyright (c) 2018-2024 Ramon Santamaria (@raysan5)                          //\n");
   1963         byteCount += sprintf(txtData + byteCount, "# //                                                                              //\n");
   1964         byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n\n");
   1965         byteCount += sprintf(txtData + byteCount, "# Vertex Count:     %i\n", mesh.vertexCount);
   1966         byteCount += sprintf(txtData + byteCount, "# Triangle Count:   %i\n\n", mesh.triangleCount);
   1967 
   1968         byteCount += sprintf(txtData + byteCount, "g mesh\n");
   1969 
   1970         for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3)
   1971         {
   1972             byteCount += sprintf(txtData + byteCount, "v %.2f %.2f %.2f\n", mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]);
   1973         }
   1974 
   1975         for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 2)
   1976         {
   1977             byteCount += sprintf(txtData + byteCount, "vt %.3f %.3f\n", mesh.texcoords[v], mesh.texcoords[v + 1]);
   1978         }
   1979 
   1980         for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3)
   1981         {
   1982             byteCount += sprintf(txtData + byteCount, "vn %.3f %.3f %.3f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]);
   1983         }
   1984 
   1985         if (mesh.indices != NULL)
   1986         {
   1987             for (int i = 0, v = 0; i < mesh.triangleCount; i++, v += 3)
   1988             {
   1989                 byteCount += sprintf(txtData + byteCount, "f %i/%i/%i %i/%i/%i %i/%i/%i\n",
   1990                     mesh.indices[v] + 1, mesh.indices[v] + 1, mesh.indices[v] + 1,
   1991                     mesh.indices[v + 1] + 1, mesh.indices[v + 1] + 1, mesh.indices[v + 1] + 1,
   1992                     mesh.indices[v + 2] + 1, mesh.indices[v + 2] + 1, mesh.indices[v + 2] + 1);
   1993             }
   1994         }
   1995         else
   1996         {
   1997             for (int i = 0, v = 1; i < mesh.triangleCount; i++, v += 3)
   1998             {
   1999                 byteCount += sprintf(txtData + byteCount, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", v, v, v, v + 1, v + 1, v + 1, v + 2, v + 2, v + 2);
   2000             }
   2001         }
   2002 
   2003         byteCount += sprintf(txtData + byteCount, "\n");
   2004 
   2005         // NOTE: Text data length exported is determined by '\0' (NULL) character
   2006         success = SaveFileText(fileName, txtData);
   2007 
   2008         RL_FREE(txtData);
   2009     }
   2010     else if (IsFileExtension(fileName, ".raw"))
   2011     {
   2012         // TODO: Support additional file formats to export mesh vertex data
   2013     }
   2014 
   2015     return success;
   2016 }
   2017 
   2018 // Export mesh as code file (.h) defining multiple arrays of vertex attributes
   2019 bool ExportMeshAsCode(Mesh mesh, const char *fileName)
   2020 {
   2021     bool success = false;
   2022 
   2023 #ifndef TEXT_BYTES_PER_LINE
   2024     #define TEXT_BYTES_PER_LINE     20
   2025 #endif
   2026 
   2027     // NOTE: Text data buffer size is fixed to 64MB
   2028     char *txtData = (char *)RL_CALLOC(64*1024*1024, sizeof(char));  // 64 MB
   2029 
   2030     int byteCount = 0;
   2031     byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n");
   2032     byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
   2033     byteCount += sprintf(txtData + byteCount, "// MeshAsCode exporter v1.0 - Mesh vertex data exported as arrays                     //\n");
   2034     byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
   2035     byteCount += sprintf(txtData + byteCount, "// more info and bugs-report:  github.com/raysan5/raylib                              //\n");
   2036     byteCount += sprintf(txtData + byteCount, "// feedback and support:       ray[at]raylib.com                                      //\n");
   2037     byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
   2038     byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2023 Ramon Santamaria (@raysan5)                                     //\n");
   2039     byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
   2040     byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
   2041 
   2042     // Get file name from path and convert variable name to uppercase
   2043     char varFileName[256] = { 0 };
   2044     strcpy(varFileName, GetFileNameWithoutExt(fileName));
   2045     for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
   2046 
   2047     // Add image information
   2048     byteCount += sprintf(txtData + byteCount, "// Mesh basic information\n");
   2049     byteCount += sprintf(txtData + byteCount, "#define %s_VERTEX_COUNT    %i\n", varFileName, mesh.vertexCount);
   2050     byteCount += sprintf(txtData + byteCount, "#define %s_TRIANGLE_COUNT   %i\n\n", varFileName, mesh.triangleCount);
   2051 
   2052     // Define vertex attributes data as separate arrays
   2053     //-----------------------------------------------------------------------------------------
   2054     if (mesh.vertices != NULL)      // Vertex position (XYZ - 3 components per vertex - float)
   2055     {
   2056         byteCount += sprintf(txtData + byteCount, "static float %s_VERTEX_DATA[%i] = { ", varFileName, mesh.vertexCount*3);
   2057         for (int i = 0; i < mesh.vertexCount*3 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.vertices[i]);
   2058         byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.vertices[mesh.vertexCount*3 - 1]);
   2059     }
   2060 
   2061     if (mesh.texcoords != NULL)      // Vertex texture coordinates (UV - 2 components per vertex - float)
   2062     {
   2063         byteCount += sprintf(txtData + byteCount, "static float %s_TEXCOORD_DATA[%i] = { ", varFileName, mesh.vertexCount*2);
   2064         for (int i = 0; i < mesh.vertexCount*2 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.texcoords[i]);
   2065         byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.texcoords[mesh.vertexCount*2 - 1]);
   2066     }
   2067 
   2068     if (mesh.texcoords2 != NULL)      // Vertex texture coordinates (UV - 2 components per vertex - float)
   2069     {
   2070         byteCount += sprintf(txtData + byteCount, "static float %s_TEXCOORD2_DATA[%i] = { ", varFileName, mesh.vertexCount*2);
   2071         for (int i = 0; i < mesh.vertexCount*2 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.texcoords2[i]);
   2072         byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.texcoords2[mesh.vertexCount*2 - 1]);
   2073     }
   2074 
   2075     if (mesh.normals != NULL)      // Vertex normals (XYZ - 3 components per vertex - float)
   2076     {
   2077         byteCount += sprintf(txtData + byteCount, "static float %s_NORMAL_DATA[%i] = { ", varFileName, mesh.vertexCount*3);
   2078         for (int i = 0; i < mesh.vertexCount*3 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.normals[i]);
   2079         byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.normals[mesh.vertexCount*3 - 1]);
   2080     }
   2081 
   2082     if (mesh.tangents != NULL)      // Vertex tangents (XYZW - 4 components per vertex - float)
   2083     {
   2084         byteCount += sprintf(txtData + byteCount, "static float %s_TANGENT_DATA[%i] = { ", varFileName, mesh.vertexCount*4);
   2085         for (int i = 0; i < mesh.vertexCount*4 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.tangents[i]);
   2086         byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.tangents[mesh.vertexCount*4 - 1]);
   2087     }
   2088 
   2089     if (mesh.colors != NULL)        // Vertex colors (RGBA - 4 components per vertex - unsigned char)
   2090     {
   2091         byteCount += sprintf(txtData + byteCount, "static unsigned char %s_COLOR_DATA[%i] = { ", varFileName, mesh.vertexCount*4);
   2092         for (int i = 0; i < mesh.vertexCount*4 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), mesh.colors[i]);
   2093         byteCount += sprintf(txtData + byteCount, "0x%x };\n\n", mesh.colors[mesh.vertexCount*4 - 1]);
   2094     }
   2095 
   2096     if (mesh.indices != NULL)       // Vertex indices (3 index per triangle - unsigned short)
   2097     {
   2098         byteCount += sprintf(txtData + byteCount, "static unsigned short %s_INDEX_DATA[%i] = { ", varFileName, mesh.triangleCount*3);
   2099         for (int i = 0; i < mesh.triangleCount*3 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%i,\n" : "%i, "), mesh.indices[i]);
   2100         byteCount += sprintf(txtData + byteCount, "%i };\n", mesh.indices[mesh.triangleCount*3 - 1]);
   2101     }
   2102     //-----------------------------------------------------------------------------------------
   2103 
   2104     // NOTE: Text data size exported is determined by '\0' (NULL) character
   2105     success = SaveFileText(fileName, txtData);
   2106 
   2107     RL_FREE(txtData);
   2108 
   2109     //if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image as code exported successfully", fileName);
   2110     //else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image as code", fileName);
   2111 
   2112     return success;
   2113 }
   2114 
   2115 #if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL)
   2116 // Process obj materials
   2117 static void ProcessMaterialsOBJ(Material *materials, tinyobj_material_t *mats, int materialCount)
   2118 {
   2119     // Init model mats
   2120     for (int m = 0; m < materialCount; m++)
   2121     {
   2122         // Init material to default
   2123         // NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE
   2124         materials[m] = LoadMaterialDefault();
   2125 
   2126         if (mats == NULL) continue;
   2127 
   2128         // Get default texture, in case no texture is defined
   2129         // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
   2130         materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
   2131 
   2132         if (mats[m].diffuse_texname != NULL) materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture(mats[m].diffuse_texname);  //char *diffuse_texname; // map_Kd
   2133         else materials[m].maps[MATERIAL_MAP_DIFFUSE].color = (Color){ (unsigned char)(mats[m].diffuse[0]*255.0f), (unsigned char)(mats[m].diffuse[1]*255.0f), (unsigned char)(mats[m].diffuse[2]*255.0f), 255 }; //float diffuse[3];
   2134         materials[m].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f;
   2135 
   2136         if (mats[m].specular_texname != NULL) materials[m].maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture(mats[m].specular_texname);  //char *specular_texname; // map_Ks
   2137         materials[m].maps[MATERIAL_MAP_SPECULAR].color = (Color){ (unsigned char)(mats[m].specular[0]*255.0f), (unsigned char)(mats[m].specular[1]*255.0f), (unsigned char)(mats[m].specular[2]*255.0f), 255 }; //float specular[3];
   2138         materials[m].maps[MATERIAL_MAP_SPECULAR].value = 0.0f;
   2139 
   2140         if (mats[m].bump_texname != NULL) materials[m].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture(mats[m].bump_texname);  //char *bump_texname; // map_bump, bump
   2141         materials[m].maps[MATERIAL_MAP_NORMAL].color = WHITE;
   2142         materials[m].maps[MATERIAL_MAP_NORMAL].value = mats[m].shininess;
   2143 
   2144         materials[m].maps[MATERIAL_MAP_EMISSION].color = (Color){ (unsigned char)(mats[m].emission[0]*255.0f), (unsigned char)(mats[m].emission[1]*255.0f), (unsigned char)(mats[m].emission[2]*255.0f), 255 }; //float emission[3];
   2145 
   2146         if (mats[m].displacement_texname != NULL) materials[m].maps[MATERIAL_MAP_HEIGHT].texture = LoadTexture(mats[m].displacement_texname);  //char *displacement_texname; // disp
   2147     }
   2148 }
   2149 #endif
   2150 
   2151 // Load materials from model file
   2152 Material *LoadMaterials(const char *fileName, int *materialCount)
   2153 {
   2154     Material *materials = NULL;
   2155     unsigned int count = 0;
   2156 
   2157     // TODO: Support IQM and GLTF for materials parsing
   2158 
   2159 #if defined(SUPPORT_FILEFORMAT_MTL)
   2160     if (IsFileExtension(fileName, ".mtl"))
   2161     {
   2162         tinyobj_material_t *mats = NULL;
   2163 
   2164         int result = tinyobj_parse_mtl_file(&mats, &count, fileName);
   2165         if (result != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName);
   2166 
   2167         materials = RL_MALLOC(count*sizeof(Material));
   2168         ProcessMaterialsOBJ(materials, mats, count);
   2169 
   2170         tinyobj_materials_free(mats, count);
   2171     }
   2172 #else
   2173     TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load material file", fileName);
   2174 #endif
   2175 
   2176     *materialCount = count;
   2177     return materials;
   2178 }
   2179 
   2180 // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)
   2181 Material LoadMaterialDefault(void)
   2182 {
   2183     Material material = { 0 };
   2184     material.maps = (MaterialMap *)RL_CALLOC(MAX_MATERIAL_MAPS, sizeof(MaterialMap));
   2185 
   2186     // Using rlgl default shader
   2187     material.shader.id = rlGetShaderIdDefault();
   2188     material.shader.locs = rlGetShaderLocsDefault();
   2189 
   2190     // Using rlgl default texture (1x1 pixel, UNCOMPRESSED_R8G8B8A8, 1 mipmap)
   2191     material.maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
   2192     //material.maps[MATERIAL_MAP_NORMAL].texture;         // NOTE: By default, not set
   2193     //material.maps[MATERIAL_MAP_SPECULAR].texture;       // NOTE: By default, not set
   2194 
   2195     material.maps[MATERIAL_MAP_DIFFUSE].color = WHITE;    // Diffuse color
   2196     material.maps[MATERIAL_MAP_SPECULAR].color = WHITE;   // Specular color
   2197 
   2198     return material;
   2199 }
   2200 
   2201 // Check if a material is valid (map textures loaded in GPU)
   2202 bool IsMaterialValid(Material material)
   2203 {
   2204     bool result = false;
   2205 
   2206     if ((material.maps != NULL) &&      // Validate material contain some map
   2207         (material.shader.id > 0)) result = true; // Validate material shader is valid
   2208 
   2209     // TODO: Check if available maps contain loaded textures
   2210 
   2211     return result;
   2212 }
   2213 
   2214 // Unload material from memory
   2215 void UnloadMaterial(Material material)
   2216 {
   2217     // Unload material shader (avoid unloading default shader, managed by raylib)
   2218     if (material.shader.id != rlGetShaderIdDefault()) UnloadShader(material.shader);
   2219 
   2220     // Unload loaded texture maps (avoid unloading default texture, managed by raylib)
   2221     if (material.maps != NULL)
   2222     {
   2223         for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
   2224         {
   2225             if (material.maps[i].texture.id != rlGetTextureIdDefault()) rlUnloadTexture(material.maps[i].texture.id);
   2226         }
   2227     }
   2228 
   2229     RL_FREE(material.maps);
   2230 }
   2231 
   2232 // Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...)
   2233 // NOTE: Previous texture should be manually unloaded
   2234 void SetMaterialTexture(Material *material, int mapType, Texture2D texture)
   2235 {
   2236     material->maps[mapType].texture = texture;
   2237 }
   2238 
   2239 // Set the material for a mesh
   2240 void SetModelMeshMaterial(Model *model, int meshId, int materialId)
   2241 {
   2242     if (meshId >= model->meshCount) TRACELOG(LOG_WARNING, "MESH: Id greater than mesh count");
   2243     else if (materialId >= model->materialCount) TRACELOG(LOG_WARNING, "MATERIAL: Id greater than material count");
   2244     else  model->meshMaterial[meshId] = materialId;
   2245 }
   2246 
   2247 // Load model animations from file
   2248 ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount)
   2249 {
   2250     ModelAnimation *animations = NULL;
   2251 
   2252 #if defined(SUPPORT_FILEFORMAT_IQM)
   2253     if (IsFileExtension(fileName, ".iqm")) animations = LoadModelAnimationsIQM(fileName, animCount);
   2254 #endif
   2255 #if defined(SUPPORT_FILEFORMAT_M3D)
   2256     if (IsFileExtension(fileName, ".m3d")) animations = LoadModelAnimationsM3D(fileName, animCount);
   2257 #endif
   2258 #if defined(SUPPORT_FILEFORMAT_GLTF)
   2259     if (IsFileExtension(fileName, ".gltf;.glb")) animations = LoadModelAnimationsGLTF(fileName, animCount);
   2260 #endif
   2261 
   2262     return animations;
   2263 }
   2264 
   2265 // Update model animated bones transform matrices for a given frame
   2266 // NOTE: Updated data is not uploaded to GPU but kept at model.meshes[i].boneMatrices[boneId],
   2267 // to be uploaded to shader at drawing, in case GPU skinning is enabled
   2268 void UpdateModelAnimationBones(Model model, ModelAnimation anim, int frame)
   2269 {
   2270     if ((anim.frameCount > 0) && (anim.bones != NULL) && (anim.framePoses != NULL))
   2271     {
   2272         if (frame >= anim.frameCount) frame = frame%anim.frameCount;
   2273 
   2274         for (int i = 0; i < model.meshCount; i++)
   2275         {
   2276             if (model.meshes[i].boneMatrices)
   2277             {
   2278                 assert(model.meshes[i].boneCount == anim.boneCount);
   2279 
   2280                 for (int boneId = 0; boneId < model.meshes[i].boneCount; boneId++)
   2281                 {
   2282                     Vector3 inTranslation = model.bindPose[boneId].translation;
   2283                     Quaternion inRotation = model.bindPose[boneId].rotation;
   2284                     Vector3 inScale = model.bindPose[boneId].scale;
   2285 
   2286                     Vector3 outTranslation = anim.framePoses[frame][boneId].translation;
   2287                     Quaternion outRotation = anim.framePoses[frame][boneId].rotation;
   2288                     Vector3 outScale = anim.framePoses[frame][boneId].scale;
   2289 
   2290                     Vector3 invTranslation = Vector3RotateByQuaternion(Vector3Negate(inTranslation), QuaternionInvert(inRotation));
   2291                     Quaternion invRotation = QuaternionInvert(inRotation);
   2292                     Vector3 invScale = Vector3Divide((Vector3){ 1.0f, 1.0f, 1.0f }, inScale);
   2293 
   2294                     Vector3 boneTranslation = Vector3Add(
   2295                         Vector3RotateByQuaternion(Vector3Multiply(outScale, invTranslation),
   2296                         outRotation), outTranslation);
   2297                     Quaternion boneRotation = QuaternionMultiply(outRotation, invRotation);
   2298                     Vector3 boneScale = Vector3Multiply(outScale, invScale);
   2299 
   2300                     Matrix boneMatrix = MatrixMultiply(MatrixMultiply(
   2301                         QuaternionToMatrix(boneRotation),
   2302                         MatrixTranslate(boneTranslation.x, boneTranslation.y, boneTranslation.z)),
   2303                         MatrixScale(boneScale.x, boneScale.y, boneScale.z));
   2304 
   2305                     model.meshes[i].boneMatrices[boneId] = boneMatrix;
   2306                 }
   2307             }
   2308         }
   2309     }
   2310 }
   2311 
   2312 // at least 2x speed up vs the old method 
   2313 // Update model animated vertex data (positions and normals) for a given frame
   2314 // NOTE: Updated data is uploaded to GPU
   2315 void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
   2316 {
   2317     UpdateModelAnimationBones(model,anim,frame);
   2318     for (int m = 0; m < model.meshCount; m++)
   2319     {
   2320         Mesh mesh = model.meshes[m];
   2321         Vector3 animVertex = { 0 };
   2322         Vector3 animNormal = { 0 };
   2323         int boneId = 0;
   2324         int boneCounter = 0;
   2325         float boneWeight = 0.0;
   2326         bool updated = false;           // Flag to check when anim vertex information is updated
   2327         const int vValues = mesh.vertexCount*3;
   2328         for (int vCounter = 0; vCounter < vValues; vCounter += 3)
   2329         {
   2330             mesh.animVertices[vCounter] = 0;
   2331             mesh.animVertices[vCounter + 1] = 0;
   2332             mesh.animVertices[vCounter + 2] = 0;
   2333             if (mesh.animNormals != NULL)
   2334             {
   2335                 mesh.animNormals[vCounter] = 0;
   2336                 mesh.animNormals[vCounter + 1] = 0;
   2337                 mesh.animNormals[vCounter + 2] = 0;
   2338             }
   2339                 // Iterates over 4 bones per vertex
   2340             for (int j = 0; j < 4; j++, boneCounter++)
   2341             {
   2342                 boneWeight = mesh.boneWeights[boneCounter];
   2343                 boneId = mesh.boneIds[boneCounter];
   2344                 // Early stop when no transformation will be applied
   2345                 if (boneWeight == 0.0f) continue;
   2346                 animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] };
   2347                 animVertex = Vector3Transform(animVertex,model.meshes[m].boneMatrices[boneId]);
   2348                 mesh.animVertices[vCounter] += animVertex.x * boneWeight;
   2349                 mesh.animVertices[vCounter+1] += animVertex.y * boneWeight;
   2350                 mesh.animVertices[vCounter+2] += animVertex.z * boneWeight;
   2351                 updated = true;
   2352                 // Normals processing
   2353                 // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
   2354                 if (mesh.normals != NULL)
   2355                 {
   2356                     animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] };
   2357                     animNormal = Vector3Transform(animNormal,model.meshes[m].boneMatrices[boneId]);
   2358                     mesh.animNormals[vCounter] += animNormal.x*boneWeight;
   2359                     mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight;
   2360                     mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight;
   2361                 }
   2362             }
   2363         }
   2364         if (updated)
   2365         {
   2366             rlUpdateVertexBuffer(mesh.vboId[0], mesh.animVertices, mesh.vertexCount*3*sizeof(float), 0); // Update vertex position
   2367             rlUpdateVertexBuffer(mesh.vboId[2], mesh.animNormals, mesh.vertexCount*3*sizeof(float), 0);  // Update vertex normals
   2368         }
   2369     }
   2370 }
   2371 
   2372 // Unload animation array data
   2373 void UnloadModelAnimations(ModelAnimation *animations, int animCount)
   2374 {
   2375     for (int i = 0; i < animCount; i++) UnloadModelAnimation(animations[i]);
   2376     RL_FREE(animations);
   2377 }
   2378 
   2379 // Unload animation data
   2380 void UnloadModelAnimation(ModelAnimation anim)
   2381 {
   2382     for (int i = 0; i < anim.frameCount; i++) RL_FREE(anim.framePoses[i]);
   2383 
   2384     RL_FREE(anim.bones);
   2385     RL_FREE(anim.framePoses);
   2386 }
   2387 
   2388 // Check model animation skeleton match
   2389 // NOTE: Only number of bones and parent connections are checked
   2390 bool IsModelAnimationValid(Model model, ModelAnimation anim)
   2391 {
   2392     int result = true;
   2393 
   2394     if (model.boneCount != anim.boneCount) result = false;
   2395     else
   2396     {
   2397         for (int i = 0; i < model.boneCount; i++)
   2398         {
   2399             if (model.bones[i].parent != anim.bones[i].parent) { result = false; break; }
   2400         }
   2401     }
   2402 
   2403     return result;
   2404 }
   2405 
   2406 #if defined(SUPPORT_MESH_GENERATION)
   2407 // Generate polygonal mesh
   2408 Mesh GenMeshPoly(int sides, float radius)
   2409 {
   2410     Mesh mesh = { 0 };
   2411 
   2412     if (sides < 3) return mesh; // Security check
   2413 
   2414     int vertexCount = sides*3;
   2415 
   2416     // Vertices definition
   2417     Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
   2418 
   2419     float d = 0.0f, dStep = 360.0f/sides;
   2420     for (int v = 0; v < vertexCount - 2; v += 3)
   2421     {
   2422         vertices[v] = (Vector3){ 0.0f, 0.0f, 0.0f };
   2423         vertices[v + 1] = (Vector3){ sinf(DEG2RAD*d)*radius, 0.0f, cosf(DEG2RAD*d)*radius };
   2424         vertices[v + 2] = (Vector3){ sinf(DEG2RAD*(d+dStep))*radius, 0.0f, cosf(DEG2RAD*(d+dStep))*radius };
   2425         d += dStep;
   2426     }
   2427 
   2428     // Normals definition
   2429     Vector3 *normals = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
   2430     for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f };   // Vector3.up;
   2431 
   2432     // TexCoords definition
   2433     Vector2 *texcoords = (Vector2 *)RL_MALLOC(vertexCount*sizeof(Vector2));
   2434     for (int n = 0; n < vertexCount; n++) texcoords[n] = (Vector2){ 0.0f, 0.0f };
   2435 
   2436     mesh.vertexCount = vertexCount;
   2437     mesh.triangleCount = sides;
   2438     mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
   2439     mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
   2440     mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
   2441 
   2442     // Mesh vertices position array
   2443     for (int i = 0; i < mesh.vertexCount; i++)
   2444     {
   2445         mesh.vertices[3*i] = vertices[i].x;
   2446         mesh.vertices[3*i + 1] = vertices[i].y;
   2447         mesh.vertices[3*i + 2] = vertices[i].z;
   2448     }
   2449 
   2450     // Mesh texcoords array
   2451     for (int i = 0; i < mesh.vertexCount; i++)
   2452     {
   2453         mesh.texcoords[2*i] = texcoords[i].x;
   2454         mesh.texcoords[2*i + 1] = texcoords[i].y;
   2455     }
   2456 
   2457     // Mesh normals array
   2458     for (int i = 0; i < mesh.vertexCount; i++)
   2459     {
   2460         mesh.normals[3*i] = normals[i].x;
   2461         mesh.normals[3*i + 1] = normals[i].y;
   2462         mesh.normals[3*i + 2] = normals[i].z;
   2463     }
   2464 
   2465     RL_FREE(vertices);
   2466     RL_FREE(normals);
   2467     RL_FREE(texcoords);
   2468 
   2469     // Upload vertex data to GPU (static mesh)
   2470     // NOTE: mesh.vboId array is allocated inside UploadMesh()
   2471     UploadMesh(&mesh, false);
   2472 
   2473     return mesh;
   2474 }
   2475 
   2476 // Generate plane mesh (with subdivisions)
   2477 Mesh GenMeshPlane(float width, float length, int resX, int resZ)
   2478 {
   2479     Mesh mesh = { 0 };
   2480 
   2481 #define CUSTOM_MESH_GEN_PLANE
   2482 #if defined(CUSTOM_MESH_GEN_PLANE)
   2483     resX++;
   2484     resZ++;
   2485 
   2486     // Vertices definition
   2487     int vertexCount = resX*resZ; // vertices get reused for the faces
   2488 
   2489     Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
   2490     for (int z = 0; z < resZ; z++)
   2491     {
   2492         // [-length/2, length/2]
   2493         float zPos = ((float)z/(resZ - 1) - 0.5f)*length;
   2494         for (int x = 0; x < resX; x++)
   2495         {
   2496             // [-width/2, width/2]
   2497             float xPos = ((float)x/(resX - 1) - 0.5f)*width;
   2498             vertices[x + z*resX] = (Vector3){ xPos, 0.0f, zPos };
   2499         }
   2500     }
   2501 
   2502     // Normals definition
   2503     Vector3 *normals = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
   2504     for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f };   // Vector3.up;
   2505 
   2506     // TexCoords definition
   2507     Vector2 *texcoords = (Vector2 *)RL_MALLOC(vertexCount*sizeof(Vector2));
   2508     for (int v = 0; v < resZ; v++)
   2509     {
   2510         for (int u = 0; u < resX; u++)
   2511         {
   2512             texcoords[u + v*resX] = (Vector2){ (float)u/(resX - 1), (float)v/(resZ - 1) };
   2513         }
   2514     }
   2515 
   2516     // Triangles definition (indices)
   2517     int numFaces = (resX - 1)*(resZ - 1);
   2518     int *triangles = (int *)RL_MALLOC(numFaces*6*sizeof(int));
   2519     int t = 0;
   2520     for (int face = 0; face < numFaces; face++)
   2521     {
   2522         // Retrieve lower left corner from face ind
   2523         int i = face + face/(resX - 1);
   2524 
   2525         triangles[t++] = i + resX;
   2526         triangles[t++] = i + 1;
   2527         triangles[t++] = i;
   2528 
   2529         triangles[t++] = i + resX;
   2530         triangles[t++] = i + resX + 1;
   2531         triangles[t++] = i + 1;
   2532     }
   2533 
   2534     mesh.vertexCount = vertexCount;
   2535     mesh.triangleCount = numFaces*2;
   2536     mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
   2537     mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
   2538     mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
   2539     mesh.indices = (unsigned short *)RL_MALLOC(mesh.triangleCount*3*sizeof(unsigned short));
   2540 
   2541     // Mesh vertices position array
   2542     for (int i = 0; i < mesh.vertexCount; i++)
   2543     {
   2544         mesh.vertices[3*i] = vertices[i].x;
   2545         mesh.vertices[3*i + 1] = vertices[i].y;
   2546         mesh.vertices[3*i + 2] = vertices[i].z;
   2547     }
   2548 
   2549     // Mesh texcoords array
   2550     for (int i = 0; i < mesh.vertexCount; i++)
   2551     {
   2552         mesh.texcoords[2*i] = texcoords[i].x;
   2553         mesh.texcoords[2*i + 1] = texcoords[i].y;
   2554     }
   2555 
   2556     // Mesh normals array
   2557     for (int i = 0; i < mesh.vertexCount; i++)
   2558     {
   2559         mesh.normals[3*i] = normals[i].x;
   2560         mesh.normals[3*i + 1] = normals[i].y;
   2561         mesh.normals[3*i + 2] = normals[i].z;
   2562     }
   2563 
   2564     // Mesh indices array initialization
   2565     for (int i = 0; i < mesh.triangleCount*3; i++) mesh.indices[i] = triangles[i];
   2566 
   2567     RL_FREE(vertices);
   2568     RL_FREE(normals);
   2569     RL_FREE(texcoords);
   2570     RL_FREE(triangles);
   2571 
   2572 #else       // Use par_shapes library to generate plane mesh
   2573 
   2574     par_shapes_mesh *plane = par_shapes_create_plane(resX, resZ);   // No normals/texcoords generated!!!
   2575     par_shapes_scale(plane, width, length, 1.0f);
   2576     par_shapes_rotate(plane, -PI/2.0f, (float[]){ 1, 0, 0 });
   2577     par_shapes_translate(plane, -width/2, 0.0f, length/2);
   2578 
   2579     mesh.vertices = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float));
   2580     mesh.texcoords = (float *)RL_MALLOC(plane->ntriangles*3*2*sizeof(float));
   2581     mesh.normals = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float));
   2582 
   2583     mesh.vertexCount = plane->ntriangles*3;
   2584     mesh.triangleCount = plane->ntriangles;
   2585 
   2586     for (int k = 0; k < mesh.vertexCount; k++)
   2587     {
   2588         mesh.vertices[k*3] = plane->points[plane->triangles[k]*3];
   2589         mesh.vertices[k*3 + 1] = plane->points[plane->triangles[k]*3 + 1];
   2590         mesh.vertices[k*3 + 2] = plane->points[plane->triangles[k]*3 + 2];
   2591 
   2592         mesh.normals[k*3] = plane->normals[plane->triangles[k]*3];
   2593         mesh.normals[k*3 + 1] = plane->normals[plane->triangles[k]*3 + 1];
   2594         mesh.normals[k*3 + 2] = plane->normals[plane->triangles[k]*3 + 2];
   2595 
   2596         mesh.texcoords[k*2] = plane->tcoords[plane->triangles[k]*2];
   2597         mesh.texcoords[k*2 + 1] = plane->tcoords[plane->triangles[k]*2 + 1];
   2598     }
   2599 
   2600     par_shapes_free_mesh(plane);
   2601 #endif
   2602 
   2603     // Upload vertex data to GPU (static mesh)
   2604     UploadMesh(&mesh, false);
   2605 
   2606     return mesh;
   2607 }
   2608 
   2609 // Generated cuboid mesh
   2610 Mesh GenMeshCube(float width, float height, float length)
   2611 {
   2612     Mesh mesh = { 0 };
   2613 
   2614 #define CUSTOM_MESH_GEN_CUBE
   2615 #if defined(CUSTOM_MESH_GEN_CUBE)
   2616     float vertices[] = {
   2617         -width/2, -height/2, length/2,
   2618         width/2, -height/2, length/2,
   2619         width/2, height/2, length/2,
   2620         -width/2, height/2, length/2,
   2621         -width/2, -height/2, -length/2,
   2622         -width/2, height/2, -length/2,
   2623         width/2, height/2, -length/2,
   2624         width/2, -height/2, -length/2,
   2625         -width/2, height/2, -length/2,
   2626         -width/2, height/2, length/2,
   2627         width/2, height/2, length/2,
   2628         width/2, height/2, -length/2,
   2629         -width/2, -height/2, -length/2,
   2630         width/2, -height/2, -length/2,
   2631         width/2, -height/2, length/2,
   2632         -width/2, -height/2, length/2,
   2633         width/2, -height/2, -length/2,
   2634         width/2, height/2, -length/2,
   2635         width/2, height/2, length/2,
   2636         width/2, -height/2, length/2,
   2637         -width/2, -height/2, -length/2,
   2638         -width/2, -height/2, length/2,
   2639         -width/2, height/2, length/2,
   2640         -width/2, height/2, -length/2
   2641     };
   2642 
   2643     float texcoords[] = {
   2644         0.0f, 0.0f,
   2645         1.0f, 0.0f,
   2646         1.0f, 1.0f,
   2647         0.0f, 1.0f,
   2648         1.0f, 0.0f,
   2649         1.0f, 1.0f,
   2650         0.0f, 1.0f,
   2651         0.0f, 0.0f,
   2652         0.0f, 1.0f,
   2653         0.0f, 0.0f,
   2654         1.0f, 0.0f,
   2655         1.0f, 1.0f,
   2656         1.0f, 1.0f,
   2657         0.0f, 1.0f,
   2658         0.0f, 0.0f,
   2659         1.0f, 0.0f,
   2660         1.0f, 0.0f,
   2661         1.0f, 1.0f,
   2662         0.0f, 1.0f,
   2663         0.0f, 0.0f,
   2664         0.0f, 0.0f,
   2665         1.0f, 0.0f,
   2666         1.0f, 1.0f,
   2667         0.0f, 1.0f
   2668     };
   2669 
   2670     float normals[] = {
   2671         0.0f, 0.0f, 1.0f,
   2672         0.0f, 0.0f, 1.0f,
   2673         0.0f, 0.0f, 1.0f,
   2674         0.0f, 0.0f, 1.0f,
   2675         0.0f, 0.0f,-1.0f,
   2676         0.0f, 0.0f,-1.0f,
   2677         0.0f, 0.0f,-1.0f,
   2678         0.0f, 0.0f,-1.0f,
   2679         0.0f, 1.0f, 0.0f,
   2680         0.0f, 1.0f, 0.0f,
   2681         0.0f, 1.0f, 0.0f,
   2682         0.0f, 1.0f, 0.0f,
   2683         0.0f,-1.0f, 0.0f,
   2684         0.0f,-1.0f, 0.0f,
   2685         0.0f,-1.0f, 0.0f,
   2686         0.0f,-1.0f, 0.0f,
   2687         1.0f, 0.0f, 0.0f,
   2688         1.0f, 0.0f, 0.0f,
   2689         1.0f, 0.0f, 0.0f,
   2690         1.0f, 0.0f, 0.0f,
   2691         -1.0f, 0.0f, 0.0f,
   2692         -1.0f, 0.0f, 0.0f,
   2693         -1.0f, 0.0f, 0.0f,
   2694         -1.0f, 0.0f, 0.0f
   2695     };
   2696 
   2697     mesh.vertices = (float *)RL_MALLOC(24*3*sizeof(float));
   2698     memcpy(mesh.vertices, vertices, 24*3*sizeof(float));
   2699 
   2700     mesh.texcoords = (float *)RL_MALLOC(24*2*sizeof(float));
   2701     memcpy(mesh.texcoords, texcoords, 24*2*sizeof(float));
   2702 
   2703     mesh.normals = (float *)RL_MALLOC(24*3*sizeof(float));
   2704     memcpy(mesh.normals, normals, 24*3*sizeof(float));
   2705 
   2706     mesh.indices = (unsigned short *)RL_MALLOC(36*sizeof(unsigned short));
   2707 
   2708     int k = 0;
   2709 
   2710     // Indices can be initialized right now
   2711     for (int i = 0; i < 36; i += 6)
   2712     {
   2713         mesh.indices[i] = 4*k;
   2714         mesh.indices[i + 1] = 4*k + 1;
   2715         mesh.indices[i + 2] = 4*k + 2;
   2716         mesh.indices[i + 3] = 4*k;
   2717         mesh.indices[i + 4] = 4*k + 2;
   2718         mesh.indices[i + 5] = 4*k + 3;
   2719 
   2720         k++;
   2721     }
   2722 
   2723     mesh.vertexCount = 24;
   2724     mesh.triangleCount = 12;
   2725 
   2726 #else               // Use par_shapes library to generate cube mesh
   2727 /*
   2728 // Platonic solids:
   2729 par_shapes_mesh* par_shapes_create_tetrahedron();       // 4 sides polyhedron (pyramid)
   2730 par_shapes_mesh* par_shapes_create_cube();              // 6 sides polyhedron (cube)
   2731 par_shapes_mesh* par_shapes_create_octahedron();        // 8 sides polyhedron (diamond)
   2732 par_shapes_mesh* par_shapes_create_dodecahedron();      // 12 sides polyhedron
   2733 par_shapes_mesh* par_shapes_create_icosahedron();       // 20 sides polyhedron
   2734 */
   2735     // Platonic solid generation: cube (6 sides)
   2736     // NOTE: No normals/texcoords generated by default
   2737     par_shapes_mesh *cube = par_shapes_create_cube();
   2738     cube->tcoords = PAR_MALLOC(float, 2*cube->npoints);
   2739     for (int i = 0; i < 2*cube->npoints; i++) cube->tcoords[i] = 0.0f;
   2740     par_shapes_scale(cube, width, height, length);
   2741     par_shapes_translate(cube, -width/2, 0.0f, -length/2);
   2742     par_shapes_compute_normals(cube);
   2743 
   2744     mesh.vertices = (float *)RL_MALLOC(cube->ntriangles*3*3*sizeof(float));
   2745     mesh.texcoords = (float *)RL_MALLOC(cube->ntriangles*3*2*sizeof(float));
   2746     mesh.normals = (float *)RL_MALLOC(cube->ntriangles*3*3*sizeof(float));
   2747 
   2748     mesh.vertexCount = cube->ntriangles*3;
   2749     mesh.triangleCount = cube->ntriangles;
   2750 
   2751     for (int k = 0; k < mesh.vertexCount; k++)
   2752     {
   2753         mesh.vertices[k*3] = cube->points[cube->triangles[k]*3];
   2754         mesh.vertices[k*3 + 1] = cube->points[cube->triangles[k]*3 + 1];
   2755         mesh.vertices[k*3 + 2] = cube->points[cube->triangles[k]*3 + 2];
   2756 
   2757         mesh.normals[k*3] = cube->normals[cube->triangles[k]*3];
   2758         mesh.normals[k*3 + 1] = cube->normals[cube->triangles[k]*3 + 1];
   2759         mesh.normals[k*3 + 2] = cube->normals[cube->triangles[k]*3 + 2];
   2760 
   2761         mesh.texcoords[k*2] = cube->tcoords[cube->triangles[k]*2];
   2762         mesh.texcoords[k*2 + 1] = cube->tcoords[cube->triangles[k]*2 + 1];
   2763     }
   2764 
   2765     par_shapes_free_mesh(cube);
   2766 #endif
   2767 
   2768     // Upload vertex data to GPU (static mesh)
   2769     UploadMesh(&mesh, false);
   2770 
   2771     return mesh;
   2772 }
   2773 
   2774 // Generate sphere mesh (standard sphere)
   2775 Mesh GenMeshSphere(float radius, int rings, int slices)
   2776 {
   2777     Mesh mesh = { 0 };
   2778 
   2779     if ((rings >= 3) && (slices >= 3))
   2780     {
   2781         par_shapes_set_epsilon_degenerate_sphere(0.0);
   2782         par_shapes_mesh *sphere = par_shapes_create_parametric_sphere(slices, rings);
   2783         par_shapes_scale(sphere, radius, radius, radius);
   2784         // NOTE: Soft normals are computed internally
   2785 
   2786         mesh.vertices = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
   2787         mesh.texcoords = (float *)RL_MALLOC(sphere->ntriangles*3*2*sizeof(float));
   2788         mesh.normals = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
   2789 
   2790         mesh.vertexCount = sphere->ntriangles*3;
   2791         mesh.triangleCount = sphere->ntriangles;
   2792 
   2793         for (int k = 0; k < mesh.vertexCount; k++)
   2794         {
   2795             mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3];
   2796             mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1];
   2797             mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2];
   2798 
   2799             mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3];
   2800             mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1];
   2801             mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2];
   2802 
   2803             mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2];
   2804             mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1];
   2805         }
   2806 
   2807         par_shapes_free_mesh(sphere);
   2808 
   2809         // Upload vertex data to GPU (static mesh)
   2810         UploadMesh(&mesh, false);
   2811     }
   2812     else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: sphere");
   2813 
   2814     return mesh;
   2815 }
   2816 
   2817 // Generate hemisphere mesh (half sphere, no bottom cap)
   2818 Mesh GenMeshHemiSphere(float radius, int rings, int slices)
   2819 {
   2820     Mesh mesh = { 0 };
   2821 
   2822     if ((rings >= 3) && (slices >= 3))
   2823     {
   2824         if (radius < 0.0f) radius = 0.0f;
   2825 
   2826         par_shapes_mesh *sphere = par_shapes_create_hemisphere(slices, rings);
   2827         par_shapes_scale(sphere, radius, radius, radius);
   2828         // NOTE: Soft normals are computed internally
   2829 
   2830         mesh.vertices = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
   2831         mesh.texcoords = (float *)RL_MALLOC(sphere->ntriangles*3*2*sizeof(float));
   2832         mesh.normals = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
   2833 
   2834         mesh.vertexCount = sphere->ntriangles*3;
   2835         mesh.triangleCount = sphere->ntriangles;
   2836 
   2837         for (int k = 0; k < mesh.vertexCount; k++)
   2838         {
   2839             mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3];
   2840             mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1];
   2841             mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2];
   2842 
   2843             mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3];
   2844             mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1];
   2845             mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2];
   2846 
   2847             mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2];
   2848             mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1];
   2849         }
   2850 
   2851         par_shapes_free_mesh(sphere);
   2852 
   2853         // Upload vertex data to GPU (static mesh)
   2854         UploadMesh(&mesh, false);
   2855     }
   2856     else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: hemisphere");
   2857 
   2858     return mesh;
   2859 }
   2860 
   2861 // Generate cylinder mesh
   2862 Mesh GenMeshCylinder(float radius, float height, int slices)
   2863 {
   2864     Mesh mesh = { 0 };
   2865 
   2866     if (slices >= 3)
   2867     {
   2868         // Instance a cylinder that sits on the Z=0 plane using the given tessellation
   2869         // levels across the UV domain.  Think of "slices" like a number of pizza
   2870         // slices, and "stacks" like a number of stacked rings
   2871         // Height and radius are both 1.0, but they can easily be changed with par_shapes_scale
   2872         par_shapes_mesh *cylinder = par_shapes_create_cylinder(slices, 8);
   2873         par_shapes_scale(cylinder, radius, radius, height);
   2874         par_shapes_rotate(cylinder, -PI/2.0f, (float[]){ 1, 0, 0 });
   2875 
   2876         // Generate an orientable disk shape (top cap)
   2877         par_shapes_mesh *capTop = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, 1 });
   2878         capTop->tcoords = PAR_MALLOC(float, 2*capTop->npoints);
   2879         for (int i = 0; i < 2*capTop->npoints; i++) capTop->tcoords[i] = 0.0f;
   2880         par_shapes_rotate(capTop, -PI/2.0f, (float[]){ 1, 0, 0 });
   2881         par_shapes_rotate(capTop, 90*DEG2RAD, (float[]){ 0, 1, 0 });
   2882         par_shapes_translate(capTop, 0, height, 0);
   2883 
   2884         // Generate an orientable disk shape (bottom cap)
   2885         par_shapes_mesh *capBottom = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, -1 });
   2886         capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints);
   2887         for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f;
   2888         par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 });
   2889         par_shapes_rotate(capBottom, -90*DEG2RAD, (float[]){ 0, 1, 0 });
   2890 
   2891         par_shapes_merge_and_free(cylinder, capTop);
   2892         par_shapes_merge_and_free(cylinder, capBottom);
   2893 
   2894         mesh.vertices = (float *)RL_MALLOC(cylinder->ntriangles*3*3*sizeof(float));
   2895         mesh.texcoords = (float *)RL_MALLOC(cylinder->ntriangles*3*2*sizeof(float));
   2896         mesh.normals = (float *)RL_MALLOC(cylinder->ntriangles*3*3*sizeof(float));
   2897 
   2898         mesh.vertexCount = cylinder->ntriangles*3;
   2899         mesh.triangleCount = cylinder->ntriangles;
   2900 
   2901         for (int k = 0; k < mesh.vertexCount; k++)
   2902         {
   2903             mesh.vertices[k*3] = cylinder->points[cylinder->triangles[k]*3];
   2904             mesh.vertices[k*3 + 1] = cylinder->points[cylinder->triangles[k]*3 + 1];
   2905             mesh.vertices[k*3 + 2] = cylinder->points[cylinder->triangles[k]*3 + 2];
   2906 
   2907             mesh.normals[k*3] = cylinder->normals[cylinder->triangles[k]*3];
   2908             mesh.normals[k*3 + 1] = cylinder->normals[cylinder->triangles[k]*3 + 1];
   2909             mesh.normals[k*3 + 2] = cylinder->normals[cylinder->triangles[k]*3 + 2];
   2910 
   2911             mesh.texcoords[k*2] = cylinder->tcoords[cylinder->triangles[k]*2];
   2912             mesh.texcoords[k*2 + 1] = cylinder->tcoords[cylinder->triangles[k]*2 + 1];
   2913         }
   2914 
   2915         par_shapes_free_mesh(cylinder);
   2916 
   2917         // Upload vertex data to GPU (static mesh)
   2918         UploadMesh(&mesh, false);
   2919     }
   2920     else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: cylinder");
   2921 
   2922     return mesh;
   2923 }
   2924 
   2925 // Generate cone/pyramid mesh
   2926 Mesh GenMeshCone(float radius, float height, int slices)
   2927 {
   2928     Mesh mesh = { 0 };
   2929 
   2930     if (slices >= 3)
   2931     {
   2932         // Instance a cone that sits on the Z=0 plane using the given tessellation
   2933         // levels across the UV domain.  Think of "slices" like a number of pizza
   2934         // slices, and "stacks" like a number of stacked rings
   2935         // Height and radius are both 1.0, but they can easily be changed with par_shapes_scale
   2936         par_shapes_mesh *cone = par_shapes_create_cone(slices, 8);
   2937         par_shapes_scale(cone, radius, radius, height);
   2938         par_shapes_rotate(cone, -PI/2.0f, (float[]){ 1, 0, 0 });
   2939         par_shapes_rotate(cone, PI/2.0f, (float[]){ 0, 1, 0 });
   2940 
   2941         // Generate an orientable disk shape (bottom cap)
   2942         par_shapes_mesh *capBottom = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, -1 });
   2943         capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints);
   2944         for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f;
   2945         par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 });
   2946 
   2947         par_shapes_merge_and_free(cone, capBottom);
   2948 
   2949         mesh.vertices = (float *)RL_MALLOC(cone->ntriangles*3*3*sizeof(float));
   2950         mesh.texcoords = (float *)RL_MALLOC(cone->ntriangles*3*2*sizeof(float));
   2951         mesh.normals = (float *)RL_MALLOC(cone->ntriangles*3*3*sizeof(float));
   2952 
   2953         mesh.vertexCount = cone->ntriangles*3;
   2954         mesh.triangleCount = cone->ntriangles;
   2955 
   2956         for (int k = 0; k < mesh.vertexCount; k++)
   2957         {
   2958             mesh.vertices[k*3] = cone->points[cone->triangles[k]*3];
   2959             mesh.vertices[k*3 + 1] = cone->points[cone->triangles[k]*3 + 1];
   2960             mesh.vertices[k*3 + 2] = cone->points[cone->triangles[k]*3 + 2];
   2961 
   2962             mesh.normals[k*3] = cone->normals[cone->triangles[k]*3];
   2963             mesh.normals[k*3 + 1] = cone->normals[cone->triangles[k]*3 + 1];
   2964             mesh.normals[k*3 + 2] = cone->normals[cone->triangles[k]*3 + 2];
   2965 
   2966             mesh.texcoords[k*2] = cone->tcoords[cone->triangles[k]*2];
   2967             mesh.texcoords[k*2 + 1] = cone->tcoords[cone->triangles[k]*2 + 1];
   2968         }
   2969 
   2970         par_shapes_free_mesh(cone);
   2971 
   2972         // Upload vertex data to GPU (static mesh)
   2973         UploadMesh(&mesh, false);
   2974     }
   2975     else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: cone");
   2976 
   2977     return mesh;
   2978 }
   2979 
   2980 // Generate torus mesh
   2981 Mesh GenMeshTorus(float radius, float size, int radSeg, int sides)
   2982 {
   2983     Mesh mesh = { 0 };
   2984 
   2985     if ((sides >= 3) && (radSeg >= 3))
   2986     {
   2987         if (radius > 1.0f) radius = 1.0f;
   2988         else if (radius < 0.1f) radius = 0.1f;
   2989 
   2990         // Create a donut that sits on the Z=0 plane with the specified inner radius
   2991         // The outer radius can be controlled with par_shapes_scale
   2992         par_shapes_mesh *torus = par_shapes_create_torus(radSeg, sides, radius);
   2993         par_shapes_scale(torus, size/2, size/2, size/2);
   2994 
   2995         mesh.vertices = (float *)RL_MALLOC(torus->ntriangles*3*3*sizeof(float));
   2996         mesh.texcoords = (float *)RL_MALLOC(torus->ntriangles*3*2*sizeof(float));
   2997         mesh.normals = (float *)RL_MALLOC(torus->ntriangles*3*3*sizeof(float));
   2998 
   2999         mesh.vertexCount = torus->ntriangles*3;
   3000         mesh.triangleCount = torus->ntriangles;
   3001 
   3002         for (int k = 0; k < mesh.vertexCount; k++)
   3003         {
   3004             mesh.vertices[k*3] = torus->points[torus->triangles[k]*3];
   3005             mesh.vertices[k*3 + 1] = torus->points[torus->triangles[k]*3 + 1];
   3006             mesh.vertices[k*3 + 2] = torus->points[torus->triangles[k]*3 + 2];
   3007 
   3008             mesh.normals[k*3] = torus->normals[torus->triangles[k]*3];
   3009             mesh.normals[k*3 + 1] = torus->normals[torus->triangles[k]*3 + 1];
   3010             mesh.normals[k*3 + 2] = torus->normals[torus->triangles[k]*3 + 2];
   3011 
   3012             mesh.texcoords[k*2] = torus->tcoords[torus->triangles[k]*2];
   3013             mesh.texcoords[k*2 + 1] = torus->tcoords[torus->triangles[k]*2 + 1];
   3014         }
   3015 
   3016         par_shapes_free_mesh(torus);
   3017 
   3018         // Upload vertex data to GPU (static mesh)
   3019         UploadMesh(&mesh, false);
   3020     }
   3021     else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: torus");
   3022 
   3023     return mesh;
   3024 }
   3025 
   3026 // Generate trefoil knot mesh
   3027 Mesh GenMeshKnot(float radius, float size, int radSeg, int sides)
   3028 {
   3029     Mesh mesh = { 0 };
   3030 
   3031     if ((sides >= 3) && (radSeg >= 3))
   3032     {
   3033         if (radius > 3.0f) radius = 3.0f;
   3034         else if (radius < 0.5f) radius = 0.5f;
   3035 
   3036         par_shapes_mesh *knot = par_shapes_create_trefoil_knot(radSeg, sides, radius);
   3037         par_shapes_scale(knot, size, size, size);
   3038 
   3039         mesh.vertices = (float *)RL_MALLOC(knot->ntriangles*3*3*sizeof(float));
   3040         mesh.texcoords = (float *)RL_MALLOC(knot->ntriangles*3*2*sizeof(float));
   3041         mesh.normals = (float *)RL_MALLOC(knot->ntriangles*3*3*sizeof(float));
   3042 
   3043         mesh.vertexCount = knot->ntriangles*3;
   3044         mesh.triangleCount = knot->ntriangles;
   3045 
   3046         for (int k = 0; k < mesh.vertexCount; k++)
   3047         {
   3048             mesh.vertices[k*3] = knot->points[knot->triangles[k]*3];
   3049             mesh.vertices[k*3 + 1] = knot->points[knot->triangles[k]*3 + 1];
   3050             mesh.vertices[k*3 + 2] = knot->points[knot->triangles[k]*3 + 2];
   3051 
   3052             mesh.normals[k*3] = knot->normals[knot->triangles[k]*3];
   3053             mesh.normals[k*3 + 1] = knot->normals[knot->triangles[k]*3 + 1];
   3054             mesh.normals[k*3 + 2] = knot->normals[knot->triangles[k]*3 + 2];
   3055 
   3056             mesh.texcoords[k*2] = knot->tcoords[knot->triangles[k]*2];
   3057             mesh.texcoords[k*2 + 1] = knot->tcoords[knot->triangles[k]*2 + 1];
   3058         }
   3059 
   3060         par_shapes_free_mesh(knot);
   3061 
   3062         // Upload vertex data to GPU (static mesh)
   3063         UploadMesh(&mesh, false);
   3064     }
   3065     else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: knot");
   3066 
   3067     return mesh;
   3068 }
   3069 
   3070 // Generate a mesh from heightmap
   3071 // NOTE: Vertex data is uploaded to GPU
   3072 Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
   3073 {
   3074     #define GRAY_VALUE(c) ((float)(c.r + c.g + c.b)/3.0f)
   3075 
   3076     Mesh mesh = { 0 };
   3077 
   3078     int mapX = heightmap.width;
   3079     int mapZ = heightmap.height;
   3080 
   3081     Color *pixels = LoadImageColors(heightmap);
   3082 
   3083     // NOTE: One vertex per pixel
   3084     mesh.triangleCount = (mapX - 1)*(mapZ - 1)*2;    // One quad every four pixels
   3085 
   3086     mesh.vertexCount = mesh.triangleCount*3;
   3087 
   3088     mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
   3089     mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
   3090     mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
   3091     mesh.colors = NULL;
   3092 
   3093     int vCounter = 0;       // Used to count vertices float by float
   3094     int tcCounter = 0;      // Used to count texcoords float by float
   3095     int nCounter = 0;       // Used to count normals float by float
   3096 
   3097     Vector3 scaleFactor = { size.x/(mapX - 1), size.y/255.0f, size.z/(mapZ - 1) };
   3098 
   3099     Vector3 vA = { 0 };
   3100     Vector3 vB = { 0 };
   3101     Vector3 vC = { 0 };
   3102     Vector3 vN = { 0 };
   3103 
   3104     for (int z = 0; z < mapZ-1; z++)
   3105     {
   3106         for (int x = 0; x < mapX-1; x++)
   3107         {
   3108             // Fill vertices array with data
   3109             //----------------------------------------------------------
   3110 
   3111             // one triangle - 3 vertex
   3112             mesh.vertices[vCounter] = (float)x*scaleFactor.x;
   3113             mesh.vertices[vCounter + 1] = GRAY_VALUE(pixels[x + z*mapX])*scaleFactor.y;
   3114             mesh.vertices[vCounter + 2] = (float)z*scaleFactor.z;
   3115 
   3116             mesh.vertices[vCounter + 3] = (float)x*scaleFactor.x;
   3117             mesh.vertices[vCounter + 4] = GRAY_VALUE(pixels[x + (z + 1)*mapX])*scaleFactor.y;
   3118             mesh.vertices[vCounter + 5] = (float)(z + 1)*scaleFactor.z;
   3119 
   3120             mesh.vertices[vCounter + 6] = (float)(x + 1)*scaleFactor.x;
   3121             mesh.vertices[vCounter + 7] = GRAY_VALUE(pixels[(x + 1) + z*mapX])*scaleFactor.y;
   3122             mesh.vertices[vCounter + 8] = (float)z*scaleFactor.z;
   3123 
   3124             // Another triangle - 3 vertex
   3125             mesh.vertices[vCounter + 9] = mesh.vertices[vCounter + 6];
   3126             mesh.vertices[vCounter + 10] = mesh.vertices[vCounter + 7];
   3127             mesh.vertices[vCounter + 11] = mesh.vertices[vCounter + 8];
   3128 
   3129             mesh.vertices[vCounter + 12] = mesh.vertices[vCounter + 3];
   3130             mesh.vertices[vCounter + 13] = mesh.vertices[vCounter + 4];
   3131             mesh.vertices[vCounter + 14] = mesh.vertices[vCounter + 5];
   3132 
   3133             mesh.vertices[vCounter + 15] = (float)(x + 1)*scaleFactor.x;
   3134             mesh.vertices[vCounter + 16] = GRAY_VALUE(pixels[(x + 1) + (z + 1)*mapX])*scaleFactor.y;
   3135             mesh.vertices[vCounter + 17] = (float)(z + 1)*scaleFactor.z;
   3136             vCounter += 18;     // 6 vertex, 18 floats
   3137 
   3138             // Fill texcoords array with data
   3139             //--------------------------------------------------------------
   3140             mesh.texcoords[tcCounter] = (float)x/(mapX - 1);
   3141             mesh.texcoords[tcCounter + 1] = (float)z/(mapZ - 1);
   3142 
   3143             mesh.texcoords[tcCounter + 2] = (float)x/(mapX - 1);
   3144             mesh.texcoords[tcCounter + 3] = (float)(z + 1)/(mapZ - 1);
   3145 
   3146             mesh.texcoords[tcCounter + 4] = (float)(x + 1)/(mapX - 1);
   3147             mesh.texcoords[tcCounter + 5] = (float)z/(mapZ - 1);
   3148 
   3149             mesh.texcoords[tcCounter + 6] = mesh.texcoords[tcCounter + 4];
   3150             mesh.texcoords[tcCounter + 7] = mesh.texcoords[tcCounter + 5];
   3151 
   3152             mesh.texcoords[tcCounter + 8] = mesh.texcoords[tcCounter + 2];
   3153             mesh.texcoords[tcCounter + 9] = mesh.texcoords[tcCounter + 3];
   3154 
   3155             mesh.texcoords[tcCounter + 10] = (float)(x + 1)/(mapX - 1);
   3156             mesh.texcoords[tcCounter + 11] = (float)(z + 1)/(mapZ - 1);
   3157             tcCounter += 12;    // 6 texcoords, 12 floats
   3158 
   3159             // Fill normals array with data
   3160             //--------------------------------------------------------------
   3161             for (int i = 0; i < 18; i += 9)
   3162             {
   3163                 vA.x = mesh.vertices[nCounter + i];
   3164                 vA.y = mesh.vertices[nCounter + i + 1];
   3165                 vA.z = mesh.vertices[nCounter + i + 2];
   3166 
   3167                 vB.x = mesh.vertices[nCounter + i + 3];
   3168                 vB.y = mesh.vertices[nCounter + i + 4];
   3169                 vB.z = mesh.vertices[nCounter + i + 5];
   3170 
   3171                 vC.x = mesh.vertices[nCounter + i + 6];
   3172                 vC.y = mesh.vertices[nCounter + i + 7];
   3173                 vC.z = mesh.vertices[nCounter + i + 8];
   3174 
   3175                 vN = Vector3Normalize(Vector3CrossProduct(Vector3Subtract(vB, vA), Vector3Subtract(vC, vA)));
   3176 
   3177                 mesh.normals[nCounter + i] = vN.x;
   3178                 mesh.normals[nCounter + i + 1] = vN.y;
   3179                 mesh.normals[nCounter + i + 2] = vN.z;
   3180 
   3181                 mesh.normals[nCounter + i + 3] = vN.x;
   3182                 mesh.normals[nCounter + i + 4] = vN.y;
   3183                 mesh.normals[nCounter + i + 5] = vN.z;
   3184 
   3185                 mesh.normals[nCounter + i + 6] = vN.x;
   3186                 mesh.normals[nCounter + i + 7] = vN.y;
   3187                 mesh.normals[nCounter + i + 8] = vN.z;
   3188             }
   3189 
   3190             nCounter += 18;     // 6 vertex, 18 floats
   3191         }
   3192     }
   3193 
   3194     UnloadImageColors(pixels);  // Unload pixels color data
   3195 
   3196     // Upload vertex data to GPU (static mesh)
   3197     UploadMesh(&mesh, false);
   3198 
   3199     return mesh;
   3200 }
   3201 
   3202 // Generate a cubes mesh from pixel data
   3203 // NOTE: Vertex data is uploaded to GPU
   3204 Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
   3205 {
   3206     #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a))
   3207 
   3208     Mesh mesh = { 0 };
   3209 
   3210     Color *pixels = LoadImageColors(cubicmap);
   3211 
   3212     // NOTE: Max possible number of triangles numCubes*(12 triangles by cube)
   3213     int maxTriangles = cubicmap.width*cubicmap.height*12;
   3214 
   3215     int vCounter = 0;       // Used to count vertices
   3216     int tcCounter = 0;      // Used to count texcoords
   3217     int nCounter = 0;       // Used to count normals
   3218 
   3219     float w = cubeSize.x;
   3220     float h = cubeSize.z;
   3221     float h2 = cubeSize.y;
   3222 
   3223     Vector3 *mapVertices = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3));
   3224     Vector2 *mapTexcoords = (Vector2 *)RL_MALLOC(maxTriangles*3*sizeof(Vector2));
   3225     Vector3 *mapNormals = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3));
   3226 
   3227     // Define the 6 normals of the cube, we will combine them accordingly later...
   3228     Vector3 n1 = { 1.0f, 0.0f, 0.0f };
   3229     Vector3 n2 = { -1.0f, 0.0f, 0.0f };
   3230     Vector3 n3 = { 0.0f, 1.0f, 0.0f };
   3231     Vector3 n4 = { 0.0f, -1.0f, 0.0f };
   3232     Vector3 n5 = { 0.0f, 0.0f, -1.0f };
   3233     Vector3 n6 = { 0.0f, 0.0f, 1.0f };
   3234 
   3235     // NOTE: We use texture rectangles to define different textures for top-bottom-front-back-right-left (6)
   3236     typedef struct RectangleF {
   3237         float x;
   3238         float y;
   3239         float width;
   3240         float height;
   3241     } RectangleF;
   3242 
   3243     RectangleF rightTexUV = { 0.0f, 0.0f, 0.5f, 0.5f };
   3244     RectangleF leftTexUV = { 0.5f, 0.0f, 0.5f, 0.5f };
   3245     RectangleF frontTexUV = { 0.0f, 0.0f, 0.5f, 0.5f };
   3246     RectangleF backTexUV = { 0.5f, 0.0f, 0.5f, 0.5f };
   3247     RectangleF topTexUV = { 0.0f, 0.5f, 0.5f, 0.5f };
   3248     RectangleF bottomTexUV = { 0.5f, 0.5f, 0.5f, 0.5f };
   3249 
   3250     for (int z = 0; z < cubicmap.height; ++z)
   3251     {
   3252         for (int x = 0; x < cubicmap.width; ++x)
   3253         {
   3254             // Define the 8 vertex of the cube, we will combine them accordingly later...
   3255             Vector3 v1 = { w*(x - 0.5f), h2, h*(z - 0.5f) };
   3256             Vector3 v2 = { w*(x - 0.5f), h2, h*(z + 0.5f) };
   3257             Vector3 v3 = { w*(x + 0.5f), h2, h*(z + 0.5f) };
   3258             Vector3 v4 = { w*(x + 0.5f), h2, h*(z - 0.5f) };
   3259             Vector3 v5 = { w*(x + 0.5f), 0, h*(z - 0.5f) };
   3260             Vector3 v6 = { w*(x - 0.5f), 0, h*(z - 0.5f) };
   3261             Vector3 v7 = { w*(x - 0.5f), 0, h*(z + 0.5f) };
   3262             Vector3 v8 = { w*(x + 0.5f), 0, h*(z + 0.5f) };
   3263 
   3264             // We check pixel color to be WHITE -> draw full cube
   3265             if (COLOR_EQUAL(pixels[z*cubicmap.width + x], WHITE))
   3266             {
   3267                 // Define triangles and checking collateral cubes
   3268                 //------------------------------------------------
   3269 
   3270                 // Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
   3271                 // WARNING: Not required for a WHITE cubes, created to allow seeing the map from outside
   3272                 mapVertices[vCounter] = v1;
   3273                 mapVertices[vCounter + 1] = v2;
   3274                 mapVertices[vCounter + 2] = v3;
   3275                 mapVertices[vCounter + 3] = v1;
   3276                 mapVertices[vCounter + 4] = v3;
   3277                 mapVertices[vCounter + 5] = v4;
   3278                 vCounter += 6;
   3279 
   3280                 mapNormals[nCounter] = n3;
   3281                 mapNormals[nCounter + 1] = n3;
   3282                 mapNormals[nCounter + 2] = n3;
   3283                 mapNormals[nCounter + 3] = n3;
   3284                 mapNormals[nCounter + 4] = n3;
   3285                 mapNormals[nCounter + 5] = n3;
   3286                 nCounter += 6;
   3287 
   3288                 mapTexcoords[tcCounter] = (Vector2){ topTexUV.x, topTexUV.y };
   3289                 mapTexcoords[tcCounter + 1] = (Vector2){ topTexUV.x, topTexUV.y + topTexUV.height };
   3290                 mapTexcoords[tcCounter + 2] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
   3291                 mapTexcoords[tcCounter + 3] = (Vector2){ topTexUV.x, topTexUV.y };
   3292                 mapTexcoords[tcCounter + 4] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
   3293                 mapTexcoords[tcCounter + 5] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y };
   3294                 tcCounter += 6;
   3295 
   3296                 // Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8)
   3297                 mapVertices[vCounter] = v6;
   3298                 mapVertices[vCounter + 1] = v8;
   3299                 mapVertices[vCounter + 2] = v7;
   3300                 mapVertices[vCounter + 3] = v6;
   3301                 mapVertices[vCounter + 4] = v5;
   3302                 mapVertices[vCounter + 5] = v8;
   3303                 vCounter += 6;
   3304 
   3305                 mapNormals[nCounter] = n4;
   3306                 mapNormals[nCounter + 1] = n4;
   3307                 mapNormals[nCounter + 2] = n4;
   3308                 mapNormals[nCounter + 3] = n4;
   3309                 mapNormals[nCounter + 4] = n4;
   3310                 mapNormals[nCounter + 5] = n4;
   3311                 nCounter += 6;
   3312 
   3313                 mapTexcoords[tcCounter] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
   3314                 mapTexcoords[tcCounter + 1] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
   3315                 mapTexcoords[tcCounter + 2] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y + bottomTexUV.height };
   3316                 mapTexcoords[tcCounter + 3] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
   3317                 mapTexcoords[tcCounter + 4] = (Vector2){ bottomTexUV.x, bottomTexUV.y };
   3318                 mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
   3319                 tcCounter += 6;
   3320 
   3321                 // Checking cube on bottom of current cube
   3322                 if (((z < cubicmap.height - 1) && COLOR_EQUAL(pixels[(z + 1)*cubicmap.width + x], BLACK)) || (z == cubicmap.height - 1))
   3323                 {
   3324                     // Define front triangles (2 tris, 6 vertex) --> v2 v7 v3, v3 v7 v8
   3325                     // NOTE: Collateral occluded faces are not generated
   3326                     mapVertices[vCounter] = v2;
   3327                     mapVertices[vCounter + 1] = v7;
   3328                     mapVertices[vCounter + 2] = v3;
   3329                     mapVertices[vCounter + 3] = v3;
   3330                     mapVertices[vCounter + 4] = v7;
   3331                     mapVertices[vCounter + 5] = v8;
   3332                     vCounter += 6;
   3333 
   3334                     mapNormals[nCounter] = n6;
   3335                     mapNormals[nCounter + 1] = n6;
   3336                     mapNormals[nCounter + 2] = n6;
   3337                     mapNormals[nCounter + 3] = n6;
   3338                     mapNormals[nCounter + 4] = n6;
   3339                     mapNormals[nCounter + 5] = n6;
   3340                     nCounter += 6;
   3341 
   3342                     mapTexcoords[tcCounter] = (Vector2){ frontTexUV.x, frontTexUV.y };
   3343                     mapTexcoords[tcCounter + 1] = (Vector2){ frontTexUV.x, frontTexUV.y + frontTexUV.height };
   3344                     mapTexcoords[tcCounter + 2] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y };
   3345                     mapTexcoords[tcCounter + 3] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y };
   3346                     mapTexcoords[tcCounter + 4] = (Vector2){ frontTexUV.x, frontTexUV.y + frontTexUV.height };
   3347                     mapTexcoords[tcCounter + 5] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y + frontTexUV.height };
   3348                     tcCounter += 6;
   3349                 }
   3350 
   3351                 // Checking cube on top of current cube
   3352                 if (((z > 0) && COLOR_EQUAL(pixels[(z - 1)*cubicmap.width + x], BLACK)) || (z == 0))
   3353                 {
   3354                     // Define back triangles (2 tris, 6 vertex) --> v1 v5 v6, v1 v4 v5
   3355                     // NOTE: Collateral occluded faces are not generated
   3356                     mapVertices[vCounter] = v1;
   3357                     mapVertices[vCounter + 1] = v5;
   3358                     mapVertices[vCounter + 2] = v6;
   3359                     mapVertices[vCounter + 3] = v1;
   3360                     mapVertices[vCounter + 4] = v4;
   3361                     mapVertices[vCounter + 5] = v5;
   3362                     vCounter += 6;
   3363 
   3364                     mapNormals[nCounter] = n5;
   3365                     mapNormals[nCounter + 1] = n5;
   3366                     mapNormals[nCounter + 2] = n5;
   3367                     mapNormals[nCounter + 3] = n5;
   3368                     mapNormals[nCounter + 4] = n5;
   3369                     mapNormals[nCounter + 5] = n5;
   3370                     nCounter += 6;
   3371 
   3372                     mapTexcoords[tcCounter] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y };
   3373                     mapTexcoords[tcCounter + 1] = (Vector2){ backTexUV.x, backTexUV.y + backTexUV.height };
   3374                     mapTexcoords[tcCounter + 2] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y + backTexUV.height };
   3375                     mapTexcoords[tcCounter + 3] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y };
   3376                     mapTexcoords[tcCounter + 4] = (Vector2){ backTexUV.x, backTexUV.y };
   3377                     mapTexcoords[tcCounter + 5] = (Vector2){ backTexUV.x, backTexUV.y + backTexUV.height };
   3378                     tcCounter += 6;
   3379                 }
   3380 
   3381                 // Checking cube on right of current cube
   3382                 if (((x < cubicmap.width - 1) && COLOR_EQUAL(pixels[z*cubicmap.width + (x + 1)], BLACK)) || (x == cubicmap.width - 1))
   3383                 {
   3384                     // Define right triangles (2 tris, 6 vertex) --> v3 v8 v4, v4 v8 v5
   3385                     // NOTE: Collateral occluded faces are not generated
   3386                     mapVertices[vCounter] = v3;
   3387                     mapVertices[vCounter + 1] = v8;
   3388                     mapVertices[vCounter + 2] = v4;
   3389                     mapVertices[vCounter + 3] = v4;
   3390                     mapVertices[vCounter + 4] = v8;
   3391                     mapVertices[vCounter + 5] = v5;
   3392                     vCounter += 6;
   3393 
   3394                     mapNormals[nCounter] = n1;
   3395                     mapNormals[nCounter + 1] = n1;
   3396                     mapNormals[nCounter + 2] = n1;
   3397                     mapNormals[nCounter + 3] = n1;
   3398                     mapNormals[nCounter + 4] = n1;
   3399                     mapNormals[nCounter + 5] = n1;
   3400                     nCounter += 6;
   3401 
   3402                     mapTexcoords[tcCounter] = (Vector2){ rightTexUV.x, rightTexUV.y };
   3403                     mapTexcoords[tcCounter + 1] = (Vector2){ rightTexUV.x, rightTexUV.y + rightTexUV.height };
   3404                     mapTexcoords[tcCounter + 2] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y };
   3405                     mapTexcoords[tcCounter + 3] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y };
   3406                     mapTexcoords[tcCounter + 4] = (Vector2){ rightTexUV.x, rightTexUV.y + rightTexUV.height };
   3407                     mapTexcoords[tcCounter + 5] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y + rightTexUV.height };
   3408                     tcCounter += 6;
   3409                 }
   3410 
   3411                 // Checking cube on left of current cube
   3412                 if (((x > 0) && COLOR_EQUAL(pixels[z*cubicmap.width + (x - 1)], BLACK)) || (x == 0))
   3413                 {
   3414                     // Define left triangles (2 tris, 6 vertex) --> v1 v7 v2, v1 v6 v7
   3415                     // NOTE: Collateral occluded faces are not generated
   3416                     mapVertices[vCounter] = v1;
   3417                     mapVertices[vCounter + 1] = v7;
   3418                     mapVertices[vCounter + 2] = v2;
   3419                     mapVertices[vCounter + 3] = v1;
   3420                     mapVertices[vCounter + 4] = v6;
   3421                     mapVertices[vCounter + 5] = v7;
   3422                     vCounter += 6;
   3423 
   3424                     mapNormals[nCounter] = n2;
   3425                     mapNormals[nCounter + 1] = n2;
   3426                     mapNormals[nCounter + 2] = n2;
   3427                     mapNormals[nCounter + 3] = n2;
   3428                     mapNormals[nCounter + 4] = n2;
   3429                     mapNormals[nCounter + 5] = n2;
   3430                     nCounter += 6;
   3431 
   3432                     mapTexcoords[tcCounter] = (Vector2){ leftTexUV.x, leftTexUV.y };
   3433                     mapTexcoords[tcCounter + 1] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y + leftTexUV.height };
   3434                     mapTexcoords[tcCounter + 2] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y };
   3435                     mapTexcoords[tcCounter + 3] = (Vector2){ leftTexUV.x, leftTexUV.y };
   3436                     mapTexcoords[tcCounter + 4] = (Vector2){ leftTexUV.x, leftTexUV.y + leftTexUV.height };
   3437                     mapTexcoords[tcCounter + 5] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y + leftTexUV.height };
   3438                     tcCounter += 6;
   3439                 }
   3440             }
   3441             // We check pixel color to be BLACK, we will only draw floor and roof
   3442             else if (COLOR_EQUAL(pixels[z*cubicmap.width + x], BLACK))
   3443             {
   3444                 // Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
   3445                 mapVertices[vCounter] = v1;
   3446                 mapVertices[vCounter + 1] = v3;
   3447                 mapVertices[vCounter + 2] = v2;
   3448                 mapVertices[vCounter + 3] = v1;
   3449                 mapVertices[vCounter + 4] = v4;
   3450                 mapVertices[vCounter + 5] = v3;
   3451                 vCounter += 6;
   3452 
   3453                 mapNormals[nCounter] = n4;
   3454                 mapNormals[nCounter + 1] = n4;
   3455                 mapNormals[nCounter + 2] = n4;
   3456                 mapNormals[nCounter + 3] = n4;
   3457                 mapNormals[nCounter + 4] = n4;
   3458                 mapNormals[nCounter + 5] = n4;
   3459                 nCounter += 6;
   3460 
   3461                 mapTexcoords[tcCounter] = (Vector2){ topTexUV.x, topTexUV.y };
   3462                 mapTexcoords[tcCounter + 1] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
   3463                 mapTexcoords[tcCounter + 2] = (Vector2){ topTexUV.x, topTexUV.y + topTexUV.height };
   3464                 mapTexcoords[tcCounter + 3] = (Vector2){ topTexUV.x, topTexUV.y };
   3465                 mapTexcoords[tcCounter + 4] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y };
   3466                 mapTexcoords[tcCounter + 5] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
   3467                 tcCounter += 6;
   3468 
   3469                 // Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8)
   3470                 mapVertices[vCounter] = v6;
   3471                 mapVertices[vCounter + 1] = v7;
   3472                 mapVertices[vCounter + 2] = v8;
   3473                 mapVertices[vCounter + 3] = v6;
   3474                 mapVertices[vCounter + 4] = v8;
   3475                 mapVertices[vCounter + 5] = v5;
   3476                 vCounter += 6;
   3477 
   3478                 mapNormals[nCounter] = n3;
   3479                 mapNormals[nCounter + 1] = n3;
   3480                 mapNormals[nCounter + 2] = n3;
   3481                 mapNormals[nCounter + 3] = n3;
   3482                 mapNormals[nCounter + 4] = n3;
   3483                 mapNormals[nCounter + 5] = n3;
   3484                 nCounter += 6;
   3485 
   3486                 mapTexcoords[tcCounter] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
   3487                 mapTexcoords[tcCounter + 1] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y + bottomTexUV.height };
   3488                 mapTexcoords[tcCounter + 2] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
   3489                 mapTexcoords[tcCounter + 3] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
   3490                 mapTexcoords[tcCounter + 4] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
   3491                 mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y };
   3492                 tcCounter += 6;
   3493             }
   3494         }
   3495     }
   3496 
   3497     // Move data from mapVertices temp arrays to vertices float array
   3498     mesh.vertexCount = vCounter;
   3499     mesh.triangleCount = vCounter/3;
   3500 
   3501     mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
   3502     mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
   3503     mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
   3504     mesh.colors = NULL;
   3505 
   3506     int fCounter = 0;
   3507 
   3508     // Move vertices data
   3509     for (int i = 0; i < vCounter; i++)
   3510     {
   3511         mesh.vertices[fCounter] = mapVertices[i].x;
   3512         mesh.vertices[fCounter + 1] = mapVertices[i].y;
   3513         mesh.vertices[fCounter + 2] = mapVertices[i].z;
   3514         fCounter += 3;
   3515     }
   3516 
   3517     fCounter = 0;
   3518 
   3519     // Move normals data
   3520     for (int i = 0; i < nCounter; i++)
   3521     {
   3522         mesh.normals[fCounter] = mapNormals[i].x;
   3523         mesh.normals[fCounter + 1] = mapNormals[i].y;
   3524         mesh.normals[fCounter + 2] = mapNormals[i].z;
   3525         fCounter += 3;
   3526     }
   3527 
   3528     fCounter = 0;
   3529 
   3530     // Move texcoords data
   3531     for (int i = 0; i < tcCounter; i++)
   3532     {
   3533         mesh.texcoords[fCounter] = mapTexcoords[i].x;
   3534         mesh.texcoords[fCounter + 1] = mapTexcoords[i].y;
   3535         fCounter += 2;
   3536     }
   3537 
   3538     RL_FREE(mapVertices);
   3539     RL_FREE(mapNormals);
   3540     RL_FREE(mapTexcoords);
   3541 
   3542     UnloadImageColors(pixels);   // Unload pixels color data
   3543 
   3544     // Upload vertex data to GPU (static mesh)
   3545     UploadMesh(&mesh, false);
   3546 
   3547     return mesh;
   3548 }
   3549 #endif      // SUPPORT_MESH_GENERATION
   3550 
   3551 // Compute mesh bounding box limits
   3552 // NOTE: minVertex and maxVertex should be transformed by model transform matrix
   3553 BoundingBox GetMeshBoundingBox(Mesh mesh)
   3554 {
   3555     // Get min and max vertex to construct bounds (AABB)
   3556     Vector3 minVertex = { 0 };
   3557     Vector3 maxVertex = { 0 };
   3558 
   3559     if (mesh.vertices != NULL)
   3560     {
   3561         minVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] };
   3562         maxVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] };
   3563 
   3564         for (int i = 1; i < mesh.vertexCount; i++)
   3565         {
   3566             minVertex = Vector3Min(minVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] });
   3567             maxVertex = Vector3Max(maxVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] });
   3568         }
   3569     }
   3570 
   3571     // Create the bounding box
   3572     BoundingBox box = { 0 };
   3573     box.min = minVertex;
   3574     box.max = maxVertex;
   3575 
   3576     return box;
   3577 }
   3578 
   3579 // Compute mesh tangents
   3580 // NOTE: To calculate mesh tangents and binormals we need mesh vertex positions and texture coordinates
   3581 // Implementation based on: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html
   3582 void GenMeshTangents(Mesh *mesh)
   3583 {
   3584     if ((mesh->vertices == NULL) || (mesh->texcoords == NULL))
   3585     {
   3586         TRACELOG(LOG_WARNING, "MESH: Tangents generation requires texcoord vertex attribute data");
   3587         return;
   3588     }
   3589 
   3590     if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
   3591     else
   3592     {
   3593         RL_FREE(mesh->tangents);
   3594         mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
   3595     }
   3596 
   3597     Vector3 *tan1 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
   3598     Vector3 *tan2 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
   3599 
   3600     if (mesh->vertexCount % 3 != 0)
   3601     {
   3602         TRACELOG(LOG_WARNING, "MESH: vertexCount expected to be a multiple of 3. Expect uninitialized values.");
   3603     }
   3604 
   3605     for (int i = 0; i <= mesh->vertexCount - 3; i += 3)
   3606     {
   3607         // Get triangle vertices
   3608         Vector3 v1 = { mesh->vertices[(i + 0)*3 + 0], mesh->vertices[(i + 0)*3 + 1], mesh->vertices[(i + 0)*3 + 2] };
   3609         Vector3 v2 = { mesh->vertices[(i + 1)*3 + 0], mesh->vertices[(i + 1)*3 + 1], mesh->vertices[(i + 1)*3 + 2] };
   3610         Vector3 v3 = { mesh->vertices[(i + 2)*3 + 0], mesh->vertices[(i + 2)*3 + 1], mesh->vertices[(i + 2)*3 + 2] };
   3611 
   3612         // Get triangle texcoords
   3613         Vector2 uv1 = { mesh->texcoords[(i + 0)*2 + 0], mesh->texcoords[(i + 0)*2 + 1] };
   3614         Vector2 uv2 = { mesh->texcoords[(i + 1)*2 + 0], mesh->texcoords[(i + 1)*2 + 1] };
   3615         Vector2 uv3 = { mesh->texcoords[(i + 2)*2 + 0], mesh->texcoords[(i + 2)*2 + 1] };
   3616 
   3617         float x1 = v2.x - v1.x;
   3618         float y1 = v2.y - v1.y;
   3619         float z1 = v2.z - v1.z;
   3620         float x2 = v3.x - v1.x;
   3621         float y2 = v3.y - v1.y;
   3622         float z2 = v3.z - v1.z;
   3623 
   3624         float s1 = uv2.x - uv1.x;
   3625         float t1 = uv2.y - uv1.y;
   3626         float s2 = uv3.x - uv1.x;
   3627         float t2 = uv3.y - uv1.y;
   3628 
   3629         float div = s1*t2 - s2*t1;
   3630         float r = (div == 0.0f)? 0.0f : 1.0f/div;
   3631 
   3632         Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r };
   3633         Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r };
   3634 
   3635         tan1[i + 0] = sdir;
   3636         tan1[i + 1] = sdir;
   3637         tan1[i + 2] = sdir;
   3638 
   3639         tan2[i + 0] = tdir;
   3640         tan2[i + 1] = tdir;
   3641         tan2[i + 2] = tdir;
   3642     }
   3643 
   3644     // Compute tangents considering normals
   3645     for (int i = 0; i < mesh->vertexCount; i++)
   3646     {
   3647         Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
   3648         Vector3 tangent = tan1[i];
   3649 
   3650         // TODO: Review, not sure if tangent computation is right, just used reference proposed maths...
   3651 #if defined(COMPUTE_TANGENTS_METHOD_01)
   3652         Vector3 tmp = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent)));
   3653         tmp = Vector3Normalize(tmp);
   3654         mesh->tangents[i*4 + 0] = tmp.x;
   3655         mesh->tangents[i*4 + 1] = tmp.y;
   3656         mesh->tangents[i*4 + 2] = tmp.z;
   3657         mesh->tangents[i*4 + 3] = 1.0f;
   3658 #else
   3659         Vector3OrthoNormalize(&normal, &tangent);
   3660         mesh->tangents[i*4 + 0] = tangent.x;
   3661         mesh->tangents[i*4 + 1] = tangent.y;
   3662         mesh->tangents[i*4 + 2] = tangent.z;
   3663         mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f)? -1.0f : 1.0f;
   3664 #endif
   3665     }
   3666 
   3667     RL_FREE(tan1);
   3668     RL_FREE(tan2);
   3669 
   3670     if (mesh->vboId != NULL)
   3671     {
   3672         if (mesh->vboId[SHADER_LOC_VERTEX_TANGENT] != 0)
   3673         {
   3674             // Update existing vertex buffer
   3675             rlUpdateVertexBuffer(mesh->vboId[SHADER_LOC_VERTEX_TANGENT], mesh->tangents, mesh->vertexCount*4*sizeof(float), 0);
   3676         }
   3677         else
   3678         {
   3679             // Load a new tangent attributes buffer
   3680             mesh->vboId[SHADER_LOC_VERTEX_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), false);
   3681         }
   3682 
   3683         rlEnableVertexArray(mesh->vaoId);
   3684         rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0);
   3685         rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT);
   3686         rlDisableVertexArray();
   3687     }
   3688 
   3689     TRACELOG(LOG_INFO, "MESH: Tangents data computed and uploaded for provided mesh");
   3690 }
   3691 
   3692 // Draw a model (with texture if set)
   3693 void DrawModel(Model model, Vector3 position, float scale, Color tint)
   3694 {
   3695     Vector3 vScale = { scale, scale, scale };
   3696     Vector3 rotationAxis = { 0.0f, 1.0f, 0.0f };
   3697 
   3698     DrawModelEx(model, position, rotationAxis, 0.0f, vScale, tint);
   3699 }
   3700 
   3701 // Draw a model with extended parameters
   3702 void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
   3703 {
   3704     // Calculate transformation matrix from function parameters
   3705     // Get transform matrix (rotation -> scale -> translation)
   3706     Matrix matScale = MatrixScale(scale.x, scale.y, scale.z);
   3707     Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD);
   3708     Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
   3709 
   3710     Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
   3711 
   3712     // Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform)
   3713     model.transform = MatrixMultiply(model.transform, matTransform);
   3714 
   3715     for (int i = 0; i < model.meshCount; i++)
   3716     {
   3717         Color color = model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color;
   3718 
   3719         Color colorTint = WHITE;
   3720         colorTint.r = (unsigned char)(((int)color.r*(int)tint.r)/255);
   3721         colorTint.g = (unsigned char)(((int)color.g*(int)tint.g)/255);
   3722         colorTint.b = (unsigned char)(((int)color.b*(int)tint.b)/255);
   3723         colorTint.a = (unsigned char)(((int)color.a*(int)tint.a)/255);
   3724 
   3725         model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = colorTint;
   3726         DrawMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform);
   3727         model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = color;
   3728     }
   3729 }
   3730 
   3731 // Draw a model wires (with texture if set)
   3732 void DrawModelWires(Model model, Vector3 position, float scale, Color tint)
   3733 {
   3734     rlEnableWireMode();
   3735 
   3736     DrawModel(model, position, scale, tint);
   3737 
   3738     rlDisableWireMode();
   3739 }
   3740 
   3741 // Draw a model wires (with texture if set) with extended parameters
   3742 void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
   3743 {
   3744     rlEnableWireMode();
   3745 
   3746     DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);
   3747 
   3748     rlDisableWireMode();
   3749 }
   3750 
   3751 // Draw a model points
   3752 void DrawModelPoints(Model model, Vector3 position, float scale, Color tint)
   3753 {
   3754     rlEnablePointMode();
   3755     rlDisableBackfaceCulling();
   3756 
   3757     DrawModel(model, position, scale, tint);
   3758 
   3759     rlEnableBackfaceCulling();
   3760     rlDisableWireMode();
   3761 }
   3762 
   3763 // Draw a model points
   3764 void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
   3765 {
   3766     rlEnablePointMode();
   3767     rlDisableBackfaceCulling();
   3768 
   3769     DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);
   3770 
   3771     rlEnableBackfaceCulling();
   3772     rlDisableWireMode();
   3773 }
   3774 
   3775 // Draw a billboard
   3776 void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint)
   3777 {
   3778     Rectangle source = { 0.0f, 0.0f, (float)texture.width, (float)texture.height };
   3779 
   3780     DrawBillboardRec(camera, texture, source, position, (Vector2) { scale*fabsf((float)source.width/source.height), scale }, tint);
   3781 }
   3782 
   3783 // Draw a billboard (part of a texture defined by a rectangle)
   3784 void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint)
   3785 {
   3786     // NOTE: Billboard locked on axis-Y
   3787     Vector3 up = { 0.0f, 1.0f, 0.0f };
   3788 
   3789     DrawBillboardPro(camera, texture, source, position, up, size, Vector2Scale(size, 0.5), 0.0f, tint);
   3790 }
   3791 
   3792 // Draw a billboard with additional parameters
   3793 void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint)
   3794 {
   3795     // Compute the up vector and the right vector
   3796     Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
   3797     Vector3 right = { matView.m0, matView.m4, matView.m8 };
   3798     right = Vector3Scale(right, size.x);
   3799     up = Vector3Scale(up, size.y);
   3800 
   3801     // Flip the content of the billboard while maintaining the counterclockwise edge rendering order
   3802     if (size.x < 0.0f)
   3803     {
   3804         source.x += size.x;
   3805         source.width *= -1.0;
   3806         right = Vector3Negate(right);
   3807         origin.x *= -1.0f;
   3808     }
   3809     if (size.y < 0.0f)
   3810     {
   3811         source.y += size.y;
   3812         source.height *= -1.0;
   3813         up = Vector3Negate(up);
   3814         origin.y *= -1.0f;
   3815     }
   3816 
   3817     // Draw the texture region described by source on the following rectangle in 3D space:
   3818     //
   3819     //                size.x          <--.
   3820     //  3 ^---------------------------+ 2 \ rotation
   3821     //    |                           |   /
   3822     //    |                           |
   3823     //    |   origin.x   position     |
   3824     // up |..............             | size.y
   3825     //    |             .             |
   3826     //    |             . origin.y    |
   3827     //    |             .             |
   3828     //  0 +---------------------------> 1
   3829     //                right
   3830     Vector3 forward;
   3831     if (rotation != 0.0) forward = Vector3CrossProduct(right, up);
   3832 
   3833     Vector3 origin3D = Vector3Add(Vector3Scale(Vector3Normalize(right), origin.x), Vector3Scale(Vector3Normalize(up), origin.y));
   3834 
   3835     Vector3 points[4];
   3836     points[0] = Vector3Zero();
   3837     points[1] = right;
   3838     points[2] = Vector3Add(up, right);
   3839     points[3] = up;
   3840 
   3841     for (int i = 0; i < 4; i++)
   3842     {
   3843         points[i] = Vector3Subtract(points[i], origin3D);
   3844         if (rotation != 0.0) points[i] = Vector3RotateByAxisAngle(points[i], forward, rotation * DEG2RAD);
   3845         points[i] = Vector3Add(points[i], position);
   3846     }
   3847 
   3848     Vector2 texcoords[4];
   3849     texcoords[0] = (Vector2) { (float)source.x/texture.width, (float)(source.y + source.height)/texture.height };
   3850     texcoords[1] = (Vector2) { (float)(source.x + source.width)/texture.width, (float)(source.y + source.height)/texture.height };
   3851     texcoords[2] = (Vector2) { (float)(source.x + source.width)/texture.width, (float)source.y/texture.height };
   3852     texcoords[3] = (Vector2) { (float)source.x/texture.width, (float)source.y/texture.height };
   3853 
   3854     rlSetTexture(texture.id);
   3855     rlBegin(RL_QUADS);
   3856 
   3857         rlColor4ub(tint.r, tint.g, tint.b, tint.a);
   3858         for (int i = 0; i < 4; i++)
   3859         {
   3860             rlTexCoord2f(texcoords[i].x, texcoords[i].y);
   3861             rlVertex3f(points[i].x, points[i].y, points[i].z);
   3862         }
   3863 
   3864     rlEnd();
   3865     rlSetTexture(0);
   3866 }
   3867 
   3868 // Draw a bounding box with wires
   3869 void DrawBoundingBox(BoundingBox box, Color color)
   3870 {
   3871     Vector3 size = { 0 };
   3872 
   3873     size.x = fabsf(box.max.x - box.min.x);
   3874     size.y = fabsf(box.max.y - box.min.y);
   3875     size.z = fabsf(box.max.z - box.min.z);
   3876 
   3877     Vector3 center = { box.min.x + size.x/2.0f, box.min.y + size.y/2.0f, box.min.z + size.z/2.0f };
   3878 
   3879     DrawCubeWires(center, size.x, size.y, size.z, color);
   3880 }
   3881 
   3882 // Check collision between two spheres
   3883 bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2)
   3884 {
   3885     bool collision = false;
   3886 
   3887     // Simple way to check for collision, just checking distance between two points
   3888     // Unfortunately, sqrtf() is a costly operation, so we avoid it with following solution
   3889     /*
   3890     float dx = center1.x - center2.x;      // X distance between centers
   3891     float dy = center1.y - center2.y;      // Y distance between centers
   3892     float dz = center1.z - center2.z;      // Z distance between centers
   3893 
   3894     float distance = sqrtf(dx*dx + dy*dy + dz*dz);  // Distance between centers
   3895 
   3896     if (distance <= (radius1 + radius2)) collision = true;
   3897     */
   3898 
   3899     // Check for distances squared to avoid sqrtf()
   3900     if (Vector3DotProduct(Vector3Subtract(center2, center1), Vector3Subtract(center2, center1)) <= (radius1 + radius2)*(radius1 + radius2)) collision = true;
   3901 
   3902     return collision;
   3903 }
   3904 
   3905 // Check collision between two boxes
   3906 // NOTE: Boxes are defined by two points minimum and maximum
   3907 bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2)
   3908 {
   3909     bool collision = true;
   3910 
   3911     if ((box1.max.x >= box2.min.x) && (box1.min.x <= box2.max.x))
   3912     {
   3913         if ((box1.max.y < box2.min.y) || (box1.min.y > box2.max.y)) collision = false;
   3914         if ((box1.max.z < box2.min.z) || (box1.min.z > box2.max.z)) collision = false;
   3915     }
   3916     else collision = false;
   3917 
   3918     return collision;
   3919 }
   3920 
   3921 // Check collision between box and sphere
   3922 bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius)
   3923 {
   3924     bool collision = false;
   3925 
   3926     float dmin = 0;
   3927 
   3928     if (center.x < box.min.x) dmin += powf(center.x - box.min.x, 2);
   3929     else if (center.x > box.max.x) dmin += powf(center.x - box.max.x, 2);
   3930 
   3931     if (center.y < box.min.y) dmin += powf(center.y - box.min.y, 2);
   3932     else if (center.y > box.max.y) dmin += powf(center.y - box.max.y, 2);
   3933 
   3934     if (center.z < box.min.z) dmin += powf(center.z - box.min.z, 2);
   3935     else if (center.z > box.max.z) dmin += powf(center.z - box.max.z, 2);
   3936 
   3937     if (dmin <= (radius*radius)) collision = true;
   3938 
   3939     return collision;
   3940 }
   3941 
   3942 // Get collision info between ray and sphere
   3943 RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius)
   3944 {
   3945     RayCollision collision = { 0 };
   3946 
   3947     Vector3 raySpherePos = Vector3Subtract(center, ray.position);
   3948     float vector = Vector3DotProduct(raySpherePos, ray.direction);
   3949     float distance = Vector3Length(raySpherePos);
   3950     float d = radius*radius - (distance*distance - vector*vector);
   3951 
   3952     collision.hit = d >= 0.0f;
   3953 
   3954     // Check if ray origin is inside the sphere to calculate the correct collision point
   3955     if (distance < radius)
   3956     {
   3957         collision.distance = vector + sqrtf(d);
   3958 
   3959         // Calculate collision point
   3960         collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance));
   3961 
   3962         // Calculate collision normal (pointing outwards)
   3963         collision.normal = Vector3Negate(Vector3Normalize(Vector3Subtract(collision.point, center)));
   3964     }
   3965     else
   3966     {
   3967         collision.distance = vector - sqrtf(d);
   3968 
   3969         // Calculate collision point
   3970         collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance));
   3971 
   3972         // Calculate collision normal (pointing inwards)
   3973         collision.normal = Vector3Normalize(Vector3Subtract(collision.point, center));
   3974     }
   3975 
   3976     return collision;
   3977 }
   3978 
   3979 // Get collision info between ray and box
   3980 RayCollision GetRayCollisionBox(Ray ray, BoundingBox box)
   3981 {
   3982     RayCollision collision = { 0 };
   3983 
   3984     // Note: If ray.position is inside the box, the distance is negative (as if the ray was reversed)
   3985     // Reversing ray.direction will give use the correct result
   3986     bool insideBox = (ray.position.x > box.min.x) && (ray.position.x < box.max.x) &&
   3987                      (ray.position.y > box.min.y) && (ray.position.y < box.max.y) &&
   3988                      (ray.position.z > box.min.z) && (ray.position.z < box.max.z);
   3989 
   3990     if (insideBox) ray.direction = Vector3Negate(ray.direction);
   3991 
   3992     float t[11] = { 0 };
   3993 
   3994     t[8] = 1.0f/ray.direction.x;
   3995     t[9] = 1.0f/ray.direction.y;
   3996     t[10] = 1.0f/ray.direction.z;
   3997 
   3998     t[0] = (box.min.x - ray.position.x)*t[8];
   3999     t[1] = (box.max.x - ray.position.x)*t[8];
   4000     t[2] = (box.min.y - ray.position.y)*t[9];
   4001     t[3] = (box.max.y - ray.position.y)*t[9];
   4002     t[4] = (box.min.z - ray.position.z)*t[10];
   4003     t[5] = (box.max.z - ray.position.z)*t[10];
   4004     t[6] = (float)fmax(fmax(fmin(t[0], t[1]), fmin(t[2], t[3])), fmin(t[4], t[5]));
   4005     t[7] = (float)fmin(fmin(fmax(t[0], t[1]), fmax(t[2], t[3])), fmax(t[4], t[5]));
   4006 
   4007     collision.hit = !((t[7] < 0) || (t[6] > t[7]));
   4008     collision.distance = t[6];
   4009     collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance));
   4010 
   4011     // Get box center point
   4012     collision.normal = Vector3Lerp(box.min, box.max, 0.5f);
   4013     // Get vector center point->hit point
   4014     collision.normal = Vector3Subtract(collision.point, collision.normal);
   4015     // Scale vector to unit cube
   4016     // NOTE: We use an additional .01 to fix numerical errors
   4017     collision.normal = Vector3Scale(collision.normal, 2.01f);
   4018     collision.normal = Vector3Divide(collision.normal, Vector3Subtract(box.max, box.min));
   4019     // The relevant elements of the vector are now slightly larger than 1.0f (or smaller than -1.0f)
   4020     // and the others are somewhere between -1.0 and 1.0 casting to int is exactly our wanted normal!
   4021     collision.normal.x = (float)((int)collision.normal.x);
   4022     collision.normal.y = (float)((int)collision.normal.y);
   4023     collision.normal.z = (float)((int)collision.normal.z);
   4024 
   4025     collision.normal = Vector3Normalize(collision.normal);
   4026 
   4027     if (insideBox)
   4028     {
   4029         // Reset ray.direction
   4030         ray.direction = Vector3Negate(ray.direction);
   4031         // Fix result
   4032         collision.distance *= -1.0f;
   4033         collision.normal = Vector3Negate(collision.normal);
   4034     }
   4035 
   4036     return collision;
   4037 }
   4038 
   4039 // Get collision info between ray and mesh
   4040 RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform)
   4041 {
   4042     RayCollision collision = { 0 };
   4043 
   4044     // Check if mesh vertex data on CPU for testing
   4045     if (mesh.vertices != NULL)
   4046     {
   4047         int triangleCount = mesh.triangleCount;
   4048 
   4049         // Test against all triangles in mesh
   4050         for (int i = 0; i < triangleCount; i++)
   4051         {
   4052             Vector3 a, b, c;
   4053             Vector3* vertdata = (Vector3*)mesh.vertices;
   4054 
   4055             if (mesh.indices)
   4056             {
   4057                 a = vertdata[mesh.indices[i*3 + 0]];
   4058                 b = vertdata[mesh.indices[i*3 + 1]];
   4059                 c = vertdata[mesh.indices[i*3 + 2]];
   4060             }
   4061             else
   4062             {
   4063                 a = vertdata[i*3 + 0];
   4064                 b = vertdata[i*3 + 1];
   4065                 c = vertdata[i*3 + 2];
   4066             }
   4067 
   4068             a = Vector3Transform(a, transform);
   4069             b = Vector3Transform(b, transform);
   4070             c = Vector3Transform(c, transform);
   4071 
   4072             RayCollision triHitInfo = GetRayCollisionTriangle(ray, a, b, c);
   4073 
   4074             if (triHitInfo.hit)
   4075             {
   4076                 // Save the closest hit triangle
   4077                 if ((!collision.hit) || (collision.distance > triHitInfo.distance)) collision = triHitInfo;
   4078             }
   4079         }
   4080     }
   4081 
   4082     return collision;
   4083 }
   4084 
   4085 // Get collision info between ray and triangle
   4086 // NOTE: The points are expected to be in counter-clockwise winding
   4087 // NOTE: Based on https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
   4088 RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3)
   4089 {
   4090     #define EPSILON 0.000001f        // A small number
   4091 
   4092     RayCollision collision = { 0 };
   4093     Vector3 edge1 = { 0 };
   4094     Vector3 edge2 = { 0 };
   4095     Vector3 p, q, tv;
   4096     float det, invDet, u, v, t;
   4097 
   4098     // Find vectors for two edges sharing V1
   4099     edge1 = Vector3Subtract(p2, p1);
   4100     edge2 = Vector3Subtract(p3, p1);
   4101 
   4102     // Begin calculating determinant - also used to calculate u parameter
   4103     p = Vector3CrossProduct(ray.direction, edge2);
   4104 
   4105     // If determinant is near zero, ray lies in plane of triangle or ray is parallel to plane of triangle
   4106     det = Vector3DotProduct(edge1, p);
   4107 
   4108     // Avoid culling!
   4109     if ((det > -EPSILON) && (det < EPSILON)) return collision;
   4110 
   4111     invDet = 1.0f/det;
   4112 
   4113     // Calculate distance from V1 to ray origin
   4114     tv = Vector3Subtract(ray.position, p1);
   4115 
   4116     // Calculate u parameter and test bound
   4117     u = Vector3DotProduct(tv, p)*invDet;
   4118 
   4119     // The intersection lies outside the triangle
   4120     if ((u < 0.0f) || (u > 1.0f)) return collision;
   4121 
   4122     // Prepare to test v parameter
   4123     q = Vector3CrossProduct(tv, edge1);
   4124 
   4125     // Calculate V parameter and test bound
   4126     v = Vector3DotProduct(ray.direction, q)*invDet;
   4127 
   4128     // The intersection lies outside the triangle
   4129     if ((v < 0.0f) || ((u + v) > 1.0f)) return collision;
   4130 
   4131     t = Vector3DotProduct(edge2, q)*invDet;
   4132 
   4133     if (t > EPSILON)
   4134     {
   4135         // Ray hit, get hit point and normal
   4136         collision.hit = true;
   4137         collision.distance = t;
   4138         collision.normal = Vector3Normalize(Vector3CrossProduct(edge1, edge2));
   4139         collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, t));
   4140     }
   4141 
   4142     return collision;
   4143 }
   4144 
   4145 // Get collision info between ray and quad
   4146 // NOTE: The points are expected to be in counter-clockwise winding
   4147 RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4)
   4148 {
   4149     RayCollision collision = { 0 };
   4150 
   4151     collision = GetRayCollisionTriangle(ray, p1, p2, p4);
   4152 
   4153     if (!collision.hit) collision = GetRayCollisionTriangle(ray, p2, p3, p4);
   4154 
   4155     return collision;
   4156 }
   4157 
   4158 //----------------------------------------------------------------------------------
   4159 // Module specific Functions Definition
   4160 //----------------------------------------------------------------------------------
   4161 #if defined(SUPPORT_FILEFORMAT_IQM) || defined(SUPPORT_FILEFORMAT_GLTF)
   4162 // Build pose from parent joints
   4163 // NOTE: Required for animations loading (required by IQM and GLTF)
   4164 static void BuildPoseFromParentJoints(BoneInfo *bones, int boneCount, Transform *transforms)
   4165 {
   4166     for (int i = 0; i < boneCount; i++)
   4167     {
   4168         if (bones[i].parent >= 0)
   4169         {
   4170             if (bones[i].parent > i)
   4171             {
   4172                 TRACELOG(LOG_WARNING, "Assumes bones are toplogically sorted, but bone %d has parent %d. Skipping.", i, bones[i].parent);
   4173                 continue;
   4174             }
   4175             transforms[i].rotation = QuaternionMultiply(transforms[bones[i].parent].rotation, transforms[i].rotation);
   4176             transforms[i].translation = Vector3RotateByQuaternion(transforms[i].translation, transforms[bones[i].parent].rotation);
   4177             transforms[i].translation = Vector3Add(transforms[i].translation, transforms[bones[i].parent].translation);
   4178             transforms[i].scale = Vector3Multiply(transforms[i].scale, transforms[bones[i].parent].scale);
   4179         }
   4180     }
   4181 }
   4182 #endif
   4183 
   4184 #if defined(SUPPORT_FILEFORMAT_OBJ)
   4185 // Load OBJ mesh data
   4186 //
   4187 // Keep the following information in mind when reading this
   4188 //  - A mesh is created for every material present in the obj file
   4189 //  - the model.meshCount is therefore the materialCount returned from tinyobj
   4190 //  - the mesh is automatically triangulated by tinyobj
   4191 static Model LoadOBJ(const char *fileName)
   4192 {
   4193     tinyobj_attrib_t objAttributes = { 0 };
   4194     tinyobj_shape_t* objShapes = NULL;
   4195     unsigned int objShapeCount = 0;
   4196 
   4197     tinyobj_material_t* objMaterials = NULL;
   4198     unsigned int objMaterialCount = 0;
   4199 
   4200     Model model = { 0 };
   4201     model.transform = MatrixIdentity();
   4202 
   4203     char* fileText = LoadFileText(fileName);
   4204 
   4205     if (fileText == NULL)
   4206     {
   4207         TRACELOG(LOG_ERROR, "MODEL Unable to read obj file %s", fileName);
   4208         return model;
   4209     }
   4210 
   4211     char currentDir[1024] = { 0 };
   4212     strcpy(currentDir, GetWorkingDirectory()); // Save current working directory
   4213     const char* workingDir = GetDirectoryPath(fileName); // Switch to OBJ directory for material path correctness
   4214     if (CHDIR(workingDir) != 0)
   4215     {
   4216         TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir);
   4217     }
   4218 
   4219     unsigned int dataSize = (unsigned int)strlen(fileText);
   4220 
   4221     unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;
   4222     int ret = tinyobj_parse_obj(&objAttributes, &objShapes, &objShapeCount, &objMaterials, &objMaterialCount, fileText, dataSize, flags);
   4223 
   4224     if (ret != TINYOBJ_SUCCESS)
   4225     {
   4226         TRACELOG(LOG_ERROR, "MODEL Unable to read obj data %s", fileName);
   4227         return model;
   4228     }
   4229 
   4230     UnloadFileText(fileText);
   4231 
   4232     unsigned int faceVertIndex = 0;
   4233     unsigned int nextShape = 1;
   4234     int lastMaterial = -1;
   4235     unsigned int meshIndex = 0;
   4236 
   4237     // count meshes
   4238     unsigned int nextShapeEnd = objAttributes.num_face_num_verts;
   4239 
   4240     // see how many verts till the next shape
   4241 
   4242     if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset;
   4243 
   4244     // walk all the faces
   4245     for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)
   4246     {
   4247         if (faceId >= nextShapeEnd)
   4248         {
   4249             // try to find the last vert in the next shape
   4250             nextShape++;
   4251             if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset;
   4252             else nextShapeEnd = objAttributes.num_face_num_verts; // this is actually the total number of face verts in the file, not faces
   4253             meshIndex++;
   4254         }
   4255         else if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial)
   4256         {
   4257             meshIndex++;// if this is a new material, we need to allocate a new mesh
   4258         }
   4259 
   4260         lastMaterial = objAttributes.material_ids[faceId];
   4261         faceVertIndex += objAttributes.face_num_verts[faceId];
   4262     }
   4263 
   4264     // allocate the base meshes and materials
   4265     model.meshCount = meshIndex + 1;
   4266     model.meshes = (Mesh*)MemAlloc(sizeof(Mesh) * model.meshCount);
   4267 
   4268     if (objMaterialCount > 0)
   4269     {
   4270         model.materialCount = objMaterialCount;
   4271         model.materials = (Material*)MemAlloc(sizeof(Material) * objMaterialCount);
   4272     }
   4273     else // we must allocate at least one material
   4274     {
   4275         model.materialCount = 1;
   4276         model.materials = (Material*)MemAlloc(sizeof(Material) * 1);
   4277     }
   4278 
   4279     model.meshMaterial = (int*)MemAlloc(sizeof(int) * model.meshCount);
   4280 
   4281     // see how many verts are in each mesh
   4282     unsigned int* localMeshVertexCounts = (unsigned int*)MemAlloc(sizeof(unsigned int) * model.meshCount);
   4283 
   4284     faceVertIndex = 0;
   4285     nextShapeEnd = objAttributes.num_face_num_verts;
   4286     lastMaterial = -1;
   4287     meshIndex = 0;
   4288     unsigned int localMeshVertexCount = 0;
   4289 
   4290     nextShape = 1;
   4291     if (objShapeCount > 1)
   4292         nextShapeEnd = objShapes[nextShape].face_offset;
   4293 
   4294     // walk all the faces
   4295     for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)
   4296     {
   4297         bool newMesh = false; // do we need a new mesh?
   4298         if (faceId >= nextShapeEnd)
   4299         {
   4300             // try to find the last vert in the next shape
   4301             nextShape++;
   4302             if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset;
   4303             else nextShapeEnd = objAttributes.num_face_num_verts; // this is actually the total number of face verts in the file, not faces
   4304 
   4305             newMesh = true;
   4306         }
   4307         else if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial)
   4308         {
   4309             newMesh = true;
   4310         }
   4311 
   4312         lastMaterial = objAttributes.material_ids[faceId];
   4313 
   4314         if (newMesh)
   4315         {
   4316             localMeshVertexCounts[meshIndex] = localMeshVertexCount;
   4317 
   4318             localMeshVertexCount = 0;
   4319             meshIndex++;
   4320         }
   4321 
   4322         faceVertIndex += objAttributes.face_num_verts[faceId];
   4323         localMeshVertexCount += objAttributes.face_num_verts[faceId];
   4324     }
   4325     localMeshVertexCounts[meshIndex] = localMeshVertexCount;
   4326 
   4327     for (int i = 0; i < model.meshCount; i++)
   4328     {
   4329         // allocate the buffers for each mesh
   4330         unsigned int vertexCount = localMeshVertexCounts[i];
   4331 
   4332         model.meshes[i].vertexCount = vertexCount;
   4333         model.meshes[i].triangleCount = vertexCount / 3;
   4334 
   4335         model.meshes[i].vertices = (float*)MemAlloc(sizeof(float) * vertexCount * 3);
   4336         model.meshes[i].normals = (float*)MemAlloc(sizeof(float) * vertexCount * 3);
   4337         model.meshes[i].texcoords = (float*)MemAlloc(sizeof(float) * vertexCount * 2);
   4338         model.meshes[i].colors = (unsigned char*)MemAlloc(sizeof(unsigned char) * vertexCount * 4);
   4339     }
   4340 
   4341     MemFree(localMeshVertexCounts);
   4342     localMeshVertexCounts = NULL;
   4343 
   4344     // fill meshes
   4345     faceVertIndex = 0;
   4346 
   4347     nextShapeEnd = objAttributes.num_face_num_verts;
   4348 
   4349     // see how many verts till the next shape
   4350     nextShape = 1;
   4351     if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset;
   4352     lastMaterial = -1;
   4353     meshIndex = 0;
   4354     localMeshVertexCount = 0;
   4355 
   4356     // walk all the faces
   4357     for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)
   4358     {
   4359         bool newMesh = false; // do we need a new mesh?
   4360         if (faceId >= nextShapeEnd)
   4361         {
   4362             // try to find the last vert in the next shape
   4363             nextShape++;
   4364             if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset;
   4365             else nextShapeEnd = objAttributes.num_face_num_verts; // this is actually the total number of face verts in the file, not faces
   4366             newMesh = true;
   4367         }
   4368         // if this is a new material, we need to allocate a new mesh
   4369         if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial) newMesh = true;
   4370         lastMaterial = objAttributes.material_ids[faceId];
   4371 
   4372         if (newMesh)
   4373         {
   4374             localMeshVertexCount = 0;
   4375             meshIndex++;
   4376         }
   4377 
   4378         int matId = 0;
   4379         if (lastMaterial >= 0 && lastMaterial < (int)objMaterialCount)
   4380             matId = lastMaterial;
   4381 
   4382         model.meshMaterial[meshIndex] = matId;
   4383 
   4384         for (int f = 0; f < objAttributes.face_num_verts[faceId]; f++)
   4385         {
   4386             int vertIndex = objAttributes.faces[faceVertIndex].v_idx;
   4387             int normalIndex = objAttributes.faces[faceVertIndex].vn_idx;
   4388             int texcordIndex = objAttributes.faces[faceVertIndex].vt_idx;
   4389 
   4390             for (int i = 0; i < 3; i++)
   4391                 model.meshes[meshIndex].vertices[localMeshVertexCount * 3 + i] = objAttributes.vertices[vertIndex * 3 + i];
   4392 
   4393             for (int i = 0; i < 3; i++)
   4394                 model.meshes[meshIndex].normals[localMeshVertexCount * 3 + i] = objAttributes.normals[normalIndex * 3 + i];
   4395 
   4396             for (int i = 0; i < 2; i++)
   4397                 model.meshes[meshIndex].texcoords[localMeshVertexCount * 2 + i] = objAttributes.texcoords[texcordIndex * 2 + i];
   4398 
   4399             model.meshes[meshIndex].texcoords[localMeshVertexCount * 2 + 1] = 1.0f - model.meshes[meshIndex].texcoords[localMeshVertexCount * 2 + 1];
   4400 
   4401             for (int i = 0; i < 4; i++)
   4402                 model.meshes[meshIndex].colors[localMeshVertexCount * 4 + i] = 255;
   4403 
   4404             faceVertIndex++;
   4405             localMeshVertexCount++;
   4406         }
   4407     }
   4408 
   4409     if (objMaterialCount > 0) ProcessMaterialsOBJ(model.materials, objMaterials, objMaterialCount);
   4410     else model.materials[0] = LoadMaterialDefault(); // Set default material for the mesh
   4411 
   4412     tinyobj_attrib_free(&objAttributes);
   4413     tinyobj_shapes_free(objShapes, objShapeCount);
   4414     tinyobj_materials_free(objMaterials, objMaterialCount);
   4415 
   4416     for (int i = 0; i < model.meshCount; i++)
   4417         UploadMesh(model.meshes + i, true);
   4418 
   4419     // Restore current working directory
   4420     if (CHDIR(currentDir) != 0)
   4421     {
   4422         TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", currentDir);
   4423     }
   4424 
   4425     return model;
   4426 }
   4427 #endif
   4428 
   4429 #if defined(SUPPORT_FILEFORMAT_IQM)
   4430 // Load IQM mesh data
   4431 static Model LoadIQM(const char *fileName)
   4432 {
   4433     #define IQM_MAGIC     "INTERQUAKEMODEL" // IQM file magic number
   4434     #define IQM_VERSION          2          // only IQM version 2 supported
   4435 
   4436     #define BONE_NAME_LENGTH    32          // BoneInfo name string length
   4437     #define MESH_NAME_LENGTH    32          // Mesh name string length
   4438     #define MATERIAL_NAME_LENGTH 32         // Material name string length
   4439 
   4440     int dataSize = 0;
   4441     unsigned char *fileData = LoadFileData(fileName, &dataSize);
   4442     unsigned char *fileDataPtr = fileData;
   4443 
   4444     // IQM file structs
   4445     //-----------------------------------------------------------------------------------
   4446     typedef struct IQMHeader {
   4447         char magic[16];
   4448         unsigned int version;
   4449         unsigned int dataSize;
   4450         unsigned int flags;
   4451         unsigned int num_text, ofs_text;
   4452         unsigned int num_meshes, ofs_meshes;
   4453         unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
   4454         unsigned int num_triangles, ofs_triangles, ofs_adjacency;
   4455         unsigned int num_joints, ofs_joints;
   4456         unsigned int num_poses, ofs_poses;
   4457         unsigned int num_anims, ofs_anims;
   4458         unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
   4459         unsigned int num_comment, ofs_comment;
   4460         unsigned int num_extensions, ofs_extensions;
   4461     } IQMHeader;
   4462 
   4463     typedef struct IQMMesh {
   4464         unsigned int name;
   4465         unsigned int material;
   4466         unsigned int first_vertex, num_vertexes;
   4467         unsigned int first_triangle, num_triangles;
   4468     } IQMMesh;
   4469 
   4470     typedef struct IQMTriangle {
   4471         unsigned int vertex[3];
   4472     } IQMTriangle;
   4473 
   4474     typedef struct IQMJoint {
   4475         unsigned int name;
   4476         int parent;
   4477         float translate[3], rotate[4], scale[3];
   4478     } IQMJoint;
   4479 
   4480     typedef struct IQMVertexArray {
   4481         unsigned int type;
   4482         unsigned int flags;
   4483         unsigned int format;
   4484         unsigned int size;
   4485         unsigned int offset;
   4486     } IQMVertexArray;
   4487 
   4488     // NOTE: Below IQM structures are not used but listed for reference
   4489     /*
   4490     typedef struct IQMAdjacency {
   4491         unsigned int triangle[3];
   4492     } IQMAdjacency;
   4493 
   4494     typedef struct IQMPose {
   4495         int parent;
   4496         unsigned int mask;
   4497         float channeloffset[10];
   4498         float channelscale[10];
   4499     } IQMPose;
   4500 
   4501     typedef struct IQMAnim {
   4502         unsigned int name;
   4503         unsigned int first_frame, num_frames;
   4504         float framerate;
   4505         unsigned int flags;
   4506     } IQMAnim;
   4507 
   4508     typedef struct IQMBounds {
   4509         float bbmin[3], bbmax[3];
   4510         float xyradius, radius;
   4511     } IQMBounds;
   4512     */
   4513     //-----------------------------------------------------------------------------------
   4514 
   4515     // IQM vertex data types
   4516     enum {
   4517         IQM_POSITION     = 0,
   4518         IQM_TEXCOORD     = 1,
   4519         IQM_NORMAL       = 2,
   4520         IQM_TANGENT      = 3,       // NOTE: Tangents unused by default
   4521         IQM_BLENDINDEXES = 4,
   4522         IQM_BLENDWEIGHTS = 5,
   4523         IQM_COLOR        = 6,
   4524         IQM_CUSTOM       = 0x10     // NOTE: Custom vertex values unused by default
   4525     };
   4526 
   4527     Model model = { 0 };
   4528 
   4529     IQMMesh *imesh = NULL;
   4530     IQMTriangle *tri = NULL;
   4531     IQMVertexArray *va = NULL;
   4532     IQMJoint *ijoint = NULL;
   4533 
   4534     float *vertex = NULL;
   4535     float *normal = NULL;
   4536     float *text = NULL;
   4537     char *blendi = NULL;
   4538     unsigned char *blendw = NULL;
   4539     unsigned char *color = NULL;
   4540 
   4541     // In case file can not be read, return an empty model
   4542     if (fileDataPtr == NULL) return model;
   4543 
   4544     const char *basePath = GetDirectoryPath(fileName);
   4545 
   4546     // Read IQM header
   4547     IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr;
   4548 
   4549     if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0)
   4550     {
   4551         TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
   4552         return model;
   4553     }
   4554 
   4555     if (iqmHeader->version != IQM_VERSION)
   4556     {
   4557         TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version);
   4558         return model;
   4559     }
   4560 
   4561     //fileDataPtr += sizeof(IQMHeader);       // Move file data pointer
   4562 
   4563     // Meshes data processing
   4564     imesh = RL_MALLOC(iqmHeader->num_meshes*sizeof(IQMMesh));
   4565     //fseek(iqmFile, iqmHeader->ofs_meshes, SEEK_SET);
   4566     //fread(imesh, sizeof(IQMMesh)*iqmHeader->num_meshes, 1, iqmFile);
   4567     memcpy(imesh, fileDataPtr + iqmHeader->ofs_meshes, iqmHeader->num_meshes*sizeof(IQMMesh));
   4568 
   4569     model.meshCount = iqmHeader->num_meshes;
   4570     model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
   4571 
   4572     model.materialCount = model.meshCount;
   4573     model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
   4574     model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
   4575 
   4576     char name[MESH_NAME_LENGTH] = { 0 };
   4577     char material[MATERIAL_NAME_LENGTH] = { 0 };
   4578 
   4579     for (int i = 0; i < model.meshCount; i++)
   4580     {
   4581         //fseek(iqmFile, iqmHeader->ofs_text + imesh[i].name, SEEK_SET);
   4582         //fread(name, sizeof(char), MESH_NAME_LENGTH, iqmFile);
   4583         memcpy(name, fileDataPtr + iqmHeader->ofs_text + imesh[i].name, MESH_NAME_LENGTH*sizeof(char));
   4584 
   4585         //fseek(iqmFile, iqmHeader->ofs_text + imesh[i].material, SEEK_SET);
   4586         //fread(material, sizeof(char), MATERIAL_NAME_LENGTH, iqmFile);
   4587         memcpy(material, fileDataPtr + iqmHeader->ofs_text + imesh[i].material, MATERIAL_NAME_LENGTH*sizeof(char));
   4588 
   4589         model.materials[i] = LoadMaterialDefault();
   4590         model.materials[i].maps[MATERIAL_MAP_ALBEDO].texture = LoadTexture(TextFormat("%s/%s", basePath, material));
   4591 
   4592         model.meshMaterial[i] = i;
   4593 
   4594         TRACELOG(LOG_DEBUG, "MODEL: [%s] mesh name (%s), material (%s)", fileName, name, material);
   4595 
   4596         model.meshes[i].vertexCount = imesh[i].num_vertexes;
   4597 
   4598         model.meshes[i].vertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));       // Default vertex positions
   4599         model.meshes[i].normals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));        // Default vertex normals
   4600         model.meshes[i].texcoords = RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float));      // Default vertex texcoords
   4601 
   4602         model.meshes[i].boneIds = RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(unsigned char));  // Up-to 4 bones supported!
   4603         model.meshes[i].boneWeights = RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float));      // Up-to 4 bones supported!
   4604 
   4605         model.meshes[i].triangleCount = imesh[i].num_triangles;
   4606         model.meshes[i].indices = RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short));
   4607 
   4608         // Animated vertex data, what we actually process for rendering
   4609         // NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning)
   4610         model.meshes[i].animVertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
   4611         model.meshes[i].animNormals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
   4612     }
   4613 
   4614     // Triangles data processing
   4615     tri = RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle));
   4616     //fseek(iqmFile, iqmHeader->ofs_triangles, SEEK_SET);
   4617     //fread(tri, sizeof(IQMTriangle), iqmHeader->num_triangles, iqmFile);
   4618     memcpy(tri, fileDataPtr + iqmHeader->ofs_triangles, iqmHeader->num_triangles*sizeof(IQMTriangle));
   4619 
   4620     for (int m = 0; m < model.meshCount; m++)
   4621     {
   4622         int tcounter = 0;
   4623 
   4624         for (unsigned int i = imesh[m].first_triangle; i < (imesh[m].first_triangle + imesh[m].num_triangles); i++)
   4625         {
   4626             // IQM triangles indexes are stored in counter-clockwise, but raylib processes the index in linear order,
   4627             // expecting they point to the counter-clockwise vertex triangle, so we need to reverse triangle indexes
   4628             // NOTE: raylib renders vertex data in counter-clockwise order (standard convention) by default
   4629             model.meshes[m].indices[tcounter + 2] = tri[i].vertex[0] - imesh[m].first_vertex;
   4630             model.meshes[m].indices[tcounter + 1] = tri[i].vertex[1] - imesh[m].first_vertex;
   4631             model.meshes[m].indices[tcounter] = tri[i].vertex[2] - imesh[m].first_vertex;
   4632             tcounter += 3;
   4633         }
   4634     }
   4635 
   4636     // Vertex arrays data processing
   4637     va = RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
   4638     //fseek(iqmFile, iqmHeader->ofs_vertexarrays, SEEK_SET);
   4639     //fread(va, sizeof(IQMVertexArray), iqmHeader->num_vertexarrays, iqmFile);
   4640     memcpy(va, fileDataPtr + iqmHeader->ofs_vertexarrays, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
   4641 
   4642     for (unsigned int i = 0; i < iqmHeader->num_vertexarrays; i++)
   4643     {
   4644         switch (va[i].type)
   4645         {
   4646             case IQM_POSITION:
   4647             {
   4648                 vertex = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
   4649                 //fseek(iqmFile, va[i].offset, SEEK_SET);
   4650                 //fread(vertex, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
   4651                 memcpy(vertex, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
   4652 
   4653                 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
   4654                 {
   4655                     int vCounter = 0;
   4656                     for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
   4657                     {
   4658                         model.meshes[m].vertices[vCounter] = vertex[i];
   4659                         model.meshes[m].animVertices[vCounter] = vertex[i];
   4660                         vCounter++;
   4661                     }
   4662                 }
   4663             } break;
   4664             case IQM_NORMAL:
   4665             {
   4666                 normal = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
   4667                 //fseek(iqmFile, va[i].offset, SEEK_SET);
   4668                 //fread(normal, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
   4669                 memcpy(normal, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
   4670 
   4671                 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
   4672                 {
   4673                     int vCounter = 0;
   4674                     for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
   4675                     {
   4676                         model.meshes[m].normals[vCounter] = normal[i];
   4677                         model.meshes[m].animNormals[vCounter] = normal[i];
   4678                         vCounter++;
   4679                     }
   4680                 }
   4681             } break;
   4682             case IQM_TEXCOORD:
   4683             {
   4684                 text = RL_MALLOC(iqmHeader->num_vertexes*2*sizeof(float));
   4685                 //fseek(iqmFile, va[i].offset, SEEK_SET);
   4686                 //fread(text, iqmHeader->num_vertexes*2*sizeof(float), 1, iqmFile);
   4687                 memcpy(text, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*2*sizeof(float));
   4688 
   4689                 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
   4690                 {
   4691                     int vCounter = 0;
   4692                     for (unsigned int i = imesh[m].first_vertex*2; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*2; i++)
   4693                     {
   4694                         model.meshes[m].texcoords[vCounter] = text[i];
   4695                         vCounter++;
   4696                     }
   4697                 }
   4698             } break;
   4699             case IQM_BLENDINDEXES:
   4700             {
   4701                 blendi = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(char));
   4702                 //fseek(iqmFile, va[i].offset, SEEK_SET);
   4703                 //fread(blendi, iqmHeader->num_vertexes*4*sizeof(char), 1, iqmFile);
   4704                 memcpy(blendi, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(char));
   4705 
   4706                 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
   4707                 {
   4708                     int boneCounter = 0;
   4709                     for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
   4710                     {
   4711                         model.meshes[m].boneIds[boneCounter] = blendi[i];
   4712                         boneCounter++;
   4713                     }
   4714                 }
   4715             } break;
   4716             case IQM_BLENDWEIGHTS:
   4717             {
   4718                 blendw = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
   4719                 //fseek(iqmFile, va[i].offset, SEEK_SET);
   4720                 //fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
   4721                 memcpy(blendw, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
   4722 
   4723                 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
   4724                 {
   4725                     int boneCounter = 0;
   4726                     for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
   4727                     {
   4728                         model.meshes[m].boneWeights[boneCounter] = blendw[i]/255.0f;
   4729                         boneCounter++;
   4730                     }
   4731                 }
   4732             } break;
   4733             case IQM_COLOR:
   4734             {
   4735                 color = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
   4736                 //fseek(iqmFile, va[i].offset, SEEK_SET);
   4737                 //fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
   4738                 memcpy(color, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
   4739 
   4740                 for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
   4741                 {
   4742                     model.meshes[m].colors = RL_CALLOC(model.meshes[m].vertexCount*4, sizeof(unsigned char));
   4743 
   4744                     int vCounter = 0;
   4745                     for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
   4746                     {
   4747                         model.meshes[m].colors[vCounter] = color[i];
   4748                         vCounter++;
   4749                     }
   4750                 }
   4751             } break;
   4752         }
   4753     }
   4754 
   4755     // Bones (joints) data processing
   4756     ijoint = RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
   4757     //fseek(iqmFile, iqmHeader->ofs_joints, SEEK_SET);
   4758     //fread(ijoint, sizeof(IQMJoint), iqmHeader->num_joints, iqmFile);
   4759     memcpy(ijoint, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
   4760 
   4761     model.boneCount = iqmHeader->num_joints;
   4762     model.bones = RL_MALLOC(iqmHeader->num_joints*sizeof(BoneInfo));
   4763     model.bindPose = RL_MALLOC(iqmHeader->num_joints*sizeof(Transform));
   4764 
   4765     for (unsigned int i = 0; i < iqmHeader->num_joints; i++)
   4766     {
   4767         // Bones
   4768         model.bones[i].parent = ijoint[i].parent;
   4769         //fseek(iqmFile, iqmHeader->ofs_text + ijoint[i].name, SEEK_SET);
   4770         //fread(model.bones[i].name, sizeof(char), BONE_NAME_LENGTH, iqmFile);
   4771         memcpy(model.bones[i].name, fileDataPtr + iqmHeader->ofs_text + ijoint[i].name, BONE_NAME_LENGTH*sizeof(char));
   4772 
   4773         // Bind pose (base pose)
   4774         model.bindPose[i].translation.x = ijoint[i].translate[0];
   4775         model.bindPose[i].translation.y = ijoint[i].translate[1];
   4776         model.bindPose[i].translation.z = ijoint[i].translate[2];
   4777 
   4778         model.bindPose[i].rotation.x = ijoint[i].rotate[0];
   4779         model.bindPose[i].rotation.y = ijoint[i].rotate[1];
   4780         model.bindPose[i].rotation.z = ijoint[i].rotate[2];
   4781         model.bindPose[i].rotation.w = ijoint[i].rotate[3];
   4782 
   4783         model.bindPose[i].scale.x = ijoint[i].scale[0];
   4784         model.bindPose[i].scale.y = ijoint[i].scale[1];
   4785         model.bindPose[i].scale.z = ijoint[i].scale[2];
   4786     }
   4787 
   4788     BuildPoseFromParentJoints(model.bones, model.boneCount, model.bindPose);
   4789 
   4790     for (int i = 0; i < model.meshCount; i++)
   4791     {
   4792         model.meshes[i].boneCount = model.boneCount;
   4793         model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
   4794 
   4795         for (int j = 0; j < model.meshes[i].boneCount; j++)
   4796         {
   4797             model.meshes[i].boneMatrices[j] = MatrixIdentity();
   4798         }
   4799     }
   4800 
   4801     UnloadFileData(fileData);
   4802 
   4803     RL_FREE(imesh);
   4804     RL_FREE(tri);
   4805     RL_FREE(va);
   4806     RL_FREE(vertex);
   4807     RL_FREE(normal);
   4808     RL_FREE(text);
   4809     RL_FREE(blendi);
   4810     RL_FREE(blendw);
   4811     RL_FREE(ijoint);
   4812     RL_FREE(color);
   4813 
   4814     return model;
   4815 }
   4816 
   4817 // Load IQM animation data
   4818 static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCount)
   4819 {
   4820     #define IQM_MAGIC       "INTERQUAKEMODEL"   // IQM file magic number
   4821     #define IQM_VERSION     2                   // only IQM version 2 supported
   4822 
   4823     int dataSize = 0;
   4824     unsigned char *fileData = LoadFileData(fileName, &dataSize);
   4825     unsigned char *fileDataPtr = fileData;
   4826 
   4827     typedef struct IQMHeader {
   4828         char magic[16];
   4829         unsigned int version;
   4830         unsigned int dataSize;
   4831         unsigned int flags;
   4832         unsigned int num_text, ofs_text;
   4833         unsigned int num_meshes, ofs_meshes;
   4834         unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
   4835         unsigned int num_triangles, ofs_triangles, ofs_adjacency;
   4836         unsigned int num_joints, ofs_joints;
   4837         unsigned int num_poses, ofs_poses;
   4838         unsigned int num_anims, ofs_anims;
   4839         unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
   4840         unsigned int num_comment, ofs_comment;
   4841         unsigned int num_extensions, ofs_extensions;
   4842     } IQMHeader;
   4843 
   4844     typedef struct IQMJoint {
   4845         unsigned int name;
   4846         int parent;
   4847         float translate[3], rotate[4], scale[3];
   4848     } IQMJoint;
   4849 
   4850     typedef struct IQMPose {
   4851         int parent;
   4852         unsigned int mask;
   4853         float channeloffset[10];
   4854         float channelscale[10];
   4855     } IQMPose;
   4856 
   4857     typedef struct IQMAnim {
   4858         unsigned int name;
   4859         unsigned int first_frame, num_frames;
   4860         float framerate;
   4861         unsigned int flags;
   4862     } IQMAnim;
   4863 
   4864     // In case file can not be read, return an empty model
   4865     if (fileDataPtr == NULL) return NULL;
   4866 
   4867     // Read IQM header
   4868     IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr;
   4869 
   4870     if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0)
   4871     {
   4872         TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
   4873         return NULL;
   4874     }
   4875 
   4876     if (iqmHeader->version != IQM_VERSION)
   4877     {
   4878         TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version);
   4879         return NULL;
   4880     }
   4881 
   4882     // Get bones data
   4883     IQMPose *poses = RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose));
   4884     //fseek(iqmFile, iqmHeader->ofs_poses, SEEK_SET);
   4885     //fread(poses, sizeof(IQMPose), iqmHeader->num_poses, iqmFile);
   4886     memcpy(poses, fileDataPtr + iqmHeader->ofs_poses, iqmHeader->num_poses*sizeof(IQMPose));
   4887 
   4888     // Get animations data
   4889     *animCount = iqmHeader->num_anims;
   4890     IQMAnim *anim = RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim));
   4891     //fseek(iqmFile, iqmHeader->ofs_anims, SEEK_SET);
   4892     //fread(anim, sizeof(IQMAnim), iqmHeader->num_anims, iqmFile);
   4893     memcpy(anim, fileDataPtr + iqmHeader->ofs_anims, iqmHeader->num_anims*sizeof(IQMAnim));
   4894 
   4895     ModelAnimation *animations = RL_MALLOC(iqmHeader->num_anims*sizeof(ModelAnimation));
   4896 
   4897     // frameposes
   4898     unsigned short *framedata = RL_MALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
   4899     //fseek(iqmFile, iqmHeader->ofs_frames, SEEK_SET);
   4900     //fread(framedata, sizeof(unsigned short), iqmHeader->num_frames*iqmHeader->num_framechannels, iqmFile);
   4901     memcpy(framedata, fileDataPtr + iqmHeader->ofs_frames, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
   4902 
   4903     // joints
   4904     IQMJoint *joints = RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
   4905     memcpy(joints, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
   4906 
   4907     for (unsigned int a = 0; a < iqmHeader->num_anims; a++)
   4908     {
   4909         animations[a].frameCount = anim[a].num_frames;
   4910         animations[a].boneCount = iqmHeader->num_poses;
   4911         animations[a].bones = RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo));
   4912         animations[a].framePoses = RL_MALLOC(anim[a].num_frames*sizeof(Transform *));
   4913         memcpy(animations[a].name, fileDataPtr + iqmHeader->ofs_text + anim[a].name, 32);   //  I don't like this 32 here
   4914         TraceLog(LOG_INFO, "IQM Anim %s", animations[a].name);
   4915         // animations[a].framerate = anim.framerate;     // TODO: Use animation framerate data?
   4916 
   4917         for (unsigned int j = 0; j < iqmHeader->num_poses; j++)
   4918         {
   4919             // If animations and skeleton are in the same file, copy bone names to anim
   4920             if (iqmHeader->num_joints > 0)
   4921                 memcpy(animations[a].bones[j].name, fileDataPtr + iqmHeader->ofs_text + joints[j].name, BONE_NAME_LENGTH*sizeof(char));
   4922             else
   4923                 strcpy(animations[a].bones[j].name, "ANIMJOINTNAME"); // default bone name otherwise
   4924             animations[a].bones[j].parent = poses[j].parent;
   4925         }
   4926 
   4927         for (unsigned int j = 0; j < anim[a].num_frames; j++) animations[a].framePoses[j] = RL_MALLOC(iqmHeader->num_poses*sizeof(Transform));
   4928 
   4929         int dcounter = anim[a].first_frame*iqmHeader->num_framechannels;
   4930 
   4931         for (unsigned int frame = 0; frame < anim[a].num_frames; frame++)
   4932         {
   4933             for (unsigned int i = 0; i < iqmHeader->num_poses; i++)
   4934             {
   4935                 animations[a].framePoses[frame][i].translation.x = poses[i].channeloffset[0];
   4936 
   4937                 if (poses[i].mask & 0x01)
   4938                 {
   4939                     animations[a].framePoses[frame][i].translation.x += framedata[dcounter]*poses[i].channelscale[0];
   4940                     dcounter++;
   4941                 }
   4942 
   4943                 animations[a].framePoses[frame][i].translation.y = poses[i].channeloffset[1];
   4944 
   4945                 if (poses[i].mask & 0x02)
   4946                 {
   4947                     animations[a].framePoses[frame][i].translation.y += framedata[dcounter]*poses[i].channelscale[1];
   4948                     dcounter++;
   4949                 }
   4950 
   4951                 animations[a].framePoses[frame][i].translation.z = poses[i].channeloffset[2];
   4952 
   4953                 if (poses[i].mask & 0x04)
   4954                 {
   4955                     animations[a].framePoses[frame][i].translation.z += framedata[dcounter]*poses[i].channelscale[2];
   4956                     dcounter++;
   4957                 }
   4958 
   4959                 animations[a].framePoses[frame][i].rotation.x = poses[i].channeloffset[3];
   4960 
   4961                 if (poses[i].mask & 0x08)
   4962                 {
   4963                     animations[a].framePoses[frame][i].rotation.x += framedata[dcounter]*poses[i].channelscale[3];
   4964                     dcounter++;
   4965                 }
   4966 
   4967                 animations[a].framePoses[frame][i].rotation.y = poses[i].channeloffset[4];
   4968 
   4969                 if (poses[i].mask & 0x10)
   4970                 {
   4971                     animations[a].framePoses[frame][i].rotation.y += framedata[dcounter]*poses[i].channelscale[4];
   4972                     dcounter++;
   4973                 }
   4974 
   4975                 animations[a].framePoses[frame][i].rotation.z = poses[i].channeloffset[5];
   4976 
   4977                 if (poses[i].mask & 0x20)
   4978                 {
   4979                     animations[a].framePoses[frame][i].rotation.z += framedata[dcounter]*poses[i].channelscale[5];
   4980                     dcounter++;
   4981                 }
   4982 
   4983                 animations[a].framePoses[frame][i].rotation.w = poses[i].channeloffset[6];
   4984 
   4985                 if (poses[i].mask & 0x40)
   4986                 {
   4987                     animations[a].framePoses[frame][i].rotation.w += framedata[dcounter]*poses[i].channelscale[6];
   4988                     dcounter++;
   4989                 }
   4990 
   4991                 animations[a].framePoses[frame][i].scale.x = poses[i].channeloffset[7];
   4992 
   4993                 if (poses[i].mask & 0x80)
   4994                 {
   4995                     animations[a].framePoses[frame][i].scale.x += framedata[dcounter]*poses[i].channelscale[7];
   4996                     dcounter++;
   4997                 }
   4998 
   4999                 animations[a].framePoses[frame][i].scale.y = poses[i].channeloffset[8];
   5000 
   5001                 if (poses[i].mask & 0x100)
   5002                 {
   5003                     animations[a].framePoses[frame][i].scale.y += framedata[dcounter]*poses[i].channelscale[8];
   5004                     dcounter++;
   5005                 }
   5006 
   5007                 animations[a].framePoses[frame][i].scale.z = poses[i].channeloffset[9];
   5008 
   5009                 if (poses[i].mask & 0x200)
   5010                 {
   5011                     animations[a].framePoses[frame][i].scale.z += framedata[dcounter]*poses[i].channelscale[9];
   5012                     dcounter++;
   5013                 }
   5014 
   5015                 animations[a].framePoses[frame][i].rotation = QuaternionNormalize(animations[a].framePoses[frame][i].rotation);
   5016             }
   5017         }
   5018 
   5019         // Build frameposes
   5020         for (unsigned int frame = 0; frame < anim[a].num_frames; frame++)
   5021         {
   5022             for (int i = 0; i < animations[a].boneCount; i++)
   5023             {
   5024                 if (animations[a].bones[i].parent >= 0)
   5025                 {
   5026                     animations[a].framePoses[frame][i].rotation = QuaternionMultiply(animations[a].framePoses[frame][animations[a].bones[i].parent].rotation, animations[a].framePoses[frame][i].rotation);
   5027                     animations[a].framePoses[frame][i].translation = Vector3RotateByQuaternion(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].rotation);
   5028                     animations[a].framePoses[frame][i].translation = Vector3Add(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].translation);
   5029                     animations[a].framePoses[frame][i].scale = Vector3Multiply(animations[a].framePoses[frame][i].scale, animations[a].framePoses[frame][animations[a].bones[i].parent].scale);
   5030                 }
   5031             }
   5032         }
   5033     }
   5034 
   5035     UnloadFileData(fileData);
   5036 
   5037     RL_FREE(joints);
   5038     RL_FREE(framedata);
   5039     RL_FREE(poses);
   5040     RL_FREE(anim);
   5041 
   5042     return animations;
   5043 }
   5044 
   5045 #endif
   5046 
   5047 #if defined(SUPPORT_FILEFORMAT_GLTF)
   5048 // Load file data callback for cgltf
   5049 static cgltf_result LoadFileGLTFCallback(const struct cgltf_memory_options *memoryOptions, const struct cgltf_file_options *fileOptions, const char *path, cgltf_size *size, void **data)
   5050 {
   5051     int filesize;
   5052     unsigned char *filedata = LoadFileData(path, &filesize);
   5053 
   5054     if (filedata == NULL) return cgltf_result_io_error;
   5055 
   5056     *size = filesize;
   5057     *data = filedata;
   5058 
   5059     return cgltf_result_success;
   5060 }
   5061 
   5062 // Release file data callback for cgltf
   5063 static void ReleaseFileGLTFCallback(const struct cgltf_memory_options *memoryOptions, const struct cgltf_file_options *fileOptions, void *data)
   5064 {
   5065     UnloadFileData(data);
   5066 }
   5067 
   5068 // Load image from different glTF provided methods (uri, path, buffer_view)
   5069 static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPath)
   5070 {
   5071     Image image = { 0 };
   5072 
   5073     if (cgltfImage->uri != NULL)     // Check if image data is provided as an uri (base64 or path)
   5074     {
   5075         if ((strlen(cgltfImage->uri) > 5) &&
   5076             (cgltfImage->uri[0] == 'd') &&
   5077             (cgltfImage->uri[1] == 'a') &&
   5078             (cgltfImage->uri[2] == 't') &&
   5079             (cgltfImage->uri[3] == 'a') &&
   5080             (cgltfImage->uri[4] == ':'))     // Check if image is provided as base64 text data
   5081         {
   5082             // Data URI Format: data:<mediatype>;base64,<data>
   5083 
   5084             // Find the comma
   5085             int i = 0;
   5086             while ((cgltfImage->uri[i] != ',') && (cgltfImage->uri[i] != 0)) i++;
   5087 
   5088             if (cgltfImage->uri[i] == 0) TRACELOG(LOG_WARNING, "IMAGE: glTF data URI is not a valid image");
   5089             else
   5090             {
   5091                 int base64Size = (int)strlen(cgltfImage->uri + i + 1);
   5092                 while (cgltfImage->uri[i + base64Size] == '=') base64Size--;    // Ignore optional paddings
   5093                 int numberOfEncodedBits = base64Size*6 - (base64Size*6) % 8 ;   // Encoded bits minus extra bits, so it becomes a multiple of 8 bits
   5094                 int outSize = numberOfEncodedBits/8 ;                           // Actual encoded bytes
   5095                 void *data = NULL;
   5096 
   5097                 cgltf_options options = { 0 };
   5098                 options.file.read = LoadFileGLTFCallback;
   5099                 options.file.release = ReleaseFileGLTFCallback;
   5100                 cgltf_result result = cgltf_load_buffer_base64(&options, outSize, cgltfImage->uri + i + 1, &data);
   5101 
   5102                 if (result == cgltf_result_success)
   5103                 {
   5104                     image = LoadImageFromMemory(".png", (unsigned char *)data, outSize);
   5105                     RL_FREE(data);
   5106                 }
   5107             }
   5108         }
   5109         else     // Check if image is provided as image path
   5110         {
   5111             image = LoadImage(TextFormat("%s/%s", texPath, cgltfImage->uri));
   5112         }
   5113     }
   5114     else if (cgltfImage->buffer_view->buffer->data != NULL)    // Check if image is provided as data buffer
   5115     {
   5116         unsigned char *data = RL_MALLOC(cgltfImage->buffer_view->size);
   5117         int offset = (int)cgltfImage->buffer_view->offset;
   5118         int stride = (int)cgltfImage->buffer_view->stride? (int)cgltfImage->buffer_view->stride : 1;
   5119 
   5120         // Copy buffer data to memory for loading
   5121         for (unsigned int i = 0; i < cgltfImage->buffer_view->size; i++)
   5122         {
   5123             data[i] = ((unsigned char *)cgltfImage->buffer_view->buffer->data)[offset];
   5124             offset += stride;
   5125         }
   5126 
   5127         // Check mime_type for image: (cgltfImage->mime_type == "image/png")
   5128         // NOTE: Detected that some models define mime_type as "image\\/png"
   5129         if ((strcmp(cgltfImage->mime_type, "image\\/png") == 0) ||
   5130             (strcmp(cgltfImage->mime_type, "image/png") == 0)) image = LoadImageFromMemory(".png", data, (int)cgltfImage->buffer_view->size);
   5131         else if ((strcmp(cgltfImage->mime_type, "image\\/jpeg") == 0) ||
   5132                  (strcmp(cgltfImage->mime_type, "image/jpeg") == 0)) image = LoadImageFromMemory(".jpg", data, (int)cgltfImage->buffer_view->size);
   5133         else TRACELOG(LOG_WARNING, "MODEL: glTF image data MIME type not recognized", TextFormat("%s/%s", texPath, cgltfImage->uri));
   5134 
   5135         RL_FREE(data);
   5136     }
   5137 
   5138     return image;
   5139 }
   5140 
   5141 // Load bone info from GLTF skin data
   5142 static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, int *boneCount)
   5143 {
   5144     *boneCount = (int)skin.joints_count;
   5145     BoneInfo *bones = RL_MALLOC(skin.joints_count*sizeof(BoneInfo));
   5146 
   5147     for (unsigned int i = 0; i < skin.joints_count; i++)
   5148     {
   5149         cgltf_node node = *skin.joints[i];
   5150         if (node.name != NULL)
   5151         {
   5152             strncpy(bones[i].name, node.name, sizeof(bones[i].name));
   5153             bones[i].name[sizeof(bones[i].name) - 1] = '\0';
   5154         }
   5155 
   5156         // Find parent bone index
   5157         int parentIndex = -1;
   5158 
   5159         for (unsigned int j = 0; j < skin.joints_count; j++)
   5160         {
   5161             if (skin.joints[j] == node.parent)
   5162             {
   5163                 parentIndex = (int)j;
   5164                 break;
   5165             }
   5166         }
   5167 
   5168         bones[i].parent = parentIndex;
   5169     }
   5170 
   5171     return bones;
   5172 }
   5173 
   5174 // Load glTF file into model struct, .gltf and .glb supported
   5175 static Model LoadGLTF(const char *fileName)
   5176 {
   5177     /*********************************************************************************************
   5178 
   5179         Function implemented by Wilhem Barbier(@wbrbr), with modifications by Tyler Bezera(@gamerfiend)
   5180         Transform handling implemented by Paul Melis (@paulmelis).
   5181         Reviewed by Ramon Santamaria (@raysan5)
   5182 
   5183         FEATURES:
   5184           - Supports .gltf and .glb files
   5185           - Supports embedded (base64) or external textures
   5186           - Supports PBR metallic/roughness flow, loads material textures, values and colors
   5187                      PBR specular/glossiness flow and extended texture flows not supported
   5188           - Supports multiple meshes per model (every primitives is loaded as a separate mesh)
   5189           - Supports basic animations
   5190           - Transforms, including parent-child relations, are applied on the mesh data, but the
   5191             hierarchy is not kept (as it can't be represented).
   5192           - Mesh instances in the glTF file (i.e. same mesh linked from multiple nodes)
   5193             are turned into separate raylib Meshes.
   5194 
   5195         RESTRICTIONS:
   5196           - Only triangle meshes supported
   5197           - Vertex attribute types and formats supported:
   5198               > Vertices (position): vec3: float
   5199               > Normals: vec3: float
   5200               > Texcoords: vec2: float
   5201               > Colors: vec4: u8, u16, f32 (normalized)
   5202               > Indices: u16, u32 (truncated to u16)
   5203           - Scenes defined in the glTF file are ignored. All nodes in the file
   5204             are used.
   5205 
   5206     ***********************************************************************************************/
   5207 
   5208     // Macro to simplify attributes loading code
   5209     #define LOAD_ATTRIBUTE(accesor, numComp, srcType, dstPtr) LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, srcType)
   5210 
   5211     #define LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, dstType) \
   5212     { \
   5213         int n = 0; \
   5214         srcType *buffer = (srcType *)accesor->buffer_view->buffer->data + accesor->buffer_view->offset/sizeof(srcType) + accesor->offset/sizeof(srcType); \
   5215         for (unsigned int k = 0; k < accesor->count; k++) \
   5216         {\
   5217             for (int l = 0; l < numComp; l++) \
   5218             {\
   5219                 dstPtr[numComp*k + l] = (dstType)buffer[n + l];\
   5220             }\
   5221             n += (int)(accesor->stride/sizeof(srcType));\
   5222         }\
   5223     }
   5224 
   5225     Model model = { 0 };
   5226 
   5227     // glTF file loading
   5228     int dataSize = 0;
   5229     unsigned char *fileData = LoadFileData(fileName, &dataSize);
   5230 
   5231     if (fileData == NULL) return model;
   5232 
   5233     // glTF data loading
   5234     cgltf_options options = { 0 };
   5235     options.file.read = LoadFileGLTFCallback;
   5236     options.file.release = ReleaseFileGLTFCallback;
   5237     cgltf_data *data = NULL;
   5238     cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data);
   5239 
   5240     if (result == cgltf_result_success)
   5241     {
   5242         if (data->file_type == cgltf_file_type_glb) TRACELOG(LOG_INFO, "MODEL: [%s] Model basic data (glb) loaded successfully", fileName);
   5243         else if (data->file_type == cgltf_file_type_gltf) TRACELOG(LOG_INFO, "MODEL: [%s] Model basic data (glTF) loaded successfully", fileName);
   5244         else TRACELOG(LOG_WARNING, "MODEL: [%s] Model format not recognized", fileName);
   5245 
   5246         TRACELOG(LOG_INFO, "    > Meshes count: %i", data->meshes_count);
   5247         TRACELOG(LOG_INFO, "    > Materials count: %i (+1 default)", data->materials_count);
   5248         TRACELOG(LOG_DEBUG, "    > Buffers count: %i", data->buffers_count);
   5249         TRACELOG(LOG_DEBUG, "    > Images count: %i", data->images_count);
   5250         TRACELOG(LOG_DEBUG, "    > Textures count: %i", data->textures_count);
   5251 
   5252         // Force reading data buffers (fills buffer_view->buffer->data)
   5253         // NOTE: If an uri is defined to base64 data or external path, it's automatically loaded
   5254         result = cgltf_load_buffers(&options, data, fileName);
   5255         if (result != cgltf_result_success) TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load mesh/material buffers", fileName);
   5256 
   5257         int primitivesCount = 0;
   5258         // NOTE: We will load every primitive in the glTF as a separate raylib Mesh.
   5259         // Determine total number of meshes needed from the node hierarchy.
   5260         for (unsigned int i = 0; i < data->nodes_count; i++)
   5261         {
   5262             cgltf_node *node = &(data->nodes[i]);
   5263             cgltf_mesh *mesh = node->mesh;
   5264             if (!mesh)
   5265                 continue;
   5266 
   5267             for (unsigned int p = 0; p < mesh->primitives_count; p++)
   5268             {
   5269                 if (mesh->primitives[p].type == cgltf_primitive_type_triangles)
   5270                     primitivesCount++;
   5271             }
   5272         }
   5273         TRACELOG(LOG_DEBUG, "    > Primitives (triangles only) count based on hierarchy : %i", primitivesCount);
   5274 
   5275         // Load our model data: meshes and materials
   5276         model.meshCount = primitivesCount;
   5277         model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
   5278 
   5279         // NOTE: We keep an extra slot for default material, in case some mesh requires it
   5280         model.materialCount = (int)data->materials_count + 1;
   5281         model.materials = RL_CALLOC(model.materialCount, sizeof(Material));
   5282         model.materials[0] = LoadMaterialDefault();     // Load default material (index: 0)
   5283 
   5284         // Load mesh-material indices, by default all meshes are mapped to material index: 0
   5285         model.meshMaterial = RL_CALLOC(model.meshCount, sizeof(int));
   5286 
   5287         // Load materials data
   5288         //----------------------------------------------------------------------------------------------------
   5289         for (unsigned int i = 0, j = 1; i < data->materials_count; i++, j++)
   5290         {
   5291             model.materials[j] = LoadMaterialDefault();
   5292             const char *texPath = GetDirectoryPath(fileName);
   5293 
   5294             // Check glTF material flow: PBR metallic/roughness flow
   5295             // NOTE: Alternatively, materials can follow PBR specular/glossiness flow
   5296             if (data->materials[i].has_pbr_metallic_roughness)
   5297             {
   5298                 // Load base color texture (albedo)
   5299                 if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture)
   5300                 {
   5301                     Image imAlbedo = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath);
   5302                     if (imAlbedo.data != NULL)
   5303                     {
   5304                         model.materials[j].maps[MATERIAL_MAP_ALBEDO].texture = LoadTextureFromImage(imAlbedo);
   5305                         UnloadImage(imAlbedo);
   5306                     }
   5307                 }
   5308                 // Load base color factor (tint)
   5309                 model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255);
   5310                 model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255);
   5311                 model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255);
   5312                 model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255);
   5313 
   5314                 // Load metallic/roughness texture
   5315                 if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture)
   5316                 {
   5317                     Image imMetallicRoughness = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath);
   5318                     if (imMetallicRoughness.data != NULL)
   5319                     {
   5320                         model.materials[j].maps[MATERIAL_MAP_ROUGHNESS].texture = LoadTextureFromImage(imMetallicRoughness);
   5321                         UnloadImage(imMetallicRoughness);
   5322                     }
   5323 
   5324                     // Load metallic/roughness material properties
   5325                     float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor;
   5326                     model.materials[j].maps[MATERIAL_MAP_ROUGHNESS].value = roughness;
   5327 
   5328                     float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor;
   5329                     model.materials[j].maps[MATERIAL_MAP_METALNESS].value = metallic;
   5330                 }
   5331 
   5332                 // Load normal texture
   5333                 if (data->materials[i].normal_texture.texture)
   5334                 {
   5335                     Image imNormal = LoadImageFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath);
   5336                     if (imNormal.data != NULL)
   5337                     {
   5338                         model.materials[j].maps[MATERIAL_MAP_NORMAL].texture = LoadTextureFromImage(imNormal);
   5339                         UnloadImage(imNormal);
   5340                     }
   5341                 }
   5342 
   5343                 // Load ambient occlusion texture
   5344                 if (data->materials[i].occlusion_texture.texture)
   5345                 {
   5346                     Image imOcclusion = LoadImageFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath);
   5347                     if (imOcclusion.data != NULL)
   5348                     {
   5349                         model.materials[j].maps[MATERIAL_MAP_OCCLUSION].texture = LoadTextureFromImage(imOcclusion);
   5350                         UnloadImage(imOcclusion);
   5351                     }
   5352                 }
   5353 
   5354                 // Load emissive texture
   5355                 if (data->materials[i].emissive_texture.texture)
   5356                 {
   5357                     Image imEmissive = LoadImageFromCgltfImage(data->materials[i].emissive_texture.texture->image, texPath);
   5358                     if (imEmissive.data != NULL)
   5359                     {
   5360                         model.materials[j].maps[MATERIAL_MAP_EMISSION].texture = LoadTextureFromImage(imEmissive);
   5361                         UnloadImage(imEmissive);
   5362                     }
   5363 
   5364                     // Load emissive color factor
   5365                     model.materials[j].maps[MATERIAL_MAP_EMISSION].color.r = (unsigned char)(data->materials[i].emissive_factor[0]*255);
   5366                     model.materials[j].maps[MATERIAL_MAP_EMISSION].color.g = (unsigned char)(data->materials[i].emissive_factor[1]*255);
   5367                     model.materials[j].maps[MATERIAL_MAP_EMISSION].color.b = (unsigned char)(data->materials[i].emissive_factor[2]*255);
   5368                     model.materials[j].maps[MATERIAL_MAP_EMISSION].color.a = 255;
   5369                 }
   5370             }
   5371 
   5372             // Other possible materials not supported by raylib pipeline:
   5373             // has_clearcoat, has_transmission, has_volume, has_ior, has specular, has_sheen
   5374         }
   5375 
   5376         // Visit each node in the hierarchy and process any mesh linked from it.
   5377         // Each primitive within a glTF node becomes a Raylib Mesh.
   5378         // The local-to-world transform of each node is used to transform the
   5379         // points/normals/tangents of the created Mesh(es).
   5380         // Any glTF mesh linked from more than one Node (i.e. instancing)
   5381         // is turned into multiple Mesh's, as each Node will have its own
   5382         // transform applied.
   5383         // Note: the code below disregards the scenes defined in the file, all nodes are used.
   5384         //----------------------------------------------------------------------------------------------------
   5385         int meshIndex = 0;
   5386         for (unsigned int i = 0; i < data->nodes_count; i++)
   5387         {
   5388             cgltf_node *node = &(data->nodes[i]);
   5389 
   5390             cgltf_mesh *mesh = node->mesh;
   5391             if (!mesh)
   5392                 continue;
   5393 
   5394             cgltf_float worldTransform[16];
   5395             cgltf_node_transform_world(node, worldTransform);
   5396 
   5397             Matrix worldMatrix = {
   5398                 worldTransform[0], worldTransform[4], worldTransform[8], worldTransform[12],
   5399                 worldTransform[1], worldTransform[5], worldTransform[9], worldTransform[13],
   5400                 worldTransform[2], worldTransform[6], worldTransform[10], worldTransform[14],
   5401                 worldTransform[3], worldTransform[7], worldTransform[11], worldTransform[15]
   5402             };
   5403 
   5404             Matrix worldMatrixNormals = MatrixTranspose(MatrixInvert(worldMatrix));
   5405 
   5406             for (unsigned int p = 0; p < mesh->primitives_count; p++)
   5407             {
   5408                 // NOTE: We only support primitives defined by triangles
   5409                 // Other alternatives: points, lines, line_strip, triangle_strip
   5410                 if (mesh->primitives[p].type != cgltf_primitive_type_triangles) continue;
   5411 
   5412                 // NOTE: Attributes data could be provided in several data formats (8, 8u, 16u, 32...),
   5413                 // Only some formats for each attribute type are supported, read info at the top of this function!
   5414 
   5415                 for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++)
   5416                 {
   5417                     // Check the different attributes for every primitive
   5418                     if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_position)      // POSITION, vec3, float
   5419                     {
   5420                         cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
   5421 
   5422                         // WARNING: SPECS: POSITION accessor MUST have its min and max properties defined
   5423 
   5424                         if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_32f))
   5425                         {
   5426                             // Init raylib mesh vertices to copy glTF attribute data
   5427                             model.meshes[meshIndex].vertexCount = (int)attribute->count;
   5428                             model.meshes[meshIndex].vertices = RL_MALLOC(attribute->count*3*sizeof(float));
   5429 
   5430                             // Load 3 components of float data type into mesh.vertices
   5431                             LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].vertices)
   5432 
   5433                             // Transform the vertices
   5434                             float *vertices = model.meshes[meshIndex].vertices;
   5435                             for (unsigned int k = 0; k < attribute->count; k++)
   5436                             {
   5437                                 Vector3 vt = Vector3Transform((Vector3){ vertices[3*k], vertices[3*k+1], vertices[3*k+2] }, worldMatrix);
   5438                                 vertices[3*k] = vt.x;
   5439                                 vertices[3*k+1] = vt.y;
   5440                                 vertices[3*k+2] = vt.z;
   5441                             }
   5442                         }
   5443                         else TRACELOG(LOG_WARNING, "MODEL: [%s] Vertices attribute data format not supported, use vec3 float", fileName);
   5444                     }
   5445                     else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_normal)   // NORMAL, vec3, float
   5446                     {
   5447                         cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
   5448 
   5449                         if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_32f))
   5450                         {
   5451                             // Init raylib mesh normals to copy glTF attribute data
   5452                             model.meshes[meshIndex].normals = RL_MALLOC(attribute->count*3*sizeof(float));
   5453 
   5454                             // Load 3 components of float data type into mesh.normals
   5455                             LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].normals)
   5456 
   5457                             // Transform the normals
   5458                             float *normals = model.meshes[meshIndex].normals;
   5459                             for (unsigned int k = 0; k < attribute->count; k++)
   5460                             {
   5461                                 Vector3 nt = Vector3Transform((Vector3){ normals[3*k], normals[3*k+1], normals[3*k+2] }, worldMatrixNormals);
   5462                                 normals[3*k] = nt.x;
   5463                                 normals[3*k+1] = nt.y;
   5464                                 normals[3*k+2] = nt.z;
   5465                             }
   5466                         }
   5467                         else TRACELOG(LOG_WARNING, "MODEL: [%s] Normal attribute data format not supported, use vec3 float", fileName);
   5468                     }
   5469                     else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_tangent)   // TANGENT, vec3, float
   5470                     {
   5471                         cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
   5472 
   5473                         if ((attribute->type == cgltf_type_vec4) && (attribute->component_type == cgltf_component_type_r_32f))
   5474                         {
   5475                             // Init raylib mesh tangent to copy glTF attribute data
   5476                             model.meshes[meshIndex].tangents = RL_MALLOC(attribute->count*4*sizeof(float));
   5477 
   5478                             // Load 4 components of float data type into mesh.tangents
   5479                             LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].tangents)
   5480 
   5481                             // Transform the tangents
   5482                             float *tangents = model.meshes[meshIndex].tangents;
   5483                             for (unsigned int k = 0; k < attribute->count; k++)
   5484                             {
   5485                                 Vector3 tt = Vector3Transform((Vector3){ tangents[3*k], tangents[3*k+1], tangents[3*k+2] }, worldMatrix);
   5486                                 tangents[3*k] = tt.x;
   5487                                 tangents[3*k+1] = tt.y;
   5488                                 tangents[3*k+2] = tt.z;
   5489                             }
   5490                         }
   5491                         else TRACELOG(LOG_WARNING, "MODEL: [%s] Tangent attribute data format not supported, use vec4 float", fileName);
   5492                     }
   5493                     else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_texcoord) // TEXCOORD_n, vec2, float/u8n/u16n
   5494                     {
   5495                         // Support up to 2 texture coordinates attributes
   5496                         float *texcoordPtr = NULL;
   5497 
   5498                         cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
   5499 
   5500                         if (attribute->type == cgltf_type_vec2)
   5501                         {
   5502                             if (attribute->component_type == cgltf_component_type_r_32f)  // vec2, float
   5503                             {
   5504                                 // Init raylib mesh texcoords to copy glTF attribute data
   5505                                 texcoordPtr = (float *)RL_MALLOC(attribute->count*2*sizeof(float));
   5506 
   5507                                 // Load 3 components of float data type into mesh.texcoords
   5508                                 LOAD_ATTRIBUTE(attribute, 2, float, texcoordPtr)
   5509                             }
   5510                             else if (attribute->component_type == cgltf_component_type_r_8u) // vec2, u8n
   5511                             {
   5512                                 // Init raylib mesh texcoords to copy glTF attribute data
   5513                                 texcoordPtr = (float *)RL_MALLOC(attribute->count*2*sizeof(float));
   5514 
   5515                                 // Load data into a temp buffer to be converted to raylib data type
   5516                                 unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*2*sizeof(unsigned char));
   5517                                 LOAD_ATTRIBUTE(attribute, 2, unsigned char, temp);
   5518 
   5519                                 // Convert data to raylib texcoord data type (float)
   5520                                 for (unsigned int t = 0; t < attribute->count*2; t++) texcoordPtr[t] = (float)temp[t]/255.0f;
   5521 
   5522                                 RL_FREE(temp);
   5523                             }
   5524                             else if (attribute->component_type == cgltf_component_type_r_16u) // vec2, u16n
   5525                             {
   5526                                 // Init raylib mesh texcoords to copy glTF attribute data
   5527                                 texcoordPtr = (float *)RL_MALLOC(attribute->count*2*sizeof(float));
   5528 
   5529                                 // Load data into a temp buffer to be converted to raylib data type
   5530                                 unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*2*sizeof(unsigned short));
   5531                                 LOAD_ATTRIBUTE(attribute, 2, unsigned short, temp);
   5532 
   5533                                 // Convert data to raylib texcoord data type (float)
   5534                                 for (unsigned int t = 0; t < attribute->count*2; t++) texcoordPtr[t] = (float)temp[t]/65535.0f;
   5535 
   5536                                 RL_FREE(temp);
   5537                             }
   5538                             else TRACELOG(LOG_WARNING, "MODEL: [%s] Texcoords attribute data format not supported", fileName);
   5539                         }
   5540                         else TRACELOG(LOG_WARNING, "MODEL: [%s] Texcoords attribute data format not supported, use vec2 float", fileName);
   5541 
   5542                         int index = mesh->primitives[p].attributes[j].index;
   5543                         if (index == 0) model.meshes[meshIndex].texcoords = texcoordPtr;
   5544                         else if (index == 1) model.meshes[meshIndex].texcoords2 = texcoordPtr;
   5545                         else
   5546                         {
   5547                             TRACELOG(LOG_WARNING, "MODEL: [%s] No more than 2 texture coordinates attributes supported", fileName);
   5548                             if (texcoordPtr != NULL) RL_FREE(texcoordPtr);
   5549                         }
   5550                     }
   5551                     else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_color)    // COLOR_n, vec3/vec4, float/u8n/u16n
   5552                     {
   5553                         cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
   5554 
   5555                         // WARNING: SPECS: All components of each COLOR_n accessor element MUST be clamped to [0.0, 1.0] range
   5556 
   5557                         if (attribute->type == cgltf_type_vec3)  // RGB
   5558                         {
   5559                             if (attribute->component_type == cgltf_component_type_r_8u)
   5560                             {
   5561                                 // Init raylib mesh color to copy glTF attribute data
   5562                                 model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
   5563 
   5564                                 // Load data into a temp buffer to be converted to raylib data type
   5565                                 unsigned char *temp = RL_MALLOC(attribute->count*3*sizeof(unsigned char));
   5566                                 LOAD_ATTRIBUTE(attribute, 3, unsigned char, temp);
   5567 
   5568                                 // Convert data to raylib color data type (4 bytes)
   5569                                 for (unsigned int c = 0, k = 0; c < (attribute->count*4 - 3); c += 4, k += 3)
   5570                                 {
   5571                                     model.meshes[meshIndex].colors[c] = temp[k];
   5572                                     model.meshes[meshIndex].colors[c + 1] = temp[k + 1];
   5573                                     model.meshes[meshIndex].colors[c + 2] = temp[k + 2];
   5574                                     model.meshes[meshIndex].colors[c + 3] = 255;
   5575                                 }
   5576 
   5577                                 RL_FREE(temp);
   5578                             }
   5579                             else if (attribute->component_type == cgltf_component_type_r_16u)
   5580                             {
   5581                                 // Init raylib mesh color to copy glTF attribute data
   5582                                 model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
   5583 
   5584                                 // Load data into a temp buffer to be converted to raylib data type
   5585                                 unsigned short *temp = RL_MALLOC(attribute->count*3*sizeof(unsigned short));
   5586                                 LOAD_ATTRIBUTE(attribute, 3, unsigned short, temp);
   5587 
   5588                                 // Convert data to raylib color data type (4 bytes)
   5589                                 for (unsigned int c = 0, k = 0; c < (attribute->count*4 - 3); c += 4, k += 3)
   5590                                 {
   5591                                     model.meshes[meshIndex].colors[c] = (unsigned char)(((float)temp[k]/65535.0f)*255.0f);
   5592                                     model.meshes[meshIndex].colors[c + 1] = (unsigned char)(((float)temp[k + 1]/65535.0f)*255.0f);
   5593                                     model.meshes[meshIndex].colors[c + 2] = (unsigned char)(((float)temp[k + 2]/65535.0f)*255.0f);
   5594                                     model.meshes[meshIndex].colors[c + 3] = 255;
   5595                                 }
   5596 
   5597                                 RL_FREE(temp);
   5598                             }
   5599                             else if (attribute->component_type == cgltf_component_type_r_32f)
   5600                             {
   5601                                 // Init raylib mesh color to copy glTF attribute data
   5602                                 model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
   5603 
   5604                                 // Load data into a temp buffer to be converted to raylib data type
   5605                                 float *temp = RL_MALLOC(attribute->count*3*sizeof(float));
   5606                                 LOAD_ATTRIBUTE(attribute, 3, float, temp);
   5607 
   5608                                 // Convert data to raylib color data type (4 bytes)
   5609                                 for (unsigned int c = 0, k = 0; c < (attribute->count*4 - 3); c += 4, k += 3)
   5610                                 {
   5611                                     model.meshes[meshIndex].colors[c] = (unsigned char)(temp[k]*255.0f);
   5612                                     model.meshes[meshIndex].colors[c + 1] = (unsigned char)(temp[k + 1]*255.0f);
   5613                                     model.meshes[meshIndex].colors[c + 2] = (unsigned char)(temp[k + 2]*255.0f);
   5614                                     model.meshes[meshIndex].colors[c + 3] = 255;
   5615                                 }
   5616 
   5617                                 RL_FREE(temp);
   5618                             }
   5619                             else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName);
   5620                         }
   5621                         else if (attribute->type == cgltf_type_vec4) // RGBA
   5622                         {
   5623                             if (attribute->component_type == cgltf_component_type_r_8u)
   5624                             {
   5625                                 // Init raylib mesh color to copy glTF attribute data
   5626                                 model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
   5627 
   5628                                 // Load 4 components of unsigned char data type into mesh.colors
   5629                                 LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].colors)
   5630                             }
   5631                             else if (attribute->component_type == cgltf_component_type_r_16u)
   5632                             {
   5633                                 // Init raylib mesh color to copy glTF attribute data
   5634                                 model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
   5635 
   5636                                 // Load data into a temp buffer to be converted to raylib data type
   5637                                 unsigned short *temp = RL_MALLOC(attribute->count*4*sizeof(unsigned short));
   5638                                 LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
   5639 
   5640                                 // Convert data to raylib color data type (4 bytes)
   5641                                 for (unsigned int c = 0; c < attribute->count*4; c++) model.meshes[meshIndex].colors[c] = (unsigned char)(((float)temp[c]/65535.0f)*255.0f);
   5642 
   5643                                 RL_FREE(temp);
   5644                             }
   5645                             else if (attribute->component_type == cgltf_component_type_r_32f)
   5646                             {
   5647                                 // Init raylib mesh color to copy glTF attribute data
   5648                                 model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
   5649 
   5650                                 // Load data into a temp buffer to be converted to raylib data type
   5651                                 float *temp = RL_MALLOC(attribute->count*4*sizeof(float));
   5652                                 LOAD_ATTRIBUTE(attribute, 4, float, temp);
   5653 
   5654                                 // Convert data to raylib color data type (4 bytes), we expect the color data normalized
   5655                                 for (unsigned int c = 0; c < attribute->count*4; c++) model.meshes[meshIndex].colors[c] = (unsigned char)(temp[c]*255.0f);
   5656 
   5657                                 RL_FREE(temp);
   5658                             }
   5659                             else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName);
   5660                         }
   5661                         else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName);
   5662                     }
   5663 
   5664                     // NOTE: Attributes related to animations are processed separately
   5665                 }
   5666 
   5667                 // Load primitive indices data (if provided)
   5668                 if (mesh->primitives[p].indices != NULL)
   5669                 {
   5670                     cgltf_accessor *attribute = mesh->primitives[p].indices;
   5671 
   5672                     model.meshes[meshIndex].triangleCount = (int)attribute->count/3;
   5673 
   5674                     if (attribute->component_type == cgltf_component_type_r_16u)
   5675                     {
   5676                         // Init raylib mesh indices to copy glTF attribute data
   5677                         model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short));
   5678 
   5679                         // Load unsigned short data type into mesh.indices
   5680                         LOAD_ATTRIBUTE(attribute, 1, unsigned short, model.meshes[meshIndex].indices)
   5681                     }
   5682                     else if (attribute->component_type == cgltf_component_type_r_8u)
   5683                     {
   5684                         // Init raylib mesh indices to copy glTF attribute data
   5685                         model.meshes[meshIndex].indices = RL_MALLOC(attribute->count * sizeof(unsigned short));
   5686                         LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned char, model.meshes[meshIndex].indices, unsigned short)
   5687 
   5688                     }
   5689                     else if (attribute->component_type == cgltf_component_type_r_32u)
   5690                     {
   5691                         // Init raylib mesh indices to copy glTF attribute data
   5692                         model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short));
   5693                         LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned int, model.meshes[meshIndex].indices, unsigned short);
   5694 
   5695                         TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data converted from u32 to u16, possible loss of data", fileName);
   5696                     }
   5697                     else
   5698                     {
   5699                         TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data format not supported, use u16", fileName);
   5700                     }
   5701                 }
   5702                 else model.meshes[meshIndex].triangleCount = model.meshes[meshIndex].vertexCount/3;    // Unindexed mesh
   5703 
   5704                 // Assign to the primitive mesh the corresponding material index
   5705                 // NOTE: If no material defined, mesh uses the already assigned default material (index: 0)
   5706                 for (unsigned int m = 0; m < data->materials_count; m++)
   5707                 {
   5708                     // The primitive actually keeps the pointer to the corresponding material,
   5709                     // raylib instead assigns to the mesh the by its index, as loaded in model.materials array
   5710                     // To get the index, we check if material pointers match, and we assign the corresponding index,
   5711                     // skipping index 0, the default material
   5712                     if (&data->materials[m] == mesh->primitives[p].material)
   5713                     {
   5714                         model.meshMaterial[meshIndex] = m + 1;
   5715                         break;
   5716                     }
   5717                 }
   5718 
   5719                 meshIndex++;       // Move to next mesh
   5720             }
   5721         }
   5722 
   5723         // Load glTF meshes animation data
   5724         // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skins
   5725         // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skinned-mesh-attributes
   5726         //
   5727         // LIMITATIONS:
   5728         //  - Only supports 1 armature per file, and skips loading it if there are multiple armatures
   5729         //  - Only supports linear interpolation (default method in Blender when checked "Always Sample Animations" when exporting a GLTF file)
   5730         //  - Only supports translation/rotation/scale animation channel.path, weights not considered (i.e. morph targets)
   5731         //----------------------------------------------------------------------------------------------------
   5732         if (data->skins_count > 0)
   5733         {
   5734             cgltf_skin skin = data->skins[0];
   5735             model.bones = LoadBoneInfoGLTF(skin, &model.boneCount);
   5736             model.bindPose = RL_MALLOC(model.boneCount*sizeof(Transform));
   5737 
   5738             for (int i = 0; i < model.boneCount; i++)
   5739             {
   5740                 cgltf_node* node = skin.joints[i];
   5741                 cgltf_float worldTransform[16];
   5742                 cgltf_node_transform_world(node, worldTransform);
   5743                 Matrix worldMatrix = {
   5744                     worldTransform[0], worldTransform[4], worldTransform[8], worldTransform[12],
   5745                     worldTransform[1], worldTransform[5], worldTransform[9], worldTransform[13],
   5746                     worldTransform[2], worldTransform[6], worldTransform[10], worldTransform[14],
   5747                     worldTransform[3], worldTransform[7], worldTransform[11], worldTransform[15]
   5748                 };
   5749                 MatrixDecompose(worldMatrix, &(model.bindPose[i].translation), &(model.bindPose[i].rotation), &(model.bindPose[i].scale));
   5750             }
   5751         }
   5752         if (data->skins_count > 1)
   5753         {
   5754             TRACELOG(LOG_WARNING, "MODEL: [%s] can only load one skin (armature) per model, but gltf skins_count == %i", fileName, data->skins_count);
   5755         }
   5756 
   5757         meshIndex = 0;
   5758         for (unsigned int i = 0; i < data->nodes_count; i++)
   5759         {
   5760             cgltf_node *node = &(data->nodes[i]);
   5761 
   5762             cgltf_mesh *mesh = node->mesh;
   5763             if (!mesh)
   5764                 continue;
   5765 
   5766             for (unsigned int p = 0; p < mesh->primitives_count; p++)
   5767             {
   5768                 // NOTE: We only support primitives defined by triangles
   5769                 if (mesh->primitives[p].type != cgltf_primitive_type_triangles) continue;
   5770 
   5771                 for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++)
   5772                 {
   5773                     // NOTE: JOINTS_1 + WEIGHT_1 will be used for +4 joints influencing a vertex -> Not supported by raylib
   5774 
   5775                     if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_joints) // JOINTS_n (vec4: 4 bones max per vertex / u8, u16)
   5776                     {
   5777                         cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
   5778 
   5779                         // NOTE: JOINTS_n can only be vec4 and u8/u16
   5780                         // SPECS: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview
   5781 
   5782                         // WARNING: raylib only supports model.meshes[].boneIds as u8 (unsigned char),
   5783                         // if data is provided in any other format, it is converted to supported format but
   5784                         // it could imply data loss (a warning message is issued in that case)
   5785 
   5786                         if (attribute->type == cgltf_type_vec4)
   5787                         {
   5788                             if (attribute->component_type == cgltf_component_type_r_8u)
   5789                             {
   5790                                 // Init raylib mesh boneIds to copy glTF attribute data
   5791                                 model.meshes[meshIndex].boneIds = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
   5792 
   5793                                 // Load attribute: vec4, u8 (unsigned char)
   5794                                 LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].boneIds)
   5795                             }
   5796                             else if (attribute->component_type == cgltf_component_type_r_16u)
   5797                             {
   5798                                 // Init raylib mesh boneIds to copy glTF attribute data
   5799                                 model.meshes[meshIndex].boneIds = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
   5800 
   5801                                 // Load data into a temp buffer to be converted to raylib data type
   5802                                 unsigned short *temp = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned short));
   5803                                 LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
   5804 
   5805                                 // Convert data to raylib color data type (4 bytes)
   5806                                 bool boneIdOverflowWarning = false;
   5807                                 for (int b = 0; b < model.meshes[meshIndex].vertexCount*4; b++)
   5808                                 {
   5809                                     if ((temp[b] > 255) && !boneIdOverflowWarning)
   5810                                     {
   5811                                         TRACELOG(LOG_WARNING, "MODEL: [%s] Joint attribute data format (u16) overflow", fileName);
   5812                                         boneIdOverflowWarning = true;
   5813                                     }
   5814 
   5815                                     // Despite the possible overflow, we convert data to unsigned char
   5816                                     model.meshes[meshIndex].boneIds[b] = (unsigned char)temp[b];
   5817                                 }
   5818 
   5819                                 RL_FREE(temp);
   5820                             }
   5821                             else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint attribute data format not supported", fileName);
   5822                         }
   5823                         else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint attribute data format not supported", fileName);
   5824                     }
   5825                     else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_weights)  // WEIGHTS_n (vec4, u8n/u16n/f32)
   5826                     {
   5827                         cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
   5828 
   5829                         if (attribute->type == cgltf_type_vec4)
   5830                         {
   5831                             // TODO: Support component types: u8, u16?
   5832                             if (attribute->component_type == cgltf_component_type_r_8u)
   5833                             {
   5834                                 // Init raylib mesh bone weight to copy glTF attribute data
   5835                                 model.meshes[meshIndex].boneWeights = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
   5836 
   5837                                 // Load data into a temp buffer to be converted to raylib data type
   5838                                 unsigned char *temp = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
   5839                                 LOAD_ATTRIBUTE(attribute, 4, unsigned char, temp);
   5840 
   5841                                 // Convert data to raylib bone weight data type (4 bytes)
   5842                                 for (unsigned int b = 0; b < attribute->count*4; b++) model.meshes[meshIndex].boneWeights[b] = (float)temp[b]/255.0f;
   5843 
   5844                                 RL_FREE(temp);
   5845                             }
   5846                             else if (attribute->component_type == cgltf_component_type_r_16u)
   5847                             {
   5848                                 // Init raylib mesh bone weight to copy glTF attribute data
   5849                                 model.meshes[meshIndex].boneWeights = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
   5850 
   5851                                 // Load data into a temp buffer to be converted to raylib data type
   5852                                 unsigned short *temp = RL_MALLOC(attribute->count*4*sizeof(unsigned short));
   5853                                 LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
   5854 
   5855                                 // Convert data to raylib bone weight data type
   5856                                 for (unsigned int b = 0; b < attribute->count*4; b++) model.meshes[meshIndex].boneWeights[b] = (float)temp[b]/65535.0f;
   5857 
   5858                                 RL_FREE(temp);
   5859                             }
   5860                             else if (attribute->component_type == cgltf_component_type_r_32f)
   5861                             {
   5862                                 // Init raylib mesh bone weight to copy glTF attribute data
   5863                                 model.meshes[meshIndex].boneWeights = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
   5864 
   5865                                 // Load 4 components of float data type into mesh.boneWeights
   5866                                 // for cgltf_attribute_type_weights we have:
   5867                                 //   - data.meshes[0] (256 vertices)
   5868                                 //   - 256 values, provided as cgltf_type_vec4 of float (4 byte per joint, stride 16)
   5869                                 LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].boneWeights)
   5870                             }
   5871                             else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint weight attribute data format not supported, use vec4 float", fileName);
   5872                         }
   5873                         else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint weight attribute data format not supported, use vec4 float", fileName);
   5874                     }
   5875                 }
   5876 
   5877                 // Animated vertex data
   5878                 model.meshes[meshIndex].animVertices = RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
   5879                 memcpy(model.meshes[meshIndex].animVertices, model.meshes[meshIndex].vertices, model.meshes[meshIndex].vertexCount*3*sizeof(float));
   5880                 model.meshes[meshIndex].animNormals = RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
   5881                 if (model.meshes[meshIndex].normals != NULL)
   5882                 {
   5883                     memcpy(model.meshes[meshIndex].animNormals, model.meshes[meshIndex].normals, model.meshes[meshIndex].vertexCount*3*sizeof(float));
   5884                 }
   5885 
   5886                 // Bone Transform Matrices
   5887                 model.meshes[meshIndex].boneCount = model.boneCount;
   5888                 model.meshes[meshIndex].boneMatrices = RL_CALLOC(model.meshes[meshIndex].boneCount, sizeof(Matrix));
   5889 
   5890                 for (int j = 0; j < model.meshes[meshIndex].boneCount; j++)
   5891                 {
   5892                     model.meshes[meshIndex].boneMatrices[j] = MatrixIdentity();
   5893                 }
   5894 
   5895                 meshIndex++;       // Move to next mesh
   5896             }
   5897 
   5898         }
   5899 
   5900         // Free all cgltf loaded data
   5901         cgltf_free(data);
   5902     }
   5903     else TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName);
   5904 
   5905     // WARNING: cgltf requires the file pointer available while reading data
   5906     UnloadFileData(fileData);
   5907 
   5908     return model;
   5909 }
   5910 
   5911 // Get interpolated pose for bone sampler at a specific time. Returns true on success
   5912 static bool GetPoseAtTimeGLTF(cgltf_interpolation_type interpolationType, cgltf_accessor *input, cgltf_accessor *output, float time, void *data)
   5913 {
   5914     if (interpolationType >= cgltf_interpolation_type_max_enum) return false;
   5915 
   5916     // Input and output should have the same count
   5917     float tstart = 0.0f;
   5918     float tend = 0.0f;
   5919     int keyframe = 0;       // Defaults to first pose
   5920 
   5921     for (int i = 0; i < (int)input->count - 1; i++)
   5922     {
   5923         cgltf_bool r1 = cgltf_accessor_read_float(input, i, &tstart, 1);
   5924         if (!r1) return false;
   5925 
   5926         cgltf_bool r2 = cgltf_accessor_read_float(input, i + 1, &tend, 1);
   5927         if (!r2) return false;
   5928 
   5929         if ((tstart <= time) && (time < tend))
   5930         {
   5931             keyframe = i;
   5932             break;
   5933         }
   5934     }
   5935 
   5936     // Constant animation, no need to interpolate
   5937     if (FloatEquals(tend, tstart)) return true;
   5938 
   5939     float duration = fmaxf((tend - tstart), EPSILON);
   5940     float t = (time - tstart)/duration;
   5941     t = (t < 0.0f)? 0.0f : t;
   5942     t = (t > 1.0f)? 1.0f : t;
   5943 
   5944     if (output->component_type != cgltf_component_type_r_32f) return false;
   5945 
   5946     if (output->type == cgltf_type_vec3)
   5947     {
   5948         switch (interpolationType)
   5949         {
   5950             case cgltf_interpolation_type_step:
   5951             {
   5952                 float tmp[3] = { 0.0f };
   5953                 cgltf_accessor_read_float(output, keyframe, tmp, 3);
   5954                 Vector3 v1 = {tmp[0], tmp[1], tmp[2]};
   5955                 Vector3 *r = data;
   5956 
   5957                 *r = v1;
   5958             } break;
   5959             case cgltf_interpolation_type_linear:
   5960             {
   5961                 float tmp[3] = { 0.0f };
   5962                 cgltf_accessor_read_float(output, keyframe, tmp, 3);
   5963                 Vector3 v1 = {tmp[0], tmp[1], tmp[2]};
   5964                 cgltf_accessor_read_float(output, keyframe+1, tmp, 3);
   5965                 Vector3 v2 = {tmp[0], tmp[1], tmp[2]};
   5966                 Vector3 *r = data;
   5967 
   5968                 *r = Vector3Lerp(v1, v2, t);
   5969             } break;
   5970             case cgltf_interpolation_type_cubic_spline:
   5971             {
   5972                 float tmp[3] = { 0.0f };
   5973                 cgltf_accessor_read_float(output, 3*keyframe+1, tmp, 3);
   5974                 Vector3 v1 = {tmp[0], tmp[1], tmp[2]};
   5975                 cgltf_accessor_read_float(output, 3*keyframe+2, tmp, 3);
   5976                 Vector3 tangent1 = {tmp[0], tmp[1], tmp[2]};
   5977                 cgltf_accessor_read_float(output, 3*(keyframe+1)+1, tmp, 3);
   5978                 Vector3 v2 = {tmp[0], tmp[1], tmp[2]};
   5979                 cgltf_accessor_read_float(output, 3*(keyframe+1), tmp, 3);
   5980                 Vector3 tangent2 = {tmp[0], tmp[1], tmp[2]};
   5981                 Vector3 *r = data;
   5982 
   5983                 *r = Vector3CubicHermite(v1, tangent1, v2, tangent2, t);
   5984             } break;
   5985             default: break;
   5986         }
   5987     }
   5988     else if (output->type == cgltf_type_vec4)
   5989     {
   5990         // Only v4 is for rotations, so we know it's a quaternion
   5991         switch (interpolationType)
   5992         {
   5993             case cgltf_interpolation_type_step:
   5994             {
   5995                 float tmp[4] = { 0.0f };
   5996                 cgltf_accessor_read_float(output, keyframe, tmp, 4);
   5997                 Vector4 v1 = {tmp[0], tmp[1], tmp[2], tmp[3]};
   5998                 Vector4 *r = data;
   5999 
   6000                 *r = v1;
   6001             } break;
   6002             case cgltf_interpolation_type_linear:
   6003             {
   6004                 float tmp[4] = { 0.0f };
   6005                 cgltf_accessor_read_float(output, keyframe, tmp, 4);
   6006                 Vector4 v1 = {tmp[0], tmp[1], tmp[2], tmp[3]};
   6007                 cgltf_accessor_read_float(output, keyframe+1, tmp, 4);
   6008                 Vector4 v2 = {tmp[0], tmp[1], tmp[2], tmp[3]};
   6009                 Vector4 *r = data;
   6010 
   6011                 *r = QuaternionSlerp(v1, v2, t);
   6012             } break;
   6013             case cgltf_interpolation_type_cubic_spline:
   6014             {
   6015                 float tmp[4] = { 0.0f };
   6016                 cgltf_accessor_read_float(output, 3*keyframe+1, tmp, 4);
   6017                 Vector4 v1 = {tmp[0], tmp[1], tmp[2], tmp[3]};
   6018                 cgltf_accessor_read_float(output, 3*keyframe+2, tmp, 4);
   6019                 Vector4 outTangent1 = {tmp[0], tmp[1], tmp[2], 0.0f};
   6020                 cgltf_accessor_read_float(output, 3*(keyframe+1)+1, tmp, 4);
   6021                 Vector4 v2 = {tmp[0], tmp[1], tmp[2], tmp[3]};
   6022                 cgltf_accessor_read_float(output, 3*(keyframe+1), tmp, 4);
   6023                 Vector4 inTangent2 = {tmp[0], tmp[1], tmp[2], 0.0f};
   6024                 Vector4 *r = data;
   6025 
   6026                 v1 = QuaternionNormalize(v1);
   6027                 v2 = QuaternionNormalize(v2);
   6028 
   6029                 if (Vector4DotProduct(v1, v2) < 0.0f)
   6030                 {
   6031                     v2 = Vector4Negate(v2);
   6032                 }
   6033 
   6034                 outTangent1 = Vector4Scale(outTangent1, duration);
   6035                 inTangent2 = Vector4Scale(inTangent2, duration);
   6036 
   6037                 *r = QuaternionCubicHermiteSpline(v1, outTangent1, v2, inTangent2, t);
   6038             } break;
   6039             default: break;
   6040         }
   6041     }
   6042 
   6043     return true;
   6044 }
   6045 
   6046 #define GLTF_ANIMDELAY 17    // Animation frames delay, (~1000 ms/60 FPS = 16.666666* ms)
   6047 
   6048 static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCount)
   6049 {
   6050     // glTF file loading
   6051     int dataSize = 0;
   6052     unsigned char *fileData = LoadFileData(fileName, &dataSize);
   6053 
   6054     ModelAnimation *animations = NULL;
   6055 
   6056     // glTF data loading
   6057     cgltf_options options = { 0 };
   6058     options.file.read = LoadFileGLTFCallback;
   6059     options.file.release = ReleaseFileGLTFCallback;
   6060     cgltf_data *data = NULL;
   6061     cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data);
   6062 
   6063     if (result != cgltf_result_success)
   6064     {
   6065         TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName);
   6066         *animCount = 0;
   6067         return NULL;
   6068     }
   6069 
   6070     result = cgltf_load_buffers(&options, data, fileName);
   6071     if (result != cgltf_result_success) TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load animation buffers", fileName);
   6072 
   6073     if (result == cgltf_result_success)
   6074     {
   6075         if (data->skins_count > 0)
   6076         {
   6077             cgltf_skin skin = data->skins[0];
   6078             *animCount = (int)data->animations_count;
   6079             animations = RL_MALLOC(data->animations_count*sizeof(ModelAnimation));
   6080 
   6081             for (unsigned int i = 0; i < data->animations_count; i++)
   6082             {
   6083                 animations[i].bones = LoadBoneInfoGLTF(skin, &animations[i].boneCount);
   6084 
   6085                 cgltf_animation animData = data->animations[i];
   6086 
   6087                 struct Channels {
   6088                     cgltf_animation_channel *translate;
   6089                     cgltf_animation_channel *rotate;
   6090                     cgltf_animation_channel *scale;
   6091                     cgltf_interpolation_type interpolationType;
   6092                 };
   6093 
   6094                 struct Channels *boneChannels = RL_CALLOC(animations[i].boneCount, sizeof(struct Channels));
   6095                 float animDuration = 0.0f;
   6096 
   6097                 for (unsigned int j = 0; j < animData.channels_count; j++)
   6098                 {
   6099                     cgltf_animation_channel channel = animData.channels[j];
   6100                     int boneIndex = -1;
   6101 
   6102                     for (unsigned int k = 0; k < skin.joints_count; k++)
   6103                     {
   6104                         if (animData.channels[j].target_node == skin.joints[k])
   6105                         {
   6106                             boneIndex = k;
   6107                             break;
   6108                         }
   6109                     }
   6110 
   6111                     if (boneIndex == -1)
   6112                     {
   6113                         // Animation channel for a node not in the armature
   6114                         continue;
   6115                     }
   6116 
   6117                     boneChannels[boneIndex].interpolationType = animData.channels[j].sampler->interpolation;
   6118 
   6119                     if (animData.channels[j].sampler->interpolation != cgltf_interpolation_type_max_enum)
   6120                     {
   6121                         if (channel.target_path == cgltf_animation_path_type_translation)
   6122                         {
   6123                             boneChannels[boneIndex].translate = &animData.channels[j];
   6124                         }
   6125                         else if (channel.target_path == cgltf_animation_path_type_rotation)
   6126                         {
   6127                             boneChannels[boneIndex].rotate = &animData.channels[j];
   6128                         }
   6129                         else if (channel.target_path == cgltf_animation_path_type_scale)
   6130                         {
   6131                             boneChannels[boneIndex].scale = &animData.channels[j];
   6132                         }
   6133                         else
   6134                         {
   6135                             TRACELOG(LOG_WARNING, "MODEL: [%s] Unsupported target_path on channel %d's sampler for animation %d. Skipping.", fileName, j, i);
   6136                         }
   6137                     }
   6138                     else TRACELOG(LOG_WARNING, "MODEL: [%s] Invalid interpolation curve encountered for GLTF animation.", fileName);
   6139 
   6140                     float t = 0.0f;
   6141                     cgltf_bool r = cgltf_accessor_read_float(channel.sampler->input, channel.sampler->input->count - 1, &t, 1);
   6142 
   6143                     if (!r)
   6144                     {
   6145                         TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load input time", fileName);
   6146                         continue;
   6147                     }
   6148 
   6149                     animDuration = (t > animDuration)? t : animDuration;
   6150                 }
   6151 
   6152                 if (animData.name != NULL)
   6153                 {
   6154                     strncpy(animations[i].name, animData.name, sizeof(animations[i].name));
   6155                     animations[i].name[sizeof(animations[i].name) - 1] = '\0';
   6156                 }
   6157 
   6158                 animations[i].frameCount = (int)(animDuration*1000.0f/GLTF_ANIMDELAY) + 1;
   6159                 animations[i].framePoses = RL_MALLOC(animations[i].frameCount*sizeof(Transform *));
   6160 
   6161                 for (int j = 0; j < animations[i].frameCount; j++)
   6162                 {
   6163                     animations[i].framePoses[j] = RL_MALLOC(animations[i].boneCount*sizeof(Transform));
   6164                     float time = ((float) j*GLTF_ANIMDELAY)/1000.0f;
   6165 
   6166                     for (int k = 0; k < animations[i].boneCount; k++)
   6167                     {
   6168                         Vector3 translation = {skin.joints[k]->translation[0], skin.joints[k]->translation[1], skin.joints[k]->translation[2]};
   6169                         Quaternion rotation = {skin.joints[k]->rotation[0], skin.joints[k]->rotation[1], skin.joints[k]->rotation[2], skin.joints[k]->rotation[3]};
   6170                         Vector3 scale = {skin.joints[k]->scale[0], skin.joints[k]->scale[1], skin.joints[k]->scale[2]};
   6171 
   6172                         if (boneChannels[k].translate)
   6173                         {
   6174                             if (!GetPoseAtTimeGLTF(boneChannels[k].interpolationType, boneChannels[k].translate->sampler->input, boneChannels[k].translate->sampler->output, time, &translation))
   6175                             {
   6176                                 TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load translate pose data for bone %s", fileName, animations[i].bones[k].name);
   6177                             }
   6178                         }
   6179 
   6180                         if (boneChannels[k].rotate)
   6181                         {
   6182                             if (!GetPoseAtTimeGLTF(boneChannels[k].interpolationType, boneChannels[k].rotate->sampler->input, boneChannels[k].rotate->sampler->output, time, &rotation))
   6183                             {
   6184                                 TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load rotate pose data for bone %s", fileName, animations[i].bones[k].name);
   6185                             }
   6186                         }
   6187 
   6188                         if (boneChannels[k].scale)
   6189                         {
   6190                             if (!GetPoseAtTimeGLTF(boneChannels[k].interpolationType, boneChannels[k].scale->sampler->input, boneChannels[k].scale->sampler->output, time, &scale))
   6191                             {
   6192                                 TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load scale pose data for bone %s", fileName, animations[i].bones[k].name);
   6193                             }
   6194                         }
   6195 
   6196                         animations[i].framePoses[j][k] = (Transform){
   6197                             .translation = translation,
   6198                             .rotation = rotation,
   6199                             .scale = scale
   6200                         };
   6201                     }
   6202 
   6203                     BuildPoseFromParentJoints(animations[i].bones, animations[i].boneCount, animations[i].framePoses[j]);
   6204                 }
   6205 
   6206                 TRACELOG(LOG_INFO, "MODEL: [%s] Loaded animation: %s (%d frames, %fs)", fileName, (animData.name != NULL)? animData.name : "NULL", animations[i].frameCount, animDuration);
   6207                 RL_FREE(boneChannels);
   6208             }
   6209         }
   6210 
   6211         if (data->skins_count > 1)
   6212         {
   6213             TRACELOG(LOG_WARNING, "MODEL: [%s] expected exactly one skin to load animation data from, but found %i", fileName, data->skins_count);
   6214         }
   6215 
   6216         cgltf_free(data);
   6217     }
   6218     UnloadFileData(fileData);
   6219     return animations;
   6220 }
   6221 #endif
   6222 
   6223 #if defined(SUPPORT_FILEFORMAT_VOX)
   6224 // Load VOX (MagicaVoxel) mesh data
   6225 static Model LoadVOX(const char *fileName)
   6226 {
   6227     Model model = { 0 };
   6228 
   6229     int nbvertices = 0;
   6230     int meshescount = 0;
   6231 
   6232     // Read vox file into buffer
   6233     int dataSize = 0;
   6234     unsigned char *fileData = LoadFileData(fileName, &dataSize);
   6235 
   6236     if (fileData == 0)
   6237     {
   6238         TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load VOX file", fileName);
   6239         return model;
   6240     }
   6241 
   6242     // Read and build voxarray description
   6243     VoxArray3D voxarray = { 0 };
   6244     int ret = Vox_LoadFromMemory(fileData, dataSize, &voxarray);
   6245 
   6246     if (ret != VOX_SUCCESS)
   6247     {
   6248         // Error
   6249         UnloadFileData(fileData);
   6250 
   6251         TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load VOX data", fileName);
   6252         return model;
   6253     }
   6254     else
   6255     {
   6256         // Success: Compute meshes count
   6257         nbvertices = voxarray.vertices.used;
   6258         meshescount = 1 + (nbvertices/65536);
   6259 
   6260         TRACELOG(LOG_INFO, "MODEL: [%s] VOX data loaded successfully : %i vertices/%i meshes", fileName, nbvertices, meshescount);
   6261     }
   6262 
   6263     // Build models from meshes
   6264     model.transform = MatrixIdentity();
   6265 
   6266     model.meshCount = meshescount;
   6267     model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
   6268 
   6269     model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
   6270 
   6271     model.materialCount = 1;
   6272     model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
   6273     model.materials[0] = LoadMaterialDefault();
   6274 
   6275     // Init model meshes
   6276     int verticesRemain = voxarray.vertices.used;
   6277     int verticesMax = 65532; // 5461 voxels x 12 vertices per voxel -> 65532 (must be inf 65536)
   6278 
   6279     // 6*4 = 12 vertices per voxel
   6280     Vector3 *pvertices = (Vector3 *)voxarray.vertices.array;
   6281     Vector3 *pnormals = (Vector3 *)voxarray.normals.array;
   6282     Color *pcolors = (Color *)voxarray.colors.array;
   6283 
   6284     unsigned short *pindices = voxarray.indices.array;    // 5461*6*6 = 196596 indices max per mesh
   6285 
   6286     int size = 0;
   6287 
   6288     for (int i = 0; i < meshescount; i++)
   6289     {
   6290         Mesh *pmesh = &model.meshes[i];
   6291         memset(pmesh, 0, sizeof(Mesh));
   6292 
   6293         // Copy vertices
   6294         pmesh->vertexCount = (int)fmin(verticesMax, verticesRemain);
   6295 
   6296         size = pmesh->vertexCount*sizeof(float)*3;
   6297         pmesh->vertices = (float *)RL_MALLOC(size);
   6298         memcpy(pmesh->vertices, pvertices, size);
   6299 
   6300         // Copy normals
   6301         pmesh->normals = (float *)RL_MALLOC(size);
   6302         memcpy(pmesh->normals, pnormals, size);
   6303 
   6304         // Copy indices
   6305         size = voxarray.indices.used*sizeof(unsigned short);
   6306         pmesh->indices = (unsigned short *)RL_MALLOC(size);
   6307         memcpy(pmesh->indices, pindices, size);
   6308 
   6309         pmesh->triangleCount = (pmesh->vertexCount/4)*2;
   6310 
   6311         // Copy colors
   6312         size = pmesh->vertexCount*sizeof(Color);
   6313         pmesh->colors = RL_MALLOC(size);
   6314         memcpy(pmesh->colors, pcolors, size);
   6315 
   6316         // First material index
   6317         model.meshMaterial[i] = 0;
   6318 
   6319         verticesRemain -= verticesMax;
   6320         pvertices += verticesMax;
   6321         pnormals += verticesMax;
   6322         pcolors += verticesMax;
   6323     }
   6324 
   6325     // Free buffers
   6326     Vox_FreeArrays(&voxarray);
   6327     UnloadFileData(fileData);
   6328 
   6329     return model;
   6330 }
   6331 #endif
   6332 
   6333 #if defined(SUPPORT_FILEFORMAT_M3D)
   6334 // Hook LoadFileData()/UnloadFileData() calls to M3D loaders
   6335 unsigned char *m3d_loaderhook(char *fn, unsigned int *len) { return LoadFileData((const char *)fn, (int *)len); }
   6336 void m3d_freehook(void *data) { UnloadFileData((unsigned char *)data); }
   6337 
   6338 // Load M3D mesh data
   6339 static Model LoadM3D(const char *fileName)
   6340 {
   6341     Model model = { 0 };
   6342 
   6343     m3d_t *m3d = NULL;
   6344     m3dp_t *prop = NULL;
   6345     int i, j, k, l, n, mi = -2, vcolor = 0;
   6346 
   6347     int dataSize = 0;
   6348     unsigned char *fileData = LoadFileData(fileName, &dataSize);
   6349 
   6350     if (fileData != NULL)
   6351     {
   6352         m3d = m3d_load(fileData, m3d_loaderhook, m3d_freehook, NULL);
   6353 
   6354         if (!m3d || M3D_ERR_ISFATAL(m3d->errcode))
   6355         {
   6356             TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load M3D data, error code %d", fileName, m3d? m3d->errcode : -2);
   6357             if (m3d) m3d_free(m3d);
   6358             UnloadFileData(fileData);
   6359             return model;
   6360         }
   6361         else TRACELOG(LOG_INFO, "MODEL: [%s] M3D data loaded successfully: %i faces/%i materials", fileName, m3d->numface, m3d->nummaterial);
   6362 
   6363         // no face? this is probably just a material library
   6364         if (!m3d->numface)
   6365         {
   6366             m3d_free(m3d);
   6367             UnloadFileData(fileData);
   6368             return model;
   6369         }
   6370 
   6371         if (m3d->nummaterial > 0)
   6372         {
   6373             model.meshCount = model.materialCount = m3d->nummaterial;
   6374             TRACELOG(LOG_INFO, "MODEL: model has %i material meshes", model.materialCount);
   6375         }
   6376         else
   6377         {
   6378             model.meshCount = 1; model.materialCount = 0;
   6379             TRACELOG(LOG_INFO, "MODEL: No materials, putting all meshes in a default material");
   6380         }
   6381 
   6382         // We always need a default material, so we add +1
   6383         model.materialCount++;
   6384 
   6385         // Faces must be in non-decreasing materialid order. Verify that quickly, sorting them otherwise
   6386         // WARNING: Sorting is not needed, valid M3D model files should already be sorted
   6387         // Just keeping the sorting function for reference (Check PR #3363 #3385)
   6388         /*
   6389         for (i = 1; i < m3d->numface; i++)
   6390         {
   6391             if (m3d->face[i-1].materialid <= m3d->face[i].materialid) continue;
   6392 
   6393             // face[i-1] > face[i].  slide face[i] lower
   6394             m3df_t slider = m3d->face[i];
   6395             j = i-1;
   6396 
   6397             do
   6398             {   // face[j] > slider, face[j+1] is svailable vacant gap
   6399                 m3d->face[j+1] = m3d->face[j];
   6400                 j = j-1;
   6401             }
   6402             while (j >= 0 && m3d->face[j].materialid > slider.materialid);
   6403 
   6404             m3d->face[j+1] = slider;
   6405         }
   6406         */
   6407 
   6408         model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
   6409         model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
   6410         model.materials = (Material *)RL_CALLOC(model.materialCount + 1, sizeof(Material));
   6411 
   6412         // Map no material to index 0 with default shader, everything else materialid + 1
   6413         model.materials[0] = LoadMaterialDefault();
   6414 
   6415         for (i = l = 0, k = -1; i < (int)m3d->numface; i++, l++)
   6416         {
   6417             // Materials are grouped together
   6418             if (mi != m3d->face[i].materialid)
   6419             {
   6420                 // there should be only one material switch per material kind, but be bulletproof for non-optimal model files
   6421                 if (k + 1 >= model.meshCount)
   6422                 {
   6423                     model.meshCount++;
   6424                     model.meshes = (Mesh *)RL_REALLOC(model.meshes, model.meshCount*sizeof(Mesh));
   6425                     memset(&model.meshes[model.meshCount - 1], 0, sizeof(Mesh));
   6426                     model.meshMaterial = (int *)RL_REALLOC(model.meshMaterial, model.meshCount*sizeof(int));
   6427                 }
   6428 
   6429                 k++;
   6430                 mi = m3d->face[i].materialid;
   6431 
   6432                 // Only allocate colors VertexBuffer if there's a color vertex in the model for this material batch
   6433                 // if all colors are fully transparent black for all verteces of this materal, then we assume no vertex colors
   6434                 for (j = i, l = vcolor = 0; (j < (int)m3d->numface) && (mi == m3d->face[j].materialid); j++, l++)
   6435                 {
   6436                     if (!m3d->vertex[m3d->face[j].vertex[0]].color ||
   6437                         !m3d->vertex[m3d->face[j].vertex[1]].color ||
   6438                         !m3d->vertex[m3d->face[j].vertex[2]].color) vcolor = 1;
   6439                 }
   6440 
   6441                 model.meshes[k].vertexCount = l*3;
   6442                 model.meshes[k].triangleCount = l;
   6443                 model.meshes[k].vertices = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
   6444                 model.meshes[k].texcoords = (float *)RL_CALLOC(model.meshes[k].vertexCount*2, sizeof(float));
   6445                 model.meshes[k].normals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
   6446 
   6447                 // If no map is provided, or we have colors defined, we allocate storage for vertex colors
   6448                 // M3D specs only consider vertex colors if no material is provided, however raylib uses both and mixes the colors
   6449                 if ((mi == M3D_UNDEF) || vcolor) model.meshes[k].colors = RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
   6450 
   6451                 // If no map is provided and we allocated vertex colors, set them to white
   6452                 if ((mi == M3D_UNDEF) && (model.meshes[k].colors != NULL))
   6453                 {
   6454                     for (int c = 0; c < model.meshes[k].vertexCount*4; c++) model.meshes[k].colors[c] = 255;
   6455                 }
   6456 
   6457                 if (m3d->numbone && m3d->numskin)
   6458                 {
   6459                     model.meshes[k].boneIds = (unsigned char *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
   6460                     model.meshes[k].boneWeights = (float *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(float));
   6461                     model.meshes[k].animVertices = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
   6462                     model.meshes[k].animNormals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
   6463                 }
   6464 
   6465                 model.meshMaterial[k] = mi + 1;
   6466                 l = 0;
   6467             }
   6468 
   6469             // Process meshes per material, add triangles
   6470             model.meshes[k].vertices[l*9 + 0] = m3d->vertex[m3d->face[i].vertex[0]].x*m3d->scale;
   6471             model.meshes[k].vertices[l*9 + 1] = m3d->vertex[m3d->face[i].vertex[0]].y*m3d->scale;
   6472             model.meshes[k].vertices[l*9 + 2] = m3d->vertex[m3d->face[i].vertex[0]].z*m3d->scale;
   6473             model.meshes[k].vertices[l*9 + 3] = m3d->vertex[m3d->face[i].vertex[1]].x*m3d->scale;
   6474             model.meshes[k].vertices[l*9 + 4] = m3d->vertex[m3d->face[i].vertex[1]].y*m3d->scale;
   6475             model.meshes[k].vertices[l*9 + 5] = m3d->vertex[m3d->face[i].vertex[1]].z*m3d->scale;
   6476             model.meshes[k].vertices[l*9 + 6] = m3d->vertex[m3d->face[i].vertex[2]].x*m3d->scale;
   6477             model.meshes[k].vertices[l*9 + 7] = m3d->vertex[m3d->face[i].vertex[2]].y*m3d->scale;
   6478             model.meshes[k].vertices[l*9 + 8] = m3d->vertex[m3d->face[i].vertex[2]].z*m3d->scale;
   6479 
   6480             // Without vertex color (full transparency), we use the default color
   6481             if (model.meshes[k].colors != NULL)
   6482             {
   6483                 if (m3d->vertex[m3d->face[i].vertex[0]].color & 0xFF000000)
   6484                     memcpy(&model.meshes[k].colors[l*12 + 0], &m3d->vertex[m3d->face[i].vertex[0]].color, 4);
   6485                 if (m3d->vertex[m3d->face[i].vertex[1]].color & 0xFF000000)
   6486                     memcpy(&model.meshes[k].colors[l*12 + 4], &m3d->vertex[m3d->face[i].vertex[1]].color, 4);
   6487                 if (m3d->vertex[m3d->face[i].vertex[2]].color & 0xFF000000)
   6488                     memcpy(&model.meshes[k].colors[l*12 + 8], &m3d->vertex[m3d->face[i].vertex[2]].color, 4);
   6489             }
   6490 
   6491             if (m3d->face[i].texcoord[0] != M3D_UNDEF)
   6492             {
   6493                 model.meshes[k].texcoords[l*6 + 0] = m3d->tmap[m3d->face[i].texcoord[0]].u;
   6494                 model.meshes[k].texcoords[l*6 + 1] = 1.0f - m3d->tmap[m3d->face[i].texcoord[0]].v;
   6495                 model.meshes[k].texcoords[l*6 + 2] = m3d->tmap[m3d->face[i].texcoord[1]].u;
   6496                 model.meshes[k].texcoords[l*6 + 3] = 1.0f - m3d->tmap[m3d->face[i].texcoord[1]].v;
   6497                 model.meshes[k].texcoords[l*6 + 4] = m3d->tmap[m3d->face[i].texcoord[2]].u;
   6498                 model.meshes[k].texcoords[l*6 + 5] = 1.0f - m3d->tmap[m3d->face[i].texcoord[2]].v;
   6499             }
   6500 
   6501             if (m3d->face[i].normal[0] != M3D_UNDEF)
   6502             {
   6503                 model.meshes[k].normals[l*9 + 0] = m3d->vertex[m3d->face[i].normal[0]].x;
   6504                 model.meshes[k].normals[l*9 + 1] = m3d->vertex[m3d->face[i].normal[0]].y;
   6505                 model.meshes[k].normals[l*9 + 2] = m3d->vertex[m3d->face[i].normal[0]].z;
   6506                 model.meshes[k].normals[l*9 + 3] = m3d->vertex[m3d->face[i].normal[1]].x;
   6507                 model.meshes[k].normals[l*9 + 4] = m3d->vertex[m3d->face[i].normal[1]].y;
   6508                 model.meshes[k].normals[l*9 + 5] = m3d->vertex[m3d->face[i].normal[1]].z;
   6509                 model.meshes[k].normals[l*9 + 6] = m3d->vertex[m3d->face[i].normal[2]].x;
   6510                 model.meshes[k].normals[l*9 + 7] = m3d->vertex[m3d->face[i].normal[2]].y;
   6511                 model.meshes[k].normals[l*9 + 8] = m3d->vertex[m3d->face[i].normal[2]].z;
   6512             }
   6513 
   6514             // Add skin (vertex / bone weight pairs)
   6515             if (m3d->numbone && m3d->numskin)
   6516             {
   6517                 for (n = 0; n < 3; n++)
   6518                 {
   6519                     int skinid = m3d->vertex[m3d->face[i].vertex[n]].skinid;
   6520 
   6521                     // Check if there is a skin for this mesh, should be, just failsafe
   6522                     if ((skinid != M3D_UNDEF) && (skinid < (int)m3d->numskin))
   6523                     {
   6524                         for (j = 0; j < 4; j++)
   6525                         {
   6526                             model.meshes[k].boneIds[l*12 + n*4 + j] = m3d->skin[skinid].boneid[j];
   6527                             model.meshes[k].boneWeights[l*12 + n*4 + j] = m3d->skin[skinid].weight[j];
   6528                         }
   6529                     }
   6530                     else
   6531                     {
   6532                         // raylib does not handle boneless meshes with skeletal animations, so
   6533                         // we put all vertices without a bone into a special "no bone" bone
   6534                         model.meshes[k].boneIds[l*12 + n*4] = m3d->numbone;
   6535                         model.meshes[k].boneWeights[l*12 + n*4] = 1.0f;
   6536                     }
   6537                 }
   6538             }
   6539         }
   6540 
   6541         // Load materials
   6542         for (i = 0; i < (int)m3d->nummaterial; i++)
   6543         {
   6544             model.materials[i + 1] = LoadMaterialDefault();
   6545 
   6546             for (j = 0; j < m3d->material[i].numprop; j++)
   6547             {
   6548                 prop = &m3d->material[i].prop[j];
   6549 
   6550                 switch (prop->type)
   6551                 {
   6552                     case m3dp_Kd:
   6553                     {
   6554                         memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].color, &prop->value.color, 4);
   6555                         model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f;
   6556                     } break;
   6557                     case m3dp_Ks:
   6558                     {
   6559                         memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].color, &prop->value.color, 4);
   6560                     } break;
   6561                     case m3dp_Ns:
   6562                     {
   6563                         model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].value = prop->value.fnum;
   6564                     } break;
   6565                     case m3dp_Ke:
   6566                     {
   6567                         memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].color, &prop->value.color, 4);
   6568                         model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].value = 0.0f;
   6569                     } break;
   6570                     case m3dp_Pm:
   6571                     {
   6572                         model.materials[i + 1].maps[MATERIAL_MAP_METALNESS].value = prop->value.fnum;
   6573                     } break;
   6574                     case m3dp_Pr:
   6575                     {
   6576                         model.materials[i + 1].maps[MATERIAL_MAP_ROUGHNESS].value = prop->value.fnum;
   6577                     } break;
   6578                     case m3dp_Ps:
   6579                     {
   6580                         model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].color = WHITE;
   6581                         model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].value = prop->value.fnum;
   6582                     } break;
   6583                     default:
   6584                     {
   6585                         if (prop->type >= 128)
   6586                         {
   6587                             Image image = { 0 };
   6588                             image.data = m3d->texture[prop->value.textureid].d;
   6589                             image.width = m3d->texture[prop->value.textureid].w;
   6590                             image.height = m3d->texture[prop->value.textureid].h;
   6591                             image.mipmaps = 1;
   6592                             image.format = (m3d->texture[prop->value.textureid].f == 4)? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 :
   6593                                            ((m3d->texture[prop->value.textureid].f == 3)? PIXELFORMAT_UNCOMPRESSED_R8G8B8 :
   6594                                            ((m3d->texture[prop->value.textureid].f == 2)? PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA : PIXELFORMAT_UNCOMPRESSED_GRAYSCALE));
   6595 
   6596                             switch (prop->type)
   6597                             {
   6598                                 case m3dp_map_Kd: model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTextureFromImage(image); break;
   6599                                 case m3dp_map_Ks: model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].texture = LoadTextureFromImage(image); break;
   6600                                 case m3dp_map_Ke: model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].texture = LoadTextureFromImage(image); break;
   6601                                 case m3dp_map_Km: model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].texture = LoadTextureFromImage(image); break;
   6602                                 case m3dp_map_Ka: model.materials[i + 1].maps[MATERIAL_MAP_OCCLUSION].texture = LoadTextureFromImage(image); break;
   6603                                 case m3dp_map_Pm: model.materials[i + 1].maps[MATERIAL_MAP_ROUGHNESS].texture = LoadTextureFromImage(image); break;
   6604                                 default: break;
   6605                             }
   6606                         }
   6607                     } break;
   6608                 }
   6609             }
   6610         }
   6611 
   6612         // Load bones
   6613         if (m3d->numbone)
   6614         {
   6615             model.boneCount = m3d->numbone + 1;
   6616             model.bones = RL_CALLOC(model.boneCount, sizeof(BoneInfo));
   6617             model.bindPose = RL_CALLOC(model.boneCount, sizeof(Transform));
   6618 
   6619             for (i = 0; i < (int)m3d->numbone; i++)
   6620             {
   6621                 model.bones[i].parent = m3d->bone[i].parent;
   6622                 strncpy(model.bones[i].name, m3d->bone[i].name, sizeof(model.bones[i].name));
   6623                 model.bindPose[i].translation.x = m3d->vertex[m3d->bone[i].pos].x*m3d->scale;
   6624                 model.bindPose[i].translation.y = m3d->vertex[m3d->bone[i].pos].y*m3d->scale;
   6625                 model.bindPose[i].translation.z = m3d->vertex[m3d->bone[i].pos].z*m3d->scale;
   6626                 model.bindPose[i].rotation.x = m3d->vertex[m3d->bone[i].ori].x;
   6627                 model.bindPose[i].rotation.y = m3d->vertex[m3d->bone[i].ori].y;
   6628                 model.bindPose[i].rotation.z = m3d->vertex[m3d->bone[i].ori].z;
   6629                 model.bindPose[i].rotation.w = m3d->vertex[m3d->bone[i].ori].w;
   6630 
   6631                 // TODO: If the orientation quaternion is not normalized, then that's encoding scaling
   6632                 model.bindPose[i].rotation = QuaternionNormalize(model.bindPose[i].rotation);
   6633                 model.bindPose[i].scale.x = model.bindPose[i].scale.y = model.bindPose[i].scale.z = 1.0f;
   6634 
   6635                 // Child bones are stored in parent bone relative space, convert that into model space
   6636                 if (model.bones[i].parent >= 0)
   6637                 {
   6638                     model.bindPose[i].rotation = QuaternionMultiply(model.bindPose[model.bones[i].parent].rotation, model.bindPose[i].rotation);
   6639                     model.bindPose[i].translation = Vector3RotateByQuaternion(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].rotation);
   6640                     model.bindPose[i].translation = Vector3Add(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].translation);
   6641                     model.bindPose[i].scale = Vector3Multiply(model.bindPose[i].scale, model.bindPose[model.bones[i].parent].scale);
   6642                 }
   6643             }
   6644 
   6645             // Add a special "no bone" bone
   6646             model.bones[i].parent = -1;
   6647             strcpy(model.bones[i].name, "NO BONE");
   6648             model.bindPose[i].translation.x = 0.0f;
   6649             model.bindPose[i].translation.y = 0.0f;
   6650             model.bindPose[i].translation.z = 0.0f;
   6651             model.bindPose[i].rotation.x = 0.0f;
   6652             model.bindPose[i].rotation.y = 0.0f;
   6653             model.bindPose[i].rotation.z = 0.0f;
   6654             model.bindPose[i].rotation.w = 1.0f;
   6655             model.bindPose[i].scale.x = model.bindPose[i].scale.y = model.bindPose[i].scale.z = 1.0f;
   6656         }
   6657 
   6658         // Load bone-pose default mesh into animation vertices. These will be updated when UpdateModelAnimation gets
   6659         // called, but not before, however DrawMesh uses these if they exist (so not good if they are left empty)
   6660         if (m3d->numbone && m3d->numskin)
   6661         {
   6662             for (i = 0; i < model.meshCount; i++)
   6663             {
   6664                 memcpy(model.meshes[i].animVertices, model.meshes[i].vertices, model.meshes[i].vertexCount*3*sizeof(float));
   6665                 memcpy(model.meshes[i].animNormals, model.meshes[i].normals, model.meshes[i].vertexCount*3*sizeof(float));
   6666 
   6667                 model.meshes[i].boneCount = model.boneCount;
   6668                 model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
   6669                 for (j = 0; j < model.meshes[i].boneCount; j++)
   6670                 {
   6671                     model.meshes[i].boneMatrices[j] = MatrixIdentity();
   6672                 }
   6673             }
   6674         }
   6675 
   6676         m3d_free(m3d);
   6677         UnloadFileData(fileData);
   6678     }
   6679 
   6680     return model;
   6681 }
   6682 
   6683 #define M3D_ANIMDELAY 17    // Animation frames delay, (~1000 ms/60 FPS = 16.666666* ms)
   6684 
   6685 // Load M3D animation data
   6686 static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCount)
   6687 {
   6688     ModelAnimation *animations = NULL;
   6689 
   6690     m3d_t *m3d = NULL;
   6691     int i = 0, j = 0;
   6692     *animCount = 0;
   6693 
   6694     int dataSize = 0;
   6695     unsigned char *fileData = LoadFileData(fileName, &dataSize);
   6696 
   6697     if (fileData != NULL)
   6698     {
   6699         m3d = m3d_load(fileData, m3d_loaderhook, m3d_freehook, NULL);
   6700 
   6701         if (!m3d || M3D_ERR_ISFATAL(m3d->errcode))
   6702         {
   6703             TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load M3D data, error code %d", fileName, m3d? m3d->errcode : -2);
   6704             UnloadFileData(fileData);
   6705             return NULL;
   6706         }
   6707         else TRACELOG(LOG_INFO, "MODEL: [%s] M3D data loaded successfully: %i animations, %i bones, %i skins", fileName,
   6708             m3d->numaction, m3d->numbone, m3d->numskin);
   6709 
   6710         // No animation or bone+skin?
   6711         if (!m3d->numaction || !m3d->numbone || !m3d->numskin)
   6712         {
   6713             m3d_free(m3d);
   6714             UnloadFileData(fileData);
   6715             return NULL;
   6716         }
   6717 
   6718         animations = RL_MALLOC(m3d->numaction*sizeof(ModelAnimation));
   6719         *animCount = m3d->numaction;
   6720 
   6721         for (unsigned int a = 0; a < m3d->numaction; a++)
   6722         {
   6723             animations[a].frameCount = m3d->action[a].durationmsec/M3D_ANIMDELAY;
   6724             animations[a].boneCount = m3d->numbone + 1;
   6725             animations[a].bones = RL_MALLOC((m3d->numbone + 1)*sizeof(BoneInfo));
   6726             animations[a].framePoses = RL_MALLOC(animations[a].frameCount*sizeof(Transform *));
   6727             strncpy(animations[a].name, m3d->action[a].name, sizeof(animations[a].name));
   6728             animations[a].name[sizeof(animations[a].name) - 1] = '\0';
   6729 
   6730             TRACELOG(LOG_INFO, "MODEL: [%s] animation #%i: %i msec, %i frames", fileName, a, m3d->action[a].durationmsec, animations[a].frameCount);
   6731 
   6732             for (i = 0; i < (int)m3d->numbone; i++)
   6733             {
   6734                 animations[a].bones[i].parent = m3d->bone[i].parent;
   6735                 strncpy(animations[a].bones[i].name, m3d->bone[i].name, sizeof(animations[a].bones[i].name));
   6736             }
   6737 
   6738             // A special, never transformed "no bone" bone, used for boneless vertices
   6739             animations[a].bones[i].parent = -1;
   6740             strcpy(animations[a].bones[i].name, "NO BONE");
   6741 
   6742             // M3D stores frames at arbitrary intervals with sparse skeletons. We need full skeletons at
   6743             // regular intervals, so let the M3D SDK do the heavy lifting and calculate interpolated bones
   6744             for (i = 0; i < animations[a].frameCount; i++)
   6745             {
   6746                 animations[a].framePoses[i] = RL_MALLOC((m3d->numbone + 1)*sizeof(Transform));
   6747 
   6748                 m3db_t *pose = m3d_pose(m3d, a, i*M3D_ANIMDELAY);
   6749 
   6750                 if (pose != NULL)
   6751                 {
   6752                     for (j = 0; j < (int)m3d->numbone; j++)
   6753                     {
   6754                         animations[a].framePoses[i][j].translation.x = m3d->vertex[pose[j].pos].x*m3d->scale;
   6755                         animations[a].framePoses[i][j].translation.y = m3d->vertex[pose[j].pos].y*m3d->scale;
   6756                         animations[a].framePoses[i][j].translation.z = m3d->vertex[pose[j].pos].z*m3d->scale;
   6757                         animations[a].framePoses[i][j].rotation.x = m3d->vertex[pose[j].ori].x;
   6758                         animations[a].framePoses[i][j].rotation.y = m3d->vertex[pose[j].ori].y;
   6759                         animations[a].framePoses[i][j].rotation.z = m3d->vertex[pose[j].ori].z;
   6760                         animations[a].framePoses[i][j].rotation.w = m3d->vertex[pose[j].ori].w;
   6761                         animations[a].framePoses[i][j].rotation = QuaternionNormalize(animations[a].framePoses[i][j].rotation);
   6762                         animations[a].framePoses[i][j].scale.x = animations[a].framePoses[i][j].scale.y = animations[a].framePoses[i][j].scale.z = 1.0f;
   6763 
   6764                         // Child bones are stored in parent bone relative space, convert that into model space
   6765                         if (animations[a].bones[j].parent >= 0)
   6766                         {
   6767                             animations[a].framePoses[i][j].rotation = QuaternionMultiply(animations[a].framePoses[i][animations[a].bones[j].parent].rotation, animations[a].framePoses[i][j].rotation);
   6768                             animations[a].framePoses[i][j].translation = Vector3RotateByQuaternion(animations[a].framePoses[i][j].translation, animations[a].framePoses[i][animations[a].bones[j].parent].rotation);
   6769                             animations[a].framePoses[i][j].translation = Vector3Add(animations[a].framePoses[i][j].translation, animations[a].framePoses[i][animations[a].bones[j].parent].translation);
   6770                             animations[a].framePoses[i][j].scale = Vector3Multiply(animations[a].framePoses[i][j].scale, animations[a].framePoses[i][animations[a].bones[j].parent].scale);
   6771                         }
   6772                     }
   6773 
   6774                     // Default transform for the "no bone" bone
   6775                     animations[a].framePoses[i][j].translation.x = 0.0f;
   6776                     animations[a].framePoses[i][j].translation.y = 0.0f;
   6777                     animations[a].framePoses[i][j].translation.z = 0.0f;
   6778                     animations[a].framePoses[i][j].rotation.x = 0.0f;
   6779                     animations[a].framePoses[i][j].rotation.y = 0.0f;
   6780                     animations[a].framePoses[i][j].rotation.z = 0.0f;
   6781                     animations[a].framePoses[i][j].rotation.w = 1.0f;
   6782                     animations[a].framePoses[i][j].scale.x = animations[a].framePoses[i][j].scale.y = animations[a].framePoses[i][j].scale.z = 1.0f;
   6783                     RL_FREE(pose);
   6784                 }
   6785             }
   6786         }
   6787 
   6788         m3d_free(m3d);
   6789         UnloadFileData(fileData);
   6790     }
   6791 
   6792     return animations;
   6793 }
   6794 #endif
   6795 
   6796 #endif      // SUPPORT_MODULE_RMODELS