From 93b0bcb335016b1319cf9cd99cde730f9a736888 Mon Sep 17 00:00:00 2001 From: JackCarterSmith Date: Tue, 26 Jul 2022 23:48:56 +0200 Subject: [PATCH 1/7] Updated documentation and Jenkins management --- Jenkinsfile | 142 ++++++++++++++++++++++++++++------------------------ README.md | 55 ++++++++++++++++++-- 2 files changed, 128 insertions(+), 69 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index eb4bd54..5f8de41 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,67 +1,77 @@ -pipeline { - agent any - options { - skipDefaultCheckout(true) - } - environment { - CI_OUTPUT_NAME = "RSE_Model" - CI_BUILD_NUMBER = "$BUILD_NUMBER" - } - stages { - stage('Prepare') { - steps { - cleanWs() - } - } - stage('Build') { - steps { - parallel( - linux: { - dir("linux") { - checkout([$class: 'GitSCM', branches: [[name: '**']], browser: [$class: 'GiteaBrowser', repoUrl: 'https://git.jcsmith.fr/jackcartersmith/RSE-Model.git'], extensions: [], userRemoteConfigs: [[credentialsId: 'jenkins-ssh', url: 'ssh://git@git.jcsmith.fr:2322/JCS-Prod/RSE-Model.git']]]) - cmakeBuild buildDir: 'build', installation: 'latest', steps: [[args: 'all']] - } - }, - windows: { - dir("windows") { - checkout([$class: 'GitSCM', branches: [[name: '**']], browser: [$class: 'GiteaBrowser', repoUrl: 'https://git.jcsmith.fr/jackcartersmith/RSE-Model.git'], extensions: [], userRemoteConfigs: [[credentialsId: 'jenkins-ssh', url: 'ssh://git@git.jcsmith.fr:2322/JCS-Prod/RSE-Model.git']]]) - cmakeBuild buildDir: 'build', cmakeArgs: '-DGNU_HOST=x86_64-w64-mingw32 -DCMAKE_TOOLCHAIN_FILE=../mingw_cross_toolchain.cmake -D"ZLIB_INCLUDE_DIR=/mnt/cc-libs/mingw64/zlib/1.2.11/include" -D"ZLIB_LIBRARY=/mnt/cc-libs/mingw64/zlib/1.2.11/lib/libzlib.dll.a" -D"PNG_PNG_INCLUDE_DIR=/mnt/cc-libs/mingw64/libpng/1.6.37/include" -D"PNG_LIBRARY=/mnt/cc-libs/mingw64/libpng/1.6.37/lib/libpng.dll.a"', installation: 'latest', steps: [[args: 'all']] - } - } - ) - } - } - stage('Deploy') { - steps { - dir("zip_linux") { - sh 'cp ../linux/build/${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}* .' - } - dir("zip_win") { - sh 'cp ../windows/build/${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}* /mnt/cc-libs/mingw64/zlib/1.2.11/bin/libzlib.dll /mnt/cc-libs/mingw64/libpng/1.6.37/bin/libpng16.dll .' - } - zip archive: false, dir: 'zip_linux', exclude: '', glob: '', zipFile: 'x64.zip' - sh 'mv x64.zip ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_x64.zip' - zip archive: false, dir: 'zip_win', exclude: '', glob: '', zipFile: 'mingw64.zip' - sh 'mv mingw64.zip ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_mingw64.zip' - } - } - stage('Sign') { - steps { - sh 'ls -l' - sh 'gpg --batch --detach-sign -o ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_x64.zip.gpg ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_x64.zip' - sh 'gpg --batch --detach-sign -o ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_mingw64.zip.gpg ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_mingw64.zip' - archiveArtifacts(artifacts: '*.zip,*.gpg') - } - } - } - /* - post { - always { - cleanWs(cleanWhenNotBuilt: false, - deleteDirs: true, - disableDeferredWipeout: true, - notFailBuild: true) - } - } - */ +pipeline { + agent any + options { + skipDefaultCheckout(true) + } + environment { + CI_OUTPUT_NAME = "RSE_Texture" + CI_BUILD_NUMBER = "$BUILD_NUMBER" + } + stages { + stage('Prepare') { + steps { + cleanWs() + rtConanClient(id: "conan", userHome: "/home/jackcartersmith") + } + } + stage('Build') { + steps { + parallel( + linux: { + dir("linux") { + checkout([$class: 'GitSCM', branches: [[name: '**']], browser: [$class: 'GiteaBrowser', repoUrl: 'https://git.jcsmith.fr/JCS-Prod/RSE-Texture'], extensions: [], userRemoteConfigs: [[credentialsId: 'jenkins-ssh', url: 'ssh://git@git.jcsmith.fr:2322/JCS-Prod/RSE-Texture.git']]]) + dir("build") { + rtConanRun(clientId: "conan", command: "install .. --build missing") + } + cmakeBuild buildDir: 'build', installation: 'latest', steps: [[args: 'all']] + } + }, + windows: { + dir("windows") { + checkout([$class: 'GitSCM', branches: [[name: '**']], browser: [$class: 'GiteaBrowser', repoUrl: 'https://git.jcsmith.fr/JCS-Prod/RSE-Texture'], extensions: [], userRemoteConfigs: [[credentialsId: 'jenkins-ssh', url: 'ssh://git@git.jcsmith.fr:2322/JCS-Prod/RSE-Texture.git']]]) + dir("build") { + rtConanRun(clientId: "conan", command: "install .. --profile windows --build missing") + } + cmakeBuild buildDir: 'build', cmakeArgs: '-DGNU_HOST=x86_64-w64-mingw32 -DCMAKE_TOOLCHAIN_FILE=../mingw_cross_toolchain.cmake', installation: 'latest', steps: [[args: 'all']] + } + } + ) + } + } + stage('Deploy') { + steps { + dir("zip_linux") { + sh 'cp ../linux/build/${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}* .' + } + dir("zip_win") { + sh 'cp ../windows/build/${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}* ../windows/build/*.dll .' + } + zip archive: false, dir: 'zip_linux', exclude: '', glob: '', zipFile: 'x64.zip' + sh 'mv x64.zip ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_x64.zip' + zip archive: false, dir: 'zip_win', exclude: '', glob: '', zipFile: 'mingw64.zip' + sh 'mv mingw64.zip ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_mingw64.zip' + archiveArtifacts(artifacts: '*.zip') + fingerprint(targets: '*.zip') + } + } + stage('Sign') { + steps { + sh 'ls -l' + sh 'gpg --batch --detach-sign -o ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_x64.zip.gpg ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_x64.zip' + sh 'gpg --batch --detach-sign -o ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_mingw64.zip.gpg ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_mingw64.zip' + archiveArtifacts(artifacts: '*.gpg') + fingerprint(targets: '*.gpg') + } + } + } + /* + post { + always { + cleanWs(cleanWhenNotBuilt: false, + deleteDirs: true, + disableDeferredWipeout: true, + notFailBuild: true) + } + } + */ } \ No newline at end of file diff --git a/README.md b/README.md index e7cdc3a..fb55f45 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,57 @@ The collection consist of few independants modules, each of them deals with spec All modules are independants. This is the **'MODEL'** module. -:exclamation: **Master branch is ugly for now and should not be used, please take only released versions.** :exclamation: - ## MODEL MODULE -It's extract texture datas from Rogue Squadron 3D (PC) game models files (HOB). \ No newline at end of file +It's extract texture datas from Rogue Squadron 3D (PC) game models files (HOB). + +This module can do: +- Extract objects inside HOB files to Wavefront OBJ format, +- Extract automatically inside subfolder (usefull when you have multiples objects to extract), +- Multiple inputs files. + +## TODO + +- Add textures to models. +- Discover all unknow fields, animation, bones mesh, etc. + +### Using + +`RSE-Model_"version" [options] ` or you can simply drag&drop HOB files on it. + +A futur main program can extract all HOB files directly from DAT file. +Due to issue with copyrights, I can't provide samples... You need to extract HOB files yourself. + + + +### Options + +- -h Print this message +- -v Activate verbose output +- -no-subdir Extract textures directly inside current folder + +### Dependencies + +- obj-lib: as obj file exporter. (https://github.com/rlk/obj) + +### Compiling + +You can compile on both Windows (MinGW) or native Linux system thanks to CMake. + +To compile, just clone and launch cmake: + +```shell +cmake . +make +make install +``` + +We can also use cross-compilation (after installing `mingw64` and `cmake` packages on your distrib): + +```shell +mkdir build && cd build +cmake -DGNU_HOST=x86_64-w64-mingw32 \ + -DCMAKE_TOOLCHAIN_FILE=../mingw_cross_toolchain.cmake \ + .. +cmake --build . +``` \ No newline at end of file From b3827b8820653f070d1736efaa9fb37a6fa88e7a Mon Sep 17 00:00:00 2001 From: JackCarterSmith Date: Tue, 26 Jul 2022 20:57:50 +0200 Subject: [PATCH 2/7] Program structure --- src/Model-Extractor.c | 97 ++++++++++++++++++++++++++++-------- src/Model-Extractor.h | 22 -------- src/errors_types.h | 25 ++++++++++ src/hob_parser.c | 52 +++++++++++++++++++ src/hob_parser.h | 14 ++++++ src/hob_struct.h | 113 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 280 insertions(+), 43 deletions(-) delete mode 100644 src/Model-Extractor.h create mode 100644 src/errors_types.h create mode 100644 src/hob_parser.c create mode 100644 src/hob_parser.h create mode 100644 src/hob_struct.h diff --git a/src/Model-Extractor.c b/src/Model-Extractor.c index 461d125..011fb51 100644 --- a/src/Model-Extractor.c +++ b/src/Model-Extractor.c @@ -1,47 +1,102 @@ /* ================================================================================ - Name : Map-Extractor.c + Name : Model-Extractor.c Author : JackCarterSmith License : GPL-v3.0 - Description : DAT textures extractor to PNG format with enhanced function in C + Description : HOB model parser and export to Waveform OBJ format. ================================================================================ */ -#include "Model-Extractor.h" +#include +#include +#include +#if defined(_WIN32) + #include +#else + #include + #include +#endif +#include "errors_types.h" +#include "config.h" +#include "options.h" +#include "hob_struct.h" +#include "hob_parser.h" #include "rlk/obj.h" +/* + * Internal functions declarations + */ + +unsigned int mainProcess(int args_cnt, char *args_value[]); +void createSubDir(char *dirName); +int checkInputArgs(int arg_nbr, char *args[]); +//int exportTextures(HMT_FILE *hmt_f, char *filename); +void dispHelp(); + + +/* + * Global variables declaration + */ + int _options; // Global options settings variable + +/* + * - MAIN - + */ int main(int argc, char *argv[]) { // Init buffer vars - int file_index; - printf("\n*** RogueSquadron Extractor (RSE) - MAP module - v%s ***\n", VERSION); + + printf("\n*** RogueSquadron Extractor (RSE) - MODEL module - v%s ***\n", VERSION); // Check if filenames arguments exist if (argc < 2) { printf("\n[ERR] No input file/commands specified!\n"); dispHelp(); - return EXIT_FAILURE; //TODO: implement own error codes system + return ERROR_ARGS_NULL; } - _options = checkArgs(argv, argc); // Analyse program arguments - if (_options == -1) return EXIT_SUCCESS; + _options = checkInputArgs(argc, argv); // Analyse program arguments + if (_options == -1) return NO_ERROR; - // Do the work - for (file_index=(_options >> 8) & 0xFF; file_index> 8) & 0xFF; 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) { + printf("[ERR] Failed to parse datas from %s\n", args_value[file_index]); + free(hobStruct); + return ERROR_PROCESS; + } + } + + free(hobStruct); + + + /* + if (exportTextures(hmt_fdatas, argv[file_index]) == EXIT_FAILURE) return EXIT_FAILURE; + purgeHMTFromMemory(hmt_fdatas); // Clean up memory (because I'm a good boy) + */ + + return NO_ERROR; +} + +int checkInputArgs(int arg_nbr, char *args[]) { int _o = 0x0002; // Default options parameters char test[256]; int i; @@ -86,6 +141,6 @@ void dispHelp() { printf("\n"); printf("Options:\n -h Print this message\n -v Activate verbose console output\n -no-subdir Extract textures inside current folder\n"); printf("\n"); - printf("Usage: RSE-Texture_%s [options] \n", VERSION); + printf("Usage: RSE-Model_%s [options] \n", VERSION); printf("\n"); } diff --git a/src/Model-Extractor.h b/src/Model-Extractor.h deleted file mode 100644 index bde7db8..0000000 --- a/src/Model-Extractor.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef MAP_EXTRACTOR_H_ -#define MAP_EXTRACTOR_H_ - -#include -#include -#include -#if defined(_WIN32) - #include -#else - #include - #include -#endif -#include "config.h" -#include "options.h" - - -void createSubDir(char *dirName); -int checkArgs(char *args[], int arg_nbr); -//int exportTextures(HMT_FILE *hmt_f, char *filename); -void dispHelp(); - -#endif diff --git a/src/errors_types.h b/src/errors_types.h new file mode 100644 index 0000000..e94fe6c --- /dev/null +++ b/src/errors_types.h @@ -0,0 +1,25 @@ +/* + * errors_types.h + * + * Created on: 26 juil. 2022 + * Author: JackCarterSmith + */ + +#include "error.h" //TODO: use it as base for error ID + + +#ifndef SRC_ERRORS_TYPES_H_ +#define SRC_ERRORS_TYPES_H_ + +#define NO_ERROR 0 +#define ERROR_GENERIC 1 +#define ERROR_MEMORY 2 +#define ERROR_IO 3 +#define ERROR_PROCESS 4 + +#define ERROR_ARGS_NULL 10 +#define ERROR_ARGS_RANGE 11 + +#define ERROR_REALITY_BROKED -1 + +#endif /* SRC_ERRORS_TYPES_H_ */ diff --git a/src/hob_parser.c b/src/hob_parser.c new file mode 100644 index 0000000..9e34709 --- /dev/null +++ b/src/hob_parser.c @@ -0,0 +1,52 @@ +/* + * hob_parser.c + * + * Created on: 26 juil. 2022 + * Author: JackCarterSmith + */ + +#include +#include +#include "errors_types.h" +#include "options.h" +#include "hob_struct.h" +#include "hob_parser.h" + + +unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { + unsigned char err = NO_ERROR; + long fileSize; + FILE* fStream = NULL; + char* memFile = NULL; + + if (hob_struct != 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 (_options & VERBOSE_ENABLED) printf("\n[DBG] Input file size: %ld byte(s)\n", fileSize); + + memFile = malloc(fileSize + 1); + if (memFile != NULL) { + // Copy file in RAM + fread(memFile, fileSize, 1, fStream); + fclose(fStream); + hob_struct->obj_count = ((T_HOBFILE_HEADER *)memFile)->obj_count; + printf("[INFO] - Object(s) number: %d ...\n", hob_struct->obj_count); + } else { + fclose(fStream); + err = ERROR_MEMORY; + if (_options & VERBOSE_ENABLED) printf("\n[ERR] Can't allocate enough memory for file processing!\n"); + } + } else { + err = ERROR_IO; + if (_options & VERBOSE_ENABLED) printf("\n[ERR] Input file %s not found!\n", fileName); + } + } else err = ERROR_ARGS_NULL; + + return err; +} diff --git a/src/hob_parser.h b/src/hob_parser.h new file mode 100644 index 0000000..6b918bf --- /dev/null +++ b/src/hob_parser.h @@ -0,0 +1,14 @@ +/* + * hob_parser.h + * + * Created on: 26 juil. 2022 + * Author: JackCarterSmith + */ + + +#ifndef SRC_HOB_PARSER_H_ +#define SRC_HOB_PARSER_H_ + +unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct); + +#endif /* SRC_HOB_PARSER_H_ */ diff --git a/src/hob_struct.h b/src/hob_struct.h new file mode 100644 index 0000000..b72d3d3 --- /dev/null +++ b/src/hob_struct.h @@ -0,0 +1,113 @@ +/* + * hob_struct.h + * + * Created on: 26 juil. 2022 + * Author: JackCarterSmith + */ + +#ifndef SRC_HOB_STRUCT_H_ +#define SRC_HOB_STRUCT_H_ + + +/////////////////////////////////////////////////////////////////////////////// +// HOB file structure +/////////////////////////////////////////////////////////////////////////////// + +typedef unsigned int T_RGBA; + +typedef struct tex_coord { unsigned short u,v; } T_TEXCOORD; + +typedef struct hob_face { + unsigned int flags; + unsigned char b1; + unsigned char b2; + unsigned char b3; + unsigned char bsize; + unsigned char ftype; // 3-Tri / 4-Quad + unsigned __int64 material_index; //TODO: verify for 64bits width and adapt MinGW dependancy to __int64 + unsigned __int64 indices[4]; //TODO: verify for 64bits width and adapt MinGW dependancy to __int64 + T_RGBA vertex_colors[4]; //TODO: convert in R:8_G:8_B:8_A:8 format? Caution with BE/LE conversion + T_TEXCOORD tex_coords[4]; +} T_HOB_FACE; + +typedef struct hob_face_group { + unsigned int meshdef1_offset; + + unsigned int face_block_end_offset; + unsigned int face_block_offset; + unsigned int vertex_block_offset; + + unsigned int face_count; + T_HOB_FACE* faces; + + unsigned int vertex_count; + unsigned short* vertices; +} T_HOB_FACE_GROUP; + +typedef struct hob_object { + unsigned char name[16]; + unsigned int face_group_offset; + unsigned int face_group_header_offset; + unsigned int face_group_header2_offset; + + unsigned int face_group_count; + unsigned int face_group_count0; + + T_HOB_FACE_GROUP* face_groups; +} T_HOB_OBJECT; + +/** + * \brief Model-Extractor HOB structure of an HOB file content. + * \details Used with malloc to create a clean method of bufferized + * model datas before saving it. + * \todo Export format to use it directly in other program. + */ +typedef struct hob { + unsigned int obj_count; + T_HOB_OBJECT* objects; +} T_HOB; + + +/////////////////////////////////////////////////////////////////////////////// +// Declaration of Memory Mapped Structure +/////////////////////////////////////////////////////////////////////////////// + +typedef struct __attribute__((packed)) hobfile_header { + unsigned int obj_count; + unsigned int vertices_offset; +} T_HOBFILE_HEADER; + +typedef struct __attribute__((packed)) hobfile_obj_descriptor { + unsigned char object_name[16]; + unsigned int facegroup_header_offset; + unsigned int object_parts_offset; + unsigned int facegroup_header_2_offset; + + unsigned int reserved1; // 12B of zeros + unsigned int reserved2; + unsigned int reserved3; + + unsigned int unknow1; + unsigned int unknow2; + unsigned int unknow3; + float unknow4; + + unsigned int reserved4; // 12B of zeros + unsigned int reserved5; + unsigned int reserved6; + + float reserved7; + float reserved8; + float reserved9; + float reserved10; + float reserved11; + unsigned int end_mask; // Always equal to 0xFFFFFFFF + float reserved12; + float reserved13; + float reserved14; + float reserved15; + float reserved16; + float reserved17; +} T_HOBFILE_OBJ_DESCRIPTOR; + +#endif /* SRC_HOB_STRUCT_H_ */ From f983930e15265eaa97fb11617f3b32ee5cbd334f Mon Sep 17 00:00:00 2001 From: JackCarterSmith Date: Tue, 26 Jul 2022 22:35:24 +0200 Subject: [PATCH 3/7] Facegroup parser --- src/Model-Extractor.c | 19 ++++++++- src/hob_parser.c | 69 +++++++++++++++++++++++++++++++-- src/hob_struct.h | 89 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 171 insertions(+), 6 deletions(-) diff --git a/src/Model-Extractor.c b/src/Model-Extractor.c index 011fb51..a3e12c5 100644 --- a/src/Model-Extractor.c +++ b/src/Model-Extractor.c @@ -31,6 +31,7 @@ unsigned int mainProcess(int args_cnt, char *args_value[]); void createSubDir(char *dirName); int checkInputArgs(int arg_nbr, char *args[]); +void cleanUpMemory(T_HOB* hobStruct); //int exportTextures(HMT_FILE *hmt_f, char *filename); void dispHelp(); @@ -85,7 +86,7 @@ unsigned int mainProcess(int args_cnt, char *args_value[]) { } } - free(hobStruct); + cleanUpMemory(hobStruct); /* @@ -137,6 +138,22 @@ void createSubDir(char *dirName) { #endif } +void cleanUpMemory(T_HOB* hobStruct) { + int i,j,k; + + for ( i=0; iobj_count; i++ ) { + for ( j=0; jobjects[i].face_group_count; j++ ) { + + + free(&(hobStruct->objects[i].face_groups[j])); + } + + free(&(hobStruct->objects[i])); + } + + free(hobStruct); +} + void dispHelp() { printf("\n"); printf("Options:\n -h Print this message\n -v Activate verbose console output\n -no-subdir Extract textures inside current folder\n"); diff --git a/src/hob_parser.c b/src/hob_parser.c index 9e34709..6dbe6f8 100644 --- a/src/hob_parser.c +++ b/src/hob_parser.c @@ -7,6 +7,7 @@ #include #include +#include #include "errors_types.h" #include "options.h" #include "hob_struct.h" @@ -18,6 +19,8 @@ unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { long fileSize; FILE* fStream = NULL; char* memFile = NULL; + int i,j; + int* offset_index = NULL; if (hob_struct != NULL && fileName != NULL) { // Open file @@ -28,23 +31,81 @@ 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("\n[DBG] Input file size: %ld byte(s)\n", fileSize); + if (_options & VERBOSE_ENABLED) 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); + + // Retrieve object count from the header hob_struct->obj_count = ((T_HOBFILE_HEADER *)memFile)->obj_count; - printf("[INFO] - Object(s) number: %d ...\n", hob_struct->obj_count); + printf("[INFO] - Object(s) quantity: %d\n", hob_struct->obj_count); + + if (hob_struct->obj_count > 0) { + // 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++ ) { + // 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); + 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); + hob_struct->objects[i].face_group_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].face_group_header_offset); + hob_struct->objects[i].face_group_header2_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); + + // Get count and offsets from the facegroup header + hob_struct->objects[i].face_group_count = ((T_HOBFILE_FACEGROUP_HEADER *)(memFile + + hob_struct->objects[i].face_group_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].face_group_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"); + + // Get facegroup datas + offset_index = calloc(hob_struct->objects[i].face_group_count, sizeof(int)); + hob_struct->objects[i].face_groups = 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[j] = ((T_HOBFILE_FACEGROUP_OFFSET *)(memFile + hob_struct->objects[i].face_group_header_offset + + sizeof(T_HOBFILE_FACEGROUP_HEADER) + + sizeof(T_HOBFILE_FACEGROUP_OFFSET) * j))->facegroup_offset; + if (_options & VERBOSE_ENABLED) printf("[DBG] > Face group meshdef0 offset: 0x%X\n", offset_index[j]); + + // TODO: READ FACEGROUP MESHDEF!!! + } + } + + free(offset_index); + + } else { + err = ERROR_GENERIC; + printf("[INFO] Can't process empty file!\n"); + } + + free(memFile); + } else { fclose(fStream); err = ERROR_MEMORY; - if (_options & VERBOSE_ENABLED) printf("\n[ERR] Can't allocate enough memory for file processing!\n"); + if (_options & VERBOSE_ENABLED) printf("[ERR] Can't allocate enough memory for file processing!\n"); } } else { err = ERROR_IO; - if (_options & VERBOSE_ENABLED) printf("\n[ERR] Input file %s not found!\n", fileName); + if (_options & VERBOSE_ENABLED) printf("[ERR] Input file %s not found!\n", fileName); } } else err = ERROR_ARGS_NULL; diff --git a/src/hob_struct.h b/src/hob_struct.h index b72d3d3..0826048 100644 --- a/src/hob_struct.h +++ b/src/hob_struct.h @@ -9,6 +9,13 @@ #define SRC_HOB_STRUCT_H_ +/* + * long = 64bits??? + * int = 32bits + * short = 16bits + * car = 8bits + */ + /////////////////////////////////////////////////////////////////////////////// // HOB file structure /////////////////////////////////////////////////////////////////////////////// @@ -79,7 +86,7 @@ typedef struct __attribute__((packed)) hobfile_header { typedef struct __attribute__((packed)) hobfile_obj_descriptor { unsigned char object_name[16]; - unsigned int facegroup_header_offset; + unsigned int facegroup_offset; unsigned int object_parts_offset; unsigned int facegroup_header_2_offset; @@ -110,4 +117,84 @@ typedef struct __attribute__((packed)) hobfile_obj_descriptor { float reserved17; } T_HOBFILE_OBJ_DESCRIPTOR; +typedef struct __attribute__((packed)) hobfile_facegroup_header { + unsigned short facegroup_count; + unsigned short facegroup_count0; +} T_HOBFILE_FACEGROUP_HEADER; + +typedef struct __attribute__((packed)) hobfile_facegroup_offset { + unsigned int unknow1; + unsigned int facegroup_offset; +} T_HOBFILE_FACEGROUP_OFFSET; + +typedef struct __attribute__((packed)) hobfile_meshdef0_0 { + unsigned int next_meshdef0_offset; + unsigned int prev_meshdef0_offset_unsure; + unsigned int offset_beginning_if_not_first; + unsigned int offset_end_if_next_equal_0; + unsigned int meshdef1_offset_plus_4; + + unsigned int reserved1; // 8B of zeros + unsigned int reserved2; +} T_HOBFILE_MESHDEF0_0; + +typedef struct __attribute__((packed)) hobfile_meshdef0_1 { + float unknow1; + + unsigned int reserved1; // 12B of zeros + unsigned int reserved2; + unsigned int reserved3; +} T_HOBFILE_MESHDEF0_1; + +typedef struct __attribute__((packed)) hobfile_meshdef0_2 { + unsigned int unknow1; + + float unknow2; // Can be a vector??? + float unknow3; + float unknow4; + + float unknow5; // Can be a vector??? + float unknow6; + float unknow7; + + float unknow8; // Can be a matrix??? + float unknow9; + float unknow10; + float unknow11; + + float unknow12; // Can be a vector??? + float unknow13; + float unknow14; +} T_HOBFILE_MESHDEF0_2; + +typedef struct __attribute__((packed)) hobfile_meshdef1 { + unsigned int facedef_end_offset; + + unsigned int reserved1; // 20B of zeros + unsigned int reserved2; + unsigned int reserved3; + unsigned int reserved4; + unsigned int reserved5; + + unsigned int vertex_count; + unsigned int unknow1; + unsigned int reserved6; + unsigned int faceblock_offset; + unsigned int vertexblocks_offset; + + unsigned int reserved7; // 52B of zeros + unsigned int reserved8; + unsigned int reserved9; + unsigned int reserved10; + unsigned int reserved11; + unsigned int reserved12; + unsigned int reserved13; + unsigned int reserved14; + unsigned int reserved15; + unsigned int reserved16; + unsigned int reserved17; + unsigned int reserved18; + unsigned int reserved19; +} T_HOBFILE_MESHDEF1; + #endif /* SRC_HOB_STRUCT_H_ */ From 27457ea4f968b64bca55e13c3b8e4d6a60c57a60 Mon Sep 17 00:00:00 2001 From: JackCarterSmith Date: Wed, 27 Jul 2022 17:16:56 +0200 Subject: [PATCH 4/7] Vertices extraction --- src/Model-Extractor.c | 31 +++++++++++++------------- src/hob_parser.c | 51 ++++++++++++++++++++++++++++++++++++++++--- src/hob_struct.h | 11 +++++++++- 3 files changed, 74 insertions(+), 19 deletions(-) diff --git a/src/Model-Extractor.c b/src/Model-Extractor.c index a3e12c5..16009d7 100644 --- a/src/Model-Extractor.c +++ b/src/Model-Extractor.c @@ -21,19 +21,19 @@ #include "options.h" #include "hob_struct.h" #include "hob_parser.h" -#include "rlk/obj.h" +//#include "rlk/obj.h" /* * Internal functions declarations */ -unsigned int mainProcess(int args_cnt, char *args_value[]); -void createSubDir(char *dirName); -int checkInputArgs(int arg_nbr, char *args[]); -void cleanUpMemory(T_HOB* hobStruct); +static unsigned int mainProcess(int args_cnt, char *args_value[]); +static void createSubDir(char *dirName); +static int checkInputArgs(int arg_nbr, char *args[]); +static void cleanUpMemory(T_HOB* hobStruct); //int exportTextures(HMT_FILE *hmt_f, char *filename); -void dispHelp(); +static inline void dispHelp(); /* @@ -69,7 +69,7 @@ int main(int argc, char *argv[]) { * Private functions definition */ -unsigned int mainProcess(int args_cnt, char *args_value[]) { +static unsigned int mainProcess(int args_cnt, char *args_value[]) { unsigned short file_index; T_HOB* hobStruct = NULL; @@ -97,7 +97,7 @@ unsigned int mainProcess(int args_cnt, char *args_value[]) { return NO_ERROR; } -int checkInputArgs(int arg_nbr, char *args[]) { +static int checkInputArgs(int arg_nbr, char *args[]) { int _o = 0x0002; // Default options parameters char test[256]; int i; @@ -125,7 +125,7 @@ int checkInputArgs(int arg_nbr, char *args[]) { return _o; } -void createSubDir(char *dirName) { +static void createSubDir(char *dirName) { if (dirName == NULL) return; char _dir[260]; //TODO: Change directory management strcpy(_dir, dirName); @@ -138,23 +138,24 @@ void createSubDir(char *dirName) { #endif } -void cleanUpMemory(T_HOB* hobStruct) { - int i,j,k; +static void cleanUpMemory(T_HOB* hobStruct) { + int i,j; for ( i=0; iobj_count; i++ ) { for ( j=0; jobjects[i].face_group_count; j++ ) { - - free(&(hobStruct->objects[i].face_groups[j])); + free(hobStruct->objects[i].face_groups[j].faces); + free(hobStruct->objects[i].face_groups[j].vertices); } - free(&(hobStruct->objects[i])); + free(hobStruct->objects[i].face_groups); } + free(hobStruct->objects); free(hobStruct); } -void dispHelp() { +static inline void dispHelp() { printf("\n"); printf("Options:\n -h Print this message\n -v Activate verbose console output\n -no-subdir Extract textures inside current folder\n"); printf("\n"); diff --git a/src/hob_parser.c b/src/hob_parser.c index 6dbe6f8..3a4fe3f 100644 --- a/src/hob_parser.c +++ b/src/hob_parser.c @@ -19,7 +19,7 @@ unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { long fileSize; FILE* fStream = NULL; char* memFile = NULL; - int i,j; + int i,j,k; int* offset_index = NULL; if (hob_struct != NULL && fileName != NULL) { @@ -83,9 +83,54 @@ unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { offset_index[j] = ((T_HOBFILE_FACEGROUP_OFFSET *)(memFile + hob_struct->objects[i].face_group_header_offset + sizeof(T_HOBFILE_FACEGROUP_HEADER) + sizeof(T_HOBFILE_FACEGROUP_OFFSET) * j))->facegroup_offset; - if (_options & VERBOSE_ENABLED) printf("[DBG] > Face group meshdef0 offset: 0x%X\n", offset_index[j]); + if (_options & VERBOSE_ENABLED) printf("\n[DBG] > Face group meshdef0 offset: 0x%X\n", offset_index[j]); - // TODO: READ FACEGROUP MESHDEF!!! + // Get meshdef1 (mesh descriptor) offset + hob_struct->objects[i].face_groups[j].meshdef1_offset = ((T_HOBFILE_MESHDEF0_0 *)(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].face_groups[j].meshdef1_offset); + + if (hob_struct->objects[i].face_groups[j].meshdef1_offset > 0) { + // Read meshdef1 datas + hob_struct->objects[i].face_groups[j].face_block_end_offset = ((T_HOBFILE_MESHDEF1 *)(memFile + + hob_struct->objects[i].face_groups[j].meshdef1_offset - 4))->facedef_end_offset; + hob_struct->objects[i].face_groups[j].vertex_count = ((T_HOBFILE_MESHDEF1 *)(memFile + + hob_struct->objects[i].face_groups[j].meshdef1_offset - 4))->vertex_count; + hob_struct->objects[i].face_groups[j].face_block_offset = ((T_HOBFILE_MESHDEF1 *)(memFile + + hob_struct->objects[i].face_groups[j].meshdef1_offset - 4))->faceblock_offset; + if (_options & VERBOSE_ENABLED) printf("[DBG] > Faces offset: 0x%X\n", hob_struct->objects[i].face_groups[j].face_block_offset); + hob_struct->objects[i].face_groups[j].vertex_block_offset = ((T_HOBFILE_MESHDEF1 *)(memFile + + hob_struct->objects[i].face_groups[j].meshdef1_offset - 4))->vertexblocks_offset; + if (_options & VERBOSE_ENABLED) printf("[DBG] > Vertex offset: 0x%X\n", hob_struct->objects[i].face_groups[j].vertex_block_offset); + + //TODO: read Faces + + // Get vertices datas + hob_struct->objects[i].face_groups[j].vertices = calloc(hob_struct->objects[i].face_groups[j].vertex_count, sizeof(T_VERTEX)); + for ( k = 0; k < hob_struct->objects[i].face_groups[j].vertex_count; k++ ) { + hob_struct->objects[i].face_groups[j].vertices[k].x = ((T_HOBFILE_VERTEX *)(memFile + + hob_struct->objects[i].face_groups[j].vertex_block_offset + + sizeof(T_VERTEX) * k))->x; + + hob_struct->objects[i].face_groups[j].vertices[k].y = ((T_HOBFILE_VERTEX *)(memFile + + hob_struct->objects[i].face_groups[j].vertex_block_offset + + sizeof(T_VERTEX) * k))->y; + + hob_struct->objects[i].face_groups[j].vertices[k].z = ((T_HOBFILE_VERTEX *)(memFile + + hob_struct->objects[i].face_groups[j].vertex_block_offset + + sizeof(T_VERTEX) * k))->z; + + hob_struct->objects[i].face_groups[j].vertices[k].w = ((T_HOBFILE_VERTEX *)(memFile + + hob_struct->objects[i].face_groups[j].vertex_block_offset + + sizeof(T_VERTEX) * k))->w; // Always 0??? + + //if (_options & VERBOSE_ENABLED) printf("[DBG] > Found vertex: (%d, %d, %d)\n", + // hob_struct->objects[i].face_groups[j].vertices[k].x, + // hob_struct->objects[i].face_groups[j].vertices[k].y, + // hob_struct->objects[i].face_groups[j].vertices[k].z + // ); + } + } } } diff --git a/src/hob_struct.h b/src/hob_struct.h index 0826048..ff0d2c3 100644 --- a/src/hob_struct.h +++ b/src/hob_struct.h @@ -22,6 +22,8 @@ typedef unsigned int T_RGBA; +typedef struct vertex { short x,y,z,w; } T_VERTEX; + typedef struct tex_coord { unsigned short u,v; } T_TEXCOORD; typedef struct hob_face { @@ -48,7 +50,7 @@ typedef struct hob_face_group { T_HOB_FACE* faces; unsigned int vertex_count; - unsigned short* vertices; + T_VERTEX* vertices; } T_HOB_FACE_GROUP; typedef struct hob_object { @@ -197,4 +199,11 @@ typedef struct __attribute__((packed)) hobfile_meshdef1 { unsigned int reserved19; } T_HOBFILE_MESHDEF1; +typedef struct __attribute__((packed)) hobfile_vertex { + short x; + short y; + short z; + short w; +} T_HOBFILE_VERTEX; + #endif /* SRC_HOB_STRUCT_H_ */ From e5b3058999640027044beea7597dfa37501e4207 Mon Sep 17 00:00:00 2001 From: JackCarterSmith Date: Wed, 27 Jul 2022 17:18:07 +0200 Subject: [PATCH 5/7] Completed HOB parser --- src/hob_parser.c | 231 +++++++++++++++++++++++++++++++++++++++++++++-- src/hob_struct.h | 105 ++++++++++++++++----- 2 files changed, 303 insertions(+), 33 deletions(-) diff --git a/src/hob_parser.c b/src/hob_parser.c index 3a4fe3f..4a4a19a 100644 --- a/src/hob_parser.c +++ b/src/hob_parser.c @@ -20,6 +20,7 @@ unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { FILE* fStream = NULL; char* memFile = NULL; int i,j,k; + unsigned int facesExtraOffset; int* offset_index = NULL; if (hob_struct != NULL && fileName != NULL) { @@ -51,6 +52,7 @@ unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { 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"); printf("[INFO] - Process %s object...\n", hob_struct->objects[i].name); // Get offsets @@ -101,11 +103,224 @@ unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { if (_options & VERBOSE_ENABLED) printf("[DBG] > Faces offset: 0x%X\n", hob_struct->objects[i].face_groups[j].face_block_offset); hob_struct->objects[i].face_groups[j].vertex_block_offset = ((T_HOBFILE_MESHDEF1 *)(memFile + hob_struct->objects[i].face_groups[j].meshdef1_offset - 4))->vertexblocks_offset; - if (_options & VERBOSE_ENABLED) printf("[DBG] > Vertex offset: 0x%X\n", hob_struct->objects[i].face_groups[j].vertex_block_offset); + if (_options & VERBOSE_ENABLED) printf("[DBG] > Vertex offset: 0x%X\n\n", hob_struct->objects[i].face_groups[j].vertex_block_offset); - //TODO: read Faces + // Get face datas + if( ((T_HOBFILE_FACEBLOCK *)(memFile + hob_struct->objects[i].face_groups[j].face_block_offset))->reserved1 != 0 || + ((T_HOBFILE_FACEBLOCK *)(memFile + hob_struct->objects[i].face_groups[j].face_block_offset))->reserved2 != 0 ) { + if (_options & VERBOSE_ENABLED) printf("[DBG] > Face block: uncommon zero header!\n"); + } + if ( ((T_HOBFILE_FACEBLOCK *)(memFile + hob_struct->objects[i].face_groups[j].face_block_offset))->facesOffset != + hob_struct->objects[i].face_groups[j].face_block_offset + sizeof(T_HOBFILE_FACEBLOCK)) { + if (_options & VERBOSE_ENABLED) printf("[DBG] > Face block: uncommon face data offset position!\n"); + } + hob_struct->objects[i].face_groups[j].face_count = ((T_HOBFILE_FACEBLOCK *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset))->faceCounts; + hob_struct->objects[i].face_groups[j].faces = calloc(hob_struct->objects[i].face_groups[j].face_count, sizeof(T_HOB_FACE)); + facesExtraOffset = 0; + for ( k = 0; k < hob_struct->objects[i].face_groups[j].face_count; k++ ) { + // Get flags + hob_struct->objects[i].face_groups[j].faces[k].flags = ((T_HOBFILE_FACES_HEADER *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->flags; - // Get vertices datas + // Get unknown bytes + hob_struct->objects[i].face_groups[j].faces[k].b1 = ((T_HOBFILE_FACES_HEADER *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->b1; + hob_struct->objects[i].face_groups[j].faces[k].b2 = ((T_HOBFILE_FACES_HEADER *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->b2; + hob_struct->objects[i].face_groups[j].faces[k].b3 = ((T_HOBFILE_FACES_HEADER *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->b3; + + hob_struct->objects[i].face_groups[j].faces[k].bsize = ((T_HOBFILE_FACES_HEADER *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->faceBlockIntSize * 4; // Multiply by 4 to get the bytes exact number + if (((T_HOBFILE_FACES_HEADER *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->headerSeparator != 0) { + if (_options & VERBOSE_ENABLED) printf("[DBG] > Face header: uncommon separator!\n"); + } + + // Get materials index + hob_struct->objects[i].face_groups[j].faces[k].material_index = ((T_HOBFILE_FACES_HEADER *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->materialIndex; + + // Get vertex indices + memcpy(hob_struct->objects[i].face_groups[j].faces[k].indices, + ((T_HOBFILE_FACES_HEADER *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->vertexIndices, + sizeof(unsigned short) * 4); + + // Recalculate the dynamic extra bytes offset size - if present + if (hob_struct->objects[i].face_groups[j].faces[k].flags_bits.fHasExtraBytesBeforeColor) facesExtraOffset += 8; + + // Get vertex color - if present + if (hob_struct->objects[i].face_groups[j].faces[k].flags_bits.fHasColor) { + if (hob_struct->objects[i].face_groups[j].faces[k].flags_bits.fSeparateColorVertex) { + hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[0] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->v1_rgba; + hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[1] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->v2_rgba; + hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[2] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->v3_rgba; + if (hob_struct->objects[i].face_groups[j].faces[k].flags_bits.fIsQuad) { + hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[3] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->v4_rgba; + facesExtraOffset += sizeof(T_HOBFILE_FACES_VERTEX_COLOR); + } else { + facesExtraOffset += sizeof(T_HOBFILE_FACES_VERTEX_COLOR) - sizeof(T_RGBA); + } + } else { + hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[0] = ((T_HOBFILE_FACES_COLOR *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->rgba; + hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[1] = ((T_HOBFILE_FACES_COLOR *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->rgba; + hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[2] = ((T_HOBFILE_FACES_COLOR *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->rgba; + hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[3] = ((T_HOBFILE_FACES_COLOR *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->rgba; + facesExtraOffset += sizeof(T_HOBFILE_FACES_COLOR); + } + } + + // Get UV map - if present + if (hob_struct->objects[i].face_groups[j].faces[k].flags_bits.fHasTexture) { + hob_struct->objects[i].face_groups[j].faces[k].tex_coords[0] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->v1_texcoord; + hob_struct->objects[i].face_groups[j].faces[k].tex_coords[1] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->v2_texcoord; + hob_struct->objects[i].face_groups[j].faces[k].tex_coords[2] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->v3_texcoord; + if (hob_struct->objects[i].face_groups[j].faces[k].flags_bits.fIsQuad) { + hob_struct->objects[i].face_groups[j].faces[k].tex_coords[3] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(memFile + + hob_struct->objects[i].face_groups[j].face_block_offset + + sizeof(T_HOBFILE_FACEBLOCK) + + sizeof(T_HOBFILE_FACES_HEADER) + + sizeof(T_HOBFILE_FACES_HEADER) * k + + facesExtraOffset))->v4_texcoord; + facesExtraOffset += sizeof(T_HOBFILE_FACES_VERTEX_TEXTURE); + } else { + facesExtraOffset += sizeof(T_HOBFILE_FACES_VERTEX_TEXTURE) - sizeof(T_TEXCOORD); + } + } + + if (_options & VERBOSE_ENABLED) { + printf("[DBG] > Face %d details: 0x%X, %d, %d, %d, %d\n", k, + hob_struct->objects[i].face_groups[j].faces[k].flags, + hob_struct->objects[i].face_groups[j].faces[k].b1, + hob_struct->objects[i].face_groups[j].faces[k].b2, + hob_struct->objects[i].face_groups[j].faces[k].b3, + hob_struct->objects[i].face_groups[j].faces[k].bsize + ); + printf("[DBG] - Type is Quad: %d\n", hob_struct->objects[i].face_groups[j].faces[k].flags_bits.fIsQuad); + printf("[DBG] - Material offset: 0x%X\n", hob_struct->objects[i].face_groups[j].faces[k].material_index); + printf("[DBG] - Vertex indices: %d, %d, %d, %d\n", + hob_struct->objects[i].face_groups[j].faces[k].indices[0], + hob_struct->objects[i].face_groups[j].faces[k].indices[1], + hob_struct->objects[i].face_groups[j].faces[k].indices[2], + hob_struct->objects[i].face_groups[j].faces[k].indices[3] + ); + printf("[DBG] - Vertex colors: 0x%X, 0x%X, 0x%X, 0x%X\n", + hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[0], + hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[1], + hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[2], + hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[3] + ); + printf("[DBG] - Vertex UV coord (divided by 4096):\n"); + printf("[DBG] > %.8f(%d), %.8f(%d)\n", + ((double) 1/4096) * hob_struct->objects[i].face_groups[j].faces[k].tex_coords[0].u, + hob_struct->objects[i].face_groups[j].faces[k].tex_coords[0].u, + ((double) 1/4096) * hob_struct->objects[i].face_groups[j].faces[k].tex_coords[0].v, + hob_struct->objects[i].face_groups[j].faces[k].tex_coords[0].v + ); + printf("[DBG] > %.8f(%d), %.8f(%d)\n", + ((double) 1/4096) * hob_struct->objects[i].face_groups[j].faces[k].tex_coords[1].u, + hob_struct->objects[i].face_groups[j].faces[k].tex_coords[1].u, + ((double) 1/4096) * hob_struct->objects[i].face_groups[j].faces[k].tex_coords[1].v, + hob_struct->objects[i].face_groups[j].faces[k].tex_coords[1].v + ); + printf("[DBG] > %.8f(%d), %.8f(%d)\n", + ((double) 1/4096) * hob_struct->objects[i].face_groups[j].faces[k].tex_coords[2].u, + hob_struct->objects[i].face_groups[j].faces[k].tex_coords[2].u, + ((double) 1/4096) * hob_struct->objects[i].face_groups[j].faces[k].tex_coords[2].v, + hob_struct->objects[i].face_groups[j].faces[k].tex_coords[2].v + ); + printf("[DBG] > %.8f(%d), %.8f(%d)\n", + ((double) 1/4096) * hob_struct->objects[i].face_groups[j].faces[k].tex_coords[3].u, + hob_struct->objects[i].face_groups[j].faces[k].tex_coords[3].u, + ((double) 1/4096) * hob_struct->objects[i].face_groups[j].faces[k].tex_coords[3].v, + hob_struct->objects[i].face_groups[j].faces[k].tex_coords[3].v + ); + printf("\n"); + } + } + + // Get vertex datas hob_struct->objects[i].face_groups[j].vertices = calloc(hob_struct->objects[i].face_groups[j].vertex_count, sizeof(T_VERTEX)); for ( k = 0; k < hob_struct->objects[i].face_groups[j].vertex_count; k++ ) { hob_struct->objects[i].face_groups[j].vertices[k].x = ((T_HOBFILE_VERTEX *)(memFile @@ -124,11 +339,11 @@ unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { + hob_struct->objects[i].face_groups[j].vertex_block_offset + sizeof(T_VERTEX) * k))->w; // Always 0??? - //if (_options & VERBOSE_ENABLED) printf("[DBG] > Found vertex: (%d, %d, %d)\n", - // hob_struct->objects[i].face_groups[j].vertices[k].x, - // hob_struct->objects[i].face_groups[j].vertices[k].y, - // hob_struct->objects[i].face_groups[j].vertices[k].z - // ); + if (_options & VERBOSE_ENABLED) printf("[DBG] > Found vertex %d: (%d, %d, %d)\n", k, + hob_struct->objects[i].face_groups[j].vertices[k].x, + hob_struct->objects[i].face_groups[j].vertices[k].y, + hob_struct->objects[i].face_groups[j].vertices[k].z + ); } } } diff --git a/src/hob_struct.h b/src/hob_struct.h index ff0d2c3..b68df84 100644 --- a/src/hob_struct.h +++ b/src/hob_struct.h @@ -26,15 +26,33 @@ typedef struct vertex { short x,y,z,w; } T_VERTEX; typedef struct tex_coord { unsigned short u,v; } T_TEXCOORD; +typedef struct face_flags { + unsigned int fUnknown0:1; + unsigned int fUnknown1:1; + unsigned int fHasTexture:1; + unsigned int fIsQuad:1; + unsigned int fSeparateColorVertex:1; + unsigned int fHasColor:1; + unsigned int fHasExtraBytesBeforeColor:1; + unsigned int fUnknown7:1; + unsigned int fUnknown8:1; + unsigned int fUnknown9:1; + unsigned int fUnknown10:1; + + unsigned int reserved:21; +} FACE_FLAGS; + typedef struct hob_face { - unsigned int flags; + union { + unsigned int flags; + FACE_FLAGS flags_bits; + }; unsigned char b1; unsigned char b2; unsigned char b3; unsigned char bsize; - unsigned char ftype; // 3-Tri / 4-Quad - unsigned __int64 material_index; //TODO: verify for 64bits width and adapt MinGW dependancy to __int64 - unsigned __int64 indices[4]; //TODO: verify for 64bits width and adapt MinGW dependancy to __int64 + unsigned short material_index; + unsigned short indices[4]; T_RGBA vertex_colors[4]; //TODO: convert in R:8_G:8_B:8_A:8 format? Caution with BE/LE conversion T_TEXCOORD tex_coords[4]; } T_HOB_FACE; @@ -96,10 +114,10 @@ typedef struct __attribute__((packed)) hobfile_obj_descriptor { unsigned int reserved2; unsigned int reserved3; - unsigned int unknow1; - unsigned int unknow2; - unsigned int unknow3; - float unknow4; + unsigned int unknown1; + unsigned int unknown2; + unsigned int unknown3; + float unknown4; unsigned int reserved4; // 12B of zeros unsigned int reserved5; @@ -125,7 +143,7 @@ typedef struct __attribute__((packed)) hobfile_facegroup_header { } T_HOBFILE_FACEGROUP_HEADER; typedef struct __attribute__((packed)) hobfile_facegroup_offset { - unsigned int unknow1; + unsigned int unknown1; unsigned int facegroup_offset; } T_HOBFILE_FACEGROUP_OFFSET; @@ -141,7 +159,7 @@ typedef struct __attribute__((packed)) hobfile_meshdef0_0 { } T_HOBFILE_MESHDEF0_0; typedef struct __attribute__((packed)) hobfile_meshdef0_1 { - float unknow1; + float unknown1; unsigned int reserved1; // 12B of zeros unsigned int reserved2; @@ -149,24 +167,24 @@ typedef struct __attribute__((packed)) hobfile_meshdef0_1 { } T_HOBFILE_MESHDEF0_1; typedef struct __attribute__((packed)) hobfile_meshdef0_2 { - unsigned int unknow1; + unsigned int Unknown1; - float unknow2; // Can be a vector??? - float unknow3; - float unknow4; + float unknown2; // Can be a vector??? + float unknown3; + float unknown4; - float unknow5; // Can be a vector??? - float unknow6; - float unknow7; + float unknown5; // Can be a vector??? + float unknown6; + float unknown7; - float unknow8; // Can be a matrix??? - float unknow9; - float unknow10; - float unknow11; + float unknown8; // Can be a matrix??? + float unknown9; + float unknown10; + float unknown11; - float unknow12; // Can be a vector??? - float unknow13; - float unknow14; + float unknown12; // Can be a vector??? + float unknown13; + float unknown14; } T_HOBFILE_MESHDEF0_2; typedef struct __attribute__((packed)) hobfile_meshdef1 { @@ -179,7 +197,7 @@ typedef struct __attribute__((packed)) hobfile_meshdef1 { unsigned int reserved5; unsigned int vertex_count; - unsigned int unknow1; + unsigned int unknown1; unsigned int reserved6; unsigned int faceblock_offset; unsigned int vertexblocks_offset; @@ -199,6 +217,43 @@ typedef struct __attribute__((packed)) hobfile_meshdef1 { unsigned int reserved19; } T_HOBFILE_MESHDEF1; +typedef struct __attribute__((packed)) hobfile_faceblock { + unsigned int reserved1; // 8B of zeros + unsigned int reserved2; + + unsigned int facesOffset; + unsigned int faceCounts; +} T_HOBFILE_FACEBLOCK; + +typedef struct __attribute__((packed)) hobfile_faces_header { + unsigned int flags; + unsigned char b1; + unsigned char b2; + unsigned char b3; + unsigned char faceBlockIntSize; // Bytes size divided by 4, count as number of UInt32 type. + unsigned short headerSeparator; + unsigned short materialIndex; + unsigned short vertexIndices[4]; // Relative to facegroup, the last value is equal to 0 when it's triangle shape. +} T_HOBFILE_FACES_HEADER; + +typedef struct __attribute__((packed)) 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 { + T_RGBA rgba; +} T_HOBFILE_FACES_COLOR; + +typedef struct __attribute__((packed)) 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 { short x; short y; From e0c9f2c7d8e4fc18f03586899821335f50cd3925 Mon Sep 17 00:00:00 2001 From: JackCarterSmith Date: Wed, 27 Jul 2022 17:33:55 +0200 Subject: [PATCH 6/7] Structure for exporting --- CMakeLists.txt | 6 +++--- src/Model-Extractor.c | 20 ++++++++++++------- src/hob_struct.h | 2 +- src/obj_exporter.c | 46 +++++++++++++++++++++++++++++++++++++++++++ src/obj_exporter.h | 13 ++++++++++++ 5 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 src/obj_exporter.c create mode 100644 src/obj_exporter.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 222220a..30a6a90 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,8 +23,8 @@ include(CheckCSourceCompiles) # needed packages -find_package(GLEW REQUIRED) -include_directories(${GLEW_INCLUDE_DIR}) +#find_package(GLEW REQUIRED) +#include_directories(${GLEW_INCLUDE_DIR}) # define src/headers files @@ -45,7 +45,7 @@ if(MSVC) set_target_properties(rse-model PROPERTIES PREFIX "lib") set_target_properties(rse-model PROPERTIES IMPORT_PREFIX "lib") endif() -target_link_libraries(rse-model ${GLEW_LIBRARIES}) +target_link_libraries(rse-model m) # add GPG signature command #add_custom_command( diff --git a/src/Model-Extractor.c b/src/Model-Extractor.c index 16009d7..76b4aa7 100644 --- a/src/Model-Extractor.c +++ b/src/Model-Extractor.c @@ -21,7 +21,7 @@ #include "options.h" #include "hob_struct.h" #include "hob_parser.h" -//#include "rlk/obj.h" +#include "obj_exporter.h" /* @@ -72,6 +72,7 @@ int main(int argc, char *argv[]) { static unsigned int mainProcess(int args_cnt, char *args_value[]) { 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++) @@ -84,16 +85,21 @@ static unsigned int mainProcess(int args_cnt, char *args_value[]) { free(hobStruct); return ERROR_PROCESS; } + + if (hobStruct->obj_count > 0) { + if (_options & 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) + 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); + } + } } cleanUpMemory(hobStruct); - - /* - if (exportTextures(hmt_fdatas, argv[file_index]) == EXIT_FAILURE) return EXIT_FAILURE; - purgeHMTFromMemory(hmt_fdatas); // Clean up memory (because I'm a good boy) - */ - return NO_ERROR; } diff --git a/src/hob_struct.h b/src/hob_struct.h index b68df84..55b1697 100644 --- a/src/hob_struct.h +++ b/src/hob_struct.h @@ -72,7 +72,7 @@ typedef struct hob_face_group { } T_HOB_FACE_GROUP; typedef struct hob_object { - unsigned char name[16]; + char name[16]; unsigned int face_group_offset; unsigned int face_group_header_offset; unsigned int face_group_header2_offset; diff --git a/src/obj_exporter.c b/src/obj_exporter.c new file mode 100644 index 0000000..6448553 --- /dev/null +++ b/src/obj_exporter.c @@ -0,0 +1,46 @@ +/* + * obj_exporter.c + * + * Created on: 27 juil. 2022 + * Author: JackCarterSmith + */ + +#include +#include +#include +#include "errors_types.h" +#include "options.h" +#include "hob_struct.h" +#include "rlk/obj.h" +#include "obj_exporter.h" + + +unsigned char exportOBJModel(T_HOB_OBJECT* hob_objects, const char *out_path) { + char export_path[128]; + obj* objConstruct = NULL; + + if (hob_objects == NULL || out_path == NULL) + return ERROR_ARGS_NULL; + + if (_options & OUTPUT_DIR) { + strcpy(export_path, out_path); + #ifdef _WIN32 + strcat(export_path, "-out\\"); + #else + strcat(export_path, "-out/"); + #endif + strcat(export_path, hob_objects->name); + } else { + strcpy(export_path, hob_objects->name); + } + strcat(export_path, ".obj"); + + objConstruct = obj_create(NULL); + + //TODO: Write datas to obj file! + + obj_write(objConstruct, hob_objects->name, export_path, 8); + obj_delete(objConstruct); + + return NO_ERROR; +} diff --git a/src/obj_exporter.h b/src/obj_exporter.h new file mode 100644 index 0000000..f6e7945 --- /dev/null +++ b/src/obj_exporter.h @@ -0,0 +1,13 @@ +/* + * obj_exporter.h + * + * Created on: 27 juil. 2022 + * Author: JackCarterSmith + */ + +#ifndef SRC_OBJ_EXPORTER_H_ +#define SRC_OBJ_EXPORTER_H_ + +unsigned char exportOBJModel(T_HOB_OBJECT* hob_objects, const char *out_path); + +#endif /* SRC_OBJ_EXPORTER_H_ */ From 068fdff8fd5439c529711871fa3d46181f9a04e3 Mon Sep 17 00:00:00 2001 From: JackCarterSmith Date: Wed, 27 Jul 2022 19:58:55 +0200 Subject: [PATCH 7/7] Obj file export basic --- src/hob_parser.c | 2 +- src/obj_exporter.c | 66 +++++++++++++++++++++++++++++++++++++++------- src/obj_exporter.h | 7 +++++ 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/src/hob_parser.c b/src/hob_parser.c index 4a4a19a..aaf1254 100644 --- a/src/hob_parser.c +++ b/src/hob_parser.c @@ -19,7 +19,7 @@ unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) { long fileSize; FILE* fStream = NULL; char* memFile = NULL; - int i,j,k; + unsigned int i,j,k; unsigned int facesExtraOffset; int* offset_index = NULL; diff --git a/src/obj_exporter.c b/src/obj_exporter.c index 6448553..d042dfe 100644 --- a/src/obj_exporter.c +++ b/src/obj_exporter.c @@ -16,30 +16,78 @@ unsigned char exportOBJModel(T_HOB_OBJECT* hob_objects, const char *out_path) { - char export_path[128]; + char objExport_path[128]; + char mtlExport_path[128]; obj* objConstruct = NULL; + unsigned int i,j; + int surfID = 0, materialID = 0, tmpVertex = 0, tmpIndex = 0; + float vertexBuff[3] = {0}, textureBuff[2] = {0}; + int indicesBuff[3] = {0}; if (hob_objects == NULL || out_path == NULL) return ERROR_ARGS_NULL; if (_options & OUTPUT_DIR) { - strcpy(export_path, out_path); + strcpy(objExport_path, out_path); #ifdef _WIN32 - strcat(export_path, "-out\\"); + strcat(objExport_path, "-out\\"); #else - strcat(export_path, "-out/"); + strcat(objExport_path, "-out/"); #endif - strcat(export_path, hob_objects->name); + strcat(objExport_path, hob_objects->name); } else { - strcpy(export_path, hob_objects->name); + strcpy(objExport_path, hob_objects->name); } - strcat(export_path, ".obj"); + strcpy(mtlExport_path, objExport_path); + strcat(objExport_path, ".obj"); + strcat(mtlExport_path, ".mtl"); objConstruct = obj_create(NULL); - //TODO: Write datas to obj file! + // Build face/surface material group + for ( i = 0; i < hob_objects->face_group_count; i++) { + surfID = obj_add_surf(objConstruct); + materialID = obj_add_mtrl(objConstruct); - obj_write(objConstruct, hob_objects->name, export_path, 8); + // Build vertex container + for ( j = 0; j < hob_objects->face_groups[i].vertex_count; j++ ) { + tmpVertex = obj_add_vert(objConstruct); + + vertexBuff[0] = ((float)1/1024) * -hob_objects->face_groups[i].vertices[j].x; // Invert X to fix mirror display + vertexBuff[1] = ((float)1/1024) * -hob_objects->face_groups[i].vertices[j].y; // Invert Y to render upside up + vertexBuff[2] = ((float)1/1024) * hob_objects->face_groups[i].vertices[j].z; + + obj_set_vert_v(objConstruct, tmpVertex, vertexBuff); + + //textureBuff[0] = ((float)1/1) * hob_objects->face_groups[i]. + + //obj_set_vert_t(objConstruct, tmpVertex, textureBuff); + } + + // Build indices container + for ( j = 0; j < hob_objects->face_groups[i].face_count; j++ ) { + tmpIndex = obj_add_poly(objConstruct, surfID); + + indicesBuff[0] = (int)hob_objects->face_groups[i].faces[j].indices[0]; + indicesBuff[1] = (int)hob_objects->face_groups[i].faces[j].indices[1]; + indicesBuff[2] = (int)hob_objects->face_groups[i].faces[j].indices[2]; + + obj_set_poly(objConstruct, surfID, tmpIndex, indicesBuff); + + // Process 2 triangles if face is Quad + if (hob_objects->face_groups[i].faces[j].flags_bits.fIsQuad) { + tmpIndex = obj_add_poly(objConstruct, surfID); + + indicesBuff[0] = (int)hob_objects->face_groups[i].faces[j].indices[0]; + indicesBuff[1] = (int)hob_objects->face_groups[i].faces[j].indices[2]; + indicesBuff[2] = (int)hob_objects->face_groups[i].faces[j].indices[3]; + + obj_set_poly(objConstruct, surfID, tmpIndex, indicesBuff); + } + } + } + + obj_write(objConstruct, objExport_path, NULL, 8); obj_delete(objConstruct); return NO_ERROR; diff --git a/src/obj_exporter.h b/src/obj_exporter.h index f6e7945..d5a86c7 100644 --- a/src/obj_exporter.h +++ b/src/obj_exporter.h @@ -8,6 +8,13 @@ #ifndef SRC_OBJ_EXPORTER_H_ #define SRC_OBJ_EXPORTER_H_ + +typedef struct t_material { + unsigned short hasTexture; + unsigned short bpp; + unsigned int gl_tex_id; +} T_MATERIAL; + unsigned char exportOBJModel(T_HOB_OBJECT* hob_objects, const char *out_path); #endif /* SRC_OBJ_EXPORTER_H_ */