github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/tests/raylib/rmodels.c (about)

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