diff --git a/CMakeLists.txt b/CMakeLists.txt index c8f120c..b75ccd9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,10 +42,10 @@ add_executable(rse-model ${RSE_MOD_SRCS} ${RSE_MOD_HRDS}) set_target_properties(rse-model PROPERTIES OUTPUT_NAME ${RSE_MOD_NAME}) if(MSVC) # msvc does not append 'lib' - do it here to have consistent name - set_target_properties(rse-model PROPERTIES PREFIX "lib") + #set_target_properties(rse-model PROPERTIES PREFIX "lib") set_target_properties(rse-model PROPERTIES IMPORT_PREFIX "lib") endif() -target_link_libraries(rse-model m) +target_link_libraries(rse-model) # add GPG signature command #add_custom_command( diff --git a/Jenkinsfile b/Jenkinsfile index fe61954..c5a2d07 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,7 +5,7 @@ pipeline { } environment { CI_OUTPUT_NAME = "RSE_Model" - CI_VERSION = "1.0.0" + CI_VERSION = "1.0.1" CI_BUILD_NUMBER = "$BUILD_NUMBER" } stages { diff --git a/README.md b/README.md index dda8db9..6a1b814 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Due to issue with copyrights, I can't provide samples... You need to extract HOB You can compile on both Windows (MinGW) or native Linux system thanks to CMake. -To compile, just clone and launch cmake: +To compile, just clone (**don't forget git submodules**) and launch cmake: ```shell cmake . diff --git a/src/Model-Extractor.c b/src/Model-Extractor.c index 2c70ea8..e4b8c0f 100644 --- a/src/Model-Extractor.c +++ b/src/Model-Extractor.c @@ -1,10 +1,9 @@ -/* - ================================================================================ - Name : Model-Extractor.c - Author : JackCarterSmith - License : GPL-v3.0 - Description : HOB model parser and export to Waveform OBJ format. - ================================================================================ +/** + * \file Model-Extractor.c + * \date 25/07/2022 + * \author JackCarterSmith + * \copyright GPL-v3.0 + * \brief HOB model parser and export to Waveform OBJ format. */ #include @@ -28,40 +27,36 @@ * Internal functions declarations */ -static unsigned int mainProcess(int args_cnt, char *args_value[]); +static unsigned int mainProcess(int args_cnt, char* args_value[], T_PROG_OPTIONS* opt_ptr); static void createSubDir(char *dirName); -static int checkInputArgs(int arg_nbr, char *args[]); +static unsigned char checkInputArgs(T_PROG_OPTIONS* opt_ptr, int p_arg_nbr, char* p_args[]); static void cleanUpMemory(T_HOB* hobStruct); -//int exportTextures(HMT_FILE *hmt_f, char *filename); -static inline void dispHelp(); - - -/* - * Global variables declaration - */ - -int _options; // Global options settings variable +static void dispHelp(); /* * - MAIN - */ int main(int argc, char *argv[]) { - // Init buffer vars - + T_PROG_OPTIONS _opts; + unsigned char p; + // Hello world! printf("\n*** RogueSquadron Extractor (RSE) - MODEL module - v%s ***\n", VERSION); - // Check if filenames arguments exist + // Check for arguments if (argc < 2) { printf("\n[ERR] No input file/commands specified!\n"); dispHelp(); return ERROR_ARGS_NULL; } - _options = checkInputArgs(argc, argv); // Analyse program arguments - if (_options == -1) return NO_ERROR; - return mainProcess(argc, argv); + // Create options for programs according to user's arguments. + p = checkInputArgs(&_opts, argc, argv); + if ( p == ERROR_GENERIC ) return NO_ERROR; + else if ( p != NO_ERROR ) return p; + + return mainProcess(argc, argv, &_opts); } @@ -69,28 +64,28 @@ int main(int argc, char *argv[]) { * Private functions definition */ -static unsigned int mainProcess(int args_cnt, char *args_value[]) { +static unsigned int mainProcess(int args_cnt, char* args_value[], T_PROG_OPTIONS* p_opts) { unsigned short file_index; T_HOB* hobStruct = NULL; int i; // Manage multiple inputs files - for (file_index=(_options >> 8) & 0xFF; file_index < args_cnt; file_index++) + for ( file_index = p_opts->input_files_cnt; file_index < args_cnt; file_index++) { printf("\n=============================================\n[INFO] - Parsing file: %s ...\n", args_value[file_index]); hobStruct = calloc(1, sizeof(T_HOB)); // Parse data from HOB file and put in T_HOB structure. - if (parseHOBFile(args_value[file_index], hobStruct) != NO_ERROR) { + if (parseHOBFile(args_value[file_index], hobStruct, p_opts) != NO_ERROR) { printf("[ERR] Failed to parse datas from %s\n", args_value[file_index]); free(hobStruct); return ERROR_PROCESS; } if (hobStruct->obj_count > 0) { - if (_options & OUTPUT_DIR) createSubDir(args_value[file_index]); + if (p_opts->output_dir) createSubDir(args_value[file_index]); for ( i = 0; i < hobStruct->obj_count; i++ ) { - if (exportOBJModel(&(hobStruct->objects[i]), args_value[file_index]) != NO_ERROR) + if (exportOBJModel(&(hobStruct->objects[i]), args_value[file_index], p_opts) != NO_ERROR) printf("[ERR] Failed to export %s object in OBJ format!\n", hobStruct->objects[i].name); else printf("[INFO] Successfully exported %s object in OBJ format.\n", hobStruct->objects[i].name); @@ -103,35 +98,47 @@ static unsigned int mainProcess(int args_cnt, char *args_value[]) { return NO_ERROR; } -static int checkInputArgs(int arg_nbr, char *args[]) { - int _o = (OUTPUT_DIR | EXPORT_MTL); // Default options parameters +static unsigned char checkInputArgs(T_PROG_OPTIONS* opt_ptr, int p_arg_nbr, char* p_args[]) { char test[256]; int i; - if (arg_nbr > 1) { - for (i=1; iraw = 0; + opt_ptr->output_dir = 1; + opt_ptr->export_mtl = 1; + + if (p_arg_nbr > 1) { + for ( i = 1; i < p_arg_nbr; i++) { + strcpy(test, p_args[i]); + if (p_args[i][0] != '-') break; + if (strcmp(p_args[i], "-h") == 0) { dispHelp(); - return -1; - } else if (strcmp(args[i], "-v") == 0) { - _o |= VERBOSE_ENABLED; + return ERROR_GENERIC; + } else if (strcmp(p_args[i], "-v") == 0) { + opt_ptr->verbose_mode = 1; printf("[OPTN] Verbose enabled.\n"); - } else if (strcmp(args[i], "-no-subdir") == 0) { - _o &= ~OUTPUT_DIR; + } else if (strcmp(p_args[i], "-vv") == 0) { + opt_ptr->debug_mode = 1; + printf("[OPTN] Debug enabled.\n"); + } else if (strcmp(p_args[i], "-vvv") == 0) { + opt_ptr->god_mode = 1; + printf("[OPTN] God damn it!\n"); + } else if (strcmp(p_args[i], "-no-subdir") == 0) { + opt_ptr->output_dir = 0; printf("[OPTN] Export to current directory.\n"); - } else if (strcmp(args[i], "-mtl") == 0) { - _o &= ~EXPORT_MTL; + } else if (strcmp(p_args[i], "-mtl") == 0) { + opt_ptr->export_mtl = 0; printf("[OPTN] No materials datas.\n"); } else { - printf("[ERR] Unknown option: %s\n", args[i]); + printf("[ERR] Unknown option: %s\n", p_args[i]); } } - _o = (i << 8) | (_o & 0x00FF); + + opt_ptr->input_files_cnt = i; + return NO_ERROR; } - return _o; + return ERROR_ARGS_NULL; } static void createSubDir(char *dirName) { @@ -164,10 +171,10 @@ static void cleanUpMemory(T_HOB* hobStruct) { free(hobStruct); } -static inline void dispHelp() { +static void dispHelp() { printf("\n"); printf("Options:\n -h Print this message\n"); - printf(" -v Activate verbose console output\n"); + printf(" -v -vv Activate verbose console output\n"); printf(" -no-subdir Export models inside current folder\n"); printf(" -no-mtl Disable materials datas export with model\n"); printf("\n"); diff --git a/src/errors_types.h b/src/errors_types.h index e94fe6c..6d101ab 100644 --- a/src/errors_types.h +++ b/src/errors_types.h @@ -5,12 +5,15 @@ * Author: JackCarterSmith */ -#include "error.h" //TODO: use it as base for error ID +//#include "error.h" //TODO: use it as base for error ID #ifndef SRC_ERRORS_TYPES_H_ #define SRC_ERRORS_TYPES_H_ +#ifdef NO_ERROR +#undef NO_ERROR +#endif #define NO_ERROR 0 #define ERROR_GENERIC 1 #define ERROR_MEMORY 2 diff --git a/src/hob_parser.c b/src/hob_parser.c index 0108257..427de3f 100644 --- a/src/hob_parser.c +++ b/src/hob_parser.c @@ -1,8 +1,9 @@ -/* - * hob_parser.c - * - * Created on: 26 juil. 2022 - * Author: JackCarterSmith +/** + * \file hob_parser.c + * \date 26/07/2022 + * \author JackCarterSmith + * \copyright GPL-v3.0 + * \brief Decode HOB file structure. */ #include @@ -14,7 +15,7 @@ #include "hob_parser.h" -unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { +unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct, T_PROG_OPTIONS* p_opts) { unsigned char err = NO_ERROR; long fileSize; FILE* fStream = NULL; @@ -32,7 +33,7 @@ unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { fseek(fStream, 0, SEEK_END); fileSize = ftell(fStream); fseek(fStream, 0, SEEK_SET); - if (_options & VERBOSE_ENABLED) printf("[DBG] > Input file size: %ld bytes\n", fileSize); + if (p_opts->verbose_mode) printf("[DBG] > Input file size: %ld bytes\n", fileSize); memFile = malloc(fileSize + 1); if (memFile != NULL) { @@ -48,67 +49,74 @@ unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { // Populate HOB structure with object descriptor hob_struct->objects = calloc(hob_struct->obj_count, sizeof(T_HOB_OBJECT)); for ( i = 0; i < hob_struct->obj_count; i++ ) { + if (p_opts->debug_mode) printf("\n-=====================-Begin of Object part-======================-\n"); + // Get object name memcpy(hob_struct->objects[i].name, ((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->object_name, 16); - if (_options & VERBOSE_ENABLED) printf("\n"); + if (p_opts->verbose_mode) printf("\n"); printf("[INFO] - Process %s object...\n", hob_struct->objects[i].name); // Get offsets hob_struct->objects[i].face_group_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->facegroup_offset; - if (_options & VERBOSE_ENABLED) printf("[DBG] > Face group offset: 0x%X\n", hob_struct->objects[i].face_group_offset); + if (p_opts->verbose_mode) printf("[DBG] > Face group offset: 0x%X\n", hob_struct->objects[i].face_group_offset); hob_struct->objects[i].object_part_header_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->object_parts_offset; - if (_options & VERBOSE_ENABLED) printf("[DBG] > Face group header/object parts offset: 0x%X\n", hob_struct->objects[i].object_part_header_offset); - hob_struct->objects[i].face_group_header2_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile + if (p_opts->verbose_mode) printf("[DBG] > Face group header/object parts offset: 0x%X\n", hob_struct->objects[i].object_part_header_offset); + hob_struct->objects[i].face_group_header_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->facegroup_header_2_offset; - if (_options & VERBOSE_ENABLED) printf("[DBG] > Face group header2 offset: 0x%X\n", hob_struct->objects[i].face_group_header2_offset); + if (p_opts->verbose_mode) printf("[DBG] > Face group header2 offset: 0x%X\n", hob_struct->objects[i].face_group_header_offset); + + if (p_opts->god_mode) { + printf("[DBG] > Face group unknown1: %d\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknownOffset1); + printf("[DBG] > Face group unknown2: %d\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknownOffset2); + printf("[DBG] > Face group unknown3: %d\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknownOffset3); + printf("[DBG] > Face group unknown4: %.8f\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknown4); + } // Get count and offsets from the facegroup header + hob_struct->objects[i].object_part_count = ((T_HOBFILE_FACEGROUP_HEADER *)(memFile + + hob_struct->objects[i].object_part_header_offset))->object_part_count; + if (p_opts->verbose_mode) printf("[DBG] > Object parts count: %d\n", hob_struct->objects[i].object_part_count); hob_struct->objects[i].face_group_count = ((T_HOBFILE_FACEGROUP_HEADER *)(memFile + hob_struct->objects[i].object_part_header_offset))->facegroup_count; - if (_options & VERBOSE_ENABLED) printf("[DBG] > Face group count: %d\n", hob_struct->objects[i].face_group_count); - hob_struct->objects[i].face_group_count0 = ((T_HOBFILE_FACEGROUP_HEADER *)(memFile - + hob_struct->objects[i].object_part_header_offset))->facegroup_count0; - if (_options & VERBOSE_ENABLED) printf("[DBG] > Face group count0: %d\n", hob_struct->objects[i].face_group_count0); - if (hob_struct->objects[i].face_group_count != hob_struct->objects[i].face_group_count0 && (_options & VERBOSE_ENABLED)) printf("[DBG] > Facegroup count are different!\n"); + if (p_opts->verbose_mode) printf("[DBG] > Face groups count: %d\n", hob_struct->objects[i].face_group_count); + if (hob_struct->objects[i].object_part_count != hob_struct->objects[i].face_group_count && (p_opts->verbose_mode)) printf("[DBG] > Object parts / facegroup count are different!\n"); // Get facegroup datas - offset_index = calloc(hob_struct->objects[i].face_group_count, sizeof(int)); - hob_struct->objects[i].object_parts = calloc(hob_struct->objects[i].face_group_count, sizeof(T_HOB_FACE_GROUP)); - for ( j = 0; j < hob_struct->objects[i].face_group_count; j++ ) { + offset_index = calloc(hob_struct->objects[i].object_part_count, sizeof(int)); + hob_struct->objects[i].object_parts = calloc(hob_struct->objects[i].object_part_count, sizeof(T_HOB_FACE_GROUP)); + for ( j = 0; j < hob_struct->objects[i].object_part_count; j++ ) { + if (p_opts->debug_mode) printf("\n-----------------------Begin of Mesh part-------------------------\n"); + offset_index[j] = ((T_HOBFILE_FACEGROUP_OFFSET *)(memFile + hob_struct->objects[i].object_part_header_offset + sizeof(T_HOBFILE_FACEGROUP_HEADER) + sizeof(T_HOBFILE_FACEGROUP_OFFSET) * j))->facegroup_offset; - if (_options & VERBOSE_ENABLED) printf("\n[DBG] > Face group meshdef0 offset: 0x%X\n", offset_index[j]); + if (p_opts->verbose_mode) printf("\n[DBG] > Face group meshdef0 offset: 0x%X\n", offset_index[j]); // Get meshdef0 datas - if (_options & VERBOSE_ENABLED) printf("\n[DBG] > Next meshdef0 offset: 0x%X",((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->next_meshdef0_offset); - if (_options & VERBOSE_ENABLED) printf("\n[DBG] > Prev meshdef0 offset: 0x%X",((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->prev_meshdef0_offset); - hob_struct->objects[i].object_parts[j].id = ((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->object_id; - if (_options & VERBOSE_ENABLED) printf("\n[DBG] > Facegroup/object ID: %d\n", hob_struct->objects[i].object_parts[j].id); - hob_struct->objects[i].object_parts[j].transform.x = ((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->transform_x; - hob_struct->objects[i].object_parts[j].transform.y = ((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->transform_y; - hob_struct->objects[i].object_parts[j].transform.z = ((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->transform_z; - if (_options & VERBOSE_ENABLED) printf("\n[DBG] > Facegroup/object transform matrix: [%.8f %.8f %.8f]\n", - hob_struct->objects[i].object_parts[j].transform.x, - hob_struct->objects[i].object_parts[j].transform.y, - hob_struct->objects[i].object_parts[j].transform.z - ); + if (p_opts->god_mode) printf("[DBG] > meshdef0 offset1: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->offset1); + if (p_opts->god_mode) printf("[DBG] > meshdef0 offset2: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->offset2); + if (p_opts->verbose_mode) printf("[DBG] > Prev meshdef0 offset: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->prev_meshdef0_offset); + if (p_opts->verbose_mode) printf("[DBG] > Next meshdef0 offset: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->next_meshdef0_offset); + + if (p_opts->god_mode) printf("[DBG] > meshdef0 unknown3: %.8f\n",((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->unknown3); + if (p_opts->god_mode) printf("[DBG] > meshdef0 unknown4: %.8f\n",((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->unknown4); + if (p_opts->god_mode) printf("[DBG] > meshdef0 unknown5: %.8f\n",((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->unknown5); // Get meshdef1 (mesh descriptor) offset hob_struct->objects[i].object_parts[j].meshdef1_offset = ((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->meshdef1_offset_plus_4; - if (_options & VERBOSE_ENABLED) printf("[DBG] > Face group meshdef1 offset: 0x%X\n", hob_struct->objects[i].object_parts[j].meshdef1_offset); + if (p_opts->verbose_mode) printf("\n[DBG] > Face group meshdef1 offset: 0x%X\n", hob_struct->objects[i].object_parts[j].meshdef1_offset); if( ((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->reserved1 != 0 || ((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->reserved2 != 0 ) { - if (_options & VERBOSE_ENABLED) printf("[DBG] > Face group meshdef0: no 0!\n"); + if (p_opts->god_mode) printf("[DBG] > Face group meshdef0: no 0!\n"); } if (hob_struct->objects[i].object_parts[j].meshdef1_offset > 0) { @@ -119,25 +127,27 @@ unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { + hob_struct->objects[i].object_parts[j].meshdef1_offset - 4))->vertex_count; hob_struct->objects[i].object_parts[j].face_block_offset = ((T_HOBFILE_MESHDEF1 *)(memFile + hob_struct->objects[i].object_parts[j].meshdef1_offset - 4))->faceblock_offset; - if (_options & VERBOSE_ENABLED) printf("[DBG] > Faces offset: 0x%X\n", hob_struct->objects[i].object_parts[j].face_block_offset); + if (p_opts->verbose_mode) printf("[DBG] > Faces offset: 0x%X\n", hob_struct->objects[i].object_parts[j].face_block_offset); hob_struct->objects[i].object_parts[j].vertex_block_offset = ((T_HOBFILE_MESHDEF1 *)(memFile + hob_struct->objects[i].object_parts[j].meshdef1_offset - 4))->vertexblocks_offset; - if (_options & VERBOSE_ENABLED) printf("[DBG] > Vertex offset: 0x%X\n\n", hob_struct->objects[i].object_parts[j].vertex_block_offset); + if (p_opts->verbose_mode) printf("[DBG] > Vertex offset: 0x%X\n\n", hob_struct->objects[i].object_parts[j].vertex_block_offset); // Get face datas if( ((T_HOBFILE_FACEBLOCK *)(memFile + hob_struct->objects[i].object_parts[j].face_block_offset))->reserved1 != 0 || ((T_HOBFILE_FACEBLOCK *)(memFile + hob_struct->objects[i].object_parts[j].face_block_offset))->reserved2 != 0 ) { - if (_options & VERBOSE_ENABLED) printf("[DBG] > Face block: uncommon zero header!\n"); + if (p_opts->god_mode) printf("[DBG] > Face block: uncommon zero header!\n"); } if ( ((T_HOBFILE_FACEBLOCK *)(memFile + hob_struct->objects[i].object_parts[j].face_block_offset))->facesOffset != hob_struct->objects[i].object_parts[j].face_block_offset + sizeof(T_HOBFILE_FACEBLOCK)) { - if (_options & VERBOSE_ENABLED) printf("[DBG] > Face block: uncommon face data offset position!\n"); + if (p_opts->god_mode) printf("[DBG] > Face block: uncommon face data offset position!\n"); } hob_struct->objects[i].object_parts[j].face_count = ((T_HOBFILE_FACEBLOCK *)(memFile + hob_struct->objects[i].object_parts[j].face_block_offset))->faceCounts; hob_struct->objects[i].object_parts[j].faces = calloc(hob_struct->objects[i].object_parts[j].face_count, sizeof(T_HOB_FACE)); facesExtraOffset = 0; for ( k = 0; k < hob_struct->objects[i].object_parts[j].face_count; k++ ) { + if (p_opts->debug_mode) printf("\n----------------------Begin of FaceGroup part----------------------\n"); + // Get flags hob_struct->objects[i].object_parts[j].faces[k].flags = ((T_HOBFILE_FACES_HEADER *)(memFile + hob_struct->objects[i].object_parts[j].face_block_offset @@ -172,7 +182,7 @@ unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { + sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * k + facesExtraOffset))->headerSeparator != 0) { - if (_options & VERBOSE_ENABLED) printf("[DBG] > Face header: uncommon separator!\n"); + if (p_opts->god_mode) printf("[DBG] > Face header: uncommon separator!\n"); } // Get materials index @@ -288,8 +298,8 @@ unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { } } - if (_options & VERBOSE_ENABLED) { - printf("[DBG] > Face %d details: 0x%X, %d, %d, %d, %d\n", k, + if (p_opts->debug_mode) { + printf("[DBG] > Face %d details: flags:0x%X b1:%d b2:%d b3%d bsize:%d\n", k, hob_struct->objects[i].object_parts[j].faces[k].flags, hob_struct->objects[i].object_parts[j].faces[k].b1, hob_struct->objects[i].object_parts[j].faces[k].b2, @@ -337,6 +347,8 @@ unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { ); printf("\n"); } + + if (p_opts->debug_mode) printf("\n-----------------------End of FaceGroup part-----------------------\n"); } // Get vertex datas @@ -358,14 +370,32 @@ unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { + hob_struct->objects[i].object_parts[j].vertex_block_offset + sizeof(T_VERTEX) * k))->w; // Always 0??? - if (_options & VERBOSE_ENABLED) printf("[DBG] > Found vertex %d: (%d, %d, %d)\n", k, + if (p_opts->debug_mode) printf("[DBG] > Found vertex %d: (%d, %d, %d)\n", k, hob_struct->objects[i].object_parts[j].vertices[k].x, hob_struct->objects[i].object_parts[j].vertices[k].y, hob_struct->objects[i].object_parts[j].vertices[k].z ); } } + + // Get object part ID, used by animation? bones? + hob_struct->objects[i].object_parts[j].id = ((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->object_id; + if (p_opts->verbose_mode) printf("\n[DBG] > Facegroup/object ID: %d\n", hob_struct->objects[i].object_parts[j].id); + + // Get the transform matrix, used by at-st and at-at (at this time) + hob_struct->objects[i].object_parts[j].transform.x = ((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->transform_x; + hob_struct->objects[i].object_parts[j].transform.y = ((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->transform_y; + hob_struct->objects[i].object_parts[j].transform.z = ((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->transform_z; + if (p_opts->god_mode) printf("\n[DBG] > Facegroup/object transform matrix: [%.8f %.8f %.8f]\n", + hob_struct->objects[i].object_parts[j].transform.x, + hob_struct->objects[i].object_parts[j].transform.y, + hob_struct->objects[i].object_parts[j].transform.z + ); + + if (p_opts->debug_mode) printf("\n-----------------------End of Mesh part---------------------------\n"); } + + if (p_opts->debug_mode) printf("\n-=====================-End of Object part-========================-\n"); } free(offset_index); @@ -380,11 +410,11 @@ unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { } else { fclose(fStream); err = ERROR_MEMORY; - if (_options & VERBOSE_ENABLED) printf("[ERR] Can't allocate enough memory for file processing!\n"); + if (p_opts->verbose_mode) printf("[ERR] Can't allocate enough memory for file processing!\n"); } } else { err = ERROR_IO; - if (_options & VERBOSE_ENABLED) printf("[ERR] Input file %s not found!\n", fileName); + if (p_opts->verbose_mode) printf("[ERR] Input file %s not found!\n", fileName); } } else err = ERROR_ARGS_NULL; diff --git a/src/hob_parser.h b/src/hob_parser.h index 6b918bf..7219839 100644 --- a/src/hob_parser.h +++ b/src/hob_parser.h @@ -1,14 +1,15 @@ -/* - * hob_parser.h - * - * Created on: 26 juil. 2022 - * Author: JackCarterSmith +/** + * \file hob_parser.h + * \date 26/07/2022 + * \author JackCarterSmith + * \copyright GPL-v3.0 + * \brief Decode HOB file structure. */ #ifndef SRC_HOB_PARSER_H_ #define SRC_HOB_PARSER_H_ -unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct); +unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct, T_PROG_OPTIONS* p_opts); #endif /* SRC_HOB_PARSER_H_ */ diff --git a/src/hob_struct.h b/src/hob_struct.h index c3bc733..28b96a8 100644 --- a/src/hob_struct.h +++ b/src/hob_struct.h @@ -16,6 +16,12 @@ * car = 8bits */ +#if defined(_MSC_VER) +#define PACK +#elif defined(__GNUC__) +#define PACK __attribute__((packed)) +#endif + /////////////////////////////////////////////////////////////////////////////// // HOB file structure /////////////////////////////////////////////////////////////////////////////// @@ -80,10 +86,10 @@ typedef struct hob_object { char name[16]; unsigned int face_group_offset; unsigned int object_part_header_offset; - unsigned int face_group_header2_offset; + unsigned int face_group_header_offset; + unsigned int object_part_count; unsigned int face_group_count; - unsigned int face_group_count0; T_HOB_FACE_GROUP* object_parts; } T_HOB_OBJECT; @@ -102,14 +108,19 @@ typedef struct hob { /////////////////////////////////////////////////////////////////////////////// // Declaration of Memory Mapped Structure +// Caution: the place of variable is important for correct mapping! /////////////////////////////////////////////////////////////////////////////// -typedef struct __attribute__((packed)) hobfile_header { +#if defined(_MSC_VER) +#pragma pack(push, 1) +#endif + +typedef struct PACK hobfile_header { unsigned int obj_count; unsigned int vertices_offset; } T_HOBFILE_HEADER; -typedef struct __attribute__((packed)) hobfile_obj_descriptor { +typedef struct PACK hobfile_obj_descriptor { unsigned char object_name[16]; unsigned int facegroup_offset; unsigned int object_parts_offset; @@ -119,9 +130,9 @@ typedef struct __attribute__((packed)) hobfile_obj_descriptor { unsigned int reserved2; unsigned int reserved3; - unsigned int unknown1; - unsigned int unknown2; - unsigned int unknown3; + unsigned int unknownOffset1; + unsigned int unknownOffset2; + unsigned int unknownOffset3; float unknown4; unsigned int reserved4; // 12B of zeros @@ -142,21 +153,21 @@ typedef struct __attribute__((packed)) hobfile_obj_descriptor { float reserved17; } T_HOBFILE_OBJ_DESCRIPTOR; -typedef struct __attribute__((packed)) hobfile_facegroup_header { +typedef struct PACK hobfile_facegroup_header { + unsigned short object_part_count; unsigned short facegroup_count; - unsigned short facegroup_count0; } T_HOBFILE_FACEGROUP_HEADER; -typedef struct __attribute__((packed)) hobfile_facegroup_offset { +typedef struct PACK hobfile_facegroup_offset { unsigned int unknown1; unsigned int facegroup_offset; } T_HOBFILE_FACEGROUP_OFFSET; -typedef struct __attribute__((packed)) hobfile_meshdef0 { - unsigned int next_meshdef0_offset; - unsigned int unknown1; - unsigned int unknown2; +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 @@ -200,7 +211,7 @@ typedef struct __attribute__((packed)) hobfile_meshdef0 { float transform_z; } T_HOBFILE_MESHDEF0; -typedef struct __attribute__((packed)) hobfile_meshdef1 { +typedef struct PACK hobfile_meshdef1 { unsigned int facedef_end_offset; unsigned int reserved1; // 20B of zeros @@ -230,7 +241,7 @@ typedef struct __attribute__((packed)) hobfile_meshdef1 { unsigned int reserved19; } T_HOBFILE_MESHDEF1; -typedef struct __attribute__((packed)) hobfile_faceblock { +typedef struct PACK hobfile_faceblock { unsigned int reserved1; // 8B of zeros unsigned int reserved2; @@ -238,7 +249,7 @@ typedef struct __attribute__((packed)) hobfile_faceblock { unsigned int faceCounts; } T_HOBFILE_FACEBLOCK; -typedef struct __attribute__((packed)) hobfile_faces_header { +typedef struct PACK hobfile_faces_header { unsigned int flags; unsigned char b1; unsigned char b2; @@ -249,29 +260,33 @@ typedef struct __attribute__((packed)) hobfile_faces_header { 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 __attribute__((packed)) hobfile_faces_extra_vertex_color { +typedef struct PACK hobfile_faces_extra_vertex_color { T_RGBA v1_rgba; T_RGBA v2_rgba; T_RGBA v3_rgba; T_RGBA v4_rgba; // Used with quad type face } T_HOBFILE_FACES_VERTEX_COLOR; -typedef struct __attribute__((packed)) hobfile_faces_extra_color { +typedef struct PACK hobfile_faces_extra_color { T_RGBA rgba; } T_HOBFILE_FACES_COLOR; -typedef struct __attribute__((packed)) hobfile_faces_extra_vertex_texture { +typedef struct PACK hobfile_faces_extra_vertex_texture { T_TEXCOORD v1_texcoord; // Should be divided (no shifting) by 4096 to get 0...1 range T_TEXCOORD v2_texcoord; T_TEXCOORD v3_texcoord; T_TEXCOORD v4_texcoord; // Used with quad type face } T_HOBFILE_FACES_VERTEX_TEXTURE; -typedef struct __attribute__((packed)) hobfile_vertex { +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 /* SRC_HOB_STRUCT_H_ */ diff --git a/src/obj_exporter.c b/src/obj_exporter.c index 00052de..bc3500d 100644 --- a/src/obj_exporter.c +++ b/src/obj_exporter.c @@ -1,8 +1,9 @@ -/* - * obj_exporter.c - * - * Created on: 27 juil. 2022 - * Author: JackCarterSmith +/** + * \file obj_exporter.c + * \date 27/07/2022 + * \author JackCarterSmith + * \copyright GPL-v3.0 + * \brief Export datas to Waveform OBJ format. */ #include @@ -17,7 +18,7 @@ static void mtlPathPatch(const char* out_file, const char* obj_name) ; -unsigned char exportOBJModel(T_HOB_OBJECT* hob_objects, const char *out_path) { +unsigned char exportOBJModel(T_HOB_OBJECT* hob_objects, const char *out_path, T_PROG_OPTIONS* p_opts) { char objExport_path[128]; char mtlExport_path[128]; obj* objConstruct = NULL; @@ -30,7 +31,7 @@ unsigned char exportOBJModel(T_HOB_OBJECT* hob_objects, const char *out_path) { if (hob_objects == NULL || out_path == NULL) return ERROR_ARGS_NULL; - if (_options & OUTPUT_DIR) { + if (p_opts->output_dir) { strcpy(objExport_path, out_path); #ifdef _WIN32 strcat(objExport_path, "-out\\"); @@ -105,9 +106,11 @@ unsigned char exportOBJModel(T_HOB_OBJECT* hob_objects, const char *out_path) { indexOffset = obj_num_vert(objConstruct); } - if (_options & EXPORT_MTL) { + if (p_opts->export_mtl) { obj_write(objConstruct, objExport_path, mtlExport_path, 8); - if (_options & OUTPUT_DIR) mtlPathPatch(objExport_path, hob_objects->name); +#if defined(__GNUC__) //TODO: review MSVC file management or include and rewrite obj lib? + if (p_opts->output_dir) mtlPathPatch(objExport_path, hob_objects->name); +#endif } else obj_write(objConstruct, objExport_path, NULL, 8); obj_delete(objConstruct); @@ -150,7 +153,11 @@ static void mtlPathPatch(const char* out_file, const char* obj_name) { // Begin rewrite file obj = fopen(out_file, "w"); fprintf(obj, "mtllib %s", _path); +#if defined(_MSC_VER) + fwrite(memFile, fileSize - pos , 1, obj); +#elif defined(__GNUC__) fwrite(memFile, fileSize - (pos + lines), 1, obj); +#endif free(memFile); } diff --git a/src/obj_exporter.h b/src/obj_exporter.h index d5a86c7..d0f7b30 100644 --- a/src/obj_exporter.h +++ b/src/obj_exporter.h @@ -1,8 +1,9 @@ -/* - * obj_exporter.h - * - * Created on: 27 juil. 2022 - * Author: JackCarterSmith +/** + * \file obj_exporter.h + * \date 27/07/2022 + * \author JackCarterSmith + * \copyright GPL-v3.0 + * \brief Export datas to Waveform OBJ format. */ #ifndef SRC_OBJ_EXPORTER_H_ @@ -15,6 +16,6 @@ typedef struct t_material { unsigned int gl_tex_id; } T_MATERIAL; -unsigned char exportOBJModel(T_HOB_OBJECT* hob_objects, const char *out_path); +unsigned char exportOBJModel(T_HOB_OBJECT* hob_objects, const char *out_path, T_PROG_OPTIONS* p_opts); #endif /* SRC_OBJ_EXPORTER_H_ */ diff --git a/src/options.h b/src/options.h index 392e9a2..80bb82a 100644 --- a/src/options.h +++ b/src/options.h @@ -1,10 +1,32 @@ +/** + * \file options.h + * \date 29/07/2022 + * \author JackCarterSmith + * \copyright GPL-v3.0 + * \brief Shared options structure definition and declaration. + */ + #ifndef OPTIONS_H_ #define OPTIONS_H_ -#define VERBOSE_ENABLED 0x0001 -#define OUTPUT_DIR 0x0002 -#define EXPORT_MTL 0x0004 +/// Options structure +typedef union u_prog_options { + struct { + unsigned char verbose_mode:1; //!< Output simple details about ID and other "light" things. -extern int _options; + unsigned char output_dir:1; //!< Export extracted datas to a sub-directory. + unsigned char export_mtl:1; //!< Export materials datas with object. -#endif + unsigned char reserved0:5; //!< For future use. + + unsigned char debug_mode:1; //!< Output all values of faces, indices and vertices and others "heavy" things. + unsigned char god_mode:1; //!< Dev only. Output experimental values. + + unsigned char reserved1:6; //!< For future use. + + unsigned short input_files_cnt; //!< Internal files counters. + }; + unsigned int raw; //!< Raw options access for bit-masking or memory copy/compare. +} T_PROG_OPTIONS ; + +#endif /* OPTIONS_H_ */