aboutsummaryrefslogtreecommitdiff
path: root/raylib/src/rmodels.c
diff options
context:
space:
mode:
Diffstat (limited to 'raylib/src/rmodels.c')
-rw-r--r--raylib/src/rmodels.c185
1 files changed, 78 insertions, 107 deletions
diff --git a/raylib/src/rmodels.c b/raylib/src/rmodels.c
index a11ecf7..229d373 100644
--- a/raylib/src/rmodels.c
+++ b/raylib/src/rmodels.c
@@ -1052,26 +1052,16 @@ Model LoadModel(const char *fileName)
// Make sure model transform is set to identity matrix!
model.transform = MatrixIdentity();
- if (model.meshCount == 0)
+ if ((model.meshCount != 0) && (model.meshes != NULL))
{
- model.meshCount = 1;
- model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
-#if defined(SUPPORT_MESH_GENERATION)
- TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load mesh data, default to cube mesh", fileName);
- model.meshes[0] = GenMeshCube(1.0f, 1.0f, 1.0f);
-#else
- TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load mesh data", fileName);
-#endif
- }
- else
- {
- // Upload vertex data to GPU (static mesh)
+ // Upload vertex data to GPU (static meshes)
for (int i = 0; i < model.meshCount; i++) UploadMesh(&model.meshes[i], false);
}
+ else TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load model mesh(es) data", fileName);
if (model.materialCount == 0)
{
- TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to load material data, default to white material", fileName);
+ TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to load model material data, default to white material", fileName);
model.materialCount = 1;
model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
@@ -1171,6 +1161,12 @@ BoundingBox GetModelBoundingBox(Model model)
}
}
+ // Apply model.transform to bounding box
+ // WARNING: Current BoundingBox structure design does not support rotation transformations,
+ // in those cases is up to the user to calculate the proper box bounds (8 vertices transformed)
+ bounds.min = Vector3Transform(bounds.min, model.transform);
+ bounds.max = Vector3Transform(bounds.max, model.transform);
+
return bounds;
}
@@ -2146,11 +2142,11 @@ Mesh GenMeshPoly(int sides, float radius)
Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
float d = 0.0f, dStep = 360.0f/sides;
- for (int v = 0; v < vertexCount; v += 3)
+ for (int v = 0; v < vertexCount - 2; v += 3)
{
vertices[v] = (Vector3){ 0.0f, 0.0f, 0.0f };
vertices[v + 1] = (Vector3){ sinf(DEG2RAD*d)*radius, 0.0f, cosf(DEG2RAD*d)*radius };
- vertices[v + 2] = (Vector3){sinf(DEG2RAD*(d+dStep))*radius, 0.0f, cosf(DEG2RAD*(d+dStep))*radius };
+ vertices[v + 2] = (Vector3){ sinf(DEG2RAD*(d+dStep))*radius, 0.0f, cosf(DEG2RAD*(d+dStep))*radius };
d += dStep;
}
@@ -2249,7 +2245,7 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ)
for (int face = 0; face < numFaces; face++)
{
// Retrieve lower left corner from face ind
- int i = face % (resX - 1) + (face/(resZ - 1)*resX);
+ int i = face + face / (resX - 1);
triangles[t++] = i + resX;
triangles[t++] = i + 1;
@@ -3935,9 +3931,10 @@ static Model LoadOBJ(const char *fileName)
if (fileText != NULL)
{
unsigned int dataSize = (unsigned int)strlen(fileText);
+
char currentDir[1024] = { 0 };
- strcpy(currentDir, GetWorkingDirectory());
- const char *workingDir = GetDirectoryPath(fileName);
+ strcpy(currentDir, GetWorkingDirectory()); // Save current working directory
+ const char *workingDir = GetDirectoryPath(fileName); // Switch to OBJ directory for material path correctness
if (CHDIR(workingDir) != 0)
{
TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir);
@@ -3949,117 +3946,91 @@ static Model LoadOBJ(const char *fileName)
if (ret != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load OBJ data", fileName);
else TRACELOG(LOG_INFO, "MODEL: [%s] OBJ data loaded successfully: %i meshes/%i materials", fileName, meshCount, materialCount);
- model.meshCount = materialCount;
+ // WARNING: We are not splitting meshes by materials (previous implementation)
+ // Depending on the provided OBJ that was not the best option and it just crashed
+ // so, implementation was simplified to prioritize parsed meshes
+ model.meshCount = meshCount;
- // Init model materials array
- if (materialCount > 0)
+ // Set number of materials available
+ // NOTE: There could be more materials available than meshes but it will be resolved at
+ // model.meshMaterial, just assigning the right material to corresponding mesh
+ model.materialCount = materialCount;
+ if (model.materialCount == 0)
{
- model.materialCount = materialCount;
- model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
- TRACELOG(LOG_INFO, "MODEL: model has %i material meshes", materialCount);
- }
- else
- {
- model.meshCount = 1;
- TRACELOG(LOG_INFO, "MODEL: No materials, putting all meshes in a default material");
+ model.materialCount = 1;
+ TRACELOG(LOG_INFO, "MODEL: No materials provided, setting one default material for all meshes");
}
+ // Init model meshes and materials
model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
- model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
-
- // Count the faces for each material
- int *matFaces = RL_CALLOC(model.meshCount, sizeof(int));
+ model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); // Material index assigned to each mesh
+ model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
- // if no materials are present use all faces on one mesh
- if (materialCount > 0)
+ // Process each provided mesh
+ for (int i = 0; i < model.meshCount; i++)
{
- for (unsigned int fi = 0; fi < attrib.num_faces; fi++)
+ // WARNING: We need to calculate the mesh triangles manually using meshes[i].face_offset
+ // because in case of triangulated quads, meshes[i].length actually report quads,
+ // despite the triangulation that is efectively considered on attrib.num_faces
+ unsigned int tris = 0;
+ if (i == model.meshCount - 1) tris = attrib.num_faces - meshes[i].face_offset;
+ else tris = meshes[i + 1].face_offset;
+
+ model.meshes[i].vertexCount = tris*3;
+ model.meshes[i].triangleCount = tris; // Face count (triangulated)
+ model.meshes[i].vertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
+ model.meshes[i].texcoords = (float *)RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float));
+ model.meshes[i].normals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
+ model.meshMaterial[i] = 0; // By default, assign material 0 to each mesh
+
+ // Process all mesh faces
+ for (unsigned int face = 0, f = meshes[i].face_offset, v = 0, vt = 0, vn = 0; face < tris; face++, f++, v += 3, vt += 3, vn += 3)
{
- //tinyobj_vertex_index_t face = attrib.faces[fi];
- int idx = attrib.material_ids[fi];
- matFaces[idx]++;
- }
+ // Get indices for the face
+ tinyobj_vertex_index_t idx0 = attrib.faces[f*3 + 0];
+ tinyobj_vertex_index_t idx1 = attrib.faces[f*3 + 1];
+ tinyobj_vertex_index_t idx2 = attrib.faces[f*3 + 2];
- }
- else
- {
- matFaces[0] = attrib.num_faces;
- }
-
- //--------------------------------------
- // Create the material meshes
-
- // Running counts/indexes for each material mesh as we are
- // building them at the same time
- int *vCount = RL_CALLOC(model.meshCount, sizeof(int));
- int *vtCount = RL_CALLOC(model.meshCount, sizeof(int));
- int *vnCount = RL_CALLOC(model.meshCount, sizeof(int));
- int *faceCount = RL_CALLOC(model.meshCount, sizeof(int));
-
- // Allocate space for each of the material meshes
- for (int mi = 0; mi < model.meshCount; mi++)
- {
- model.meshes[mi].vertexCount = matFaces[mi]*3;
- model.meshes[mi].triangleCount = matFaces[mi];
- model.meshes[mi].vertices = (float *)RL_CALLOC(model.meshes[mi].vertexCount*3, sizeof(float));
- model.meshes[mi].texcoords = (float *)RL_CALLOC(model.meshes[mi].vertexCount*2, sizeof(float));
- model.meshes[mi].normals = (float *)RL_CALLOC(model.meshes[mi].vertexCount*3, sizeof(float));
- model.meshMaterial[mi] = mi;
- }
-
- // Scan through the combined sub meshes and pick out each material mesh
- for (unsigned int af = 0; af < attrib.num_faces; af++)
- {
- int mm = attrib.material_ids[af]; // mesh material for this face
- if (mm == -1) { mm = 0; } // no material object..
+ // Fill vertices buffer (float) using vertex index of the face
+ for (int n = 0; n < 3; n++) { model.meshes[i].vertices[v*3 + n] = attrib.vertices[idx0.v_idx*3 + n]; }
+ for (int n = 0; n < 3; n++) { model.meshes[i].vertices[(v + 1)*3 + n] = attrib.vertices[idx1.v_idx*3 + n]; }
+ for (int n = 0; n < 3; n++) { model.meshes[i].vertices[(v + 2)*3 + n] = attrib.vertices[idx2.v_idx*3 + n]; }
- // Get indices for the face
- tinyobj_vertex_index_t idx0 = attrib.faces[3*af + 0];
- tinyobj_vertex_index_t idx1 = attrib.faces[3*af + 1];
- tinyobj_vertex_index_t idx2 = attrib.faces[3*af + 2];
+ if (attrib.num_texcoords > 0)
+ {
+ // Fill texcoords buffer (float) using vertex index of the face
+ // NOTE: Y-coordinate must be flipped upside-down
+ model.meshes[i].texcoords[vt*2 + 0] = attrib.texcoords[idx0.vt_idx*2 + 0];
+ model.meshes[i].texcoords[vt*2 + 1] = 1.0f - attrib.texcoords[idx0.vt_idx*2 + 1];
- // Fill vertices buffer (float) using vertex index of the face
- for (int v = 0; v < 3; v++) { model.meshes[mm].vertices[vCount[mm] + v] = attrib.vertices[idx0.v_idx*3 + v]; } vCount[mm] +=3;
- for (int v = 0; v < 3; v++) { model.meshes[mm].vertices[vCount[mm] + v] = attrib.vertices[idx1.v_idx*3 + v]; } vCount[mm] +=3;
- for (int v = 0; v < 3; v++) { model.meshes[mm].vertices[vCount[mm] + v] = attrib.vertices[idx2.v_idx*3 + v]; } vCount[mm] +=3;
+ model.meshes[i].texcoords[(vt + 1)*2 + 0] = attrib.texcoords[idx1.vt_idx*2 + 0];
+ model.meshes[i].texcoords[(vt + 1)*2 + 1] = 1.0f - attrib.texcoords[idx1.vt_idx*2 + 1];
- if (attrib.num_texcoords > 0)
- {
- // Fill texcoords buffer (float) using vertex index of the face
- // NOTE: Y-coordinate must be flipped upside-down to account for
- // raylib's upside down textures...
- model.meshes[mm].texcoords[vtCount[mm] + 0] = attrib.texcoords[idx0.vt_idx*2 + 0];
- model.meshes[mm].texcoords[vtCount[mm] + 1] = 1.0f - attrib.texcoords[idx0.vt_idx*2 + 1]; vtCount[mm] += 2;
- model.meshes[mm].texcoords[vtCount[mm] + 0] = attrib.texcoords[idx1.vt_idx*2 + 0];
- model.meshes[mm].texcoords[vtCount[mm] + 1] = 1.0f - attrib.texcoords[idx1.vt_idx*2 + 1]; vtCount[mm] += 2;
- model.meshes[mm].texcoords[vtCount[mm] + 0] = attrib.texcoords[idx2.vt_idx*2 + 0];
- model.meshes[mm].texcoords[vtCount[mm] + 1] = 1.0f - attrib.texcoords[idx2.vt_idx*2 + 1]; vtCount[mm] += 2;
- }
+ model.meshes[i].texcoords[(vt + 2)*2 + 0] = attrib.texcoords[idx2.vt_idx*2 + 0];
+ model.meshes[i].texcoords[(vt + 2)*2 + 1] = 1.0f - attrib.texcoords[idx2.vt_idx*2 + 1];
+ }
- if (attrib.num_normals > 0)
- {
- // Fill normals buffer (float) using vertex index of the face
- for (int v = 0; v < 3; v++) { model.meshes[mm].normals[vnCount[mm] + v] = attrib.normals[idx0.vn_idx*3 + v]; } vnCount[mm] +=3;
- for (int v = 0; v < 3; v++) { model.meshes[mm].normals[vnCount[mm] + v] = attrib.normals[idx1.vn_idx*3 + v]; } vnCount[mm] +=3;
- for (int v = 0; v < 3; v++) { model.meshes[mm].normals[vnCount[mm] + v] = attrib.normals[idx2.vn_idx*3 + v]; } vnCount[mm] +=3;
+ if (attrib.num_normals > 0)
+ {
+ // Fill normals buffer (float) using vertex index of the face
+ for (int n = 0; n < 3; n++) { model.meshes[i].normals[vn*3 + n] = attrib.normals[idx0.vn_idx*3 + n]; }
+ for (int n = 0; n < 3; n++) { model.meshes[i].normals[(vn + 1)*3 + n] = attrib.normals[idx1.vn_idx*3 + n]; }
+ for (int n = 0; n < 3; n++) { model.meshes[i].normals[(vn + 2)*3 + n] = attrib.normals[idx2.vn_idx*3 + n]; }
+ }
}
}
// Init model materials
- ProcessMaterialsOBJ(model.materials, materials, materialCount);
+ if (materialCount > 0) ProcessMaterialsOBJ(model.materials, materials, materialCount);
+ else model.materials[0] = LoadMaterialDefault(); // Set default material for the mesh
tinyobj_attrib_free(&attrib);
- tinyobj_shapes_free(meshes, meshCount);
+ tinyobj_shapes_free(meshes, model.meshCount);
tinyobj_materials_free(materials, materialCount);
UnloadFileText(fileText);
- RL_FREE(matFaces);
- RL_FREE(vCount);
- RL_FREE(vtCount);
- RL_FREE(vnCount);
- RL_FREE(faceCount);
-
+ // Restore current working directory
if (CHDIR(currentDir) != 0)
{
TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", currentDir);