|
|
|
@ -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 <string.h>
|
|
|
|
|
#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;
|
|
|
|
|