diff --git a/Jenkinsfile b/Jenkinsfile index ad145c8..80af602 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,7 +5,7 @@ pipeline { } environment { CI_OUTPUT_NAME = "RSEModel" - CI_VERSION = "2.3.0" + CI_VERSION = "2.3.1" CI_BUILD_NUMBER = "$BUILD_NUMBER" } stages { diff --git a/RSEModel/src/RSEModel.c b/RSEModel/src/RSEModel.c index 5b7d3db..ea00c1b 100644 --- a/RSEModel/src/RSEModel.c +++ b/RSEModel/src/RSEModel.c @@ -104,7 +104,7 @@ static unsigned int mainProcess(int args_cnt, char* args_value[], T_PROG_OPTIONS } // If Texture module loaded, process HMT file for mtl naming (doesn't extract texture!) - if (p_opts->texture_module) { + if (p_opts->texture_module && p_opts->export_mtl) { if (strlen(args_value[file_index]) >= MAX_STR_VAR) return RSPLIB_ERROR_GENERIC; strncpy(hmt_filename, args_value[file_index], strlen(args_value[file_index]) - 3); diff --git a/RSPModelLib/include/RSPModel_datatypes.h b/RSPModelLib/include/RSPModel_datatypes.h index bbdc715..44243c2 100644 --- a/RSPModelLib/include/RSPModel_datatypes.h +++ b/RSPModelLib/include/RSPModel_datatypes.h @@ -1,6 +1,6 @@ /** * @file RSPModel_datatypes.h - * @date 11/08/2022 + * @date 21/02/2023 * @author JackCarterSmith * @copyright GPL-v3.0 * @brief RSP Model workflow structures definitions @@ -46,20 +46,24 @@ typedef struct rspmodel_vertex { short x,y,z,w; } T_RSPMODEL_VERTEX; typedef struct rspmodel_texcoord { short u,v; } T_RSPMODEL_TEXCOORD; +typedef struct rspmodel_bbox { T_RSPMODEL_VECTOR3 start,end; } T_RSPMODEL_BBOX; + typedef struct face_flags { - unsigned int fUnknown0:1; - unsigned int fUnknown1:1; + unsigned int fUnused0:1; //TODO: Parse all HOB to find anyone with this field different of 0 + unsigned int fUnused1:1; //TODO: Parse all HOB to find anyone with this field different of 0 + unsigned int fHasTexture:1; unsigned int fIsQuad:1; unsigned int fSeparateColorVertex:1; unsigned int fHasColor:1; unsigned int fHasExtraBytesBeforeColor:1; - unsigned int fUnknown7:1; + unsigned int fNoCulled:1; // Face with this flag always be rendered without culling, usefull to render "flat" object + unsigned int fUnknown8:1; unsigned int fUnknown9:1; unsigned int fUnknown10:1; - unsigned int reserved:21; + unsigned int fReserved:21; } FACE_FLAGS; typedef struct hob_face { @@ -78,6 +82,7 @@ typedef struct hob_face { } T_RSPMODEL_FACE; typedef struct rspmodel_obj_parts { + unsigned int meshdef0_offset; unsigned int meshdef1_offset; unsigned int face_block_end_offset; @@ -97,8 +102,16 @@ typedef struct rspmodel_obj_parts { typedef struct rspmodel_object { char name[16]; unsigned int face_group_offset; - unsigned int object_part_header_offset; - unsigned int face_group_header_offset; + unsigned int object_parts_header_offset; + unsigned int object_parts_header_offset2; + unsigned int object_parts_header2_offset; + unsigned int object_parts_header2_offset2; + + unsigned int object_subparts_names_offset; + unsigned int effects_offset; + unsigned int properties_offset2; + + T_RSPMODEL_BBOX bounding_box; unsigned int object_part_count; unsigned int face_group_count; diff --git a/RSPModelLib/src/hob_parser.c b/RSPModelLib/src/hob_parser.c index c9d2319..cf94435 100644 --- a/RSPModelLib/src/hob_parser.c +++ b/RSPModelLib/src/hob_parser.c @@ -1,6 +1,6 @@ /** * @file hob_parser.c - * @date 18/01/2023 + * @date 21/02/2023 * @author JackCarterSmith * @copyright GPL-v3.0 * @brief Process HOB file structure and extract its datas. @@ -12,8 +12,8 @@ #include #include "RSPModel_errordefs.h" #include "RSPModel_datatypes.h" -#include "hob_struct.h" #include "hob_parser.h" +#include "hob_struct.h" //////////////////////////////////////////////////////////////////////////////// @@ -21,8 +21,15 @@ //////////////////////////////////////////////////////////////////////////////// static unsigned short ExtractObjects(T_RSPMODEL_HOB*, const MEMFILE, const RSPMODEL_PARAMETERS*); -static unsigned short ExtractObjParts(T_RSPMODEL_OBJECT*, const MEMFILE, const RSPMODEL_PARAMETERS*); -static unsigned short ExtractObjParts_faces(T_RSPMODEL_OBJ_PARTS*, const MEMFILE, const RSPMODEL_PARAMETERS*); + +static unsigned short ParseObjectHeader(T_RSPMODEL_OBJECT*, const MEMFILE, const unsigned char, const RSPMODEL_PARAMETERS*); +static unsigned short ParseObjectPartsHeaders(T_RSPMODEL_OBJECT*, const MEMFILE, const RSPMODEL_PARAMETERS*); +static unsigned short ParseObjectPartHeader(T_RSPMODEL_OBJ_PARTS*, const MEMFILE, const int, const unsigned char, const RSPMODEL_PARAMETERS*); +static unsigned short ParseObjectMeshDef(T_RSPMODEL_OBJ_PARTS*, const MEMFILE, const RSPMODEL_PARAMETERS*); +static unsigned short ParseObjectFaceblockHeader(T_RSPMODEL_OBJ_PARTS*, const MEMFILE, const RSPMODEL_PARAMETERS*); +static unsigned short ParseObjectFace(T_RSPMODEL_FACE*, const MEMFILE, unsigned int* const, const unsigned int, const RSPMODEL_PARAMETERS*); +static unsigned short ParseObjectFaceVertices(T_RSPMODEL_VERTEX*, const MEMFILE, const unsigned int, const unsigned int, const RSPMODEL_PARAMETERS*); + static unsigned short ExtractObjpart_Face_Colors(T_RSPMODEL_FACE*, const char*); static unsigned short ExtractObjpart_Face_UVMaps(T_RSPMODEL_FACE*, const char*); @@ -102,7 +109,8 @@ unsigned short RSP_ModelLib_FreeHOBFile(const MEMFILE* memFile) { * @return Error code, RSPLIB_SUCCESS when no error. */ static unsigned short ExtractObjects(T_RSPMODEL_HOB* pHobStruct, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) { - unsigned int i; + unsigned int i, j, k; + unsigned int faceExtraOffset = 0; if (pHobStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL; @@ -119,272 +127,436 @@ static unsigned short ExtractObjects(T_RSPMODEL_HOB* pHobStruct, const MEMFILE p if (pHobStruct->objects == NULL) return RSPLIB_ERROR_MEMORY; for ( i = 0; i < pHobStruct->obj_count; i++ ) { - if (pParams->debug_mode) printf("\n-=====================-Begin of Object part-======================-\n"); + if (pParams->debug_mode) printf("\n-=======================- Begin of Object -=======================-\n"); - // Get object name - memcpy(pHobStruct->objects[i].name, ((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER) - + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->object_name, 16); + // Parse object headers + ParseObjectHeader(&pHobStruct->objects[i], pMemfile, i, pParams); - if (pParams->verbose_mode) printf("\n[INFO] - Process %s object...\n", pHobStruct->objects[i].name); + // Extract object parts + ParseObjectPartsHeaders(&pHobStruct->objects[i], pMemfile, pParams); + pHobStruct->objects[i].object_parts = calloc(pHobStruct->objects[i].object_part_count, sizeof(T_RSPMODEL_OBJ_PARTS)); + if (pHobStruct->objects[i].object_parts == NULL) return RSPLIB_ERROR_MEMORY; - // Get offsets - pHobStruct->objects[i].face_group_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER) - + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->facegroup_offset; - if (pParams->verbose_mode) printf("[DBG] > Face group offset: 0x%X\n", pHobStruct->objects[i].face_group_offset); - pHobStruct->objects[i].object_part_header_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER) - + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->object_parts_offset; - if (pParams->verbose_mode) printf("[DBG] > Face group header/object parts offset: 0x%X\n", pHobStruct->objects[i].object_part_header_offset); - pHobStruct->objects[i].face_group_header_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER) - + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->facegroup_header_2_offset; - if (pParams->verbose_mode) printf("[DBG] > Face group header2 offset: 0x%X\n", pHobStruct->objects[i].face_group_header_offset); + for ( j = 0; j < pHobStruct->objects[i].object_part_count; j++ ) { + if (pParams->debug_mode) printf("\n-~~~~~~~~~~~~~~~~~~~~~- Begin of obj. part -~~~~~~~~~~~~~~~~~~~~~~-\n"); - if (pParams->god_mode) { - printf("[DBG] > Face group unknown1: %d\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknownOffset1); - printf("[DBG] > Face group unknown2: %d\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknownOffset2); - printf("[DBG] > Face group unknown3: %d\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknownOffset3); - printf("[DBG] > Face group unknown4: %.8f\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknown4); + // Parse object parts headers + ParseObjectPartHeader(&pHobStruct->objects[i].object_parts[j], pMemfile, pHobStruct->objects[i].object_parts_header_offset, j, pParams); + + // Parse object meshdef + ParseObjectMeshDef(&pHobStruct->objects[i].object_parts[j], pMemfile, pParams); + + if (pHobStruct->objects[i].object_parts[j].meshdef1_offset) { + if (pParams->debug_mode) printf("\n------------------------- Begin of Mesh -------------------------\n"); + + // Extract object faces header datas + ParseObjectFaceblockHeader(&pHobStruct->objects[i].object_parts[j], pMemfile, pParams); + + pHobStruct->objects[i].object_parts[j].faces = calloc(pHobStruct->objects[i].object_parts[j].face_count, sizeof(T_RSPMODEL_FACE)); + if (pHobStruct->objects[i].object_parts[j].faces == NULL) return RSPLIB_ERROR_MEMORY; + + faceExtraOffset = pHobStruct->objects[i].object_parts[j].face_block_offset + sizeof(T_HOBFILE_FACEBLOCK); + for ( k = 0; k < pHobStruct->objects[i].object_parts[j].face_count; k++ ) { + if (pParams->debug_mode) printf("\n-......................- Begin of Face -.....................-\n"); + + ParseObjectFace(&pHobStruct->objects[i].object_parts[j].faces[k], pMemfile, &faceExtraOffset, k, pParams); + + if (pParams->debug_mode) printf("\n-.......................- End of Face -......................-\n"); + } + + // Get vertex datas + pHobStruct->objects[i].object_parts[j].vertices = calloc(pHobStruct->objects[i].object_parts[j].vertex_count, sizeof(T_RSPMODEL_VERTEX)); + if (pHobStruct->objects[i].object_parts[j].vertices == NULL) return RSPLIB_ERROR_MEMORY; + + for ( k = 0; k < pHobStruct->objects[i].object_parts[j].vertex_count; k++ ) { + ParseObjectFaceVertices(&pHobStruct->objects[i].object_parts[j].vertices[k], pMemfile, + pHobStruct->objects[i].object_parts[j].vertex_block_offset + sizeof(T_RSPMODEL_VERTEX) * k, k, pParams); + } + + if (pParams->debug_mode) printf("\n------------------------- End of Mesh ---------------------------\n"); + } + + if (pParams->debug_mode) printf("\n-~~~~~~~~~~~~~~~~~~~~~~- End of obj. part -~~~~~~~~~~~~~~~~~~~~~~~-\n"); } - // Get count and offsets from the facegroup header - pHobStruct->objects[i].object_part_count = ((T_HOBFILE_FACEGROUP_HEADER *)(pMemfile - + pHobStruct->objects[i].object_part_header_offset))->object_part_count; - if (pParams->verbose_mode) printf("[DBG] > Object parts count: %d\n", pHobStruct->objects[i].object_part_count); - pHobStruct->objects[i].face_group_count = ((T_HOBFILE_FACEGROUP_HEADER *)(pMemfile - + pHobStruct->objects[i].object_part_header_offset))->facegroup_count; - if (pParams->verbose_mode) printf("[DBG] > Face groups count: %d\n", pHobStruct->objects[i].face_group_count); - //TODO: Caution with obj/facegrp count difference. What is facegroup count??? - /* - * Seem "object" are independant structure like xwing, turret, etc. - * Facegroup is more like part of previous object, like wing-left, turret-barrel, etc. - */ - if (pHobStruct->objects[i].object_part_count != pHobStruct->objects[i].face_group_count) - if (pParams->verbose_mode) printf("[DBG] > Object parts / facegroup count are different!\n"); - - // Get facegroup datas - ExtractObjParts(&pHobStruct->objects[i], pMemfile, pParams); + if (pParams->debug_mode) printf("\n-=======================- End of Object -=========================-\n"); } return RSPLIB_SUCCESS; } /** - * @brief Count object's sub-part and extract datas from them. + * @brief Parse datas from object's header * - * @param[in|out] pObject Take object structure to get the T_RSPMODEL_OBJ_PARTS buffer and object datas. - * @param[in] pMemfile Pointer to an in-memory file location. - * @param[in] pParams Program option, used to tune parser features. + * @param[in|out] pObjStruct Take object structure and fill it with header datas. + * @param[in] pMemfile Pointer to an in-memory file location. + * @param[in] objIndex Object index for correct offset align. + * @param[in] pParams Program option, used to tune parser features. * * @return Error code, RSPLIB_SUCCESS when no error. */ -static unsigned short ExtractObjParts(T_RSPMODEL_OBJECT* pObject, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) { - unsigned int i, subpart_offset = 0; +static unsigned short ParseObjectHeader(T_RSPMODEL_OBJECT* pObjStruct, const MEMFILE pMemfile, const unsigned char objIndex, const RSPMODEL_PARAMETERS* pParams) { + if (pObjStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL; - if (pObject == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL; + // Create struct casting for clean code reading + const T_HOBFILE_OBJ_HEADER* const hobObjHeader = + ((T_HOBFILE_OBJ_HEADER*)(pMemfile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_HEADER) * objIndex)); - pObject->object_parts = calloc(pObject->object_part_count, sizeof(T_RSPMODEL_OBJ_PARTS)); - if (pObject->object_parts == NULL) return RSPLIB_ERROR_MEMORY; + // Get object name + memcpy(pObjStruct->name, hobObjHeader->object_name, 16); + if (pParams->verbose_mode) printf("\n[INFO] - Process %s object...\n", pObjStruct->name); - for ( i = 0; i < pObject->object_part_count; i++ ) { - if (pParams->debug_mode) printf("\n-----------------------Begin of Mesh part-------------------------\n"); - subpart_offset = ((T_HOBFILE_FACEGROUP_OFFSET *)(pMemfile + pObject->object_part_header_offset - + sizeof(T_HOBFILE_FACEGROUP_HEADER) + sizeof(T_HOBFILE_FACEGROUP_OFFSET) * i))->facegroup_offset; - if (pParams->verbose_mode) printf("\n[DBG] > Face group meshdef0 offset: 0x%X\n", subpart_offset); - - // Get meshdef0 datas - if (pParams->god_mode) printf("[DBG] > meshdef0 offset1: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->offset1); - if (pParams->god_mode) printf("[DBG] > meshdef0 offset2: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->offset2); - if (pParams->verbose_mode) printf("[DBG] > Prev meshdef0 offset: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->prev_meshdef0_offset); - if (pParams->verbose_mode) printf("[DBG] > Next meshdef0 offset: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->next_meshdef0_offset); - - if (pParams->god_mode) printf("[DBG] > meshdef0 unknown3: %.8f\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->unknown3); - if (pParams->god_mode) printf("[DBG] > meshdef0 unknown4: %.8f\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->unknown4); - if (pParams->god_mode) printf("[DBG] > meshdef0 unknown5: %.8f\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->unknown5); - - // Get meshdef1 (mesh descriptor) offset - pObject->object_parts[i].meshdef1_offset = ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->meshdef1_offset_plus_4; - if (pParams->verbose_mode) printf("\n[DBG] > Face group meshdef1 offset: 0x%X\n", pObject->object_parts[i].meshdef1_offset); - - if( ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->reserved1 != 0 || - ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->reserved2 != 0 ) { - if (pParams->god_mode) printf("[DBG] > Face group meshdef0: no 0!\n"); - } - - if (pObject->object_parts[i].meshdef1_offset > 0) { - // Read meshdef1 datas - pObject->object_parts[i].face_block_end_offset = ((T_HOBFILE_MESHDEF1 *)(pMemfile - + pObject->object_parts[i].meshdef1_offset - 4))->facedef_end_offset; - pObject->object_parts[i].vertex_count = ((T_HOBFILE_MESHDEF1 *)(pMemfile - + pObject->object_parts[i].meshdef1_offset - 4))->vertex_count; - if (pParams->verbose_mode) printf("[DBG] > Vertex count: %d\n", pObject->object_parts[i].vertex_count); - pObject->object_parts[i].face_block_offset = ((T_HOBFILE_MESHDEF1 *)(pMemfile - + pObject->object_parts[i].meshdef1_offset - 4))->faceblock_offset; - if (pParams->verbose_mode) printf("[DBG] > Faces offset: 0x%X\n", pObject->object_parts[i].face_block_offset); - pObject->object_parts[i].vertex_block_offset = ((T_HOBFILE_MESHDEF1 *)(pMemfile - + pObject->object_parts[i].meshdef1_offset - 4))->vertexblocks_offset; - if (pParams->verbose_mode) printf("[DBG] > Vertex offset: 0x%X\n\n", pObject->object_parts[i].vertex_block_offset); - - // Get faces datas - ExtractObjParts_faces(&pObject->object_parts[i], pMemfile, pParams); - } - - // Get object part ID, used by animation? bones? - pObject->object_parts[i].id = ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->object_id; - if (pParams->verbose_mode) printf("\n[DBG] > Facegroup/object ID: %d\n", pObject->object_parts[i].id); - - // Get the transform matrix, used by at-st and at-at (at this time) - pObject->object_parts[i].transform.x = ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->transform_x; - pObject->object_parts[i].transform.y = ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->transform_y; - pObject->object_parts[i].transform.z = ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->transform_z; - if (pParams->god_mode) printf("\n[DBG] > Facegroup/object transform matrix: [%.8f %.8f %.8f]\n", - pObject->object_parts[i].transform.x, - pObject->object_parts[i].transform.y, - pObject->object_parts[i].transform.z - ); - - if (pParams->debug_mode) printf("\n-----------------------End of Mesh part---------------------------\n"); + // Get offsets + pObjStruct->face_group_offset = hobObjHeader->facegroup_start_offset; + pObjStruct->object_parts_header_offset = hobObjHeader->object_parts_offset; + pObjStruct->object_parts_header_offset2 = hobObjHeader->object_parts_offset2; + pObjStruct->object_parts_header2_offset = hobObjHeader->object_parts2_offset; + pObjStruct->object_parts_header2_offset2 = hobObjHeader->object_parts2_offset2; + pObjStruct->object_subparts_names_offset = hobObjHeader->subparts_namelist_offset; + pObjStruct->effects_offset = hobObjHeader->effects_offset; + pObjStruct->properties_offset2 = hobObjHeader->properties_offset; + if (pParams->verbose_mode) { + printf("[DBG] > Face group start offset: 0x%X\n", pObjStruct->face_group_offset); + printf("[DBG] > Object parts 1st header offset (main): 0x%X\n", pObjStruct->object_parts_header_offset); + printf("[DBG] > Object parts 1st header offset (aux): 0x%X\n", pObjStruct->object_parts_header_offset2); + printf("[DBG] > Object parts 2nd header offset (main): 0x%X\n", pObjStruct->object_parts_header2_offset); + printf("[DBG] > Object parts 2nd header offset (aux): 0x%X\n", pObjStruct->object_parts_header2_offset2); + printf("[DBG] > Object subparts names offset: 0x%X\n", pObjStruct->object_subparts_names_offset); + printf("[DBG] > Object effects offset: 0x%X\n", pObjStruct->effects_offset); + printf("[DBG] > Object properties offset: 0x%X\n", pObjStruct->properties_offset2); } - if (pParams->debug_mode) printf("\n-=====================-End of Object part-========================-\n"); + // Get bounding box + pObjStruct->bounding_box.start.x = hobObjHeader->bbox_start_x; + pObjStruct->bounding_box.start.y = hobObjHeader->bbox_start_y; + pObjStruct->bounding_box.start.z = hobObjHeader->bbox_start_z; + pObjStruct->bounding_box.end.x = hobObjHeader->bbox_end_x; + pObjStruct->bounding_box.end.y = hobObjHeader->bbox_end_y; + pObjStruct->bounding_box.end.z = hobObjHeader->bbox_end_z; + if (pParams->verbose_mode) { + printf("[DBG] > Bounding box start: (%.8f, %.8f, %.8f)\n", + pObjStruct->bounding_box.start.x, + pObjStruct->bounding_box.start.y, + pObjStruct->bounding_box.start.z + ); + printf("[DBG] > Bounding box end: (%.8f, %.8f, %.8f)\n", + pObjStruct->bounding_box.end.x, + pObjStruct->bounding_box.end.y, + pObjStruct->bounding_box.end.z + ); + } + + if (pParams->god_mode) { + printf("[DBG] > Object header unknown4: %.8f\n", hobObjHeader->unknown4); + } return RSPLIB_SUCCESS; } /** - * @brief Extract datas from faces from object sub-part. + * @brief Parse datas from object parts's headers * - * @param[in|out] pObjPart Take object sub-part structure to get the T_RSPMODEL_FACE buffer and object sub-part datas. - * @param[in] pMemfile Pointer to an in-memory file location. - * @param[in] pParams Program option, used to tune parser features. + * "objects" are individual, independent from each others, element of the game world. + * "object parts" are a group of mesh isolated by their animation attribute (and probably others physics attributes...) + * "facegroup" are like object parts but isolated by their rendering properties like associated texture, lighting properties, etc. + * + * @param[in|out] pObjStruct Take object structure and fill it with header datas. + * @param[in] pMemfile Pointer to an in-memory file location. + * @param[in] pParams Program option, used to tune parser features. * * @return Error code, RSPLIB_SUCCESS when no error. */ -static unsigned short ExtractObjParts_faces(T_RSPMODEL_OBJ_PARTS* pObjPart, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) { - unsigned int i, facesExtraOffset = 0; +static unsigned short ParseObjectPartsHeaders(T_RSPMODEL_OBJECT* pObjStruct, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) { + unsigned int i; + char tmpStr[9] = {0}; + if (pObjStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL; - if (pObjPart == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL; - if( ((T_HOBFILE_FACEBLOCK *)(pMemfile + pObjPart->face_block_offset))->reserved1 != 0 || - ((T_HOBFILE_FACEBLOCK *)(pMemfile + pObjPart->face_block_offset))->reserved2 != 0 ) { - if (pParams->god_mode) printf("[DBG] > Face block: uncommon zero header!\n"); - } - if ( ((T_HOBFILE_FACEBLOCK *)(pMemfile + pObjPart->face_block_offset))->facesOffset != - pObjPart->face_block_offset + sizeof(T_HOBFILE_FACEBLOCK)) { - if (pParams->god_mode) printf("[DBG] > Face block: uncommon face data offset position!\n"); + + // Create struct casting for clean code reading + const T_HOBFILE_OBJPARTS_HEADER* const hobObjPartsHeader1 = ((T_HOBFILE_OBJPARTS_HEADER*)(pMemfile + pObjStruct->object_parts_header_offset)); + const T_HOBFILE_OBJPARTS_NAMEID* const hobObjPartsNames = ((T_HOBFILE_OBJPARTS_NAMEID*)(pMemfile + pObjStruct->object_subparts_names_offset)); + + // Get count and offsets from the facegroup header + pObjStruct->object_part_count = hobObjPartsHeader1->object_part_count; + pObjStruct->face_group_count = hobObjPartsHeader1->facegroup_count; + if (pParams->verbose_mode) { + printf("\n"); + printf("[DBG] > Object parts count: %d\n", pObjStruct->object_part_count); + printf("[DBG] > Face groups count: %d\n", pObjStruct->face_group_count); } - pObjPart->face_count = ((T_HOBFILE_FACEBLOCK *)(pMemfile + pObjPart->face_block_offset))->faceCounts; - pObjPart->faces = calloc(pObjPart->face_count, sizeof(T_RSPMODEL_FACE)); - for ( i = 0; i < pObjPart->face_count; i++ ) { - if (pParams->debug_mode) printf("\n----------------------Begin of Face part----------------------\n"); + //TODO: others T_HOBFILE_FACEGROUP_XXXXXXX parsing - // Get flags - pObjPart->faces[i].flags = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset - + sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->flags; + // Get names from object parts and ID association + printf("\n"); + for (i = 0; i < (pObjStruct->object_part_count - 1); i++) { // object_part_count minus 1 because the first one (id=0) is always the root part + memcpy(tmpStr, hobObjPartsNames[i].name, 8); + if (pParams->verbose_mode) + printf("[DBG] > Object parts ID/name found: %d/%s\n", hobObjPartsNames[i].id, tmpStr); - // Get unknown bytes - pObjPart->faces[i].b1 = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset - + sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->b1; - pObjPart->faces[i].b2 = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset - + sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->b2; - pObjPart->faces[i].b3 = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset - + sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->b3; - - pObjPart->faces[i].bsize = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset - + sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->faceBlockIntSize * 4; // Multiply by 4 to get the bytes exact number - if (((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset + sizeof(T_HOBFILE_FACEBLOCK) - + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->headerSeparator != 0) { - if (pParams->god_mode) printf("[DBG] > Face header: uncommon separator!\n"); - } - - // Get materials index - pObjPart->faces[i].mt_index = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset - + sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->materialIndex; - - // Get vertex indices - memcpy(pObjPart->faces[i].indices, ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset - + sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->vertexIndices, - sizeof(unsigned short) * 4); - - // Recalculate the dynamic extra bytes offset size - if present - if (pObjPart->faces[i].flags_bits.fHasExtraBytesBeforeColor) facesExtraOffset += 8; - - // Get vertex color - if present - if (pObjPart->faces[i].flags_bits.fHasColor) { - facesExtraOffset += ExtractObjpart_Face_Colors(&pObjPart->faces[i], pMemfile + pObjPart->face_block_offset - + sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) + sizeof(T_HOBFILE_FACES_HEADER) * i - + facesExtraOffset); - } - - // Get UV map - if present - if (pObjPart->faces[i].flags_bits.fHasTexture) { - facesExtraOffset += ExtractObjpart_Face_UVMaps(&pObjPart->faces[i], pMemfile + pObjPart->face_block_offset - + sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) + sizeof(T_HOBFILE_FACES_HEADER) * i - + facesExtraOffset); - } - - if (pParams->debug_mode) { - printf("[DBG] > Face %d details: flags:0x%X b1:%d b2:%d b3%d bsize:%d\n", i, pObjPart->faces[i].flags, - pObjPart->faces[i].b1, pObjPart->faces[i].b2, pObjPart->faces[i].b3, pObjPart->faces[i].bsize); - printf("[DBG] - Type is Quad: %d\n", pObjPart->faces[i].flags_bits.fIsQuad); - printf("[DBG] - Have color: %d\n", pObjPart->faces[i].flags_bits.fHasColor); - printf("[DBG] - Have texture: %d\n", pObjPart->faces[i].flags_bits.fHasTexture); - printf("[DBG] - Material/texture index: %d\n", pObjPart->faces[i].mt_index); - printf("[DBG] - Vertex indices: %d, %d, %d, %d\n", pObjPart->faces[i].indices[0], pObjPart->faces[i].indices[1], - pObjPart->faces[i].indices[2], pObjPart->faces[i].indices[3]); - printf("[DBG] - Vertex colors: 0x%X, 0x%X, 0x%X, 0x%X\n", pObjPart->faces[i].vertex_colors[0], - pObjPart->faces[i].vertex_colors[1], pObjPart->faces[i].vertex_colors[2], pObjPart->faces[i].vertex_colors[3]); - printf("[DBG] - Vertex UV coord (divided by 4096):\n"); - printf("[DBG] > %.8f(%d), %.8f(%d)\n", - ((double) 1/4096) * pObjPart->faces[i].tex_coords[0].u, - pObjPart->faces[i].tex_coords[0].u, - ((double) 1/4096) * pObjPart->faces[i].tex_coords[0].v, - pObjPart->faces[i].tex_coords[0].v - ); - printf("[DBG] > %.8f(%d), %.8f(%d)\n", - ((double) 1/4096) * pObjPart->faces[i].tex_coords[1].u, - pObjPart->faces[i].tex_coords[1].u, - ((double) 1/4096) * pObjPart->faces[i].tex_coords[1].v, - pObjPart->faces[i].tex_coords[1].v - ); - printf("[DBG] > %.8f(%d), %.8f(%d)\n", - ((double) 1/4096) * pObjPart->faces[i].tex_coords[2].u, - pObjPart->faces[i].tex_coords[2].u, - ((double) 1/4096) * pObjPart->faces[i].tex_coords[2].v, - pObjPart->faces[i].tex_coords[2].v - ); - printf("[DBG] > %.8f(%d), %.8f(%d)\n", - ((double) 1/4096) * pObjPart->faces[i].tex_coords[3].u, - pObjPart->faces[i].tex_coords[3].u, - ((double) 1/4096) * pObjPart->faces[i].tex_coords[3].v, - pObjPart->faces[i].tex_coords[3].v - ); - printf("\n"); - } - - if (pParams->debug_mode) printf("\n-----------------------End of Face part-----------------------\n"); + if (pParams->god_mode && hobObjPartsNames[i].unknown0) + printf("[DBG] > Object parts ID unknown0 unexpected: 0x%X\n", hobObjPartsNames[i].unknown0); } - // Get vertex datas - pObjPart->vertices = calloc(pObjPart->vertex_count, sizeof(T_RSPMODEL_VERTEX)); - if (pObjPart->vertices == NULL) return RSPLIB_ERROR_MEMORY; + return RSPLIB_SUCCESS; +} - for ( i = 0; i < pObjPart->vertex_count; i++ ) { - pObjPart->vertices[i].x = - ((T_HOBFILE_VERTEX *)(pMemfile + pObjPart->vertex_block_offset + sizeof(T_RSPMODEL_VERTEX) * i))->x; +/** + * @brief Parse datas from the specific object header. + * + * @param[in|out] pObjPartStruct Take object part structure and fill it with header datas. + * @param[in] pMemfile Pointer to an in-memory file location. + * @param[in] objPartIndex Object part index for correct offset align. + * @param[in] pParams Program option, used to tune parser features. + * + * @return Error code, RSPLIB_SUCCESS when no error. + */ +static unsigned short ParseObjectPartHeader(T_RSPMODEL_OBJ_PARTS* pObjPartStruct, const MEMFILE pMemfile, + const int objPartHdrOffset, const unsigned char objPartIndex, const RSPMODEL_PARAMETERS* pParams) { - pObjPart->vertices[i].y = - ((T_HOBFILE_VERTEX *)(pMemfile + pObjPart->vertex_block_offset + sizeof(T_RSPMODEL_VERTEX) * i))->y; + if (pObjPartStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL; - pObjPart->vertices[i].z = - ((T_HOBFILE_VERTEX *)(pMemfile + pObjPart->vertex_block_offset + sizeof(T_RSPMODEL_VERTEX) * i))->z; + // Create struct casting for clean code reading + const T_HOBFILE_OBJPART_HEADER* const hobObjPartHeader = ((T_HOBFILE_OBJPART_HEADER *)(pMemfile + objPartHdrOffset + + sizeof(T_HOBFILE_OBJPARTS_HEADER) + sizeof(T_HOBFILE_OBJPART_HEADER) * objPartIndex)); - pObjPart->vertices[i].w = - ((T_HOBFILE_VERTEX *)(pMemfile + pObjPart->vertex_block_offset + sizeof(T_RSPMODEL_VERTEX) * i))->w; // Always 0??? + // Get object part datas offset + pObjPartStruct->meshdef0_offset = hobObjPartHeader->facegroup_offset; + if (pParams->verbose_mode) printf("[DBG] > Obj. part %d facegroup (meshdef0) array offset: 0x%X\n", objPartIndex, pObjPartStruct->meshdef0_offset); + if (pParams->god_mode) printf("[DBG] > Obj. part unknown0: 0x%X\n", hobObjPartHeader->unknown0); - if (pParams->debug_mode) printf("[DBG] > Found vertex %d: (%d, %d, %d)\n", i, - pObjPart->vertices[i].x, pObjPart->vertices[i].y, pObjPart->vertices[i].z - ); + return RSPLIB_SUCCESS; +} + +/** + * @brief Parse datas from object mesh definition. + * + * MeshDef (or Facegroup) is a compact structure containing the global geometry informations of a specific mesh. + * It's split in 2 parts: meshdef0 and meshdef1, meshdef1 offset is indicated in meshdef0 struct. + * + * @param[in|out] pObjPartStruct Take object part structure and fill it with header datas. + * @param[in] pMemfile Pointer to an in-memory file location. + * @param[in] pParams Program option, used to tune parser features. + * + * @return Error code, RSPLIB_SUCCESS when no error. + */ +static unsigned short ParseObjectMeshDef(T_RSPMODEL_OBJ_PARTS* pObjPartStruct, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) { + if (pObjPartStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL; + + // Create struct casting for clean code reading + const T_HOBFILE_MESHDEF0* const hobObjMeshDef0 = ((T_HOBFILE_MESHDEF0*)(pMemfile + pObjPartStruct->meshdef0_offset)); + + // Get meshdef0 datas + //pObjPartStruct->id = hobObjMeshDef0->object_id; // Get object part ID, used by animation? bones? + pObjPartStruct->transform.x = hobObjMeshDef0->transform_x; // Get the transform matrix, used by complex objects like at-st and at-at (at this time) + pObjPartStruct->transform.y = hobObjMeshDef0->transform_y; + pObjPartStruct->transform.z = hobObjMeshDef0->transform_z; + if (pParams->verbose_mode) { + printf("[DBG] > Facegroup/object transform matrix: [%.8f %.8f %.8f]\n", + pObjPartStruct->transform.x, + pObjPartStruct->transform.y, + pObjPartStruct->transform.z + ); + printf("[DBG] > Prev meshdef0 offset: 0x%X\n", hobObjMeshDef0->prev_meshdef0_offset); + printf("[DBG] > Next meshdef0 offset: 0x%X\n", hobObjMeshDef0->next_meshdef0_offset); + } + if (pParams->god_mode) { + printf("[DBG] > meshdef0 offset1: 0x%X\n", hobObjMeshDef0->offset1); + printf("[DBG] > meshdef0 offset2: 0x%X\n", hobObjMeshDef0->offset2); + + printf("[DBG] > meshdef0 unknown3: %.8f\n", hobObjMeshDef0->unknown3); + printf("[DBG] > meshdef0 unknown4: %.8f\n", hobObjMeshDef0->unknown4); + printf("[DBG] > meshdef0 unknown5: %.8f\n", hobObjMeshDef0->unknown5); + + printf("[DBG] > meshdef0 unknown6: 0x%X\n", hobObjMeshDef0->unknown6); + + printf("[DBG] > meshdef0 unknown7: %.8f\n", hobObjMeshDef0->unknown7); + printf("[DBG] > meshdef0 unknown8: %.8f\n", hobObjMeshDef0->unknown8); + printf("[DBG] > meshdef0 unknown9: %.8f\n", hobObjMeshDef0->unknown9); + + printf("[DBG] > meshdef0 unknown10: %.8f\n", hobObjMeshDef0->unknown10); + printf("[DBG] > meshdef0 unknown11: %.8f\n", hobObjMeshDef0->unknown11); + printf("[DBG] > meshdef0 unknown12: %.8f\n", hobObjMeshDef0->unknown12); + + printf("[DBG] > meshdef0 unknown13: %.8f\n", hobObjMeshDef0->unknown13); + printf("[DBG] > meshdef0 unknown14: %.8f\n", hobObjMeshDef0->unknown14); + printf("[DBG] > meshdef0 unknown15: %.8f\n", hobObjMeshDef0->unknown15); + + printf("[DBG] > meshdef0 unknown16: %.8f\n", hobObjMeshDef0->unknown16); + } + + // Get meshdef1 (mesh descriptor) offset + pObjPartStruct->meshdef1_offset = hobObjMeshDef0->meshdef1_offset_plus_4; + if (pObjPartStruct->meshdef1_offset > 0) { + const T_HOBFILE_MESHDEF1* const hobObjMeshDef1 = ((T_HOBFILE_MESHDEF1*)(pMemfile + pObjPartStruct->meshdef1_offset - 4)); + + // Read meshdef1 datas + pObjPartStruct->face_block_end_offset = hobObjMeshDef1->facedef_end_offset; + pObjPartStruct->vertex_count = hobObjMeshDef1->vertex_count; + pObjPartStruct->face_block_offset = hobObjMeshDef1->faceblock_offset; + pObjPartStruct->vertex_block_offset = hobObjMeshDef1->vertexblocks_offset; + if (pParams->verbose_mode) { + printf("\n[DBG] > Facegroup vertices descriptor (meshdef1) offset: 0x%X\n", pObjPartStruct->meshdef1_offset); + printf("[DBG] > Vertex count: %d\n", pObjPartStruct->vertex_count); + printf("[DBG] > Faces offset: 0x%X\n", pObjPartStruct->face_block_offset); + printf("[DBG] > Vertex offset: 0x%X\n", pObjPartStruct->vertex_block_offset); + } + } else { + if (pParams->verbose_mode) printf("\n[DBG] > No vertices datas (meshdef1 = 0x0).\n"); + } + + return RSPLIB_SUCCESS; +} + +/** + * @brief Parse datas from object faceblock header. + * + * Faceblock is group of faces elements with header. + * Meshdef have one associated faceblock. + * + * @param[in|out] pObjPartStruct Take object part structure and fill it with header datas. + * @param[in] pMemfile Pointer to an in-memory file location. + * @param[in] pParams Program option, used to tune parser features. + * + * @return Error code, RSPLIB_SUCCESS when no error. + */ +static unsigned short ParseObjectFaceblockHeader(T_RSPMODEL_OBJ_PARTS* pObjPartStruct, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) { + if (pObjPartStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL; + + // Create struct casting for clean code reading + const T_HOBFILE_FACEBLOCK* const hobObjFaceblock = ((T_HOBFILE_FACEBLOCK*)(pMemfile + pObjPartStruct->face_block_offset)); + + // Get faces count + pObjPartStruct->face_count = hobObjFaceblock->faceCounts; + if (pParams->debug_mode) printf("[DBG] > Faces count: %d\n", pObjPartStruct->face_count); + + if (pParams->god_mode) { + if( hobObjFaceblock->reserved1 != 0 || hobObjFaceblock->reserved2 != 0 ) { + printf("[DBG] > Faceblock: uncommon zero header! (0x%X) (0x%X)\n", hobObjFaceblock->reserved1, hobObjFaceblock->reserved2); + } + if ( hobObjFaceblock->facesOffset != pObjPartStruct->face_block_offset + sizeof(T_HOBFILE_FACEBLOCK) ) { + printf("[DBG] > Faceblock: uncommon face data offset position!\n"); + } + } + + return RSPLIB_SUCCESS; +} + +/** + * @brief Parse datas from object face. + * + * @param[in|out] pFaceStruct Take face structure and fill it with face datas. + * @param[in] pMemfile Pointer to an in-memory file location. + * @param[in|out] facesExtraOffset Face correction offset to correctly align with datas + * @param[in] faceNbr Face number (for debug print only) + * @param[in] pParams Program option, used to tune parser features. + * + * @return Error code, RSPLIB_SUCCESS when no error. + */ +static unsigned short ParseObjectFace(T_RSPMODEL_FACE* pFaceStruct, const MEMFILE pMemfile, + unsigned int* const facesExtraOffset, const unsigned int faceNbr, const RSPMODEL_PARAMETERS* pParams) { + unsigned int localOffset; + + if (pFaceStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL; + + // Create struct casting for clean code reading + const T_HOBFILE_FACES_HEADER* const hobObjFace = ((T_HOBFILE_FACES_HEADER*)(pMemfile + *facesExtraOffset)); + + // Get flags + pFaceStruct->flags = hobObjFace->flags; + + // Get unknown bytes + pFaceStruct->b1 = hobObjFace->b1; + pFaceStruct->b2 = hobObjFace->b2; + pFaceStruct->b3 = hobObjFace->b3; + pFaceStruct->bsize = hobObjFace->faceBlockIntSize * 4; // Multiply by 4 to get the bytes exact number + + if (hobObjFace->headerSeparator != 0) { + if (pParams->god_mode) printf("[DBG] > Face header: uncommon separator! (0x%X)\n", hobObjFace->headerSeparator); + } + + // Get materials index + pFaceStruct->mt_index = hobObjFace->materialIndex; + + // Get vertex indices + memcpy(pFaceStruct->indices, hobObjFace->vertexIndices, sizeof(unsigned short) * 4); + + // Recalculate the dynamic extra bytes offset size - if present + //if (pObjPart->faces[i].flags_bits.fHasExtraBytesBeforeColor) facesExtraOffset += 8; + localOffset = pFaceStruct->flags_bits.fHasExtraBytesBeforeColor ? 8 : 0; + + // Get vertex color - if present + if (pFaceStruct->flags_bits.fHasColor) { + localOffset += ExtractObjpart_Face_Colors(pFaceStruct, pMemfile + *facesExtraOffset + sizeof(T_HOBFILE_FACES_HEADER) + localOffset); + } + + // Get UV map - if present + if (pFaceStruct->flags_bits.fHasTexture) { + localOffset += ExtractObjpart_Face_UVMaps(pFaceStruct, pMemfile + *facesExtraOffset + sizeof(T_HOBFILE_FACES_HEADER) + localOffset); + } + + // Recalculate the extra bytes offset (it's assume the faces are parsed in order) + *facesExtraOffset += pFaceStruct->bsize; + + if (pParams->debug_mode) { + printf("[DBG] > Face %d details: flags:0x%X b1:0x%X b2:0x%X b3:0x%X bsize:%d\n", faceNbr, + pFaceStruct->flags, pFaceStruct->b1, pFaceStruct->b2, pFaceStruct->b3, pFaceStruct->bsize); + printf("[DBG] - Type is Quad: %d\n", pFaceStruct->flags_bits.fIsQuad); + printf("[DBG] - Have color: %d\n", pFaceStruct->flags_bits.fHasColor); + printf("[DBG] - Have texture: %d\n", pFaceStruct->flags_bits.fHasTexture); + printf("[DBG] - Material/texture index: %d\n", pFaceStruct->mt_index); + printf("[DBG] - Vertex indices: %d, %d, %d, %d\n", pFaceStruct->indices[0], pFaceStruct->indices[1], pFaceStruct->indices[2], pFaceStruct->indices[3]); + printf("[DBG] - Vertex colors: 0x%X, 0x%X, 0x%X, 0x%X\n", pFaceStruct->vertex_colors[0], pFaceStruct->vertex_colors[1], pFaceStruct->vertex_colors[2], pFaceStruct->vertex_colors[3]); + printf("[DBG] - Vertex UV coord (divided by 4096):\n"); + printf("[DBG] > %.8f(%d), %.8f(%d)\n", + ((double) 1/4096) * pFaceStruct->tex_coords[0].u, pFaceStruct->tex_coords[0].u, + ((double) 1/4096) * pFaceStruct->tex_coords[0].v, pFaceStruct->tex_coords[0].v + ); + printf("[DBG] > %.8f(%d), %.8f(%d)\n", + ((double) 1/4096) * pFaceStruct->tex_coords[1].u, pFaceStruct->tex_coords[1].u, + ((double) 1/4096) * pFaceStruct->tex_coords[1].v, pFaceStruct->tex_coords[1].v + ); + printf("[DBG] > %.8f(%d), %.8f(%d)\n", + ((double) 1/4096) * pFaceStruct->tex_coords[2].u, pFaceStruct->tex_coords[2].u, + ((double) 1/4096) * pFaceStruct->tex_coords[2].v, pFaceStruct->tex_coords[2].v + ); + printf("[DBG] > %.8f(%d), %.8f(%d)\n", + ((double) 1/4096) * pFaceStruct->tex_coords[3].u, pFaceStruct->tex_coords[3].u, + ((double) 1/4096) * pFaceStruct->tex_coords[3].v, pFaceStruct->tex_coords[3].v + ); + } + + return RSPLIB_SUCCESS; +} + +/** + * @brief Parse datas from object face. + * + * @param[in|out] pVertexStruct Take vertex structure and fill it with vertices datas. + * @param[in] pMemfile Pointer to an in-memory file location. + * @param[in] verticesOffset Vertices area offset to correctly align with datas + * @param[in] vertexNbr Vertex number (for debug print only) + * @param[in] pParams Program option, used to tune parser features. + * + * @return Error code, RSPLIB_SUCCESS when no error. + */ +static unsigned short ParseObjectFaceVertices(T_RSPMODEL_VERTEX* pVertexStruct, const MEMFILE pMemfile, + const unsigned int verticesOffset, const unsigned int vertexNbr, const RSPMODEL_PARAMETERS* pParams) { + + if (pVertexStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL; + + // Create struct casting for clean code reading + const T_HOBFILE_VERTEX* const hobObjVertex = ((T_HOBFILE_VERTEX*)(pMemfile + verticesOffset)); + + pVertexStruct->x = hobObjVertex->x; + pVertexStruct->y = hobObjVertex->y; + pVertexStruct->z = hobObjVertex->z; + pVertexStruct->w = hobObjVertex->w; // Always 0??? + + if (pParams->debug_mode) { + printf("[DBG] > Found vertex %d: (%d, %d, %d)\n", vertexNbr, pVertexStruct->x, pVertexStruct->y, pVertexStruct->z); } return RSPLIB_SUCCESS; diff --git a/RSPModelLib/src/hob_parser.h b/RSPModelLib/src/hob_parser.h index 587e661..6ac5bda 100644 --- a/RSPModelLib/src/hob_parser.h +++ b/RSPModelLib/src/hob_parser.h @@ -1,6 +1,6 @@ /** * @file hob_parser.h - * @date 18/01/2023 + * @date 21/02/2023 * @author JackCarterSmith * @copyright GPL-v3.0 * @brief Process HOB file structure and extract its datas. diff --git a/RSPModelLib/src/hob_struct.h b/RSPModelLib/src/hob_struct.h index 9b9ac3b..8380add 100644 --- a/RSPModelLib/src/hob_struct.h +++ b/RSPModelLib/src/hob_struct.h @@ -1,6 +1,6 @@ /** * @file hob_struct.h - * @date 26/07/2022 + * @date 21/02/2023 * @author JackCarterSmith * @copyright GPL-v3.0 * @brief HOB file mapping definition. @@ -36,61 +36,110 @@ /* * - Global HOB file structure- * +------------------+--------------------------------------+----------------------------------------+ - * | T_HOBFILE_HEADER | obj_count * T_HOBFILE_OBJ_DESCRIPTOR | obj_count * T_HOBFILE_FACEGROUP_HEADER | + * | T_HOBFILE_HEADER | obj_count * T_HOBFILE_OBJ_DESCRIPTOR | obj_count * T_HOBFILE_FACEGROUP_HEADER | --> * +------------------+--------------------------------------+----------------------------------------+ * * - Facegroup sub-structure - - * +----------------------------+------------------------------------------------+ - * | T_HOBFILE_FACEGROUP_HEADER | object_part_count * T_HOBFILE_FACEGROUP_OFFSET | - * +----------------------------+------------------------------------------------+ + * +------------------------------+--------------------------------------------------+ + * --> | T_HOBFILE_FACEGROUP_HEADER_1 | object_part_count * T_HOBFILE_FACEGROUP_OFFSET_1 | + * +------------------------------+--------------------------------------------------+ + * + * - Facegroup sub-structure 2 - + * +------------------------------+------------------------------------------------------------------------+--------------------------------------------------------+ + * | T_HOBFILE_FACEGROUP_HEADER_2 | ( object_part_count + facegroup_count ) * T_HOBFILE_FACEGROUP_OFFSET_2 | ( object_part_count - 1 ) * T_HOBFILE_FACEGROUP_NAMEID | + padding + * +------------------------------+------------------------------------------------------------------------+--------------------------------------------------------+ */ typedef struct PACK hobfile_header { unsigned int obj_count; unsigned int vertices_offset; } T_HOBFILE_HEADER; -typedef struct PACK hobfile_obj_descriptor { - unsigned char object_name[16]; - unsigned int facegroup_offset; - unsigned int object_parts_offset; - unsigned int facegroup_header_2_offset; +typedef struct PACK hobfile_obj_header { + unsigned char object_name[16]; // Name of the object - unsigned int reserved1; // 12B of zeros - unsigned int reserved2; - unsigned int reserved3; + unsigned int facegroup_start_offset; // First facegroup datas offset. Look in T_HOBFILE_FACEGROUP_HEADER for all offsets of facegroups of the current object. + unsigned int object_parts_offset; // Object parts descriptor offset + unsigned int object_parts_offset2; // Facegroup descriptor offset (subpart of Object parts descriptor) - unsigned int unknownOffset1; - unsigned int unknownOffset2; - unsigned int unknownOffset3; - float unknown4; + unsigned int object_parts2_offset; // Optional offset - seem present in tieinter_HOB - point just after the 0xFFFFFFFF of the first one + unsigned int object_parts2_offset2; // Optional offset - seem present in tieinter_HOB + unsigned int reserved1; // Always zeros ? - unsigned int reserved4; // 12B of zeros + unsigned int subparts_namelist_offset; // Point to an array of string value (8 chars) + ID (2 chars - 1 to obj_parts-1). Seem like name of articulation points (some have name like "node_86"). + unsigned int effects_offset; // Empty in gun_turret and no datas after, xwing have 0x5006, present in koelsch. worddevastator can have more answers... + unsigned int properties_offset; // Offset to different string (a_b/zf/zt/zb/etc.) Animation datas ? Empty with 6x float in train_hob, a_b object is canon beams in gun_turret + + float unknown4; // Probably scale: 1.0F/1.125F + + unsigned int reserved4; // 12B of zeros unsigned int reserved5; unsigned int reserved6; - float reserved7; + float unknown5; //Scale? ~20.0F + float unknown6; //Scale? ~77-418.0F + + float reserved7; //Translation matrix? Center of object? float reserved8; float reserved9; - float reserved10; - float reserved11; - unsigned int end_mask; // Always equal to 0xFFFFFFFF - float reserved12; - float reserved13; - float reserved14; - float reserved15; - float reserved16; - float reserved17; -} T_HOBFILE_OBJ_DESCRIPTOR; -typedef struct PACK hobfile_facegroup_header { + unsigned int footer_offset; //To redefine, seem to be a copy of following bounding box? Maybe there are 2 box: render and collision? + + float bbox_start_x; // Bounding box start vector + float bbox_start_y; + float bbox_start_z; + + float bbox_end_x; // Bounding box start vector + float bbox_end_y; + float bbox_end_z; +} T_HOBFILE_OBJ_HEADER; + + +/* + * T_HOBFILE_OBJPARTS_HEADER + * | + * \ + * |T_HOBFILE_OBJPART_HEADER + * \ + * T_HOBFILE_OBJPART_HEADER + * | + * \ + * |T_HOBFILE_FACEGROUP_HEADER + * \ + * T_HOBFILE_FACEGROUP_HEADER + */ +typedef struct PACK hobfile_objparts_header { + unsigned short object_part_count; + unsigned short facegroup_count; //aka. meshdef count +} T_HOBFILE_OBJPARTS_HEADER; + +typedef struct PACK hobfile_objpart_header { + unsigned int unknown0; // It is flags? + unsigned int facegroup_offset; +} T_HOBFILE_OBJPART_HEADER; + +/* TODO: Not sure these exist +typedef struct PACK hobfile_facegroup_header_2 { //TODO: This is part of a bigger one unsigned short object_part_count; unsigned short facegroup_count; -} T_HOBFILE_FACEGROUP_HEADER; +} T_HOBFILE_FACEGROUP_HEADER_2; -typedef struct PACK hobfile_facegroup_offset { - unsigned int unknown1; - unsigned int facegroup_offset; -} T_HOBFILE_FACEGROUP_OFFSET; +typedef struct PACK hobfile_facegroup_offset_2 { //TODO: This is part of a bigger one + unsigned int unknownOffset0; +} T_HOBFILE_FACEGROUP_OFFSET_2; +*/ + +typedef struct PACK hobfile_objparts_nameid { + unsigned char name[8]; + unsigned char unknown0; // Always zeros ? + unsigned char id; +} T_HOBFILE_OBJPARTS_NAMEID; + +/* TODO: +typedef struct PACK hobfile_effects { + unsigned char something0; + unsigned short something1; +} T_HOBFILE_EFFECTS; + */ typedef struct PACK hobfile_meshdef0 { unsigned int offset1; @@ -120,20 +169,21 @@ typedef struct PACK hobfile_meshdef0 { unsigned int reserved10; unsigned int reserved11; - unsigned int object_id; + unsigned int unknown6; // Not fg_object_ID - float unknown12; // Can be a vector??? - float unknown13; + float unknown7; // Can be a vector??? + float unknown8; + float unknown9; + + float unknown10; // Can be a vector??? + float unknown11; + float unknown12; + + float unknown13; // Can be a matrix??? float unknown14; + float unknown15; - float unknown15; // Can be a vector??? float unknown16; - float unknown17; - - float unknown18; // Can be a matrix??? - float unknown19; - float unknown20; - float unknown21; float transform_x; float transform_y; @@ -180,11 +230,11 @@ typedef struct PACK hobfile_faceblock { typedef struct PACK hobfile_faces_header { unsigned int flags; - unsigned char b1; // 74 = transparent / 75 = opaque - unsigned char b2; - unsigned char b3; + unsigned char b1; // Seem to alter texture mapping on face, 49 -> quad face, 48 -> tri face, 47 -> N/A + unsigned char b2; // 61 -> texture right rotation, 71 -> little red overlay, 81 -> bigger red overlay, x1 -> don't do anything + unsigned char b3; // Seem to alter rendering matrix or maybe vertices position relative to unsigned char faceBlockIntSize; // Bytes size divided by 4, count as number of UInt32 type. - unsigned short headerSeparator; + unsigned short headerSeparator; // If header it's uncommon, it's probably because you made a wrong parsing unsigned short materialIndex; unsigned short vertexIndices[4]; // Relative to facegroup, the last value is equal to 0 when it's triangle shape. } T_HOBFILE_FACES_HEADER; diff --git a/RSPModelLib/src/hob_struct2.h b/RSPModelLib/src/hob_struct2.h deleted file mode 100644 index 846e05b..0000000 --- a/RSPModelLib/src/hob_struct2.h +++ /dev/null @@ -1,246 +0,0 @@ -/** - * @file hob_struct.h - * @date 26/07/2022 - * @author JackCarterSmith - * @copyright GPL-v3.0 - * @brief HOB file mapping definition. - * - */ - -#ifndef RSPMODELLIB_HOB_STRUCT_H_ -#define RSPMODELLIB_HOB_STRUCT_H_ - - -/* - * long = 64bits??? - * int = 32bits - * short = 16bits - * car = 8bits - */ - -#if defined(_MSC_VER) -#define PACK -#elif defined(__GNUC__) -#define PACK __attribute__((packed)) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Declaration of Memory Mapped Structure -// Caution: the place of variable is important for correct mapping! -/////////////////////////////////////////////////////////////////////////////// - -#if defined(_MSC_VER) -#pragma pack(push, 1) -#endif - -/* - * - Global HOB file structure- - * +------------------+--------------------------------------+----------------------------------------+ - * | T_HOBFILE_HEADER | obj_count * T_HOBFILE_OBJ_DESCRIPTOR | obj_count * T_HOBFILE_FACEGROUP_HEADER | --> - * +------------------+--------------------------------------+----------------------------------------+ - * - * - Facegroup sub-structure - - * +------------------------------+--------------------------------------------------+ - * --> | T_HOBFILE_FACEGROUP_HEADER_1 | object_part_count * T_HOBFILE_FACEGROUP_OFFSET_1 | - * +------------------------------+--------------------------------------------------+ - * - * - Facegroup sub-structure 2 - - * +------------------------------+------------------------------------------------------------------------+--------------------------------------------------------+ - * | T_HOBFILE_FACEGROUP_HEADER_2 | ( object_part_count + facegroup_count ) * T_HOBFILE_FACEGROUP_OFFSET_2 | ( object_part_count - 1 ) * T_HOBFILE_FACEGROUP_NAMEID | + padding - * +------------------------------+------------------------------------------------------------------------+--------------------------------------------------------+ - */ -typedef struct PACK hobfile_header { - unsigned int obj_count; - unsigned int vertices_offset; -} T_HOBFILE_HEADER; - -typedef struct PACK hobfile_obj_header { - unsigned char object_name[16]; // Name of the object - - unsigned int facegroup_start_offset; // First facegroup datas offset. Look in T_HOBFILE_FACEGROUP_HEADER for all offsets of facegroups of the current object. - unsigned int object_parts_offset; // Object parts descriptor offset - unsigned int object_parts_offset2; // Facegroup descriptor offset (subpart of Object parts descriptor) - - unsigned int opt_offset1; // Optional offset - empty on last obj_header - point to after end mask ffffff of current bloc - unsigned int opt_offset2; // Optional offset - empty on last obj_header - point to after the previous opt_offset1 - unsigned int reserved1; // Always zeros ? - - unsigned int subparts_namelist_offset; // Point to an array of string value (8 chars) + ID (2 chars - 1 to obj_parts-1). Seem like name of articulation points (some have name like "node_86"). - unsigned int effects_offset; // Empty in gun_turret and no datas after, xwing have 0x5006. worddevastator should have the answer... - unsigned int properties_offset; // Offset to different string (a_b/zf/zt/zb/etc.) Animation datas ? Empty with 6x float in train_hob - - float unknown4; // Probably scale: 1.0F/1.125F - - unsigned int reserved4; // 12B of zeros - unsigned int reserved5; - unsigned int reserved6; - - float unknown5; //Scale? ~20.0F - float unknown6; //Scale? ~77-418.0F - - float reserved7; //Translation matrix? Center of object? - float reserved8; - float reserved9; - - unsigned int footer_offset; //To redefine, seem to be a copy of following bounding box? Maybe there are 2 box: render and collision? - - float bbox_start_x; // Bounding box start vector - float bbox_start_y; - float bbox_start_z; - - float bbox_end_x; // Bounding box start vector - float bbox_end_y; - float bbox_end_z; -} T_HOBFILE_OBJ_HEADER; - -typedef struct PACK hobfile_facegroup_header_1 { - unsigned short object_part_count; - unsigned short facegroup_count; -} T_HOBFILE_FACEGROUP_HEADER_1; - -typedef struct PACK hobfile_facegroup_offset_1 { - unsigned int unknown0; // Flags? - unsigned int facegroup_offset; -} T_HOBFILE_FACEGROUP_OFFSET_1; - -typedef struct PACK hobfile_facegroup_header_2 { - unsigned short object_part_count; - unsigned short facegroup_count; -} T_HOBFILE_FACEGROUP_HEADER_2; - -typedef struct PACK hobfile_facegroup_offset_2 { - unsigned int unknownOffset0; -} T_HOBFILE_FACEGROUP_OFFSET_2; - -typedef struct PACK hobfile_facegroup_nameid { - unsigned char name[8]; - unsigned short id; -} T_HOBFILE_FACEGROUP_NAMEID; - -typedef struct PACK hobfile_meshdef0 { - unsigned int offset1; - unsigned int offset2; - unsigned int prev_meshdef0_offset; - unsigned int next_meshdef0_offset; - unsigned int meshdef1_offset_plus_4; - - unsigned int reserved1; // 8B of zeros - unsigned int reserved2; - - float unknown3; - - unsigned int reserved3; // 12B of zeros - unsigned int reserved4; - unsigned int reserved5; - - float unknown4; - - unsigned int reserved6; // 12B of zeros - unsigned int reserved7; - unsigned int reserved8; - - float unknown5; - - unsigned int reserved9; // 12B of zeros - unsigned int reserved10; - unsigned int reserved11; - - unsigned int object_id; - - float unknown12; // Can be a vector??? - float unknown13; - float unknown14; - - float unknown15; // Can be a vector??? - float unknown16; - float unknown17; - - float unknown18; // Can be a matrix??? - float unknown19; - float unknown20; - float unknown21; - - float transform_x; - float transform_y; - float transform_z; -} T_HOBFILE_MESHDEF0; - -typedef struct PACK hobfile_meshdef1 { - unsigned int facedef_end_offset; - - unsigned int reserved1; // 20B of zeros - unsigned int reserved2; - unsigned int reserved3; - unsigned int reserved4; - unsigned int reserved5; - - unsigned int vertex_count; - unsigned int unknown1; - unsigned int reserved6; - unsigned int faceblock_offset; - unsigned int vertexblocks_offset; - - unsigned int reserved7; // 52B of zeros - unsigned int reserved8; - unsigned int reserved9; - unsigned int reserved10; - unsigned int reserved11; - unsigned int reserved12; - unsigned int reserved13; - unsigned int reserved14; - unsigned int reserved15; - unsigned int reserved16; - unsigned int reserved17; - unsigned int reserved18; - unsigned int reserved19; -} T_HOBFILE_MESHDEF1; - -typedef struct PACK hobfile_faceblock { - unsigned int reserved1; // 8B of zeros - unsigned int reserved2; - - unsigned int facesOffset; - unsigned int faceCounts; -} T_HOBFILE_FACEBLOCK; - -typedef struct PACK hobfile_faces_header { - unsigned int flags; - unsigned char b1; // 74 = transparent / 75 = opaque - unsigned char b2; - unsigned char b3; - unsigned char faceBlockIntSize; // Bytes size divided by 4, count as number of UInt32 type. - unsigned short headerSeparator; - unsigned short materialIndex; - unsigned short vertexIndices[4]; // Relative to facegroup, the last value is equal to 0 when it's triangle shape. -} T_HOBFILE_FACES_HEADER; - -typedef struct PACK hobfile_faces_extra_vertex_color { - T_RSPMODEL_RGBA v1_rgba; - T_RSPMODEL_RGBA v2_rgba; - T_RSPMODEL_RGBA v3_rgba; - T_RSPMODEL_RGBA v4_rgba; // Used with quad type face -} T_HOBFILE_FACES_VERTEX_COLOR; - -typedef struct PACK hobfile_faces_extra_color { - T_RSPMODEL_RGBA rgba; -} T_HOBFILE_FACES_COLOR; - -typedef struct PACK hobfile_faces_extra_vertex_texture { - T_RSPMODEL_TEXCOORD v1_texcoord; // Should be divided (no shifting) by 4096 to get 0...1 range - T_RSPMODEL_TEXCOORD v2_texcoord; - T_RSPMODEL_TEXCOORD v3_texcoord; - T_RSPMODEL_TEXCOORD v4_texcoord; // Used with quad type face -} T_HOBFILE_FACES_VERTEX_TEXTURE; - -typedef struct PACK hobfile_vertex { - short x; - short y; - short z; - short w; -} T_HOBFILE_VERTEX; - -#if defined(_MSC_VER) -#pragma pack(pop) -#endif - -#endif /* RSPMODELLIB_HOB_STRUCT_H_ */ diff --git a/RSPModelLib/src/mesh_builder.h b/RSPModelLib/src/mesh_builder.h new file mode 100644 index 0000000..2a53acc --- /dev/null +++ b/RSPModelLib/src/mesh_builder.h @@ -0,0 +1,21 @@ +/** + * @file mesh_builder.h + * @date 18/01/2023 + * @author JackCarterSmith + * @copyright GPL-v3.0 + * @brief Mesh constructor of HOB objects. + * + */ + +#include "RSPModel_datatypes.h" + +#ifndef MESH_BUILDER_H_ +#define MESH_BUILDER_H_ + +unsigned short RSP_ModelLib_HOBObjectToGL( const T_RSPMODEL_OBJECT* objStruct ); +/* +unsigned short RSP_ModelLib_HOBObjectToGL( const T_RSPMODEL_OBJECT* objStruct, void* glObj ); +unsigned short RSP_ModelLib_HOBObjectToD3D( const T_RSPMODEL_OBJECT* objStruct, void* D3DObj ); +*/ + +#endif /* MESH_BUILDER_H_ */