summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--examples/models/resources/models/cube.obj44
-rw-r--r--projects/VS2017/examples/core_basic_window.vcxproj2
-rw-r--r--projects/VS2017/examples/core_basic_window_cpp.vcxproj2
-rw-r--r--projects/VS2017/raylib/raylib.vcxproj2
-rw-r--r--src/config.h6
-rw-r--r--src/external/tinyobj_loader_c.h9
-rw-r--r--src/models.c586
-rw-r--r--src/raylib.h45
-rw-r--r--src/rlgl.h39
9 files changed, 564 insertions, 171 deletions
diff --git a/examples/models/resources/models/cube.obj b/examples/models/resources/models/cube.obj
index 0e9d6597..bf7e3bee 100644
--- a/examples/models/resources/models/cube.obj
+++ b/examples/models/resources/models/cube.obj
@@ -1,7 +1,7 @@
# reference material
-mtllib myCube.mtl
+#mtllib cube.mtl
-# object Pau_Box
+# object box
# vertex (XZY)
v 5.5 0 1.5
@@ -14,85 +14,55 @@ v 5.5 3 -1.5
v 8.5 3 -1.5
# normals (XYZ)
-# red
vn 0 -1 0
-#blue
vn 0 1 0
-#top
vn 0 0 1
-#yellow
vn 1 0 0
-#bottom
vn 0 0 -1
-#green
vn -1 0 0
-
# UVs (XY)
-# yellow (1234)
vt 0.5 0 0
vt 1 0 0
vt 1 0.5 0
vt 0.5 0.5 0
-# red (5678)
vt 0.5 0.5 0
vt 1 0.5 0
vt 0.5 1 0
vt 1 1 0
-#bottom (9101112)
vt 0 0.5 0
vt 1 0.5 0
vt 1 0 0
vt 0 0 0
-#top (13141516)
vt 0 0.5 0
vt 1 0.5 0
vt 1 1 0
vt 0 1 0
-#green (17181920)
vt 0.5 0 0
vt 0 0 0
vt 0 0.5 0
vt 0.5 0.5 0
-#blue (21222324)
vt 0 0.5 0
vt 0.5 0.5 0
vt 0.5 1 0
vt 0 1 0
# merger
-g Pau_Box
+g box
# reference material
-usemtl Material_1
-
-# bottom
-f 1/9/1 3/10/1 4/11/1
-f 4/11/1 2/12/1 1/9/1
+#usemtl mat01
-# top
+# faces
+f 1/9/1 3/10/1 4/11/1
+f 4/11/1 2/12/1 1/9/1
f 5/13/2 6/14/2 8/15/2
f 8/15/2 7/16/2 5/13/2
-
-# front-yellow
f 1/17/6 2/18/6 6/19/6
f 6/19/6 5/20/6 1/17/6
-
-# right-blue
f 2/6/1 4/5/1 8/7/1
f 8/7/1 6/8/1 2/6/1
-
-# back-green
f 4/2/3 3/1/3 7/4/3
f 7/4/3 8/3/3 4/2/3
-
-# left-red
f 3/22/5 1/21/5 5/24/5
f 5/24/5 7/23/5 3/22/5
-
-
-
-
-
-
-
diff --git a/projects/VS2017/examples/core_basic_window.vcxproj b/projects/VS2017/examples/core_basic_window.vcxproj
index 48e06e44..87bef8d8 100644
--- a/projects/VS2017/examples/core_basic_window.vcxproj
+++ b/projects/VS2017/examples/core_basic_window.vcxproj
@@ -22,7 +22,7 @@
<ProjectGuid>{0981CA98-E4A5-4DF1-987F-A41D09131EFC}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>core_basic_window</RootNamespace>
- <WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>
+ <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
<ProjectName>core_basic_window</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
diff --git a/projects/VS2017/examples/core_basic_window_cpp.vcxproj b/projects/VS2017/examples/core_basic_window_cpp.vcxproj
index 39a2aee7..cfe08524 100644
--- a/projects/VS2017/examples/core_basic_window_cpp.vcxproj
+++ b/projects/VS2017/examples/core_basic_window_cpp.vcxproj
@@ -22,7 +22,7 @@
<ProjectGuid>{B655E850-3322-42F7-941D-6AC18FD66CA1}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>raylib_example_cpp</RootNamespace>
- <WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>
+ <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
<ProjectName>core_basic_window_cpp</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
diff --git a/projects/VS2017/raylib/raylib.vcxproj b/projects/VS2017/raylib/raylib.vcxproj
index 4c620053..3ff77104 100644
--- a/projects/VS2017/raylib/raylib.vcxproj
+++ b/projects/VS2017/raylib/raylib.vcxproj
@@ -22,7 +22,7 @@
<ProjectGuid>{E89D61AC-55DE-4482-AFD4-DF7242EBC859}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>raylib</RootNamespace>
- <WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>
+ <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
diff --git a/src/config.h b/src/config.h
index d45ff707..4174ed71 100644
--- a/src/config.h
+++ b/src/config.h
@@ -66,10 +66,10 @@
//------------------------------------------------------------------------------------
// Draw rectangle shapes using font texture white character instead of default white texture
// Allows drawing rectangles and text with a single draw call, very useful for GUI systems!
-#define SUPPORT_FONT_TEXTURE
+#define SUPPORT_FONT_TEXTURE 1
// Use QUADS instead of TRIANGLES for drawing when possible
// Some lines-based shapes could still use lines
-#define SUPPORT_QUADS_DRAW_MODE
+#define SUPPORT_QUADS_DRAW_MODE 1
//------------------------------------------------------------------------------------
// Module: textures - Configuration Flags
@@ -114,6 +114,8 @@
// Selected desired model fileformats to be supported for loading
#define SUPPORT_FILEFORMAT_OBJ 1
#define SUPPORT_FILEFORMAT_MTL 1
+#define SUPPORT_FILEFORMAT_IQM 1
+#define SUPPORT_FILEFORMAT_GLTF 1
// Support procedural mesh generation functions, uses external par_shapes.h library
// NOTE: Some generated meshes DO NOT include generated texture coordinates
#define SUPPORT_MESH_GENERATION 1
diff --git a/src/external/tinyobj_loader_c.h b/src/external/tinyobj_loader_c.h
index e9d015ff..ae975829 100644
--- a/src/external/tinyobj_loader_c.h
+++ b/src/external/tinyobj_loader_c.h
@@ -1342,12 +1342,13 @@ int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
attrib->num_normals = (unsigned int)num_vn;
attrib->texcoords = (float *)TINYOBJ_MALLOC(sizeof(float) * num_vt * 2);
attrib->num_texcoords = (unsigned int)num_vt;
- attrib->faces = (tinyobj_vertex_index_t *)TINYOBJ_MALLOC(
- sizeof(tinyobj_vertex_index_t) * num_f);
- attrib->num_faces = (unsigned int)num_f;
+ attrib->faces = (tinyobj_vertex_index_t *)TINYOBJ_MALLOC(sizeof(tinyobj_vertex_index_t) * num_f);
attrib->face_num_verts = (int *)TINYOBJ_MALLOC(sizeof(int) * num_faces);
+
+ attrib->num_faces = (unsigned int)num_faces;
+ attrib->num_face_num_verts = (unsigned int)num_f;
+
attrib->material_ids = (int *)TINYOBJ_MALLOC(sizeof(int) * num_faces);
- attrib->num_face_num_verts = (unsigned int)num_faces;
for (i = 0; i < num_lines; i++) {
if (commands[i].type == COMMAND_EMPTY) {
diff --git a/src/models.c b/src/models.c
index 2893fd2f..632aca2b 100644
--- a/src/models.c
+++ b/src/models.c
@@ -57,11 +57,6 @@
#include "external/tinyobj_loader_c.h" // OBJ/MTL file formats loading
#endif
-#if defined(SUPPORT_FILEFORMAT_IQM)
- #define RIQM_IMPLEMENTATION
- #include "external/riqm.h" // IQM file format loading
-#endif
-
#if defined(SUPPORT_FILEFORMAT_GLTF)
#define CGLTF_IMPLEMENTATION
#include "external/cgltf.h" // glTF file format loading
@@ -629,22 +624,30 @@ Model LoadModel(const char *fileName)
#if defined(SUPPORT_FILEFORMAT_IQM)
if (IsFileExtension(fileName, ".iqm")) model = LoadIQM(fileName);
#endif
+
+ // Make sure model transform is set to identity matrix!
+ model.transform = MatrixIdentity();
if (model.meshCount == 0)
{
TraceLog(LOG_WARNING, "[%s] No meshes can be loaded, default to cube mesh", fileName);
model.meshCount = 1;
- model.meshes = (Mesh *)malloc(model.meshCount*sizeof(Mesh));
+ model.meshes = (Mesh *)calloc(model.meshCount, sizeof(Mesh));
model.meshes[0] = GenMeshCube(1.0f, 1.0f, 1.0f);
}
-
+ else
+ {
+ // Upload vertex data to GPU (static mesh)
+ for (int i = 0; i < model.meshCount; i++) rlLoadMesh(&model.meshes[i], false);
+ }
+
if (model.materialCount == 0)
{
TraceLog(LOG_WARNING, "[%s] No materials can be loaded, default to white material", fileName);
model.materialCount = 1;
- model.materials = (Material *)malloc(model.materialCount*sizeof(Material));
+ model.materials = (Material *)calloc(model.materialCount, sizeof(Material));
model.materials[0] = LoadMaterialDefault();
model.meshMaterial = (int *)calloc(model.meshCount, sizeof(int));
@@ -682,31 +685,16 @@ void UnloadModel(Model model)
{
for (int i = 0; i < model.meshCount; i++) UnloadMesh(&model.meshes[i]);
for (int i = 0; i < model.materialCount; i++) UnloadMaterial(model.materials[i]);
+
+ free(model.meshes);
+ free(model.materials);
free(model.meshMaterial);
-
- TraceLog(LOG_INFO, "Unloaded model data from RAM and VRAM");
-}
-
-// Load mesh from file
-// NOTE: Mesh data loaded in CPU and GPU
-Mesh LoadMesh(const char *fileName)
-{
- Mesh mesh = { 0 };
-
- // TODO: Review this function, should still exist?
-#if defined(SUPPORT_MESH_GENERATION)
- if (mesh.vertexCount == 0)
- {
- TraceLog(LOG_WARNING, "Mesh could not be loaded! Let's load a cube to replace it!");
- mesh = GenMeshCube(1.0f, 1.0f, 1.0f);
- }
- else rlLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh)
-#else
- rlLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh)
-#endif
+ // Unload animation data
+ free(model.bones);
+ free(model.bindPose);
- return mesh;
+ TraceLog(LOG_INFO, "Unloaded model data from RAM and VRAM");
}
// Unload mesh from memory (RAM and/or VRAM)
@@ -1879,7 +1867,7 @@ void UnloadMaterial(Material material)
void DrawModel(Model model, Vector3 position, float scale, Color tint)
{
Vector3 vScale = { scale, scale, scale };
- Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f };
+ Vector3 rotationAxis = { 0.0f, 1.0f, 0.0f };
DrawModelEx(model, position, rotationAxis, 0.0f, vScale, tint);
}
@@ -1896,8 +1884,6 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota
Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
// Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform)
- //Matrix matModel = MatrixMultiply(model.transform, matTransform); // Transform to world-space coordinates
-
model.transform = MatrixMultiply(model.transform, matTransform);
for (int i = 0; i < model.meshCount; i++)
@@ -2126,25 +2112,25 @@ RayHitInfo GetCollisionRayModel(Ray ray, Model *model)
{
RayHitInfo result = { 0 };
- for (int i = 0; i < model->meshCount; i++)
+ for (int m = 0; m < model->meshCount; m++)
{
// Check if meshhas vertex data on CPU for testing
- if (model->meshes[i].vertices != NULL)
+ if (model->meshes[m].vertices != NULL)
{
// model->mesh.triangleCount may not be set, vertexCount is more reliable
- int triangleCount = model->meshes[i].vertexCount/3;
+ int triangleCount = model->meshes[m].vertexCount/3;
// Test against all triangles in mesh
for (int i = 0; i < triangleCount; i++)
{
Vector3 a, b, c;
- Vector3 *vertdata = (Vector3 *)model->meshes[i].vertices;
+ Vector3 *vertdata = (Vector3 *)model->meshes[m].vertices;
- if (model->meshes[i].indices)
+ if (model->meshes[m].indices)
{
- a = vertdata[model->meshes[i].indices[i*3 + 0]];
- b = vertdata[model->meshes[i].indices[i*3 + 1]];
- c = vertdata[model->meshes[i].indices[i*3 + 2]];
+ a = vertdata[model->meshes[m].indices[i*3 + 0]];
+ b = vertdata[model->meshes[m].indices[i*3 + 1]];
+ c = vertdata[model->meshes[m].indices[i*3 + 2]];
}
else
{
@@ -2260,6 +2246,8 @@ BoundingBox MeshBoundingBox(Mesh mesh)
// Get min and max vertex to construct bounds (AABB)
Vector3 minVertex = { 0 };
Vector3 maxVertex = { 0 };
+
+ printf("Mesh vertex count: %i\n", mesh.vertexCount);
if (mesh.vertices != NULL)
{
@@ -2274,7 +2262,7 @@ BoundingBox MeshBoundingBox(Mesh mesh)
}
// Create the bounding box
- BoundingBox box;
+ BoundingBox box = { 0 };
box.min = minVertex;
box.max = maxVertex;
@@ -2383,97 +2371,160 @@ void MeshBinormals(Mesh *mesh)
static Model LoadOBJ(const char *fileName)
{
Model model = { 0 };
-
+
tinyobj_attrib_t attrib;
tinyobj_shape_t *meshes = NULL;
unsigned int meshCount = 0;
-
+
tinyobj_material_t *materials = NULL;
unsigned int materialCount = 0;
int dataLength = 0;
char *data = NULL;
-
+
// Load model data
FILE *objFile = fopen(fileName, "rb");
if (objFile != NULL)
{
fseek(objFile, 0, SEEK_END);
- long dataLength = ftell(objFile); // Get file size
- fseek(objFile, 0, SEEK_SET); // Reset file pointer
+ long length = ftell(objFile); // Get file size
+ fseek(objFile, 0, SEEK_SET); // Reset file pointer
- data = (char *)malloc(dataLength);
+ data = (char *)malloc(length);
- fread(data, dataLength, 1, objFile);
+ fread(data, length, 1, objFile);
+ dataLength = length;
fclose(objFile);
}
- if (data != NULL)
+ if (data != NULL)
{
unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;
int ret = tinyobj_parse_obj(&attrib, &meshes, &meshCount, &materials, &materialCount, data, dataLength, flags);
if (ret != TINYOBJ_SUCCESS) TraceLog(LOG_WARNING, "[%s] Model data could not be loaded", fileName);
else TraceLog(LOG_INFO, "[%s] Model data loaded successfully: %i meshes / %i materials", fileName, meshCount, materialCount);
-
- for (int i = 0; i < meshCount; i++)
- {
- printf("shape[%d] name = %s\n", i, meshes[i].name);
- }
+
+ // Init model meshes array
+ model.meshCount = meshCount;
+ model.meshes = (Mesh *)malloc(model.meshCount*sizeof(Mesh));
+
+ // Init model materials array
+ model.materialCount = materialCount;
+ model.materials = (Material *)malloc(model.materialCount*sizeof(Material));
+ model.meshMaterial = (int *)calloc(model.meshCount, sizeof(int));
/*
- // Data reference to process
- typedef struct {
- char *name;
-
- float ambient[3];
- float diffuse[3];
- float specular[3];
- float transmittance[3];
- float emission[3];
- float shininess;
- float ior; // index of refraction
- float dissolve; // 1 == opaque; 0 == fully transparent
- // illumination model (see http://www.fileformat.info/format/material/)
- int illum;
-
- int pad0;
-
- char *ambient_texname; // map_Ka
- char *diffuse_texname; // map_Kd
- char *specular_texname; // map_Ks
- char *specular_highlight_texname; // map_Ns
- char *bump_texname; // map_bump, bump
- char *displacement_texname; // disp
- char *alpha_texname; // map_d
- } tinyobj_material_t;
-
+ // Multiple meshes data reference
+ // NOTE: They are provided as a faces offset
typedef struct {
char *name; // group name or object name
unsigned int face_offset;
unsigned int length;
} tinyobj_shape_t;
+ */
+
+ // Init model meshes
+ for (int m = 0; m < 1; m++)
+ {
+ Mesh mesh = { 0 };
+ memset(&mesh, 0, sizeof(Mesh));
+ mesh.vertexCount = attrib.num_faces*3;
+ mesh.triangleCount = attrib.num_faces;
+ mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float));
+ mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float));
+ mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float));
+
+ int vCount = 0;
+ int vtCount = 0;
+ int vnCount = 0;
+
+ for (int f = 0; f < attrib.num_faces; f++)
+ {
+ // Get indices for the face
+ tinyobj_vertex_index_t idx0 = attrib.faces[3*f + 0];
+ tinyobj_vertex_index_t idx1 = attrib.faces[3*f + 1];
+ tinyobj_vertex_index_t idx2 = attrib.faces[3*f + 2];
+
+ // TraceLog(LOG_DEBUG, "Face %i index: v %i/%i/%i . vt %i/%i/%i . vn %i/%i/%i\n", f, idx0.v_idx, idx1.v_idx, idx2.v_idx, idx0.vt_idx, idx1.vt_idx, idx2.vt_idx, idx0.vn_idx, idx1.vn_idx, idx2.vn_idx);
+
+ // Fill vertices buffer (float) using vertex index of the face
+ for (int v = 0; v < 3; v++) { mesh.vertices[vCount + v] = attrib.vertices[idx0.v_idx*3 + v]; } vCount +=3;
+ for (int v = 0; v < 3; v++) { mesh.vertices[vCount + v] = attrib.vertices[idx1.v_idx*3 + v]; } vCount +=3;
+ for (int v = 0; v < 3; v++) { mesh.vertices[vCount + v] = attrib.vertices[idx2.v_idx*3 + v]; } vCount +=3;
+
+ // Fill texcoords buffer (float) using vertex index of the face
+ // NOTE: Y-coordinate must be flipped upside-down
+ mesh.texcoords[vtCount + 0] = attrib.texcoords[idx0.vt_idx*2 + 0];
+ mesh.texcoords[vtCount + 1] = 1.0f - attrib.texcoords[idx0.vt_idx*2 + 1]; vtCount += 2;
+ mesh.texcoords[vtCount + 0] = attrib.texcoords[idx1.vt_idx*2 + 0];
+ mesh.texcoords[vtCount + 1] = 1.0f - attrib.texcoords[idx1.vt_idx*2 + 1]; vtCount += 2;
+ mesh.texcoords[vtCount + 0] = attrib.texcoords[idx2.vt_idx*2 + 0];
+ mesh.texcoords[vtCount + 1] = 1.0f - attrib.texcoords[idx2.vt_idx*2 + 1]; vtCount += 2;
+
+ // Fill normals buffer (float) using vertex index of the face
+ for (int v = 0; v < 3; v++) { mesh.normals[vnCount + v] = attrib.normals[idx0.vn_idx*3 + v]; } vnCount +=3;
+ for (int v = 0; v < 3; v++) { mesh.normals[vnCount + v] = attrib.normals[idx1.vn_idx*3 + v]; } vnCount +=3;
+ for (int v = 0; v < 3; v++) { mesh.normals[vnCount + v] = attrib.normals[idx2.vn_idx*3 + v]; } vnCount +=3;
+ }
- typedef struct { int v_idx, vt_idx, vn_idx; } tinyobj_vertex_index_t;
+ model.meshes[m] = mesh; // Assign mesh data to model
- typedef struct {
- unsigned int num_vertices;
- unsigned int num_normals;
- unsigned int num_texcoords;
- unsigned int num_faces;
- unsigned int num_face_num_verts;
-
- int pad0;
-
- float *vertices;
- float *normals;
- float *texcoords;
- tinyobj_vertex_index_t *faces;
- int *face_num_verts;
- int *material_ids;
- } tinyobj_attrib_t;
- */
+ // Assign mesh material for current mesh
+ model.meshMaterial[m] = attrib.material_ids[m];
+ }
+
+ // Init model materials
+ for (int m = 0; m < materialCount; m++)
+ {
+ // Init material to default
+ // NOTE: Uses default shader, only MAP_DIFFUSE supported
+ model.materials[m] = LoadMaterialDefault();
+
+ /*
+ typedef struct {
+ char *name;
+
+ float ambient[3];
+ float diffuse[3];
+ float specular[3];
+ float transmittance[3];
+ float emission[3];
+ float shininess;
+ float ior; // index of refraction
+ float dissolve; // 1 == opaque; 0 == fully transparent
+ // illumination model (see http://www.fileformat.info/format/material/)
+ int illum;
+
+ int pad0;
+
+ char *ambient_texname; // map_Ka
+ char *diffuse_texname; // map_Kd
+ char *specular_texname; // map_Ks
+ char *specular_highlight_texname; // map_Ns
+ char *bump_texname; // map_bump, bump
+ char *displacement_texname; // disp
+ char *alpha_texname; // map_d
+ } tinyobj_material_t;
+ */
+
+ model.materials[m].maps[MAP_DIFFUSE].texture = LoadTexture(materials[m].diffuse_texname); //char *diffuse_texname; // map_Kd
+ model.materials[m].maps[MAP_DIFFUSE].color = (Color){ (float)(materials[m].diffuse[0]*255.0f), (float)(materials[m].diffuse[1]*255.0f), (float)(materials[m].diffuse[2]*255.0f), 255 }; //float diffuse[3];
+ model.materials[m].maps[MAP_DIFFUSE].value = 0.0f;
+
+ model.materials[m].maps[MAP_SPECULAR].texture = LoadTexture(materials[m].specular_texname); //char *specular_texname; // map_Ks
+ model.materials[m].maps[MAP_SPECULAR].color = (Color){ (float)(materials[m].specular[0]*255.0f), (float)(materials[m].specular[1]*255.0f), (float)(materials[m].specular[2]*255.0f), 255 }; //float specular[3];
+ model.materials[m].maps[MAP_SPECULAR].value = 0.0f;
+
+ model.materials[m].maps[MAP_NORMAL].texture = LoadTexture(materials[m].bump_texname); //char *bump_texname; // map_bump, bump
+ model.materials[m].maps[MAP_NORMAL].color = WHITE;
+ model.materials[m].maps[MAP_NORMAL].value = materials[m].shininess;
+
+ model.materials[m].maps[MAP_EMISSION].color = (Color){ (float)(materials[m].emission[0]*255.0f), (float)(materials[m].emission[1]*255.0f), (float)(materials[m].emission[2]*255.0f), 255 }; //float emission[3];
+
+ model.materials[m].maps[MAP_HEIGHT].texture = LoadTexture(materials[m].displacement_texname); //char *displacement_texname; // disp
+ }
tinyobj_attrib_free(&attrib);
tinyobj_shapes_free(meshes, meshCount);
@@ -2487,13 +2538,336 @@ static Model LoadOBJ(const char *fileName)
}
#endif
-#if defined(SUPPORT_FILEFORMAT_GLTF)
+#if defined(SUPPORT_FILEFORMAT_IQM)
// Load IQM mesh data
static Model LoadIQM(const char *fileName)
{
+ #define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number
+ #define IQM_VERSION 2 // only IQM version 2 supported
+
+ #define BONE_NAME_LENGTH 32 // BoneInfo name string length
+ #define MESH_NAME_LENGTH 32 // Mesh name string length
+
+ // IQM file structs
+ //-----------------------------------------------------------------------------------
+ typedef struct IQMHeader {
+ char magic[16];
+ unsigned int version;
+ unsigned int filesize;
+ unsigned int flags;
+ unsigned int num_text, ofs_text;
+ unsigned int num_meshes, ofs_meshes;
+ unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
+ unsigned int num_triangles, ofs_triangles, ofs_adjacency;
+ unsigned int num_joints, ofs_joints;
+ unsigned int num_poses, ofs_poses;
+ unsigned int num_anims, ofs_anims;
+ unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
+ unsigned int num_comment, ofs_comment;
+ unsigned int num_extensions, ofs_extensions;
+ } IQMHeader;
+
+ typedef struct IQMMesh {
+ unsigned int name;
+ unsigned int material;
+ unsigned int first_vertex, num_vertexes;
+ unsigned int first_triangle, num_triangles;
+ } IQMMesh;
+
+ typedef struct IQMTriangle {
+ unsigned int vertex[3];
+ } IQMTriangle;
+
+ // NOTE: Adjacency unused by default
+ typedef struct IQMAdjacency {
+ unsigned int triangle[3];
+ } IQMAdjacency;
+
+ typedef struct IQMJoint {
+ unsigned int name;
+ int parent;
+ float translate[3], rotate[4], scale[3];
+ } IQMJoint;
+
+ typedef struct IQMPose {
+ int parent;
+ unsigned int mask;
+ float channeloffset[10];
+ float channelscale[10];
+ } IQMPose;
+
+ typedef struct IQMAnim {
+ unsigned int name;
+ unsigned int first_frame, num_frames;
+ float framerate;
+ unsigned int flags;
+ } IQMAnim;
+
+ typedef struct IQMVertexArray {
+ unsigned int type;
+ unsigned int flags;
+ unsigned int format;
+ unsigned int size;
+ unsigned int offset;
+ } IQMVertexArray;
+
+ // NOTE: Bounds unused by default
+ typedef struct IQMBounds {
+ float bbmin[3], bbmax[3];
+ float xyradius, radius;
+ } IQMBounds;
+ //-----------------------------------------------------------------------------------
+
+ // IQM vertex data types
+ typedef enum {
+ IQM_POSITION = 0,
+ IQM_TEXCOORD = 1,
+ IQM_NORMAL = 2,
+ IQM_TANGENT = 3, // NOTE: Tangents unused by default
+ IQM_BLENDINDEXES = 4,
+ IQM_BLENDWEIGHTS = 5,
+ IQM_COLOR = 6, // NOTE: Vertex colors unused by default
+ IQM_CUSTOM = 0x10 // NOTE: Custom vertex values unused by default
+ } IQMVertexType;
+
Model model = { 0 };
- // TODO: Load IQM file
+ FILE *iqmFile;
+ IQMHeader iqm;
+
+ IQMMesh *imesh;
+ IQMTriangle *tri;
+ IQMVertexArray *va;
+ IQMJoint *ijoint;
+
+ float *vertex = NULL;
+ float *normal = NULL;
+ float *text = NULL;
+ char *blendi = NULL;
+ unsigned char *blendw = NULL;
+
+ iqmFile = fopen(fileName, "rb");
+
+ if (iqmFile == NULL)
+ {
+ TraceLog(LOG_WARNING, "[%s] IQM file could not be opened", fileName);
+ return model;
+ }
+
+ fread(&iqm,sizeof(IQMHeader), 1, iqmFile); // Read IQM header
+
+ if (strncmp(iqm.magic, IQM_MAGIC, sizeof(IQM_MAGIC)))
+ {
+ TraceLog(LOG_WARNING, "[%s] IQM file does not seem to be valid", fileName);
+ fclose(iqmFile);
+ return model;
+ }
+
+ if (iqm.version != IQM_VERSION)
+ {
+ TraceLog(LOG_WARNING, "[%s] IQM file version is not supported (%i).", fileName, iqm.version);
+ fclose(iqmFile);
+ return model;
+ }
+
+ // Meshes data processing
+ imesh = malloc(sizeof(IQMMesh)*iqm.num_meshes);
+ fseek(iqmFile, iqm.ofs_meshes, SEEK_SET);
+ fread(imesh, sizeof(IQMMesh)*iqm.num_meshes, 1, iqmFile);
+
+ model.meshCount = iqm.num_meshes;
+ model.meshes = malloc(sizeof(Mesh)*iqm.num_meshes);
+
+ char name[MESH_NAME_LENGTH];
+
+ for (int i = 0; i < iqm.num_meshes; i++)
+ {
+ fseek(iqmFile,iqm.ofs_text+imesh[i].name,SEEK_SET);
+ fread(name, sizeof(char)*MESH_NAME_LENGTH, 1, iqmFile); // Mesh name not used...
+ model.meshes[i].vertexCount = imesh[i].num_vertexes;
+
+ model.meshes[i].vertices = malloc(sizeof(float)*imesh[i].num_vertexes*3); // Default vertex positions
+ model.meshes[i].normals = malloc(sizeof(float)*imesh[i].num_vertexes*3); // Default vertex normals
+ model.meshes[i].texcoords = malloc(sizeof(float)*imesh[i].num_vertexes*2); // Default vertex texcoords
+
+ model.meshes[i].boneIds = malloc(sizeof(int)*imesh[i].num_vertexes*4); // Up-to 4 bones supported!
+ model.meshes[i].boneWeights = malloc(sizeof(float)*imesh[i].num_vertexes*4); // Up-to 4 bones supported!
+
+ model.meshes[i].triangleCount = imesh[i].num_triangles;
+ model.meshes[i].indices = malloc(sizeof(unsigned short)*imesh[i].num_triangles*3);
+
+ // Animated verted data, what we actually process for rendering
+ // NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning)
+ model.meshes[i].animVertices = malloc(sizeof(float)*imesh[i].num_vertexes*3);
+ model.meshes[i].animNormals = malloc(sizeof(float)*imesh[i].num_vertexes*3);
+ }
+
+ // Triangles data processing
+ tri = malloc(sizeof(IQMTriangle)*iqm.num_triangles);
+ fseek(iqmFile, iqm.ofs_triangles, SEEK_SET);
+ fread(tri, sizeof(IQMTriangle)*iqm.num_triangles, 1, iqmFile);
+
+ for (int m = 0; m < iqm.num_meshes; m++)
+ {
+ int tcounter = 0;
+
+ for (int i = imesh[m].first_triangle; i < imesh[m].first_triangle+imesh[m].num_triangles; i++)
+ {
+ // IQM triangles are stored counter clockwise, but raylib sets opengl to clockwise drawing, so we swap them around
+ model.meshes[m].indices[tcounter+2] = tri[i].vertex[0] - imesh[m].first_vertex;
+ model.meshes[m].indices[tcounter+1] = tri[i].vertex[1] - imesh[m].first_vertex;
+ model.meshes[m].indices[tcounter] = tri[i].vertex[2] - imesh[m].first_vertex;
+ tcounter += 3;
+ }
+ }
+
+ // Vertex arrays data processing
+ va = malloc(sizeof(IQMVertexArray)*iqm.num_vertexarrays);
+ fseek(iqmFile, iqm.ofs_vertexarrays, SEEK_SET);
+ fread(va, sizeof(IQMVertexArray)*iqm.num_vertexarrays, 1, iqmFile);
+
+ for (int i = 0; i < iqm.num_vertexarrays; i++)
+ {
+ switch (va[i].type)
+ {
+ case IQM_POSITION:
+ {
+ vertex = malloc(sizeof(float)*iqm.num_vertexes*3);
+ fseek(iqmFile, va[i].offset, SEEK_SET);
+ fread(vertex, sizeof(float)*iqm.num_vertexes*3, 1, iqmFile);
+
+ for (int m = 0; m < iqm.num_meshes; m++)
+ {
+ int vCounter = 0;
+ for (int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
+ {
+ model.meshes[m].vertices[vCounter] = vertex[i];
+ model.meshes[m].animVertices[vCounter] = vertex[i];
+ vCounter++;
+ }
+ }
+ } break;
+ case IQM_NORMAL:
+ {
+ normal = malloc(sizeof(float)*iqm.num_vertexes*3);
+ fseek(iqmFile, va[i].offset, SEEK_SET);
+ fread(normal, sizeof(float)*iqm.num_vertexes*3, 1, iqmFile);
+
+ for (int m = 0; m < iqm.num_meshes; m++)
+ {
+ int vCounter = 0;
+ for (int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
+ {
+ model.meshes[m].normals[vCounter] = normal[i];
+ model.meshes[m].animNormals[vCounter] = normal[i];
+ vCounter++;
+ }
+ }
+ } break;
+ case IQM_TEXCOORD:
+ {
+ text = malloc(sizeof(float)*iqm.num_vertexes*2);
+ fseek(iqmFile, va[i].offset, SEEK_SET);
+ fread(text, sizeof(float)*iqm.num_vertexes*2, 1, iqmFile);
+
+ for (int m = 0; m < iqm.num_meshes; m++)
+ {
+ int vCounter = 0;
+ for (int i = imesh[m].first_vertex*2; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*2; i++)
+ {
+ model.meshes[m].texcoords[vCounter] = text[i];
+ vCounter++;
+ }
+ }
+ } break;
+ case IQM_BLENDINDEXES:
+ {
+ blendi = malloc(sizeof(char)*iqm.num_vertexes*4);
+ fseek(iqmFile, va[i].offset, SEEK_SET);
+ fread(blendi, sizeof(char)*iqm.num_vertexes*4, 1, iqmFile);
+
+ for (int m = 0; m < iqm.num_meshes; m++)
+ {
+ int boneCounter = 0;
+ for (int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
+ {
+ model.meshes[m].boneIds[boneCounter] = blendi[i];
+ boneCounter++;
+ }
+ }
+ } break;
+ case IQM_BLENDWEIGHTS:
+ {
+ blendw = malloc(sizeof(unsigned char)*iqm.num_vertexes*4);
+ fseek(iqmFile,va[i].offset,SEEK_SET);
+ fread(blendw,sizeof(unsigned char)*iqm.num_vertexes*4,1,iqmFile);
+
+ for (int m = 0; m < iqm.num_meshes; m++)
+ {
+ int boneCounter = 0;
+ for (int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
+ {
+ model.meshes[m].boneWeights[boneCounter] = blendw[i]/255.0f;
+ boneCounter++;
+ }
+ }
+ } break;
+ }
+ }
+
+ // Bones (joints) data processing
+ ijoint = malloc(sizeof(IQMJoint)*iqm.num_joints);
+ fseek(iqmFile, iqm.ofs_joints, SEEK_SET);
+ fread(ijoint, sizeof(IQMJoint)*iqm.num_joints, 1, iqmFile);
+
+ model.boneCount = iqm.num_joints;
+ model.bones = malloc(sizeof(BoneInfo)*iqm.num_joints);
+ model.bindPose = malloc(sizeof(Transform)*iqm.num_joints);
+
+ for (int i = 0; i < iqm.num_joints; i++)
+ {
+ // Bones
+ model.bones[i].parent = ijoint[i].parent;
+ fseek(iqmFile, iqm.ofs_text + ijoint[i].name, SEEK_SET);
+ fread(model.bones[i].name,sizeof(char)*BONE_NAME_LENGTH, 1, iqmFile);
+
+ // Bind pose (base pose)
+ model.bindPose[i].translation.x = ijoint[i].translate[0];
+ model.bindPose[i].translation.y = ijoint[i].translate[1];
+ model.bindPose[i].translation.z = ijoint[i].translate[2];
+
+ model.bindPose[i].rotation.x = ijoint[i].rotate[0];
+ model.bindPose[i].rotation.y = ijoint[i].rotate[1];
+ model.bindPose[i].rotation.z = ijoint[i].rotate[2];
+ model.bindPose[i].rotation.w = ijoint[i].rotate[3];
+
+ model.bindPose[i].scale.x = ijoint[i].scale[0];
+ model.bindPose[i].scale.y = ijoint[i].scale[1];
+ model.bindPose[i].scale.z = ijoint[i].scale[2];
+ }
+
+ // Build bind pose from parent joints
+ for (int i = 0; i < model.boneCount; i++)
+ {
+ if (model.bones[i].parent >= 0)
+ {
+ model.bindPose[i].rotation = QuaternionMultiply(model.bindPose[model.bones[i].parent].rotation, model.bindPose[i].rotation);
+ model.bindPose[i].translation = Vector3RotateByQuaternion(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].rotation);
+ model.bindPose[i].translation = Vector3Add(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].translation);
+ model.bindPose[i].scale = Vector3MultiplyV(model.bindPose[i].scale, model.bindPose[model.bones[i].parent].scale);
+ }
+ }
+
+ fclose(iqmFile);
+ free(imesh);
+ free(tri);
+ free(va);
+ free(vertex);
+ free(normal);
+ free(text);
+ free(blendi);
+ free(blendw);
+ free(ijoint);
return model;
}
@@ -2525,23 +2899,23 @@ static Model LoadGLTF(const char *fileName)
// glTF data loading
cgltf_options options = {0};
- cgltf_data data;
+ cgltf_data *data;
cgltf_result result = cgltf_parse(&options, buffer, size, &data);
free(buffer);
if (result == cgltf_result_success)
{
- printf("Type: %u\n", data.file_type);
- printf("Version: %d\n", data.version);
- printf("Meshes: %lu\n", data.meshes_count);
+ // printf("Type: %u\n", data.file_type);
+ // printf("Version: %d\n", data.version);
+ // printf("Meshes: %lu\n", data.meshes_count);
// TODO: Process glTF data and map to model
// NOTE: data.buffers[] should be loaded to model.meshes and data.images[] should be loaded to model.materials
// Use buffers[n].uri and images[n].uri... or use cgltf_load_buffers(&options, data, fileName);
- cgltf_free(&data);
+ cgltf_free(data);
}
else TraceLog(LOG_WARNING, "[%s] glTF data could not be loaded", fileName);
diff --git a/src/raylib.h b/src/raylib.h
index 1ad719bd..93965038 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -307,10 +307,10 @@ typedef struct Mesh {
unsigned short *indices;// Vertex indices (in case vertex data comes indexed)
// Animation vertex data
- float *baseVertices; // Vertex base position (required to apply bones transformations)
- float *baseNormals; // Vertex base normals (required to apply bones transformations)
- float *weightBias; // Vertex weight bias
- int *weightId; // Vertex weight id
+ float *animVertices; // Animated vertex positions (after bones transformations)
+ float *animNormals; // Animated normals (after bones transformations)
+ int *boneIds; // Vertex bone ids, up to 4 bones influence by vertex (skinning)
+ float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning)
// OpenGL identifiers
unsigned int vaoId; // OpenGL Vertex Array Object id
@@ -337,6 +337,19 @@ typedef struct Material {
float *params; // Material generic parameters (if required)
} Material;
+// Transformation properties
+typedef struct Transform {
+ Vector3 translation; // Translation
+ Quaternion rotation; // Rotation
+ Vector3 scale; // Scale
+} Transform;
+
+// Bone information
+typedef struct BoneInfo {
+ char name[32]; // Bone name
+ int parent; // Bone parent
+} BoneInfo;
+
// Model type
typedef struct Model {
Matrix transform; // Local transform matrix
@@ -346,10 +359,23 @@ typedef struct Model {
int materialCount; // Number of materials
Material *materials; // Materials array
-
int *meshMaterial; // Mesh material number
+
+ // Animation data
+ int boneCount; // Number of bones
+ BoneInfo *bones; // Bones information (skeleton)
+ Transform *bindPose; // Bones base transformation (pose)
} Model;
+// Model animation
+typedef struct ModelAnimation {
+ int boneCount; // Number of bones
+ BoneInfo *bones; // Bones information (skeleton)
+
+ int frameCount; // Number of animation frames
+ Transform **framePoses; // Poses array by frame
+} ModelAnimation;
+
// Ray type (useful for raycast)
typedef struct Ray {
Vector3 position; // Ray position (origin)
@@ -1230,17 +1256,16 @@ RLAPI void DrawGizmo(Vector3 position);
// Model loading/unloading functions
RLAPI Model LoadModel(const char *fileName); // Load model from files (meshes and materials)
RLAPI Model LoadModelFromMesh(Mesh mesh); // Load model from generated mesh
+//RLAPI void LoadModelAnimations(const char fileName, ModelAnimation *anims, int *animsCount); // Load model animations from file
+//RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); // Update model animation pose
RLAPI void UnloadModel(Model model); // Unload model from memory (RAM and/or VRAM)
-// Mesh loading/unloading functions
-RLAPI Mesh LoadMesh(const char *fileName); // Load mesh from file
-RLAPI void UnloadMesh(Mesh *mesh); // Unload mesh from memory (RAM and/or VRAM)
-RLAPI void ExportMesh(Mesh mesh, const char *fileName); // Export mesh data to file
-
// Mesh manipulation functions
RLAPI BoundingBox MeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits
RLAPI void MeshTangents(Mesh *mesh); // Compute mesh tangents
RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals
+RLAPI void UnloadMesh(Mesh *mesh); // Unload mesh from memory (RAM and/or VRAM)
+RLAPI void ExportMesh(Mesh mesh, const char *fileName); // Export mesh data to file
// Mesh generation functions
RLAPI Mesh GenMeshPoly(int sides, float radius); // Generate polygonal mesh
diff --git a/src/rlgl.h b/src/rlgl.h
index 49ab1de5..8cc4c590 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -205,8 +205,8 @@ typedef unsigned char byte;
unsigned short *indices;// vertex indices (in case vertex data comes indexed)
// Animation vertex data
- float *baseVertices; // Vertex base position (required to apply bones transformations)
- float *baseNormals; // Vertex base normals (required to apply bones transformations)
+ float *animVertices; // Animated vertex positions (after bones transformations)
+ float *animNormals; // Animated normals (after bones transformations)
float *weightBias; // Vertex weight bias
int *weightId; // Vertex weight id
@@ -455,6 +455,7 @@ void rlDeleteVertexArrays(unsigned int id); // Unload vertex data (V
void rlDeleteBuffers(unsigned int id); // Unload vertex data (VBO) from GPU memory
void rlClearColor(byte r, byte g, byte b, byte a); // Clear color buffer with color
void rlClearScreenBuffers(void); // Clear used screen buffers (color and depth)
+void rlUpdateBuffer(int bufferId, void *data, int dataSize); // Update GPU buffer with new data
//------------------------------------------------------------------------------------
// Functions Declaration - rlgl functionality
@@ -1501,6 +1502,13 @@ void rlClearScreenBuffers(void)
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Stencil buffer not used...
}
+// Update GPU buffer with new data
+void rlUpdateBuffer(int bufferId, void *data, int dataSize)
+{
+ glBindBuffer(GL_ARRAY_BUFFER, bufferId);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, dataSize, data);
+}
+
//----------------------------------------------------------------------------------
// Module Functions Definition - rlgl Functions
//----------------------------------------------------------------------------------
@@ -2036,6 +2044,8 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi
unsigned int rlLoadTextureDepth(int width, int height, int bits, bool useRenderBuffer)
{
unsigned int id = 0;
+
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
unsigned int glInternalFormat = GL_DEPTH_COMPONENT16;
if ((bits != 16) && (bits != 24) && (bits != 32)) bits = 16;
@@ -2081,6 +2091,7 @@ unsigned int rlLoadTextureDepth(int width, int height, int bits, bool useRenderB
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
+#endif
return id;
}
@@ -2092,7 +2103,8 @@ unsigned int rlLoadTextureCubemap(void *data, int size, int format)
{
unsigned int cubemapId = 0;
unsigned int dataSize = GetPixelDataSize(size, size, format);
-
+
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glGenTextures(1, &cubemapId);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapId);
@@ -2137,6 +2149,7 @@ unsigned int rlLoadTextureCubemap(void *data, int size, int format)
#endif
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+#endif
return cubemapId;
}
@@ -2221,9 +2234,9 @@ RenderTexture2D rlLoadRenderTexture(int width, int height, int format, int depth
{
RenderTexture2D target = { 0 };
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
if (useDepthTexture && texDepthSupported) target.depthTexture = true;
-#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Create the framebuffer object
glGenFramebuffers(1, &target.id);
glBindFramebuffer(GL_FRAMEBUFFER, target.id);
@@ -2274,6 +2287,7 @@ RenderTexture2D rlLoadRenderTexture(int width, int height, int format, int depth
// NOTE: Attach type: 0-Color, 1-Depth renderbuffer, 2-Depth texture
void rlRenderTextureAttach(RenderTexture2D target, unsigned int id, int attachType)
{
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glBindFramebuffer(GL_FRAMEBUFFER, target.id);
if (attachType == 0) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, id, 0);
@@ -2284,11 +2298,15 @@ void rlRenderTextureAttach(RenderTexture2D target, unsigned int id, int attachTy
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
+#endif
}
// Verify render texture is complete
bool rlRenderTextureComplete(RenderTexture target)
{
+ bool result = false;
+
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glBindFramebuffer(GL_FRAMEBUFFER, target.id);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
@@ -2309,7 +2327,10 @@ bool rlRenderTextureComplete(RenderTexture target)
glBindFramebuffer(GL_FRAMEBUFFER, 0);
- return (status == GL_FRAMEBUFFER_COMPLETE);
+ result = (status == GL_FRAMEBUFFER_COMPLETE);
+#endif
+
+ return result;
}
// Generate mipmap data for selected texture
@@ -2775,10 +2796,10 @@ void rlUnloadMesh(Mesh *mesh)
free(mesh->texcoords2);
free(mesh->indices);
- free(mesh->baseVertices);
- free(mesh->baseNormals);
- free(mesh->weightBias);
- free(mesh->weightId);
+ free(mesh->animVertices);
+ free(mesh->animNormals);
+ free(mesh->boneWeights);
+ free(mesh->boneIds);
rlDeleteBuffers(mesh->vboId[0]); // vertex
rlDeleteBuffers(mesh->vboId[1]); // texcoords