|
|
@ -896,8 +896,8 @@ Material *LoadMaterials(const char *fileName, int *materialCount) |
|
|
|
#if defined(SUPPORT_FILEFORMAT_MTL) |
|
|
|
if (IsFileExtension(fileName, ".mtl")) |
|
|
|
{ |
|
|
|
tinyobj_material_t *mats; |
|
|
|
|
|
|
|
tinyobj_material_t *mats = NULL; |
|
|
|
|
|
|
|
int result = tinyobj_parse_mtl_file(&mats, &count, fileName); |
|
|
|
if (result != TINYOBJ_SUCCESS) { |
|
|
|
TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName); |
|
|
@ -2566,6 +2566,12 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota |
|
|
|
for (int i = 0; i < model.meshCount; i++) |
|
|
|
{ |
|
|
|
// TODO: Review color + tint premultiplication mechanism |
|
|
|
|
|
|
|
// (codifies) Ray not only does this work as expected but |
|
|
|
// multiplying *is* definately the way to tint |
|
|
|
// can we call it reviewed ? |
|
|
|
|
|
|
|
// would you prefer an extra model.tint, that rlDrawMesh uses ? |
|
|
|
Color color = model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color; |
|
|
|
|
|
|
|
Color colorTint = WHITE; |
|
|
@ -2942,11 +2948,15 @@ RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight) |
|
|
|
|
|
|
|
#if defined(SUPPORT_FILEFORMAT_OBJ) |
|
|
|
// Load OBJ mesh data |
|
|
|
|
|
|
|
// TODO used by loadOBJ, could change to a function that could handle |
|
|
|
// data coming from a file, memory or archive... |
|
|
|
|
|
|
|
static Model LoadOBJ(const char *fileName) |
|
|
|
{ |
|
|
|
Model model = { 0 }; |
|
|
|
|
|
|
|
tinyobj_attrib_t attrib; |
|
|
|
tinyobj_attrib_t attrib = { 0 }; |
|
|
|
tinyobj_shape_t *meshes = NULL; |
|
|
|
unsigned int meshCount = 0; |
|
|
|
|
|
|
@ -2968,126 +2978,112 @@ 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); |
|
|
|
|
|
|
|
// Init model meshes array |
|
|
|
// TODO: Support multiple meshes... in the meantime, only one mesh is returned |
|
|
|
//model.meshCount = meshCount; |
|
|
|
model.meshCount = 1; |
|
|
|
model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); |
|
|
|
|
|
|
|
|
|
|
|
model.meshCount = materialCount; |
|
|
|
|
|
|
|
|
|
|
|
// Init model materials array |
|
|
|
if (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.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); |
|
|
|
model.meshMaterial = (int *)RL_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++) |
|
|
|
|
|
|
|
// count the faces for each material |
|
|
|
int* matFaces = RL_CALLOC(meshCount, sizeof(int)); |
|
|
|
|
|
|
|
for (int mi=0; mi<meshCount; mi++) { |
|
|
|
for (int fi=0; fi<meshes[mi].length; fi++) { |
|
|
|
int idx = attrib.material_ids[meshes[mi].face_offset + fi]; |
|
|
|
if (idx == -1) idx = 0; // for no material face (which could be the whole model) |
|
|
|
matFaces[idx]++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//-------------------------------------- |
|
|
|
// 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.meshes[mi].vboId = (unsigned int *)RL_CALLOC(DEFAULT_MESH_VERTEX_BUFFERS, sizeof(unsigned int)); |
|
|
|
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++) |
|
|
|
{ |
|
|
|
Mesh mesh = { 0 }; |
|
|
|
memset(&mesh, 0, sizeof(Mesh)); |
|
|
|
mesh.vertexCount = attrib.num_faces*3; |
|
|
|
mesh.triangleCount = attrib.num_faces; |
|
|
|
mesh.vertices = (float *)RL_CALLOC(mesh.vertexCount*3, sizeof(float)); |
|
|
|
mesh.texcoords = (float *)RL_CALLOC(mesh.vertexCount*2, sizeof(float)); |
|
|
|
mesh.normals = (float *)RL_CALLOC(mesh.vertexCount*3, sizeof(float)); |
|
|
|
mesh.vboId = (unsigned int *)RL_CALLOC(DEFAULT_MESH_VERTEX_BUFFERS, sizeof(unsigned int)); |
|
|
|
|
|
|
|
int vCount = 0; |
|
|
|
int vtCount = 0; |
|
|
|
int vnCount = 0; |
|
|
|
|
|
|
|
for (unsigned int f = 0; f < attrib.num_faces; f++) |
|
|
|
int mm = attrib.material_ids[af]; // mesh material for this face |
|
|
|
if (mm == -1) { mm = 0; } // no material object.. |
|
|
|
// 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]; |
|
|
|
|
|
|
|
// 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; |
|
|
|
|
|
|
|
if (attrib.num_texcoords > 0) |
|
|
|
{ |
|
|
|
// 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]; |
|
|
|
|
|
|
|
// 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; |
|
|
|
|
|
|
|
if (attrib.num_texcoords > 0) |
|
|
|
{ |
|
|
|
// 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; |
|
|
|
} |
|
|
|
|
|
|
|
if (attrib.num_normals > 0) |
|
|
|
{ |
|
|
|
// 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; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
model.meshes[m] = mesh; // Assign mesh data to model |
|
|
|
|
|
|
|
// Assign mesh material for current mesh |
|
|
|
model.meshMaterial[m] = attrib.material_ids[m]; |
|
|
|
|
|
|
|
// Set unfound materials to default |
|
|
|
if (model.meshMaterial[m] == -1) model.meshMaterial[m] = 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; |
|
|
|
} |
|
|
|
|
|
|
|
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; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Init model materials |
|
|
|
for (unsigned int m = 0; m < materialCount; m++) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// Init material to default |
|
|
|
// NOTE: Uses default shader, only MAP_DIFFUSE supported |
|
|
|
// NOTE: Uses default shader, which only supports MAP_DIFFUSE |
|
|
|
|
|
|
|
// (codifies) TODO my lighting shader should support at least |
|
|
|
// diffuse AND specular ... |
|
|
|
model.materials[m] = LoadMaterialDefault(); |
|
|
|
|
|
|
|
/* |
|
|
|
typedef struct { |
|
|
|
char *name; |
|
|
|
|
|
|
|
float ambient[3]; |
|
|
|
float diffuse[3]; |
|
|
|
float specular[3]; |
|
|
|
float transmittance[3]; |
|
|
|
float emission[3]; |
|
|
|
float shininess; |
|
|
|
float ior; // index of refraction |
|
|
|
float dissolve; // 1 == opaque; 0 == fully transparent |
|
|
|
// illumination model (Ref: http://www.fileformat.info/format/material/) |
|
|
|
int illum; |
|
|
|
|
|
|
|
int pad0; |
|
|
|
|
|
|
|
char *ambient_texname; // map_Ka |
|
|
|
char *diffuse_texname; // map_Kd |
|
|
|
char *specular_texname; // map_Ks |
|
|
|
char *specular_highlight_texname; // map_Ns |
|
|
|
char *bump_texname; // map_bump, bump |
|
|
|
char *displacement_texname; // disp |
|
|
|
char *alpha_texname; // map_d |
|
|
|
} tinyobj_material_t; |
|
|
|
*/ |
|
|
|
|
|
|
|
model.materials[m].maps[MAP_DIFFUSE].texture = 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 |
|
|
|
if (materials[m].diffuse_texname != NULL) { |
|
|
|
model.materials[m].maps[MAP_DIFFUSE].texture = LoadTexture(materials[m].diffuse_texname); //char *diffuse_texname; // map_Kd |
|
|
|
} else { |
|
|
|
model.materials[m].maps[MAP_DIFFUSE].texture = GetTextureDefault(); |
|
|
|
} |
|
|
|
|
|
|
|
model.materials[m].maps[MAP_DIFFUSE].color = (Color){ (unsigned char)(materials[m].diffuse[0]*255.0f), (unsigned char)(materials[m].diffuse[1]*255.0f), (unsigned char)(materials[m].diffuse[2]*255.0f), 255 }; //float diffuse[3]; |
|
|
|
model.materials[m].maps[MAP_DIFFUSE].value = 0.0f; |
|
|
|
|
|
|
@ -3109,6 +3105,11 @@ static Model LoadOBJ(const char *fileName) |
|
|
|
tinyobj_materials_free(materials, materialCount); |
|
|
|
|
|
|
|
RL_FREE(fileData); |
|
|
|
|
|
|
|
RL_FREE(vCount); |
|
|
|
RL_FREE(vtCount); |
|
|
|
RL_FREE(vnCount); |
|
|
|
RL_FREE(faceCount); |
|
|
|
|
|
|
|
chdir(currentDir); |
|
|
|
} |
|
|
|