/** * @file hob_parser.c * @date 18/08/2022 * @author JackCarterSmith * @copyright GPL-v3.0 * @brief Process HOB file structure and extract its datas. * */ #include #include #include #include "RSPModel_errordefs.h" #include "RSPModel_datatypes.h" #include "hob_struct.h" #include "hob_parser.h" //////////////////////////////////////////////////////////////////////////////// // Private functions declarations //////////////////////////////////////////////////////////////////////////////// static unsigned int ExtractObjects(T_RSPMODEL_HOB*, const MEMFILE, const RSPMODEL_PARAMETERS*); static unsigned int ExtractObjParts(T_RSPMODEL_OBJECT*, const MEMFILE, const RSPMODEL_PARAMETERS*); static unsigned int ExtractObjParts_faces(T_RSPMODEL_OBJ_PARTS*, const MEMFILE, const RSPMODEL_PARAMETERS*); static inline unsigned int ExtractObjpart_Face_Colors(T_RSPMODEL_FACE*, const char*); static inline unsigned int ExtractObjpart_Face_UVMaps(T_RSPMODEL_FACE*, const char*); //////////////////////////////////////////////////////////////////////////////// // Public functions definition //////////////////////////////////////////////////////////////////////////////// unsigned char RSP_ModelLib_ParseHOBMemFile(const MEMFILE pMemFile, T_RSPMODEL_HOB* hobStruct, const RSPMODEL_PARAMETERS* pParams) { unsigned char err = RSPLIB_SUCCESS; if (hobStruct != NULL && pMemFile != NULL) { // Do the magic! err = ExtractObjects(hobStruct, pMemFile, pParams); } else err = RSPLIB_ERROR_ARGS_NULL; return err; } unsigned char RSP_ModelLib_ParseHOBFile(const char* fileName, T_RSPMODEL_HOB* hobStruct, const RSPMODEL_PARAMETERS* pParams) { unsigned char err = RSPLIB_SUCCESS; long fileSize; FILE* fStream = NULL; MEMFILE memFile = NULL; if (hobStruct != NULL && fileName != NULL) { // Open file fStream = fopen(fileName, "rb"); if (fStream != NULL) { // Determine file size in bytes fseek(fStream, 0, SEEK_END); fileSize = ftell(fStream); fseek(fStream, 0, SEEK_SET); if (pParams->verbose_mode) printf("[DBG] > Input file size: %ld bytes\n", fileSize); memFile = malloc(fileSize + 1); if (memFile != NULL) { // Copy file in RAM fread(memFile, fileSize, 1, fStream); fclose(fStream); // Do the magic! err = ExtractObjects(hobStruct, memFile, pParams); free(memFile); } else { fclose(fStream); err = RSPLIB_ERROR_MEMORY; if (pParams->verbose_mode) printf("[ERR] Can't allocate enough memory for file processing!\n"); } } else { err = RSPLIB_ERROR_IO; if (pParams->verbose_mode) printf("[ERR] Input file %s not found!\n", fileName); } } else err = RSPLIB_ERROR_ARGS_NULL; return err; } //////////////////////////////////////////////////////////////////////////////// // Private functions definition //////////////////////////////////////////////////////////////////////////////// /** * @brief Count objects and extract datas from them. * * @param[in|out] pHobStruct Take root hob structure to get the T_RSPMODEL_OBJECT buffer and header datas. * @param[in] pMemfile Pointer to an in-memory file location. * @param[in] verbose * * @return Error code, RSPLIB_SUCCESS when no error. */ static unsigned int ExtractObjects(T_RSPMODEL_HOB* pHobStruct, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) { unsigned int i; if (pHobStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL; // Retrieve object count from the header pHobStruct->obj_count = ((T_HOBFILE_HEADER *)pMemfile)->obj_count; printf("[INFO] - Object(s) quantity: %d\n", pHobStruct->obj_count); if (pHobStruct->obj_count <= 0) { printf("[INFO] Can't process empty file!\n"); return RSPLIB_ERROR_GENERIC; } // Populate HOB structure with object descriptor pHobStruct->objects = calloc(pHobStruct->obj_count, sizeof(T_RSPMODEL_OBJECT)); 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"); // 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); if (pParams->verbose_mode) printf("\n"); printf("[INFO] - Process %s object...\n", pHobStruct->objects[i].name); // 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); 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); } // 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); if (pHobStruct->objects[i].object_part_count != pHobStruct->objects[i].face_group_count && (pParams->verbose_mode)) printf("[DBG] > Object parts / facegroup count are different!\n"); // Get facegroup datas ExtractObjParts(&pHobStruct->objects[i], pMemfile, pParams); } return RSPLIB_SUCCESS; } /** * @brief Count object's sub-part and extract datas from them. * * @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] verbose * * @return Error code, RSPLIB_SUCCESS when no error. */ static unsigned int ExtractObjParts(T_RSPMODEL_OBJECT* pObject, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) { unsigned int i, subpart_offset = 0; if (pObject == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL; pObject->object_parts = calloc(pObject->object_part_count, sizeof(T_RSPMODEL_OBJ_PARTS)); if (pObject->object_parts == NULL) return RSPLIB_ERROR_MEMORY; 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; 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"); } if (pParams->debug_mode) printf("\n-=====================-End of Object part-========================-\n"); return RSPLIB_SUCCESS; } /** * @brief Extract datas from faces from object sub-part. * * @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] verbose * * @return Error code, RSPLIB_SUCCESS when no error. */ static unsigned int ExtractObjParts_faces(T_RSPMODEL_OBJ_PARTS* pObjPart, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) { unsigned int i, facesExtraOffset = 0; 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"); } 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 FaceGroup part----------------------\n"); // 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 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].material_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] - Material offset: 0x%X\n", pObjPart->faces[i].material_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 FaceGroup part-----------------------\n"); } // Get vertex datas pObjPart->vertices = calloc(pObjPart->vertex_count, sizeof(T_VERTEX)); if (pObjPart->vertices == NULL) return RSPLIB_ERROR_MEMORY; for ( i = 0; i < pObjPart->vertex_count; i++ ) { pObjPart->vertices[i].x = ((T_HOBFILE_VERTEX *)(pMemfile + pObjPart->vertex_block_offset + sizeof(T_VERTEX) * i))->x; pObjPart->vertices[i].y = ((T_HOBFILE_VERTEX *)(pMemfile + pObjPart->vertex_block_offset + sizeof(T_VERTEX) * i))->y; pObjPart->vertices[i].z = ((T_HOBFILE_VERTEX *)(pMemfile + pObjPart->vertex_block_offset + sizeof(T_VERTEX) * i))->z; pObjPart->vertices[i].w = ((T_HOBFILE_VERTEX *)(pMemfile + pObjPart->vertex_block_offset + sizeof(T_VERTEX) * i))->w; // Always 0??? 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 Extract colors from HOB's face to T_RSPMODEL_FACE instance. * * @param pFace[out] Pointer to an empty instance of T_RSPMODEL_FACE. * @param pFaceMemFileOffset[in] Pointer to the in-memory location of face HOB datas. * @warning Access to an unallocated memory location using this function result in an ACCESS_VIOLATION. * * @return The size of processed data. Used to count new offset between each face in object sub-part. */ static inline unsigned int ExtractObjpart_Face_Colors(T_RSPMODEL_FACE* pFace, const char* pFaceMemFileOffset) { unsigned int dynOffset = 0; if (pFace->flags_bits.fSeparateColorVertex) { pFace->vertex_colors[0] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(pFaceMemFileOffset))->v1_rgba; pFace->vertex_colors[1] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(pFaceMemFileOffset))->v2_rgba; pFace->vertex_colors[2] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(pFaceMemFileOffset))->v3_rgba; if (pFace->flags_bits.fIsQuad) { pFace->vertex_colors[3] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(pFaceMemFileOffset))->v4_rgba; dynOffset += sizeof(T_HOBFILE_FACES_VERTEX_COLOR); } else { dynOffset += sizeof(T_HOBFILE_FACES_VERTEX_COLOR) - sizeof(T_RGBA); } } else { pFace->vertex_colors[0] = ((T_HOBFILE_FACES_COLOR *)(pFaceMemFileOffset))->rgba; pFace->vertex_colors[1] = ((T_HOBFILE_FACES_COLOR *)(pFaceMemFileOffset))->rgba; pFace->vertex_colors[2] = ((T_HOBFILE_FACES_COLOR *)(pFaceMemFileOffset))->rgba; pFace->vertex_colors[3] = ((T_HOBFILE_FACES_COLOR *)(pFaceMemFileOffset))->rgba; dynOffset += sizeof(T_HOBFILE_FACES_COLOR); } return dynOffset; } /** * @brief Extract UV maps from HOB's face to T_RSPMODEL_FACE instance. * * @param pFace[out] Pointer to an empty instance of T_RSPMODEL_FACE. * @param pFaceMemFileOffset[in] Pointer to the in-memory location of face HOB datas. * @warning Access to an unallocated memory location using this function result in an ACCESS_VIOLATION. * * @return The size of processed data. Used to count new offset between each face in object sub-part. */ static inline unsigned int ExtractObjpart_Face_UVMaps(T_RSPMODEL_FACE* pFace, const char* pFaceMemFileOffset) { unsigned int dynOffset = 0; pFace->tex_coords[0] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(pFaceMemFileOffset))->v1_texcoord; pFace->tex_coords[1] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(pFaceMemFileOffset))->v2_texcoord; pFace->tex_coords[2] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(pFaceMemFileOffset))->v3_texcoord; if (pFace->flags_bits.fIsQuad) { pFace->tex_coords[3] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(pFaceMemFileOffset))->v4_texcoord; dynOffset += sizeof(T_HOBFILE_FACES_VERTEX_TEXTURE); } else { dynOffset += sizeof(T_HOBFILE_FACES_VERTEX_TEXTURE) - sizeof(T_TEXCOORD); } return dynOffset; }