diff --git a/src/external/tinyobj_loader_c.h b/src/external/tinyobj_loader_c.h index 7ef55ff94..50207cc7e 100644 --- a/src/external/tinyobj_loader_c.h +++ b/src/external/tinyobj_loader_c.h @@ -24,6 +24,10 @@ #ifndef TINOBJ_LOADER_C_H_ #define TINOBJ_LOADER_C_H_ +// TODO (codifies) I have commented out many printf's I used to observe +// the several bugs in action related to hashmap, they can be removed at +// some point - I only left them in case (paranoid - me?) + /* @todo { Remove stddef dependency. unsigned int? } ---> RAY: DONE. */ //#include @@ -166,6 +170,10 @@ static unsigned int length_until_newline(const char *token, unsigned int n) { if ((token[len] == '\r') && ((len < (n - 2)) && (token[len + 1] != '\n'))) { break; } + // codifies - added this, to get this working + if ((token[len] == '\n') && ((len < (n - 2)) && (token[len + 1] != '\r'))) { + break; + } } return len; @@ -547,7 +555,7 @@ static void initMaterial(tinyobj_material_t *material) { #define HASH_TABLE_ERROR 1 #define HASH_TABLE_SUCCESS 0 -#define HASH_TABLE_DEFAULT_SIZE 10 +#define HASH_TABLE_DEFAULT_SIZE 11 typedef struct hash_table_entry_t { @@ -571,11 +579,11 @@ static unsigned long hash_djb2(const unsigned char* str) { unsigned long hash = 5381; int c; - + //printf("hashed >>>%s<<< into ",str); while ((c = *str++)) { hash = ((hash << 5) + hash) + (unsigned long)(c); } - + //printf("into %lu\n",hash); return hash; } @@ -607,8 +615,10 @@ static int hash_table_insert_value(unsigned long hash, long value, hash_table_t* for (i = 1; hash_table->entries[index].filled; i++) { - if (i >= hash_table->capacity) + if (i >= hash_table->capacity) { + //printf("insert failed\n"); return HASH_TABLE_ERROR; + } index = (start_index + (i * i)) % hash_table->capacity; } @@ -622,12 +632,15 @@ static int hash_table_insert_value(unsigned long hash, long value, hash_table_t* entry->next = start_entry->next; start_entry->next = entry; } + + //printf("using hash %lu \n",hash); return HASH_TABLE_SUCCESS; } static int hash_table_insert(unsigned long hash, long value, hash_table_t* hash_table) { + //printf("inserting %i into hash ",value); int ret = hash_table_insert_value(hash, value, hash_table); if (ret == HASH_TABLE_SUCCESS) { @@ -639,15 +652,19 @@ static int hash_table_insert(unsigned long hash, long value, hash_table_t* hash_ static hash_table_entry_t* hash_table_find(unsigned long hash, hash_table_t* hash_table) { + //printf("looking for hash %lu - ",hash); hash_table_entry_t* entry = hash_table->entries + (hash % hash_table->capacity); while (entry) { if (entry->hash == hash && entry->filled) { + //printf(" found\n"); return entry; } entry = entry->next; } + //printf(" NOT found\n"); + return NULL; } @@ -657,6 +674,9 @@ static void hash_table_maybe_grow(unsigned int new_n, hash_table_t* hash_table) hash_table_t new_hash_table; unsigned int i; + // extra room for collisions + new_n *= 2; + if (new_n <= hash_table->capacity) { return; } @@ -668,7 +688,9 @@ static void hash_table_maybe_grow(unsigned int new_n, hash_table_t* hash_table) new_hash_table.n = hash_table->n; /* Rehash */ - for (i = 0; i < hash_table->capacity; i++) + // we asked for twice as much as was in there so just rehash the first half which + // is the whole source table + for (i = 0; i < hash_table->capacity / 2; 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); @@ -708,6 +730,7 @@ static void hash_table_set(const char* name, unsigned int val, hash_table_t* has 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); + //printf("found a value of %i for %s\n",ret->value, name); return ret->value; } @@ -1137,7 +1160,7 @@ static int parseLine(Command *command, const char *p, unsigned int p_len, skip_space(&token); command->material_name = p + (token - linebuf); command->material_name_len = (unsigned int)length_until_newline( - token, (p_len - (unsigned int)(token - linebuf)) + 1); + token, (p_len - (unsigned int)(token - linebuf)) + 1); command->type = COMMAND_USEMTL; return 1; @@ -1151,8 +1174,7 @@ static int parseLine(Command *command, const char *p, unsigned int p_len, skip_space(&token); command->mtllib_name = p + (token - linebuf); command->mtllib_name_len = (unsigned int)length_until_newline( - token, p_len - (unsigned int)(token - linebuf)) + - 1; + token, (p_len - (unsigned int)(token - linebuf)) + 1); command->type = COMMAND_MTLLIB; return 1; @@ -1377,7 +1399,7 @@ int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, /* 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; + material_name_null_term[commands[i].material_name_len] = 0; if (hash_table_exists(material_name_null_term, &material_table)) material_id = (int)hash_table_get(material_name_null_term, &material_table); diff --git a/src/models.c b/src/models.c index 2a815e7ca..cfed95022 100644 --- a/src/models.c +++ b/src/models.c @@ -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++) - { - 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++) - { - // 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; - } + + // count the faces for each material + int* matFaces = RL_CALLOC(meshCount, sizeof(int)); + + for (int mi=0; mi 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); }