From d62652c5b29b322c8c9fa2ab7c7912fe366cd4bc Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 18 Feb 2019 18:46:17 +0100 Subject: Update cgltf library Added some comments to loader function... --- src/models.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index 5feec0f6..eace0f66 100644 --- a/src/models.c +++ b/src/models.c @@ -2748,17 +2748,17 @@ static Mesh LoadIQM(const char *fileName) #endif #if defined(SUPPORT_FILEFORMAT_GLTF) -// Load GLTF mesh data +// Load glTF mesh data static Mesh LoadGLTF(const char *fileName) { Mesh mesh = { 0 }; - // GLTF file loading + // glTF file loading FILE *gltfFile = fopen(fileName, "rb"); if (gltfFile == NULL) { - TraceLog(LOG_WARNING, "[%s] GLTF file could not be opened", fileName); + TraceLog(LOG_WARNING, "[%s] glTF file could not be opened", fileName); return mesh; } @@ -2771,22 +2771,28 @@ static Mesh LoadGLTF(const char *fileName) fclose(gltfFile); - // GLTF data loading + // glTF data loading cgltf_options options = {0}; 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); + + // TODO: Process glTF data and map to mesh + + // NOTE: data.buffers[] and data.images[] should be loaded + // using buffers[n].uri and images[n].uri... or use cgltf_load_buffers(&options, data, fileName); + + cgltf_free(&data); } - else TraceLog(LOG_WARNING, "[%s] GLTF data could not be loaded", fileName); + else TraceLog(LOG_WARNING, "[%s] glTF data could not be loaded", fileName); - free(buffer); - cgltf_free(&data); - return mesh; } #endif -- cgit v1.2.3 From 641895b5ba778fdc9024ebb58446dcc8ea36a00a Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 21 Feb 2019 18:45:19 +0100 Subject: Remove end-line spaces --- src/core.c | 6 +- src/models.c | 208 ++++++++++++++++++++++++++++----------------------------- src/raudio.c | 14 ++-- src/rlgl.h | 114 +++++++++++++++---------------- src/shapes.c | 8 +-- src/text.c | 86 ++++++++++++------------ src/textures.c | 4 +- 7 files changed, 220 insertions(+), 220 deletions(-) (limited to 'src/models.c') diff --git a/src/core.c b/src/core.c index 36315113..714e6e2c 100644 --- a/src/core.c +++ b/src/core.c @@ -707,7 +707,7 @@ bool WindowShouldClose(void) { #if defined(PLATFORM_WEB) // Emterpreter-Async required to run sync code - // https://github.com/kripken/emscripten/wiki/Emterpreter#emterpreter-async-run-synchronous-code + // https://github.com/emscripten-core/emscripten/wiki/Emterpreter#emterpreter-async-run-synchronous-code // By default, this function is never called on a web-ready raylib example because we encapsulate // frame code in a UpdateDrawFrame() function, to allow browser manage execution asynchronously // but now emscripten allows sync code to be executed in an interpreted way, using emterpreter! @@ -1228,7 +1228,7 @@ void BeginTextureMode(RenderTexture2D target) rlLoadIdentity(); // Reset current matrix (MODELVIEW) //rlScalef(0.0f, -1.0f, 0.0f); // Flip Y-drawing (?) - + // Setup current width/height for proper aspect ratio // calculation when using BeginMode3D() currentWidth = target.texture.width; @@ -1254,7 +1254,7 @@ void EndTextureMode(void) rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix rlLoadIdentity(); // Reset current matrix (MODELVIEW) - + // Reset current screen size currentWidth = GetScreenWidth(); currentHeight = GetScreenHeight(); diff --git a/src/models.c b/src/models.c index eace0f66..384c8db4 100644 --- a/src/models.c +++ b/src/models.c @@ -116,7 +116,7 @@ void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color) void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color) { if (rlCheckBufferLimit(2*36)) rlglDraw(); - + rlPushMatrix(); rlTranslatef(center.x, center.y, center.z); rlRotatef(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z); @@ -140,7 +140,7 @@ void DrawCube(Vector3 position, float width, float height, float length, Color c float x = 0.0f; float y = 0.0f; float z = 0.0f; - + if (rlCheckBufferLimit(36)) rlglDraw(); rlPushMatrix(); @@ -221,7 +221,7 @@ void DrawCubeWires(Vector3 position, float width, float height, float length, Co float x = 0.0f; float y = 0.0f; float z = 0.0f; - + if (rlCheckBufferLimit(36)) rlglDraw(); rlPushMatrix(); @@ -626,7 +626,7 @@ Model LoadModel(const char *fileName) Model LoadModelFromMesh(Mesh mesh) { Model model = { 0 }; - + model.mesh = mesh; model.transform = MatrixIdentity(); model.material = LoadMaterialDefault(); @@ -679,11 +679,11 @@ void UnloadMesh(Mesh *mesh) void ExportMesh(Mesh mesh, const char *fileName) { bool success = false; - + if (IsFileExtension(fileName, ".obj")) { FILE *objFile = fopen(fileName, "wt"); - + fprintf(objFile, "# //////////////////////////////////////////////////////////////////////////////////\n"); fprintf(objFile, "# // //\n"); fprintf(objFile, "# // rMeshOBJ exporter v1.0 - Mesh exported as triangle faces and not optimized //\n"); @@ -696,33 +696,33 @@ void ExportMesh(Mesh mesh, const char *fileName) fprintf(objFile, "# //////////////////////////////////////////////////////////////////////////////////\n\n"); fprintf(objFile, "# Vertex Count: %i\n", mesh.vertexCount); fprintf(objFile, "# Triangle Count: %i\n\n", mesh.triangleCount); - + fprintf(objFile, "g mesh\n"); - + for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3) { fprintf(objFile, "v %.2f %.2f %.2f\n", mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]); } - + for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 2) { fprintf(objFile, "vt %.2f %.2f\n", mesh.texcoords[v], mesh.texcoords[v + 1]); } - + for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3) { fprintf(objFile, "vn %.2f %.2f %.2f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]); } - + for (int i = 0; i < mesh.triangleCount; i += 3) { fprintf(objFile, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", i, i, i, i + 1, i + 1, i + 1, i + 2, i + 2, i + 2); } - + fprintf(objFile, "\n"); - + fclose(objFile); - + success = true; } else if (IsFileExtension(fileName, ".raw")) { } // TODO: Support additional file formats to export mesh vertex data @@ -737,7 +737,7 @@ Mesh GenMeshPoly(int sides, float radius) { Mesh mesh = { 0 }; int vertexCount = sides*3; - + // Vertices definition Vector3 *vertices = (Vector3 *)malloc(vertexCount*sizeof(Vector3)); for (int i = 0, v = 0; i < 360; i += 360/sides, v += 3) @@ -745,13 +745,13 @@ Mesh GenMeshPoly(int sides, float radius) vertices[v] = (Vector3){ 0.0f, 0.0f, 0.0f }; vertices[v + 1] = (Vector3){ sinf(DEG2RAD*i)*radius, 0.0f, cosf(DEG2RAD*i)*radius }; vertices[v + 2] = (Vector3){ sinf(DEG2RAD*(i + 360/sides))*radius, 0.0f, cosf(DEG2RAD*(i + 360/sides))*radius }; - } - + } + // Normals definition Vector3 *normals = (Vector3 *)malloc(vertexCount*sizeof(Vector3)); for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f }; // Vector3.up; - // TexCoords definition + // TexCoords definition Vector2 *texcoords = (Vector2 *)malloc(vertexCount*sizeof(Vector2)); for (int n = 0; n < vertexCount; n++) texcoords[n] = (Vector2){ 0.0f, 0.0f }; @@ -760,7 +760,7 @@ Mesh GenMeshPoly(int sides, float radius) 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)); - + // Mesh vertices position array for (int i = 0; i < mesh.vertexCount; i++) { @@ -768,14 +768,14 @@ Mesh GenMeshPoly(int sides, float radius) mesh.vertices[3*i + 1] = vertices[i].y; mesh.vertices[3*i + 2] = vertices[i].z; } - + // Mesh texcoords array for (int i = 0; i < mesh.vertexCount; i++) { mesh.texcoords[2*i] = texcoords[i].x; mesh.texcoords[2*i + 1] = texcoords[i].y; } - + // Mesh normals array for (int i = 0; i < mesh.vertexCount; i++) { @@ -783,14 +783,14 @@ Mesh GenMeshPoly(int sides, float radius) mesh.normals[3*i + 1] = normals[i].y; mesh.normals[3*i + 2] = normals[i].z; } - + free(vertices); free(normals); free(texcoords); // Upload vertex data to GPU (static mesh) - rlLoadMesh(&mesh, false); - + rlLoadMesh(&mesh, false); + return mesh; } @@ -803,7 +803,7 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ) #if defined(CUSTOM_MESH_GEN_PLANE) resX++; resZ++; - + // Vertices definition int vertexCount = resX*resZ; // vertices get reused for the faces @@ -824,7 +824,7 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ) Vector3 *normals = (Vector3 *)malloc(vertexCount*sizeof(Vector3)); for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f }; // Vector3.up; - // TexCoords definition + // TexCoords definition Vector2 *texcoords = (Vector2 *)malloc(vertexCount*sizeof(Vector2)); for (int v = 0; v < resZ; v++) { @@ -847,7 +847,7 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ) triangles[t++] = i + 1; triangles[t++] = i; - triangles[t++] = i + resX; + triangles[t++] = i + resX; triangles[t++] = i + resX + 1; triangles[t++] = i + 1; } @@ -858,7 +858,7 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ) mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float)); mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.indices = (unsigned short *)malloc(mesh.triangleCount*3*sizeof(unsigned short)); - + // Mesh vertices position array for (int i = 0; i < mesh.vertexCount; i++) { @@ -866,14 +866,14 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ) mesh.vertices[3*i + 1] = vertices[i].y; mesh.vertices[3*i + 2] = vertices[i].z; } - + // Mesh texcoords array for (int i = 0; i < mesh.vertexCount; i++) { mesh.texcoords[2*i] = texcoords[i].x; mesh.texcoords[2*i + 1] = texcoords[i].y; } - + // Mesh normals array for (int i = 0; i < mesh.vertexCount; i++) { @@ -881,22 +881,22 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ) mesh.normals[3*i + 1] = normals[i].y; mesh.normals[3*i + 2] = normals[i].z; } - + // Mesh indices array initialization for (int i = 0; i < mesh.triangleCount*3; i++) mesh.indices[i] = triangles[i]; - + free(vertices); free(normals); free(texcoords); free(triangles); - + #else // Use par_shapes library to generate plane mesh par_shapes_mesh *plane = par_shapes_create_plane(resX, resZ); // No normals/texcoords generated!!! par_shapes_scale(plane, width, length, 1.0f); par_shapes_rotate(plane, -PI/2.0f, (float[]){ 1, 0, 0 }); par_shapes_translate(plane, -width/2, 0.0f, length/2); - + mesh.vertices = (float *)malloc(plane->ntriangles*3*3*sizeof(float)); mesh.texcoords = (float *)malloc(plane->ntriangles*3*2*sizeof(float)); mesh.normals = (float *)malloc(plane->ntriangles*3*3*sizeof(float)); @@ -909,11 +909,11 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ) mesh.vertices[k*3] = plane->points[plane->triangles[k]*3]; mesh.vertices[k*3 + 1] = plane->points[plane->triangles[k]*3 + 1]; mesh.vertices[k*3 + 2] = plane->points[plane->triangles[k]*3 + 2]; - + mesh.normals[k*3] = plane->normals[plane->triangles[k]*3]; mesh.normals[k*3 + 1] = plane->normals[plane->triangles[k]*3 + 1]; mesh.normals[k*3 + 2] = plane->normals[plane->triangles[k]*3 + 2]; - + mesh.texcoords[k*2] = plane->tcoords[plane->triangles[k]*2]; mesh.texcoords[k*2 + 1] = plane->tcoords[plane->triangles[k]*2 + 1]; } @@ -922,7 +922,7 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ) #endif // Upload vertex data to GPU (static mesh) - rlLoadMesh(&mesh, false); + rlLoadMesh(&mesh, false); return mesh; } @@ -960,7 +960,7 @@ Mesh GenMeshCube(float width, float height, float length) -width/2, height/2, length/2, -width/2, height/2, -length/2 }; - + float texcoords[] = { 0.0f, 0.0f, 1.0f, 0.0f, @@ -987,7 +987,7 @@ Mesh GenMeshCube(float width, float height, float length) 1.0f, 1.0f, 0.0f, 1.0f }; - + float normals[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, @@ -1017,15 +1017,15 @@ Mesh GenMeshCube(float width, float height, float length) mesh.vertices = (float *)malloc(24*3*sizeof(float)); memcpy(mesh.vertices, vertices, 24*3*sizeof(float)); - + mesh.texcoords = (float *)malloc(24*2*sizeof(float)); memcpy(mesh.texcoords, texcoords, 24*2*sizeof(float)); - + mesh.normals = (float *)malloc(24*3*sizeof(float)); memcpy(mesh.normals, normals, 24*3*sizeof(float)); - + mesh.indices = (unsigned short *)malloc(36*sizeof(unsigned short)); - + int k = 0; // Indices can be initialized right now @@ -1040,10 +1040,10 @@ Mesh GenMeshCube(float width, float height, float length) k++; } - + mesh.vertexCount = 24; mesh.triangleCount = 12; - + #else // Use par_shapes library to generate cube mesh /* // Platonic solids: @@ -1057,11 +1057,11 @@ par_shapes_mesh* par_shapes_create_icosahedron(); // 20 sides polyhedron // NOTE: No normals/texcoords generated by default par_shapes_mesh *cube = par_shapes_create_cube(); cube->tcoords = PAR_MALLOC(float, 2*cube->npoints); - for (int i = 0; i < 2*cube->npoints; i++) cube->tcoords[i] = 0.0f; + for (int i = 0; i < 2*cube->npoints; i++) cube->tcoords[i] = 0.0f; par_shapes_scale(cube, width, height, length); par_shapes_translate(cube, -width/2, 0.0f, -length/2); par_shapes_compute_normals(cube); - + mesh.vertices = (float *)malloc(cube->ntriangles*3*3*sizeof(float)); mesh.texcoords = (float *)malloc(cube->ntriangles*3*2*sizeof(float)); mesh.normals = (float *)malloc(cube->ntriangles*3*3*sizeof(float)); @@ -1074,11 +1074,11 @@ par_shapes_mesh* par_shapes_create_icosahedron(); // 20 sides polyhedron mesh.vertices[k*3] = cube->points[cube->triangles[k]*3]; mesh.vertices[k*3 + 1] = cube->points[cube->triangles[k]*3 + 1]; mesh.vertices[k*3 + 2] = cube->points[cube->triangles[k]*3 + 2]; - + mesh.normals[k*3] = cube->normals[cube->triangles[k]*3]; mesh.normals[k*3 + 1] = cube->normals[cube->triangles[k]*3 + 1]; mesh.normals[k*3 + 2] = cube->normals[cube->triangles[k]*3 + 2]; - + mesh.texcoords[k*2] = cube->tcoords[cube->triangles[k]*2]; mesh.texcoords[k*2 + 1] = cube->tcoords[cube->triangles[k]*2 + 1]; } @@ -1087,7 +1087,7 @@ par_shapes_mesh* par_shapes_create_icosahedron(); // 20 sides polyhedron #endif // Upload vertex data to GPU (static mesh) - rlLoadMesh(&mesh, false); + rlLoadMesh(&mesh, false); return mesh; } @@ -1099,8 +1099,8 @@ RLAPI Mesh GenMeshSphere(float radius, int rings, int slices) par_shapes_mesh *sphere = par_shapes_create_parametric_sphere(slices, rings); par_shapes_scale(sphere, radius, radius, radius); - // NOTE: Soft normals are computed internally - + // NOTE: Soft normals are computed internally + mesh.vertices = (float *)malloc(sphere->ntriangles*3*3*sizeof(float)); mesh.texcoords = (float *)malloc(sphere->ntriangles*3*2*sizeof(float)); mesh.normals = (float *)malloc(sphere->ntriangles*3*3*sizeof(float)); @@ -1113,19 +1113,19 @@ RLAPI Mesh GenMeshSphere(float radius, int rings, int slices) mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3]; mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1]; mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2]; - + mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3]; mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1]; mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2]; - + mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2]; mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1]; } par_shapes_free_mesh(sphere); - + // Upload vertex data to GPU (static mesh) - rlLoadMesh(&mesh, false); + rlLoadMesh(&mesh, false); return mesh; } @@ -1137,8 +1137,8 @@ RLAPI Mesh GenMeshHemiSphere(float radius, int rings, int slices) par_shapes_mesh *sphere = par_shapes_create_hemisphere(slices, rings); par_shapes_scale(sphere, radius, radius, radius); - // NOTE: Soft normals are computed internally - + // NOTE: Soft normals are computed internally + mesh.vertices = (float *)malloc(sphere->ntriangles*3*3*sizeof(float)); mesh.texcoords = (float *)malloc(sphere->ntriangles*3*2*sizeof(float)); mesh.normals = (float *)malloc(sphere->ntriangles*3*3*sizeof(float)); @@ -1151,19 +1151,19 @@ RLAPI Mesh GenMeshHemiSphere(float radius, int rings, int slices) mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3]; mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1]; mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2]; - + mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3]; mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1]; mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2]; - + mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2]; mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1]; } par_shapes_free_mesh(sphere); - + // Upload vertex data to GPU (static mesh) - rlLoadMesh(&mesh, false); + rlLoadMesh(&mesh, false); return mesh; } @@ -1175,7 +1175,7 @@ Mesh GenMeshCylinder(float radius, float height, int slices) // Instance a cylinder that sits on the Z=0 plane using the given tessellation // levels across the UV domain. Think of "slices" like a number of pizza - // slices, and "stacks" like a number of stacked rings. + // slices, and "stacks" like a number of stacked rings. // Height and radius are both 1.0, but they can easily be changed with par_shapes_scale par_shapes_mesh *cylinder = par_shapes_create_cylinder(slices, 8); par_shapes_scale(cylinder, radius, radius, height); @@ -1187,16 +1187,16 @@ Mesh GenMeshCylinder(float radius, float height, int slices) for (int i = 0; i < 2*capTop->npoints; i++) capTop->tcoords[i] = 0.0f; par_shapes_rotate(capTop, -PI/2.0f, (float[]){ 1, 0, 0 }); par_shapes_translate(capTop, 0, height, 0); - + // Generate an orientable disk shape (bottom cap) par_shapes_mesh *capBottom = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, -1 }); capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints); for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f; par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 }); - + par_shapes_merge_and_free(cylinder, capTop); par_shapes_merge_and_free(cylinder, capBottom); - + mesh.vertices = (float *)malloc(cylinder->ntriangles*3*3*sizeof(float)); mesh.texcoords = (float *)malloc(cylinder->ntriangles*3*2*sizeof(float)); mesh.normals = (float *)malloc(cylinder->ntriangles*3*3*sizeof(float)); @@ -1209,19 +1209,19 @@ Mesh GenMeshCylinder(float radius, float height, int slices) mesh.vertices[k*3] = cylinder->points[cylinder->triangles[k]*3]; mesh.vertices[k*3 + 1] = cylinder->points[cylinder->triangles[k]*3 + 1]; mesh.vertices[k*3 + 2] = cylinder->points[cylinder->triangles[k]*3 + 2]; - + mesh.normals[k*3] = cylinder->normals[cylinder->triangles[k]*3]; mesh.normals[k*3 + 1] = cylinder->normals[cylinder->triangles[k]*3 + 1]; mesh.normals[k*3 + 2] = cylinder->normals[cylinder->triangles[k]*3 + 2]; - + mesh.texcoords[k*2] = cylinder->tcoords[cylinder->triangles[k]*2]; mesh.texcoords[k*2 + 1] = cylinder->tcoords[cylinder->triangles[k]*2 + 1]; } par_shapes_free_mesh(cylinder); - + // Upload vertex data to GPU (static mesh) - rlLoadMesh(&mesh, false); + rlLoadMesh(&mesh, false); return mesh; } @@ -1233,7 +1233,7 @@ Mesh GenMeshTorus(float radius, float size, int radSeg, int sides) if (radius > 1.0f) radius = 1.0f; else if (radius < 0.1f) radius = 0.1f; - + // Create a donut that sits on the Z=0 plane with the specified inner radius // The outer radius can be controlled with par_shapes_scale par_shapes_mesh *torus = par_shapes_create_torus(radSeg, sides, radius); @@ -1251,19 +1251,19 @@ Mesh GenMeshTorus(float radius, float size, int radSeg, int sides) mesh.vertices[k*3] = torus->points[torus->triangles[k]*3]; mesh.vertices[k*3 + 1] = torus->points[torus->triangles[k]*3 + 1]; mesh.vertices[k*3 + 2] = torus->points[torus->triangles[k]*3 + 2]; - + mesh.normals[k*3] = torus->normals[torus->triangles[k]*3]; mesh.normals[k*3 + 1] = torus->normals[torus->triangles[k]*3 + 1]; mesh.normals[k*3 + 2] = torus->normals[torus->triangles[k]*3 + 2]; - + mesh.texcoords[k*2] = torus->tcoords[torus->triangles[k]*2]; mesh.texcoords[k*2 + 1] = torus->tcoords[torus->triangles[k]*2 + 1]; } par_shapes_free_mesh(torus); - + // Upload vertex data to GPU (static mesh) - rlLoadMesh(&mesh, false); + rlLoadMesh(&mesh, false); return mesh; } @@ -1272,7 +1272,7 @@ Mesh GenMeshTorus(float radius, float size, int radSeg, int sides) Mesh GenMeshKnot(float radius, float size, int radSeg, int sides) { Mesh mesh = { 0 }; - + if (radius > 3.0f) radius = 3.0f; else if (radius < 0.5f) radius = 0.5f; @@ -1291,19 +1291,19 @@ Mesh GenMeshKnot(float radius, float size, int radSeg, int sides) mesh.vertices[k*3] = knot->points[knot->triangles[k]*3]; mesh.vertices[k*3 + 1] = knot->points[knot->triangles[k]*3 + 1]; mesh.vertices[k*3 + 2] = knot->points[knot->triangles[k]*3 + 2]; - + mesh.normals[k*3] = knot->normals[knot->triangles[k]*3]; mesh.normals[k*3 + 1] = knot->normals[knot->triangles[k]*3 + 1]; mesh.normals[k*3 + 2] = knot->normals[knot->triangles[k]*3 + 2]; - + mesh.texcoords[k*2] = knot->tcoords[knot->triangles[k]*2]; mesh.texcoords[k*2 + 1] = knot->tcoords[knot->triangles[k]*2 + 1]; } par_shapes_free_mesh(knot); - + // Upload vertex data to GPU (static mesh) - rlLoadMesh(&mesh, false); + rlLoadMesh(&mesh, false); return mesh; } @@ -1411,7 +1411,7 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size) } free(pixels); - + // Upload vertex data to GPU (static mesh) rlLoadMesh(&mesh, false); @@ -1771,9 +1771,9 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) free(mapTexcoords); free(cubicmapPixels); // Free image pixel data - + // Upload vertex data to GPU (static mesh) - rlLoadMesh(&mesh, false); + rlLoadMesh(&mesh, false); return mesh; } @@ -1821,7 +1821,7 @@ void UnloadMaterial(Material material) // Unload loaded texture maps (avoid unloading default texture, managed by raylib) for (int i = 0; i < MAX_MATERIAL_MAPS; i++) { - if (material.maps[i].texture.id != GetTextureDefault().id) rlDeleteTextures(material.maps[i].texture.id); + if (material.maps[i].texture.id != GetTextureDefault().id) rlDeleteTextures(material.maps[i].texture.id); } } @@ -1842,7 +1842,7 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota Matrix matScale = MatrixScale(scale.x, scale.y, scale.z); Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD); Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z); - + Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); // Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform) @@ -2037,7 +2037,7 @@ bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadi if (distance < sphereRadius) collisionDistance = vector + sqrtf(d); else collisionDistance = vector - sqrtf(d); - + // Calculate collision point Vector3 cPoint = Vector3Add(ray.position, Vector3Scale(ray.direction, collisionDistance)); @@ -2097,7 +2097,7 @@ RayHitInfo GetCollisionRayModel(Ray ray, Model *model) b = vertdata[i*3 + 1]; c = vertdata[i*3 + 2]; } - + a = Vector3Transform(a, model->transform); b = Vector3Transform(b, model->transform); c = Vector3Transform(c, model->transform); @@ -2231,7 +2231,7 @@ void MeshTangents(Mesh *mesh) { if (mesh->tangents == NULL) mesh->tangents = (float *)malloc(mesh->vertexCount*4*sizeof(float)); else TraceLog(LOG_WARNING, "Mesh tangents already exist"); - + Vector3 *tan1 = (Vector3 *)malloc(mesh->vertexCount*sizeof(Vector3)); Vector3 *tan2 = (Vector3 *)malloc(mesh->vertexCount*sizeof(Vector3)); @@ -2264,7 +2264,7 @@ void MeshTangents(Mesh *mesh) Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r }; Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r }; - + tan1[i + 0] = sdir; tan1[i + 1] = sdir; tan1[i + 2] = sdir; @@ -2296,10 +2296,10 @@ void MeshTangents(Mesh *mesh) mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f) ? -1.0f : 1.0f; #endif } - + free(tan1); free(tan2); - + TraceLog(LOG_INFO, "Tangents computed for mesh"); } @@ -2311,7 +2311,7 @@ void MeshBinormals(Mesh *mesh) 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] }; float tangentW = mesh->tangents[i*4 + 3]; - + // TODO: Register computed binormal in mesh->binormal ? // Vector3 binormal = Vector3Multiply(Vector3CrossProduct(normal, tangent), tangentW); } @@ -2740,11 +2740,11 @@ static Material LoadMTL(const char *fileName) static Mesh LoadIQM(const char *fileName) { Mesh mesh = { 0 }; - + // TODO: Load IQM file - + return mesh; -} +} #endif #if defined(SUPPORT_FILEFORMAT_GLTF) @@ -2752,10 +2752,10 @@ static Mesh LoadIQM(const char *fileName) static Mesh LoadGLTF(const char *fileName) { Mesh mesh = { 0 }; - + // glTF file loading FILE *gltfFile = fopen(fileName, "rb"); - + if (gltfFile == NULL) { TraceLog(LOG_WARNING, "[%s] glTF file could not be opened", fileName); @@ -2768,31 +2768,31 @@ static Mesh LoadGLTF(const char *fileName) void *buffer = malloc(size); fread(buffer, size, 1, gltfFile); - + fclose(gltfFile); // glTF data loading cgltf_options options = {0}; 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); - + // TODO: Process glTF data and map to mesh - + // NOTE: data.buffers[] and data.images[] should be loaded // using buffers[n].uri and images[n].uri... or use cgltf_load_buffers(&options, data, fileName); - + cgltf_free(&data); } else TraceLog(LOG_WARNING, "[%s] glTF data could not be loaded", fileName); - return mesh; + return mesh; } #endif diff --git a/src/raudio.c b/src/raudio.c index b19c7d86..e1c9fd48 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -1245,7 +1245,7 @@ Music LoadMusicStream(const char *fileName) void UnloadMusicStream(Music music) { if (music == NULL) return; - + CloseAudioStream(music->stream); #if defined(SUPPORT_FILEFORMAT_OGG) @@ -1311,7 +1311,7 @@ void ResumeMusicStream(Music music) void StopMusicStream(Music music) { if (music == NULL) return; - + StopAudioStream(music->stream); // Restart music context @@ -1343,7 +1343,7 @@ void StopMusicStream(Music music) void UpdateMusicStream(Music music) { if (music == NULL) return; - + bool streamEnding = false; unsigned int subBufferSizeInFrames = ((AudioBuffer *)music->stream.audioBuffer)->bufferSizeInFrames/2; @@ -1393,16 +1393,16 @@ void UpdateMusicStream(Music music) } break; #endif #if defined(SUPPORT_FILEFORMAT_MOD) - case MUSIC_MODULE_MOD: + case MUSIC_MODULE_MOD: { // NOTE: 3rd parameter (nbsample) specify the number of stereo 16bits samples you want, so sampleCount/2 - jar_mod_fillbuffer(&music->ctxMod, (short *)pcm, samplesCount/2, 0); + jar_mod_fillbuffer(&music->ctxMod, (short *)pcm, samplesCount/2, 0); } break; #endif default: break; } - + UpdateAudioStream(music->stream, pcm, samplesCount); if ((music->ctxType == MUSIC_MODULE_XM) || (music->ctxType == MUSIC_MODULE_MOD)) { @@ -1475,7 +1475,7 @@ void SetMusicLoopCount(Music music, int count) float GetMusicTimeLength(Music music) { float totalSeconds = 0.0f; - + if (music != NULL) totalSeconds = (float)music->totalSamples/(music->stream.sampleRate*music->stream.channels); return totalSeconds; diff --git a/src/rlgl.h b/src/rlgl.h index f2762637..c9f15385 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -356,7 +356,7 @@ typedef unsigned char byte; LOC_MAP_PREFILTER, LOC_MAP_BRDF } ShaderLocationIndex; - + // Shader uniform data types typedef enum { UNIFORM_FLOAT = 0, @@ -993,14 +993,14 @@ void rlPushMatrix(void) // Pop lattest inserted matrix from stack void rlPopMatrix(void) -{ +{ if (stackCounter > 0) { Matrix mat = stack[stackCounter - 1]; *currentMatrix = mat; stackCounter--; } - + if ((stackCounter == 0) && (currentMatrixMode == RL_MODELVIEW)) { currentMatrix = &modelview; @@ -1141,7 +1141,7 @@ void rlEnd(void) // Make sure vertexCount is the same for vertices, texcoords, colors and normals // NOTE: In OpenGL 1.1, one glColor call can be made for all the subsequent glVertex calls - + // Make sure colors count match vertex count if (vertexData[currentBuffer].vCounter != vertexData[currentBuffer].cCounter) { @@ -1156,7 +1156,7 @@ void rlEnd(void) vertexData[currentBuffer].cCounter++; } } - + // Make sure texcoords count match vertex count if (vertexData[currentBuffer].vCounter != vertexData[currentBuffer].tcCounter) { @@ -1194,10 +1194,10 @@ void rlEnd(void) void rlVertex3f(float x, float y, float z) { Vector3 vec = { x, y, z }; - + // Transform provided vector if required if (useTransformMatrix) vec = Vector3Transform(vec, transformMatrix); - + // Verify that MAX_BATCH_ELEMENTS limit not reached if (vertexData[currentBuffer].vCounter < (MAX_BATCH_ELEMENTS*4)) { @@ -1499,7 +1499,7 @@ void rlglInit(int width, int height) //for (int i = 0; i < numComp; i++) TraceLog(LOG_INFO, "Supported compressed format: 0x%x", format[i]); // NOTE: We don't need that much data on screen... right now... - + // TODO: Automatize extensions loading using rlLoadExtensions() and GLAD // Actually, when rlglInit() is called in InitWindow() in core.c, // OpenGL required extensions have already been loaded (PLATFORM_DESKTOP) @@ -1512,7 +1512,7 @@ void rlglInit(int width, int height) // NOTE: On OpenGL 3.3 VAO and NPOT are supported by default vaoSupported = true; - + // Multiple texture extensions supported by default texNPOTSupported = true; texFloatSupported = true; @@ -1585,11 +1585,11 @@ void rlglInit(int width, int height) // Check texture float support if (strcmp(extList[i], (const char *)"GL_OES_texture_float") == 0) texFloatSupported = true; - + // Check depth texture support if ((strcmp(extList[i], (const char *)"GL_OES_depth_texture") == 0) || (strcmp(extList[i], (const char *)"GL_WEBGL_depth_texture") == 0)) texDepthSupported = true; - + if (strcmp(extList[i], (const char *)"GL_OES_depth24") == 0) maxDepthBits = 24; if (strcmp(extList[i], (const char *)"GL_OES_depth32") == 0) maxDepthBits = 32; #endif @@ -1648,8 +1648,8 @@ void rlglInit(int width, int height) if (debugMarkerSupported) TraceLog(LOG_INFO, "[EXTENSION] Debug Marker supported"); - - + + // Initialize buffers, default shaders and default textures //---------------------------------------------------------- @@ -1666,7 +1666,7 @@ void rlglInit(int width, int height) // Init default vertex arrays buffers LoadBuffersDefault(); - + // Init transformations matrix accumulator transformMatrix = MatrixIdentity(); @@ -1995,9 +1995,9 @@ unsigned int rlLoadTextureDepth(int width, int height, int bits, bool useRenderB { unsigned int id = 0; unsigned int glInternalFormat = GL_DEPTH_COMPONENT16; - + if ((bits != 16) && (bits != 24) && (bits != 32)) bits = 16; - + if (bits == 24) { #if defined(GRAPHICS_API_OPENGL_33) @@ -2006,7 +2006,7 @@ unsigned int rlLoadTextureDepth(int width, int height, int bits, bool useRenderB if (maxDepthBits >= 24) glInternalFormat = GL_DEPTH_COMPONENT24_OES; #endif } - + if (bits == 32) { #if defined(GRAPHICS_API_OPENGL_33) @@ -2021,7 +2021,7 @@ unsigned int rlLoadTextureDepth(int width, int height, int bits, bool useRenderB glGenTextures(1, &id); glBindTexture(GL_TEXTURE_2D, id); glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); - + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -2036,10 +2036,10 @@ unsigned int rlLoadTextureDepth(int width, int height, int bits, bool useRenderB glGenRenderbuffers(1, &id); glBindRenderbuffer(GL_RENDERBUFFER, id); glRenderbufferStorage(GL_RENDERBUFFER, glInternalFormat, width, height); - + glBindRenderbuffer(GL_RENDERBUFFER, 0); } - + return id; } @@ -2053,7 +2053,7 @@ unsigned int rlLoadTextureCubemap(void *data, int size, int format) glGenTextures(1, &cubemapId); glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapId); - + unsigned int glInternalFormat, glFormat, glType; rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); @@ -2084,7 +2084,7 @@ unsigned int rlLoadTextureCubemap(void *data, int size, int format) #endif } } - + // Set cubemap texture sampling parameters glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -2178,14 +2178,14 @@ void rlUnloadTexture(unsigned int id) RenderTexture2D rlLoadRenderTexture(int width, int height, int format, int depthBits, bool useDepthTexture) { RenderTexture2D target = { 0 }; - + if (useDepthTexture && texDepthSupported) target.depthTexture = true; -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Create the framebuffer object glGenFramebuffers(1, &target.id); glBindFramebuffer(GL_FRAMEBUFFER, target.id); - + // Create fbo color texture attachment //----------------------------------------------------------------------------------------------------- if ((format != -1) && (format < COMPRESSED_DXT1_RGB)) @@ -2198,7 +2198,7 @@ RenderTexture2D rlLoadRenderTexture(int width, int height, int format, int depth target.texture.mipmaps = 1; } //----------------------------------------------------------------------------------------------------- - + // Create fbo depth renderbuffer/texture //----------------------------------------------------------------------------------------------------- if (depthBits > 0) @@ -2210,7 +2210,7 @@ RenderTexture2D rlLoadRenderTexture(int width, int height, int format, int depth target.depth.mipmaps = 1; } //----------------------------------------------------------------------------------------------------- - + // Attach color texture and depth renderbuffer to FBO //----------------------------------------------------------------------------------------------------- rlRenderTextureAttach(target, target.texture.id, 0); // COLOR attachment @@ -2235,12 +2235,12 @@ void rlRenderTextureAttach(RenderTexture2D target, unsigned int id, int attachTy glBindFramebuffer(GL_FRAMEBUFFER, target.id); if (attachType == 0) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, id, 0); - else if (attachType == 1) + else if (attachType == 1) { if (target.depthTexture) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, id, 0); else glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, id); } - + glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -2248,7 +2248,7 @@ void rlRenderTextureAttach(RenderTexture2D target, unsigned int id, int attachTy bool rlRenderTextureComplete(RenderTexture target) { glBindFramebuffer(GL_FRAMEBUFFER, target.id); - + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) @@ -2264,9 +2264,9 @@ bool rlRenderTextureComplete(RenderTexture target) default: break; } } - + glBindFramebuffer(GL_FRAMEBUFFER, 0); - + return (status == GL_FRAMEBUFFER_COMPLETE); } @@ -2349,7 +2349,7 @@ void rlLoadMesh(Mesh *mesh, bool dynamic) TraceLog(LOG_WARNING, "Trying to re-load an already loaded mesh"); return; } - + mesh->vaoId = 0; // Vertex Array Object mesh->vboId[0] = 0; // Vertex positions VBO mesh->vboId[1] = 0; // Vertex texcoords VBO @@ -2766,7 +2766,7 @@ unsigned char *rlReadScreenPixels(int width, int height) for (int x = 0; x < (width*4); x++) { imgData[((height - 1) - y)*width*4 + x] = screenData[(y*width*4) + x]; // Flip line - + // Set alpha component value to 255 (no trasparent image retrieval) // NOTE: Alpha value has already been applied to RGB in framebuffer, we don't need it! if (((x + 1)%4) == 0) imgData[((height - 1) - y)*width*4 + x] = 255; @@ -2822,7 +2822,7 @@ void *rlReadTexturePixels(Texture2D texture) // We are using Option 1, just need to care for texture format on retrieval // NOTE: This behaviour could be conditioned by graphic driver... RenderTexture2D fbo = rlLoadRenderTexture(texture.width, texture.height, UNCOMPRESSED_R8G8B8A8, 16, false); - + glBindFramebuffer(GL_FRAMEBUFFER, fbo.id); glBindTexture(GL_TEXTURE_2D, 0); @@ -2836,7 +2836,7 @@ void *rlReadTexturePixels(Texture2D texture) // Get OpenGL internal formats and data type from our texture format unsigned int glInternalFormat, glFormat, glType; rlGetGlTextureFormats(texture.format, &glInternalFormat, &glFormat, &glType); - + // NOTE: We read data as RGBA because FBO texture is configured as RGBA, despite binding a RGB texture... glReadPixels(0, 0, texture.width, texture.height, glFormat, glType, pixels); @@ -3064,7 +3064,7 @@ void SetShaderValueV(Shader shader, int uniformLoc, const void *value, int unifo case UNIFORM_SAMPLER2D: glUniform1iv(uniformLoc, count, (int *)value); break; default: TraceLog(LOG_WARNING, "Shader uniform could not be set data type not recognized"); } - + //glUseProgram(0); // Avoid reseting current shader program, in case other uniforms are set #endif } @@ -3143,7 +3143,7 @@ Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size) // NOTE: Faces are stored as 32 bit floating point values glGenTextures(1, &cubemap.id); glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id); - for (unsigned int i = 0; i < 6; i++) + for (unsigned int i = 0; i < 6; i++) { #if defined(GRAPHICS_API_OPENGL_33) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB32F, size, size, 0, GL_RGB, GL_FLOAT, NULL); @@ -3151,7 +3151,7 @@ Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size) if (texFloatSupported) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, size, size, 0, GL_RGB, GL_FLOAT, NULL); #endif } - + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); #if defined(GRAPHICS_API_OPENGL_33) @@ -3231,7 +3231,7 @@ Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size, size, 0, GL_RGB, GL_FLOAT, NULL); } - + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); @@ -3309,7 +3309,7 @@ Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size, size, 0, GL_RGB, GL_FLOAT, NULL); } - + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); @@ -3417,7 +3417,7 @@ Texture2D GenTextureBRDF(Shader shader, int size) // Unbind framebuffer and textures glBindFramebuffer(GL_FRAMEBUFFER, 0); - + // Unload framebuffer but keep color texture glDeleteRenderbuffers(1, &rbo); glDeleteFramebuffers(1, &fbo); @@ -3464,7 +3464,7 @@ void EndBlendMode(void) void BeginScissorMode(int x, int y, int width, int height) { rlglDraw(); // Force drawing elements - + glEnable(GL_SCISSOR_TEST); glScissor(x, screenHeight - (y + height), width, height); } @@ -3473,7 +3473,7 @@ void BeginScissorMode(int x, int y, int width, int height) void EndScissorMode(void) { rlglDraw(); // Force drawing elements - + glDisable(GL_SCISSOR_TEST); } @@ -4050,7 +4050,7 @@ static void LoadBuffersDefault(void) glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*6*MAX_BATCH_ELEMENTS, vertexData[i].indices, GL_STATIC_DRAW); #endif } - + TraceLog(LOG_INFO, "Internal buffers uploaded successfully (GPU)"); // Unbind the current VAO @@ -4073,7 +4073,7 @@ static void UpdateBuffersDefault(void) glBindBuffer(GL_ARRAY_BUFFER, vertexData[currentBuffer].vboId[0]); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*vertexData[currentBuffer].vCounter, vertexData[currentBuffer].vertices); //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_BATCH_ELEMENTS, vertexData[currentBuffer].vertices, GL_DYNAMIC_DRAW); // Update all buffer - + // Texture coordinates buffer glBindBuffer(GL_ARRAY_BUFFER, vertexData[currentBuffer].vboId[1]); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*vertexData[currentBuffer].vCounter, vertexData[currentBuffer].texcoords); @@ -4083,13 +4083,13 @@ static void UpdateBuffersDefault(void) glBindBuffer(GL_ARRAY_BUFFER, vertexData[currentBuffer].vboId[2]); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*vertexData[currentBuffer].vCounter, vertexData[currentBuffer].colors); //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_BATCH_ELEMENTS, vertexData[currentBuffer].colors, GL_DYNAMIC_DRAW); // Update all buffer - + // NOTE: glMapBuffer() causes sync issue. - // If GPU is working with this buffer, glMapBuffer() will wait(stall) until GPU to finish its job. + // If GPU is working with this buffer, glMapBuffer() will wait(stall) until GPU to finish its job. // To avoid waiting (idle), you can call first glBufferData() with NULL pointer before glMapBuffer(). // If you do that, the previous data in PBO will be discarded and glMapBuffer() returns a new // allocated pointer immediately even if GPU is still working with the previous data. - + // Another option: map the buffer object into client's memory // Probably this code could be moved somewhere else... // vertexData[currentBuffer].vertices = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); @@ -4135,7 +4135,7 @@ static void DrawBuffersDefault(void) glUniform1i(currentShader.locs[LOC_MAP_DIFFUSE], 0); // NOTE: Additional map textures not considered for default buffers drawing - + int vertexOffset = 0; if (vaoSupported) glBindVertexArray(vertexData[currentBuffer].vaoId); @@ -4160,7 +4160,7 @@ static void DrawBuffersDefault(void) } glActiveTexture(GL_TEXTURE0); - + for (int i = 0; i < drawsCounter; i++) { glBindTexture(GL_TEXTURE_2D, draws[i].textureId); @@ -4170,7 +4170,7 @@ static void DrawBuffersDefault(void) { #if defined(GRAPHICS_API_OPENGL_33) // We need to define the number of indices to be processed: quadsCount*6 - // NOTE: The final parameter tells the GPU the offset in bytes from the + // NOTE: The final parameter tells the GPU the offset in bytes from the // start of the index buffer to the location of the first index to process glDrawElements(GL_TRIANGLES, draws[i].vertexCount/4*6, GL_UNSIGNED_INT, (GLvoid *)(sizeof(GLuint)*vertexOffset/4*6)); #elif defined(GRAPHICS_API_OPENGL_ES2) @@ -4216,7 +4216,7 @@ static void DrawBuffersDefault(void) } drawsCounter = 1; - + // Change to next buffer in the list currentBuffer++; if (currentBuffer >= MAX_BATCH_BUFFERING) currentBuffer = 0; @@ -4369,14 +4369,14 @@ static void GenDrawCube(void) static VrStereoConfig SetStereoConfig(VrDeviceInfo hmd, Shader distortion) { VrStereoConfig config = { 0 }; - + // Initialize framebuffer and textures for stereo rendering // NOTE: Screen size should match HMD aspect ratio config.stereoFbo = rlLoadRenderTexture(screenWidth, screenHeight, UNCOMPRESSED_R8G8B8A8, 24, false); - + // Assign distortion shader config.distortionShader = distortion; - + // Compute aspect ratio float aspect = ((float)hmd.hResolution*0.5f)/(float)hmd.vResolution; @@ -4442,7 +4442,7 @@ static VrStereoConfig SetStereoConfig(VrDeviceInfo hmd, Shader distortion) SetShaderValue(config.distortionShader, GetShaderLocation(config.distortionShader, "hmdWarpParam"), hmd.lensDistortionValues, UNIFORM_VEC4); SetShaderValue(config.distortionShader, GetShaderLocation(config.distortionShader, "chromaAbParam"), hmd.chromaAbCorrection, UNIFORM_VEC4); #endif - + return config; } diff --git a/src/shapes.c b/src/shapes.c index 8976c81c..87bb573c 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -143,7 +143,7 @@ void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color) rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height); rlVertex2f(0.0f, thick); - + rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height); rlVertex2f(d, thick); @@ -187,7 +187,7 @@ void DrawCircle(int centerX, int centerY, float radius, Color color) void DrawCircleSector(Vector2 center, float radius, int startAngle, int endAngle, Color color) { #define CIRCLE_SECTOR_LENGTH 10 - + #if defined(SUPPORT_QUADS_DRAW_MODE) if (rlCheckBufferLimit(4*((360/CIRCLE_SECTOR_LENGTH)/2))) rlglDraw(); @@ -307,10 +307,10 @@ void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height); rlVertex2f(0.0f, 0.0f); - + rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height); rlVertex2f(0.0f, rec.height); - + rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height); rlVertex2f(rec.width, rec.height); diff --git a/src/text.c b/src/text.c index 17f6d9dd..9a7d690d 100644 --- a/src/text.c +++ b/src/text.c @@ -790,14 +790,14 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f } // Draw text using font inside rectangle limits -void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint) +void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint) { DrawTextRecEx(font, text, rec, fontSize, spacing, wordWrap, tint, 0, 0, WHITE, WHITE); } // Draw text using font inside rectangle limits with support for text selection -void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, - int selectStart, int selectLength, Color selectText, Color selectBack) +void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, + int selectStart, int selectLength, Color selectText, Color selectBack) { int length = strlen(text); int textOffsetX = 0; // Offset between characters @@ -813,12 +813,12 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f int state = wordWrap? MEASURE_STATE : DRAW_STATE; int startLine = -1; // Index where to begin drawing (where a line begins) int endLine = -1; // Index where to stop drawing (where a line ends) - + for (int i = 0; i < length; i++) { int glyphWidth = 0; letter = (unsigned char)text[i]; - + if (letter != '\n') { if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification HACK! @@ -836,41 +836,41 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f i++; } else index = GetGlyphIndex(font, (unsigned char)text[i]); - - glyphWidth = (font.chars[index].advanceX == 0)? + + glyphWidth = (font.chars[index].advanceX == 0)? (int)(font.chars[index].rec.width*scaleFactor + spacing): (int)(font.chars[index].advanceX*scaleFactor + spacing); } - + // NOTE: When wordWrap is ON we first measure how much of the text we can draw - // before going outside of the `rec` container. We store this info inside + // before going outside of the `rec` container. We store this info inside // `startLine` and `endLine` then we change states, draw the text between those two // variables then change states again and again recursively until the end of the text // (or until we get outside of the container). - // When wordWrap is OFF we don't need the measure state so we go to the drawing - // state immediately and begin drawing on the next line before we can get outside + // When wordWrap is OFF we don't need the measure state so we go to the drawing + // state immediately and begin drawing on the next line before we can get outside // the container. - if (state == MEASURE_STATE) + if (state == MEASURE_STATE) { if ((letter == ' ') || (letter == '\t') || (letter == '\n')) endLine = i; - - if ((textOffsetX + glyphWidth + 1) >= rec.width) + + if ((textOffsetX + glyphWidth + 1) >= rec.width) { endLine = (endLine < 1) ? i : endLine; if (i == endLine) endLine -= 1; if ((startLine + 1) == endLine) endLine = i - 1; state = !state; - } - else if ((i + 1) == length) + } + else if ((i + 1) == length) { endLine = i; state = !state; } - else if (letter == '\n') + else if (letter == '\n') { state = !state; } - + if (state == DRAW_STATE) { textOffsetX = 0; @@ -878,8 +878,8 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f glyphWidth = 0; } - } - else + } + else { if (letter == '\n') { @@ -888,17 +888,17 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); textOffsetX = 0; } - } - else + } + else { if (!wordWrap && ((textOffsetX + glyphWidth + 1) >= rec.width)) { textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); textOffsetX = 0; } - + if ((textOffsetY + (int)((font.baseSize + font.baseSize/2)*scaleFactor)) > rec.height) break; - + //draw selected bool isGlyphSelected = false; if ((selectStart >= 0) && (i >= selectStart) && (i < (selectStart + selectLength))) @@ -907,7 +907,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f DrawRectangleRec(strec, selectBack); isGlyphSelected = true; } - + //draw glyph if ((letter != ' ') && (letter != '\t')) { @@ -915,12 +915,12 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f (Rectangle){ rec.x + textOffsetX + font.chars[index].offsetX*scaleFactor, rec.y + textOffsetY + font.chars[index].offsetY*scaleFactor, font.chars[index].rec.width*scaleFactor, - font.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, + font.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, (!isGlyphSelected) ? tint : selectText); } } - - if (wordWrap && (i == endLine)) + + if (wordWrap && (i == endLine)) { textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); textOffsetX = 0; @@ -930,7 +930,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f state = !state; } } - + textOffsetX += glyphWidth; } } @@ -968,11 +968,11 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing unsigned char letter = 0; // Current character int index = 0; // Index position in sprite font - + for (int i = 0; i < len; i++) { lenCounter++; - + if (text[i] != '\n') { if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification @@ -1105,7 +1105,7 @@ const char *TextSubtext(const char *text, int position, int length) const char *TextReplace(char *text, const char *replace, const char *by) { char *result; - + char *insertPoint; // Next insert point char *temp; // Temp pointer int replaceLen; // Replace string length of (the string to remove) @@ -1163,7 +1163,7 @@ const char *TextInsert(const char *text, const char *insert, int position) for (int i = 0; i < position; i++) result[i] = text[i]; for (int i = position; i < insertLen + position; i++) result[i] = insert[i]; for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i]; - + result[textLen + insertLen] = '\0'; // Make sure text string is valid! return result; @@ -1174,7 +1174,7 @@ const char *TextInsert(const char *text, const char *insert, int position) const char *TextJoin(const char **textList, int count, const char *delimiter) { // TODO: Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH - + static char text[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(text, 0, MAX_TEXT_BUFFER_LENGTH); @@ -1197,9 +1197,9 @@ const char **TextSplit(const char *text, char delimiter, int *count) // all used memory is static... it has some limitations: // 1. Maximum number of possible split strings is set by MAX_SUBSTRINGS_COUNT // 2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH - + #define MAX_SUBSTRINGS_COUNT 64 - + static const char *result[MAX_SUBSTRINGS_COUNT] = { NULL }; static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); @@ -1208,7 +1208,7 @@ const char **TextSplit(const char *text, char delimiter, int *count) int counter = 1; // Count how many substrings we have on text and point to every one - for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++) + for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++) { buffer[i] = text[i]; if (buffer[i] == '\0') break; @@ -1217,7 +1217,7 @@ const char **TextSplit(const char *text, char delimiter, int *count) buffer[i] = '\0'; // Set an end of string at this point result[counter] = buffer + i + 1; counter++; - + if (counter == MAX_SUBSTRINGS_COUNT) break; } } @@ -1239,11 +1239,11 @@ void TextAppend(char *text, const char *append, int *position) int TextFindIndex(const char *text, const char *find) { int position = -1; - + char *ptr = strstr(text, find); - + if (ptr != NULL) position = ptr - text; - + return position; } @@ -1314,10 +1314,10 @@ int TextToInteger(const char *text) { if ((text[i] > 47) && (text[i] < 58)) result += ((int)text[i] - 48)*units; else { result = -1; break; } - + units *= 10; } - + return result; } diff --git a/src/textures.c b/src/textures.c index 75624fdb..48b89384 100644 --- a/src/textures.c +++ b/src/textures.c @@ -2529,7 +2529,7 @@ void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangl { Rectangle source = { offset.x*texture.width, offset.y*texture.height, tiling.x*texture.width, tiling.y*texture.height }; Vector2 origin = { 0.0f, 0.0f }; - + DrawTexturePro(texture, source, quad, origin, 0.0f, tint); } @@ -3198,7 +3198,7 @@ static int SaveKTX(Image image, const char *fileName) //unsigned char id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }; const char ktxIdentifier[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' }; - + // Get the image header strncpy(ktxHeader.id, ktxIdentifier, 12); // KTX 1.1 signature ktxHeader.endianness = 0; -- cgit v1.2.3 From 374811c440302701496bfb474ce5861c951c5884 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 22 Feb 2019 13:13:11 +0100 Subject: Change ternary operator formatting --- src/core.c | 44 ++++++++++++++++++++++---------------------- src/models.c | 8 ++++---- src/raudio.c | 22 +++++++++++----------- src/rlgl.h | 10 +++++----- src/shapes.c | 2 +- src/text.c | 10 +++++----- src/textures.c | 8 ++++---- 7 files changed, 52 insertions(+), 52 deletions(-) (limited to 'src/models.c') diff --git a/src/core.c b/src/core.c index 9f62b4c8..bff92600 100644 --- a/src/core.c +++ b/src/core.c @@ -1430,11 +1430,11 @@ Vector3 ColorToHSV(Color color) Vector3 hsv = { 0.0f, 0.0f, 0.0f }; float min, max, delta; - min = rgb.x < rgb.y ? rgb.x : rgb.y; - min = min < rgb.z ? min : rgb.z; + min = rgb.x < rgb.y? rgb.x : rgb.y; + min = min < rgb.z? min : rgb.z; - max = rgb.x > rgb.y ? rgb.x : rgb.y; - max = max > rgb.z ? max : rgb.z; + max = rgb.x > rgb.y? rgb.x : rgb.y; + max = max > rgb.z? max : rgb.z; hsv.z = max; // Value delta = max - min; @@ -1485,25 +1485,25 @@ Color ColorFromHSV(Vector3 hsv) // Red channel float k = fmod((5.0f + h/60.0f), 6); float t = 4.0f - k; - k = (t < k) ? t : k; - k = (k < 1) ? k : 1; - k = (k > 0) ? k : 0; + k = (t < k)? t : k; + k = (k < 1)? k : 1; + k = (k > 0)? k : 0; color.r = (v - v*s*k)*255; // Green channel k = fmod((3.0f + h/60.0f), 6); t = 4.0f - k; - k = (t < k) ? t : k; - k = (k < 1) ? k : 1; - k = (k > 0) ? k : 0; + k = (t < k)? t : k; + k = (k < 1)? k : 1; + k = (k > 0)? k : 0; color.g = (v - v*s*k)*255; // Blue channel k = fmod((1.0f + h/60.0f), 6); t = 4.0f - k; - k = (t < k) ? t : k; - k = (k < 1) ? k : 1; - k = (k > 0) ? k : 0; + k = (t < k)? t : k; + k = (k < 1)? k : 1; + k = (k > 0)? k : 0; color.b = (v - v*s*k)*255; return color; @@ -1677,7 +1677,7 @@ const char *GetFileNameWithoutExt(const char *filePath) // NOTE: strrchr() returns a pointer to the last occurrence of character lastDot = strrchr(result, nameDot); - lastSep = (pathSep == 0) ? NULL : strrchr(result, pathSep); + lastSep = (pathSep == 0)? NULL : strrchr(result, pathSep); if (lastDot != NULL) // Check if it has an extension separator... { @@ -3191,7 +3191,7 @@ static void PollInputEvents(void) // Poll Events (registered events) // NOTE: Activity is paused if not enabled (appEnabled) - while ((ident = ALooper_pollAll(appEnabled ? 0 : -1, NULL, &events,(void**)&source)) >= 0) + while ((ident = ALooper_pollAll(appEnabled? 0 : -1, NULL, &events,(void**)&source)) >= 0) { // Process this event if (source != NULL) source->process(androidApp, source); @@ -3771,7 +3771,7 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent } printf("%s, numTouches: %d %s%s%s%s\n", emscripten_event_type_to_string(eventType), event->numTouches, - event->ctrlKey ? " CTRL" : "", event->shiftKey ? " SHIFT" : "", event->altKey ? " ALT" : "", event->metaKey ? " META" : ""); + event->ctrlKey? " CTRL" : "", event->shiftKey? " SHIFT" : "", event->altKey? " ALT" : "", event->metaKey? " META" : ""); for (int i = 0; i < event->numTouches; ++i) { @@ -3825,7 +3825,7 @@ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadE { /* printf("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"\n", - eventType != 0 ? emscripten_event_type_to_string(eventType) : "Gamepad state", + eventType != 0? emscripten_event_type_to_string(eventType) : "Gamepad state", gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping); for(int i = 0; i < gamepadEvent->numAxes; ++i) printf("Axis %d: %g\n", i, gamepadEvent->axis[i]); @@ -4189,11 +4189,11 @@ static void EventThreadSpawn(char *device) { // Looks like a interesting device TraceLog(LOG_INFO, "Opening input device [%s] (%s%s%s%s%s)", device, - worker->isMouse ? "mouse " : "", - worker->isMultitouch ? "multitouch " : "", - worker->isTouch ? "touchscreen " : "", - worker->isGamepad ? "gamepad " : "", - worker->isKeyboard ? "keyboard " : ""); + worker->isMouse? "mouse " : "", + worker->isMultitouch? "multitouch " : "", + worker->isTouch? "touchscreen " : "", + worker->isGamepad? "gamepad " : "", + worker->isKeyboard? "keyboard " : ""); // Create a thread for this device int error = pthread_create(&worker->threadId, NULL, &EventThread, (void *)worker); diff --git a/src/models.c b/src/models.c index 384c8db4..b261f58d 100644 --- a/src/models.c +++ b/src/models.c @@ -2260,7 +2260,7 @@ void MeshTangents(Mesh *mesh) float t2 = uv3.y - uv1.y; float div = s1*t2 - s2*t1; - float r = (div == 0.0f) ? 0.0f : 1.0f/div; + float r = (div == 0.0f)? 0.0f : 1.0f/div; Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r }; Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r }; @@ -2293,7 +2293,7 @@ void MeshTangents(Mesh *mesh) mesh->tangents[i*4 + 0] = tangent.x; mesh->tangents[i*4 + 1] = tangent.y; mesh->tangents[i*4 + 2] = tangent.z; - mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f) ? -1.0f : 1.0f; + mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f)? -1.0f : 1.0f; #endif } @@ -2312,7 +2312,7 @@ void MeshBinormals(Mesh *mesh) Vector3 tangent = { mesh->tangents[i*4 + 0], mesh->tangents[i*4 + 1], mesh->tangents[i*4 + 2] }; float tangentW = mesh->tangents[i*4 + 3]; - // TODO: Register computed binormal in mesh->binormal ? + // TODO: Register computed binormal in mesh->binormal? // Vector3 binormal = Vector3Multiply(Vector3CrossProduct(normal, tangent), tangentW); } } @@ -2639,7 +2639,7 @@ static Material LoadMTL(const char *fileName) } break; case 'e': // Ke float float float Emmisive color (RGB) { - // TODO: Support Ke ? + // TODO: Support Ke? } break; default: break; } diff --git a/src/raudio.c b/src/raudio.c index 4f3e9220..451d3bc3 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -834,7 +834,7 @@ Sound LoadSoundFromWave(Wave wave) // // I have decided on the first option because it offloads work required for the format conversion to the to the loading stage. // The downside to this is that it uses more memory if the original sound is u8 or s16. - mal_format formatIn = ((wave.sampleSize == 8) ? mal_format_u8 : ((wave.sampleSize == 16) ? mal_format_s16 : mal_format_f32)); + mal_format formatIn = ((wave.sampleSize == 8)? mal_format_u8 : ((wave.sampleSize == 16)? mal_format_s16 : mal_format_f32)); mal_uint32 frameCountIn = wave.sampleCount/wave.channels; mal_uint32 frameCount = (mal_uint32)mal_convert_frames(NULL, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, formatIn, wave.channels, wave.sampleRate, frameCountIn); @@ -946,7 +946,7 @@ void ExportWaveAsCode(Wave wave, const char *fileName) // Write byte data as hexadecimal text fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize); - for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0) ? "0x%x,\n" : "0x%x, "), ((unsigned char *)wave.data)[i]); + for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)wave.data)[i]); fprintf(txtFile, "0x%x };\n", ((unsigned char *)wave.data)[dataSize - 1]); fclose(txtFile); @@ -997,8 +997,8 @@ void SetSoundPitch(Sound sound, float pitch) // Convert wave data to desired format void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) { - mal_format formatIn = ((wave->sampleSize == 8) ? mal_format_u8 : ((wave->sampleSize == 16) ? mal_format_s16 : mal_format_f32)); - mal_format formatOut = (( sampleSize == 8) ? mal_format_u8 : (( sampleSize == 16) ? mal_format_s16 : mal_format_f32)); + mal_format formatIn = ((wave->sampleSize == 8)? mal_format_u8 : ((wave->sampleSize == 16)? mal_format_s16 : mal_format_f32)); + mal_format formatOut = (( sampleSize == 8)? mal_format_u8 : (( sampleSize == 16)? mal_format_s16 : mal_format_f32)); mal_uint32 frameCountIn = wave->sampleCount; // Is wave->sampleCount actually the frame count? That terminology needs to change, if so. @@ -1511,7 +1511,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un stream.channels = 1; // Fallback to mono channel } - mal_format formatIn = ((stream.sampleSize == 8) ? mal_format_u8 : ((stream.sampleSize == 16) ? mal_format_s16 : mal_format_f32)); + mal_format formatIn = ((stream.sampleSize == 8)? mal_format_u8 : ((stream.sampleSize == 16)? mal_format_s16 : mal_format_f32)); // The size of a streaming buffer must be at least double the size of a period. unsigned int periodSize = device.bufferSizeInFrames/device.periods; @@ -1528,7 +1528,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un audioBuffer->looping = true; // Always loop for streaming buffers. stream.audioBuffer = audioBuffer; - TraceLog(LOG_INFO, "[AUD ID %i] Audio stream loaded successfully (%i Hz, %i bit, %s)", stream.source, stream.sampleRate, stream.sampleSize, (stream.channels == 1) ? "Mono" : "Stereo"); + TraceLog(LOG_INFO, "[AUD ID %i] Audio stream loaded successfully (%i Hz, %i bit, %s)", stream.source, stream.sampleRate, stream.sampleSize, (stream.channels == 1)? "Mono" : "Stereo"); return stream; } @@ -1566,7 +1566,7 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) else { // Just update whichever sub-buffer is processed. - subBufferToUpdate = (audioBuffer->isSubBufferProcessed[0]) ? 0 : 1; + subBufferToUpdate = (audioBuffer->isSubBufferProcessed[0])? 0 : 1; } mal_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2; @@ -1769,7 +1769,7 @@ static Wave LoadWAV(const char *fileName) // NOTE: subChunkSize comes in bytes, we need to translate it to number of samples wave.sampleCount = (wavData.subChunkSize/(wave.sampleSize/8))/wave.channels; - TraceLog(LOG_INFO, "[%s] WAV file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); + TraceLog(LOG_INFO, "[%s] WAV file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo"); } } } @@ -1890,7 +1890,7 @@ static Wave LoadOGG(const char *fileName) TraceLog(LOG_DEBUG, "[%s] Samples obtained: %i", fileName, numSamplesOgg); - TraceLog(LOG_INFO, "[%s] OGG file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); + TraceLog(LOG_INFO, "[%s] OGG file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo"); stb_vorbis_close(oggFile); } @@ -1917,7 +1917,7 @@ static Wave LoadFLAC(const char *fileName) if (wave.channels > 2) TraceLog(LOG_WARNING, "[%s] FLAC channels number (%i) not supported", fileName, wave.channels); if (wave.data == NULL) TraceLog(LOG_WARNING, "[%s] FLAC data could not be loaded", fileName); - else TraceLog(LOG_INFO, "[%s] FLAC file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); + else TraceLog(LOG_INFO, "[%s] FLAC file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo"); return wave; } @@ -1944,7 +1944,7 @@ static Wave LoadMP3(const char *fileName) if (wave.channels > 2) TraceLog(LOG_WARNING, "[%s] MP3 channels number (%i) not supported", fileName, wave.channels); if (wave.data == NULL) TraceLog(LOG_WARNING, "[%s] MP3 data could not be loaded", fileName); - else TraceLog(LOG_INFO, "[%s] MP3 file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); + else TraceLog(LOG_INFO, "[%s] MP3 file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo"); return wave; } diff --git a/src/rlgl.h b/src/rlgl.h index c9f15385..52165150 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -775,8 +775,8 @@ typedef struct DrawCall { #endif "void main() \n" "{ \n" - " vec2 lensCenter = fragTexCoord.x < 0.5 ? leftLensCenter : rightLensCenter; \n" - " vec2 screenCenter = fragTexCoord.x < 0.5 ? leftScreenCenter : rightScreenCenter; \n" + " vec2 lensCenter = fragTexCoord.x < 0.5? leftLensCenter : rightLensCenter; \n" + " vec2 screenCenter = fragTexCoord.x < 0.5? leftScreenCenter : rightScreenCenter; \n" " vec2 theta = (fragTexCoord - lensCenter)*scaleIn; \n" " float rSq = theta.x*theta.x + theta.y*theta.y; \n" " vec2 theta1 = theta*(hmdWarpParam.x + hmdWarpParam.y*rSq + hmdWarpParam.z*rSq*rSq + hmdWarpParam.w*rSq*rSq*rSq); \n" @@ -1136,7 +1136,7 @@ void rlEnd(void) // TODO: System could be improved (a bit) just storing every draw alignment value // and adding it to vertexOffset on drawing... maybe in a future... int vertexCount = draws[drawsCounter - 1].vertexCount; - int vertexToAlign = (vertexCount >= 4) ? vertexCount%4 : (4 - vertexCount%4); + int vertexToAlign = (vertexCount >= 4)? vertexCount%4 : (4 - vertexCount%4); for (int i = 0; i < vertexToAlign; i++) rlVertex3f(-1, -1, -1); // Make sure vertexCount is the same for vertices, texcoords, colors and normals @@ -1233,7 +1233,7 @@ void rlTexCoord2f(float x, float y) } // Define one vertex (normal) -// NOTE: Normals limited to TRIANGLES only ? +// NOTE: Normals limited to TRIANGLES only? void rlNormal3f(float x, float y, float z) { // TODO: Normals usage... @@ -2206,7 +2206,7 @@ RenderTexture2D rlLoadRenderTexture(int width, int height, int format, int depth target.depth.id = rlLoadTextureDepth(width, height, depthBits, !useDepthTexture); target.depth.width = width; target.depth.height = height; - target.depth.format = 19; //DEPTH_COMPONENT_24BIT ? + target.depth.format = 19; //DEPTH_COMPONENT_24BIT? target.depth.mipmaps = 1; } //----------------------------------------------------------------------------------------------------- diff --git a/src/shapes.c b/src/shapes.c index dbc38082..837e4e9c 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -132,7 +132,7 @@ void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color) rlPushMatrix(); rlTranslatef((float)startPos.x, (float)startPos.y, 0.0f); rlRotatef(RAD2DEG*angle, 0.0f, 0.0f, 1.0f); - rlTranslatef(0, (thick > 1.0f) ? -thick/2.0f : -1.0f, 0.0f); + rlTranslatef(0, (thick > 1.0f)? -thick/2.0f : -1.0f, 0.0f); rlBegin(RL_QUADS); rlColor4ub(color.r, color.g, color.b, color.a); diff --git a/src/text.c b/src/text.c index 56db3f28..39582db2 100644 --- a/src/text.c +++ b/src/text.c @@ -306,7 +306,7 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou Font font = { 0 }; font.baseSize = fontSize; - font.charsCount = (charsCount > 0) ? charsCount : 95; + font.charsCount = (charsCount > 0)? charsCount : 95; font.chars = LoadFontData(fileName, font.baseSize, fontChars, font.charsCount, FONT_DEFAULT); #if defined(SUPPORT_FILEFORMAT_TTF) @@ -483,7 +483,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap); // In case no chars count provided, default to 95 - charsCount = (charsCount > 0) ? charsCount : 95; + charsCount = (charsCount > 0)? charsCount : 95; // Fill fontChars in case not provided externally // NOTE: By default we fill charsCount consecutevely, starting at 32 (Space) @@ -557,7 +557,7 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi Image atlas = { 0 }; // In case no chars count provided we suppose default of 95 - charsCount = (charsCount > 0) ? charsCount : 95; + charsCount = (charsCount > 0)? charsCount : 95; // Calculate image size based on required pixel area // NOTE 1: Image is forced to be squared and POT... very conservative! @@ -856,7 +856,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f if ((textOffsetX + glyphWidth + 1) >= rec.width) { - endLine = (endLine < 1) ? i : endLine; + endLine = (endLine < 1)? i : endLine; if (i == endLine) endLine -= 1; if ((startLine + 1) == endLine) endLine = i - 1; state = !state; @@ -916,7 +916,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f rec.y + textOffsetY + font.chars[index].offsetY*scaleFactor, font.chars[index].rec.width*scaleFactor, font.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, - (!isGlyphSelected) ? tint : selectText); + (!isGlyphSelected)? tint : selectText); } } diff --git a/src/textures.c b/src/textures.c index 5c48ba45..d79cb3cb 100644 --- a/src/textures.c +++ b/src/textures.c @@ -588,7 +588,7 @@ Vector4 *GetImageDataNormalized(Image image) pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31); pixels[i].y = (float)((pixel & 0b0000011111000000) >> 6)*(1.0f/31); pixels[i].z = (float)((pixel & 0b0000000000111110) >> 1)*(1.0f/31); - pixels[i].w = ((pixel & 0b0000000000000001) == 0) ? 0.0f : 1.0f; + pixels[i].w = ((pixel & 0b0000000000000001) == 0)? 0.0f : 1.0f; } break; case UNCOMPRESSED_R5G6B5: @@ -814,7 +814,7 @@ void ExportImageAsCode(Image image, const char *fileName) fprintf(txtFile, "#define %s_FORMAT %i // raylib internal pixel format\n\n", varFileName, image.format); fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize); - for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0) ? "0x%x,\n" : "0x%x, "), ((unsigned char *)image.data)[i]); + for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)image.data)[i]); fprintf(txtFile, "0x%x };\n", ((unsigned char *)image.data)[dataSize - 1]); fclose(txtFile); @@ -984,7 +984,7 @@ void ImageFormat(Image *image, int newFormat) r = (unsigned char)(round(pixels[i].x*31.0f)); g = (unsigned char)(round(pixels[i].y*31.0f)); b = (unsigned char)(round(pixels[i].z*31.0f)); - a = (pixels[i].w > ((float)ALPHA_THRESHOLD/255.0f)) ? 1 : 0; + a = (pixels[i].w > ((float)ALPHA_THRESHOLD/255.0f))? 1 : 0; ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a; } @@ -2231,7 +2231,7 @@ Image GenImageGradientH(int width, int height, Color left, Color right) Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer) { Color *pixels = (Color *)malloc(width*height*sizeof(Color)); - float radius = (width < height) ? (float)width/2.0f : (float)height/2.0f; + float radius = (width < height)? (float)width/2.0f : (float)height/2.0f; float centerX = (float)width/2.0f; float centerY = (float)height/2.0f; -- cgit v1.2.3 From 9f54a69cec1e6d2927e1998e75e316ce133e4669 Mon Sep 17 00:00:00 2001 From: Rafael Sachetto Date: Fri, 8 Mar 2019 15:06:17 -0300 Subject: Adding DrawCubeWiresV for convenience --- src/models.c | 6 ++++++ src/raylib.h | 1 + 2 files changed, 7 insertions(+) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index b261f58d..a5dbf5e7 100644 --- a/src/models.c +++ b/src/models.c @@ -285,6 +285,12 @@ void DrawCubeWires(Vector3 position, float width, float height, float length, Co rlPopMatrix(); } +// Draw cube wires (vector version) +void DrawCubeWiresV(Vector3 position, Vector3 size, Color color) +{ + DrawCubeWires(position, size.x, size.y, size.z, color); +} + // Draw cube // NOTE: Cube position is the center position void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float length, Color color) diff --git a/src/raylib.h b/src/raylib.h index cc461204..ccdb4aab 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1207,6 +1207,7 @@ RLAPI void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, floa RLAPI void DrawCube(Vector3 position, float width, float height, float length, Color color); // Draw cube RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version) RLAPI void DrawCubeWires(Vector3 position, float width, float height, float length, Color color); // Draw cube wires +RLAPI void DrawCubeWiresV(Vector3 position, Vector3 size, Color color); // Draw cube wires (Vector version) RLAPI void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float length, Color color); // Draw cube textured RLAPI void DrawSphere(Vector3 centerPos, float radius, Color color); // Draw sphere RLAPI void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere with extended parameters -- cgit v1.2.3 From a643dc4ca016ce5791608852ab1357f2d94ebe9b Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 29 Mar 2019 16:48:23 +0100 Subject: WARNING: Redesigned model struct for multi-meshes This is quite a big change, Model struct has been redesigned to support multiple meshes and multiple materials, most 3d fileformats contain multiple meshes and reference multiple materials. Consequently, multiple functions have been reviewed. LoadOBJ(), LoadIQM(), LoadGLFT() now return a Model. Current LoadOBJ() is not valid anymore, actually, tinyobj_loader_c library is considered for replacement. --- src/external/tinyobj_loader_c.h | 1583 +++++++++++++++++++++++++++++++++++++++ src/models.c | 155 ++-- src/raylib.h | 21 +- 3 files changed, 1685 insertions(+), 74 deletions(-) create mode 100644 src/external/tinyobj_loader_c.h (limited to 'src/models.c') diff --git a/src/external/tinyobj_loader_c.h b/src/external/tinyobj_loader_c.h new file mode 100644 index 00000000..e9d015ff --- /dev/null +++ b/src/external/tinyobj_loader_c.h @@ -0,0 +1,1583 @@ +/* + The MIT License (MIT) + + Copyright (c) 2016 - 2019 Syoyo Fujita and many contributors. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ +#ifndef TINOBJ_LOADER_C_H_ +#define TINOBJ_LOADER_C_H_ + +/* @todo { Remove stddef dependency. size_t? } */ +#include + +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; + +typedef struct { + char *name; /* group name or object name. */ + unsigned int face_offset; + unsigned int length; +} tinyobj_shape_t; + +typedef struct { int v_idx, vt_idx, vn_idx; } tinyobj_vertex_index_t; + +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; + + +#define TINYOBJ_FLAG_TRIANGULATE (1 << 0) + +#define TINYOBJ_INVALID_INDEX (0x80000000) + +#define TINYOBJ_SUCCESS (0) +#define TINYOBJ_ERROR_EMPTY (-1) +#define TINYOBJ_ERROR_INVALID_PARAMETER (-2) +#define TINYOBJ_ERROR_FILE_OPERATION (-3) + +/* Parse wavefront .obj(.obj string data is expanded to linear char array `buf') + * flags are combination of TINYOBJ_FLAG_*** + * Returns TINYOBJ_SUCCESS if things goes well. + * Returns TINYOBJ_ERR_*** when there is an error. + */ +extern int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, + size_t *num_shapes, tinyobj_material_t **materials, + size_t *num_materials, const char *buf, size_t len, + unsigned int flags); +extern int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out, + size_t *num_materials_out, + const char *filename); + +extern void tinyobj_attrib_init(tinyobj_attrib_t *attrib); +extern void tinyobj_attrib_free(tinyobj_attrib_t *attrib); +extern void tinyobj_shapes_free(tinyobj_shape_t *shapes, size_t num_shapes); +extern void tinyobj_materials_free(tinyobj_material_t *materials, + size_t num_materials); + +#ifdef TINYOBJ_LOADER_C_IMPLEMENTATION +#include +#include +#include +#include + +#if defined(TINYOBJ_MALLOC) && defined(TINYOBJ_REALLOC) && defined(TINYOBJ_CALLOC) && defined(TINYOBJ_FREE) +/* ok */ +#elif !defined(TINYOBJ_MALLOC) && !defined(TINYOBJ_REALLOC) && !defined(TINYOBJ_CALLOC) && !defined(TINYOBJ_FREE) +/* ok */ +#else +#error "Must define all or none of TINYOBJ_MALLOC, TINYOBJ_REALLOC, TINYOBJ_CALLOC and TINYOBJ_FREE." +#endif + +#ifndef TINYOBJ_MALLOC +#include +#define TINYOBJ_MALLOC malloc +#define TINYOBJ_REALLOC realloc +#define TINYOBJ_CALLOC calloc +#define TINYOBJ_FREE free +#endif + +#define TINYOBJ_MAX_FACES_PER_F_LINE (16) + +#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) +#define IS_DIGIT(x) ((unsigned int)((x) - '0') < (unsigned int)(10)) +#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0')) + +static void skip_space(const char **token) { + while ((*token)[0] == ' ' || (*token)[0] == '\t') { + (*token)++; + } +} + +static void skip_space_and_cr(const char **token) { + while ((*token)[0] == ' ' || (*token)[0] == '\t' || (*token)[0] == '\r') { + (*token)++; + } +} + +static int until_space(const char *token) { + const char *p = token; + while (p[0] != '\0' && p[0] != ' ' && p[0] != '\t' && p[0] != '\r') { + p++; + } + + return (int)(p - token); +} + +static size_t length_until_newline(const char *token, size_t n) { + size_t len = 0; + + /* Assume token[n-1] = '\0' */ + for (len = 0; len < n - 1; len++) { + if (token[len] == '\n') { + break; + } + if ((token[len] == '\r') && ((len < (n - 2)) && (token[len + 1] != '\n'))) { + break; + } + } + + return len; +} + +static size_t length_until_line_feed(const char *token, size_t n) { + size_t len = 0; + + /* Assume token[n-1] = '\0' */ + for (len = 0; len < n; len++) { + if ((token[len] == '\n') || (token[len] == '\r')) { + break; + } + } + + return len; +} + +/* http://stackoverflow.com/questions/5710091/how-does-atoi-function-in-c-work +*/ +static int my_atoi(const char *c) { + int value = 0; + int sign = 1; + if (*c == '+' || *c == '-') { + if (*c == '-') sign = -1; + c++; + } + while (((*c) >= '0') && ((*c) <= '9')) { /* isdigit(*c) */ + value *= 10; + value += (int)(*c - '0'); + c++; + } + return value * sign; +} + +/* Make index zero-base, and also support relative index. */ +static int fixIndex(int idx, size_t n) { + if (idx > 0) return idx - 1; + if (idx == 0) return 0; + return (int)n + idx; /* negative value = relative */ +} + +/* Parse raw triples: i, i/j/k, i//k, i/j */ +static tinyobj_vertex_index_t parseRawTriple(const char **token) { + tinyobj_vertex_index_t vi; + /* 0x80000000 = -2147483648 = invalid */ + vi.v_idx = (int)(0x80000000); + vi.vn_idx = (int)(0x80000000); + vi.vt_idx = (int)(0x80000000); + + vi.v_idx = my_atoi((*token)); + while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && + (*token)[0] != '\t' && (*token)[0] != '\r') { + (*token)++; + } + if ((*token)[0] != '/') { + return vi; + } + (*token)++; + + /* i//k */ + if ((*token)[0] == '/') { + (*token)++; + vi.vn_idx = my_atoi((*token)); + while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && + (*token)[0] != '\t' && (*token)[0] != '\r') { + (*token)++; + } + return vi; + } + + /* i/j/k or i/j */ + vi.vt_idx = my_atoi((*token)); + while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && + (*token)[0] != '\t' && (*token)[0] != '\r') { + (*token)++; + } + if ((*token)[0] != '/') { + return vi; + } + + /* i/j/k */ + (*token)++; /* skip '/' */ + vi.vn_idx = my_atoi((*token)); + while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && + (*token)[0] != '\t' && (*token)[0] != '\r') { + (*token)++; + } + return vi; +} + +static int parseInt(const char **token) { + int i = 0; + skip_space(token); + i = my_atoi((*token)); + (*token) += until_space((*token)); + return i; +} + +/* + * Tries to parse a floating point number located at s. + * + * s_end should be a location in the string where reading should absolutely + * stop. For example at the end of the string, to prevent buffer overflows. + * + * Parses the following EBNF grammar: + * sign = "+" | "-" ; + * END = ? anything not in digit ? + * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; + * integer = [sign] , digit , {digit} ; + * decimal = integer , ["." , integer] ; + * float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ; + * + * Valid strings are for example: + * -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2 + * + * If the parsing is a success, result is set to the parsed value and true + * is returned. + * + * The function is greedy and will parse until any of the following happens: + * - a non-conforming character is encountered. + * - s_end is reached. + * + * The following situations triggers a failure: + * - s >= s_end. + * - parse failure. + */ +static int tryParseDouble(const char *s, const char *s_end, double *result) { + double mantissa = 0.0; + /* This exponent is base 2 rather than 10. + * However the exponent we parse is supposed to be one of ten, + * thus we must take care to convert the exponent/and or the + * mantissa to a * 2^E, where a is the mantissa and E is the + * exponent. + * To get the final double we will use ldexp, it requires the + * exponent to be in base 2. + */ + int exponent = 0; + + /* NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED + * TO JUMP OVER DEFINITIONS. + */ + char sign = '+'; + char exp_sign = '+'; + char const *curr = s; + + /* How many characters were read in a loop. */ + int read = 0; + /* Tells whether a loop terminated due to reaching s_end. */ + int end_not_reached = 0; + + /* + BEGIN PARSING. + */ + + if (s >= s_end) { + return 0; /* fail */ + } + + /* Find out what sign we've got. */ + if (*curr == '+' || *curr == '-') { + sign = *curr; + curr++; + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else { + goto fail; + } + + /* Read the integer part. */ + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + mantissa *= 10; + mantissa += (int)(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + + /* We must make sure we actually got something. */ + if (read == 0) goto fail; + /* We allow numbers of form "#", "###" etc. */ + if (!end_not_reached) goto assemble; + + /* Read the decimal part. */ + if (*curr == '.') { + curr++; + read = 1; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + /* pow(10.0, -read) */ + double frac_value = 1.0; + int f; + for (f = 0; f < read; f++) { + frac_value *= 0.1; + } + mantissa += (int)(*curr - 0x30) * frac_value; + read++; + curr++; + end_not_reached = (curr != s_end); + } + } else if (*curr == 'e' || *curr == 'E') { + } else { + goto assemble; + } + + if (!end_not_reached) goto assemble; + + /* Read the exponent part. */ + if (*curr == 'e' || *curr == 'E') { + curr++; + /* Figure out if a sign is present and if it is. */ + end_not_reached = (curr != s_end); + if (end_not_reached && (*curr == '+' || *curr == '-')) { + exp_sign = *curr; + curr++; + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else { + /* Empty E is not allowed. */ + goto fail; + } + + read = 0; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + exponent *= 10; + exponent += (int)(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + if (read == 0) goto fail; + } + +assemble : + + { + double a = 1.0; /* = pow(5.0, exponent); */ + double b = 1.0; /* = 2.0^exponent */ + int i; + for (i = 0; i < exponent; i++) { + a = a * 5.0; + } + + for (i = 0; i < exponent; i++) { + b = b * 2.0; + } + + if (exp_sign == '-') { + a = 1.0 / a; + b = 1.0 / b; + } + + *result = + /* (sign == '+' ? 1 : -1) * ldexp(mantissa * pow(5.0, exponent), + exponent); */ + (sign == '+' ? 1 : -1) * (mantissa * a * b); + } + + return 1; +fail: + return 0; +} + +static float parseFloat(const char **token) { + const char *end; + double val = 0.0; + float f = 0.0f; + skip_space(token); + end = (*token) + until_space((*token)); + val = 0.0; + tryParseDouble((*token), end, &val); + f = (float)(val); + (*token) = end; + return f; +} + +static void parseFloat2(float *x, float *y, const char **token) { + (*x) = parseFloat(token); + (*y) = parseFloat(token); +} + +static void parseFloat3(float *x, float *y, float *z, const char **token) { + (*x) = parseFloat(token); + (*y) = parseFloat(token); + (*z) = parseFloat(token); +} + +static char *my_strdup(const char *s, size_t max_length) { + char *d; + size_t len; + + if (s == NULL) return NULL; + + /* Do not consider CRLF line ending(#19) */ + len = length_until_line_feed(s, max_length); + /* len = strlen(s); */ + + /* trim line ending and append '\0' */ + d = (char *)TINYOBJ_MALLOC(len + 1); /* + '\0' */ + memcpy(d, s, (size_t)(len)); + d[len] = '\0'; + + return d; +} + +static char *my_strndup(const char *s, size_t len) { + char *d; + size_t slen; + + if (s == NULL) return NULL; + if (len == 0) return NULL; + + d = (char *)TINYOBJ_MALLOC(len + 1); /* + '\0' */ + slen = strlen(s); + if (slen < len) { + memcpy(d, s, slen); + d[slen] = '\0'; + } else { + memcpy(d, s, len); + d[len] = '\0'; + } + + return d; +} + +char *dynamic_fgets(char **buf, size_t *size, FILE *file) { + char *offset; + char *ret; + size_t old_size; + + if (!(ret = fgets(*buf, (int)*size, file))) { + return ret; + } + + if (NULL != strchr(*buf, '\n')) { + return ret; + } + + do { + old_size = *size; + *size *= 2; + *buf = (char*)TINYOBJ_REALLOC(*buf, *size); + offset = &((*buf)[old_size - 1]); + + ret = fgets(offset, (int)(old_size + 1), file); + } while(ret && (NULL == strchr(*buf, '\n'))); + + return ret; +} + +static void initMaterial(tinyobj_material_t *material) { + int i; + material->name = NULL; + material->ambient_texname = NULL; + material->diffuse_texname = NULL; + material->specular_texname = NULL; + material->specular_highlight_texname = NULL; + material->bump_texname = NULL; + material->displacement_texname = NULL; + material->alpha_texname = NULL; + for (i = 0; i < 3; i++) { + material->ambient[i] = 0.f; + material->diffuse[i] = 0.f; + material->specular[i] = 0.f; + material->transmittance[i] = 0.f; + material->emission[i] = 0.f; + } + material->illum = 0; + material->dissolve = 1.f; + material->shininess = 1.f; + material->ior = 1.f; +} + +/* Implementation of string to int hashtable */ + +#define HASH_TABLE_ERROR 1 +#define HASH_TABLE_SUCCESS 0 + +#define HASH_TABLE_DEFAULT_SIZE 10 + +typedef struct hash_table_entry_t +{ + unsigned long hash; + int filled; + int pad0; + long value; + + struct hash_table_entry_t* next; +} hash_table_entry_t; + +typedef struct +{ + unsigned long* hashes; + hash_table_entry_t* entries; + size_t capacity; + size_t n; +} hash_table_t; + +static unsigned long hash_djb2(const unsigned char* str) +{ + unsigned long hash = 5381; + int c; + + while ((c = *str++)) { + hash = ((hash << 5) + hash) + (unsigned long)(c); + } + + return hash; +} + +static void create_hash_table(size_t start_capacity, hash_table_t* hash_table) +{ + if (start_capacity < 1) + start_capacity = HASH_TABLE_DEFAULT_SIZE; + hash_table->hashes = (unsigned long*) TINYOBJ_MALLOC(start_capacity * sizeof(unsigned long)); + hash_table->entries = (hash_table_entry_t*) TINYOBJ_CALLOC(start_capacity, sizeof(hash_table_entry_t)); + hash_table->capacity = start_capacity; + hash_table->n = 0; +} + +static void destroy_hash_table(hash_table_t* hash_table) +{ + TINYOBJ_FREE(hash_table->entries); + TINYOBJ_FREE(hash_table->hashes); +} + +/* Insert with quadratic probing */ +static int hash_table_insert_value(unsigned long hash, long value, hash_table_t* hash_table) +{ + /* Insert value */ + size_t start_index = hash % hash_table->capacity; + size_t index = start_index; + hash_table_entry_t* start_entry = hash_table->entries + start_index; + size_t i; + hash_table_entry_t* entry; + + for (i = 1; hash_table->entries[index].filled; i++) + { + if (i >= hash_table->capacity) + return HASH_TABLE_ERROR; + index = (start_index + (i * i)) % hash_table->capacity; + } + + entry = hash_table->entries + index; + entry->hash = hash; + entry->filled = 1; + entry->value = value; + + if (index != start_index) { + /* This is a new entry, but not the start entry, hence we need to add a next pointer to our entry */ + entry->next = start_entry->next; + start_entry->next = entry; + } + + return HASH_TABLE_SUCCESS; +} + +static int hash_table_insert(unsigned long hash, long value, hash_table_t* hash_table) +{ + int ret = hash_table_insert_value(hash, value, hash_table); + if (ret == HASH_TABLE_SUCCESS) + { + hash_table->hashes[hash_table->n] = hash; + hash_table->n++; + } + return ret; +} + +static hash_table_entry_t* hash_table_find(unsigned long hash, hash_table_t* hash_table) +{ + hash_table_entry_t* entry = hash_table->entries + (hash % hash_table->capacity); + while (entry) + { + if (entry->hash == hash && entry->filled) + { + return entry; + } + entry = entry->next; + } + return NULL; +} + +static void hash_table_maybe_grow(size_t new_n, hash_table_t* hash_table) +{ + size_t new_capacity; + hash_table_t new_hash_table; + size_t i; + + if (new_n <= hash_table->capacity) { + return; + } + new_capacity = 2 * ((2 * hash_table->capacity) > new_n ? hash_table->capacity : new_n); + /* Create a new hash table. We're not calling create_hash_table because we want to realloc the hash array */ + new_hash_table.hashes = hash_table->hashes = (unsigned long*) TINYOBJ_REALLOC((void*) hash_table->hashes, sizeof(unsigned long) * new_capacity); + new_hash_table.entries = (hash_table_entry_t*) TINYOBJ_CALLOC(new_capacity, sizeof(hash_table_entry_t)); + new_hash_table.capacity = new_capacity; + new_hash_table.n = hash_table->n; + + /* Rehash */ + for (i = 0; i < hash_table->capacity; i++) + { + hash_table_entry_t* entry = hash_table_find(hash_table->hashes[i], hash_table); + hash_table_insert_value(hash_table->hashes[i], entry->value, &new_hash_table); + } + + TINYOBJ_FREE(hash_table->entries); + (*hash_table) = new_hash_table; +} + +static int hash_table_exists(const char* name, hash_table_t* hash_table) +{ + return hash_table_find(hash_djb2((const unsigned char*)name), hash_table) != NULL; +} + +static void hash_table_set(const char* name, size_t val, hash_table_t* hash_table) +{ + /* Hash name */ + unsigned long hash = hash_djb2((const unsigned char *)name); + + hash_table_entry_t* entry = hash_table_find(hash, hash_table); + if (entry) + { + entry->value = (long)val; + return; + } + + /* Expand if necessary + * Grow until the element has been added + */ + do + { + hash_table_maybe_grow(hash_table->n + 1, hash_table); + } + while (hash_table_insert(hash, (long)val, hash_table) != HASH_TABLE_SUCCESS); +} + +static long hash_table_get(const char* name, hash_table_t* hash_table) +{ + hash_table_entry_t* ret = hash_table_find(hash_djb2((const unsigned char*)(name)), hash_table); + return ret->value; +} + +static tinyobj_material_t *tinyobj_material_add(tinyobj_material_t *prev, + size_t num_materials, + tinyobj_material_t *new_mat) { + tinyobj_material_t *dst; + dst = (tinyobj_material_t *)TINYOBJ_REALLOC( + prev, sizeof(tinyobj_material_t) * (num_materials + 1)); + + dst[num_materials] = (*new_mat); /* Just copy pointer for char* members */ + return dst; +} + +static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out, + size_t *num_materials_out, + const char *filename, + hash_table_t* material_table) { + tinyobj_material_t material; + size_t buffer_size = 128; + char *linebuf; + FILE *fp; + size_t num_materials = 0; + tinyobj_material_t *materials = NULL; + int has_previous_material = 0; + const char *line_end = NULL; + + if (materials_out == NULL) { + return TINYOBJ_ERROR_INVALID_PARAMETER; + } + + if (num_materials_out == NULL) { + return TINYOBJ_ERROR_INVALID_PARAMETER; + } + + (*materials_out) = NULL; + (*num_materials_out) = 0; + + fp = fopen(filename, "r"); + if (!fp) { + fprintf(stderr, "TINYOBJ: Error reading file '%s': %s (%d)\n", filename, strerror(errno), errno); + return TINYOBJ_ERROR_FILE_OPERATION; + } + + /* Create a default material */ + initMaterial(&material); + + linebuf = (char*)TINYOBJ_MALLOC(buffer_size); + while (NULL != dynamic_fgets(&linebuf, &buffer_size, fp)) { + const char *token = linebuf; + + line_end = token + strlen(token); + + /* Skip leading space. */ + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; /* empty line */ + + if (token[0] == '#') continue; /* comment line */ + + /* new mtl */ + if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) { + char namebuf[4096]; + + /* flush previous material. */ + if (has_previous_material) { + materials = tinyobj_material_add(materials, num_materials, &material); + num_materials++; + } else { + has_previous_material = 1; + } + + /* initial temporary material */ + initMaterial(&material); + + /* set new mtl name */ + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + material.name = my_strdup(namebuf, (size_t) (line_end - token)); + + /* Add material to material table */ + if (material_table) + hash_table_set(material.name, num_materials, material_table); + + continue; + } + + /* ambient */ + if (token[0] == 'K' && token[1] == 'a' && IS_SPACE((token[2]))) { + float r, g, b; + token += 2; + parseFloat3(&r, &g, &b, &token); + material.ambient[0] = r; + material.ambient[1] = g; + material.ambient[2] = b; + continue; + } + + /* diffuse */ + if (token[0] == 'K' && token[1] == 'd' && IS_SPACE((token[2]))) { + float r, g, b; + token += 2; + parseFloat3(&r, &g, &b, &token); + material.diffuse[0] = r; + material.diffuse[1] = g; + material.diffuse[2] = b; + continue; + } + + /* specular */ + if (token[0] == 'K' && token[1] == 's' && IS_SPACE((token[2]))) { + float r, g, b; + token += 2; + parseFloat3(&r, &g, &b, &token); + material.specular[0] = r; + material.specular[1] = g; + material.specular[2] = b; + continue; + } + + /* transmittance */ + if (token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) { + float r, g, b; + token += 2; + parseFloat3(&r, &g, &b, &token); + material.transmittance[0] = r; + material.transmittance[1] = g; + material.transmittance[2] = b; + continue; + } + + /* ior(index of refraction) */ + if (token[0] == 'N' && token[1] == 'i' && IS_SPACE((token[2]))) { + token += 2; + material.ior = parseFloat(&token); + continue; + } + + /* emission */ + if (token[0] == 'K' && token[1] == 'e' && IS_SPACE(token[2])) { + float r, g, b; + token += 2; + parseFloat3(&r, &g, &b, &token); + material.emission[0] = r; + material.emission[1] = g; + material.emission[2] = b; + continue; + } + + /* shininess */ + if (token[0] == 'N' && token[1] == 's' && IS_SPACE(token[2])) { + token += 2; + material.shininess = parseFloat(&token); + continue; + } + + /* illum model */ + if (0 == strncmp(token, "illum", 5) && IS_SPACE(token[5])) { + token += 6; + material.illum = parseInt(&token); + continue; + } + + /* dissolve */ + if ((token[0] == 'd' && IS_SPACE(token[1]))) { + token += 1; + material.dissolve = parseFloat(&token); + continue; + } + if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) { + token += 2; + /* Invert value of Tr(assume Tr is in range [0, 1]) */ + material.dissolve = 1.0f - parseFloat(&token); + continue; + } + + /* ambient texture */ + if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) { + token += 7; + material.ambient_texname = my_strdup(token, (size_t) (line_end - token)); + continue; + } + + /* diffuse texture */ + if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) { + token += 7; + material.diffuse_texname = my_strdup(token, (size_t) (line_end - token)); + continue; + } + + /* specular texture */ + if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) { + token += 7; + material.specular_texname = my_strdup(token, (size_t) (line_end - token)); + continue; + } + + /* specular highlight texture */ + if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) { + token += 7; + material.specular_highlight_texname = my_strdup(token, (size_t) (line_end - token)); + continue; + } + + /* bump texture */ + if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) { + token += 9; + material.bump_texname = my_strdup(token, (size_t) (line_end - token)); + continue; + } + + /* alpha texture */ + if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) { + token += 6; + material.alpha_texname = my_strdup(token, (size_t) (line_end - token)); + continue; + } + + /* bump texture */ + if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) { + token += 5; + material.bump_texname = my_strdup(token, (size_t) (line_end - token)); + continue; + } + + /* displacement texture */ + if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) { + token += 5; + material.displacement_texname = my_strdup(token, (size_t) (line_end - token)); + continue; + } + + /* @todo { unknown parameter } */ + } + + if (material.name) { + /* Flush last material element */ + materials = tinyobj_material_add(materials, num_materials, &material); + num_materials++; + } + + (*num_materials_out) = num_materials; + (*materials_out) = materials; + + if (linebuf) { + TINYOBJ_FREE(linebuf); + } + + return TINYOBJ_SUCCESS; +} + +int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out, + size_t *num_materials_out, + const char *filename) { + return tinyobj_parse_and_index_mtl_file(materials_out, num_materials_out, filename, NULL); +} + + +typedef enum { + COMMAND_EMPTY, + COMMAND_V, + COMMAND_VN, + COMMAND_VT, + COMMAND_F, + COMMAND_G, + COMMAND_O, + COMMAND_USEMTL, + COMMAND_MTLLIB + +} CommandType; + +typedef struct { + float vx, vy, vz; + float nx, ny, nz; + float tx, ty; + + /* @todo { Use dynamic array } */ + tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE]; + size_t num_f; + + int f_num_verts[TINYOBJ_MAX_FACES_PER_F_LINE]; + size_t num_f_num_verts; + + const char *group_name; + unsigned int group_name_len; + int pad0; + + const char *object_name; + unsigned int object_name_len; + int pad1; + + const char *material_name; + unsigned int material_name_len; + int pad2; + + const char *mtllib_name; + unsigned int mtllib_name_len; + + CommandType type; +} Command; + +static int parseLine(Command *command, const char *p, size_t p_len, + int triangulate) { + char linebuf[4096]; + const char *token; + assert(p_len < 4095); + + memcpy(linebuf, p, p_len); + linebuf[p_len] = '\0'; + + token = linebuf; + + command->type = COMMAND_EMPTY; + + /* Skip leading space. */ + skip_space(&token); + + assert(token); + if (token[0] == '\0') { /* empty line */ + return 0; + } + + if (token[0] == '#') { /* comment line */ + return 0; + } + + /* vertex */ + if (token[0] == 'v' && IS_SPACE((token[1]))) { + float x, y, z; + token += 2; + parseFloat3(&x, &y, &z, &token); + command->vx = x; + command->vy = y; + command->vz = z; + command->type = COMMAND_V; + return 1; + } + + /* normal */ + if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { + float x, y, z; + token += 3; + parseFloat3(&x, &y, &z, &token); + command->nx = x; + command->ny = y; + command->nz = z; + command->type = COMMAND_VN; + return 1; + } + + /* texcoord */ + if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { + float x, y; + token += 3; + parseFloat2(&x, &y, &token); + command->tx = x; + command->ty = y; + command->type = COMMAND_VT; + return 1; + } + + /* face */ + if (token[0] == 'f' && IS_SPACE((token[1]))) { + size_t num_f = 0; + + tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE]; + token += 2; + skip_space(&token); + + while (!IS_NEW_LINE(token[0])) { + tinyobj_vertex_index_t vi = parseRawTriple(&token); + skip_space_and_cr(&token); + + f[num_f] = vi; + num_f++; + } + + command->type = COMMAND_F; + + if (triangulate) { + size_t k; + size_t n = 0; + + tinyobj_vertex_index_t i0 = f[0]; + tinyobj_vertex_index_t i1; + tinyobj_vertex_index_t i2 = f[1]; + + assert(3 * num_f < TINYOBJ_MAX_FACES_PER_F_LINE); + + for (k = 2; k < num_f; k++) { + i1 = i2; + i2 = f[k]; + command->f[3 * n + 0] = i0; + command->f[3 * n + 1] = i1; + command->f[3 * n + 2] = i2; + + command->f_num_verts[n] = 3; + n++; + } + command->num_f = 3 * n; + command->num_f_num_verts = n; + + } else { + size_t k = 0; + assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE); + for (k = 0; k < num_f; k++) { + command->f[k] = f[k]; + } + + command->num_f = num_f; + command->f_num_verts[0] = (int)num_f; + command->num_f_num_verts = 1; + } + + return 1; + } + + /* use mtl */ + if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { + token += 7; + + skip_space(&token); + command->material_name = p + (token - linebuf); + command->material_name_len = (unsigned int)length_until_newline( + token, (p_len - (size_t)(token - linebuf)) + 1); + command->type = COMMAND_USEMTL; + + return 1; + } + + /* load mtl */ + if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + /* By specification, `mtllib` should be appear only once in .obj */ + token += 7; + + skip_space(&token); + command->mtllib_name = p + (token - linebuf); + command->mtllib_name_len = (unsigned int)length_until_newline( + token, p_len - (size_t)(token - linebuf)) + + 1; + command->type = COMMAND_MTLLIB; + + return 1; + } + + /* group name */ + if (token[0] == 'g' && IS_SPACE((token[1]))) { + /* @todo { multiple group name. } */ + token += 2; + + command->group_name = p + (token - linebuf); + command->group_name_len = (unsigned int)length_until_newline( + token, p_len - (size_t)(token - linebuf)) + + 1; + command->type = COMMAND_G; + + return 1; + } + + /* object name */ + if (token[0] == 'o' && IS_SPACE((token[1]))) { + /* @todo { multiple object name? } */ + token += 2; + + command->object_name = p + (token - linebuf); + command->object_name_len = (unsigned int)length_until_newline( + token, p_len - (size_t)(token - linebuf)) + + 1; + command->type = COMMAND_O; + + return 1; + } + + return 0; +} + +typedef struct { + size_t pos; + size_t len; +} LineInfo; + +static int is_line_ending(const char *p, size_t i, size_t end_i) { + if (p[i] == '\0') return 1; + if (p[i] == '\n') return 1; /* this includes \r\n */ + if (p[i] == '\r') { + if (((i + 1) < end_i) && (p[i + 1] != '\n')) { /* detect only \r case */ + return 1; + } + } + return 0; +} + +int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, + size_t *num_shapes, tinyobj_material_t **materials_out, + size_t *num_materials_out, const char *buf, size_t len, + unsigned int flags) { + LineInfo *line_infos = NULL; + Command *commands = NULL; + size_t num_lines = 0; + + size_t num_v = 0; + size_t num_vn = 0; + size_t num_vt = 0; + size_t num_f = 0; + size_t num_faces = 0; + + int mtllib_line_index = -1; + + tinyobj_material_t *materials = NULL; + size_t num_materials = 0; + + hash_table_t material_table; + + if (len < 1) return TINYOBJ_ERROR_INVALID_PARAMETER; + if (attrib == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + if (shapes == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + if (num_shapes == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + if (buf == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + if (materials_out == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + if (num_materials_out == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + + tinyobj_attrib_init(attrib); + /* 1. Find '\n' and create line data. */ + { + size_t i; + size_t end_idx = len; + size_t prev_pos = 0; + size_t line_no = 0; + size_t last_line_ending = 0; + + /* Count # of lines. */ + for (i = 0; i < end_idx; i++) { + if (is_line_ending(buf, i, end_idx)) { + num_lines++; + last_line_ending = i; + } + } + /* The last char from the input may not be a line + * ending character so add an extra line if there + * are more characters after the last line ending + * that was found. */ + if (end_idx - last_line_ending > 0) { + num_lines++; + } + + if (num_lines == 0) return TINYOBJ_ERROR_EMPTY; + + line_infos = (LineInfo *)TINYOBJ_MALLOC(sizeof(LineInfo) * num_lines); + + /* Fill line infos. */ + for (i = 0; i < end_idx; i++) { + if (is_line_ending(buf, i, end_idx)) { + line_infos[line_no].pos = prev_pos; + line_infos[line_no].len = i - prev_pos; + prev_pos = i + 1; + line_no++; + } + } + if (end_idx - last_line_ending > 0) { + line_infos[line_no].pos = prev_pos; + line_infos[line_no].len = end_idx - 1 - last_line_ending; + } + } + + commands = (Command *)TINYOBJ_MALLOC(sizeof(Command) * num_lines); + + create_hash_table(HASH_TABLE_DEFAULT_SIZE, &material_table); + + /* 2. parse each line */ + { + size_t i = 0; + for (i = 0; i < num_lines; i++) { + int ret = parseLine(&commands[i], &buf[line_infos[i].pos], + line_infos[i].len, flags & TINYOBJ_FLAG_TRIANGULATE); + if (ret) { + if (commands[i].type == COMMAND_V) { + num_v++; + } else if (commands[i].type == COMMAND_VN) { + num_vn++; + } else if (commands[i].type == COMMAND_VT) { + num_vt++; + } else if (commands[i].type == COMMAND_F) { + num_f += commands[i].num_f; + num_faces += commands[i].num_f_num_verts; + } + + if (commands[i].type == COMMAND_MTLLIB) { + mtllib_line_index = (int)i; + } + } + } + } + + /* line_infos are not used anymore. Release memory. */ + if (line_infos) { + TINYOBJ_FREE(line_infos); + } + + /* Load material(if exits) */ + if (mtllib_line_index >= 0 && commands[mtllib_line_index].mtllib_name && + commands[mtllib_line_index].mtllib_name_len > 0) { + char *filename = my_strndup(commands[mtllib_line_index].mtllib_name, + commands[mtllib_line_index].mtllib_name_len); + + int ret = tinyobj_parse_and_index_mtl_file(&materials, &num_materials, filename, &material_table); + + if (ret != TINYOBJ_SUCCESS) { + /* warning. */ + fprintf(stderr, "TINYOBJ: Failed to parse material file '%s': %d\n", filename, ret); + } + + TINYOBJ_FREE(filename); + + } + + /* Construct attributes */ + + { + size_t v_count = 0; + size_t n_count = 0; + size_t t_count = 0; + size_t f_count = 0; + size_t face_count = 0; + int material_id = -1; /* -1 = default unknown material. */ + size_t i = 0; + + attrib->vertices = (float *)TINYOBJ_MALLOC(sizeof(float) * num_v * 3); + attrib->num_vertices = (unsigned int)num_v; + attrib->normals = (float *)TINYOBJ_MALLOC(sizeof(float) * num_vn * 3); + 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->face_num_verts = (int *)TINYOBJ_MALLOC(sizeof(int) * num_faces); + 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) { + continue; + } else if (commands[i].type == COMMAND_USEMTL) { + /* @todo + if (commands[t][i].material_name && + commands[t][i].material_name_len > 0) { + std::string material_name(commands[t][i].material_name, + commands[t][i].material_name_len); + + if (material_map.find(material_name) != material_map.end()) { + material_id = material_map[material_name]; + } else { + // Assign invalid material ID + material_id = -1; + } + } + */ + if (commands[i].material_name && + commands[i].material_name_len >0) + { + /* Create a null terminated string */ + char* material_name_null_term = (char*) TINYOBJ_MALLOC(commands[i].material_name_len + 1); + memcpy((void*) material_name_null_term, (const void*) commands[i].material_name, commands[i].material_name_len); + material_name_null_term[commands[i].material_name_len - 1] = 0; + + if (hash_table_exists(material_name_null_term, &material_table)) + material_id = (int)hash_table_get(material_name_null_term, &material_table); + else + material_id = -1; + + TINYOBJ_FREE(material_name_null_term); + } + } else if (commands[i].type == COMMAND_V) { + attrib->vertices[3 * v_count + 0] = commands[i].vx; + attrib->vertices[3 * v_count + 1] = commands[i].vy; + attrib->vertices[3 * v_count + 2] = commands[i].vz; + v_count++; + } else if (commands[i].type == COMMAND_VN) { + attrib->normals[3 * n_count + 0] = commands[i].nx; + attrib->normals[3 * n_count + 1] = commands[i].ny; + attrib->normals[3 * n_count + 2] = commands[i].nz; + n_count++; + } else if (commands[i].type == COMMAND_VT) { + attrib->texcoords[2 * t_count + 0] = commands[i].tx; + attrib->texcoords[2 * t_count + 1] = commands[i].ty; + t_count++; + } else if (commands[i].type == COMMAND_F) { + size_t k = 0; + for (k = 0; k < commands[i].num_f; k++) { + tinyobj_vertex_index_t vi = commands[i].f[k]; + int v_idx = fixIndex(vi.v_idx, v_count); + int vn_idx = fixIndex(vi.vn_idx, n_count); + int vt_idx = fixIndex(vi.vt_idx, t_count); + attrib->faces[f_count + k].v_idx = v_idx; + attrib->faces[f_count + k].vn_idx = vn_idx; + attrib->faces[f_count + k].vt_idx = vt_idx; + } + + for (k = 0; k < commands[i].num_f_num_verts; k++) { + attrib->material_ids[face_count + k] = material_id; + attrib->face_num_verts[face_count + k] = commands[i].f_num_verts[k]; + } + + f_count += commands[i].num_f; + face_count += commands[i].num_f_num_verts; + } + } + } + + /* 5. Construct shape information. */ + { + unsigned int face_count = 0; + size_t i = 0; + size_t n = 0; + size_t shape_idx = 0; + + const char *shape_name = NULL; + unsigned int shape_name_len = 0; + const char *prev_shape_name = NULL; + unsigned int prev_shape_name_len = 0; + unsigned int prev_shape_face_offset = 0; + unsigned int prev_face_offset = 0; + tinyobj_shape_t prev_shape = {NULL, 0, 0}; + + /* Find the number of shapes in .obj */ + for (i = 0; i < num_lines; i++) { + if (commands[i].type == COMMAND_O || commands[i].type == COMMAND_G) { + n++; + } + } + + /* Allocate array of shapes with maximum possible size(+1 for unnamed + * group/object). + * Actual # of shapes found in .obj is determined in the later */ + (*shapes) = (tinyobj_shape_t*)TINYOBJ_MALLOC(sizeof(tinyobj_shape_t) * (n + 1)); + + for (i = 0; i < num_lines; i++) { + if (commands[i].type == COMMAND_O || commands[i].type == COMMAND_G) { + if (commands[i].type == COMMAND_O) { + shape_name = commands[i].object_name; + shape_name_len = commands[i].object_name_len; + } else { + shape_name = commands[i].group_name; + shape_name_len = commands[i].group_name_len; + } + + if (face_count == 0) { + /* 'o' or 'g' appears before any 'f' */ + prev_shape_name = shape_name; + prev_shape_name_len = shape_name_len; + prev_shape_face_offset = face_count; + prev_face_offset = face_count; + } else { + if (shape_idx == 0) { + /* 'o' or 'g' after some 'v' lines. */ + (*shapes)[shape_idx].name = my_strndup( + prev_shape_name, prev_shape_name_len); /* may be NULL */ + (*shapes)[shape_idx].face_offset = prev_shape.face_offset; + (*shapes)[shape_idx].length = face_count - prev_face_offset; + shape_idx++; + + prev_face_offset = face_count; + + } else { + if ((face_count - prev_face_offset) > 0) { + (*shapes)[shape_idx].name = + my_strndup(prev_shape_name, prev_shape_name_len); + (*shapes)[shape_idx].face_offset = prev_face_offset; + (*shapes)[shape_idx].length = face_count - prev_face_offset; + shape_idx++; + prev_face_offset = face_count; + } + } + + /* Record shape info for succeeding 'o' or 'g' command. */ + prev_shape_name = shape_name; + prev_shape_name_len = shape_name_len; + prev_shape_face_offset = face_count; + } + } + if (commands[i].type == COMMAND_F) { + face_count++; + } + } + + if ((face_count - prev_face_offset) > 0) { + size_t length = face_count - prev_shape_face_offset; + if (length > 0) { + (*shapes)[shape_idx].name = + my_strndup(prev_shape_name, prev_shape_name_len); + (*shapes)[shape_idx].face_offset = prev_face_offset; + (*shapes)[shape_idx].length = face_count - prev_face_offset; + shape_idx++; + } + } else { + /* Guess no 'v' line occurrence after 'o' or 'g', so discards current + * shape information. */ + } + + (*num_shapes) = shape_idx; + } + + if (commands) { + TINYOBJ_FREE(commands); + } + + destroy_hash_table(&material_table); + + (*materials_out) = materials; + (*num_materials_out) = num_materials; + + return TINYOBJ_SUCCESS; +} + +void tinyobj_attrib_init(tinyobj_attrib_t *attrib) { + attrib->vertices = NULL; + attrib->num_vertices = 0; + attrib->normals = NULL; + attrib->num_normals = 0; + attrib->texcoords = NULL; + attrib->num_texcoords = 0; + attrib->faces = NULL; + attrib->num_faces = 0; + attrib->face_num_verts = NULL; + attrib->num_face_num_verts = 0; + attrib->material_ids = NULL; +} + +void tinyobj_attrib_free(tinyobj_attrib_t *attrib) { + if (attrib->vertices) TINYOBJ_FREE(attrib->vertices); + if (attrib->normals) TINYOBJ_FREE(attrib->normals); + if (attrib->texcoords) TINYOBJ_FREE(attrib->texcoords); + if (attrib->faces) TINYOBJ_FREE(attrib->faces); + if (attrib->face_num_verts) TINYOBJ_FREE(attrib->face_num_verts); + if (attrib->material_ids) TINYOBJ_FREE(attrib->material_ids); +} + +void tinyobj_shapes_free(tinyobj_shape_t *shapes, size_t num_shapes) { + size_t i; + if (shapes == NULL) return; + + for (i = 0; i < num_shapes; i++) { + if (shapes[i].name) TINYOBJ_FREE(shapes[i].name); + } + + TINYOBJ_FREE(shapes); +} + +void tinyobj_materials_free(tinyobj_material_t *materials, + size_t num_materials) { + size_t i; + if (materials == NULL) return; + + for (i = 0; i < num_materials; i++) { + if (materials[i].name) TINYOBJ_FREE(materials[i].name); + if (materials[i].ambient_texname) TINYOBJ_FREE(materials[i].ambient_texname); + if (materials[i].diffuse_texname) TINYOBJ_FREE(materials[i].diffuse_texname); + if (materials[i].specular_texname) TINYOBJ_FREE(materials[i].specular_texname); + if (materials[i].specular_highlight_texname) + TINYOBJ_FREE(materials[i].specular_highlight_texname); + if (materials[i].bump_texname) TINYOBJ_FREE(materials[i].bump_texname); + if (materials[i].displacement_texname) + TINYOBJ_FREE(materials[i].displacement_texname); + if (materials[i].alpha_texname) TINYOBJ_FREE(materials[i].alpha_texname); + } + + TINYOBJ_FREE(materials); +} +#endif /* TINYOBJ_LOADER_C_IMPLEMENTATION */ + +#endif /* TINOBJ_LOADER_C_H_ */ diff --git a/src/models.c b/src/models.c index a5dbf5e7..c9d92315 100644 --- a/src/models.c +++ b/src/models.c @@ -52,6 +52,11 @@ #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 +#if defined(SUPPORT_FILEFORMAT_OBJ) + #define TINYOBJ_LOADER_C_IMPLEMENTATION + #include "external/tinyobj_loader_c.h" // OBJ file format loading +#endif + #if defined(SUPPORT_FILEFORMAT_IQM) #define RIQM_IMPLEMENTATION #include "external/riqm.h" // IQM file format loading @@ -86,16 +91,16 @@ // Module specific Functions Declaration //---------------------------------------------------------------------------------- #if defined(SUPPORT_FILEFORMAT_OBJ) -static Mesh LoadOBJ(const char *fileName); // Load OBJ mesh data +static Model LoadOBJ(const char *fileName); // Load OBJ mesh data #endif #if defined(SUPPORT_FILEFORMAT_MTL) static Material LoadMTL(const char *fileName); // Load MTL material data #endif #if defined(SUPPORT_FILEFORMAT_GLTF) -static Mesh LoadIQM(const char *fileName); // Load IQM mesh data +static Model LoadIQM(const char *fileName); // Load IQM mesh data #endif #if defined(SUPPORT_FILEFORMAT_GLTF) -static Mesh LoadGLTF(const char *fileName); // Load GLTF mesh data +static Model LoadGLTF(const char *fileName); // Load GLTF mesh data #endif //---------------------------------------------------------------------------------- @@ -618,9 +623,18 @@ Model LoadModel(const char *fileName) { Model model = { 0 }; - model.mesh = LoadMesh(fileName); - model.transform = MatrixIdentity(); - model.material = LoadMaterialDefault(); +#if defined(SUPPORT_FILEFORMAT_OBJ) + if (IsFileExtension(fileName, ".obj")) model = LoadOBJ(fileName); +#endif +#if defined(SUPPORT_FILEFORMAT_GLTF) + if (IsFileExtension(fileName, ".gltf")) model = LoadGLTF(fileName); +#endif +#if defined(SUPPORT_FILEFORMAT_IQM) + if (IsFileExtension(fileName, ".iqm")) model = LoadIQM(fileName); +#endif + + if (model.meshCount == 0) TraceLog(LOG_WARNING, "[%s] No meshes can be loaded", fileName); + if (model.materialCount == 0) TraceLog(LOG_WARNING, "[%s] No materials can be loaded", fileName); return model; } @@ -633,9 +647,18 @@ Model LoadModelFromMesh(Mesh mesh) { Model model = { 0 }; - model.mesh = mesh; model.transform = MatrixIdentity(); - model.material = LoadMaterialDefault(); + + model.meshCount = 1; + model.meshes = (Mesh *)malloc(model.meshCount*sizeof(Mesh)); + model.meshes[0] = mesh; + + model.materialCount = 1; + model.materials = (Material *)malloc(model.materialCount*sizeof(Material)); + model.materials[0] = LoadMaterialDefault(); + + model.meshMaterial = (int *)malloc(model.meshCount*sizeof(int)); + model.meshMaterial[0] = 0; // First material index return model; } @@ -643,10 +666,11 @@ Model LoadModelFromMesh(Mesh mesh) // Unload model from memory (RAM and/or VRAM) void UnloadModel(Model model) { - UnloadMesh(&model.mesh); - UnloadMaterial(model.material); + 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.meshMaterial); - TraceLog(LOG_INFO, "Unloaded model data (mesh and material) from RAM and VRAM"); + TraceLog(LOG_INFO, "Unloaded model data from RAM and VRAM"); } // Load mesh from file @@ -655,12 +679,8 @@ Mesh LoadMesh(const char *fileName) { Mesh mesh = { 0 }; -#if defined(SUPPORT_FILEFORMAT_OBJ) - if (IsFileExtension(fileName, ".obj")) mesh = LoadOBJ(fileName); -#else - TraceLog(LOG_WARNING, "[%s] Mesh fileformat not supported, it can't be loaded", fileName); -#endif - + // TODO: Review this function, should still exist? + #if defined(SUPPORT_MESH_GENERATION) if (mesh.vertexCount == 0) { @@ -1855,9 +1875,12 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota //Matrix matModel = MatrixMultiply(model.transform, matTransform); // Transform to world-space coordinates model.transform = MatrixMultiply(model.transform, matTransform); - model.material.maps[MAP_DIFFUSE].color = tint; // TODO: Multiply tint color by diffuse color? - rlDrawMesh(model.mesh, model.material, model.transform); + for (int i = 0; i < model.meshCount; i++) + { + model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color = tint; + rlDrawMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform); + } } // Draw a model wires (with texture if set) @@ -2079,41 +2102,45 @@ RayHitInfo GetCollisionRayModel(Ray ray, Model *model) { RayHitInfo result = { 0 }; - // If mesh doesn't have vertex data on CPU, can't test it. - if (!model->mesh.vertices) return result; - - // model->mesh.triangleCount may not be set, vertexCount is more reliable - int triangleCount = model->mesh.vertexCount/3; - - // Test against all triangles in mesh - for (int i = 0; i < triangleCount; i++) + for (int i = 0; i < model->meshCount; i++) { - Vector3 a, b, c; - Vector3 *vertdata = (Vector3 *)model->mesh.vertices; - - if (model->mesh.indices) - { - a = vertdata[model->mesh.indices[i*3 + 0]]; - b = vertdata[model->mesh.indices[i*3 + 1]]; - c = vertdata[model->mesh.indices[i*3 + 2]]; - } - else + // Check if meshhas vertex data on CPU for testing + if (model->meshes[i].vertices != NULL) { - a = vertdata[i*3 + 0]; - b = vertdata[i*3 + 1]; - c = vertdata[i*3 + 2]; - } + // model->mesh.triangleCount may not be set, vertexCount is more reliable + int triangleCount = model->meshes[i].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; - a = Vector3Transform(a, model->transform); - b = Vector3Transform(b, model->transform); - c = Vector3Transform(c, model->transform); + if (model->meshes[i].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]]; + } + else + { + a = vertdata[i*3 + 0]; + b = vertdata[i*3 + 1]; + c = vertdata[i*3 + 2]; + } - RayHitInfo triHitInfo = GetCollisionRayTriangle(ray, a, b, c); + a = Vector3Transform(a, model->transform); + b = Vector3Transform(b, model->transform); + c = Vector3Transform(c, model->transform); - if (triHitInfo.hit) - { - // Save the closest hit triangle - if ((!result.hit) || (result.distance > triHitInfo.distance)) result = triHitInfo; + RayHitInfo triHitInfo = GetCollisionRayTriangle(ray, a, b, c); + + if (triHitInfo.hit) + { + // Save the closest hit triangle + if ((!result.hit) || (result.distance > triHitInfo.distance)) result = triHitInfo; + } + } } } @@ -2329,10 +2356,13 @@ void MeshBinormals(Mesh *mesh) #if defined(SUPPORT_FILEFORMAT_OBJ) // Load OBJ mesh data -static Mesh LoadOBJ(const char *fileName) +static Model LoadOBJ(const char *fileName) { - Mesh mesh = { 0 }; + Model model = { 0 }; + // TODO: Use tinyobj_loader_c library + +/* char dataType = 0; char comments[200]; @@ -2568,11 +2598,12 @@ static Mesh LoadOBJ(const char *fileName) free(midVertices); free(midNormals); free(midTexCoords); +*/ // NOTE: At this point we have all vertex, texcoord, normal data for the model in mesh struct TraceLog(LOG_INFO, "[%s] Model loaded successfully in RAM (CPU)", fileName); - return mesh; + return model; } #endif @@ -2743,21 +2774,21 @@ static Material LoadMTL(const char *fileName) #if defined(SUPPORT_FILEFORMAT_GLTF) // Load IQM mesh data -static Mesh LoadIQM(const char *fileName) +static Model LoadIQM(const char *fileName) { - Mesh mesh = { 0 }; + Model model = { 0 }; // TODO: Load IQM file - return mesh; + return model; } #endif #if defined(SUPPORT_FILEFORMAT_GLTF) // Load glTF mesh data -static Mesh LoadGLTF(const char *fileName) +static Model LoadGLTF(const char *fileName) { - Mesh mesh = { 0 }; + Model model = { 0 }; // glTF file loading FILE *gltfFile = fopen(fileName, "rb"); @@ -2765,7 +2796,7 @@ static Mesh LoadGLTF(const char *fileName) if (gltfFile == NULL) { TraceLog(LOG_WARNING, "[%s] glTF file could not be opened", fileName); - return mesh; + return model; } fseek(gltfFile, 0, SEEK_END); @@ -2790,15 +2821,15 @@ static Mesh LoadGLTF(const char *fileName) printf("Version: %d\n", data.version); printf("Meshes: %lu\n", data.meshes_count); - // TODO: Process glTF data and map to mesh + // TODO: Process glTF data and map to model - // NOTE: data.buffers[] and data.images[] should be loaded - // using buffers[n].uri and images[n].uri... or use cgltf_load_buffers(&options, data, fileName); + // 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); } else TraceLog(LOG_WARNING, "[%s] glTF data could not be loaded", fileName); - return mesh; + return model; } #endif diff --git a/src/raylib.h b/src/raylib.h index 5db50c04..1a344306 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -339,18 +339,15 @@ typedef struct Material { // Model type typedef struct Model { - Mesh mesh; // Vertex data buffers (RAM and VRAM) Matrix transform; // Local transform matrix - Material material; // Shader and textures data - /* - Mesh *meshes; // Vertex data buffers (RAM and VRAM) - int meshCount; - - Material *materials; // Shader and textures data - int materialCount; - - int *meshMaterial; // Material assigned to every mesh - */ + + int meshCount; // Number of meshes + Mesh *meshes; // Meshes array + + int materialCount; // Number of materials + Material *materials; // Materials array + + int *meshMaterial; // Mesh material number } Model; // Ray type (useful for raycast) @@ -1226,7 +1223,7 @@ RLAPI void DrawGizmo(Vector3 position); //------------------------------------------------------------------------------------ // Model loading/unloading functions -RLAPI Model LoadModel(const char *fileName); // Load model from files (mesh and material) +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 UnloadModel(Model model); // Unload model from memory (RAM and/or VRAM) -- cgit v1.2.3 From 8a73c5d0b403264ebd66cb5a2e1b21f91f6991b0 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 29 Mar 2019 17:15:22 +0100 Subject: Replace custom OBJ/MTL implementations by tinyobj_loader -WIP- --- src/models.c | 495 +++++++++++------------------------------------------------ 1 file changed, 89 insertions(+), 406 deletions(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index c9d92315..ec2713ed 100644 --- a/src/models.c +++ b/src/models.c @@ -52,9 +52,9 @@ #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 -#if defined(SUPPORT_FILEFORMAT_OBJ) +#if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL) #define TINYOBJ_LOADER_C_IMPLEMENTATION - #include "external/tinyobj_loader_c.h" // OBJ file format loading + #include "external/tinyobj_loader_c.h" // OBJ/MTL file formats loading #endif #if defined(SUPPORT_FILEFORMAT_IQM) @@ -93,9 +93,6 @@ #if defined(SUPPORT_FILEFORMAT_OBJ) static Model LoadOBJ(const char *fileName); // Load OBJ mesh data #endif -#if defined(SUPPORT_FILEFORMAT_MTL) -static Material LoadMTL(const char *fileName); // Load MTL material data -#endif #if defined(SUPPORT_FILEFORMAT_GLTF) static Model LoadIQM(const char *fileName); // Load IQM mesh data #endif @@ -1811,7 +1808,17 @@ Material LoadMaterial(const char *fileName) Material material = { 0 }; #if defined(SUPPORT_FILEFORMAT_MTL) - if (IsFileExtension(fileName, ".mtl")) material = LoadMTL(fileName); + if (IsFileExtension(fileName, ".mtl")) + { + tinyobj_material_t *materials; + int materialCount = 0; + + int result = tinyobj_parse_mtl_file(&materials, &materialCount, fileName); + + // TODO: Process materials to return + + tinyobj_materials_free(materials, materialCount); + } #else TraceLog(LOG_WARNING, "[%s] Material fileformat not supported, it can't be loaded", fileName); #endif @@ -2359,419 +2366,95 @@ void MeshBinormals(Mesh *mesh) static Model LoadOBJ(const char *fileName) { Model model = { 0 }; - - // TODO: Use tinyobj_loader_c library -/* - char dataType = 0; - char comments[200]; - - int vertexCount = 0; - int normalCount = 0; - int texcoordCount = 0; - int triangleCount = 0; - - FILE *objFile; - - objFile = fopen(fileName, "rt"); - - if (objFile == NULL) - { - TraceLog(LOG_WARNING, "[%s] OBJ file could not be opened", fileName); - return mesh; - } - - // First reading pass: Get vertexCount, normalCount, texcoordCount, triangleCount - // NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition) - // NOTE: faces MUST be defined as TRIANGLES (3 vertex per face) - while (!feof(objFile)) - { - dataType = 0; - fscanf(objFile, "%c", &dataType); - - switch (dataType) - { - case '#': // Comments - case 'o': // Object name (One OBJ file can contain multible named meshes) - case 'g': // Group name - case 's': // Smoothing level - case 'm': // mtllib [external .mtl file name] - case 'u': // usemtl [material name] - { - fgets(comments, 200, objFile); - } break; - case 'v': - { - fscanf(objFile, "%c", &dataType); - - if (dataType == 't') // Read texCoord - { - texcoordCount++; - fgets(comments, 200, objFile); - } - else if (dataType == 'n') // Read normals - { - normalCount++; - fgets(comments, 200, objFile); - } - else // Read vertex - { - vertexCount++; - fgets(comments, 200, objFile); - } - } break; - case 'f': - { - triangleCount++; - fgets(comments, 200, objFile); - } break; - default: break; - } - } - - TraceLog(LOG_DEBUG, "[%s] Model vertices: %i", fileName, vertexCount); - TraceLog(LOG_DEBUG, "[%s] Model texcoords: %i", fileName, texcoordCount); - TraceLog(LOG_DEBUG, "[%s] Model normals: %i", fileName, normalCount); - TraceLog(LOG_DEBUG, "[%s] Model triangles: %i", fileName, triangleCount); - - // Once we know the number of vertices to store, we create required arrays - Vector3 *midVertices = (Vector3 *)malloc(vertexCount*sizeof(Vector3)); - Vector3 *midNormals = NULL; - if (normalCount > 0) midNormals = (Vector3 *)malloc(normalCount*sizeof(Vector3)); - Vector2 *midTexCoords = NULL; - if (texcoordCount > 0) midTexCoords = (Vector2 *)malloc(texcoordCount*sizeof(Vector2)); - - int countVertex = 0; - int countNormals = 0; - int countTexCoords = 0; - - rewind(objFile); // Return to the beginning of the file, to read again - - // Second reading pass: Get vertex data to fill intermediate arrays - // NOTE: This second pass is required in case of multiple meshes defined in same OBJ - // TODO: Consider that different meshes can have different vertex data available (position, texcoords, normals) - while (!feof(objFile)) - { - fscanf(objFile, "%c", &dataType); - - switch (dataType) - { - case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'f': fgets(comments, 200, objFile); break; - case 'v': - { - fscanf(objFile, "%c", &dataType); - - if (dataType == 't') // Read texCoord - { - fscanf(objFile, "%f %f%*[^\n]s\n", &midTexCoords[countTexCoords].x, &midTexCoords[countTexCoords].y); - countTexCoords++; - - fscanf(objFile, "%c", &dataType); - } - else if (dataType == 'n') // Read normals - { - fscanf(objFile, "%f %f %f", &midNormals[countNormals].x, &midNormals[countNormals].y, &midNormals[countNormals].z); - countNormals++; - - fscanf(objFile, "%c", &dataType); - } - else // Read vertex - { - fscanf(objFile, "%f %f %f", &midVertices[countVertex].x, &midVertices[countVertex].y, &midVertices[countVertex].z); - countVertex++; - - fscanf(objFile, "%c", &dataType); - } - } break; - default: break; - } - } - - // At this point all vertex data (v, vt, vn) has been gathered on midVertices, midTexCoords, midNormals - // Now we can organize that data into our Mesh struct - - mesh.vertexCount = triangleCount*3; - - // Additional arrays to store vertex data as floats - 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)); - mesh.colors = NULL; - - int vCounter = 0; // Used to count vertices float by float - int tcCounter = 0; // Used to count texcoords float by float - int nCounter = 0; // Used to count normals float by float - - int vCount[3], vtCount[3], vnCount[3]; // Used to store triangle indices for v, vt, vn - - rewind(objFile); // Return to the beginning of the file, to read again - - if (normalCount == 0) TraceLog(LOG_INFO, "[%s] No normals data on OBJ, normals will be generated from faces data", fileName); + tinyobj_attrib_t attrib; + tinyobj_shape_t *meshes = NULL; + int meshCount = 0; + + tinyobj_material_t *materials = NULL; + int materialCount = 0; - // Third reading pass: Get faces (triangles) data and fill VertexArray - while (!feof(objFile)) + int dataLength = 0; + const char *data = get_file_data(&dataLength, fileName); + + if (data != NULL) { - fscanf(objFile, "%c", &dataType); - - switch (dataType) + 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++) { - case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'v': fgets(comments, 200, objFile); break; - case 'f': - { - // NOTE: It could be that OBJ does not have normals or texcoords defined! - - if ((normalCount == 0) && (texcoordCount == 0)) fscanf(objFile, "%i %i %i", &vCount[0], &vCount[1], &vCount[2]); - else if (normalCount == 0) fscanf(objFile, "%i/%i %i/%i %i/%i", &vCount[0], &vtCount[0], &vCount[1], &vtCount[1], &vCount[2], &vtCount[2]); - else if (texcoordCount == 0) fscanf(objFile, "%i//%i %i//%i %i//%i", &vCount[0], &vnCount[0], &vCount[1], &vnCount[1], &vCount[2], &vnCount[2]); - else fscanf(objFile, "%i/%i/%i %i/%i/%i %i/%i/%i", &vCount[0], &vtCount[0], &vnCount[0], &vCount[1], &vtCount[1], &vnCount[1], &vCount[2], &vtCount[2], &vnCount[2]); - - mesh.vertices[vCounter] = midVertices[vCount[0]-1].x; - mesh.vertices[vCounter + 1] = midVertices[vCount[0]-1].y; - mesh.vertices[vCounter + 2] = midVertices[vCount[0]-1].z; - vCounter += 3; - mesh.vertices[vCounter] = midVertices[vCount[1]-1].x; - mesh.vertices[vCounter + 1] = midVertices[vCount[1]-1].y; - mesh.vertices[vCounter + 2] = midVertices[vCount[1]-1].z; - vCounter += 3; - mesh.vertices[vCounter] = midVertices[vCount[2]-1].x; - mesh.vertices[vCounter + 1] = midVertices[vCount[2]-1].y; - mesh.vertices[vCounter + 2] = midVertices[vCount[2]-1].z; - vCounter += 3; - - if (normalCount > 0) - { - mesh.normals[nCounter] = midNormals[vnCount[0]-1].x; - mesh.normals[nCounter + 1] = midNormals[vnCount[0]-1].y; - mesh.normals[nCounter + 2] = midNormals[vnCount[0]-1].z; - nCounter += 3; - mesh.normals[nCounter] = midNormals[vnCount[1]-1].x; - mesh.normals[nCounter + 1] = midNormals[vnCount[1]-1].y; - mesh.normals[nCounter + 2] = midNormals[vnCount[1]-1].z; - nCounter += 3; - mesh.normals[nCounter] = midNormals[vnCount[2]-1].x; - mesh.normals[nCounter + 1] = midNormals[vnCount[2]-1].y; - mesh.normals[nCounter + 2] = midNormals[vnCount[2]-1].z; - nCounter += 3; - } - else - { - // If normals not defined, they are calculated from the 3 vertices [N = (V2 - V1) x (V3 - V1)] - Vector3 norm = Vector3CrossProduct(Vector3Subtract(midVertices[vCount[1]-1], midVertices[vCount[0]-1]), Vector3Subtract(midVertices[vCount[2]-1], midVertices[vCount[0]-1])); - norm = Vector3Normalize(norm); - - mesh.normals[nCounter] = norm.x; - mesh.normals[nCounter + 1] = norm.y; - mesh.normals[nCounter + 2] = norm.z; - nCounter += 3; - mesh.normals[nCounter] = norm.x; - mesh.normals[nCounter + 1] = norm.y; - mesh.normals[nCounter + 2] = norm.z; - nCounter += 3; - mesh.normals[nCounter] = norm.x; - mesh.normals[nCounter + 1] = norm.y; - mesh.normals[nCounter + 2] = norm.z; - nCounter += 3; - } - - if (texcoordCount > 0) - { - // NOTE: If using negative texture coordinates with a texture filter of GL_CLAMP_TO_EDGE doesn't work! - // NOTE: Texture coordinates are Y flipped upside-down - mesh.texcoords[tcCounter] = midTexCoords[vtCount[0]-1].x; - mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtCount[0]-1].y; - tcCounter += 2; - mesh.texcoords[tcCounter] = midTexCoords[vtCount[1]-1].x; - mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtCount[1]-1].y; - tcCounter += 2; - mesh.texcoords[tcCounter] = midTexCoords[vtCount[2]-1].x; - mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtCount[2]-1].y; - tcCounter += 2; - } - } break; - default: break; + printf("shape[%d] name = %s\n", i, meshes[i].name); } + + /* + // 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; + + typedef struct { + char *name; // group name or object name + unsigned int face_offset; + unsigned int length; + } tinyobj_shape_t; + + typedef struct { int v_idx, vt_idx, vn_idx; } tinyobj_vertex_index_t; + + 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; + */ + + tinyobj_attrib_free(&attrib); + tinyobj_shapes_free(meshes, meshCount); + tinyobj_materials_free(materials, materialCount); } - fclose(objFile); - - // Now we can free temp mid* arrays - free(midVertices); - free(midNormals); - free(midTexCoords); -*/ - - // NOTE: At this point we have all vertex, texcoord, normal data for the model in mesh struct + // NOTE: At this point we have all model data loaded TraceLog(LOG_INFO, "[%s] Model loaded successfully in RAM (CPU)", fileName); return model; } #endif -#if defined(SUPPORT_FILEFORMAT_MTL) -// Load MTL material data (specs: http://paulbourke.net/dataformats/mtl/) -// NOTE: Texture map parameters are not supported -static Material LoadMTL(const char *fileName) -{ - #define MAX_BUFFER_SIZE 128 - - Material material = { 0 }; - - char buffer[MAX_BUFFER_SIZE]; - Vector3 color = { 1.0f, 1.0f, 1.0f }; - char mapFileName[128]; - int result = 0; - - FILE *mtlFile; - - mtlFile = fopen(fileName, "rt"); - - if (mtlFile == NULL) - { - TraceLog(LOG_WARNING, "[%s] MTL file could not be opened", fileName); - return material; - } - - while (!feof(mtlFile)) - { - fgets(buffer, MAX_BUFFER_SIZE, mtlFile); - - switch (buffer[0]) - { - case 'n': // newmtl string Material name. Begins a new material description. - { - // TODO: Support multiple materials in a single .mtl - sscanf(buffer, "newmtl %127s", mapFileName); - } - case 'i': // illum int Illumination model - { - // illum = 1 if specular disabled - // illum = 2 if specular enabled (lambertian model) - // ... - } - case 'K': // Ka, Kd, Ks, Ke - { - switch (buffer[1]) - { - case 'a': // Ka float float float Ambient color (RGB) - { - sscanf(buffer, "Ka %f %f %f", &color.x, &color.y, &color.z); - // TODO: Support ambient color - //material.colAmbient.r = (unsigned char)(color.x*255); - //material.colAmbient.g = (unsigned char)(color.y*255); - //material.colAmbient.b = (unsigned char)(color.z*255); - } break; - case 'd': // Kd float float float Diffuse color (RGB) - { - sscanf(buffer, "Kd %f %f %f", &color.x, &color.y, &color.z); - material.maps[MAP_DIFFUSE].color.r = (unsigned char)(color.x*255); - material.maps[MAP_DIFFUSE].color.g = (unsigned char)(color.y*255); - material.maps[MAP_DIFFUSE].color.b = (unsigned char)(color.z*255); - } break; - case 's': // Ks float float float Specular color (RGB) - { - sscanf(buffer, "Ks %f %f %f", &color.x, &color.y, &color.z); - material.maps[MAP_SPECULAR].color.r = (unsigned char)(color.x*255); - material.maps[MAP_SPECULAR].color.g = (unsigned char)(color.y*255); - material.maps[MAP_SPECULAR].color.b = (unsigned char)(color.z*255); - } break; - case 'e': // Ke float float float Emmisive color (RGB) - { - // TODO: Support Ke? - } break; - default: break; - } - } break; - case 'N': // Ns, Ni - { - if (buffer[1] == 's') // Ns int Shininess (specular exponent). Ranges from 0 to 1000. - { - int shininess = 0; - sscanf(buffer, "Ns %i", &shininess); - - //material.params[PARAM_GLOSSINES] = (float)shininess; - } - else if (buffer[1] == 'i') // Ni int Refraction index. - { - // Not supported... - } - } break; - case 'm': // map_Kd, map_Ks, map_Ka, map_Bump, map_d - { - switch (buffer[4]) - { - case 'K': // Color texture maps - { - if (buffer[5] == 'd') // map_Kd string Diffuse color texture map. - { - result = sscanf(buffer, "map_Kd %127s", mapFileName); - if (result != EOF) material.maps[MAP_DIFFUSE].texture = LoadTexture(mapFileName); - } - else if (buffer[5] == 's') // map_Ks string Specular color texture map. - { - result = sscanf(buffer, "map_Ks %127s", mapFileName); - if (result != EOF) material.maps[MAP_SPECULAR].texture = LoadTexture(mapFileName); - } - else if (buffer[5] == 'a') // map_Ka string Ambient color texture map. - { - // Not supported... - } - } break; - case 'B': // map_Bump string Bump texture map. - { - result = sscanf(buffer, "map_Bump %127s", mapFileName); - if (result != EOF) material.maps[MAP_NORMAL].texture = LoadTexture(mapFileName); - } break; - case 'b': // map_bump string Bump texture map. - { - result = sscanf(buffer, "map_bump %127s", mapFileName); - if (result != EOF) material.maps[MAP_NORMAL].texture = LoadTexture(mapFileName); - } break; - case 'd': // map_d string Opacity texture map. - { - // Not supported... - } break; - default: break; - } - } break; - case 'd': // d, disp - { - if (buffer[1] == ' ') // d float Dissolve factor. d is inverse of Tr - { - float alpha = 1.0f; - sscanf(buffer, "d %f", &alpha); - material.maps[MAP_DIFFUSE].color.a = (unsigned char)(alpha*255); - } - else if (buffer[1] == 'i') // disp string Displacement map - { - // Not supported... - } - } break; - case 'b': // bump string Bump texture map - { - result = sscanf(buffer, "bump %127s", mapFileName); - if (result != EOF) material.maps[MAP_NORMAL].texture = LoadTexture(mapFileName); - } break; - case 'T': // Tr float Transparency Tr (alpha). Tr is inverse of d - { - float ialpha = 0.0f; - sscanf(buffer, "Tr %f", &ialpha); - material.maps[MAP_DIFFUSE].color.a = (unsigned char)((1.0f - ialpha)*255); - - } break; - case 'r': // refl string Reflection texture map - default: break; - } - } - - fclose(mtlFile); - - // NOTE: At this point we have all material data - TraceLog(LOG_INFO, "[%s] Material loaded successfully", fileName); - - return material; -} -#endif - #if defined(SUPPORT_FILEFORMAT_GLTF) // Load IQM mesh data static Model LoadIQM(const char *fileName) -- cgit v1.2.3 From 19debd2b4e44cee494c882cb8d338dc1847ae5b5 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 29 Mar 2019 17:28:10 +0100 Subject: Review some warnings --- src/models.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index ec2713ed..6f3fa73f 100644 --- a/src/models.c +++ b/src/models.c @@ -1811,7 +1811,7 @@ Material LoadMaterial(const char *fileName) if (IsFileExtension(fileName, ".mtl")) { tinyobj_material_t *materials; - int materialCount = 0; + unsigned int materialCount = 0; int result = tinyobj_parse_mtl_file(&materials, &materialCount, fileName); @@ -2369,14 +2369,29 @@ static Model LoadOBJ(const char *fileName) tinyobj_attrib_t attrib; tinyobj_shape_t *meshes = NULL; - int meshCount = 0; + unsigned int meshCount = 0; tinyobj_material_t *materials = NULL; - int materialCount = 0; + unsigned int materialCount = 0; int dataLength = 0; - const char *data = get_file_data(&dataLength, fileName); + 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 + + data = (char *)malloc(dataLength); + + fread(data, dataLength, 1, objFile); + fclose(objFile); + } + if (data != NULL) { unsigned int flags = TINYOBJ_FLAG_TRIANGULATE; -- cgit v1.2.3 From a197f40bb4bd5a644ad54bef756d7f435977df9d Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 29 Mar 2019 20:22:30 +0100 Subject: Default to white cube mesh if not loaded --- src/models.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index 6f3fa73f..2893fd2f 100644 --- a/src/models.c +++ b/src/models.c @@ -630,8 +630,25 @@ Model LoadModel(const char *fileName) if (IsFileExtension(fileName, ".iqm")) model = LoadIQM(fileName); #endif - if (model.meshCount == 0) TraceLog(LOG_WARNING, "[%s] No meshes can be loaded", fileName); - if (model.materialCount == 0) TraceLog(LOG_WARNING, "[%s] No materials can be loaded", fileName); + 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[0] = GenMeshCube(1.0f, 1.0f, 1.0f); + } + + 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[0] = LoadMaterialDefault(); + + model.meshMaterial = (int *)calloc(model.meshCount, sizeof(int)); + } return model; } -- cgit v1.2.3 From fe702cd6a2d1aeb23c47c3db412311e2b04c9b7c Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 1 Apr 2019 00:16:56 +0200 Subject: Implementing LoadOBJ() -WIP- It seems obj loading is working ok but there is some problem with drawing... --- src/models.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 140 insertions(+), 33 deletions(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index 2893fd2f..68f5f6be 100644 --- a/src/models.c +++ b/src/models.c @@ -2400,55 +2400,113 @@ static Model LoadOBJ(const char *fileName) 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++) + + // 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)); + + // Init model meshes + for (int m = 0; m < 1; m++) { - printf("shape[%d] name = %s\n", i, meshes[i].name); + printf("num_vertices: %i\n", attrib.num_vertices); + printf("num_normals: %i\n", attrib.num_normals); + printf("num_texcoords: %i\n", attrib.num_texcoords); + printf("num_faces: %i\n", attrib.num_faces); + printf("num_face_num_verts: %i\n", attrib.num_face_num_verts); + + 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 faceOffset = 0; + + int vCount = 0; + int vtCount = 0; + int vnCount = 0; + + /* + for (int i = 0; i < attrib.num_vertices*3; i++) printf("%2.2f, ", attrib.vertices[i]); + printf("\n"); + for (int i = 0; i < attrib.num_texcoords*2; i++) printf("%2.2f, ", attrib.texcoords[i]); + printf("\n"); + for (int i = 0; i < attrib.num_normals*3; i++) printf("%2.2f, ", attrib.normals[i]); + printf("\n"); + + tinyobj_vertex_index_t idx0 = attrib.faces[0]; + tinyobj_vertex_index_t idx1 = attrib.faces[1]; + tinyobj_vertex_index_t idx2 = attrib.faces[2]; + + for (int v = 0; v < 3; v++) { printf("%2.2f, ", attrib.vertices[idx0.v_idx*3 + v]); } printf("\n"); + for (int v = 0; v < 3; v++) { printf("%2.2f, ", attrib.vertices[idx1.v_idx*3 + v]); } printf("\n"); + for (int v = 0; v < 3; v++) { printf("%2.2f, ", attrib.vertices[idx2.v_idx*3 + v]); } printf("\n\n"); + + idx0 = attrib.faces[3 + 0]; + idx1 = attrib.faces[3 + 1]; + idx2 = attrib.faces[3 + 2]; + + for (int v = 0; v < 3; v++) { printf("%2.2f, ", attrib.vertices[idx0.v_idx*3 + v]); } printf("\n"); + for (int v = 0; v < 3; v++) { printf("%2.2f, ", attrib.vertices[idx1.v_idx*3 + v]); } printf("\n"); + for (int v = 0; v < 3; v++) { printf("%2.2f, ", attrib.vertices[idx2.v_idx*3 + v]); } printf("\n\n"); +*/ + for (int f = 0; f < attrib.num_faces; f++) + { + 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]; + + // printf("Face index: v %i/%i/%i . vt %i/%i/%i . vn %i/%i/%i\n", + // 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); + + 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; + + for (int v = 0; v < 2; v++) { mesh.texcoords[vtCount + v] = attrib.texcoords[idx0.vt_idx*2 + v]; } vtCount += 2; + for (int v = 0; v < 2; v++) { mesh.texcoords[vtCount + v] = attrib.texcoords[idx1.vt_idx*2 + v]; } vtCount += 2; + for (int v = 0; v < 2; v++) { mesh.texcoords[vtCount + v] = attrib.texcoords[idx2.vt_idx*2 + v]; } vtCount += 2; + + 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; + } + + printf("vCount: %i\n", vCount); + printf("vtCount: %i\n", vtCount); + printf("vnCount: %i\n", vnCount); + + model.meshes[m] = mesh; // Assign mesh data to model + rlLoadMesh(&model.meshes[m], false); // Upload vertex data to GPU (static mesh) } /* // 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; - typedef struct { char *name; // group name or object name unsigned int face_offset; @@ -2469,11 +2527,60 @@ static Model LoadOBJ(const char *fileName) float *vertices; float *normals; float *texcoords; + tinyobj_vertex_index_t *faces; int *face_num_verts; + int *material_ids; } tinyobj_attrib_t; */ + + // Init model materials + for (int m = 0; m < materialCount; m++) + { + /* + 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; + */ + + /* + // Material texture map + typedef struct MaterialMap { + Texture2D texture; // Material map texture + Color color; // Material map color + float value; // Material map value + } MaterialMap; + + // Material type (generic) + typedef struct Material { + Shader shader; // Material shader + MaterialMap maps[MAX_MATERIAL_MAPS]; // Material maps + float *params; // Material generic parameters (if required) + } Material; + */ + } tinyobj_attrib_free(&attrib); tinyobj_shapes_free(meshes, meshCount); -- cgit v1.2.3 From e5edbb7104795e9936a275a8c53caf5026ab497f Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 1 Apr 2019 12:17:29 +0200 Subject: Reviewed OBJ loading implementation -WIP- One mesh files can be loaded correctly MISSING: - Multimesh OBJ loading - Materials loading --- src/models.c | 131 +++++++++++++++++++---------------------------------------- 1 file changed, 41 insertions(+), 90 deletions(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index 68f5f6be..b1c56e48 100644 --- a/src/models.c +++ b/src/models.c @@ -635,7 +635,7 @@ Model LoadModel(const char *fileName) 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); } @@ -644,7 +644,7 @@ Model LoadModel(const char *fileName) 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)); @@ -1879,7 +1879,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 +1896,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 +2124,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 +2258,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 +2274,7 @@ BoundingBox MeshBoundingBox(Mesh mesh) } // Create the bounding box - BoundingBox box; + BoundingBox box = { 0 }; box.min = minVertex; box.max = maxVertex; @@ -2383,17 +2383,18 @@ void MeshBinormals(Mesh *mesh) static Model LoadOBJ(const char *fileName) { Model model = { 0 }; - + model.transform = MatrixIdentity(); + 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"); @@ -2425,16 +2426,21 @@ static Model LoadOBJ(const char *fileName) // Init model materials array model.materialCount = materialCount; model.materials = (Material *)malloc(model.materialCount*sizeof(Material)); + model.meshMaterial = (int *)calloc(model.meshCount, sizeof(int)); + + /* + // 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++) { - printf("num_vertices: %i\n", attrib.num_vertices); - printf("num_normals: %i\n", attrib.num_normals); - printf("num_texcoords: %i\n", attrib.num_texcoords); - printf("num_faces: %i\n", attrib.num_faces); - printf("num_face_num_verts: %i\n", attrib.num_face_num_verts); - Mesh mesh = { 0 }; memset(&mesh, 0, sizeof(Mesh)); mesh.vertexCount = attrib.num_faces*3; @@ -2443,98 +2449,43 @@ static Model LoadOBJ(const char *fileName) mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float)); mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); - int faceOffset = 0; - int vCount = 0; int vtCount = 0; int vnCount = 0; - /* - for (int i = 0; i < attrib.num_vertices*3; i++) printf("%2.2f, ", attrib.vertices[i]); - printf("\n"); - for (int i = 0; i < attrib.num_texcoords*2; i++) printf("%2.2f, ", attrib.texcoords[i]); - printf("\n"); - for (int i = 0; i < attrib.num_normals*3; i++) printf("%2.2f, ", attrib.normals[i]); - printf("\n"); - - tinyobj_vertex_index_t idx0 = attrib.faces[0]; - tinyobj_vertex_index_t idx1 = attrib.faces[1]; - tinyobj_vertex_index_t idx2 = attrib.faces[2]; - - for (int v = 0; v < 3; v++) { printf("%2.2f, ", attrib.vertices[idx0.v_idx*3 + v]); } printf("\n"); - for (int v = 0; v < 3; v++) { printf("%2.2f, ", attrib.vertices[idx1.v_idx*3 + v]); } printf("\n"); - for (int v = 0; v < 3; v++) { printf("%2.2f, ", attrib.vertices[idx2.v_idx*3 + v]); } printf("\n\n"); - - idx0 = attrib.faces[3 + 0]; - idx1 = attrib.faces[3 + 1]; - idx2 = attrib.faces[3 + 2]; - - for (int v = 0; v < 3; v++) { printf("%2.2f, ", attrib.vertices[idx0.v_idx*3 + v]); } printf("\n"); - for (int v = 0; v < 3; v++) { printf("%2.2f, ", attrib.vertices[idx1.v_idx*3 + v]); } printf("\n"); - for (int v = 0; v < 3; v++) { printf("%2.2f, ", attrib.vertices[idx2.v_idx*3 + v]); } printf("\n\n"); -*/ 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]; - // printf("Face index: v %i/%i/%i . vt %i/%i/%i . vn %i/%i/%i\n", - // 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); + // 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; - for (int v = 0; v < 2; v++) { mesh.texcoords[vtCount + v] = attrib.texcoords[idx0.vt_idx*2 + v]; } vtCount += 2; - for (int v = 0; v < 2; v++) { mesh.texcoords[vtCount + v] = attrib.texcoords[idx1.vt_idx*2 + v]; } vtCount += 2; - for (int v = 0; v < 2; v++) { mesh.texcoords[vtCount + v] = attrib.texcoords[idx2.vt_idx*2 + v]; } vtCount += 2; + // 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; } - - printf("vCount: %i\n", vCount); - printf("vtCount: %i\n", vtCount); - printf("vnCount: %i\n", vnCount); model.meshes[m] = mesh; // Assign mesh data to model rlLoadMesh(&model.meshes[m], false); // Upload vertex data to GPU (static mesh) } - - /* - // Data reference to process - typedef struct { - char *name; // group name or object name - unsigned int face_offset; - unsigned int length; - } tinyobj_shape_t; - - typedef struct { int v_idx, vt_idx, vn_idx; } tinyobj_vertex_index_t; - - 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; - */ - // Init model materials for (int m = 0; m < materialCount; m++) { -- cgit v1.2.3 From 86212e84628e589701c7934affd83685ff3e8ae9 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 1 Apr 2019 12:41:32 +0200 Subject: Support material loading from OBJ/MTL --- src/models.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index b1c56e48..9fb08d82 100644 --- a/src/models.c +++ b/src/models.c @@ -2484,11 +2484,18 @@ static Model LoadOBJ(const char *fileName) model.meshes[m] = mesh; // Assign mesh data to model rlLoadMesh(&model.meshes[m], false); // Upload vertex data to GPU (static mesh) + + // 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; @@ -2516,21 +2523,21 @@ static Model LoadOBJ(const char *fileName) } tinyobj_material_t; */ - /* - // Material texture map - typedef struct MaterialMap { - Texture2D texture; // Material map texture - Color color; // Material map color - float value; // Material map value - } MaterialMap; - - // Material type (generic) - typedef struct Material { - Shader shader; // Material shader - MaterialMap maps[MAX_MATERIAL_MAPS]; // Material maps - float *params; // Material generic parameters (if required) - } Material; - */ + 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); -- cgit v1.2.3 From f1cbdd6b3af5dc51cef306cbbc4619c7b6ed548a Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 1 Apr 2019 18:22:56 +0200 Subject: Corrected some issues - Support compiling for OpenGL 1.1 - Free meshes/materials memory after usage... --- src/models.c | 3 +++ src/rlgl.h | 19 ++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index 9fb08d82..7c266843 100644 --- a/src/models.c +++ b/src/models.c @@ -682,6 +682,9 @@ 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"); diff --git a/src/rlgl.h b/src/rlgl.h index 49ab1de5..9e9394db 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -2036,6 +2036,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 +2083,7 @@ unsigned int rlLoadTextureDepth(int width, int height, int bits, bool useRenderB glBindRenderbuffer(GL_RENDERBUFFER, 0); } +#endif return id; } @@ -2092,7 +2095,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 +2141,7 @@ unsigned int rlLoadTextureCubemap(void *data, int size, int format) #endif glBindTexture(GL_TEXTURE_CUBE_MAP, 0); +#endif return cubemapId; } @@ -2221,9 +2226,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 +2279,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 +2290,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 +2319,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 -- cgit v1.2.3 From d89d24c5e8930c18a93a6403e26914a9e2b23b84 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 4 Apr 2019 13:33:54 +0200 Subject: BIG UPDATE: Support model animations! --- src/config.h | 6 +- src/models.c | 382 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ src/raylib.h | 45 +++++-- 3 files changed, 383 insertions(+), 50 deletions(-) (limited to 'src/models.c') 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/models.c b/src/models.c index 7c266843..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,6 +624,9 @@ 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) { @@ -638,7 +636,12 @@ Model LoadModel(const char *fileName) 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); @@ -686,30 +689,12 @@ void UnloadModel(Model model) 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) @@ -2386,7 +2371,6 @@ void MeshBinormals(Mesh *mesh) static Model LoadOBJ(const char *fileName) { Model model = { 0 }; - model.transform = MatrixIdentity(); tinyobj_attrib_t attrib; tinyobj_shape_t *meshes = NULL; @@ -2486,8 +2470,7 @@ static Model LoadOBJ(const char *fileName) } model.meshes[m] = mesh; // Assign mesh data to model - rlLoadMesh(&model.meshes[m], false); // Upload vertex data to GPU (static mesh) - + // Assign mesh material for current mesh model.meshMaterial[m] = attrib.material_ids[m]; } @@ -2555,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; } @@ -2593,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 085f36f6..9607191b 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) @@ -1228,17 +1254,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 -- cgit v1.2.3 From a103086443b3d3a3a94ec52ef19ec9be68a0069c Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 4 Apr 2019 13:50:52 +0200 Subject: Removed trail spaces --- src/core.c | 32 ++++++++++++------------ src/models.c | 78 +++++++++++++++++++++++++++++----------------------------- src/raudio.c | 4 +-- src/raylib.h | 14 +++++------ src/rlgl.h | 28 ++++++++++----------- src/textures.c | 18 +++++++------- 6 files changed, 87 insertions(+), 87 deletions(-) (limited to 'src/models.c') diff --git a/src/core.c b/src/core.c index 7f2f7f1c..acc87292 100644 --- a/src/core.c +++ b/src/core.c @@ -760,7 +760,7 @@ bool IsWindowResized(void) return windowResized; #else return false; -#endif +#endif } // Check if window is currently hidden @@ -1684,14 +1684,14 @@ const char *GetFileName(const char *filePath) const char *GetFileNameWithoutExt(const char *filePath) { #define MAX_FILENAMEWITHOUTEXT_LENGTH 64 - + static char fileName[MAX_FILENAMEWITHOUTEXT_LENGTH]; memset(fileName, 0, MAX_FILENAMEWITHOUTEXT_LENGTH); - + strcpy(fileName, GetFileName(filePath)); // Get filename with extension - + int len = strlen(fileName); - + for (int i = 0; (i < len) && (i < MAX_FILENAMEWITHOUTEXT_LENGTH); i++) { if (fileName[i] == '.') @@ -3154,7 +3154,7 @@ static void PollInputEvents(void) gamepadAxisCount = axisCount; } } - + windowResized = false; #if defined(SUPPORT_EVENTS_WAITING) @@ -3433,7 +3433,7 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height) currentHeight = height; // NOTE: Postprocessing texture is not scaled to new size - + windowResized = true; } @@ -4279,7 +4279,7 @@ static void *EventThread(void *arg) { // Scancode to keycode mapping for US keyboards // TODO: Proabobly replace this with a keymap from the X11 to get the correct regional map for the keyboard (Currently non US keyboards will have the wrong mapping for some keys) - static const int keymap_US[] = + static const int keymap_US[] = {0,256,49,50,51,52,53,54,55,56,57,48,45,61,259,258,81,87,69,82,84, 89,85,73,79,80,91,93,257,341,65,83,68,70,71,72,74,75,76,59,39,96, 340,92,90,88,67,86,66,78,77,44,46,47,344,332,342,32,280,290,291, @@ -4298,7 +4298,7 @@ static void *EventThread(void *arg) struct input_event event; InputEventWorker *worker = (InputEventWorker *)arg; - + int touchAction = -1; bool gestureUpdate = false; int keycode; @@ -4400,7 +4400,7 @@ static void *EventThread(void *arg) if ((event.code == BTN_TOUCH) || (event.code == BTN_LEFT)) { currentMouseStateEvdev[MOUSE_LEFT_BUTTON] = event.value; - + #if defined(SUPPORT_GESTURES_SYSTEM) if (event.value > 0) touchAction = TOUCH_DOWN; else touchAction = TOUCH_UP; @@ -4415,9 +4415,9 @@ static void *EventThread(void *arg) // Keyboard button parsing if((event.code >= 1) && (event.code <= 255)) //Keyboard keys appear for codes 1 to 255 { - keycode = keymap_US[event.code & 0xFF]; // The code we get is a scancode so we look up the apropriate keycode + keycode = keymap_US[event.code & 0xFF]; // The code we get is a scancode so we look up the apropriate keycode // Make sure we got a valid keycode - if((keycode > 0) && (keycode < sizeof(currentKeyState))) + if((keycode > 0) && (keycode < sizeof(currentKeyState))) { // Store the key information for raylib to later use currentKeyStateEvdev[keycode] = event.value; @@ -4449,22 +4449,22 @@ static void *EventThread(void *arg) gestureEvent.pointCount = 0; gestureEvent.touchAction = touchAction; - + if (touchPosition[0].x >= 0) gestureEvent.pointCount++; if (touchPosition[1].x >= 0) gestureEvent.pointCount++; if (touchPosition[2].x >= 0) gestureEvent.pointCount++; if (touchPosition[3].x >= 0) gestureEvent.pointCount++; - + gestureEvent.pointerId[0] = 0; gestureEvent.pointerId[1] = 1; gestureEvent.pointerId[2] = 2; gestureEvent.pointerId[3] = 3; - + gestureEvent.position[0] = touchPosition[0]; gestureEvent.position[1] = touchPosition[1]; gestureEvent.position[2] = touchPosition[2]; gestureEvent.position[3] = touchPosition[3]; - + ProcessGestureEvent(gestureEvent); #endif } diff --git a/src/models.c b/src/models.c index 632aca2b..239ab5d8 100644 --- a/src/models.c +++ b/src/models.c @@ -624,19 +624,19 @@ 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) + if (model.meshCount == 0) { TraceLog(LOG_WARNING, "[%s] No meshes can be loaded, default to cube mesh", fileName); - + model.meshCount = 1; model.meshes = (Mesh *)calloc(model.meshCount, sizeof(Mesh)); model.meshes[0] = GenMeshCube(1.0f, 1.0f, 1.0f); } - else + else { // Upload vertex data to GPU (static mesh) for (int i = 0; i < model.meshCount; i++) rlLoadMesh(&model.meshes[i], false); @@ -645,11 +645,11 @@ Model LoadModel(const char *fileName) if (model.materialCount == 0) { TraceLog(LOG_WARNING, "[%s] No materials can be loaded, default to white material", fileName); - + model.materialCount = 1; model.materials = (Material *)calloc(model.materialCount, sizeof(Material)); model.materials[0] = LoadMaterialDefault(); - + model.meshMaterial = (int *)calloc(model.meshCount, sizeof(int)); } @@ -665,15 +665,15 @@ Model LoadModelFromMesh(Mesh mesh) Model model = { 0 }; model.transform = MatrixIdentity(); - + model.meshCount = 1; model.meshes = (Mesh *)malloc(model.meshCount*sizeof(Mesh)); model.meshes[0] = mesh; - + model.materialCount = 1; model.materials = (Material *)malloc(model.materialCount*sizeof(Material)); model.materials[0] = LoadMaterialDefault(); - + model.meshMaterial = (int *)malloc(model.meshCount*sizeof(int)); model.meshMaterial[0] = 0; // First material index @@ -685,11 +685,11 @@ 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); - + // Unload animation data free(model.bones); free(model.bindPose); @@ -1817,11 +1817,11 @@ Material LoadMaterial(const char *fileName) { tinyobj_material_t *materials; unsigned int materialCount = 0; - + int result = tinyobj_parse_mtl_file(&materials, &materialCount, fileName); - + // TODO: Process materials to return - + tinyobj_materials_free(materials, materialCount); } #else @@ -1886,7 +1886,7 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota // Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform) model.transform = MatrixMultiply(model.transform, matTransform); - for (int i = 0; i < model.meshCount; i++) + for (int i = 0; i < model.meshCount; i++) { model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color = tint; rlDrawMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform); @@ -2246,7 +2246,7 @@ 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) @@ -2402,20 +2402,20 @@ static Model LoadOBJ(const char *fileName) { 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); - + // 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)); - - /* + + /* // Multiple meshes data reference // NOTE: They are provided as a faces offset typedef struct { @@ -2424,7 +2424,7 @@ static Model LoadOBJ(const char *fileName) unsigned int length; } tinyobj_shape_t; */ - + // Init model meshes for (int m = 0; m < 1; m++) { @@ -2435,25 +2435,25 @@ static Model LoadOBJ(const char *fileName) 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]; @@ -2462,7 +2462,7 @@ static Model LoadOBJ(const char *fileName) 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; @@ -2481,7 +2481,7 @@ static Model LoadOBJ(const char *fileName) // Init material to default // NOTE: Uses default shader, only MAP_DIFFUSE supported model.materials[m] = LoadMaterialDefault(); - + /* typedef struct { char *name; @@ -2508,19 +2508,19 @@ static Model LoadOBJ(const char *fileName) 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 @@ -2579,7 +2579,7 @@ static Model LoadIQM(const char *fileName) } IQMTriangle; // NOTE: Adjacency unused by default - typedef struct IQMAdjacency { + typedef struct IQMAdjacency { unsigned int triangle[3]; } IQMAdjacency; @@ -2677,7 +2677,7 @@ static Model LoadIQM(const char *fileName) 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++) @@ -2685,17 +2685,17 @@ static Model LoadIQM(const char *fileName) 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); diff --git a/src/raudio.c b/src/raudio.c index 1c153009..d360b2d3 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -525,7 +525,7 @@ void InitAudioDevice(void) TraceLog(LOG_INFO, "Audio channels: %d -> %d", device.playback.channels, device.playback.internalChannels); TraceLog(LOG_INFO, "Audio sample rate: %d -> %d", device.sampleRate, device.playback.internalSampleRate); TraceLog(LOG_INFO, "Audio buffer size: %d", device.playback.internalBufferSizeInFrames); - + isAudioInitialized = MA_TRUE; } @@ -587,7 +587,7 @@ AudioBuffer *CreateAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 s dspConfig.pUserData = audioBuffer; dspConfig.allowDynamicSampleRate = MA_TRUE; // <-- Required for pitch shifting. ma_result result = ma_pcm_converter_init(&dspConfig, &audioBuffer->dsp); - + if (result != MA_SUCCESS) { TraceLog(LOG_ERROR, "CreateAudioBuffer() : Failed to create data conversion pipeline"); diff --git a/src/raylib.h b/src/raylib.h index 93965038..c365fa47 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -339,7 +339,7 @@ typedef struct Material { // Transformation properties typedef struct Transform { - Vector3 translation; // Translation + Vector3 translation; // Translation Quaternion rotation; // Rotation Vector3 scale; // Scale } Transform; @@ -353,14 +353,14 @@ typedef struct BoneInfo { // Model type typedef struct Model { Matrix transform; // Local transform matrix - + int meshCount; // Number of meshes Mesh *meshes; // Meshes array 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) @@ -371,7 +371,7 @@ typedef struct Model { 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; @@ -1082,8 +1082,8 @@ RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Col RLAPI void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // Draw a gradient-filled rectangle with custom vertex colors RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline RLAPI void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color); // Draw rectangle outline with extended parameters -RLAPI void DrawRoundedRect(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle with rounded edges -RLAPI void DrawRoundedRectLines(Rectangle rec, float roundness, int segments, int lineThick, Color color); // Draw rounded rectangle outline +RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle with rounded edges +RLAPI void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, int lineThick, Color color); // Draw rectangle with rounded edges outline RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version) @@ -1201,7 +1201,7 @@ RLAPI void DrawFPS(int posX, int posY); RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters RLAPI void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint); // Draw text using font inside rectangle limits -RLAPI void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, +RLAPI void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectText, Color selectBack); // Draw text using font inside rectangle limits with support for text selection // Text misc. functions diff --git a/src/rlgl.h b/src/rlgl.h index 8cc4c590..3f305462 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -1130,22 +1130,22 @@ void rlBegin(int mode) // Make sure current draws[i].vertexCount is aligned a multiple of 4, // that way, following QUADS drawing will keep aligned with index processing // It implies adding some extra alignment vertex at the end of the draw, - // those vertex are not processed but they are considered as an additional offset + // those vertex are not processed but they are considered as an additional offset // for the next set of vertex to be drawn if (draws[drawsCounter - 1].mode == RL_LINES) draws[drawsCounter - 1].vertexAlignment = ((draws[drawsCounter - 1].vertexCount < 4)? draws[drawsCounter - 1].vertexCount : draws[drawsCounter - 1].vertexCount%4); else if (draws[drawsCounter - 1].mode == RL_TRIANGLES) draws[drawsCounter - 1].vertexAlignment = ((draws[drawsCounter - 1].vertexCount < 4)? 1 : (4 - (draws[drawsCounter - 1].vertexCount%4))); - + if (rlCheckBufferLimit(draws[drawsCounter - 1].vertexAlignment)) rlglDraw(); else { vertexData[currentBuffer].vCounter += draws[drawsCounter - 1].vertexAlignment; vertexData[currentBuffer].cCounter += draws[drawsCounter - 1].vertexAlignment; vertexData[currentBuffer].tcCounter += draws[drawsCounter - 1].vertexAlignment; - + drawsCounter++; } } - + if (drawsCounter >= MAX_DRAWCALL_REGISTERED) rlglDraw(); draws[drawsCounter - 1].mode = mode; @@ -1301,22 +1301,22 @@ void rlEnableTexture(unsigned int id) // Make sure current draws[i].vertexCount is aligned a multiple of 4, // that way, following QUADS drawing will keep aligned with index processing // It implies adding some extra alignment vertex at the end of the draw, - // those vertex are not processed but they are considered as an additional offset + // those vertex are not processed but they are considered as an additional offset // for the next set of vertex to be drawn if (draws[drawsCounter - 1].mode == RL_LINES) draws[drawsCounter - 1].vertexAlignment = ((draws[drawsCounter - 1].vertexCount < 4)? draws[drawsCounter - 1].vertexCount : draws[drawsCounter - 1].vertexCount%4); else if (draws[drawsCounter - 1].mode == RL_TRIANGLES) draws[drawsCounter - 1].vertexAlignment = ((draws[drawsCounter - 1].vertexCount < 4)? 1 : (4 - (draws[drawsCounter - 1].vertexCount%4))); - + if (rlCheckBufferLimit(draws[drawsCounter - 1].vertexAlignment)) rlglDraw(); else { vertexData[currentBuffer].vCounter += draws[drawsCounter - 1].vertexAlignment; vertexData[currentBuffer].cCounter += draws[drawsCounter - 1].vertexAlignment; vertexData[currentBuffer].tcCounter += draws[drawsCounter - 1].vertexAlignment; - + drawsCounter++; } } - + if (drawsCounter >= MAX_DRAWCALL_REGISTERED) rlglDraw(); draws[drawsCounter - 1].textureId = id; @@ -2044,7 +2044,7 @@ 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; @@ -2103,7 +2103,7 @@ 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); @@ -2305,7 +2305,7 @@ void rlRenderTextureAttach(RenderTexture2D target, unsigned int id, int attachTy bool rlRenderTextureComplete(RenderTexture target) { bool result = false; - + #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) glBindFramebuffer(GL_FRAMEBUFFER, target.id); @@ -4196,7 +4196,7 @@ static void DrawBuffersDefault(void) glUniformMatrix4fv(currentShader.locs[LOC_MATRIX_MVP], 1, false, MatrixToFloat(matMVP)); glUniform4f(currentShader.locs[LOC_COLOR_DIFFUSE], 1.0f, 1.0f, 1.0f, 1.0f); glUniform1i(currentShader.locs[LOC_MAP_DIFFUSE], 0); // Provided value refers to the texture unit (active) - + // TODO: Support additional texture units on custom shader //if (currentShader->locs[LOC_MAP_SPECULAR] > 0) glUniform1i(currentShader.locs[LOC_MAP_SPECULAR], 1); //if (currentShader->locs[LOC_MAP_NORMAL] > 0) glUniform1i(currentShader.locs[LOC_MAP_NORMAL], 2); @@ -4231,7 +4231,7 @@ static void DrawBuffersDefault(void) for (int i = 0; i < drawsCounter; i++) { glBindTexture(GL_TEXTURE_2D, draws[i].textureId); - + // TODO: Find some way to bind additional textures --> Use global texture IDs? Register them on draw[i]? //if (currentShader->locs[LOC_MAP_SPECULAR] > 0) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureUnit1_id); } //if (currentShader->locs[LOC_MAP_SPECULAR] > 0) { glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, textureUnit2_id); } @@ -4248,7 +4248,7 @@ static void DrawBuffersDefault(void) glDrawElements(GL_TRIANGLES, draws[i].vertexCount/4*6, GL_UNSIGNED_SHORT, (GLvoid *)(sizeof(GLushort)*vertexOffset/4*6)); #endif } - + vertexOffset += (draws[i].vertexCount + draws[i].vertexAlignment); } diff --git a/src/textures.c b/src/textures.c index 38995f11..cd0bd208 100644 --- a/src/textures.c +++ b/src/textures.c @@ -181,7 +181,7 @@ static Image LoadASTC(const char *fileName); // Load ASTC file Image LoadImage(const char *fileName) { Image image = { 0 }; - + #if defined(SUPPORT_FILEFORMAT_PNG) || \ defined(SUPPORT_FILEFORMAT_BMP) || \ defined(SUPPORT_FILEFORMAT_TGA) || \ @@ -744,7 +744,7 @@ Image GetTextureData(Texture2D texture) RLAPI Image GetScreenData(void) { Image image = { 0 }; - + image.width = GetScreenWidth(); image.height = GetScreenHeight(); image.mipmaps = 1; @@ -1411,13 +1411,13 @@ void ImageResizeNN(Image *image,int newWidth,int newHeight) void ImageResizeCanvas(Image *image, int newWidth,int newHeight, int offsetX, int offsetY, Color color) { // TODO: Review different scaling situations - + if ((newWidth != image->width) || (newHeight != image->height)) { if ((newWidth > image->width) && (newHeight > image->height)) { Image imTemp = GenImageColor(newWidth, newHeight, color); - + Rectangle srcRec = { 0.0f, 0.0f, (float)image->width, (float)image->height }; Rectangle dstRec = { (float)offsetX, (float)offsetY, (float)srcRec.width, (float)srcRec.height }; @@ -1434,23 +1434,23 @@ void ImageResizeCanvas(Image *image, int newWidth,int newHeight, int offsetX, in else // One side is bigger and the other is smaller { Image imTemp = GenImageColor(newWidth, newHeight, color); - + Rectangle srcRec = { 0.0f, 0.0f, (float)image->width, (float)image->height }; Rectangle dstRec = { (float)offsetX, (float)offsetY, (float)newWidth, (float)newHeight }; - + if (newWidth < image->width) { srcRec.x = offsetX; srcRec.width = newWidth; - + dstRec.x = 0.0f; } - + if (newHeight < image->height) { srcRec.y = offsetY; srcRec.height = newHeight; - + dstRec.y = 0.0f; } -- cgit v1.2.3 From 92733d6695e0cdab3b42972f2cd6ed48d98ec689 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 5 Apr 2019 13:15:56 +0200 Subject: BIG UPDATE: New models functions for animations! Multiple functions added and some reviewed to adapt to the new multi-mesh, multi-material and animated models. --- examples/models/models_animation.c | 101 +++ examples/models/resources/guy/guy.blend | Bin 0 -> 665304 bytes examples/models/resources/guy/guy.iqm | Bin 0 -> 39408 bytes examples/models/resources/guy/guyanim.iqm | Bin 0 -> 18244 bytes examples/models/resources/guy/guytex.png | Bin 0 -> 302388 bytes examples/others/iqm_loader/models_iqm_animation.c | 98 --- examples/others/iqm_loader/resources/guy.blend | Bin 665304 -> 0 bytes examples/others/iqm_loader/resources/guy.iqm | Bin 39408 -> 0 bytes examples/others/iqm_loader/resources/guyanim.iqm | Bin 18244 -> 0 bytes examples/others/iqm_loader/resources/guytex.png | Bin 302388 -> 0 bytes examples/others/iqm_loader/riqm.h | 739 +--------------------- src/models.c | 652 ++++++++++++++----- src/raylib.h | 33 +- 13 files changed, 617 insertions(+), 1006 deletions(-) create mode 100644 examples/models/models_animation.c create mode 100644 examples/models/resources/guy/guy.blend create mode 100644 examples/models/resources/guy/guy.iqm create mode 100644 examples/models/resources/guy/guyanim.iqm create mode 100644 examples/models/resources/guy/guytex.png delete mode 100644 examples/others/iqm_loader/models_iqm_animation.c delete mode 100644 examples/others/iqm_loader/resources/guy.blend delete mode 100644 examples/others/iqm_loader/resources/guy.iqm delete mode 100644 examples/others/iqm_loader/resources/guyanim.iqm delete mode 100644 examples/others/iqm_loader/resources/guytex.png (limited to 'src/models.c') diff --git a/examples/models/models_animation.c b/examples/models/models_animation.c new file mode 100644 index 00000000..a75241b3 --- /dev/null +++ b/examples/models/models_animation.c @@ -0,0 +1,101 @@ +/******************************************************************************************* +* +* raylib [models] example - Load 3d model with animations and play them +* +* This example has been created using raylib 2.5 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2019 Ramon Santamaria (@raysan5) and @culacant +* +********************************************************************************************/ + +#include "raylib.h" + +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + int screenWidth = 800; + int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - model animation"); + + // Define the camera to look into our 3d world + Camera camera = { 0 }; + camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.type = CAMERA_PERSPECTIVE; // Camera mode type + + + Model model = LoadModel("resources/guy/guy.iqm"); // Load the animated model mesh and basic data + Texture2D texture = LoadTexture("resources/guy/guytex.png"); // Load model texture and set material + SetMaterialTexture(&model.materials[0], MAP_DIFFUSE, texture); // Set model material map texture + + Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position + + // Load animation data + int animsCount = 0; + ModelAnimation *anims = LoadModelAnimations("resources/guy/guyanim.iqm", &animsCount); + int animFrameCounter = 0; + + SetCameraMode(camera, CAMERA_FREE); // Set free camera mode + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera); + + // Play animation when spacebar is held down + if (IsKeyDown(KEY_SPACE)) + { + animFrameCounter++; + UpdateModelAnimation(model, anims[0], animFrameCounter); + if (animFrameCounter >= anims[0].frameCount) animFrameCounter = 0; + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + DrawModelEx(model, position, (Vector3){ 1.0f, 0.0f, 0.0f }, -90.0f, (Vector3){ 1.0f, 1.0f, 1.0f }, WHITE); + + for (int i = 0; i < model.boneCount; i++) + { + DrawCube(anims[0].framePoses[animFrameCounter][i].translation, 0.2f, 0.2f, 0.2f, RED); + } + + DrawGrid(10, 1.0f); // Draw a grid + + EndMode3D(); + + DrawText("PRESS SPACE to PLAY MODEL ANIMATION", 10, 10, 20, MAROON); + DrawText("(c) Guy IQM 3D model by @culacant", screenWidth - 200, screenHeight - 20, 10, GRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + // Unload model animations data + for (int i = 0; i < animsCount; i++) UnloadModelAnimation(anims[i]); + + UnloadModel(model); // Unload model + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/models/resources/guy/guy.blend b/examples/models/resources/guy/guy.blend new file mode 100644 index 00000000..3880467d Binary files /dev/null and b/examples/models/resources/guy/guy.blend differ diff --git a/examples/models/resources/guy/guy.iqm b/examples/models/resources/guy/guy.iqm new file mode 100644 index 00000000..36bed5e0 Binary files /dev/null and b/examples/models/resources/guy/guy.iqm differ diff --git a/examples/models/resources/guy/guyanim.iqm b/examples/models/resources/guy/guyanim.iqm new file mode 100644 index 00000000..824a68a3 Binary files /dev/null and b/examples/models/resources/guy/guyanim.iqm differ diff --git a/examples/models/resources/guy/guytex.png b/examples/models/resources/guy/guytex.png new file mode 100644 index 00000000..7f813552 Binary files /dev/null and b/examples/models/resources/guy/guytex.png differ diff --git a/examples/others/iqm_loader/models_iqm_animation.c b/examples/others/iqm_loader/models_iqm_animation.c deleted file mode 100644 index 18dd8577..00000000 --- a/examples/others/iqm_loader/models_iqm_animation.c +++ /dev/null @@ -1,98 +0,0 @@ -/******************************************************************************************* -* -* raylib [models] example - Load IQM 3d model with animations and play them -* -* This example has been created using raylib 2.0 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) -* -* Copyright (c) 2018 @culacant and @raysan5 -* -********************************************************************************************/ - -#include "raylib.h" - -#define RIQM_IMPLEMENTATION -#include "riqm.h" - -int main() -{ - // Initialization - //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; - - InitWindow(screenWidth, screenHeight, "raylib [models] example - iqm animation"); - - // Define the camera to look into our 3d world - Camera camera = { 0 }; - camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Camera position - camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point - camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) - camera.fovy = 45.0f; // Camera field-of-view Y - camera.type = CAMERA_PERSPECTIVE; // Camera mode type - - // Load the animated model mesh and basic data - AnimatedModel model = LoadAnimatedModel("resources/guy.iqm"); - - // Load model texture and set material - // NOTE: There is only 1 mesh and 1 material (both at index 0), thats what the 2 0's are - model = AnimatedModelAddTexture(model, "resources/guytex.png"); // REPLACE! - model = SetMeshMaterial(model, 0, 0); // REPLACE! - - // Load animation data - Animation anim = LoadAnimationFromIQM("resources/guyanim.iqm"); - - int animFrameCounter = 0; - - SetCameraMode(camera, CAMERA_FREE); // Set free camera mode - - SetTargetFPS(60); // Set our game to run at 60 frames-per-second - //-------------------------------------------------------------------------------------- - - // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key - { - // Update - //---------------------------------------------------------------------------------- - UpdateCamera(&camera); - - // Play animation when spacebar is held down - if (IsKeyDown(KEY_SPACE)) - { - animFrameCounter++; - AnimateModel(model, anim, animFrameCounter); // Animate the model with animation data and frame - } - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - BeginMode3D(camera); - - DrawAnimatedModel(model, Vector3Zero(), 1.0f, WHITE); // Draw animated model - - DrawGrid(10, 1.0f); // Draw a grid - - EndMode3D(); - - DrawText("PRESS SPACE to PLAY IQM MODEL ANIMATION", 10, 10, 20, MAROON); - - DrawText("(c) Guy IQM 3D model by @culacant", screenWidth - 200, screenHeight - 20, 10, GRAY); - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - UnloadAnimation(anim); // Unload animation data - UnloadAnimatedModel(model); // Unload animated model - - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - return 0; -} diff --git a/examples/others/iqm_loader/resources/guy.blend b/examples/others/iqm_loader/resources/guy.blend deleted file mode 100644 index 3880467d..00000000 Binary files a/examples/others/iqm_loader/resources/guy.blend and /dev/null differ diff --git a/examples/others/iqm_loader/resources/guy.iqm b/examples/others/iqm_loader/resources/guy.iqm deleted file mode 100644 index 36bed5e0..00000000 Binary files a/examples/others/iqm_loader/resources/guy.iqm and /dev/null differ diff --git a/examples/others/iqm_loader/resources/guyanim.iqm b/examples/others/iqm_loader/resources/guyanim.iqm deleted file mode 100644 index 824a68a3..00000000 Binary files a/examples/others/iqm_loader/resources/guyanim.iqm and /dev/null differ diff --git a/examples/others/iqm_loader/resources/guytex.png b/examples/others/iqm_loader/resources/guytex.png deleted file mode 100644 index 7f813552..00000000 Binary files a/examples/others/iqm_loader/resources/guytex.png and /dev/null differ diff --git a/examples/others/iqm_loader/riqm.h b/examples/others/iqm_loader/riqm.h index 694e3a95..41ef8a14 100644 --- a/examples/others/iqm_loader/riqm.h +++ b/examples/others/iqm_loader/riqm.h @@ -49,67 +49,13 @@ // Types and Structures Definition //---------------------------------------------------------------------------------- -#define JOINT_NAME_LENGTH 32 // Joint name string length -#define MESH_NAME_LENGTH 32 // Mesh name string length - -typedef struct Joint { - char name[JOINT_NAME_LENGTH]; - int parent; -} Joint; - -typedef struct Pose { - Vector3 translation; - Quaternion rotation; - Vector3 scale; -} Pose; - -typedef struct Animation { - int jointCount; // Number of joints (bones) - Joint *joints; // Joints array - // NOTE: Joints in anims do not have names - - int frameCount; // Number of animation frames - float framerate; // Frame change speed - - Pose **framepose; // Poses array by frame (and one pose by joint) -} Animation; - -// Animated Model type -typedef struct AnimatedModel { - Matrix transform; // Local transform matrix - - int meshCount; // Number of meshes - Mesh *meshes; // Meshes array - - int materialCount; // Number of materials - Material *materials; // Materials array - - int *meshMaterialId; // Mesh materials ids - - // Animation required data - int jointCount; // Number of joints (and keyposes) - Joint *joints; // Mesh joints (bones) - Pose *basepose; // Mesh base-poses by joint -} AnimatedModel; +#define BONE_NAME_LENGTH 32 // BoneInfo name string length +#define MESH_NAME_LENGTH 32 // Mesh name string length //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- -// Loading/Unloading functions -RIQMDEF AnimatedModel LoadAnimatedModel(const char *filename); -RIQMDEF void UnloadAnimatedModel(AnimatedModel model); -RIQMDEF Animation LoadAnimation(const char *filename); -RIQMDEF void UnloadAnimation(Animation anim); - -RIQMDEF AnimatedModel AnimatedModelAddTexture(AnimatedModel model, const char *filename); // GENERIC! -RIQMDEF AnimatedModel SetMeshMaterial(AnimatedModel model, int meshid, int textureid); // GENERIC! - -// Usage functionality -RIQMDEF bool CheckSkeletonsMatch(AnimatedModel model, Animation anim); -RIQMDEF void AnimateModel(AnimatedModel model, Animation anim, int frame); -RIQMDEF void DrawAnimatedModel(AnimatedModel model, Vector3 position, float scale, Color tint); -RIQMDEF void DrawAnimatedModelEx(AnimatedModel model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); #endif // RIQM_H @@ -133,90 +79,6 @@ RIQMDEF void DrawAnimatedModelEx(AnimatedModel model, Vector3 position, Vector3 //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number -#define IQM_VERSION 2 // only IQM version 2 supported -#define ANIMJOINTNAME "ANIMJOINT" // default joint name (used in Animation) - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -// 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; - -typedef struct IQMAdjacency { // adjacency unused by default - 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; - -typedef struct IQMBounds { // bounds unused by default - float bbmin[3], bbmax[3]; - float xyradius, radius; -} IQMBounds; - - -typedef enum { - IQM_POSITION = 0, - IQM_TEXCOORD = 1, - IQM_NORMAL = 2, - IQM_TANGENT = 3, // tangents unused by default - IQM_BLENDINDEXES = 4, - IQM_BLENDWEIGHTS = 5, - IQM_COLOR = 6, // vertex colors unused by default - IQM_CUSTOM = 0x10 // custom vertex values unused by default -} IQMVertexType; //---------------------------------------------------------------------------------- // Global Variables Definition @@ -225,609 +87,12 @@ typedef enum { //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- -static AnimatedModel LoadIQM(const char *filename); #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif -// Load .iqm file and initialize animated model -AnimatedModel LoadAnimatedModel(const char *filename) -{ - AnimatedModel out = LoadIQM(filename); - - for (int i = 0; i < out.meshCount; i++) rlLoadMesh(&out.meshes[i], false); - - out.transform = MatrixIdentity(); - out.meshMaterialId = malloc(sizeof(int)*out.meshCount); - out.materials = NULL; - out.materialCount = 0; - - for (int i = 0; i < out.meshCount; i++) out.meshMaterialId[i] = -1; - - return out; -} - -// Add a texture to an animated model -AnimatedModel AnimatedModelAddTexture(AnimatedModel model, const char *filename) -{ - Texture2D texture = LoadTexture(filename); - - model.materials = realloc(model.materials, sizeof(Material)*(model.materialCount + 1)); - model.materials[model.materialCount] = LoadMaterialDefault(); - model.materials[model.materialCount].maps[MAP_DIFFUSE].texture = texture; - model.materialCount++; - - return model; -} - -// Set the material for a meshes -AnimatedModel SetMeshMaterial(AnimatedModel model, int meshid, int textureid) -{ - if (meshid > model.meshCount) - { - TraceLog(LOG_WARNING, "MeshId greater than meshCount\n"); - return model; - } - - if (textureid > model.materialCount) - { - TraceLog(LOG_WARNING,"textureid greater than materialCount\n"); - return model; - } - - model.meshMaterialId[meshid] = textureid; - - return model; -} - -// Load animations from a .iqm file -Animation LoadAnimationFromIQM(const char *filename) -{ - Animation animation = { 0 }; - - FILE *iqmFile; - IQMHeader iqm; - - iqmFile = fopen(filename,"rb"); - - if (!iqmFile) - { - TraceLog(LOG_ERROR, "[%s] Unable to open file", filename); - return animation; - } - - // header - fread(&iqm, sizeof(IQMHeader), 1, iqmFile); - - if (strncmp(iqm.magic, IQM_MAGIC, sizeof(IQM_MAGIC))) - { - TraceLog(LOG_ERROR, "Magic Number \"%s\"does not match.", iqm.magic); - fclose(iqmFile); - return animation; - } - - if (iqm.version != IQM_VERSION) - { - TraceLog(LOG_ERROR, "IQM version %i is incorrect.", iqm.version); - fclose(iqmFile); - return animation; - } - - // header - if (iqm.num_anims > 1) TraceLog(LOG_WARNING, "More than 1 animation in file, only the first one will get loaded"); - - // joints - IQMPose *poses; - poses = malloc(sizeof(IQMPose)*iqm.num_poses); - fseek(iqmFile, iqm.ofs_poses, SEEK_SET); - fread(poses, sizeof(IQMPose)*iqm.num_poses, 1, iqmFile); - - animation.jointCount = iqm.num_poses; - animation.joints = malloc(sizeof(Joint)*iqm.num_poses); - - for (int j = 0; j < iqm.num_poses; j++) - { - strcpy(animation.joints[j].name, ANIMJOINTNAME); - animation.joints[j].parent = poses[j].parent; - } - - // animations - IQMAnim anim = {0}; - fseek(iqmFile, iqm.ofs_anims, SEEK_SET); - fread(&anim, sizeof(IQMAnim), 1, iqmFile); - - animation.frameCount = anim.num_frames; - animation.framerate = anim.framerate; - - // frameposes - unsigned short *framedata = malloc(sizeof(unsigned short)*iqm.num_frames*iqm.num_framechannels); - fseek(iqmFile, iqm.ofs_frames, SEEK_SET); - fread(framedata, sizeof(unsigned short)*iqm.num_frames*iqm.num_framechannels, 1, iqmFile); - - animation.framepose = malloc(sizeof(Pose*)*anim.num_frames); - for (int j = 0; j < anim.num_frames; j++) animation.framepose[j] = malloc(sizeof(Pose)*iqm.num_poses); - - int dcounter = anim.first_frame*iqm.num_framechannels; - - for (int frame = 0; frame < anim.num_frames; frame++) - { - for (int i = 0; i < iqm.num_poses; i++) - { - animation.framepose[frame][i].translation.x = poses[i].channeloffset[0]; - - if (poses[i].mask & 0x01) - { - animation.framepose[frame][i].translation.x += framedata[dcounter]*poses[i].channelscale[0]; - dcounter++; - } - - animation.framepose[frame][i].translation.y = poses[i].channeloffset[1]; - - if (poses[i].mask & 0x02) - { - animation.framepose[frame][i].translation.y += framedata[dcounter]*poses[i].channelscale[1]; - dcounter++; - } - - animation.framepose[frame][i].translation.z = poses[i].channeloffset[2]; - - if (poses[i].mask & 0x04) - { - animation.framepose[frame][i].translation.z += framedata[dcounter]*poses[i].channelscale[2]; - dcounter++; - } - - animation.framepose[frame][i].rotation.x = poses[i].channeloffset[3]; - - if (poses[i].mask & 0x08) - { - animation.framepose[frame][i].rotation.x += framedata[dcounter]*poses[i].channelscale[3]; - dcounter++; - } - - animation.framepose[frame][i].rotation.y = poses[i].channeloffset[4]; - - if (poses[i].mask & 0x10) - { - animation.framepose[frame][i].rotation.y += framedata[dcounter]*poses[i].channelscale[4]; - dcounter++; - } - - animation.framepose[frame][i].rotation.z = poses[i].channeloffset[5]; - - if (poses[i].mask & 0x20) - { - animation.framepose[frame][i].rotation.z += framedata[dcounter]*poses[i].channelscale[5]; - dcounter++; - } - - animation.framepose[frame][i].rotation.w = poses[i].channeloffset[6]; - - if (poses[i].mask & 0x40) - { - animation.framepose[frame][i].rotation.w += framedata[dcounter]*poses[i].channelscale[6]; - dcounter++; - } - - animation.framepose[frame][i].scale.x = poses[i].channeloffset[7]; - - if (poses[i].mask & 0x80) - { - animation.framepose[frame][i].scale.x += framedata[dcounter]*poses[i].channelscale[7]; - dcounter++; - } - - animation.framepose[frame][i].scale.y = poses[i].channeloffset[8]; - - if (poses[i].mask & 0x100) - { - animation.framepose[frame][i].scale.y += framedata[dcounter]*poses[i].channelscale[8]; - dcounter++; - } - - animation.framepose[frame][i].scale.z = poses[i].channeloffset[9]; - - if (poses[i].mask & 0x200) - { - animation.framepose[frame][i].scale.z += framedata[dcounter]*poses[i].channelscale[9]; - dcounter++; - } - - animation.framepose[frame][i].rotation = QuaternionNormalize(animation.framepose[frame][i].rotation); - } - } - - // Build frameposes - for (int frame = 0; frame < anim.num_frames; frame++) - { - for (int i = 0; i < animation.jointCount; i++) - { - if (animation.joints[i].parent >= 0) - { - animation.framepose[frame][i].rotation = QuaternionMultiply(animation.framepose[frame][animation.joints[i].parent].rotation, animation.framepose[frame][i].rotation); - animation.framepose[frame][i].translation = Vector3RotateByQuaternion(animation.framepose[frame][i].translation, animation.framepose[frame][animation.joints[i].parent].rotation); - animation.framepose[frame][i].translation = Vector3Add(animation.framepose[frame][i].translation, animation.framepose[frame][animation.joints[i].parent].translation); - animation.framepose[frame][i].scale = Vector3MultiplyV(animation.framepose[frame][i].scale, animation.framepose[frame][animation.joints[i].parent].scale); - } - } - } - - free(framedata); - free(poses); - - fclose(iqmFile); - - return animation; -} - -// Unload animated model -void UnloadAnimatedModel(AnimatedModel model) -{ - free(model.materials); - free(model.meshMaterialId); - free(model.joints); - free(model.basepose); - - for (int i = 0; i < model.meshCount; i++) rlUnloadMesh(&model.meshes[i]); - - free(model.meshes); -} - -// Unload animation -void UnloadAnimation(Animation anim) -{ - free(anim.joints); - free(anim.framepose); - - for (int i = 0; i < anim.frameCount; i++) free(anim.framepose[i]); -} - -// Check if skeletons match, only parents and jointCount are checked -bool CheckSkeletonsMatch(AnimatedModel model, Animation anim) -{ - if (model.jointCount != anim.jointCount) return 0; - - for (int i = 0; i < model.jointCount; i++) - { - if (model.joints[i].parent != anim.joints[i].parent) return 0; - } - - return 1; -} - -// Calculate the animated vertex positions and normals based on an animation at a given frame -void AnimateModel(AnimatedModel model, Animation anim, int frame) -{ - if (frame >= anim.frameCount) frame = frame%anim.frameCount; - - for (int m = 0; m < model.meshCount; m++) - { - Vector3 outv = {0}; - Vector3 outn = {0}; - - Vector3 baset = {0}; - Quaternion baser = {0}; - Vector3 bases = {0}; - - Vector3 outt = {0}; - Quaternion outr = {0}; - Vector3 outs = {0}; - - int vcounter = 0; - int wcounter = 0; - int weightId = 0; - - for (int i = 0; i < model.meshes[m].vertexCount; i++) - { - weightId = model.meshes[m].weightId[wcounter]; - baset = model.basepose[weightId].translation; - baser = model.basepose[weightId].rotation; - bases = model.basepose[weightId].scale; - outt = anim.framepose[frame][weightId].translation; - outr = anim.framepose[frame][weightId].rotation; - outs = anim.framepose[frame][weightId].scale; - - // vertices - // NOTE: We use meshes.baseVertices (default position) to calculate meshes.vertices (animated position) - outv = (Vector3){ model.meshes[m].baseVertices[vcounter], model.meshes[m].baseVertices[vcounter + 1], model.meshes[m].baseVertices[vcounter + 2] }; - outv = Vector3MultiplyV(outv, outs); - outv = Vector3Subtract(outv, baset); - outv = Vector3RotateByQuaternion(outv, QuaternionMultiply(outr, QuaternionInvert(baser))); - outv = Vector3Add(outv, outt); - model.meshes[m].vertices[vcounter] = outv.x; - model.meshes[m].vertices[vcounter + 1] = outv.y; - model.meshes[m].vertices[vcounter + 2] = outv.z; - - // normals - // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals) - outn = (Vector3){ model.meshes[m].baseNormals[vcounter], model.meshes[m].baseNormals[vcounter + 1], model.meshes[m].baseNormals[vcounter + 2] }; - outn = Vector3RotateByQuaternion(outn, QuaternionMultiply(outr, QuaternionInvert(baser))); - model.meshes[m].normals[vcounter] = outn.x; - model.meshes[m].normals[vcounter + 1] = outn.y; - model.meshes[m].normals[vcounter + 2] = outn.z; - vcounter += 3; - wcounter += 4; - } - } -} - -// Draw an animated model -void DrawAnimatedModel(AnimatedModel model, Vector3 position, float scale, Color tint) -{ - Vector3 vScale = { scale, scale, scale }; - Vector3 rotationAxis = { 1.0f, 0.0f,0.0f }; - - DrawAnimatedModelEx(model, position, rotationAxis, -90.0f, vScale, tint); -} - -// Draw an animated model with extended parameters -void DrawAnimatedModelEx(AnimatedModel model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) -{ - if (model.materialCount == 0) - { - TraceLog(LOG_WARNING,"No materials set, can't draw animated meshes\n"); - return; - } - - Matrix matScale = MatrixScale(scale.x, scale.y, scale.z); - Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD); - Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z); - - Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); - model.transform = MatrixMultiply(model.transform, matTransform); - - for (int i = 0; i < model.meshCount; i++) - { - rlUpdateMesh(model.meshes[i], 0, model.meshes[i].vertexCount); // Update vertex position - rlUpdateMesh(model.meshes[i], 2, model.meshes[i].vertexCount); // Update vertex normals - rlDrawMesh(model.meshes[i], model.materials[model.meshMaterialId[i]], model.transform); // Draw meshes - } -} - -// Load animated model meshes from IQM file -static AnimatedModel LoadIQM(const char *filename) -{ - AnimatedModel model = { 0 }; - - FILE *iqmFile; - IQMHeader iqm; - - IQMMesh *imesh; - IQMTriangle *tri; - IQMVertexArray *va; - IQMJoint *ijoint; - - float *vertex; - float *normal; - float *text; - char *blendi; - unsigned char *blendw; - - iqmFile = fopen(filename, "rb"); - - if (!iqmFile) - { - TraceLog(LOG_ERROR, "[%s] Unable to open file", filename); - return model; - } - - // header - fread(&iqm,sizeof(IQMHeader), 1, iqmFile); - - if (strncmp(iqm.magic, IQM_MAGIC, sizeof(IQM_MAGIC))) - { - TraceLog(LOG_ERROR, "Magic Number \"%s\"does not match.", iqm.magic); - fclose(iqmFile); - return model; - } - - if(iqm.version != IQM_VERSION) - { - TraceLog(LOG_ERROR, "IQM version %i is incorrect.", iqm.version); - fclose(iqmFile); - return model; - } - - // meshes - 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].baseVertices = malloc(sizeof(float)*imesh[i].num_vertexes*3); // Default IQM base position - model.meshes[i].baseNormals = malloc(sizeof(float)*imesh[i].num_vertexes*3); // Default IQM base normal - - model.meshes[i].texcoords = malloc(sizeof(float)*imesh[i].num_vertexes*2); - model.meshes[i].weightId = malloc(sizeof(int)*imesh[i].num_vertexes*4); - model.meshes[i].weightBias = malloc(sizeof(float)*imesh[i].num_vertexes*4); - - model.meshes[i].triangleCount = imesh[i].num_triangles; - model.meshes[i].indices = malloc(sizeof(unsigned short)*imesh[i].num_triangles*3); - - // What we actually process for rendering, should be updated transforming meshes.vertices and meshes.normals - model.meshes[i].vertices = malloc(sizeof(float)*imesh[i].num_vertexes*3); - model.meshes[i].normals = malloc(sizeof(float)*imesh[i].num_vertexes*3); - } - - // tris - 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; - } - } - - // vertarrays - 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].baseVertices[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].baseNormals[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 vcounter = 0; - for (int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++) - { - model.meshes[m].weightId[vcounter] = blendi[i]; - vcounter++; - } - } - } 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 vcounter = 0; - for (int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++) - { - model.meshes[m].weightBias[vcounter] = blendw[i]/255.0f; - vcounter++; - } - } - } break; - } - } - - // joints, include base poses - ijoint = malloc(sizeof(IQMJoint)*iqm.num_joints); - fseek(iqmFile, iqm.ofs_joints, SEEK_SET); - fread(ijoint, sizeof(IQMJoint)*iqm.num_joints, 1, iqmFile); - - model.jointCount = iqm.num_joints; - model.joints = malloc(sizeof(Joint)*iqm.num_joints); - model.basepose = malloc(sizeof(Pose)*iqm.num_joints); - - for (int i = 0; i < iqm.num_joints; i++) - { - // joints - model.joints[i].parent = ijoint[i].parent; - fseek(iqmFile, iqm.ofs_text + ijoint[i].name, SEEK_SET); - fread(model.joints[i].name,sizeof(char)*JOINT_NAME_LENGTH, 1, iqmFile); - - // basepose - model.basepose[i].translation.x = ijoint[i].translate[0]; - model.basepose[i].translation.y = ijoint[i].translate[1]; - model.basepose[i].translation.z = ijoint[i].translate[2]; - - model.basepose[i].rotation.x = ijoint[i].rotate[0]; - model.basepose[i].rotation.y = ijoint[i].rotate[1]; - model.basepose[i].rotation.z = ijoint[i].rotate[2]; - model.basepose[i].rotation.w = ijoint[i].rotate[3]; - - model.basepose[i].scale.x = ijoint[i].scale[0]; - model.basepose[i].scale.y = ijoint[i].scale[1]; - model.basepose[i].scale.z = ijoint[i].scale[2]; - } - - // build base pose - for (int i = 0; i < model.jointCount; i++) - { - if (model.joints[i].parent >= 0) - { - model.basepose[i].rotation = QuaternionMultiply(model.basepose[model.joints[i].parent].rotation, model.basepose[i].rotation); - model.basepose[i].translation = Vector3RotateByQuaternion(model.basepose[i].translation, model.basepose[model.joints[i].parent].rotation); - model.basepose[i].translation = Vector3Add(model.basepose[i].translation, model.basepose[model.joints[i].parent].translation); - model.basepose[i].scale = Vector3MultiplyV(model.basepose[i].scale, model.basepose[model.joints[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; -} #endif diff --git a/src/models.c b/src/models.c index 239ab5d8..e437a0ab 100644 --- a/src/models.c +++ b/src/models.c @@ -697,6 +697,18 @@ void UnloadModel(Model model) TraceLog(LOG_INFO, "Unloaded model data from RAM and VRAM"); } +// Load meshes from model file +Mesh *LoadMeshes(const char *fileName, int *meshCount) +{ + Mesh *meshes = NULL; + int count = 0; + + // TODO: Load meshes from file (OBJ, IQM, GLTF) + + *meshCount = count; + return meshes; +} + // Unload mesh from memory (RAM and/or VRAM) void UnloadMesh(Mesh *mesh) { @@ -759,6 +771,386 @@ void ExportMesh(Mesh mesh, const char *fileName) else TraceLog(LOG_WARNING, "Mesh could not be exported."); } +// Load materials from model file +Material *LoadMaterials(const char *fileName, int *materialCount) +{ + Material *materials = NULL; + unsigned int count = 0; + + // TODO: Support IQM and GLTF for materials parsing + +#if defined(SUPPORT_FILEFORMAT_MTL) + if (IsFileExtension(fileName, ".mtl")) + { + tinyobj_material_t *mats; + + int result = tinyobj_parse_mtl_file(&mats, &count, fileName); + + // TODO: Process materials to return + + tinyobj_materials_free(mats, count); + } +#else + TraceLog(LOG_WARNING, "[%s] Materials file not supported", fileName); +#endif + + // Set materials shader to default (DIFFUSE, SPECULAR, NORMAL) + for (int i = 0; i < count; i++) materials[i].shader = GetShaderDefault(); + + *materialCount = count; + return materials; +} + +// Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) +Material LoadMaterialDefault(void) +{ + Material material = { 0 }; + + material.shader = GetShaderDefault(); + material.maps[MAP_DIFFUSE].texture = GetTextureDefault(); // White texture (1x1 pixel) + //material.maps[MAP_NORMAL].texture; // NOTE: By default, not set + //material.maps[MAP_SPECULAR].texture; // NOTE: By default, not set + + material.maps[MAP_DIFFUSE].color = WHITE; // Diffuse color + material.maps[MAP_SPECULAR].color = WHITE; // Specular color + + return material; +} + +// Unload material from memory +void UnloadMaterial(Material material) +{ + // Unload material shader (avoid unloading default shader, managed by raylib) + if (material.shader.id != GetShaderDefault().id) UnloadShader(material.shader); + + // Unload loaded texture maps (avoid unloading default texture, managed by raylib) + for (int i = 0; i < MAX_MATERIAL_MAPS; i++) + { + if (material.maps[i].texture.id != GetTextureDefault().id) rlDeleteTextures(material.maps[i].texture.id); + } +} + +// Set texture for a material map type (MAP_DIFFUSE, MAP_SPECULAR...) +// NOTE: Previous texture should be manually unloaded +void SetMaterialTexture(Material *material, int mapType, Texture2D texture) +{ + material->maps[mapType].texture = 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"); + else model->meshMaterial[meshId] = materialId; +} + +// Load model animations from file +ModelAnimation *LoadModelAnimations(const char *filename, int *animCount) +{ + ModelAnimation *animations = (ModelAnimation *)malloc(1*sizeof(ModelAnimation)); + int count = 1; + + #define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number + #define IQM_VERSION 2 // only IQM version 2 supported + + 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 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; + + ModelAnimation animation = { 0 }; + + FILE *iqmFile; + IQMHeader iqm; + + iqmFile = fopen(filename,"rb"); + + if (!iqmFile) + { + TraceLog(LOG_ERROR, "[%s] Unable to open file", filename); + } + + // header + fread(&iqm, sizeof(IQMHeader), 1, iqmFile); + + if (strncmp(iqm.magic, IQM_MAGIC, sizeof(IQM_MAGIC))) + { + TraceLog(LOG_ERROR, "Magic Number \"%s\"does not match.", iqm.magic); + fclose(iqmFile); + } + + if (iqm.version != IQM_VERSION) + { + TraceLog(LOG_ERROR, "IQM version %i is incorrect.", iqm.version); + fclose(iqmFile); + } + + // header + if (iqm.num_anims > 1) TraceLog(LOG_WARNING, "More than 1 animation in file, only the first one will be loaded"); + + // bones + IQMPose *poses; + poses = malloc(sizeof(IQMPose)*iqm.num_poses); + fseek(iqmFile, iqm.ofs_poses, SEEK_SET); + fread(poses, sizeof(IQMPose)*iqm.num_poses, 1, iqmFile); + + animation.boneCount = iqm.num_poses; + animation.bones = malloc(sizeof(BoneInfo)*iqm.num_poses); + + for (int j = 0; j < iqm.num_poses; j++) + { + strcpy(animation.bones[j].name, "ANIMJOINTNAME"); + animation.bones[j].parent = poses[j].parent; + } + + // animations + IQMAnim anim = {0}; + fseek(iqmFile, iqm.ofs_anims, SEEK_SET); + fread(&anim, sizeof(IQMAnim), 1, iqmFile); + + animation.frameCount = anim.num_frames; + //animation.framerate = anim.framerate; + + // frameposes + unsigned short *framedata = malloc(sizeof(unsigned short)*iqm.num_frames*iqm.num_framechannels); + fseek(iqmFile, iqm.ofs_frames, SEEK_SET); + fread(framedata, sizeof(unsigned short)*iqm.num_frames*iqm.num_framechannels, 1, iqmFile); + + animation.framePoses = malloc(sizeof(Transform*)*anim.num_frames); + for (int j = 0; j < anim.num_frames; j++) animation.framePoses[j] = malloc(sizeof(Transform)*iqm.num_poses); + + int dcounter = anim.first_frame*iqm.num_framechannels; + + for (int frame = 0; frame < anim.num_frames; frame++) + { + for (int i = 0; i < iqm.num_poses; i++) + { + animation.framePoses[frame][i].translation.x = poses[i].channeloffset[0]; + + if (poses[i].mask & 0x01) + { + animation.framePoses[frame][i].translation.x += framedata[dcounter]*poses[i].channelscale[0]; + dcounter++; + } + + animation.framePoses[frame][i].translation.y = poses[i].channeloffset[1]; + + if (poses[i].mask & 0x02) + { + animation.framePoses[frame][i].translation.y += framedata[dcounter]*poses[i].channelscale[1]; + dcounter++; + } + + animation.framePoses[frame][i].translation.z = poses[i].channeloffset[2]; + + if (poses[i].mask & 0x04) + { + animation.framePoses[frame][i].translation.z += framedata[dcounter]*poses[i].channelscale[2]; + dcounter++; + } + + animation.framePoses[frame][i].rotation.x = poses[i].channeloffset[3]; + + if (poses[i].mask & 0x08) + { + animation.framePoses[frame][i].rotation.x += framedata[dcounter]*poses[i].channelscale[3]; + dcounter++; + } + + animation.framePoses[frame][i].rotation.y = poses[i].channeloffset[4]; + + if (poses[i].mask & 0x10) + { + animation.framePoses[frame][i].rotation.y += framedata[dcounter]*poses[i].channelscale[4]; + dcounter++; + } + + animation.framePoses[frame][i].rotation.z = poses[i].channeloffset[5]; + + if (poses[i].mask & 0x20) + { + animation.framePoses[frame][i].rotation.z += framedata[dcounter]*poses[i].channelscale[5]; + dcounter++; + } + + animation.framePoses[frame][i].rotation.w = poses[i].channeloffset[6]; + + if (poses[i].mask & 0x40) + { + animation.framePoses[frame][i].rotation.w += framedata[dcounter]*poses[i].channelscale[6]; + dcounter++; + } + + animation.framePoses[frame][i].scale.x = poses[i].channeloffset[7]; + + if (poses[i].mask & 0x80) + { + animation.framePoses[frame][i].scale.x += framedata[dcounter]*poses[i].channelscale[7]; + dcounter++; + } + + animation.framePoses[frame][i].scale.y = poses[i].channeloffset[8]; + + if (poses[i].mask & 0x100) + { + animation.framePoses[frame][i].scale.y += framedata[dcounter]*poses[i].channelscale[8]; + dcounter++; + } + + animation.framePoses[frame][i].scale.z = poses[i].channeloffset[9]; + + if (poses[i].mask & 0x200) + { + animation.framePoses[frame][i].scale.z += framedata[dcounter]*poses[i].channelscale[9]; + dcounter++; + } + + animation.framePoses[frame][i].rotation = QuaternionNormalize(animation.framePoses[frame][i].rotation); + } + } + + // Build frameposes + for (int frame = 0; frame < anim.num_frames; frame++) + { + for (int i = 0; i < animation.boneCount; i++) + { + if (animation.bones[i].parent >= 0) + { + animation.framePoses[frame][i].rotation = QuaternionMultiply(animation.framePoses[frame][animation.bones[i].parent].rotation, animation.framePoses[frame][i].rotation); + animation.framePoses[frame][i].translation = Vector3RotateByQuaternion(animation.framePoses[frame][i].translation, animation.framePoses[frame][animation.bones[i].parent].rotation); + animation.framePoses[frame][i].translation = Vector3Add(animation.framePoses[frame][i].translation, animation.framePoses[frame][animation.bones[i].parent].translation); + animation.framePoses[frame][i].scale = Vector3MultiplyV(animation.framePoses[frame][i].scale, animation.framePoses[frame][animation.bones[i].parent].scale); + } + } + } + + free(framedata); + free(poses); + + fclose(iqmFile); + + animations[0] = animation; + + *animCount = count; + return animations; +} + +// Update model animated vertex data (positions and normals) for a given frame +// NOTE: Updated data is uploaded to GPU +void UpdateModelAnimation(Model model, ModelAnimation anim, int frame) +{ + if (frame >= anim.frameCount) frame = frame%anim.frameCount; + + for (int m = 0; m < model.meshCount; m++) + { + Vector3 animVertex = { 0 }; + Vector3 animNormal = { 0 }; + + Vector3 inTranslation = { 0 }; + Quaternion inRotation = { 0 }; + Vector3 inScale = { 0 }; + + Vector3 outTranslation = { 0 }; + Quaternion outRotation = { 0 }; + Vector3 outScale = { 0 }; + + int vCounter = 0; + int boneCounter = 0; + int boneId = 0; + + for (int i = 0; i < model.meshes[m].vertexCount; i++) + { + boneId = model.meshes[m].boneIds[boneCounter]; + inTranslation = model.bindPose[boneId].translation; + inRotation = model.bindPose[boneId].rotation; + inScale = model.bindPose[boneId].scale; + outTranslation = anim.framePoses[frame][boneId].translation; + outRotation = anim.framePoses[frame][boneId].rotation; + outScale = anim.framePoses[frame][boneId].scale; + + // 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 = Vector3Subtract(animVertex, inTranslation); + animVertex = Vector3RotateByQuaternion(animVertex, QuaternionMultiply(outRotation, QuaternionInvert(inRotation))); + animVertex = Vector3Add(animVertex, outTranslation); + model.meshes[m].animVertices[vCounter] = animVertex.x; + model.meshes[m].animVertices[vCounter + 1] = animVertex.y; + model.meshes[m].animVertices[vCounter + 2] = animVertex.z; + + // Normals processing + // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals) + animNormal = (Vector3){ model.meshes[m].normals[vCounter], model.meshes[m].normals[vCounter + 1], model.meshes[m].normals[vCounter + 2] }; + animNormal = Vector3RotateByQuaternion(animNormal, QuaternionMultiply(outRotation, QuaternionInvert(inRotation))); + model.meshes[m].animNormals[vCounter] = animNormal.x; + model.meshes[m].animNormals[vCounter + 1] = animNormal.y; + model.meshes[m].animNormals[vCounter + 2] = animNormal.z; + vCounter += 3; + + boneCounter += 4; + } + + // Upload new vertex data to GPU for model drawing + rlUpdateBuffer(model.meshes[m].vboId[0], model.meshes[m].animVertices, model.meshes[m].vertexCount*3*sizeof(float)); // Update vertex position + rlUpdateBuffer(model.meshes[m].vboId[2], model.meshes[m].animVertices, model.meshes[m].vertexCount*3*sizeof(float)); // Update vertex normals + } +} + +// Unload animation data +void UnloadModelAnimation(ModelAnimation anim) +{ + for (int i = 0; i < anim.frameCount; i++) free(anim.framePoses[i]); + + free(anim.bones); + free(anim.framePoses); +} + +// Check model animation skeleton match +// NOTE: Only number of bones and parent connections are checked +bool IsModelAnimationValid(Model model, ModelAnimation anim) +{ + int result = true; + + if (model.boneCount != anim.boneCount) result = false; + else + { + for (int i = 0; i < model.boneCount; i++) + { + if (model.bones[i].parent != anim.bones[i].parent) { result = false; break; } + } + } + + return result; +} + #if defined(SUPPORT_MESH_GENERATION) // Generate polygonal mesh Mesh GenMeshPoly(int sides, float radius) @@ -1807,59 +2199,124 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) } #endif // SUPPORT_MESH_GENERATION -// Load material data (from file) -Material LoadMaterial(const char *fileName) +// Compute mesh bounding box limits +// NOTE: minVertex and maxVertex should be transformed by model transform matrix +BoundingBox MeshBoundingBox(Mesh mesh) { - Material material = { 0 }; + // Get min and max vertex to construct bounds (AABB) + Vector3 minVertex = { 0 }; + Vector3 maxVertex = { 0 }; -#if defined(SUPPORT_FILEFORMAT_MTL) - if (IsFileExtension(fileName, ".mtl")) + if (mesh.vertices != NULL) { - tinyobj_material_t *materials; - unsigned int materialCount = 0; - - int result = tinyobj_parse_mtl_file(&materials, &materialCount, fileName); - - // TODO: Process materials to return + minVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] }; + maxVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] }; - tinyobj_materials_free(materials, materialCount); + for (int i = 1; i < mesh.vertexCount; i++) + { + minVertex = Vector3Min(minVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] }); + maxVertex = Vector3Max(maxVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] }); + } } -#else - TraceLog(LOG_WARNING, "[%s] Material fileformat not supported, it can't be loaded", fileName); -#endif - // Our material uses the default shader (DIFFUSE, SPECULAR, NORMAL) - material.shader = GetShaderDefault(); + // Create the bounding box + BoundingBox box = { 0 }; + box.min = minVertex; + box.max = maxVertex; - return material; + return box; } -// Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) -Material LoadMaterialDefault(void) +// Compute mesh tangents +// NOTE: To calculate mesh tangents and binormals we need mesh vertex positions and texture coordinates +// Implementation base don: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html +void MeshTangents(Mesh *mesh) { - Material material = { 0 }; + if (mesh->tangents == NULL) mesh->tangents = (float *)malloc(mesh->vertexCount*4*sizeof(float)); + else TraceLog(LOG_WARNING, "Mesh tangents already exist"); - material.shader = GetShaderDefault(); - material.maps[MAP_DIFFUSE].texture = GetTextureDefault(); // White texture (1x1 pixel) - //material.maps[MAP_NORMAL].texture; // NOTE: By default, not set - //material.maps[MAP_SPECULAR].texture; // NOTE: By default, not set + Vector3 *tan1 = (Vector3 *)malloc(mesh->vertexCount*sizeof(Vector3)); + Vector3 *tan2 = (Vector3 *)malloc(mesh->vertexCount*sizeof(Vector3)); - material.maps[MAP_DIFFUSE].color = WHITE; // Diffuse color - material.maps[MAP_SPECULAR].color = WHITE; // Specular color + for (int i = 0; i < mesh->vertexCount; i += 3) + { + // Get triangle vertices + Vector3 v1 = { mesh->vertices[(i + 0)*3 + 0], mesh->vertices[(i + 0)*3 + 1], mesh->vertices[(i + 0)*3 + 2] }; + Vector3 v2 = { mesh->vertices[(i + 1)*3 + 0], mesh->vertices[(i + 1)*3 + 1], mesh->vertices[(i + 1)*3 + 2] }; + Vector3 v3 = { mesh->vertices[(i + 2)*3 + 0], mesh->vertices[(i + 2)*3 + 1], mesh->vertices[(i + 2)*3 + 2] }; - return material; + // Get triangle texcoords + Vector2 uv1 = { mesh->texcoords[(i + 0)*2 + 0], mesh->texcoords[(i + 0)*2 + 1] }; + Vector2 uv2 = { mesh->texcoords[(i + 1)*2 + 0], mesh->texcoords[(i + 1)*2 + 1] }; + Vector2 uv3 = { mesh->texcoords[(i + 2)*2 + 0], mesh->texcoords[(i + 2)*2 + 1] }; + + float x1 = v2.x - v1.x; + float y1 = v2.y - v1.y; + float z1 = v2.z - v1.z; + float x2 = v3.x - v1.x; + float y2 = v3.y - v1.y; + float z2 = v3.z - v1.z; + + float s1 = uv2.x - uv1.x; + float t1 = uv2.y - uv1.y; + float s2 = uv3.x - uv1.x; + float t2 = uv3.y - uv1.y; + + float div = s1*t2 - s2*t1; + float r = (div == 0.0f)? 0.0f : 1.0f/div; + + Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r }; + Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r }; + + tan1[i + 0] = sdir; + tan1[i + 1] = sdir; + tan1[i + 2] = sdir; + + tan2[i + 0] = tdir; + tan2[i + 1] = tdir; + tan2[i + 2] = tdir; + } + + // Compute tangents considering normals + 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 = tan1[i]; + + // 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))); + tmp = Vector3Normalize(tmp); + mesh->tangents[i*4 + 0] = tmp.x; + mesh->tangents[i*4 + 1] = tmp.y; + mesh->tangents[i*4 + 2] = tmp.z; + mesh->tangents[i*4 + 3] = 1.0f; + #else + Vector3OrthoNormalize(&normal, &tangent); + mesh->tangents[i*4 + 0] = tangent.x; + mesh->tangents[i*4 + 1] = tangent.y; + mesh->tangents[i*4 + 2] = tangent.z; + mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f)? -1.0f : 1.0f; + #endif + } + + free(tan1); + free(tan2); + + TraceLog(LOG_INFO, "Tangents computed for mesh"); } -// Unload material from memory -void UnloadMaterial(Material material) +// Compute mesh binormals (aka bitangent) +void MeshBinormals(Mesh *mesh) { - // Unload material shader (avoid unloading default shader, managed by raylib) - if (material.shader.id != GetShaderDefault().id) UnloadShader(material.shader); - - // Unload loaded texture maps (avoid unloading default texture, managed by raylib) - for (int i = 0; i < MAX_MATERIAL_MAPS; i++) + for (int i = 0; i < mesh->vertexCount; i++) { - if (material.maps[i].texture.id != GetTextureDefault().id) rlDeleteTextures(material.maps[i].texture.id); + 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] }; + float tangentW = mesh->tangents[i*4 + 3]; + + // TODO: Register computed binormal in mesh->binormal? + // Vector3 binormal = Vector3Multiply(Vector3CrossProduct(normal, tangent), tangentW); } } @@ -2239,129 +2696,6 @@ RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight) return result; } -// Compute mesh bounding box limits -// NOTE: minVertex and maxVertex should be transformed by model transform matrix -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) - { - minVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] }; - maxVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] }; - - for (int i = 1; i < mesh.vertexCount; i++) - { - minVertex = Vector3Min(minVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] }); - maxVertex = Vector3Max(maxVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] }); - } - } - - // Create the bounding box - BoundingBox box = { 0 }; - box.min = minVertex; - box.max = maxVertex; - - return box; -} - -// Compute mesh tangents -// NOTE: To calculate mesh tangents and binormals we need mesh vertex positions and texture coordinates -// Implementation base don: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html -void MeshTangents(Mesh *mesh) -{ - if (mesh->tangents == NULL) mesh->tangents = (float *)malloc(mesh->vertexCount*4*sizeof(float)); - else TraceLog(LOG_WARNING, "Mesh tangents already exist"); - - Vector3 *tan1 = (Vector3 *)malloc(mesh->vertexCount*sizeof(Vector3)); - Vector3 *tan2 = (Vector3 *)malloc(mesh->vertexCount*sizeof(Vector3)); - - for (int i = 0; i < mesh->vertexCount; i += 3) - { - // Get triangle vertices - Vector3 v1 = { mesh->vertices[(i + 0)*3 + 0], mesh->vertices[(i + 0)*3 + 1], mesh->vertices[(i + 0)*3 + 2] }; - Vector3 v2 = { mesh->vertices[(i + 1)*3 + 0], mesh->vertices[(i + 1)*3 + 1], mesh->vertices[(i + 1)*3 + 2] }; - Vector3 v3 = { mesh->vertices[(i + 2)*3 + 0], mesh->vertices[(i + 2)*3 + 1], mesh->vertices[(i + 2)*3 + 2] }; - - // Get triangle texcoords - Vector2 uv1 = { mesh->texcoords[(i + 0)*2 + 0], mesh->texcoords[(i + 0)*2 + 1] }; - Vector2 uv2 = { mesh->texcoords[(i + 1)*2 + 0], mesh->texcoords[(i + 1)*2 + 1] }; - Vector2 uv3 = { mesh->texcoords[(i + 2)*2 + 0], mesh->texcoords[(i + 2)*2 + 1] }; - - float x1 = v2.x - v1.x; - float y1 = v2.y - v1.y; - float z1 = v2.z - v1.z; - float x2 = v3.x - v1.x; - float y2 = v3.y - v1.y; - float z2 = v3.z - v1.z; - - float s1 = uv2.x - uv1.x; - float t1 = uv2.y - uv1.y; - float s2 = uv3.x - uv1.x; - float t2 = uv3.y - uv1.y; - - float div = s1*t2 - s2*t1; - float r = (div == 0.0f)? 0.0f : 1.0f/div; - - Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r }; - Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r }; - - tan1[i + 0] = sdir; - tan1[i + 1] = sdir; - tan1[i + 2] = sdir; - - tan2[i + 0] = tdir; - tan2[i + 1] = tdir; - tan2[i + 2] = tdir; - } - - // Compute tangents considering normals - 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 = tan1[i]; - - // 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))); - tmp = Vector3Normalize(tmp); - mesh->tangents[i*4 + 0] = tmp.x; - mesh->tangents[i*4 + 1] = tmp.y; - mesh->tangents[i*4 + 2] = tmp.z; - mesh->tangents[i*4 + 3] = 1.0f; - #else - Vector3OrthoNormalize(&normal, &tangent); - mesh->tangents[i*4 + 0] = tangent.x; - mesh->tangents[i*4 + 1] = tangent.y; - mesh->tangents[i*4 + 2] = tangent.z; - mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f)? -1.0f : 1.0f; - #endif - } - - free(tan1); - free(tan2); - - TraceLog(LOG_INFO, "Tangents computed for mesh"); -} - -// Compute mesh binormals (aka bitangent) -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] }; - float tangentW = mesh->tangents[i*4 + 3]; - - // TODO: Register computed binormal in mesh->binormal? - // Vector3 binormal = Vector3Multiply(Vector3CrossProduct(normal, tangent), tangentW); - } -} - //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- diff --git a/src/raylib.h b/src/raylib.h index c365fa47..55943baf 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -752,7 +752,7 @@ typedef enum { MAP_IRRADIANCE, // NOTE: Uses GL_TEXTURE_CUBE_MAP MAP_PREFILTER, // NOTE: Uses GL_TEXTURE_CUBE_MAP MAP_BRDF -} TexmapIndex; +} MaterialMapType; #define MAP_DIFFUSE MAP_ALBEDO #define MAP_SPECULAR MAP_METALNESS @@ -1256,16 +1256,25 @@ 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 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) +// Mesh loading/unloading functions +RLAPI Mesh *LoadMeshes(const char *fileName, int *meshCount); // Load meshes from model file RLAPI void ExportMesh(Mesh mesh, const char *fileName); // Export mesh data to file +RLAPI void UnloadMesh(Mesh *mesh); // Unload mesh from memory (RAM and/or VRAM) + +// Material loading/unloading functions +RLAPI Material *LoadMaterials(const char *fileName, int *materialCount); // Load materials from model file +RLAPI Material LoadMaterialDefault(void); // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) +RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM) +RLAPI void SetMaterialTexture(Material *material, int mapType, Texture2D texture); // Set texture for a material map type (MAP_DIFFUSE, MAP_SPECULAR...) +RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId); // Set material for a mesh + +// Model animations loading/unloading functions +RLAPI ModelAnimation *LoadModelAnimations(const char *fileName, int *animsCount); // Load model animations from file +RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); // Update model animation pose +RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data +RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim); // Check model animation skeleton match // Mesh generation functions RLAPI Mesh GenMeshPoly(int sides, float radius); // Generate polygonal mesh @@ -1279,10 +1288,10 @@ RLAPI Mesh GenMeshKnot(float radius, float size, int radSeg, int sides); RLAPI Mesh GenMeshHeightmap(Image heightmap, Vector3 size); // Generate heightmap mesh from image data RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); // Generate cubes-based map mesh from image data -// Material loading/unloading functions -RLAPI Material LoadMaterial(const char *fileName); // Load material from file -RLAPI Material LoadMaterialDefault(void); // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) -RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM) +// 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 // Model drawing functions RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) -- cgit v1.2.3 From c600dd07668f301fc1a986326d807f341e6ecb78 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 5 Apr 2019 16:43:09 +0200 Subject: Review PBR shaders Issue was related to vertex tangent attibutes not uploaded to GPU, a quick solution was implemented for new vertex attributes loading for already existing meshes... I don't like it specially but it will work for now. --- examples/models/models_material_pbr.c | 8 ++++++++ examples/models/resources/shaders/brdf.fs | 4 ++-- examples/models/resources/shaders/irradiance.fs | 4 ++-- examples/models/resources/shaders/prefilter.fs | 4 ++-- src/models.c | 3 +++ src/rlgl.h | 24 ++++++++++++++++++++++++ 6 files changed, 41 insertions(+), 6 deletions(-) (limited to 'src/models.c') diff --git a/examples/models/models_material_pbr.c b/examples/models/models_material_pbr.c index adb4762b..d393a20d 100644 --- a/examples/models/models_material_pbr.c +++ b/examples/models/models_material_pbr.c @@ -38,7 +38,11 @@ int main() // Load model and PBR material Model model = LoadModel("resources/pbr/trooper.obj"); + + // Mesh tangents are generated... and uploaded to GPU + // NOTE: New VBO for tangents is generated at default location and also binded to mesh VAO MeshTangents(&model.meshes[0]); + model.materials[0] = LoadMaterialPBR((Color){ 255, 255, 255, 255 }, 1.0f, 1.0f); // Define lights attributes @@ -143,9 +147,13 @@ static Material LoadMaterialPBR(Color albedo, float metalness, float roughness) #define PATH_BRDF_FS "resources/shaders/brdf.fs" // Path to bidirectional reflectance distribution function fragment shader Shader shdrCubemap = LoadShader(PATH_CUBEMAP_VS, PATH_CUBEMAP_FS); + printf("Loaded shader: cubemap\n"); Shader shdrIrradiance = LoadShader(PATH_SKYBOX_VS, PATH_IRRADIANCE_FS); + printf("Loaded shader: irradiance\n"); Shader shdrPrefilter = LoadShader(PATH_SKYBOX_VS, PATH_PREFILTER_FS); + printf("Loaded shader: prefilter\n"); Shader shdrBRDF = LoadShader(PATH_BRDF_VS, PATH_BRDF_FS); + printf("Loaded shader: brdf\n"); // Setup required shader locations SetShaderValue(shdrCubemap, GetShaderLocation(shdrCubemap, "equirectangularMap"), (int[1]){ 0 }, UNIFORM_INT); diff --git a/examples/models/resources/shaders/brdf.fs b/examples/models/resources/shaders/brdf.fs index 3e8777d2..d04bc661 100644 --- a/examples/models/resources/shaders/brdf.fs +++ b/examples/models/resources/shaders/brdf.fs @@ -10,13 +10,13 @@ #version 330 -#define MAX_SAMPLES 1024u // Input vertex attributes (from vertex shader) in vec2 fragTexCoord; // Constant values const float PI = 3.14159265359; +const uint MAX_SAMPLES = 1024u; // Output fragment color out vec4 finalColor; @@ -93,7 +93,7 @@ vec2 IntegrateBRDF(float NdotV, float roughness) vec3 V = vec3(sqrt(1.0 - NdotV*NdotV), 0.0, NdotV); vec3 N = vec3(0.0, 0.0, 1.0); - for (int i = 0; i < MAX_SAMPLES; i++) + for (uint i = 0u; i < MAX_SAMPLES; i++) { // Generate a sample vector that's biased towards the preferred alignment direction (importance sampling) diff --git a/examples/models/resources/shaders/irradiance.fs b/examples/models/resources/shaders/irradiance.fs index 87113673..b42d2143 100644 --- a/examples/models/resources/shaders/irradiance.fs +++ b/examples/models/resources/shaders/irradiance.fs @@ -9,7 +9,7 @@ #version 330 // Input vertex attributes (from vertex shader) -in vec3 fragPos; +in vec3 fragPosition; // Input uniform values uniform samplerCube environmentMap; @@ -23,7 +23,7 @@ out vec4 finalColor; void main() { // The sample direction equals the hemisphere's orientation - vec3 normal = normalize(fragPos); + vec3 normal = normalize(fragPosition); vec3 irradiance = vec3(0.0); diff --git a/examples/models/resources/shaders/prefilter.fs b/examples/models/resources/shaders/prefilter.fs index f5cf64be..9439810d 100644 --- a/examples/models/resources/shaders/prefilter.fs +++ b/examples/models/resources/shaders/prefilter.fs @@ -11,7 +11,7 @@ #define CUBEMAP_RESOLUTION 1024.0 // Input vertex attributes (from vertex shader) -in vec3 fragPos; +in vec3 fragPosition; // Input uniform values uniform samplerCube environmentMap; @@ -79,7 +79,7 @@ vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness) void main() { // Make the simplyfying assumption that V equals R equals the normal - vec3 N = normalize(fragPos); + vec3 N = normalize(fragPosition); vec3 R = N; vec3 V = R; diff --git a/src/models.c b/src/models.c index e437a0ab..7a9acdf7 100644 --- a/src/models.c +++ b/src/models.c @@ -2302,6 +2302,9 @@ void MeshTangents(Mesh *mesh) free(tan1); free(tan2); + + // 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"); } diff --git a/src/rlgl.h b/src/rlgl.h index 3d433377..bf50ad0d 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -456,6 +456,7 @@ void rlDeleteBuffers(unsigned int id); // Unload vertex data (V 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 +unsigned int rlLoadAttribBuffer(unsigned int vaoId, int shaderLoc, void *buffer, int size, bool dynamic); // Load a new attributes buffer //------------------------------------------------------------------------------------ // Functions Declaration - rlgl functionality @@ -2532,6 +2533,29 @@ void rlLoadMesh(Mesh *mesh, bool dynamic) #endif } +// Load a new attributes buffer +unsigned int rlLoadAttribBuffer(unsigned int vaoId, int shaderLoc, void *buffer, int size, bool dynamic) +{ + unsigned int id = 0; + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + int drawHint = GL_STATIC_DRAW; + if (dynamic) drawHint = GL_DYNAMIC_DRAW; + + if (vaoSupported) glBindVertexArray(vaoId); + + glGenBuffers(1, &id); + glBindBuffer(GL_ARRAY_BUFFER, id); + glBufferData(GL_ARRAY_BUFFER, size, buffer, drawHint); + glVertexAttribPointer(shaderLoc, 2, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(shaderLoc); + + if (vaoSupported) glBindVertexArray(0); +#endif + + return id; +} + // Update vertex data on GPU (upload new data to one buffer) void rlUpdateMesh(Mesh mesh, int buffer, int numVertex) { -- cgit v1.2.3 From f21761fbbb02f0b58b5b54342f0c3ad3abc0003e Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Sun, 7 Apr 2019 17:49:12 +0200 Subject: Happy new year 2019 --- examples/Makefile | 2 +- examples/audio/audio_raw_stream.c | 2 +- examples/models/models_obj_viewer.c | 2 +- examples/others/rlgl_standalone.c | 2 +- games/Makefile | 2 +- games/cat_vs_roomba/Makefile | 2 +- games/cat_vs_roomba/roomba.c | 2 +- games/cat_vs_roomba/screens/screen_ending.c | 2 +- games/cat_vs_roomba/screens/screen_gameplay.c | 2 +- games/cat_vs_roomba/screens/screen_logo.c | 2 +- games/cat_vs_roomba/screens/screen_title.c | 2 +- games/cat_vs_roomba/screens/screens.h | 2 +- games/drturtle/Makefile | 2 +- games/just_do/Makefile | 2 +- games/koala_seasons/Makefile | 2 +- games/light_my_ritual/Makefile | 2 +- games/skully_escape/Makefile | 2 +- games/transmission/Makefile | 2 +- games/transmission/screens/screen_ending.c | 2 +- games/transmission/screens/screen_gameplay.c | 2 +- games/transmission/screens/screen_logo.c | 2 +- games/transmission/screens/screen_mission.c | 2 +- games/transmission/screens/screen_title.c | 2 +- games/transmission/screens/screens.h | 2 +- games/transmission/transmission.c | 2 +- games/wave_collector/Makefile | 2 +- projects/VSCode/Makefile | 2 +- src/Makefile | 2 +- src/core.c | 2 +- src/gestures.h | 2 +- src/models.c | 2 +- src/raylib.h | 2 +- src/rglfw.c | 2 +- src/rlgl.h | 2 +- src/shapes.c | 2 +- src/text.c | 2 +- src/textures.c | 2 +- src/utils.c | 2 +- src/utils.h | 2 +- templates/advance_game/Makefile | 2 +- templates/advance_game/advance_game.c | 2 +- templates/advance_game/screens/screen_ending.c | 2 +- templates/advance_game/screens/screen_gameplay.c | 2 +- templates/advance_game/screens/screen_logo.c | 2 +- templates/advance_game/screens/screen_options.c | 2 +- templates/advance_game/screens/screen_title.c | 2 +- templates/advance_game/screens/screens.h | 2 +- templates/simple_game/Makefile | 2 +- templates/simple_game/simple_game.c | 2 +- templates/standard_game/Makefile | 2 +- templates/standard_game/screens/screen_ending.c | 2 +- templates/standard_game/screens/screen_gameplay.c | 2 +- templates/standard_game/screens/screen_logo.c | 2 +- templates/standard_game/screens/screen_options.c | 2 +- templates/standard_game/screens/screen_title.c | 2 +- templates/standard_game/screens/screens.h | 2 +- templates/standard_game/standard_game.c | 2 +- 57 files changed, 57 insertions(+), 57 deletions(-) (limited to 'src/models.c') diff --git a/examples/Makefile b/examples/Makefile index e14762b3..b35e39f9 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/examples/audio/audio_raw_stream.c b/examples/audio/audio_raw_stream.c index 7eee46f6..d7fa5d79 100644 --- a/examples/audio/audio_raw_stream.c +++ b/examples/audio/audio_raw_stream.c @@ -7,7 +7,7 @@ * This example has been created using raylib 1.6 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2015-2018 Ramon Santamaria (@raysan5) and James Hofmann (@triplefox) +* Copyright (c) 2015-2019 Ramon Santamaria (@raysan5) and James Hofmann (@triplefox) * ********************************************************************************************/ diff --git a/examples/models/models_obj_viewer.c b/examples/models/models_obj_viewer.c index 0581df34..7d387441 100644 --- a/examples/models/models_obj_viewer.c +++ b/examples/models/models_obj_viewer.c @@ -5,7 +5,7 @@ * This example has been created using raylib 2.0 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/others/rlgl_standalone.c b/examples/others/rlgl_standalone.c index 4b262bbd..42aec2e2 100644 --- a/examples/others/rlgl_standalone.c +++ b/examples/others/rlgl_standalone.c @@ -24,7 +24,7 @@ * This example is licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software: * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/games/Makefile b/games/Makefile index 5d60f15d..44e053c6 100644 --- a/games/Makefile +++ b/games/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/games/cat_vs_roomba/Makefile b/games/cat_vs_roomba/Makefile index 6662a6be..b1304656 100644 --- a/games/cat_vs_roomba/Makefile +++ b/games/cat_vs_roomba/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/games/cat_vs_roomba/roomba.c b/games/cat_vs_roomba/roomba.c index 0d236775..eeee7a71 100644 --- a/games/cat_vs_roomba/roomba.c +++ b/games/cat_vs_roomba/roomba.c @@ -8,7 +8,7 @@ * This game has been created using raylib (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/games/cat_vs_roomba/screens/screen_ending.c b/games/cat_vs_roomba/screens/screen_ending.c index ef2a5f74..466d9b91 100644 --- a/games/cat_vs_roomba/screens/screen_ending.c +++ b/games/cat_vs_roomba/screens/screen_ending.c @@ -4,7 +4,7 @@ * * Ending Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/games/cat_vs_roomba/screens/screen_gameplay.c b/games/cat_vs_roomba/screens/screen_gameplay.c index 49a0bb6b..4dd13856 100644 --- a/games/cat_vs_roomba/screens/screen_gameplay.c +++ b/games/cat_vs_roomba/screens/screen_gameplay.c @@ -4,7 +4,7 @@ * * Gameplay Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/games/cat_vs_roomba/screens/screen_logo.c b/games/cat_vs_roomba/screens/screen_logo.c index 9fc704c7..a697013e 100644 --- a/games/cat_vs_roomba/screens/screen_logo.c +++ b/games/cat_vs_roomba/screens/screen_logo.c @@ -4,7 +4,7 @@ * * Logo Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/games/cat_vs_roomba/screens/screen_title.c b/games/cat_vs_roomba/screens/screen_title.c index 009fbd0a..6acadce5 100644 --- a/games/cat_vs_roomba/screens/screen_title.c +++ b/games/cat_vs_roomba/screens/screen_title.c @@ -4,7 +4,7 @@ * * Title Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/games/cat_vs_roomba/screens/screens.h b/games/cat_vs_roomba/screens/screens.h index 9cc07eab..0ad4f9af 100644 --- a/games/cat_vs_roomba/screens/screens.h +++ b/games/cat_vs_roomba/screens/screens.h @@ -4,7 +4,7 @@ * * Screens Functions Declarations (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/games/drturtle/Makefile b/games/drturtle/Makefile index 8f1934b5..4cd5033e 100644 --- a/games/drturtle/Makefile +++ b/games/drturtle/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/games/just_do/Makefile b/games/just_do/Makefile index b6c935f6..af9b31c1 100644 --- a/games/just_do/Makefile +++ b/games/just_do/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/games/koala_seasons/Makefile b/games/koala_seasons/Makefile index 8482bf2d..25dbe696 100644 --- a/games/koala_seasons/Makefile +++ b/games/koala_seasons/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/games/light_my_ritual/Makefile b/games/light_my_ritual/Makefile index fbc34aac..3291bb3e 100644 --- a/games/light_my_ritual/Makefile +++ b/games/light_my_ritual/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/games/skully_escape/Makefile b/games/skully_escape/Makefile index 8875ad52..4673a549 100644 --- a/games/skully_escape/Makefile +++ b/games/skully_escape/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/games/transmission/Makefile b/games/transmission/Makefile index a1b7e764..f62fe080 100644 --- a/games/transmission/Makefile +++ b/games/transmission/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/games/transmission/screens/screen_ending.c b/games/transmission/screens/screen_ending.c index bb355b8b..0492a0cc 100644 --- a/games/transmission/screens/screen_ending.c +++ b/games/transmission/screens/screen_ending.c @@ -4,7 +4,7 @@ * * Ending Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/games/transmission/screens/screen_gameplay.c b/games/transmission/screens/screen_gameplay.c index ee70632a..3dfce714 100644 --- a/games/transmission/screens/screen_gameplay.c +++ b/games/transmission/screens/screen_gameplay.c @@ -4,7 +4,7 @@ * * Gameplay Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/games/transmission/screens/screen_logo.c b/games/transmission/screens/screen_logo.c index 37543302..dc016423 100644 --- a/games/transmission/screens/screen_logo.c +++ b/games/transmission/screens/screen_logo.c @@ -4,7 +4,7 @@ * * Logo Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/games/transmission/screens/screen_mission.c b/games/transmission/screens/screen_mission.c index 1cd2563b..77777c73 100644 --- a/games/transmission/screens/screen_mission.c +++ b/games/transmission/screens/screen_mission.c @@ -3,7 +3,7 @@ * raylib - transmission mission * * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/games/transmission/screens/screen_title.c b/games/transmission/screens/screen_title.c index 2a30a6ba..e9023b08 100644 --- a/games/transmission/screens/screen_title.c +++ b/games/transmission/screens/screen_title.c @@ -3,7 +3,7 @@ * raylib - transmission mission * * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/games/transmission/screens/screens.h b/games/transmission/screens/screens.h index be5e31d9..49698f0d 100644 --- a/games/transmission/screens/screens.h +++ b/games/transmission/screens/screens.h @@ -4,7 +4,7 @@ * * Screens Functions Declarations (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/games/transmission/transmission.c b/games/transmission/transmission.c index 91ca28c1..9fc3d802 100644 --- a/games/transmission/transmission.c +++ b/games/transmission/transmission.c @@ -7,7 +7,7 @@ * This game has been created using raylib (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/games/wave_collector/Makefile b/games/wave_collector/Makefile index 06e74799..703383b8 100644 --- a/games/wave_collector/Makefile +++ b/games/wave_collector/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/projects/VSCode/Makefile b/projects/VSCode/Makefile index 747718fc..3cffaaba 100644 --- a/projects/VSCode/Makefile +++ b/projects/VSCode/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/src/Makefile b/src/Makefile index e2fe6c5d..0217c198 100644 --- a/src/Makefile +++ b/src/Makefile @@ -14,7 +14,7 @@ # Many thanks to Milan Nikolic (@gen2brain) for implementing Android platform pipeline. # Many thanks to Emanuele Petriglia for his contribution on GNU/Linux pipeline. # -# Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +# Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. # In no event will the authors be held liable for any damages arising from diff --git a/src/core.c b/src/core.c index b0c0658d..42db214f 100644 --- a/src/core.c +++ b/src/core.c @@ -68,7 +68,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/gestures.h b/src/gestures.h index a4546eb1..36775333 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -24,7 +24,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/models.c b/src/models.c index 7a9acdf7..07f8203b 100644 --- a/src/models.c +++ b/src/models.c @@ -17,7 +17,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/raylib.h b/src/raylib.h index dc864b8d..dade7aba 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -49,7 +49,7 @@ * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software: * -* Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/rglfw.c b/src/rglfw.c index 853c5200..3463bb96 100644 --- a/src/rglfw.c +++ b/src/rglfw.c @@ -7,7 +7,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2017-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2017-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/rlgl.h b/src/rlgl.h index 81f39d68..3e428241 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -42,7 +42,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/shapes.c b/src/shapes.c index b7f7e3df..fbc70fc4 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -14,7 +14,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/text.c b/src/text.c index d44cdd11..cd7a6802 100644 --- a/src/text.c +++ b/src/text.c @@ -17,7 +17,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/textures.c b/src/textures.c index cd0bd208..5189b635 100644 --- a/src/textures.c +++ b/src/textures.c @@ -38,7 +38,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/utils.c b/src/utils.c index 6b174354..10cce9b9 100644 --- a/src/utils.c +++ b/src/utils.c @@ -11,7 +11,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/utils.h b/src/utils.h index 08b33962..d7ab8829 100644 --- a/src/utils.h +++ b/src/utils.h @@ -5,7 +5,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/advance_game/Makefile b/templates/advance_game/Makefile index 2e5d6e26..e475f72c 100644 --- a/templates/advance_game/Makefile +++ b/templates/advance_game/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/advance_game/advance_game.c b/templates/advance_game/advance_game.c index 48a34f6d..3fb5d657 100644 --- a/templates/advance_game/advance_game.c +++ b/templates/advance_game/advance_game.c @@ -8,7 +8,7 @@ * This game has been created using raylib (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/templates/advance_game/screens/screen_ending.c b/templates/advance_game/screens/screen_ending.c index 66b5ddf9..62d1267a 100644 --- a/templates/advance_game/screens/screen_ending.c +++ b/templates/advance_game/screens/screen_ending.c @@ -4,7 +4,7 @@ * * Ending Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/advance_game/screens/screen_gameplay.c b/templates/advance_game/screens/screen_gameplay.c index 8943adb5..8ea61491 100644 --- a/templates/advance_game/screens/screen_gameplay.c +++ b/templates/advance_game/screens/screen_gameplay.c @@ -4,7 +4,7 @@ * * Gameplay Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/advance_game/screens/screen_logo.c b/templates/advance_game/screens/screen_logo.c index 6282e83e..8badbf52 100644 --- a/templates/advance_game/screens/screen_logo.c +++ b/templates/advance_game/screens/screen_logo.c @@ -4,7 +4,7 @@ * * Logo Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/advance_game/screens/screen_options.c b/templates/advance_game/screens/screen_options.c index dc8d74fa..4b58da13 100644 --- a/templates/advance_game/screens/screen_options.c +++ b/templates/advance_game/screens/screen_options.c @@ -4,7 +4,7 @@ * * Options Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/advance_game/screens/screen_title.c b/templates/advance_game/screens/screen_title.c index 5727546a..8e74a027 100644 --- a/templates/advance_game/screens/screen_title.c +++ b/templates/advance_game/screens/screen_title.c @@ -4,7 +4,7 @@ * * Title Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/advance_game/screens/screens.h b/templates/advance_game/screens/screens.h index 4d7f9b53..7c2dfb48 100644 --- a/templates/advance_game/screens/screens.h +++ b/templates/advance_game/screens/screens.h @@ -4,7 +4,7 @@ * * Screens Functions Declarations (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/simple_game/Makefile b/templates/simple_game/Makefile index 86e0dbde..9f27a429 100644 --- a/templates/simple_game/Makefile +++ b/templates/simple_game/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/simple_game/simple_game.c b/templates/simple_game/simple_game.c index 028b1da8..8f2dc36a 100644 --- a/templates/simple_game/simple_game.c +++ b/templates/simple_game/simple_game.c @@ -8,7 +8,7 @@ * This game has been created using raylib (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/templates/standard_game/Makefile b/templates/standard_game/Makefile index b9c6c188..4333c8b8 100644 --- a/templates/standard_game/Makefile +++ b/templates/standard_game/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2018 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/standard_game/screens/screen_ending.c b/templates/standard_game/screens/screen_ending.c index 87196977..1bd5ce98 100644 --- a/templates/standard_game/screens/screen_ending.c +++ b/templates/standard_game/screens/screen_ending.c @@ -4,7 +4,7 @@ * * Ending Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/standard_game/screens/screen_gameplay.c b/templates/standard_game/screens/screen_gameplay.c index 7f108265..427e5ba7 100644 --- a/templates/standard_game/screens/screen_gameplay.c +++ b/templates/standard_game/screens/screen_gameplay.c @@ -4,7 +4,7 @@ * * Gameplay Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/standard_game/screens/screen_logo.c b/templates/standard_game/screens/screen_logo.c index c0b60571..435ea241 100644 --- a/templates/standard_game/screens/screen_logo.c +++ b/templates/standard_game/screens/screen_logo.c @@ -4,7 +4,7 @@ * * Logo Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/standard_game/screens/screen_options.c b/templates/standard_game/screens/screen_options.c index 9f6690d1..df68dd26 100644 --- a/templates/standard_game/screens/screen_options.c +++ b/templates/standard_game/screens/screen_options.c @@ -4,7 +4,7 @@ * * Options Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/standard_game/screens/screen_title.c b/templates/standard_game/screens/screen_title.c index 328448ba..5bd33825 100644 --- a/templates/standard_game/screens/screen_title.c +++ b/templates/standard_game/screens/screen_title.c @@ -4,7 +4,7 @@ * * Title Screen Functions Definitions (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/standard_game/screens/screens.h b/templates/standard_game/screens/screens.h index e961b533..9450c29f 100644 --- a/templates/standard_game/screens/screens.h +++ b/templates/standard_game/screens/screens.h @@ -4,7 +4,7 @@ * * Screens Functions Declarations (Init, Update, Draw, Unload) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/templates/standard_game/standard_game.c b/templates/standard_game/standard_game.c index 8871484e..7918562c 100644 --- a/templates/standard_game/standard_game.c +++ b/templates/standard_game/standard_game.c @@ -8,7 +8,7 @@ * This game has been created using raylib (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * ********************************************************************************************/ -- cgit v1.2.3 From b8ada4b877497cf31aad0efdec41c032fc686552 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 8 Apr 2019 12:25:13 +0200 Subject: Review creation years --- src/config.h | 2 +- src/core.c | 2 +- src/models.c | 2 +- src/raudio.c | 2 +- src/shapes.c | 2 +- src/text.c | 2 +- src/textures.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/models.c') diff --git a/src/config.h b/src/config.h index 561bcfd3..dc30eeb2 100644 --- a/src/config.h +++ b/src/config.h @@ -6,7 +6,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2018 Ahmad Fatoum & Ramon Santamaria (@raysan5) +* Copyright (c) 2018-2019 Ahmad Fatoum & Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/core.c b/src/core.c index 42db214f..32773a0d 100644 --- a/src/core.c +++ b/src/core.c @@ -68,7 +68,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/models.c b/src/models.c index 07f8203b..d5e74e33 100644 --- a/src/models.c +++ b/src/models.c @@ -17,7 +17,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/raudio.c b/src/raudio.c index d360b2d3..636d15b8 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -46,7 +46,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/shapes.c b/src/shapes.c index fbc70fc4..f407f0d2 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -14,7 +14,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/text.c b/src/text.c index cd7a6802..c07f807a 100644 --- a/src/text.c +++ b/src/text.c @@ -17,7 +17,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/textures.c b/src/textures.c index 5189b635..169f8f86 100644 --- a/src/textures.c +++ b/src/textures.c @@ -38,7 +38,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. -- cgit v1.2.3 From 32ccecb8ca1f141e6b8e20007e795c58108cb899 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 9 Apr 2019 13:23:51 +0200 Subject: Start working on glTF loading... --- src/models.c | 60 +++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 19 deletions(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index d5e74e33..73f8b940 100644 --- a/src/models.c +++ b/src/models.c @@ -3013,30 +3013,30 @@ static Model LoadIQM(const char *fileName) fread(imesh, sizeof(IQMMesh)*iqm.num_meshes, 1, iqmFile); model.meshCount = iqm.num_meshes; - model.meshes = malloc(sizeof(Mesh)*iqm.num_meshes); + model.meshes = malloc(model.meshCount*sizeof(Mesh)); char name[MESH_NAME_LENGTH]; - for (int i = 0; i < iqm.num_meshes; i++) + for (int i = 0; i < model.meshCount; 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].vertices = malloc(sizeof(float)*model.meshes[i].vertexCount*3); // Default vertex positions + model.meshes[i].normals = malloc(sizeof(float)*model.meshes[i].vertexCount*3); // Default vertex normals + model.meshes[i].texcoords = malloc(sizeof(float)*model.meshes[i].vertexCount*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].boneIds = malloc(sizeof(int)*model.meshes[i].vertexCount*4); // Up-to 4 bones supported! + model.meshes[i].boneWeights = malloc(sizeof(float)*model.meshes[i].vertexCount*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); + model.meshes[i].indices = malloc(sizeof(unsigned short)*model.meshes[i].triangleCount*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); + model.meshes[i].animVertices = malloc(sizeof(float)*model.meshes[i].vertexCount*3); + model.meshes[i].animNormals = malloc(sizeof(float)*model.meshes[i].vertexCount*3); } // Triangles data processing @@ -3044,15 +3044,15 @@ static Model LoadIQM(const char *fileName) 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++) + for (int m = 0; m < model.meshCount; m++) { int tcounter = 0; - for (int i = imesh[m].first_triangle; i < imesh[m].first_triangle+imesh[m].num_triangles; i++) + 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 + 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; } @@ -3235,7 +3235,7 @@ static Model LoadGLTF(const char *fileName) fclose(gltfFile); // glTF data loading - cgltf_options options = {0}; + cgltf_options options = { 0 }; cgltf_data *data; cgltf_result result = cgltf_parse(&options, buffer, size, &data); @@ -3243,11 +3243,33 @@ static Model LoadGLTF(const char *fileName) 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); + TraceLog(LOG_INFO, "[%s][%s] Model meshes/materials: %i/%i", (data->file_type == 2)? "glb" : "gltf", data->meshes_count, data->materials_count); + + // Read data buffers + result = cgltf_load_buffers(&options, data, fileName); + + // Process glTF data and map to model + model.meshCount = data->meshes_count; + model.meshes = malloc(model.meshCount*sizeof(Mesh)); + + for (int i = 0; i < model.meshCount; i++) + { + // NOTE: Only support meshes defined by triangle primitives + //if (data->meshes[i].primitives[n].type == cgltf_primitive_type_triangles) + { + // data.meshes[i].name not used + model.meshes[i].vertexCount = data->meshes[i].primitives_count*3; + model.meshes[i].triangleCount = data->meshes[i].primitives_count; + // data.meshes[i].weights not used (array of weights to be applied to the Morph Targets) + + model.meshes[i].vertices = malloc(sizeof(float)*model.meshes[i].vertexCount*3); // Default vertex positions + model.meshes[i].normals = malloc(sizeof(float)*model.meshes[i].vertexCount*3); // Default vertex normals + model.meshes[i].texcoords = malloc(sizeof(float)*model.meshes[i].vertexCount*2); // Default vertex texcoords + + model.meshes[i].indices = malloc(sizeof(unsigned short)*model.meshes[i].triangleCount*3); - // 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); -- cgit v1.2.3 From 21092266b57f9f444c51905fceb4eda1dd7f83c3 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 10 Apr 2019 00:44:24 +0200 Subject: Check textures available before loading --- src/models.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index 73f8b940..f10df262 100644 --- a/src/models.c +++ b/src/models.c @@ -2846,21 +2846,21 @@ static Model LoadOBJ(const char *fileName) } tinyobj_material_t; */ - model.materials[m].maps[MAP_DIFFUSE].texture = LoadTexture(materials[m].diffuse_texname); //char *diffuse_texname; // map_Kd + if (materials[m].diffuse_texname != NULL) 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 + if (materials[m].specular_texname != NULL) 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 + if (materials[m].bump_texname != NULL) 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 + if (materials[m].displacement_texname != NULL) model.materials[m].maps[MAP_HEIGHT].texture = LoadTexture(materials[m].displacement_texname); //char *displacement_texname; // disp } tinyobj_attrib_free(&attrib); -- cgit v1.2.3 From 45c820eeb4e4f559b09c382df5a7808fb1c95115 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 10 Apr 2019 22:39:42 +0200 Subject: Set default white texture for diffuse mat --- src/models.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index f10df262..d8508492 100644 --- a/src/models.c +++ b/src/models.c @@ -2846,6 +2846,8 @@ static Model LoadOBJ(const char *fileName) } tinyobj_material_t; */ + model.materials[m].maps[MAP_DIFFUSE].texture = GetTextureDefault(); // Get default texture, in case no texture is defined + if (materials[m].diffuse_texname != NULL) 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; -- cgit v1.2.3 From 8c22f685d168000eabfc994a09c3a2a61f7f633f Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 14 Apr 2019 22:29:14 +0200 Subject: Check buffer overflow --- src/models.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index d8508492..631c4942 100644 --- a/src/models.c +++ b/src/models.c @@ -295,6 +295,8 @@ void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float hei float x = position.x; float y = position.y; float z = position.z; + + if (rlCheckBufferLimit(36)) rlglDraw(); rlEnableTexture(texture.id); @@ -357,6 +359,9 @@ void DrawSphere(Vector3 centerPos, float radius, Color color) // Draw sphere with extended parameters void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color) { + int numVertex = (rings + 2)*slices*6; + if (rlCheckBufferLimit(numVertex)) rlglDraw(); + rlPushMatrix(); // NOTE: Transformation is applied in inverse order (scale -> translate) rlTranslatef(centerPos.x, centerPos.y, centerPos.z); @@ -397,6 +402,9 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color // Draw sphere wires void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color) { + int numVertex = (rings + 2)*slices*6; + if (rlCheckBufferLimit(numVertex)) rlglDraw(); + rlPushMatrix(); // NOTE: Transformation is applied in inverse order (scale -> translate) rlTranslatef(centerPos.x, centerPos.y, centerPos.z); @@ -440,6 +448,9 @@ void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Col void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color) { if (sides < 3) sides = 3; + + int numVertex = sides*6; + if (rlCheckBufferLimit(numVertex)) rlglDraw(); rlPushMatrix(); rlTranslatef(position.x, position.y, position.z); @@ -496,6 +507,9 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color) { if (sides < 3) sides = 3; + + int numVertex = sides*8; + if (rlCheckBufferLimit(numVertex)) rlglDraw(); rlPushMatrix(); rlTranslatef(position.x, position.y, position.z); @@ -524,6 +538,8 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl // Draw a plane void DrawPlane(Vector3 centerPos, Vector2 size, Color color) { + if (rlCheckBufferLimit(4)) rlglDraw(); + // NOTE: Plane is always created on XZ ground rlPushMatrix(); rlTranslatef(centerPos.x, centerPos.y, centerPos.z); @@ -560,6 +576,8 @@ void DrawGrid(int slices, float spacing) { int halfSlices = slices/2; + if (rlCheckBufferLimit(slices*4)) rlglDraw(); + rlBegin(RL_LINES); for (int i = -halfSlices; i <= halfSlices; i++) { -- cgit v1.2.3 From e67ebabb02c1068d6e7f5107dcff5388ede3faa5 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 23 Apr 2019 14:55:35 +0200 Subject: Support custom memory management macros Users can define their custom memory management macros. NOTE: Most external libraries support custom macros in the same way, raylib should redefine those macros to raylib ones, to unify custom memory loading. That redefinition is only implemented as example for stb_image.h in [textures] module. --- src/core.c | 24 ++--- src/models.c | 291 +++++++++++++++++++++++++++++---------------------------- src/raudio.c | 38 ++++---- src/raudio.h | 11 ++- src/raylib.h | 11 +++ src/rlgl.h | 88 ++++++++--------- src/text.c | 54 +++++------ src/textures.c | 181 ++++++++++++++++++----------------- src/utils.c | 6 +- 9 files changed, 365 insertions(+), 339 deletions(-) (limited to 'src/models.c') diff --git a/src/core.c b/src/core.c index 6bb54c51..844994d0 100644 --- a/src/core.c +++ b/src/core.c @@ -1113,7 +1113,7 @@ void EndDrawing(void) unsigned char *screenData = rlReadScreenPixels(screenWidth, screenHeight); GifWriteFrame(screenData, screenWidth, screenHeight, 10, 8, false); - free(screenData); // Free image data + RL_FREE(screenData); // Free image data } if (((gifFramesCounter/15)%2) == 1) @@ -1595,7 +1595,7 @@ void TakeScreenshot(const char *fileName) #endif ExportImage(image, path); - free(imgData); + RL_FREE(imgData); #if defined(PLATFORM_WEB) // Download file from MEMFS (emscripten memory filesystem) @@ -1742,8 +1742,8 @@ char **GetDirectoryFiles(const char *dirPath, int *fileCount) ClearDirectoryFiles(); // Memory allocation for MAX_DIRECTORY_FILES - dirFilesPath = (char **)malloc(sizeof(char *)*MAX_DIRECTORY_FILES); - for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesPath[i] = (char *)malloc(sizeof(char)*MAX_FILEPATH_LENGTH); + dirFilesPath = (char **)RL_MALLOC(sizeof(char *)*MAX_DIRECTORY_FILES); + for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesPath[i] = (char *)RL_MALLOC(sizeof(char)*MAX_FILEPATH_LENGTH); int counter = 0; struct dirent *ent; @@ -1776,9 +1776,9 @@ void ClearDirectoryFiles(void) { if (dirFilesCount > 0) { - for (int i = 0; i < dirFilesCount; i++) free(dirFilesPath[i]); + for (int i = 0; i < dirFilesCount; i++) RL_FREE(dirFilesPath[i]); - free(dirFilesPath); + RL_FREE(dirFilesPath); dirFilesCount = 0; } } @@ -1808,9 +1808,9 @@ void ClearDroppedFiles(void) { if (dropFilesCount > 0) { - for (int i = 0; i < dropFilesCount; i++) free(dropFilesPath[i]); + for (int i = 0; i < dropFilesCount; i++) RL_FREE(dropFilesPath[i]); - free(dropFilesPath); + RL_FREE(dropFilesPath); dropFilesCount = 0; } @@ -1925,7 +1925,7 @@ void OpenURL(const char *url) } else { - char *cmd = (char *)calloc(strlen(url) + 10, sizeof(char)); + char *cmd = (char *)RL_CALLOC(strlen(url) + 10, sizeof(char)); #if defined(_WIN32) sprintf(cmd, "explorer %s", url); @@ -1935,7 +1935,7 @@ void OpenURL(const char *url) sprintf(cmd, "open '%s'", url); #endif system(cmd); - free(cmd); + RL_FREE(cmd); } } @@ -3455,11 +3455,11 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths { ClearDroppedFiles(); - dropFilesPath = (char **)malloc(sizeof(char *)*count); + dropFilesPath = (char **)RL_MALLOC(sizeof(char *)*count); for (int i = 0; i < count; i++) { - dropFilesPath[i] = (char *)malloc(sizeof(char)*MAX_FILEPATH_LENGTH); + dropFilesPath[i] = (char *)RL_MALLOC(sizeof(char)*MAX_FILEPATH_LENGTH); strcpy(dropFilesPath[i], paths[i]); } diff --git a/src/models.c b/src/models.c index 631c4942..c81dfe19 100644 --- a/src/models.c +++ b/src/models.c @@ -651,7 +651,7 @@ Model LoadModel(const char *fileName) TraceLog(LOG_WARNING, "[%s] No meshes can be loaded, default to cube mesh", fileName); model.meshCount = 1; - model.meshes = (Mesh *)calloc(model.meshCount, sizeof(Mesh)); + model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); model.meshes[0] = GenMeshCube(1.0f, 1.0f, 1.0f); } else @@ -665,10 +665,10 @@ Model LoadModel(const char *fileName) TraceLog(LOG_WARNING, "[%s] No materials can be loaded, default to white material", fileName); model.materialCount = 1; - model.materials = (Material *)calloc(model.materialCount, sizeof(Material)); + model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material)); model.materials[0] = LoadMaterialDefault(); - model.meshMaterial = (int *)calloc(model.meshCount, sizeof(int)); + model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); } return model; @@ -685,14 +685,14 @@ Model LoadModelFromMesh(Mesh mesh) model.transform = MatrixIdentity(); model.meshCount = 1; - model.meshes = (Mesh *)malloc(model.meshCount*sizeof(Mesh)); + model.meshes = (Mesh *)RL_MALLOC(model.meshCount*sizeof(Mesh)); model.meshes[0] = mesh; model.materialCount = 1; - model.materials = (Material *)malloc(model.materialCount*sizeof(Material)); + model.materials = (Material *)RL_MALLOC(model.materialCount*sizeof(Material)); model.materials[0] = LoadMaterialDefault(); - model.meshMaterial = (int *)malloc(model.meshCount*sizeof(int)); + model.meshMaterial = (int *)RL_MALLOC(model.meshCount*sizeof(int)); model.meshMaterial[0] = 0; // First material index return model; @@ -704,13 +704,13 @@ 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); + RL_FREE(model.meshes); + RL_FREE(model.materials); + RL_FREE(model.meshMaterial); // Unload animation data - free(model.bones); - free(model.bindPose); + RL_FREE(model.bones); + RL_FREE(model.bindPose); TraceLog(LOG_INFO, "Unloaded model data from RAM and VRAM"); } @@ -866,7 +866,7 @@ void SetModelMeshMaterial(Model *model, int meshId, int materialId) // Load model animations from file ModelAnimation *LoadModelAnimations(const char *filename, int *animCount) { - ModelAnimation *animations = (ModelAnimation *)malloc(1*sizeof(ModelAnimation)); + ModelAnimation *animations = (ModelAnimation *)RL_MALLOC(1*sizeof(ModelAnimation)); int count = 1; #define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number @@ -935,12 +935,12 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount) // bones IQMPose *poses; - poses = malloc(sizeof(IQMPose)*iqm.num_poses); + poses = RL_MALLOC(sizeof(IQMPose)*iqm.num_poses); fseek(iqmFile, iqm.ofs_poses, SEEK_SET); fread(poses, sizeof(IQMPose)*iqm.num_poses, 1, iqmFile); animation.boneCount = iqm.num_poses; - animation.bones = malloc(sizeof(BoneInfo)*iqm.num_poses); + animation.bones = RL_MALLOC(sizeof(BoneInfo)*iqm.num_poses); for (int j = 0; j < iqm.num_poses; j++) { @@ -957,12 +957,12 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount) //animation.framerate = anim.framerate; // frameposes - unsigned short *framedata = malloc(sizeof(unsigned short)*iqm.num_frames*iqm.num_framechannels); + unsigned short *framedata = RL_MALLOC(sizeof(unsigned short)*iqm.num_frames*iqm.num_framechannels); fseek(iqmFile, iqm.ofs_frames, SEEK_SET); fread(framedata, sizeof(unsigned short)*iqm.num_frames*iqm.num_framechannels, 1, iqmFile); - animation.framePoses = malloc(sizeof(Transform*)*anim.num_frames); - for (int j = 0; j < anim.num_frames; j++) animation.framePoses[j] = malloc(sizeof(Transform)*iqm.num_poses); + animation.framePoses = RL_MALLOC(sizeof(Transform*)*anim.num_frames); + for (int j = 0; j < anim.num_frames; j++) animation.framePoses[j] = RL_MALLOC(sizeof(Transform)*iqm.num_poses); int dcounter = anim.first_frame*iqm.num_framechannels; @@ -1069,8 +1069,8 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount) } } - free(framedata); - free(poses); + RL_FREE(framedata); + RL_FREE(poses); fclose(iqmFile); @@ -1145,10 +1145,10 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame) // Unload animation data void UnloadModelAnimation(ModelAnimation anim) { - for (int i = 0; i < anim.frameCount; i++) free(anim.framePoses[i]); + for (int i = 0; i < anim.frameCount; i++) RL_FREE(anim.framePoses[i]); - free(anim.bones); - free(anim.framePoses); + RL_FREE(anim.bones); + RL_FREE(anim.framePoses); } // Check model animation skeleton match @@ -1177,7 +1177,7 @@ Mesh GenMeshPoly(int sides, float radius) int vertexCount = sides*3; // Vertices definition - Vector3 *vertices = (Vector3 *)malloc(vertexCount*sizeof(Vector3)); + Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3)); for (int i = 0, v = 0; i < 360; i += 360/sides, v += 3) { vertices[v] = (Vector3){ 0.0f, 0.0f, 0.0f }; @@ -1186,18 +1186,18 @@ Mesh GenMeshPoly(int sides, float radius) } // Normals definition - Vector3 *normals = (Vector3 *)malloc(vertexCount*sizeof(Vector3)); + Vector3 *normals = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3)); for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f }; // Vector3.up; // TexCoords definition - Vector2 *texcoords = (Vector2 *)malloc(vertexCount*sizeof(Vector2)); + Vector2 *texcoords = (Vector2 *)RL_MALLOC(vertexCount*sizeof(Vector2)); for (int n = 0; n < vertexCount; n++) texcoords[n] = (Vector2){ 0.0f, 0.0f }; mesh.vertexCount = vertexCount; mesh.triangleCount = sides; - 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)); + mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); // Mesh vertices position array for (int i = 0; i < mesh.vertexCount; i++) @@ -1222,9 +1222,9 @@ Mesh GenMeshPoly(int sides, float radius) mesh.normals[3*i + 2] = normals[i].z; } - free(vertices); - free(normals); - free(texcoords); + RL_FREE(vertices); + RL_FREE(normals); + RL_FREE(texcoords); // Upload vertex data to GPU (static mesh) rlLoadMesh(&mesh, false); @@ -1245,7 +1245,7 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ) // Vertices definition int vertexCount = resX*resZ; // vertices get reused for the faces - Vector3 *vertices = (Vector3 *)malloc(vertexCount*sizeof(Vector3)); + Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3)); for (int z = 0; z < resZ; z++) { // [-length/2, length/2] @@ -1259,11 +1259,11 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ) } // Normals definition - Vector3 *normals = (Vector3 *)malloc(vertexCount*sizeof(Vector3)); + Vector3 *normals = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3)); for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f }; // Vector3.up; // TexCoords definition - Vector2 *texcoords = (Vector2 *)malloc(vertexCount*sizeof(Vector2)); + Vector2 *texcoords = (Vector2 *)RL_MALLOC(vertexCount*sizeof(Vector2)); for (int v = 0; v < resZ; v++) { for (int u = 0; u < resX; u++) @@ -1274,7 +1274,7 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ) // Triangles definition (indices) int numFaces = (resX - 1)*(resZ - 1); - int *triangles = (int *)malloc(numFaces*6*sizeof(int)); + int *triangles = (int *)RL_MALLOC(numFaces*6*sizeof(int)); int t = 0; for (int face = 0; face < numFaces; face++) { @@ -1292,10 +1292,10 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ) mesh.vertexCount = vertexCount; mesh.triangleCount = numFaces*2; - 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)); - mesh.indices = (unsigned short *)malloc(mesh.triangleCount*3*sizeof(unsigned short)); + mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); + mesh.indices = (unsigned short *)RL_MALLOC(mesh.triangleCount*3*sizeof(unsigned short)); // Mesh vertices position array for (int i = 0; i < mesh.vertexCount; i++) @@ -1323,10 +1323,10 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ) // Mesh indices array initialization for (int i = 0; i < mesh.triangleCount*3; i++) mesh.indices[i] = triangles[i]; - free(vertices); - free(normals); - free(texcoords); - free(triangles); + RL_FREE(vertices); + RL_FREE(normals); + RL_FREE(texcoords); + RL_FREE(triangles); #else // Use par_shapes library to generate plane mesh @@ -1335,9 +1335,9 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ) par_shapes_rotate(plane, -PI/2.0f, (float[]){ 1, 0, 0 }); par_shapes_translate(plane, -width/2, 0.0f, length/2); - mesh.vertices = (float *)malloc(plane->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)malloc(plane->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)malloc(plane->ntriangles*3*3*sizeof(float)); + mesh.vertices = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(plane->ntriangles*3*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float)); mesh.vertexCount = plane->ntriangles*3; mesh.triangleCount = plane->ntriangles; @@ -1453,16 +1453,16 @@ Mesh GenMeshCube(float width, float height, float length) -1.0f, 0.0f, 0.0f }; - mesh.vertices = (float *)malloc(24*3*sizeof(float)); + mesh.vertices = (float *)RL_MALLOC(24*3*sizeof(float)); memcpy(mesh.vertices, vertices, 24*3*sizeof(float)); - mesh.texcoords = (float *)malloc(24*2*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(24*2*sizeof(float)); memcpy(mesh.texcoords, texcoords, 24*2*sizeof(float)); - mesh.normals = (float *)malloc(24*3*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(24*3*sizeof(float)); memcpy(mesh.normals, normals, 24*3*sizeof(float)); - mesh.indices = (unsigned short *)malloc(36*sizeof(unsigned short)); + mesh.indices = (unsigned short *)RL_MALLOC(36*sizeof(unsigned short)); int k = 0; @@ -1500,9 +1500,9 @@ par_shapes_mesh* par_shapes_create_icosahedron(); // 20 sides polyhedron par_shapes_translate(cube, -width/2, 0.0f, -length/2); par_shapes_compute_normals(cube); - mesh.vertices = (float *)malloc(cube->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)malloc(cube->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)malloc(cube->ntriangles*3*3*sizeof(float)); + mesh.vertices = (float *)RL_MALLOC(cube->ntriangles*3*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(cube->ntriangles*3*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(cube->ntriangles*3*3*sizeof(float)); mesh.vertexCount = cube->ntriangles*3; mesh.triangleCount = cube->ntriangles; @@ -1539,9 +1539,9 @@ RLAPI Mesh GenMeshSphere(float radius, int rings, int slices) par_shapes_scale(sphere, radius, radius, radius); // NOTE: Soft normals are computed internally - mesh.vertices = (float *)malloc(sphere->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)malloc(sphere->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)malloc(sphere->ntriangles*3*3*sizeof(float)); + mesh.vertices = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(sphere->ntriangles*3*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float)); mesh.vertexCount = sphere->ntriangles*3; mesh.triangleCount = sphere->ntriangles; @@ -1577,9 +1577,9 @@ RLAPI Mesh GenMeshHemiSphere(float radius, int rings, int slices) par_shapes_scale(sphere, radius, radius, radius); // NOTE: Soft normals are computed internally - mesh.vertices = (float *)malloc(sphere->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)malloc(sphere->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)malloc(sphere->ntriangles*3*3*sizeof(float)); + mesh.vertices = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(sphere->ntriangles*3*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float)); mesh.vertexCount = sphere->ntriangles*3; mesh.triangleCount = sphere->ntriangles; @@ -1635,9 +1635,9 @@ Mesh GenMeshCylinder(float radius, float height, int slices) par_shapes_merge_and_free(cylinder, capTop); par_shapes_merge_and_free(cylinder, capBottom); - mesh.vertices = (float *)malloc(cylinder->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)malloc(cylinder->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)malloc(cylinder->ntriangles*3*3*sizeof(float)); + mesh.vertices = (float *)RL_MALLOC(cylinder->ntriangles*3*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(cylinder->ntriangles*3*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(cylinder->ntriangles*3*3*sizeof(float)); mesh.vertexCount = cylinder->ntriangles*3; mesh.triangleCount = cylinder->ntriangles; @@ -1677,9 +1677,9 @@ Mesh GenMeshTorus(float radius, float size, int radSeg, int sides) par_shapes_mesh *torus = par_shapes_create_torus(radSeg, sides, radius); par_shapes_scale(torus, size/2, size/2, size/2); - mesh.vertices = (float *)malloc(torus->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)malloc(torus->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)malloc(torus->ntriangles*3*3*sizeof(float)); + mesh.vertices = (float *)RL_MALLOC(torus->ntriangles*3*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(torus->ntriangles*3*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(torus->ntriangles*3*3*sizeof(float)); mesh.vertexCount = torus->ntriangles*3; mesh.triangleCount = torus->ntriangles; @@ -1717,9 +1717,9 @@ Mesh GenMeshKnot(float radius, float size, int radSeg, int sides) par_shapes_mesh *knot = par_shapes_create_trefoil_knot(radSeg, sides, radius); par_shapes_scale(knot, size, size, size); - mesh.vertices = (float *)malloc(knot->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)malloc(knot->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)malloc(knot->ntriangles*3*3*sizeof(float)); + mesh.vertices = (float *)RL_MALLOC(knot->ntriangles*3*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(knot->ntriangles*3*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(knot->ntriangles*3*3*sizeof(float)); mesh.vertexCount = knot->ntriangles*3; mesh.triangleCount = knot->ntriangles; @@ -1764,9 +1764,9 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size) mesh.vertexCount = mesh.triangleCount*3; - mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float)); - mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); - mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float)); + mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float)); mesh.colors = NULL; int vCounter = 0; // Used to count vertices float by float @@ -1848,7 +1848,7 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size) } } - free(pixels); + RL_FREE(pixels); // Upload vertex data to GPU (static mesh) rlLoadMesh(&mesh, false); @@ -1878,9 +1878,9 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) float h = cubeSize.z; float h2 = cubeSize.y; - Vector3 *mapVertices = (Vector3 *)malloc(maxTriangles*3*sizeof(Vector3)); - Vector2 *mapTexcoords = (Vector2 *)malloc(maxTriangles*3*sizeof(Vector2)); - Vector3 *mapNormals = (Vector3 *)malloc(maxTriangles*3*sizeof(Vector3)); + Vector3 *mapVertices = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3)); + Vector2 *mapTexcoords = (Vector2 *)RL_MALLOC(maxTriangles*3*sizeof(Vector2)); + Vector3 *mapNormals = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3)); // Define the 6 normals of the cube, we will combine them accordingly later... Vector3 n1 = { 1.0f, 0.0f, 0.0f }; @@ -2167,9 +2167,9 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) mesh.vertexCount = vCounter; mesh.triangleCount = vCounter/3; - mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float)); - mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); - mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float)); + mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float)); mesh.colors = NULL; int fCounter = 0; @@ -2204,11 +2204,11 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) fCounter += 2; } - free(mapVertices); - free(mapNormals); - free(mapTexcoords); + RL_FREE(mapVertices); + RL_FREE(mapNormals); + RL_FREE(mapTexcoords); - free(cubicmapPixels); // Free image pixel data + RL_FREE(cubicmapPixels); // Free image pixel data // Upload vertex data to GPU (static mesh) rlLoadMesh(&mesh, false); @@ -2250,11 +2250,11 @@ BoundingBox MeshBoundingBox(Mesh mesh) // Implementation base don: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html void MeshTangents(Mesh *mesh) { - if (mesh->tangents == NULL) mesh->tangents = (float *)malloc(mesh->vertexCount*4*sizeof(float)); + if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float)); else TraceLog(LOG_WARNING, "Mesh tangents already exist"); - Vector3 *tan1 = (Vector3 *)malloc(mesh->vertexCount*sizeof(Vector3)); - Vector3 *tan2 = (Vector3 *)malloc(mesh->vertexCount*sizeof(Vector3)); + Vector3 *tan1 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3)); + Vector3 *tan2 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3)); for (int i = 0; i < mesh->vertexCount; i += 3) { @@ -2318,8 +2318,8 @@ void MeshTangents(Mesh *mesh) #endif } - free(tan1); - free(tan2); + RL_FREE(tan1); + RL_FREE(tan2); // 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); @@ -2746,7 +2746,7 @@ static Model LoadOBJ(const char *fileName) long length = ftell(objFile); // Get file size fseek(objFile, 0, SEEK_SET); // Reset file pointer - data = (char *)malloc(length); + data = (char *)RL_MALLOC(length); fread(data, length, 1, objFile); dataLength = length; @@ -2763,12 +2763,12 @@ static Model LoadOBJ(const char *fileName) // Init model meshes array model.meshCount = meshCount; - model.meshes = (Mesh *)malloc(model.meshCount*sizeof(Mesh)); + model.meshes = (Mesh *)RL_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)); + model.materials = (Material *)RL_MALLOC(model.materialCount*sizeof(Material)); + model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); /* // Multiple meshes data reference @@ -2787,9 +2787,9 @@ static Model LoadOBJ(const char *fileName) 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)); + mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); + mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float)); + mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); int vCount = 0; int vtCount = 0; @@ -2934,17 +2934,26 @@ static Model LoadIQM(const char *fileName) 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 IQMVertexArray { + unsigned int type; + unsigned int flags; + unsigned int format; + unsigned int size; + unsigned int offset; + } IQMVertexArray; + + // NOTE: Below IQM structures are not used but listed for reference + /* + typedef struct IQMAdjacency { + unsigned int triangle[3]; + } IQMAdjacency; typedef struct IQMPose { int parent; @@ -2960,19 +2969,11 @@ static Model LoadIQM(const char *fileName) 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 @@ -3028,12 +3029,12 @@ static Model LoadIQM(const char *fileName) } // Meshes data processing - imesh = malloc(sizeof(IQMMesh)*iqm.num_meshes); + imesh = RL_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(model.meshCount*sizeof(Mesh)); + model.meshes = RL_MALLOC(model.meshCount*sizeof(Mesh)); char name[MESH_NAME_LENGTH]; @@ -3043,24 +3044,24 @@ static Model LoadIQM(const char *fileName) 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)*model.meshes[i].vertexCount*3); // Default vertex positions - model.meshes[i].normals = malloc(sizeof(float)*model.meshes[i].vertexCount*3); // Default vertex normals - model.meshes[i].texcoords = malloc(sizeof(float)*model.meshes[i].vertexCount*2); // Default vertex texcoords + model.meshes[i].vertices = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*3); // Default vertex positions + model.meshes[i].normals = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*3); // Default vertex normals + model.meshes[i].texcoords = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*2); // Default vertex texcoords - model.meshes[i].boneIds = malloc(sizeof(int)*model.meshes[i].vertexCount*4); // Up-to 4 bones supported! - model.meshes[i].boneWeights = malloc(sizeof(float)*model.meshes[i].vertexCount*4); // Up-to 4 bones supported! + model.meshes[i].boneIds = RL_MALLOC(sizeof(int)*model.meshes[i].vertexCount*4); // Up-to 4 bones supported! + model.meshes[i].boneWeights = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*4); // Up-to 4 bones supported! model.meshes[i].triangleCount = imesh[i].num_triangles; - model.meshes[i].indices = malloc(sizeof(unsigned short)*model.meshes[i].triangleCount*3); + model.meshes[i].indices = RL_MALLOC(sizeof(unsigned short)*model.meshes[i].triangleCount*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)*model.meshes[i].vertexCount*3); - model.meshes[i].animNormals = malloc(sizeof(float)*model.meshes[i].vertexCount*3); + model.meshes[i].animVertices = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*3); + model.meshes[i].animNormals = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*3); } // Triangles data processing - tri = malloc(sizeof(IQMTriangle)*iqm.num_triangles); + tri = RL_MALLOC(sizeof(IQMTriangle)*iqm.num_triangles); fseek(iqmFile, iqm.ofs_triangles, SEEK_SET); fread(tri, sizeof(IQMTriangle)*iqm.num_triangles, 1, iqmFile); @@ -3079,7 +3080,7 @@ static Model LoadIQM(const char *fileName) } // Vertex arrays data processing - va = malloc(sizeof(IQMVertexArray)*iqm.num_vertexarrays); + va = RL_MALLOC(sizeof(IQMVertexArray)*iqm.num_vertexarrays); fseek(iqmFile, iqm.ofs_vertexarrays, SEEK_SET); fread(va, sizeof(IQMVertexArray)*iqm.num_vertexarrays, 1, iqmFile); @@ -3089,7 +3090,7 @@ static Model LoadIQM(const char *fileName) { case IQM_POSITION: { - vertex = malloc(sizeof(float)*iqm.num_vertexes*3); + vertex = RL_MALLOC(sizeof(float)*iqm.num_vertexes*3); fseek(iqmFile, va[i].offset, SEEK_SET); fread(vertex, sizeof(float)*iqm.num_vertexes*3, 1, iqmFile); @@ -3106,7 +3107,7 @@ static Model LoadIQM(const char *fileName) } break; case IQM_NORMAL: { - normal = malloc(sizeof(float)*iqm.num_vertexes*3); + normal = RL_MALLOC(sizeof(float)*iqm.num_vertexes*3); fseek(iqmFile, va[i].offset, SEEK_SET); fread(normal, sizeof(float)*iqm.num_vertexes*3, 1, iqmFile); @@ -3123,7 +3124,7 @@ static Model LoadIQM(const char *fileName) } break; case IQM_TEXCOORD: { - text = malloc(sizeof(float)*iqm.num_vertexes*2); + text = RL_MALLOC(sizeof(float)*iqm.num_vertexes*2); fseek(iqmFile, va[i].offset, SEEK_SET); fread(text, sizeof(float)*iqm.num_vertexes*2, 1, iqmFile); @@ -3139,7 +3140,7 @@ static Model LoadIQM(const char *fileName) } break; case IQM_BLENDINDEXES: { - blendi = malloc(sizeof(char)*iqm.num_vertexes*4); + blendi = RL_MALLOC(sizeof(char)*iqm.num_vertexes*4); fseek(iqmFile, va[i].offset, SEEK_SET); fread(blendi, sizeof(char)*iqm.num_vertexes*4, 1, iqmFile); @@ -3155,7 +3156,7 @@ static Model LoadIQM(const char *fileName) } break; case IQM_BLENDWEIGHTS: { - blendw = malloc(sizeof(unsigned char)*iqm.num_vertexes*4); + blendw = RL_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); @@ -3173,13 +3174,13 @@ static Model LoadIQM(const char *fileName) } // Bones (joints) data processing - ijoint = malloc(sizeof(IQMJoint)*iqm.num_joints); + ijoint = RL_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); + model.bones = RL_MALLOC(sizeof(BoneInfo)*iqm.num_joints); + model.bindPose = RL_MALLOC(sizeof(Transform)*iqm.num_joints); for (int i = 0; i < iqm.num_joints; i++) { @@ -3216,15 +3217,15 @@ static Model LoadIQM(const char *fileName) } fclose(iqmFile); - free(imesh); - free(tri); - free(va); - free(vertex); - free(normal); - free(text); - free(blendi); - free(blendw); - free(ijoint); + RL_FREE(imesh); + RL_FREE(tri); + RL_FREE(va); + RL_FREE(vertex); + RL_FREE(normal); + RL_FREE(text); + RL_FREE(blendi); + RL_FREE(blendw); + RL_FREE(ijoint); return model; } @@ -3249,7 +3250,7 @@ static Model LoadGLTF(const char *fileName) int size = ftell(gltfFile); fseek(gltfFile, 0, SEEK_SET); - void *buffer = malloc(size); + void *buffer = RL_MALLOC(size); fread(buffer, size, 1, gltfFile); fclose(gltfFile); @@ -3259,7 +3260,7 @@ static Model LoadGLTF(const char *fileName) cgltf_data *data; cgltf_result result = cgltf_parse(&options, buffer, size, &data); - free(buffer); + RL_FREE(buffer); if (result == cgltf_result_success) { @@ -3270,7 +3271,7 @@ static Model LoadGLTF(const char *fileName) // Process glTF data and map to model model.meshCount = data->meshes_count; - model.meshes = malloc(model.meshCount*sizeof(Mesh)); + model.meshes = RL_MALLOC(model.meshCount*sizeof(Mesh)); for (int i = 0; i < model.meshCount; i++) { @@ -3282,11 +3283,11 @@ static Model LoadGLTF(const char *fileName) model.meshes[i].triangleCount = data->meshes[i].primitives_count; // data.meshes[i].weights not used (array of weights to be applied to the Morph Targets) - model.meshes[i].vertices = malloc(sizeof(float)*model.meshes[i].vertexCount*3); // Default vertex positions - model.meshes[i].normals = malloc(sizeof(float)*model.meshes[i].vertexCount*3); // Default vertex normals - model.meshes[i].texcoords = malloc(sizeof(float)*model.meshes[i].vertexCount*2); // Default vertex texcoords + model.meshes[i].vertices = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*3); // Default vertex positions + model.meshes[i].normals = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*3); // Default vertex normals + model.meshes[i].texcoords = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*2); // Default vertex texcoords - model.meshes[i].indices = malloc(sizeof(unsigned short)*model.meshes[i].triangleCount*3); + model.meshes[i].indices = RL_MALLOC(sizeof(unsigned short)*model.meshes[i].triangleCount*3); } } diff --git a/src/raudio.c b/src/raudio.c index 636d15b8..9108a903 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -567,7 +567,7 @@ void SetMasterVolume(float volume) // Create a new audio buffer. Initially filled with silence AudioBuffer *CreateAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 bufferSizeInFrames, AudioBufferUsage usage) { - AudioBuffer *audioBuffer = (AudioBuffer *)calloc(sizeof(*audioBuffer) + (bufferSizeInFrames*channels*ma_get_bytes_per_sample(format)), 1); + AudioBuffer *audioBuffer = (AudioBuffer *)RL_CALLOC(sizeof(*audioBuffer) + (bufferSizeInFrames*channels*ma_get_bytes_per_sample(format)), 1); if (audioBuffer == NULL) { TraceLog(LOG_ERROR, "CreateAudioBuffer() : Failed to allocate memory for audio buffer"); @@ -591,7 +591,7 @@ AudioBuffer *CreateAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 s if (result != MA_SUCCESS) { TraceLog(LOG_ERROR, "CreateAudioBuffer() : Failed to create data conversion pipeline"); - free(audioBuffer); + RL_FREE(audioBuffer); return NULL; } @@ -623,7 +623,7 @@ void DeleteAudioBuffer(AudioBuffer *audioBuffer) } UntrackAudioBuffer(audioBuffer); - free(audioBuffer); + RL_FREE(audioBuffer); } // Check if an audio buffer is playing @@ -863,7 +863,7 @@ Sound LoadSoundFromWave(Wave wave) // Unload wave data void UnloadWave(Wave wave) { - if (wave.data != NULL) free(wave.data); + if (wave.data != NULL) RL_FREE(wave.data); TraceLog(LOG_INFO, "Unloaded wave data from RAM"); } @@ -1017,7 +1017,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) return; } - void *data = malloc(frameCount*channels*(sampleSize/8)); + void *data = RL_MALLOC(frameCount*channels*(sampleSize/8)); frameCount = (ma_uint32)ma_convert_frames(data, formatOut, channels, sampleRate, wave->data, formatIn, wave->channels, wave->sampleRate, frameCountIn); if (frameCount == 0) @@ -1030,7 +1030,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) wave->sampleSize = sampleSize; wave->sampleRate = sampleRate; wave->channels = channels; - free(wave->data); + RL_FREE(wave->data); wave->data = data; } @@ -1039,7 +1039,7 @@ Wave WaveCopy(Wave wave) { Wave newWave = { 0 }; - newWave.data = malloc(wave.sampleCount*wave.sampleSize/8*wave.channels); + newWave.data = RL_MALLOC(wave.sampleCount*wave.sampleSize/8*wave.channels); if (newWave.data != NULL) { @@ -1064,11 +1064,11 @@ void WaveCrop(Wave *wave, int initSample, int finalSample) { int sampleCount = finalSample - initSample; - void *data = malloc(sampleCount*wave->sampleSize/8*wave->channels); + void *data = RL_MALLOC(sampleCount*wave->sampleSize/8*wave->channels); memcpy(data, (unsigned char *)wave->data + (initSample*wave->channels*wave->sampleSize/8), sampleCount*wave->channels*wave->sampleSize/8); - free(wave->data); + RL_FREE(wave->data); wave->data = data; } else TraceLog(LOG_WARNING, "Wave crop range out of bounds"); @@ -1078,7 +1078,7 @@ void WaveCrop(Wave *wave, int initSample, int finalSample) // NOTE: Returned sample values are normalized to range [-1..1] float *GetWaveData(Wave wave) { - float *samples = (float *)malloc(wave.sampleCount*wave.channels*sizeof(float)); + float *samples = (float *)RL_MALLOC(wave.sampleCount*wave.channels*sizeof(float)); for (unsigned int i = 0; i < wave.sampleCount; i++) { @@ -1100,7 +1100,7 @@ float *GetWaveData(Wave wave) // Load music stream from file Music LoadMusicStream(const char *fileName) { - Music music = (MusicData *)malloc(sizeof(MusicData)); + Music music = (MusicData *)RL_MALLOC(sizeof(MusicData)); bool musicLoaded = true; #if defined(SUPPORT_FILEFORMAT_OGG) @@ -1228,7 +1228,7 @@ Music LoadMusicStream(const char *fileName) if (false) {} #endif #if defined(SUPPORT_FILEFORMAT_FLAC) - else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free(music->ctxFlac); + else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_RL_FREE(music->ctxFlac); #endif #if defined(SUPPORT_FILEFORMAT_MP3) else if (music->ctxType == MUSIC_AUDIO_MP3) drmp3_uninit(&music->ctxMp3); @@ -1240,7 +1240,7 @@ Music LoadMusicStream(const char *fileName) else if (music->ctxType == MUSIC_MODULE_MOD) jar_mod_unload(&music->ctxMod); #endif - free(music); + RL_FREE(music); music = NULL; TraceLog(LOG_WARNING, "[%s] Music file could not be opened", fileName); @@ -1262,7 +1262,7 @@ void UnloadMusicStream(Music music) if (false) {} #endif #if defined(SUPPORT_FILEFORMAT_FLAC) - else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free(music->ctxFlac); + else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_RL_FREE(music->ctxFlac); #endif #if defined(SUPPORT_FILEFORMAT_MP3) else if (music->ctxType == MUSIC_AUDIO_MP3) drmp3_uninit(&music->ctxMp3); @@ -1274,7 +1274,7 @@ void UnloadMusicStream(Music music) else if (music->ctxType == MUSIC_MODULE_MOD) jar_mod_unload(&music->ctxMod); #endif - free(music); + RL_FREE(music); } // Start music playing (open stream) @@ -1357,7 +1357,7 @@ void UpdateMusicStream(Music music) unsigned int subBufferSizeInFrames = ((AudioBuffer *)music->stream.audioBuffer)->bufferSizeInFrames/2; // NOTE: Using dynamic allocation because it could require more than 16KB - void *pcm = calloc(subBufferSizeInFrames*music->stream.channels*music->stream.sampleSize/8, 1); + void *pcm = RL_CALLOC(subBufferSizeInFrames*music->stream.channels*music->stream.sampleSize/8, 1); int samplesCount = 0; // Total size of data steamed in L+R samples for xm floats, individual L or R for ogg shorts @@ -1427,7 +1427,7 @@ void UpdateMusicStream(Music music) } // Free allocated pcm data - free(pcm); + RL_FREE(pcm); // Reset audio stream for looping if (streamEnding) @@ -1750,7 +1750,7 @@ static Wave LoadWAV(const char *fileName) else { // Allocate memory for data - wave.data = malloc(wavData.subChunkSize); + wave.data = RL_MALLOC(wavData.subChunkSize); // Read in the sound data into the soundData variable fread(wave.data, wavData.subChunkSize, 1, wavFile); @@ -1891,7 +1891,7 @@ static Wave LoadOGG(const char *fileName) float totalSeconds = stb_vorbis_stream_length_in_seconds(oggFile); if (totalSeconds > 10) TraceLog(LOG_WARNING, "[%s] Ogg audio length is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds); - wave.data = (short *)malloc(wave.sampleCount*wave.channels*sizeof(short)); + wave.data = (short *)RL_MALLOC(wave.sampleCount*wave.channels*sizeof(short)); // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!) int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, (short *)wave.data, wave.sampleCount*wave.channels); diff --git a/src/raudio.h b/src/raudio.h index e8701814..f71a3083 100644 --- a/src/raudio.h +++ b/src/raudio.h @@ -56,7 +56,16 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -//... +// Allow custom memory allocators +#ifndef RL_MALLOC + #define RL_MALLOC(sz) malloc(sz) +#endif +#ifndef RL_CALLOC + #define RL_CALLOC(n,sz) calloc(n,sz) +#endif +#ifndef RL_FREE + #define RL_FREE(p) free(p) +#endif //---------------------------------------------------------------------------------- // Types and Structures Definition diff --git a/src/raylib.h b/src/raylib.h index 424a9dd7..43260e06 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -99,6 +99,17 @@ // Shader and material limits #define MAX_SHADER_LOCATIONS 32 // Maximum number of predefined locations stored in shader struct #define MAX_MATERIAL_MAPS 12 // Maximum number of texture maps stored in shader struct + +// Allow custom memory allocators +#ifndef RL_MALLOC + #define RL_MALLOC(sz) malloc(sz) +#endif +#ifndef RL_CALLOC + #define RL_CALLOC(n,sz) calloc(n,sz) +#endif +#ifndef RL_FREE + #define RL_FREE(p) free(p) +#endif // NOTE: MSC C++ compiler does not support compound literals (C99 feature) // Plain structures in C++ (without constructors) can be initialized from { } initializers. diff --git a/src/rlgl.h b/src/rlgl.h index 0356858a..c2ddd028 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -1492,7 +1492,7 @@ void rlglInit(int width, int height) glGetIntegerv(GL_NUM_EXTENSIONS, &numExt); #if defined(_MSC_VER) - const char **extList = malloc(sizeof(const char *)*numExt); + const char **extList = RL_MALLOC(sizeof(const char *)*numExt); #else const char *extList[numExt]; #endif @@ -1504,7 +1504,7 @@ void rlglInit(int width, int height) // NOTE: We have to duplicate string because glGetString() returns a const string int len = strlen(extensions) + 1; - char *extensionsDup = (char *)malloc(len); + char *extensionsDup = (char *)RL_MALLOC(len); strcpy(extensionsDup, extensions); // NOTE: String could be splitted using strtok() function (string.h) @@ -1520,7 +1520,7 @@ void rlglInit(int width, int height) extList[numExt] = strtok(NULL, " "); } - free(extensionsDup); // Duplicated string must be deallocated + RL_FREE(extensionsDup); // Duplicated string must be deallocated numExt -= 1; #endif @@ -1595,7 +1595,7 @@ void rlglInit(int width, int height) } #if defined(_WIN32) && defined(_MSC_VER) - free(extList); + RL_FREE(extList); #endif #if defined(GRAPHICS_API_OPENGL_ES2) @@ -1640,7 +1640,7 @@ void rlglInit(int width, int height) transformMatrix = MatrixIdentity(); // Init draw calls tracking system - draws = (DrawCall *)malloc(sizeof(DrawCall)*MAX_DRAWCALL_REGISTERED); + draws = (DrawCall *)RL_MALLOC(sizeof(DrawCall)*MAX_DRAWCALL_REGISTERED); for (int i = 0; i < MAX_DRAWCALL_REGISTERED; i++) { @@ -1710,7 +1710,7 @@ void rlglClose(void) TraceLog(LOG_INFO, "[TEX ID %i] Unloaded texture data (base white texture) from VRAM", defaultTextureId); - free(draws); + RL_FREE(draws); #endif } @@ -2300,7 +2300,7 @@ void rlGenerateMipmaps(Texture2D *texture) } texture->mipmaps = mipmapCount + 1; - free(data); // Once mipmaps have been generated and data has been uploaded to GPU VRAM, we can discard RAM data + RL_FREE(data); // Once mipmaps have been generated and data has been uploaded to GPU VRAM, we can discard RAM data TraceLog(LOG_WARNING, "[TEX ID %i] Mipmaps [%i] generated manually on CPU side", texture->id, texture->mipmaps); } @@ -2735,18 +2735,18 @@ void rlDrawMesh(Mesh mesh, Material material, Matrix transform) // Unload mesh data from CPU and GPU void rlUnloadMesh(Mesh *mesh) { - free(mesh->vertices); - free(mesh->texcoords); - free(mesh->normals); - free(mesh->colors); - free(mesh->tangents); - free(mesh->texcoords2); - free(mesh->indices); - - free(mesh->animVertices); - free(mesh->animNormals); - free(mesh->boneWeights); - free(mesh->boneIds); + RL_FREE(mesh->vertices); + RL_FREE(mesh->texcoords); + RL_FREE(mesh->normals); + RL_FREE(mesh->colors); + RL_FREE(mesh->tangents); + RL_FREE(mesh->texcoords2); + RL_FREE(mesh->indices); + + RL_FREE(mesh->animVertices); + RL_FREE(mesh->animNormals); + RL_FREE(mesh->boneWeights); + RL_FREE(mesh->boneIds); rlDeleteBuffers(mesh->vboId[0]); // vertex rlDeleteBuffers(mesh->vboId[1]); // texcoords @@ -2762,14 +2762,14 @@ void rlUnloadMesh(Mesh *mesh) // Read screen pixel data (color buffer) unsigned char *rlReadScreenPixels(int width, int height) { - unsigned char *screenData = (unsigned char *)calloc(width*height*4, sizeof(unsigned char)); + unsigned char *screenData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char)); // NOTE 1: glReadPixels returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer // NOTE 2: We are getting alpha channel! Be careful, it can be transparent if not cleared properly! glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, screenData); // Flip image vertically! - unsigned char *imgData = (unsigned char *)malloc(width*height*sizeof(unsigned char)*4); + unsigned char *imgData = (unsigned char *)RL_MALLOC(width*height*sizeof(unsigned char)*4); for (int y = height - 1; y >= 0; y--) { @@ -2783,7 +2783,7 @@ unsigned char *rlReadScreenPixels(int width, int height) } } - free(screenData); + RL_FREE(screenData); return imgData; // NOTE: image data should be freed } @@ -2815,7 +2815,7 @@ void *rlReadTexturePixels(Texture2D texture) if ((glInternalFormat != -1) && (texture.format < COMPRESSED_DXT1_RGB)) { - pixels = (unsigned char *)malloc(size); + pixels = (unsigned char *)RL_MALLOC(size); glGetTexImage(GL_TEXTURE_2D, 0, glFormat, glType, pixels); } else TraceLog(LOG_WARNING, "Texture data retrieval not suported for pixel format"); @@ -2841,7 +2841,7 @@ void *rlReadTexturePixels(Texture2D texture) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.id, 0); // Allocate enough memory to read back our texture data - pixels = (unsigned char *)malloc(GetPixelDataSize(texture.width, texture.height, texture.format)); + pixels = (unsigned char *)RL_MALLOC(GetPixelDataSize(texture.width, texture.height, texture.format)); // Get OpenGL internal formats and data type from our texture format unsigned int glInternalFormat, glFormat, glType; @@ -2911,7 +2911,7 @@ char *LoadText(const char *fileName) if (size > 0) { - text = (char *)malloc(sizeof(char)*(size + 1)); + text = (char *)RL_MALLOC(sizeof(char)*(size + 1)); int count = fread(text, sizeof(char), size, textFile); text[count] = '\0'; } @@ -2938,8 +2938,8 @@ Shader LoadShader(const char *vsFileName, const char *fsFileName) shader = LoadShaderCode(vShaderStr, fShaderStr); - if (vShaderStr != NULL) free(vShaderStr); - if (fShaderStr != NULL) free(fShaderStr); + if (vShaderStr != NULL) RL_FREE(vShaderStr); + if (fShaderStr != NULL) RL_FREE(fShaderStr); return shader; } @@ -3758,7 +3758,7 @@ static unsigned int CompileShader(const char *shaderStr, int type) glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); #if defined(_MSC_VER) - char *log = malloc(maxLength); + char *log = RL_MALLOC(maxLength); #else char log[maxLength]; #endif @@ -3767,7 +3767,7 @@ static unsigned int CompileShader(const char *shaderStr, int type) TraceLog(LOG_INFO, "%s", log); #if defined(_MSC_VER) - free(log); + RL_FREE(log); #endif } else TraceLog(LOG_INFO, "[SHDR ID %i] Shader compiled successfully", shader); @@ -3814,7 +3814,7 @@ static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShad glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); #if defined(_MSC_VER) - char *log = malloc(maxLength); + char *log = RL_MALLOC(maxLength); #else char log[maxLength]; #endif @@ -3823,7 +3823,7 @@ static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShad TraceLog(LOG_INFO, "%s", log); #if defined(_MSC_VER) - free(log); + RL_FREE(log); #endif glDeleteProgram(program); @@ -3984,13 +3984,13 @@ static void LoadBuffersDefault(void) //-------------------------------------------------------------------------------------------- for (int i = 0; i < MAX_BATCH_BUFFERING; i++) { - vertexData[i].vertices = (float *)malloc(sizeof(float)*3*4*MAX_BATCH_ELEMENTS); // 3 float by vertex, 4 vertex by quad - vertexData[i].texcoords = (float *)malloc(sizeof(float)*2*4*MAX_BATCH_ELEMENTS); // 2 float by texcoord, 4 texcoord by quad - vertexData[i].colors = (unsigned char *)malloc(sizeof(unsigned char)*4*4*MAX_BATCH_ELEMENTS); // 4 float by color, 4 colors by quad + vertexData[i].vertices = (float *)RL_MALLOC(sizeof(float)*3*4*MAX_BATCH_ELEMENTS); // 3 float by vertex, 4 vertex by quad + vertexData[i].texcoords = (float *)RL_MALLOC(sizeof(float)*2*4*MAX_BATCH_ELEMENTS); // 2 float by texcoord, 4 texcoord by quad + vertexData[i].colors = (unsigned char *)RL_MALLOC(sizeof(unsigned char)*4*4*MAX_BATCH_ELEMENTS); // 4 float by color, 4 colors by quad #if defined(GRAPHICS_API_OPENGL_33) - vertexData[i].indices = (unsigned int *)malloc(sizeof(unsigned int)*6*MAX_BATCH_ELEMENTS); // 6 int by quad (indices) + vertexData[i].indices = (unsigned int *)RL_MALLOC(sizeof(unsigned int)*6*MAX_BATCH_ELEMENTS); // 6 int by quad (indices) #elif defined(GRAPHICS_API_OPENGL_ES2) - vertexData[i].indices = (unsigned short *)malloc(sizeof(unsigned short)*6*MAX_BATCH_ELEMENTS); // 6 int by quad (indices) + vertexData[i].indices = (unsigned short *)RL_MALLOC(sizeof(unsigned short)*6*MAX_BATCH_ELEMENTS); // 6 int by quad (indices) #endif for (int j = 0; j < (3*4*MAX_BATCH_ELEMENTS); j++) vertexData[i].vertices[j] = 0.0f; @@ -4266,10 +4266,10 @@ static void UnloadBuffersDefault(void) if (vaoSupported) glDeleteVertexArrays(1, &vertexData[i].vaoId); // Free vertex arrays memory from CPU (RAM) - free(vertexData[i].vertices); - free(vertexData[i].texcoords); - free(vertexData[i].colors); - free(vertexData[i].indices); + RL_FREE(vertexData[i].vertices); + RL_FREE(vertexData[i].texcoords); + RL_FREE(vertexData[i].colors); + RL_FREE(vertexData[i].indices); } } @@ -4444,7 +4444,7 @@ static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight) // Generate mipmaps // NOTE: Every mipmap data is stored after data - Color *image = (Color *)malloc(width*height*sizeof(Color)); + Color *image = (Color *)RL_MALLOC(width*height*sizeof(Color)); Color *mipmap = NULL; int offset = 0; int j = 0; @@ -4481,13 +4481,13 @@ static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight) j++; } - free(image); + RL_FREE(image); image = mipmap; mipmap = NULL; } - free(mipmap); // free mipmap data + RL_FREE(mipmap); // free mipmap data return mipmapCount; } @@ -4501,7 +4501,7 @@ static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight) int width = srcWidth/2; int height = srcHeight/2; - Color *mipmap = (Color *)malloc(width*height*sizeof(Color)); + Color *mipmap = (Color *)RL_MALLOC(width*height*sizeof(Color)); // Scaling algorithm works perfectly (box-filter) for (int y = 0; y < height; y++) diff --git a/src/text.c b/src/text.c index bd9e09f0..22bd7659 100644 --- a/src/text.c +++ b/src/text.c @@ -174,7 +174,7 @@ extern void LoadDefaultFont(void) int imWidth = 128; int imHeight = 128; - Color *imagePixels = (Color *)malloc(imWidth*imHeight*sizeof(Color)); + Color *imagePixels = (Color *)RL_MALLOC(imWidth*imHeight*sizeof(Color)); for (int i = 0; i < imWidth*imHeight; i++) imagePixels[i] = BLANK; // Initialize array @@ -196,7 +196,7 @@ extern void LoadDefaultFont(void) Image image = LoadImageEx(imagePixels, imWidth, imHeight); ImageFormat(&image, UNCOMPRESSED_GRAY_ALPHA); - free(imagePixels); + RL_FREE(imagePixels); defaultFont.texture = LoadTextureFromImage(image); UnloadImage(image); @@ -206,7 +206,7 @@ extern void LoadDefaultFont(void) // Allocate space for our characters info data // NOTE: This memory should be freed at end! --> CloseWindow() - defaultFont.chars = (CharInfo *)malloc(defaultFont.charsCount*sizeof(CharInfo)); + defaultFont.chars = (CharInfo *)RL_MALLOC(defaultFont.charsCount*sizeof(CharInfo)); int currentLine = 0; int currentPosX = charsDivisor; @@ -249,7 +249,7 @@ extern void LoadDefaultFont(void) extern void UnloadDefaultFont(void) { UnloadTexture(defaultFont.texture); - free(defaultFont.chars); + RL_FREE(defaultFont.chars); } #endif // SUPPORT_DEFAULT_FONT @@ -407,7 +407,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar) // Create a new image with the processed color data (key color replaced by BLANK) Image fontClear = LoadImageEx(pixels, image.width, image.height); - free(pixels); // Free pixels array memory + RL_FREE(pixels); // Free pixels array memory // Create spritefont with all data parsed from image Font spriteFont = { 0 }; @@ -419,7 +419,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar) // We got tempCharValues and tempCharsRecs populated with chars data // Now we move temp data to sized charValues and charRecs arrays - spriteFont.chars = (CharInfo *)malloc(spriteFont.charsCount*sizeof(CharInfo)); + spriteFont.chars = (CharInfo *)RL_MALLOC(spriteFont.charsCount*sizeof(CharInfo)); for (int i = 0; i < spriteFont.charsCount; i++) { @@ -466,7 +466,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c long size = ftell(fontFile); // Get file size fseek(fontFile, 0, SEEK_SET); // Reset file pointer - unsigned char *fontBuffer = (unsigned char *)malloc(size); + unsigned char *fontBuffer = (unsigned char *)RL_MALLOC(size); fread(fontBuffer, size, 1, fontFile); fclose(fontFile); @@ -491,12 +491,12 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c int genFontChars = false; if (fontChars == NULL) { - fontChars = (int *)malloc(charsCount*sizeof(int)); + fontChars = (int *)RL_MALLOC(charsCount*sizeof(int)); for (int i = 0; i < charsCount; i++) fontChars[i] = i + 32; genFontChars = true; } - chars = (CharInfo *)malloc(charsCount*sizeof(CharInfo)); + chars = (CharInfo *)RL_MALLOC(charsCount*sizeof(CharInfo)); // NOTE: Using simple packaging, one char after another for (int i = 0; i < charsCount; i++) @@ -540,8 +540,8 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c chars[i].advanceX *= scaleFactor; } - free(fontBuffer); - if (genFontChars) free(fontChars); + RL_FREE(fontBuffer); + if (genFontChars) RL_FREE(fontChars); } else TraceLog(LOG_WARNING, "[%s] TTF file could not be opened", fileName); #else @@ -572,7 +572,7 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi atlas.width = imageSize; // Atlas bitmap width atlas.height = imageSize; // Atlas bitmap height - atlas.data = (unsigned char *)calloc(1, atlas.width*atlas.height); // Create a bitmap to store characters (8 bpp) + atlas.data = (unsigned char *)RL_CALLOC(1, atlas.width*atlas.height); // Create a bitmap to store characters (8 bpp) atlas.format = UNCOMPRESSED_GRAYSCALE; atlas.mipmaps = 1; @@ -619,11 +619,11 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi { TraceLog(LOG_DEBUG, "Using Skyline packing algorythm!"); - stbrp_context *context = (stbrp_context *)malloc(sizeof(*context)); - stbrp_node *nodes = (stbrp_node *)malloc(charsCount*sizeof(*nodes)); + stbrp_context *context = (stbrp_context *)RL_MALLOC(sizeof(*context)); + stbrp_node *nodes = (stbrp_node *)RL_MALLOC(charsCount*sizeof(*nodes)); stbrp_init_target(context, atlas.width, atlas.height, nodes, charsCount); - stbrp_rect *rects = (stbrp_rect *)malloc(charsCount*sizeof(stbrp_rect)); + stbrp_rect *rects = (stbrp_rect *)RL_MALLOC(charsCount*sizeof(stbrp_rect)); // Fill rectangles for packaging for (int i = 0; i < charsCount; i++) @@ -655,16 +655,16 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi else TraceLog(LOG_WARNING, "Character could not be packed: %i", i); } - free(rects); - free(nodes); - free(context); + RL_FREE(rects); + RL_FREE(nodes); + RL_FREE(context); } // TODO: Crop image if required for smaller size // Convert image data from GRAYSCALE to GRAY_ALPHA // WARNING: ImageAlphaMask(&atlas, atlas) does not work in this case, requires manual operation - unsigned char *dataGrayAlpha = (unsigned char *)malloc(imageSize*imageSize*sizeof(unsigned char)*2); // Two channels + unsigned char *dataGrayAlpha = (unsigned char *)RL_MALLOC(imageSize*imageSize*sizeof(unsigned char)*2); // Two channels for (int i = 0, k = 0; i < atlas.width*atlas.height; i++, k += 2) { @@ -672,7 +672,7 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi dataGrayAlpha[k + 1] = ((unsigned char *)atlas.data)[i]; } - free(atlas.data); + RL_FREE(atlas.data); atlas.data = dataGrayAlpha; atlas.format = UNCOMPRESSED_GRAY_ALPHA; @@ -688,10 +688,10 @@ void UnloadFont(Font font) { for (int i = 0; i < font.charsCount; i++) { - free(font.chars[i].data); + RL_FREE(font.chars[i].data); } UnloadTexture(font.texture); - free(font.chars); + RL_FREE(font.chars); TraceLog(LOG_DEBUG, "Unloaded sprite font data"); } @@ -1214,7 +1214,7 @@ const char *TextReplace(char *text, const char *replace, const char *by) for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen; // Allocate returning string and point temp to it - temp = result = malloc(strlen(text) + (byLen - replaceLen)*count + 1); + temp = result = RL_MALLOC(strlen(text) + (byLen - replaceLen)*count + 1); if (!result) return NULL; // Memory could not be allocated @@ -1245,7 +1245,7 @@ const char *TextInsert(const char *text, const char *insert, int position) int textLen = strlen(text); int insertLen = strlen(insert); - char *result = (char *)malloc(textLen + insertLen + 1); + char *result = (char *)RL_MALLOC(textLen + insertLen + 1); for (int i = 0; i < position; i++) result[i] = text[i]; for (int i = position; i < insertLen + position; i++) result[i] = insert[i]; @@ -1477,7 +1477,7 @@ static Font LoadBMFont(const char *fileName) } // NOTE: We need some extra space to avoid memory corruption on next allocations! - texPath = malloc(strlen(fileName) - strlen(lastSlash) + strlen(texFileName) + 4); + texPath = RL_MALLOC(strlen(fileName) - strlen(lastSlash) + strlen(texFileName) + 4); // NOTE: strcat() and strncat() required a '\0' terminated string to work! *texPath = '\0'; @@ -1501,13 +1501,13 @@ static Font LoadBMFont(const char *fileName) else font.texture = LoadTextureFromImage(imFont); UnloadImage(imFont); - free(texPath); + RL_FREE(texPath); // Fill font characters info data font.baseSize = fontSize; font.charsCount = charsCount; - font.chars = (CharInfo *)malloc(charsCount*sizeof(CharInfo)); + font.chars = (CharInfo *)RL_MALLOC(charsCount*sizeof(CharInfo)); int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX; diff --git a/src/textures.c b/src/textures.c index 7059fabb..eb743026 100644 --- a/src/textures.c +++ b/src/textures.c @@ -112,9 +112,14 @@ defined(SUPPORT_FILEFORMAT_GIF) || \ defined(SUPPORT_FILEFORMAT_PIC) || \ defined(SUPPORT_FILEFORMAT_HDR)) + + #define STBI_MALLOC RL_MALLOC + #define STBI_FREE RL_FREE + #define STBI_REALLOC(p,newsz) realloc(p,newsz) + #define STB_IMAGE_IMPLEMENTATION - #include "external/stb_image.h" // Required for: stbi_load_from_file() - // NOTE: Used to read image data (multiple formats support) + #include "external/stb_image.h" // Required for: stbi_load_from_file() + // NOTE: Used to read image data (multiple formats support) #endif #if defined(SUPPORT_IMAGE_EXPORT) @@ -305,7 +310,7 @@ Image LoadImageEx(Color *pixels, int width, int height) int k = 0; - image.data = (unsigned char *)malloc(image.width*image.height*4*sizeof(unsigned char)); + image.data = (unsigned char *)RL_MALLOC(image.width*image.height*4*sizeof(unsigned char)); for (int i = 0; i < image.width*image.height*4; i += 4) { @@ -353,7 +358,7 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int unsigned int size = GetPixelDataSize(width, height, format); - image.data = malloc(size); // Allocate required memory in bytes + image.data = RL_MALLOC(size); // Allocate required memory in bytes // NOTE: fread() returns num read elements instead of bytes, // to get bytes we need to read (1 byte size, elements) instead of (x byte size, 1 element) @@ -364,7 +369,7 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int { TraceLog(LOG_WARNING, "[%s] RAW image data can not be read, wrong requested format or size", fileName); - free(image.data); + RL_FREE(image.data); } else { @@ -425,7 +430,7 @@ RenderTexture2D LoadRenderTexture(int width, int height) // Unload image from CPU memory (RAM) void UnloadImage(Image image) { - free(image.data); + RL_FREE(image.data); } // Unload texture from GPU memory (VRAM) @@ -448,7 +453,7 @@ void UnloadRenderTexture(RenderTexture2D target) // Get pixel data from image in the form of Color struct array Color *GetImageData(Image image) { - Color *pixels = (Color *)malloc(image.width*image.height*sizeof(Color)); + Color *pixels = (Color *)RL_MALLOC(image.width*image.height*sizeof(Color)); if (image.format >= COMPRESSED_DXT1_RGB) TraceLog(LOG_WARNING, "Pixel data retrieval not supported for compressed image formats"); else @@ -563,7 +568,7 @@ Color *GetImageData(Image image) // Get pixel data from image as Vector4 array (float normalized) Vector4 *GetImageDataNormalized(Image image) { - Vector4 *pixels = (Vector4 *)malloc(image.width*image.height*sizeof(Vector4)); + Vector4 *pixels = (Vector4 *)RL_MALLOC(image.width*image.height*sizeof(Vector4)); if (image.format >= COMPRESSED_DXT1_RGB) TraceLog(LOG_WARNING, "Pixel data retrieval not supported for compressed image formats"); else @@ -797,7 +802,7 @@ void ExportImage(Image image, const char *fileName) fclose(rawFile); } - free(imgData); + RL_FREE(imgData); #endif if (success != 0) TraceLog(LOG_INFO, "Image exported successfully: %s", fileName); @@ -863,7 +868,7 @@ Image ImageCopy(Image image) if (height < 1) height = 1; } - newImage.data = malloc(size); + newImage.data = RL_MALLOC(size); if (newImage.data != NULL) { @@ -896,7 +901,7 @@ void ImageToPOT(Image *image, Color fillColor) Color *pixelsPOT = NULL; // Generate POT array from NPOT data - pixelsPOT = (Color *)malloc(potWidth*potHeight*sizeof(Color)); + pixelsPOT = (Color *)RL_MALLOC(potWidth*potHeight*sizeof(Color)); for (int j = 0; j < potHeight; j++) { @@ -909,15 +914,15 @@ void ImageToPOT(Image *image, Color fillColor) TraceLog(LOG_WARNING, "Image converted to POT: (%ix%i) -> (%ix%i)", image->width, image->height, potWidth, potHeight); - free(pixels); // Free pixels data - free(image->data); // Free old image data + RL_FREE(pixels); // Free pixels data + RL_FREE(image->data); // Free old image data int format = image->format; // Store image data format to reconvert later // NOTE: Image size changes, new width and height *image = LoadImageEx(pixelsPOT, potWidth, potHeight); - free(pixelsPOT); // Free POT pixels data + RL_FREE(pixelsPOT); // Free POT pixels data ImageFormat(image, format); // Reconvert image to previous format } @@ -932,7 +937,7 @@ void ImageFormat(Image *image, int newFormat) { Vector4 *pixels = GetImageDataNormalized(*image); // Supports 8 to 32 bit per channel - free(image->data); // WARNING! We loose mipmaps data --> Regenerated at the end... + RL_FREE(image->data); // WARNING! We loose mipmaps data --> Regenerated at the end... image->data = NULL; image->format = newFormat; @@ -942,7 +947,7 @@ void ImageFormat(Image *image, int newFormat) { case UNCOMPRESSED_GRAYSCALE: { - image->data = (unsigned char *)malloc(image->width*image->height*sizeof(unsigned char)); + image->data = (unsigned char *)RL_MALLOC(image->width*image->height*sizeof(unsigned char)); for (int i = 0; i < image->width*image->height; i++) { @@ -952,7 +957,7 @@ void ImageFormat(Image *image, int newFormat) } break; case UNCOMPRESSED_GRAY_ALPHA: { - image->data = (unsigned char *)malloc(image->width*image->height*2*sizeof(unsigned char)); + image->data = (unsigned char *)RL_MALLOC(image->width*image->height*2*sizeof(unsigned char)); for (int i = 0; i < image->width*image->height*2; i += 2, k++) { @@ -963,7 +968,7 @@ void ImageFormat(Image *image, int newFormat) } break; case UNCOMPRESSED_R5G6B5: { - image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); + image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short)); unsigned char r = 0; unsigned char g = 0; @@ -981,7 +986,7 @@ void ImageFormat(Image *image, int newFormat) } break; case UNCOMPRESSED_R8G8B8: { - image->data = (unsigned char *)malloc(image->width*image->height*3*sizeof(unsigned char)); + image->data = (unsigned char *)RL_MALLOC(image->width*image->height*3*sizeof(unsigned char)); for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++) { @@ -994,7 +999,7 @@ void ImageFormat(Image *image, int newFormat) { #define ALPHA_THRESHOLD 50 - image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); + image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short)); unsigned char r = 0; unsigned char g = 0; @@ -1014,7 +1019,7 @@ void ImageFormat(Image *image, int newFormat) } break; case UNCOMPRESSED_R4G4B4A4: { - image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); + image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short)); unsigned char r = 0; unsigned char g = 0; @@ -1034,7 +1039,7 @@ void ImageFormat(Image *image, int newFormat) } break; case UNCOMPRESSED_R8G8B8A8: { - image->data = (unsigned char *)malloc(image->width*image->height*4*sizeof(unsigned char)); + image->data = (unsigned char *)RL_MALLOC(image->width*image->height*4*sizeof(unsigned char)); for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++) { @@ -1048,7 +1053,7 @@ void ImageFormat(Image *image, int newFormat) { // WARNING: Image is converted to GRAYSCALE eqeuivalent 32bit - image->data = (float *)malloc(image->width*image->height*sizeof(float)); + image->data = (float *)RL_MALLOC(image->width*image->height*sizeof(float)); for (int i = 0; i < image->width*image->height; i++) { @@ -1057,7 +1062,7 @@ void ImageFormat(Image *image, int newFormat) } break; case UNCOMPRESSED_R32G32B32: { - image->data = (float *)malloc(image->width*image->height*3*sizeof(float)); + image->data = (float *)RL_MALLOC(image->width*image->height*3*sizeof(float)); for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++) { @@ -1068,7 +1073,7 @@ void ImageFormat(Image *image, int newFormat) } break; case UNCOMPRESSED_R32G32B32A32: { - image->data = (float *)malloc(image->width*image->height*4*sizeof(float)); + image->data = (float *)RL_MALLOC(image->width*image->height*4*sizeof(float)); for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++) { @@ -1081,7 +1086,7 @@ void ImageFormat(Image *image, int newFormat) default: break; } - free(pixels); + RL_FREE(pixels); pixels = NULL; // In case original image had mipmaps, generate mipmaps for formated image @@ -1286,7 +1291,7 @@ void ImageCrop(Image *image, Rectangle crop) { // Start the cropping process Color *pixels = GetImageData(*image); // Get data as Color pixels array - Color *cropPixels = (Color *)malloc((int)crop.width*(int)crop.height*sizeof(Color)); + Color *cropPixels = (Color *)RL_MALLOC((int)crop.width*(int)crop.height*sizeof(Color)); for (int j = (int)crop.y; j < (int)(crop.y + crop.height); j++) { @@ -1296,7 +1301,7 @@ void ImageCrop(Image *image, Rectangle crop) } } - free(pixels); + RL_FREE(pixels); int format = image->format; @@ -1304,7 +1309,7 @@ void ImageCrop(Image *image, Rectangle crop) *image = LoadImageEx(cropPixels, (int)crop.width, (int)crop.height); - free(cropPixels); + RL_FREE(cropPixels); // Reformat 32bit RGBA image to original format ImageFormat(image, format); @@ -1341,7 +1346,7 @@ void ImageAlphaCrop(Image *image, float threshold) Rectangle crop = { xMin, yMin, (xMax + 1) - xMin, (yMax + 1) - yMin }; - free(pixels); + RL_FREE(pixels); // Check for not empty image brefore cropping if (!((xMax < xMin) || (yMax < yMin))) ImageCrop(image, crop); @@ -1355,7 +1360,7 @@ void ImageResize(Image *image, int newWidth, int newHeight) { // Get data as Color pixels array to work with it Color *pixels = GetImageData(*image); - Color *output = (Color *)malloc(newWidth*newHeight*sizeof(Color)); + Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color)); // NOTE: Color data is casted to (unsigned char *), there shouldn't been any problem... stbir_resize_uint8((unsigned char *)pixels, image->width, image->height, 0, (unsigned char *)output, newWidth, newHeight, 0, 4); @@ -1367,15 +1372,15 @@ void ImageResize(Image *image, int newWidth, int newHeight) *image = LoadImageEx(output, newWidth, newHeight); ImageFormat(image, format); // Reformat 32bit RGBA image to original format - free(output); - free(pixels); + RL_FREE(output); + RL_FREE(pixels); } // Resize and image to new size using Nearest-Neighbor scaling algorithm void ImageResizeNN(Image *image,int newWidth,int newHeight) { Color *pixels = GetImageData(*image); - Color *output = (Color *)malloc(newWidth*newHeight*sizeof(Color)); + Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color)); // EDIT: added +1 to account for an early rounding problem int xRatio = (int)((image->width << 16)/newWidth) + 1; @@ -1400,8 +1405,8 @@ void ImageResizeNN(Image *image,int newWidth,int newHeight) *image = LoadImageEx(output, newWidth, newHeight); ImageFormat(image, format); // Reformat 32bit RGBA image to original format - free(output); - free(pixels); + RL_FREE(output); + RL_FREE(pixels); } // Resize canvas and fill with color @@ -1555,7 +1560,7 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) { Color *pixels = GetImageData(*image); - free(image->data); // free old image data + RL_FREE(image->data); // free old image data if ((image->format != UNCOMPRESSED_R8G8B8) && (image->format != UNCOMPRESSED_R8G8B8A8)) { @@ -1573,7 +1578,7 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) } // NOTE: We will store the dithered data as unsigned short (16bpp) - image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); + image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short)); Color oldPixel = WHITE; Color newPixel = WHITE; @@ -1641,7 +1646,7 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) } } - free(pixels); + RL_FREE(pixels); } } @@ -1652,7 +1657,7 @@ Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount) #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a)) Color *pixels = GetImageData(image); - Color *palette = (Color *)malloc(maxPaletteSize*sizeof(Color)); + Color *palette = (Color *)RL_MALLOC(maxPaletteSize*sizeof(Color)); int palCount = 0; for (int i = 0; i < maxPaletteSize; i++) palette[i] = BLANK; // Set all colors to BLANK @@ -1689,7 +1694,7 @@ Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount) } } - free(pixels); + RL_FREE(pixels); *extractCount = palCount; @@ -1799,8 +1804,8 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) *dst = LoadImageEx(dstPixels, (int)dst->width, (int)dst->height); ImageFormat(dst, dst->format); - free(srcPixels); - free(dstPixels); + RL_FREE(srcPixels); + RL_FREE(dstPixels); } // Create an image from text (default font) @@ -1933,7 +1938,7 @@ void ImageDrawTextEx(Image *dst, Vector2 position, Font font, const char *text, void ImageFlipVertical(Image *image) { Color *srcPixels = GetImageData(*image); - Color *dstPixels = (Color *)malloc(image->width*image->height*sizeof(Color)); + Color *dstPixels = (Color *)RL_MALLOC(image->width*image->height*sizeof(Color)); for (int y = 0; y < image->height; y++) { @@ -1947,8 +1952,8 @@ void ImageFlipVertical(Image *image) ImageFormat(&processed, image->format); UnloadImage(*image); - free(srcPixels); - free(dstPixels); + RL_FREE(srcPixels); + RL_FREE(dstPixels); image->data = processed.data; } @@ -1957,7 +1962,7 @@ void ImageFlipVertical(Image *image) void ImageFlipHorizontal(Image *image) { Color *srcPixels = GetImageData(*image); - Color *dstPixels = (Color *)malloc(image->width*image->height*sizeof(Color)); + Color *dstPixels = (Color *)RL_MALLOC(image->width*image->height*sizeof(Color)); for (int y = 0; y < image->height; y++) { @@ -1971,8 +1976,8 @@ void ImageFlipHorizontal(Image *image) ImageFormat(&processed, image->format); UnloadImage(*image); - free(srcPixels); - free(dstPixels); + RL_FREE(srcPixels); + RL_FREE(dstPixels); image->data = processed.data; } @@ -1981,7 +1986,7 @@ void ImageFlipHorizontal(Image *image) void ImageRotateCW(Image *image) { Color *srcPixels = GetImageData(*image); - Color *rotPixels = (Color *)malloc(image->width*image->height*sizeof(Color)); + Color *rotPixels = (Color *)RL_MALLOC(image->width*image->height*sizeof(Color)); for (int y = 0; y < image->height; y++) { @@ -1995,8 +2000,8 @@ void ImageRotateCW(Image *image) ImageFormat(&processed, image->format); UnloadImage(*image); - free(srcPixels); - free(rotPixels); + RL_FREE(srcPixels); + RL_FREE(rotPixels); image->data = processed.data; image->width = processed.width; @@ -2007,7 +2012,7 @@ void ImageRotateCW(Image *image) void ImageRotateCCW(Image *image) { Color *srcPixels = GetImageData(*image); - Color *rotPixels = (Color *)malloc(image->width*image->height*sizeof(Color)); + Color *rotPixels = (Color *)RL_MALLOC(image->width*image->height*sizeof(Color)); for (int y = 0; y < image->height; y++) { @@ -2021,8 +2026,8 @@ void ImageRotateCCW(Image *image) ImageFormat(&processed, image->format); UnloadImage(*image); - free(srcPixels); - free(rotPixels); + RL_FREE(srcPixels); + RL_FREE(rotPixels); image->data = processed.data; image->width = processed.width; @@ -2059,7 +2064,7 @@ void ImageColorTint(Image *image, Color color) Image processed = LoadImageEx(pixels, image->width, image->height); ImageFormat(&processed, image->format); UnloadImage(*image); - free(pixels); + RL_FREE(pixels); image->data = processed.data; } @@ -2082,7 +2087,7 @@ void ImageColorInvert(Image *image) Image processed = LoadImageEx(pixels, image->width, image->height); ImageFormat(&processed, image->format); UnloadImage(*image); - free(pixels); + RL_FREE(pixels); image->data = processed.data; } @@ -2142,7 +2147,7 @@ void ImageColorContrast(Image *image, float contrast) Image processed = LoadImageEx(pixels, image->width, image->height); ImageFormat(&processed, image->format); UnloadImage(*image); - free(pixels); + RL_FREE(pixels); image->data = processed.data; } @@ -2182,7 +2187,7 @@ void ImageColorBrightness(Image *image, int brightness) Image processed = LoadImageEx(pixels, image->width, image->height); ImageFormat(&processed, image->format); UnloadImage(*image); - free(pixels); + RL_FREE(pixels); image->data = processed.data; } @@ -2212,7 +2217,7 @@ void ImageColorReplace(Image *image, Color color, Color replace) Image processed = LoadImageEx(pixels, image->width, image->height); ImageFormat(&processed, image->format); UnloadImage(*image); - free(pixels); + RL_FREE(pixels); image->data = processed.data; } @@ -2221,13 +2226,13 @@ void ImageColorReplace(Image *image, Color color, Color replace) // Generate image: plain color Image GenImageColor(int width, int height, Color color) { - Color *pixels = (Color *)calloc(width*height, sizeof(Color)); + Color *pixels = (Color *)RL_CALLOC(width*height, sizeof(Color)); for (int i = 0; i < width*height; i++) pixels[i] = color; Image image = LoadImageEx(pixels, width, height); - free(pixels); + RL_FREE(pixels); return image; } @@ -2236,7 +2241,7 @@ Image GenImageColor(int width, int height, Color color) // Generate image: vertical gradient Image GenImageGradientV(int width, int height, Color top, Color bottom) { - Color *pixels = (Color *)malloc(width*height*sizeof(Color)); + Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); for (int j = 0; j < height; j++) { @@ -2251,7 +2256,7 @@ Image GenImageGradientV(int width, int height, Color top, Color bottom) } Image image = LoadImageEx(pixels, width, height); - free(pixels); + RL_FREE(pixels); return image; } @@ -2259,7 +2264,7 @@ Image GenImageGradientV(int width, int height, Color top, Color bottom) // Generate image: horizontal gradient Image GenImageGradientH(int width, int height, Color left, Color right) { - Color *pixels = (Color *)malloc(width*height*sizeof(Color)); + Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); for (int i = 0; i < width; i++) { @@ -2274,7 +2279,7 @@ Image GenImageGradientH(int width, int height, Color left, Color right) } Image image = LoadImageEx(pixels, width, height); - free(pixels); + RL_FREE(pixels); return image; } @@ -2282,7 +2287,7 @@ Image GenImageGradientH(int width, int height, Color left, Color right) // Generate image: radial gradient Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer) { - Color *pixels = (Color *)malloc(width*height*sizeof(Color)); + Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); float radius = (width < height)? (float)width/2.0f : (float)height/2.0f; float centerX = (float)width/2.0f; @@ -2306,7 +2311,7 @@ Image GenImageGradientRadial(int width, int height, float density, Color inner, } Image image = LoadImageEx(pixels, width, height); - free(pixels); + RL_FREE(pixels); return image; } @@ -2314,7 +2319,7 @@ Image GenImageGradientRadial(int width, int height, float density, Color inner, // Generate image: checked Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2) { - Color *pixels = (Color *)malloc(width*height*sizeof(Color)); + Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); for (int y = 0; y < height; y++) { @@ -2326,7 +2331,7 @@ Image GenImageChecked(int width, int height, int checksX, int checksY, Color col } Image image = LoadImageEx(pixels, width, height); - free(pixels); + RL_FREE(pixels); return image; } @@ -2334,7 +2339,7 @@ Image GenImageChecked(int width, int height, int checksX, int checksY, Color col // Generate image: white noise Image GenImageWhiteNoise(int width, int height, float factor) { - Color *pixels = (Color *)malloc(width*height*sizeof(Color)); + Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); for (int i = 0; i < width*height; i++) { @@ -2343,7 +2348,7 @@ Image GenImageWhiteNoise(int width, int height, float factor) } Image image = LoadImageEx(pixels, width, height); - free(pixels); + RL_FREE(pixels); return image; } @@ -2351,7 +2356,7 @@ Image GenImageWhiteNoise(int width, int height, float factor) // Generate image: perlin noise Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale) { - Color *pixels = (Color *)malloc(width*height*sizeof(Color)); + Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); for (int y = 0; y < height; y++) { @@ -2374,7 +2379,7 @@ Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float } Image image = LoadImageEx(pixels, width, height); - free(pixels); + RL_FREE(pixels); return image; } @@ -2382,13 +2387,13 @@ Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float // Generate image: cellular algorithm. Bigger tileSize means bigger cells Image GenImageCellular(int width, int height, int tileSize) { - Color *pixels = (Color *)malloc(width*height*sizeof(Color)); + Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); int seedsPerRow = width/tileSize; int seedsPerCol = height/tileSize; int seedsCount = seedsPerRow * seedsPerCol; - Vector2 *seeds = (Vector2 *)malloc(seedsCount*sizeof(Vector2)); + Vector2 *seeds = (Vector2 *)RL_MALLOC(seedsCount*sizeof(Vector2)); for (int i = 0; i < seedsCount; i++) { @@ -2431,10 +2436,10 @@ Image GenImageCellular(int width, int height, int tileSize) } } - free(seeds); + RL_FREE(seeds); Image image = LoadImageEx(pixels, width, height); - free(pixels); + RL_FREE(pixels); return image; } @@ -2921,7 +2926,7 @@ static Image LoadDDS(const char *fileName) { if (ddsHeader.ddspf.flags == 0x40) // no alpha channel { - image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short)); + image.data = (unsigned short *)RL_MALLOC(image.width*image.height*sizeof(unsigned short)); fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile); image.format = UNCOMPRESSED_R5G6B5; @@ -2930,7 +2935,7 @@ static Image LoadDDS(const char *fileName) { if (ddsHeader.ddspf.aBitMask == 0x8000) // 1bit alpha { - image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short)); + image.data = (unsigned short *)RL_MALLOC(image.width*image.height*sizeof(unsigned short)); fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile); unsigned char alpha = 0; @@ -2947,7 +2952,7 @@ static Image LoadDDS(const char *fileName) } else if (ddsHeader.ddspf.aBitMask == 0xf000) // 4bit alpha { - image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short)); + image.data = (unsigned short *)RL_MALLOC(image.width*image.height*sizeof(unsigned short)); fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile); unsigned char alpha = 0; @@ -2967,14 +2972,14 @@ static Image LoadDDS(const char *fileName) if (ddsHeader.ddspf.flags == 0x40 && ddsHeader.ddspf.rgbBitCount == 24) // DDS_RGB, no compressed { // NOTE: not sure if this case exists... - image.data = (unsigned char *)malloc(image.width*image.height*3*sizeof(unsigned char)); + image.data = (unsigned char *)RL_MALLOC(image.width*image.height*3*sizeof(unsigned char)); fread(image.data, image.width*image.height*3, 1, ddsFile); image.format = UNCOMPRESSED_R8G8B8; } else if (ddsHeader.ddspf.flags == 0x41 && ddsHeader.ddspf.rgbBitCount == 32) // DDS_RGBA, no compressed { - image.data = (unsigned char *)malloc(image.width*image.height*4*sizeof(unsigned char)); + image.data = (unsigned char *)RL_MALLOC(image.width*image.height*4*sizeof(unsigned char)); fread(image.data, image.width*image.height*4, 1, ddsFile); unsigned char blue = 0; @@ -3001,7 +3006,7 @@ static Image LoadDDS(const char *fileName) TraceLog(LOG_DEBUG, "Pitch or linear size: %i", ddsHeader.pitchOrLinearSize); - image.data = (unsigned char *)malloc(size*sizeof(unsigned char)); + image.data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char)); fread(image.data, size, 1, ddsFile); @@ -3098,7 +3103,7 @@ static Image LoadPKM(const char *fileName) int size = image.width*image.height*bpp/8; // Total data size in bytes - image.data = (unsigned char *)malloc(size*sizeof(unsigned char)); + image.data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char)); fread(image.data, size, 1, pkmFile); @@ -3192,7 +3197,7 @@ static Image LoadKTX(const char *fileName) int dataSize; fread(&dataSize, sizeof(unsigned int), 1, ktxFile); - image.data = (unsigned char *)malloc(dataSize*sizeof(unsigned char)); + image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char)); fread(image.data, dataSize, 1, ktxFile); @@ -3441,7 +3446,7 @@ static Image LoadPVR(const char *fileName) } int dataSize = image.width*image.height*bpp/8; // Total data size in bytes - image.data = (unsigned char *)malloc(dataSize*sizeof(unsigned char)); + image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char)); // Read data from file fread(image.data, dataSize, 1, pvrFile); @@ -3518,7 +3523,7 @@ static Image LoadASTC(const char *fileName) { int dataSize = image.width*image.height*bpp/8; // Data size in bytes - image.data = (unsigned char *)malloc(dataSize*sizeof(unsigned char)); + image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char)); fread(image.data, dataSize, 1, astcFile); if (bpp == 8) image.format = COMPRESSED_ASTC_4x4_RGBA; diff --git a/src/utils.c b/src/utils.c index 10cce9b9..3cff472b 100644 --- a/src/utils.c +++ b/src/utils.c @@ -45,10 +45,10 @@ #include // Required for: Android assets manager: AAsset, AAssetManager_open(), ... #endif -#include // Required for: malloc(), free() -#include // Required for: fopen(), fclose(), fputc(), fwrite(), printf(), fprintf(), funopen() +#include // Required for: exit() +#include // Required for: printf(), sprintf() #include // Required for: va_list, va_start(), vfprintf(), va_end() -#include // Required for: strlen(), strrchr(), strcmp() +#include // Required for: strcpy(), strcat() #define MAX_TRACELOG_BUFFER_SIZE 128 // Max length of one trace-log message -- cgit v1.2.3 From d3dae384497f61ad7eb1d9578db8860e6e6336aa Mon Sep 17 00:00:00 2001 From: ProfJski <49599659+ProfJski@users.noreply.github.com> Date: Wed, 8 May 2019 13:54:12 -0400 Subject: Update CheckCollisionSpheres() to avoid sqrt Square root calls are computationally expensive. In this case, they can be avoided. Instead of checking distance Date: Wed, 8 May 2019 14:14:57 -0400 Subject: Update models.c --- src/models.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index 9e534a7c..fc93c141 100644 --- a/src/models.c +++ b/src/models.c @@ -2472,7 +2472,7 @@ void DrawBoundingBox(BoundingBox box, Color color) // Detect collision between two spheres bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB) { - return Vector3DotProduct(Vector3Subtract(B,A),Vector3Subtract(B,A))<=(RadA+RadB)*(RadA+RadB); + return Vector3DotProduct(Vector3Subtract(centerB,centerA),Vector3Subtract(centerB,centerA))<=(radiusA+radiusB)*(radiusA+radiusB); } // Detect collision between two boxes -- cgit v1.2.3 From 46bac0ba2c4e00eae12c6070e2c028244be75c75 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 9 May 2019 16:09:49 +0200 Subject: Add comment in CheckCollisionSpheres() --- src/models.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index fc93c141..3f809f8d 100644 --- a/src/models.c +++ b/src/models.c @@ -2472,7 +2472,24 @@ void DrawBoundingBox(BoundingBox box, Color color) // Detect collision between two spheres bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB) { - return Vector3DotProduct(Vector3Subtract(centerB,centerA),Vector3Subtract(centerB,centerA))<=(radiusA+radiusB)*(radiusA+radiusB); + bool collision = false; + + // Simple way to check for collision, just checking distance between two points + // Unfortunately, sqrtf() is a costly operation, so we avoid it with following solution + /* + float dx = centerA.x - centerB.x; // X distance between centers + float dy = centerA.y - centerB.y; // Y distance between centers + float dz = centerA.z - centerB.z; // Y distance between centers + + float distance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance between centers + + if (distance <= (radiusA + radiusB)) collision = true; + */ + + // Check for distances squared to avoid sqrtf() + collision = (Vector3DotProduct(Vector3Subtract(centerB, centerA), Vector3Subtract(centerB, centerA)) <= (radiusA + radiusB)*(radiusA + radiusB)); + + return collision; } // Detect collision between two boxes -- cgit v1.2.3 From a2ed65aa1461addee7093d92ca80615d607e926b Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 9 May 2019 16:10:55 +0200 Subject: Make code a bit clearer for beginners --- src/models.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index 3f809f8d..6af33116 100644 --- a/src/models.c +++ b/src/models.c @@ -2487,7 +2487,7 @@ bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, floa */ // Check for distances squared to avoid sqrtf() - collision = (Vector3DotProduct(Vector3Subtract(centerB, centerA), Vector3Subtract(centerB, centerA)) <= (radiusA + radiusB)*(radiusA + radiusB)); + if (Vector3DotProduct(Vector3Subtract(centerB, centerA), Vector3Subtract(centerB, centerA)) <= (radiusA + radiusB)*(radiusA + radiusB)) collision = true; return collision; } -- cgit v1.2.3 From 5a1a0a34923fa8ecfcd5d45717b7db63f630b2a7 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 15 May 2019 15:12:56 +0200 Subject: Corrected issue with multi-mesh obj models Note that all meshes are loaded as a single one at this moment, loading should be improved! --- src/models.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index 6af33116..bd83e925 100644 --- a/src/models.c +++ b/src/models.c @@ -2769,7 +2769,9 @@ static Model LoadOBJ(const char *fileName) else TraceLog(LOG_INFO, "[%s] Model data loaded successfully: %i meshes / %i materials", fileName, meshCount, materialCount); // Init model meshes array - model.meshCount = meshCount; + // TODO: Support multiple meshes... in the meantime, only one mesh is returned + //model.meshCount = meshCount; + model.meshCount = 1; model.meshes = (Mesh *)RL_MALLOC(model.meshCount*sizeof(Mesh)); // Init model materials array -- cgit v1.2.3 From e01a381aec92abe76c40711ea6c0873b3a10df0a Mon Sep 17 00:00:00 2001 From: Wilhem Barbier Date: Tue, 14 May 2019 14:06:17 +0200 Subject: Load glTF --- src/models.c | 308 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 287 insertions(+), 21 deletions(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index bd83e925..c66a7b17 100644 --- a/src/models.c +++ b/src/models.c @@ -60,6 +60,7 @@ #if defined(SUPPORT_FILEFORMAT_GLTF) #define CGLTF_IMPLEMENTATION #include "external/cgltf.h" // glTF file format loading + #include "external/stb_image.h" #endif #if defined(SUPPORT_MESH_GENERATION) @@ -637,7 +638,7 @@ Model LoadModel(const char *fileName) if (IsFileExtension(fileName, ".obj")) model = LoadOBJ(fileName); #endif #if defined(SUPPORT_FILEFORMAT_GLTF) - if (IsFileExtension(fileName, ".gltf")) model = LoadGLTF(fileName); + if (IsFileExtension(fileName, ".gltf") || IsFileExtension(fileName, ".glb")) model = LoadGLTF(fileName); #endif #if defined(SUPPORT_FILEFORMAT_IQM) if (IsFileExtension(fileName, ".iqm")) model = LoadIQM(fileName); @@ -3241,6 +3242,108 @@ static Model LoadIQM(const char *fileName) #endif #if defined(SUPPORT_FILEFORMAT_GLTF) + +const unsigned char base64_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 62, 0, 0, 0, 63, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51 +}; + +int GetSizeBase64(char* input) +{ + int size = 0; + for (int i = 0; input[4*i] != 0; i++) + { + if (input[4*i+3] == '=') + { + if (input[4*i+2] == '=') + { + size += 1; + } + else + { + size += 2; + } + } + else size += 3; + } + return size; +} + +unsigned char* DecodeBase64(char* input, int* size) +{ + *size = 0; + for (int i = 0; input[4*i] != 0; i++) + { + if (input[4*i+3] == '=') + { + if (input[4*i+2] == '=') + { + *size += 1; + } + else + { + *size += 2; + } + } + else *size += 3; + } + + unsigned char* buf = (unsigned char*)RL_MALLOC(*size); + for (int i = 0; i < *size/3; i++) + { + unsigned char a = base64_table[(int)input[4*i]]; + unsigned char b = base64_table[(int)input[4*i+1]]; + unsigned char c = base64_table[(int)input[4*i+2]]; + unsigned char d = base64_table[(int)input[4*i+3]]; + + buf[3*i] = (a << 2) | (b >> 4); + buf[3*i+1] = (b << 4) | (c >> 2); + buf[3*i+2] = (c << 6) | d; + } + + if (*size % 3 == 1) + { + int n = *size/3; + unsigned char a = base64_table[(int)input[4*n]]; + unsigned char b = base64_table[(int)input[4*n+1]]; + buf[*size-1] = (a << 2) | (b >> 4); + } + else if (*size % 3 == 2) + { + int n = *size/3 ; + unsigned char a = base64_table[(int)input[4*n]]; + unsigned char b = base64_table[(int)input[4*n+1]]; + unsigned char c = base64_table[(int)input[4*n+2]]; + buf[*size-2] = (a << 2) | (b >> 4); + buf[*size-1] = (b << 4) | (c >> 2); + } + return buf; +} + +#define LOAD_ACCESSOR(type, nbcomp, acc, dst) \ +{ \ + int n = 0; \ + type* buf = (type*)acc->buffer_view->buffer->data+acc->buffer_view->offset/sizeof(type)+acc->offset/sizeof(type); \ + for (int k = 0; k < acc->count; k++) {\ + for (int l = 0; l < nbcomp; l++) {\ + dst[nbcomp*k+l] = buf[n+l];\ + }\ + n += acc->stride/sizeof(type);\ + }\ +} + + // Load glTF mesh data static Model LoadGLTF(const char *fileName) { @@ -3266,48 +3369,211 @@ static Model LoadGLTF(const char *fileName) // glTF data loading cgltf_options options = { 0 }; - cgltf_data *data; + cgltf_data *data = NULL; cgltf_result result = cgltf_parse(&options, buffer, size, &data); - RL_FREE(buffer); - if (result == cgltf_result_success) { - TraceLog(LOG_INFO, "[%s][%s] Model meshes/materials: %i/%i", (data->file_type == 2)? "glb" : "gltf", data->meshes_count, data->materials_count); + + TraceLog(LOG_INFO, "[%s][%s] Model meshes/materials: %i/%i", fileName, (data->file_type == 2)? "glb" : "gltf", data->meshes_count, data->materials_count); // Read data buffers result = cgltf_load_buffers(&options, data, fileName); + int nb_primitives = 0; + for (int i = 0; i < data->meshes_count; i++) + { + nb_primitives += (int)data->meshes[i].primitives_count; + } + // Process glTF data and map to model - model.meshCount = data->meshes_count; - model.meshes = RL_MALLOC(model.meshCount*sizeof(Mesh)); + model.meshCount = nb_primitives; + model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh)); + model.materialCount = data->materials_count + 1; + model.materials = RL_MALLOC(model.materialCount * sizeof(Material)); + model.meshMaterial = RL_MALLOC(model.meshCount * sizeof(int)); + + for (int i = 0; i < model.materialCount - 1; i++) + { + + Texture2D texture; + const char* dir_path = GetDirectoryPath(fileName); + Color tint; + if (data->materials[i].pbr_metallic_roughness.base_color_factor) + { + tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0] * 255.99f); + tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1] * 255.99f); + tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2] * 255.99f); + tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3] * 255.99f); + } + else + { + tint.r = 1.f; + tint.g = 1.f; + tint.b = 1.f; + tint.a = 1.f; + } + if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture) + { + + cgltf_image* img = data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image; + if (img->uri) { + if (strlen(img->uri) > 5 && img->uri[0] == 'd' + && img->uri[1] == 'a' + && img->uri[2] == 't' + && img->uri[3] == 'a' + && img->uri[4] == ':') + { + // data URI + // format: data:;base64, + + // find the comma + int i = 0; + while (img->uri[i] != ',' && img->uri[i] != 0) + { + i++; + } + if (img->uri[i] == 0) { + TraceLog(LOG_WARNING, "[%s] Invalid data URI", fileName); + } + else + { + int size; + unsigned char* data = DecodeBase64(img->uri+i+1, &size); + int w, h; + unsigned char* raw = stbi_load_from_memory(data, size, &w, &h, NULL, 4); + Image image = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8); + ImageColorTint(&image, tint); + texture = LoadTextureFromImage(image); + UnloadImage(image); + } + } + else + { + char* texture_name = img->uri; + char* texture_path = RL_MALLOC(strlen(dir_path) + strlen(texture_name) + 2); + strcpy(texture_path, dir_path); + strcat(texture_path, "/"); + strcat(texture_path, texture_name); + + Image image = LoadImage(texture_path); + ImageColorTint(&image, tint); + texture = LoadTextureFromImage(image); + UnloadImage(image); + } + } + else if (img->buffer_view) + { + unsigned char* data = RL_MALLOC(img->buffer_view->size); + int n = img->buffer_view->offset; + int stride = img->buffer_view->stride ? img->buffer_view->stride : 1; + for (int i = 0; i < img->buffer_view->size; i++) + { + data[i] = ((unsigned char*)img->buffer_view->buffer->data)[n]; + n += stride; + } + + int w, h; + unsigned char* raw = stbi_load_from_memory(data, img->buffer_view->size, &w, &h, NULL, 4); + Image image = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8); + ImageColorTint(&image, tint); + texture = LoadTextureFromImage(image); + UnloadImage(image); + } + else + { + Image image = LoadImageEx(&tint, 1, 1); + texture = LoadTextureFromImage(image); + UnloadImage(image); + } + model.materials[i] = LoadMaterialDefault(); + model.materials[i].maps[MAP_DIFFUSE].texture = texture; + } + } + model.materials[model.materialCount-1] = LoadMaterialDefault(); + + int prim_index = 0; - for (int i = 0; i < model.meshCount; i++) + for (int i = 0; i < data->meshes_count; i++) { - // NOTE: Only support meshes defined by triangle primitives - //if (data->meshes[i].primitives[n].type == cgltf_primitive_type_triangles) + + for (int p = 0; p < data->meshes[i].primitives_count; p++) { - // data.meshes[i].name not used - model.meshes[i].vertexCount = data->meshes[i].primitives_count*3; - model.meshes[i].triangleCount = data->meshes[i].primitives_count; - // data.meshes[i].weights not used (array of weights to be applied to the Morph Targets) - model.meshes[i].vertices = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*3); // Default vertex positions - model.meshes[i].normals = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*3); // Default vertex normals - model.meshes[i].texcoords = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*2); // Default vertex texcoords + for (int j = 0; j < data->meshes[i].primitives[p].attributes_count; j++) + { + if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_position) + { + cgltf_accessor* acc = data->meshes[i].primitives[p].attributes[j].data; + model.meshes[prim_index].vertexCount = acc->count; + model.meshes[prim_index].vertices = RL_MALLOC(sizeof(float)*model.meshes[prim_index].vertexCount*3); + + LOAD_ACCESSOR(float, 3, acc, model.meshes[prim_index].vertices) + } + else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_normal) + { + cgltf_accessor* acc = data->meshes[i].primitives[p].attributes[j].data; + model.meshes[prim_index].normals = RL_MALLOC(sizeof(float)*acc->count*3); + + LOAD_ACCESSOR(float, 3, acc, model.meshes[prim_index].normals) + + } + else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_texcoord) + { + cgltf_accessor* acc = data->meshes[i].primitives[p].attributes[j].data; + if (acc->component_type == cgltf_component_type_r_32f) + { + model.meshes[prim_index].texcoords = RL_MALLOC(sizeof(float)*acc->count*2); + LOAD_ACCESSOR(float, 2, acc, model.meshes[prim_index].texcoords) + } + else + { + // TODO: support normalized unsigned byte/unsigned short texture coordinates + TraceLog(LOG_WARNING, "[%s] Texture coordinates must be float", fileName); + } + } + } - model.meshes[i].indices = RL_MALLOC(sizeof(unsigned short)*model.meshes[i].triangleCount*3); + cgltf_accessor* acc = data->meshes[i].primitives[p].indices; + if (acc) + { + if (acc->component_type == cgltf_component_type_r_16u) + { + model.meshes[prim_index].triangleCount = acc->count / 3; + model.meshes[prim_index].indices = RL_MALLOC(sizeof(unsigned short)*model.meshes[prim_index].triangleCount*3); + LOAD_ACCESSOR(unsigned short, 1, acc, model.meshes[prim_index].indices) + } + else + { + // TODO: support unsigned byte/unsigned int + TraceLog(LOG_WARNING, "[%s] Indices must be unsigned short", fileName); + } + } + else + { + // unindexed mesh + model.meshes[prim_index].triangleCount = model.meshes[prim_index].vertexCount / 3; + } + if (data->meshes[i].primitives[p].material) + { + // compute the offset + model.meshMaterial[prim_index] = data->meshes[i].primitives[p].material - data->materials; + } + else + { + model.meshMaterial[prim_index] = model.materialCount - 1;; + } + prim_index++; } } - // 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); } else TraceLog(LOG_WARNING, "[%s] glTF data could not be loaded", fileName); + RL_FREE(buffer); + return model; } #endif -- cgit v1.2.3 From 371abb0a26e0c5068351db8d17a64acace89a36a Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 20 May 2019 11:13:38 +0200 Subject: Review glTF implementation formatting Added comments for the future --- src/models.c | 239 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 123 insertions(+), 116 deletions(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index c66a7b17..9dddb757 100644 --- a/src/models.c +++ b/src/models.c @@ -60,7 +60,7 @@ #if defined(SUPPORT_FILEFORMAT_GLTF) #define CGLTF_IMPLEMENTATION #include "external/cgltf.h" // glTF file format loading - #include "external/stb_image.h" + #include "external/stb_image.h" // glTF texture images loading #endif #if defined(SUPPORT_MESH_GENERATION) @@ -3243,7 +3243,7 @@ static Model LoadIQM(const char *fileName) #if defined(SUPPORT_FILEFORMAT_GLTF) -const unsigned char base64_table[] = { +static const unsigned char base64Table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -3259,94 +3259,102 @@ const unsigned char base64_table[] = { 49, 50, 51 }; -int GetSizeBase64(char* input) +static int GetSizeBase64(char *input) { int size = 0; + for (int i = 0; input[4*i] != 0; i++) { - if (input[4*i+3] == '=') + if (input[4*i + 3] == '=') { - if (input[4*i+2] == '=') - { - size += 1; - } - else - { - size += 2; - } + if (input[4*i + 2] == '=') size += 1; + else size += 2; } else size += 3; } + return size; } -unsigned char* DecodeBase64(char* input, int* size) +static unsigned char *DecodeBase64(char *input, int *size) { *size = 0; for (int i = 0; input[4*i] != 0; i++) { - if (input[4*i+3] == '=') + if (input[4*i + 3] == '=') { - if (input[4*i+2] == '=') - { - *size += 1; - } - else - { - *size += 2; - } + if (input[4*i + 2] == '=') *size += 1; + else *size += 2; } else *size += 3; } - unsigned char* buf = (unsigned char*)RL_MALLOC(*size); + unsigned char *buf = (unsigned char *)RL_MALLOC(*size); for (int i = 0; i < *size/3; i++) { - unsigned char a = base64_table[(int)input[4*i]]; - unsigned char b = base64_table[(int)input[4*i+1]]; - unsigned char c = base64_table[(int)input[4*i+2]]; - unsigned char d = base64_table[(int)input[4*i+3]]; + unsigned char a = base64Table[(int)input[4*i]]; + unsigned char b = base64Table[(int)input[4*i + 1]]; + unsigned char c = base64Table[(int)input[4*i + 2]]; + unsigned char d = base64Table[(int)input[4*i + 3]]; buf[3*i] = (a << 2) | (b >> 4); - buf[3*i+1] = (b << 4) | (c >> 2); - buf[3*i+2] = (c << 6) | d; + buf[3*i + 1] = (b << 4) | (c >> 2); + buf[3*i + 2] = (c << 6) | d; } - if (*size % 3 == 1) + if (*size%3 == 1) { int n = *size/3; - unsigned char a = base64_table[(int)input[4*n]]; - unsigned char b = base64_table[(int)input[4*n+1]]; - buf[*size-1] = (a << 2) | (b >> 4); + unsigned char a = base64Table[(int)input[4*n]]; + unsigned char b = base64Table[(int)input[4*n + 1]]; + buf[*size - 1] = (a << 2) | (b >> 4); } - else if (*size % 3 == 2) + else if (*size%3 == 2) { - int n = *size/3 ; - unsigned char a = base64_table[(int)input[4*n]]; - unsigned char b = base64_table[(int)input[4*n+1]]; - unsigned char c = base64_table[(int)input[4*n+2]]; - buf[*size-2] = (a << 2) | (b >> 4); - buf[*size-1] = (b << 4) | (c >> 2); + int n = *size/3; + unsigned char a = base64Table[(int)input[4*n]]; + unsigned char b = base64Table[(int)input[4*n + 1]]; + unsigned char c = base64Table[(int)input[4*n + 2]]; + buf[*size - 2] = (a << 2) | (b >> 4); + buf[*size - 1] = (b << 4) | (c >> 2); } return buf; } -#define LOAD_ACCESSOR(type, nbcomp, acc, dst) \ -{ \ - int n = 0; \ - type* buf = (type*)acc->buffer_view->buffer->data+acc->buffer_view->offset/sizeof(type)+acc->offset/sizeof(type); \ - for (int k = 0; k < acc->count; k++) {\ - for (int l = 0; l < nbcomp; l++) {\ - dst[nbcomp*k+l] = buf[n+l];\ - }\ - n += acc->stride/sizeof(type);\ - }\ -} - - // Load glTF mesh data static Model LoadGLTF(const char *fileName) { + /*********************************************************************************** + + Function implemented by Wilhem Barbier (@wbrbr) + + Features: + - Supports .gltf and .glb files + - Supports embedded (base64) or external textures + - Loads the albedo/diffuse texture (other maps could be added) + - 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) + + *************************************************************************************/ + + #define LOAD_ACCESSOR(type, nbcomp, acc, dst) \ + { \ + int n = 0; \ + type* buf = (type*)acc->buffer_view->buffer->data+acc->buffer_view->offset/sizeof(type)+acc->offset/sizeof(type); \ + for (int k = 0; k < acc->count; k++) {\ + for (int l = 0; l < nbcomp; l++) {\ + dst[nbcomp*k+l] = buf[n+l];\ + }\ + n += acc->stride/sizeof(type);\ + }\ + } + Model model = { 0 }; // glTF file loading @@ -3374,20 +3382,17 @@ 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); // Read data buffers result = cgltf_load_buffers(&options, data, fileName); - int nb_primitives = 0; - for (int i = 0; i < data->meshes_count; i++) - { - nb_primitives += (int)data->meshes[i].primitives_count; - } + int primitivesCount = 0; + + for (int i = 0; i < data->meshes_count; i++) primitivesCount += (int)data->meshes[i].primitives_count; // Process glTF data and map to model - model.meshCount = nb_primitives; + model.meshCount = primitivesCount; model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh)); model.materialCount = data->materials_count + 1; model.materials = RL_MALLOC(model.materialCount * sizeof(Material)); @@ -3395,10 +3400,10 @@ static Model LoadGLTF(const char *fileName) for (int i = 0; i < model.materialCount - 1; i++) { - - Texture2D texture; - const char* dir_path = GetDirectoryPath(fileName); - Color tint; + Color tint = WHITE; + Texture2D texture = { 0 }; + const char *texPath = GetDirectoryPath(fileName); + if (data->materials[i].pbr_metallic_roughness.base_color_factor) { tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0] * 255.99f); @@ -3413,35 +3418,34 @@ static Model LoadGLTF(const char *fileName) tint.b = 1.f; tint.a = 1.f; } + if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture) { - cgltf_image* img = data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image; - if (img->uri) { - if (strlen(img->uri) > 5 && img->uri[0] == 'd' - && img->uri[1] == 'a' - && img->uri[2] == 't' - && img->uri[3] == 'a' - && img->uri[4] == ':') + + if (img->uri) + { + if ((strlen(img->uri) > 5) && + (img->uri[0] == 'd') && + (img->uri[1] == 'a') && + (img->uri[2] == 't') && + (img->uri[3] == 'a') && + (img->uri[4] == ':')) { - // data URI - // format: data:;base64, + // Data URI + // Format: data:;base64, - // find the comma + // Find the comma int i = 0; - while (img->uri[i] != ',' && img->uri[i] != 0) - { - i++; - } - if (img->uri[i] == 0) { - TraceLog(LOG_WARNING, "[%s] Invalid data URI", fileName); - } + while ((img->uri[i] != ',') && (img->uri[i] != 0)) i++; + + if (img->uri[i] == 0) TraceLog(LOG_WARNING, "[%s] Invalid data URI", fileName); else { int size; - unsigned char* data = DecodeBase64(img->uri+i+1, &size); + unsigned char *data = DecodeBase64(img->uri+i+1, &size); int w, h; - unsigned char* raw = stbi_load_from_memory(data, size, &w, &h, NULL, 4); + unsigned char *raw = stbi_load_from_memory(data, size, &w, &h, NULL, 4); Image image = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8); ImageColorTint(&image, tint); texture = LoadTextureFromImage(image); @@ -3450,13 +3454,13 @@ static Model LoadGLTF(const char *fileName) } else { - char* texture_name = img->uri; - char* texture_path = RL_MALLOC(strlen(dir_path) + strlen(texture_name) + 2); - strcpy(texture_path, dir_path); - strcat(texture_path, "/"); - strcat(texture_path, texture_name); + char *textureName = img->uri; + char *texturePath = RL_MALLOC(strlen(texPath) + strlen(textureName) + 2); + strcpy(texturePath, texPath); + strcat(texturePath, "/"); + strcat(texturePath, textureName); - Image image = LoadImage(texture_path); + Image image = LoadImage(texturePath); ImageColorTint(&image, tint); texture = LoadTextureFromImage(image); UnloadImage(image); @@ -3464,9 +3468,10 @@ static Model LoadGLTF(const char *fileName) } else if (img->buffer_view) { - unsigned char* data = RL_MALLOC(img->buffer_view->size); + unsigned char *data = RL_MALLOC(img->buffer_view->size); int n = img->buffer_view->offset; int stride = img->buffer_view->stride ? img->buffer_view->stride : 1; + for (int i = 0; i < img->buffer_view->size; i++) { data[i] = ((unsigned char*)img->buffer_view->buffer->data)[n]; @@ -3474,7 +3479,7 @@ static Model LoadGLTF(const char *fileName) } int w, h; - unsigned char* raw = stbi_load_from_memory(data, img->buffer_view->size, &w, &h, NULL, 4); + unsigned char *raw = stbi_load_from_memory(data, img->buffer_view->size, &w, &h, NULL, 4); Image image = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8); ImageColorTint(&image, tint); texture = LoadTextureFromImage(image); @@ -3486,45 +3491,45 @@ static Model LoadGLTF(const char *fileName) texture = LoadTextureFromImage(image); UnloadImage(image); } + model.materials[i] = LoadMaterialDefault(); model.materials[i].maps[MAP_DIFFUSE].texture = texture; } } - model.materials[model.materialCount-1] = LoadMaterialDefault(); + + model.materials[model.materialCount - 1] = LoadMaterialDefault(); - int prim_index = 0; + int primitiveIndex = 0; for (int i = 0; i < data->meshes_count; i++) { - for (int p = 0; p < data->meshes[i].primitives_count; p++) { - for (int j = 0; j < data->meshes[i].primitives[p].attributes_count; j++) { if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_position) { - cgltf_accessor* acc = data->meshes[i].primitives[p].attributes[j].data; - model.meshes[prim_index].vertexCount = acc->count; - model.meshes[prim_index].vertices = RL_MALLOC(sizeof(float)*model.meshes[prim_index].vertexCount*3); + cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data; + model.meshes[primitiveIndex].vertexCount = acc->count; + model.meshes[primitiveIndex].vertices = RL_MALLOC(sizeof(float)*model.meshes[primitiveIndex].vertexCount*3); - LOAD_ACCESSOR(float, 3, acc, model.meshes[prim_index].vertices) + LOAD_ACCESSOR(float, 3, acc, model.meshes[primitiveIndex].vertices) } else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_normal) { - cgltf_accessor* acc = data->meshes[i].primitives[p].attributes[j].data; - model.meshes[prim_index].normals = RL_MALLOC(sizeof(float)*acc->count*3); - - LOAD_ACCESSOR(float, 3, acc, model.meshes[prim_index].normals) + cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data; + model.meshes[primitiveIndex].normals = RL_MALLOC(sizeof(float)*acc->count*3); + LOAD_ACCESSOR(float, 3, acc, model.meshes[primitiveIndex].normals) } else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_texcoord) { - cgltf_accessor* acc = data->meshes[i].primitives[p].attributes[j].data; + cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data; + if (acc->component_type == cgltf_component_type_r_32f) { - model.meshes[prim_index].texcoords = RL_MALLOC(sizeof(float)*acc->count*2); - LOAD_ACCESSOR(float, 2, acc, model.meshes[prim_index].texcoords) + model.meshes[primitiveIndex].texcoords = RL_MALLOC(sizeof(float)*acc->count*2); + LOAD_ACCESSOR(float, 2, acc, model.meshes[primitiveIndex].texcoords) } else { @@ -3534,14 +3539,15 @@ static Model LoadGLTF(const char *fileName) } } - cgltf_accessor* acc = data->meshes[i].primitives[p].indices; + cgltf_accessor *acc = data->meshes[i].primitives[p].indices; + if (acc) { if (acc->component_type == cgltf_component_type_r_16u) { - model.meshes[prim_index].triangleCount = acc->count / 3; - model.meshes[prim_index].indices = RL_MALLOC(sizeof(unsigned short)*model.meshes[prim_index].triangleCount*3); - LOAD_ACCESSOR(unsigned short, 1, acc, model.meshes[prim_index].indices) + model.meshes[primitiveIndex].triangleCount = acc->count/3; + model.meshes[primitiveIndex].indices = RL_MALLOC(sizeof(unsigned short)*model.meshes[primitiveIndex].triangleCount*3); + LOAD_ACCESSOR(unsigned short, 1, acc, model.meshes[primitiveIndex].indices) } else { @@ -3551,20 +3557,21 @@ static Model LoadGLTF(const char *fileName) } else { - // unindexed mesh - model.meshes[prim_index].triangleCount = model.meshes[prim_index].vertexCount / 3; + // Unindexed mesh + model.meshes[primitiveIndex].triangleCount = model.meshes[primitiveIndex].vertexCount/3; } if (data->meshes[i].primitives[p].material) { - // compute the offset - model.meshMaterial[prim_index] = data->meshes[i].primitives[p].material - data->materials; + // Compute the offset + model.meshMaterial[primitiveIndex] = data->meshes[i].primitives[p].material - data->materials; } else { - model.meshMaterial[prim_index] = model.materialCount - 1;; + model.meshMaterial[primitiveIndex] = model.materialCount - 1;; } - prim_index++; + + primitiveIndex++; } } -- cgit v1.2.3 From 13a1744ca980a9259f2767b7593c73683cd4e420 Mon Sep 17 00:00:00 2001 From: Wilhem Barbier Date: Wed, 22 May 2019 20:27:19 +0200 Subject: Fix #848 --- src/models.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index 9dddb757..a33edfd3 100644 --- a/src/models.c +++ b/src/models.c @@ -3044,7 +3044,7 @@ static Model LoadIQM(const char *fileName) fread(imesh, sizeof(IQMMesh)*iqm.num_meshes, 1, iqmFile); model.meshCount = iqm.num_meshes; - model.meshes = RL_MALLOC(model.meshCount*sizeof(Mesh)); + model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh)); char name[MESH_NAME_LENGTH]; -- cgit v1.2.3