summaryrefslogtreecommitdiff
path: root/libs/raylib/src/models.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/raylib/src/models.c')
-rw-r--r--libs/raylib/src/models.c305
1 files changed, 171 insertions, 134 deletions
diff --git a/libs/raylib/src/models.c b/libs/raylib/src/models.c
index ba913e0..69d7856 100644
--- a/libs/raylib/src/models.c
+++ b/libs/raylib/src/models.c
@@ -45,25 +45,46 @@
#include "utils.h" // Required for: fopen() Android mapping
-#include <stdio.h> // Required for: FILE, fopen(), fclose(), fscanf(), feof(), rewind(), fgets()
#include <stdlib.h> // Required for: malloc(), free()
-#include <string.h> // Required for: strcmp()
-#include <math.h> // Required for: sin(), cos()
+#include <stdio.h> // Required for: FILE, fopen(), fclose()
+#include <string.h> // Required for: strncmp() [Used in LoadModelAnimations()], strlen() [Used in LoadTextureFromCgltfImage()]
+#include <math.h> // Required for: sinf(), cosf(), sqrtf(), fabsf()
+
+#if defined(_WIN32)
+ #include <direct.h> // Required for: _chdir() [Used in LoadOBJ()]
+ #define CHDIR _chdir
+#else
+ #include <unistd.h> // Required for: chdir() (POSIX) [Used in LoadOBJ()]
+ #define CHDIR chdir
+#endif
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
#if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL)
+ #define TINYOBJ_MALLOC RL_MALLOC
+ #define TINYOBJ_CALLOC RL_CALLOC
+ #define TINYOBJ_REALLOC RL_REALLOC
+ #define TINYOBJ_FREE RL_FREE
+
#define TINYOBJ_LOADER_C_IMPLEMENTATION
#include "external/tinyobj_loader_c.h" // OBJ/MTL file formats loading
#endif
#if defined(SUPPORT_FILEFORMAT_GLTF)
+ #define CGLTF_MALLOC RL_MALLOC
+ #define CGLTF_FREE RL_FREE
+
#define CGLTF_IMPLEMENTATION
#include "external/cgltf.h" // glTF file format loading
#include "external/stb_image.h" // glTF texture images loading
#endif
#if defined(SUPPORT_MESH_GENERATION)
+ #define PAR_MALLOC(T, N) ((T*)RL_MALLOC(N*sizeof(T)))
+ #define PAR_CALLOC(T, N) ((T*)RL_CALLOC(N*sizeof(T), 1))
+ #define PAR_REALLOC(T, BUF, N) ((T*)RL_REALLOC(BUF, sizeof(T)*(N)))
+ #define PAR_FREE RL_FREE
+
#define PAR_SHAPES_IMPLEMENTATION
#include "external/par_shapes.h" // Shapes 3d parametric generation
#endif
@@ -110,11 +131,11 @@ void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color)
rlEnd();
}
-// Draw a point in 3D space--actually a small line.
+// Draw a point in 3D space, actually a small line
void DrawPoint3D(Vector3 position, Color color)
{
if (rlCheckBufferLimit(8)) rlglDraw();
-
+
rlPushMatrix();
rlTranslatef(position.x, position.y, position.z);
rlBegin(RL_LINES);
@@ -667,10 +688,10 @@ Model LoadModel(const char *fileName)
model.meshCount = 1;
model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
#if defined(SUPPORT_MESH_GENERATION)
- TraceLog(LOG_WARNING, "[%s] No meshes can be loaded, default to cube mesh", fileName);
+ TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load mesh data, default to cube mesh", fileName);
model.meshes[0] = GenMeshCube(1.0f, 1.0f, 1.0f);
#else
- TraceLog(LOG_WARNING, "[%s] No meshes can be loaded, and can't create a default mesh. The raylib mesh generation is not supported (SUPPORT_MESH_GENERATION).", fileName);
+ TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load mesh data", fileName);
#endif
}
else
@@ -681,7 +702,7 @@ Model LoadModel(const char *fileName)
if (model.materialCount == 0)
{
- TraceLog(LOG_WARNING, "[%s] No materials can be loaded, default to white material", fileName);
+ TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to load material data, default to white material", fileName);
model.materialCount = 1;
model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
@@ -735,7 +756,7 @@ void UnloadModel(Model model)
RL_FREE(model.bones);
RL_FREE(model.bindPose);
- TraceLog(LOG_INFO, "Unloaded model data from RAM and VRAM");
+ TRACELOG(LOG_INFO, "MODEL: Unloaded model from RAM and VRAM");
}
// Load meshes from model file
@@ -809,8 +830,8 @@ void ExportMesh(Mesh mesh, const char *fileName)
}
else if (IsFileExtension(fileName, ".raw")) { } // TODO: Support additional file formats to export mesh vertex data
- if (success) TraceLog(LOG_INFO, "Mesh exported successfully: %s", fileName);
- else TraceLog(LOG_WARNING, "Mesh could not be exported.");
+ if (success) TRACELOG(LOG_INFO, "FILEIO: [%s] Mesh exported successfully", fileName);
+ else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export mesh data", fileName);
}
// Load materials from model file
@@ -828,7 +849,7 @@ Material *LoadMaterials(const char *fileName, int *materialCount)
int result = tinyobj_parse_mtl_file(&mats, &count, fileName);
if (result != TINYOBJ_SUCCESS) {
- TraceLog(LOG_WARNING, "[%s] Could not parse Materials file", fileName);
+ TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName);
}
// TODO: Process materials to return
@@ -836,7 +857,7 @@ Material *LoadMaterials(const char *fileName, int *materialCount)
tinyobj_materials_free(mats, count);
}
#else
- TraceLog(LOG_WARNING, "[%s] Materials file not supported", fileName);
+ TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load material file", fileName);
#endif
// Set materials shader to default (DIFFUSE, SPECULAR, NORMAL)
@@ -888,8 +909,8 @@ void SetMaterialTexture(Material *material, int mapType, Texture2D texture)
// Set the material for a mesh
void SetModelMeshMaterial(Model *model, int meshId, int materialId)
{
- if (meshId >= model->meshCount) TraceLog(LOG_WARNING, "Mesh id greater than mesh count");
- else if (materialId >= model->materialCount) TraceLog(LOG_WARNING,"Material id greater than material count");
+ if (meshId >= model->meshCount) TRACELOG(LOG_WARNING, "MESH: Id greater than mesh count");
+ else if (materialId >= model->materialCount) TRACELOG(LOG_WARNING, "MATERIAL: Id greater than material count");
else model->meshMaterial[meshId] = materialId;
}
@@ -930,14 +951,15 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount)
unsigned int flags;
} IQMAnim;
- FILE *iqmFile;
+ FILE *iqmFile = NULL;
IQMHeader iqm;
iqmFile = fopen(filename,"rb");
if (!iqmFile)
{
- TraceLog(LOG_ERROR, "[%s] Unable to open file", filename);
+ TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", filename);
+ return NULL;
}
// Read IQM header
@@ -945,17 +967,15 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount)
if (strncmp(iqm.magic, IQM_MAGIC, sizeof(IQM_MAGIC)))
{
- TraceLog(LOG_ERROR, "Magic Number \"%s\"does not match.", iqm.magic);
+ TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", filename);
fclose(iqmFile);
-
return NULL;
}
if (iqm.version != IQM_VERSION)
{
- TraceLog(LOG_ERROR, "IQM version %i is incorrect.", iqm.version);
+ TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version incorrect", filename);
fclose(iqmFile);
-
return NULL;
}
@@ -1092,7 +1112,7 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount)
animations[a].framePoses[frame][i].rotation = QuaternionMultiply(animations[a].framePoses[frame][animations[a].bones[i].parent].rotation, animations[a].framePoses[frame][i].rotation);
animations[a].framePoses[frame][i].translation = Vector3RotateByQuaternion(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].rotation);
animations[a].framePoses[frame][i].translation = Vector3Add(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].translation);
- animations[a].framePoses[frame][i].scale = Vector3MultiplyV(animations[a].framePoses[frame][i].scale, animations[a].framePoses[frame][animations[a].bones[i].parent].scale);
+ animations[a].framePoses[frame][i].scale = Vector3Multiply(animations[a].framePoses[frame][i].scale, animations[a].framePoses[frame][animations[a].bones[i].parent].scale);
}
}
}
@@ -1122,7 +1142,7 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
Vector3 inTranslation = { 0 };
Quaternion inRotation = { 0 };
- Vector3 inScale = { 0 };
+ //Vector3 inScale = { 0 }; // Not used...
Vector3 outTranslation = { 0 };
Quaternion outRotation = { 0 };
@@ -1137,7 +1157,7 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
boneId = model.meshes[m].boneIds[boneCounter];
inTranslation = model.bindPose[boneId].translation;
inRotation = model.bindPose[boneId].rotation;
- inScale = model.bindPose[boneId].scale;
+ //inScale = model.bindPose[boneId].scale;
outTranslation = anim.framePoses[frame][boneId].translation;
outRotation = anim.framePoses[frame][boneId].rotation;
outScale = anim.framePoses[frame][boneId].scale;
@@ -1145,7 +1165,7 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
// Vertices processing
// NOTE: We use meshes.vertices (default vertex position) to calculate meshes.animVertices (animated vertex position)
animVertex = (Vector3){ model.meshes[m].vertices[vCounter], model.meshes[m].vertices[vCounter + 1], model.meshes[m].vertices[vCounter + 2] };
- animVertex = Vector3MultiplyV(animVertex, outScale);
+ animVertex = Vector3Multiply(animVertex, outScale);
animVertex = Vector3Subtract(animVertex, inTranslation);
animVertex = Vector3RotateByQuaternion(animVertex, QuaternionMultiply(outRotation, QuaternionInvert(inRotation)));
animVertex = Vector3Add(animVertex, outTranslation);
@@ -1655,6 +1675,7 @@ Mesh GenMeshCylinder(float radius, float height, int slices)
par_shapes_mesh *cylinder = par_shapes_create_cylinder(slices, 8);
par_shapes_scale(cylinder, radius, radius, height);
par_shapes_rotate(cylinder, -PI/2.0f, (float[]){ 1, 0, 0 });
+ par_shapes_rotate(cylinder, PI/2.0f, (float[]){ 0, 1, 0 });
// Generate an orientable disk shape (top cap)
par_shapes_mesh *capTop = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, 1 });
@@ -1817,6 +1838,11 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
Vector3 scaleFactor = { size.x/mapX, size.y/255.0f, size.z/mapZ };
+ Vector3 vA;
+ Vector3 vB;
+ Vector3 vC;
+ Vector3 vN;
+
for (int z = 0; z < mapZ-1; z++)
{
for (int x = 0; x < mapX-1; x++)
@@ -1874,14 +1900,34 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
// Fill normals array with data
//--------------------------------------------------------------
- for (int i = 0; i < 18; i += 3)
+ for (int i = 0; i < 18; i += 9)
{
- mesh.normals[nCounter + i] = 0.0f;
- mesh.normals[nCounter + i + 1] = 1.0f;
- mesh.normals[nCounter + i + 2] = 0.0f;
- }
+ vA.x = mesh.vertices[nCounter + i];
+ vA.y = mesh.vertices[nCounter + i + 1];
+ vA.z = mesh.vertices[nCounter + i + 2];
- // TODO: Calculate normals in an efficient way
+ vB.x = mesh.vertices[nCounter + i + 3];
+ vB.y = mesh.vertices[nCounter + i + 4];
+ vB.z = mesh.vertices[nCounter + i + 5];
+
+ vC.x = mesh.vertices[nCounter + i + 6];
+ vC.y = mesh.vertices[nCounter + i + 7];
+ vC.z = mesh.vertices[nCounter + i + 8];
+
+ vN = Vector3Normalize(Vector3CrossProduct(Vector3Subtract(vB, vA), Vector3Subtract(vC, vA)));
+
+ mesh.normals[nCounter + i] = vN.x;
+ mesh.normals[nCounter + i + 1] = vN.y;
+ mesh.normals[nCounter + i + 2] = vN.z;
+
+ mesh.normals[nCounter + i + 3] = vN.x;
+ mesh.normals[nCounter + i + 4] = vN.y;
+ mesh.normals[nCounter + i + 5] = vN.z;
+
+ mesh.normals[nCounter + i + 6] = vN.x;
+ mesh.normals[nCounter + i + 7] = vN.y;
+ mesh.normals[nCounter + i + 8] = vN.z;
+ }
nCounter += 18; // 6 vertex, 18 floats
trisCounter += 2;
@@ -2292,7 +2338,7 @@ BoundingBox MeshBoundingBox(Mesh mesh)
void MeshTangents(Mesh *mesh)
{
if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
- else TraceLog(LOG_WARNING, "Mesh tangents already exist");
+ else TRACELOG(LOG_WARNING, "MESH: Tangents data already available, re-writting");
Vector3 *tan1 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
Vector3 *tan2 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
@@ -2344,7 +2390,7 @@ void MeshTangents(Mesh *mesh)
// TODO: Review, not sure if tangent computation is right, just used reference proposed maths...
#if defined(COMPUTE_TANGENTS_METHOD_01)
- Vector3 tmp = Vector3Subtract(tangent, Vector3Multiply(normal, Vector3DotProduct(normal, tangent)));
+ Vector3 tmp = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent)));
tmp = Vector3Normalize(tmp);
mesh->tangents[i*4 + 0] = tmp.x;
mesh->tangents[i*4 + 1] = tmp.y;
@@ -2365,7 +2411,7 @@ void MeshTangents(Mesh *mesh)
// Load a new tangent attributes buffer
mesh->vboId[LOC_VERTEX_TANGENT] = rlLoadAttribBuffer(mesh->vaoId, LOC_VERTEX_TANGENT, mesh->tangents, mesh->vertexCount*4*sizeof(float), false);
- TraceLog(LOG_INFO, "Tangents computed for mesh");
+ TRACELOG(LOG_INFO, "MESH: Tangents data computed for provided mesh");
}
// Compute mesh binormals (aka bitangent)
@@ -2373,10 +2419,10 @@ void MeshBinormals(Mesh *mesh)
{
for (int i = 0; i < mesh->vertexCount; i++)
{
- Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
- Vector3 tangent = { mesh->tangents[i*4 + 0], mesh->tangents[i*4 + 1], mesh->tangents[i*4 + 2] };
- Vector3 binormal = Vector3Multiply(Vector3CrossProduct(normal, tangent), mesh->tangents[i*4 + 3]);
-
+ //Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
+ //Vector3 tangent = { mesh->tangents[i*4 + 0], mesh->tangents[i*4 + 1], mesh->tangents[i*4 + 2] };
+ //Vector3 binormal = Vector3Scale(Vector3CrossProduct(normal, tangent), mesh->tangents[i*4 + 3]);
+
// TODO: Register computed binormal in mesh->binormal?
}
}
@@ -2408,13 +2454,13 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota
{
// TODO: Review color + tint premultiplication mechanism
Color color = model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color;
-
+
Color colorTint = WHITE;
colorTint.r = (((float)color.r/255.0)*((float)tint.r/255.0))*255;
colorTint.g = (((float)color.g/255.0)*((float)tint.g/255.0))*255;
colorTint.b = (((float)color.b/255.0)*((float)tint.b/255.0))*255;
colorTint.a = (((float)color.a/255.0)*((float)tint.a/255.0))*255;
-
+
model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color = colorTint;
rlDrawMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform);
model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color = color;
@@ -2512,9 +2558,9 @@ void DrawBoundingBox(BoundingBox box, Color color)
{
Vector3 size;
- size.x = (float)fabs(box.max.x - box.min.x);
- size.y = (float)fabs(box.max.y - box.min.y);
- size.z = (float)fabs(box.max.z - box.min.z);
+ size.x = fabsf(box.max.x - box.min.x);
+ size.y = fabsf(box.max.y - box.min.y);
+ size.z = fabsf(box.max.z - box.min.z);
Vector3 center = { box.min.x + size.x/2.0f, box.min.y + size.y/2.0f, box.min.z + size.z/2.0f };
@@ -2760,7 +2806,7 @@ RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight)
RayHitInfo result = { 0 };
- if (fabs(ray.direction.y) > EPSILON)
+ if (fabsf(ray.direction.y) > EPSILON)
{
float distance = (ray.position.y - groundHeight)/-ray.direction.y;
@@ -2793,32 +2839,20 @@ static Model LoadOBJ(const char *fileName)
tinyobj_material_t *materials = NULL;
unsigned int materialCount = 0;
- int dataLength = 0;
- char *data = NULL;
-
- // Load model data
- FILE *objFile = fopen(fileName, "rb");
+ char *fileData = LoadFileText(fileName);
- if (objFile != NULL)
+ if (fileData != NULL)
{
- fseek(objFile, 0, SEEK_END);
- long length = ftell(objFile); // Get file size
- fseek(objFile, 0, SEEK_SET); // Reset file pointer
-
- data = (char *)RL_MALLOC(length);
-
- fread(data, length, 1, objFile);
- dataLength = length;
- fclose(objFile);
- }
+ int dataSize = strlen(fileData);
+ char currentDir[1024] = { 0 };
+ strcpy(currentDir, GetWorkingDirectory());
+ chdir(GetDirectoryPath(fileName));
- if (data != NULL)
- {
unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;
- int ret = tinyobj_parse_obj(&attrib, &meshes, &meshCount, &materials, &materialCount, data, dataLength, flags);
+ int ret = tinyobj_parse_obj(&attrib, &meshes, &meshCount, &materials, &materialCount, fileData, dataSize, 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);
+ if (ret != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load OBJ data", fileName);
+ else TRACELOG(LOG_INFO, "MODEL: [%s] OBJ data loaded successfully: %i meshes / %i materials", fileName, meshCount, materialCount);
// Init model meshes array
// TODO: Support multiple meshes... in the meantime, only one mesh is returned
@@ -2868,8 +2902,6 @@ static Model LoadOBJ(const char *fileName)
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;
@@ -2955,13 +2987,12 @@ static Model LoadOBJ(const char *fileName)
tinyobj_attrib_free(&attrib);
tinyobj_shapes_free(meshes, meshCount);
tinyobj_materials_free(materials, materialCount);
+
+ RL_FREE(fileData);
- RL_FREE(data);
+ chdir(currentDir);
}
- // NOTE: At this point we have all model data loaded
- TraceLog(LOG_INFO, "[%s] Model loaded successfully in RAM (CPU)", fileName);
-
return model;
}
#endif
@@ -3048,7 +3079,7 @@ static Model LoadIQM(const char *fileName)
//-----------------------------------------------------------------------------------
// IQM vertex data types
- typedef enum {
+ enum {
IQM_POSITION = 0,
IQM_TEXCOORD = 1,
IQM_NORMAL = 2,
@@ -3057,11 +3088,11 @@ static Model LoadIQM(const char *fileName)
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 };
- FILE *iqmFile;
+ FILE *iqmFile = NULL;
IQMHeader iqm;
IQMMesh *imesh;
@@ -3079,22 +3110,22 @@ static Model LoadIQM(const char *fileName)
if (iqmFile == NULL)
{
- TraceLog(LOG_WARNING, "[%s] IQM file could not be opened", fileName);
+ TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open IQM file", fileName);
return model;
}
- fread(&iqm,sizeof(IQMHeader), 1, iqmFile); // Read IQM header
+ 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);
+ TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
fclose(iqmFile);
return model;
}
if (iqm.version != IQM_VERSION)
{
- TraceLog(LOG_WARNING, "[%s] IQM file version is not supported (%i).", fileName, iqm.version);
+ TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqm.version);
fclose(iqmFile);
return model;
}
@@ -3285,7 +3316,7 @@ static Model LoadIQM(const char *fileName)
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);
+ model.bindPose[i].scale = Vector3Multiply(model.bindPose[i].scale, model.bindPose[model.bones[i].parent].scale);
}
}
@@ -3376,9 +3407,9 @@ static unsigned char *DecodeBase64(char *input, int *size)
}
// Load texture from cgltf_image
-static Texture LoadTextureFromCgltfImage(cgltf_image *image, const char *texPath, Color tint)
+static Image LoadImageFromCgltfImage(cgltf_image *image, const char *texPath, Color tint)
{
- Texture texture = { 0 };
+ Image rimage = { 0 };
if (image->uri)
{
@@ -3396,7 +3427,7 @@ static Texture LoadTextureFromCgltfImage(cgltf_image *image, const char *texPath
int i = 0;
while ((image->uri[i] != ',') && (image->uri[i] != 0)) i++;
- if (image->uri[i] == 0) TraceLog(LOG_WARNING, "CGLTF Image: Invalid data URI");
+ if (image->uri[i] == 0) TRACELOG(LOG_WARNING, "IMAGE: glTF data URI is not a valid image");
else
{
int size;
@@ -3405,22 +3436,18 @@ static Texture LoadTextureFromCgltfImage(cgltf_image *image, const char *texPath
int w, h;
unsigned char *raw = stbi_load_from_memory(data, size, &w, &h, NULL, 4);
- Image rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
-
+ rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
+
// TODO: Tint shouldn't be applied here!
ImageColorTint(&rimage, tint);
- texture = LoadTextureFromImage(rimage);
- UnloadImage(rimage);
}
}
else
{
- Image rimage = LoadImage(TextFormat("%s/%s", texPath, image->uri));
-
+ rimage = LoadImage(TextFormat("%s/%s", texPath, image->uri));
+
// TODO: Tint shouldn't be applied here!
ImageColorTint(&rimage, tint);
- texture = LoadTextureFromImage(rimage);
- UnloadImage(rimage);
}
}
else if (image->buffer_view)
@@ -3439,41 +3466,36 @@ static Texture LoadTextureFromCgltfImage(cgltf_image *image, const char *texPath
unsigned char *raw = stbi_load_from_memory(data, image->buffer_view->size, &w, &h, NULL, 4);
free(data);
- Image rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
+ rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
free(raw);
// TODO: Tint shouldn't be applied here!
ImageColorTint(&rimage, tint);
- texture = LoadTextureFromImage(rimage);
- UnloadImage(rimage);
}
else
{
- Image rimage = LoadImageEx(&tint, 1, 1);
- texture = LoadTextureFromImage(rimage);
- UnloadImage(rimage);
+ rimage = LoadImageEx(&tint, 1, 1);
}
- return texture;
+ return rimage;
}
-// Load glTF mesh data
+// LoadGLTF loads in model data from given filename, supporting both .gltf and .glb
static Model LoadGLTF(const char *fileName)
{
/***********************************************************************************
- Function implemented by Wilhem Barbier (@wbrbr)
+ Function implemented by Wilhem Barbier(@wbrbr), with modifications by Tyler Bezera(@gamerfiend)
Features:
- Supports .gltf and .glb files
- Supports embedded (base64) or external textures
- - Loads the albedo/diffuse texture (other maps could be added)
+ - Loads all raylib supported material textures, values and colors
- Supports multiple mesh per model and multiple primitives per model
Some restrictions (not exhaustive):
- Triangle-only meshes
- Not supported node hierarchies or transforms
- - Only loads the diffuse texture... but not too hard to support other maps (normal, roughness/metalness...)
- Only supports unsigned short indices (no byte/unsigned int)
- Only supports float for texture coordinates (no byte/unsigned short)
@@ -3498,7 +3520,7 @@ static Model LoadGLTF(const char *fileName)
if (gltfFile == NULL)
{
- TraceLog(LOG_WARNING, "[%s] glTF file could not be opened", fileName);
+ TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open glTF file", fileName);
return model;
}
@@ -3518,11 +3540,12 @@ static Model LoadGLTF(const char *fileName)
if (result == cgltf_result_success)
{
- TraceLog(LOG_INFO, "[%s][%s] Model meshes/materials: %i/%i", fileName, (data->file_type == 2)? "glb" : "gltf", data->meshes_count, data->materials_count);
+ TRACELOG(LOG_INFO, "MODEL: [%s] glTF meshes (%s) count: %i", fileName, (data->file_type == 2)? "glb" : "gltf", data->meshes_count, data->materials_count);
+ TRACELOG(LOG_INFO, "MODEL: [%s] glTF materials (%s) count: %i", fileName, (data->file_type == 2)? "glb" : "gltf", data->meshes_count, data->materials_count);
// Read data buffers
result = cgltf_load_buffers(&options, data, fileName);
- if (result != cgltf_result_success) TraceLog(LOG_INFO, "[%s][%s] Error loading mesh/material buffers", fileName, (data->file_type == 2)? "glb" : "gltf");
+ if (result != cgltf_result_success) TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load mesh/material buffers", fileName);
int primitivesCount = 0;
@@ -3537,7 +3560,6 @@ static Model LoadGLTF(const char *fileName)
for (int i = 0; i < model.meshCount; i++) model.meshes[i].vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int));
- //For each material
for (int i = 0; i < model.materialCount - 1; i++)
{
model.materials[i] = LoadMaterialDefault();
@@ -3545,46 +3567,61 @@ static Model LoadGLTF(const char *fileName)
const char *texPath = GetDirectoryPath(fileName);
//Ensure material follows raylib support for PBR (metallic/roughness flow)
- if (data->materials[i].has_pbr_metallic_roughness)
+ if (data->materials[i].has_pbr_metallic_roughness)
{
- float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor;
- float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor;
-
- // NOTE: Material name not used for the moment
- //if (model.materials[i].name && data->materials[i].name) strcpy(model.materials[i].name, data->materials[i].name);
+ tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0] * 255);
+ tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1] * 255);
+ tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2] * 255);
+ tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3] * 255);
- // TODO: REview: shouldn't these be *255 ???
- tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255);
- tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255);
- tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255);
- tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255);
+ model.materials[i].maps[MAP_ALBEDO].color = tint;
- model.materials[i].maps[MAP_ROUGHNESS].color = tint;
-
- if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture)
+ if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture)
{
- model.materials[i].maps[MAP_ALBEDO].texture = LoadTextureFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath, tint);
+ Image albedo = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath, tint);
+ model.materials[i].maps[MAP_ALBEDO].texture = LoadTextureFromImage(albedo);
+ UnloadImage(albedo);
}
- // NOTE: Tint isn't need for other textures.. pass null or clear?
- // Just set as white, multiplying by white has no effect
- tint = WHITE;
+ tint = WHITE; // Set tint to white after it's been used by Albedo
if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture)
{
- model.materials[i].maps[MAP_ROUGHNESS].texture = LoadTextureFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath, tint);
+ Image metallicRoughness = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath, tint);
+ model.materials[i].maps[MAP_ROUGHNESS].texture = LoadTextureFromImage(metallicRoughness);
+
+ float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor;
+ model.materials[i].maps[MAP_ROUGHNESS].value = roughness;
+
+ float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor;
+ model.materials[i].maps[MAP_METALNESS].value = metallic;
+
+ UnloadImage(metallicRoughness);
}
- model.materials[i].maps[MAP_ROUGHNESS].value = roughness;
- model.materials[i].maps[MAP_METALNESS].value = metallic;
- if (data->materials[i].normal_texture.texture)
+ if (data->materials[i].normal_texture.texture)
{
- model.materials[i].maps[MAP_NORMAL].texture = LoadTextureFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath, tint);
+ Image normalImage = LoadImageFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath, tint);
+ model.materials[i].maps[MAP_NORMAL].texture = LoadTextureFromImage(normalImage);
+ UnloadImage(normalImage);
}
-
- if (data->materials[i].occlusion_texture.texture)
+
+ if (data->materials[i].occlusion_texture.texture)
+ {
+ Image occulsionImage = LoadImageFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath, tint);
+ model.materials[i].maps[MAP_OCCLUSION].texture = LoadTextureFromImage(occulsionImage);
+ UnloadImage(occulsionImage);
+ }
+
+ if (data->materials[i].emissive_texture.texture)
{
- model.materials[i].maps[MAP_OCCLUSION].texture = LoadTextureFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath, tint);
+ Image emissiveImage = LoadImageFromCgltfImage(data->materials[i].emissive_texture.texture->image, texPath, tint);
+ model.materials[i].maps[MAP_EMISSION].texture = LoadTextureFromImage(emissiveImage);
+ tint.r = (unsigned char)(data->materials[i].emissive_factor[0]*255);
+ tint.g = (unsigned char)(data->materials[i].emissive_factor[1]*255);
+ tint.b = (unsigned char)(data->materials[i].emissive_factor[2]*255);
+ model.materials[i].maps[MAP_EMISSION].color = tint;
+ UnloadImage(emissiveImage);
}
}
}
@@ -3626,7 +3663,7 @@ static Model LoadGLTF(const char *fileName)
else
{
// TODO: Support normalized unsigned byte/unsigned short texture coordinates
- TraceLog(LOG_WARNING, "[%s] Texture coordinates must be float", fileName);
+ TRACELOG(LOG_WARNING, "MODEL: [%s] glTF texture coordinates must be float", fileName);
}
}
}
@@ -3644,7 +3681,7 @@ static Model LoadGLTF(const char *fileName)
else
{
// TODO: Support unsigned byte/unsigned int
- TraceLog(LOG_WARNING, "[%s] Indices must be unsigned short", fileName);
+ TRACELOG(LOG_WARNING, "MODEL: [%s] glTF index data must be unsigned short", fileName);
}
}
else
@@ -3669,7 +3706,7 @@ static Model LoadGLTF(const char *fileName)
cgltf_free(data);
}
- else TraceLog(LOG_WARNING, "[%s] glTF data could not be loaded", fileName);
+ else TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName);
RL_FREE(buffer);