diff --git a/CMakeLists.txt b/CMakeLists.txt index 88ea3dd..434e2fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ if(DEFINED ENV{CI}) # Jenkins CI integration mode project(rse-model VERSION $ENV{CI_VERSION}.$ENV{CI_BUILD_NUMBER} DESCRIPTION "RogueSquadron Extractor - Model" LANGUAGES C) set(RSE_MODEL_NAME $ENV{CI_OUTPUT_NAME}) else() # Standalone project mode, should not be used for release. - project(rse-model VERSION 2.1.0 DESCRIPTION "RogueSquadron Extractor - Model" LANGUAGES C) + project(rse-model VERSION 2.2.0 DESCRIPTION "RogueSquadron Extractor - Model" LANGUAGES C) set(RSE_MODEL_NAME RSEModel) endif() set(RSP_MODEL_LIB_NAME RSPModel${PROJECT_VERSION_MAJOR}${PROJECT_VERSION_MINOR}) diff --git a/Jenkinsfile b/Jenkinsfile index c5ccb41..3b3cc03 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,7 +5,7 @@ pipeline { } environment { CI_OUTPUT_NAME = "RSEModel" - CI_VERSION = "2.1.1" + CI_VERSION = "2.2.0" CI_BUILD_NUMBER = "$BUILD_NUMBER" } stages { diff --git a/RSEModel/src/RSEModel.c b/RSEModel/src/RSEModel.c index cb61d2d..3423672 100644 --- a/RSEModel/src/RSEModel.c +++ b/RSEModel/src/RSEModel.c @@ -12,14 +12,21 @@ #include #if defined(_WIN32) #include + #include + #define F_OK 0 + #define access _access #else #include #include + #include #endif #include "options.h" #include #include #include "model_export.h" +#include "lib_interface.h" + +#define MAX_STR_VAR 1024 /* @@ -36,15 +43,19 @@ static void dispHelp(); * - MAIN - */ int main(int argc, char *argv[]) { - T_PROG_OPTIONS _opts; + T_PROG_OPTIONS _opts = {0}; unsigned char p; + unsigned int status = RSPLIB_SUCCESS; // Hello world! - printf("\n*~[ Rogue Squadron Extractor (RSE) - RSPModelLib v%s ]~*\n", RSPModel_getVersion()); + printf("\n*~[ Rogue Squadron Extractor (RSE) - RSPModelLib v%s ]~*\n\n", RSPModel_getVersion()); + + // Try linking to externals modules + linkTextureLib(&_opts); // Check for arguments if (argc < 2) { - printf("\n[ERR] No input file/commands specified!\n"); + printf("[ERR] No input file/commands specified!\n"); dispHelp(); return RSPLIB_ERROR_ARGS_NULL; } @@ -54,7 +65,11 @@ int main(int argc, char *argv[]) { if ( p == RSPLIB_ERROR_GENERIC ) return RSPLIB_SUCCESS; else if ( p != RSPLIB_SUCCESS ) return p; - return mainProcess(argc, argv, &_opts); + status = mainProcess(argc, argv, &_opts); + + unlinkTextureLib(); + + return status; } @@ -66,7 +81,9 @@ static unsigned int mainProcess(int args_cnt, char* args_value[], T_PROG_OPTIONS unsigned short file_index; RSPMODEL_PARAMETERS libParams; T_RSPMODEL_HOB* hobStruct = NULL; - int i; + char hmt_filename[MAX_STR_VAR] = {0}; + void* hmtStruct = NULL; + unsigned int i; libParams.raw = p_opts->raw & 0x7; @@ -84,6 +101,23 @@ static unsigned int mainProcess(int args_cnt, char* args_value[], T_PROG_OPTIONS RSPModel_freeHOB(hobStruct); return RSPLIB_ERROR_PROCESS; } + + // If Texture module loaded, process HMT file for mtl naming (doesn't extract texture!) + if (p_opts->texture_module) { + if (strlen(args_value[file_index]) >= MAX_STR_VAR) return RSPLIB_ERROR_GENERIC; + + strncpy(hmt_filename, args_value[file_index], strlen(args_value[file_index]) - 3); + hmt_filename[strlen(args_value[file_index]) - 1] = 0; //C6053 fix + strncat(hmt_filename, "HMT", strlen(args_value[file_index])); + + if (access(hmt_filename, F_OK) == 0) { + hmtStruct = RSPTexture_createHMT(); + RSPTexture_processHMTFile(hmtStruct, hmt_filename, 0); + } else { + printf("[ERR] HMT file '%s' not found for mtl processing!\n", hmt_filename); + return RSPLIB_ERROR_GENERIC; + } + } } else return RSPLIB_ERROR_MEMORY; if (hobStruct->obj_count > 0) { @@ -91,12 +125,14 @@ static unsigned int mainProcess(int args_cnt, char* args_value[], T_PROG_OPTIONS 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], p_opts) == RSPLIB_SUCCESS) + if (exportOBJModel(&(hobStruct->objects[i]), args_value[file_index], hmtStruct, p_opts) == RSPLIB_SUCCESS) printf("[INFO] Successfully exported %s object in OBJ format.\n", hobStruct->objects[i].name); else printf("[ERR] Failed to export %s object in OBJ format!\n", hobStruct->objects[i].name); } } + + RSPTexture_freeHMT(hmtStruct); } RSPModel_freeHOB(hobStruct); @@ -109,7 +145,6 @@ static unsigned short checkInputArgs(T_PROG_OPTIONS* opt_ptr, int p_arg_nbr, cha int i; // Set default options - opt_ptr->raw = 0; opt_ptr->output_dir = 1; if (p_arg_nbr > 1) { @@ -135,8 +170,12 @@ static unsigned short checkInputArgs(T_PROG_OPTIONS* opt_ptr, int p_arg_nbr, cha opt_ptr->output_dir = 0; printf("[OPTN] Export to current directory.\n"); } else if (strcmp(p_args[i], "-mtl") == 0) { - opt_ptr->export_mtl = 1; - printf("[OPTN] Export materials datas.\n"); + if (opt_ptr->texture_module) { + opt_ptr->export_mtl = 1; + printf("[OPTN] Export materials datas.\n"); + } else { + printf("[OPTN] Can't export materials datas, RSPTextureLib not found or incorrect version!\n"); + } } else { printf("[ERR] Unknown option: %s\n", p_args[i]); } diff --git a/RSEModel/src/lib_interface.c b/RSEModel/src/lib_interface.c new file mode 100644 index 0000000..fe7f807 --- /dev/null +++ b/RSEModel/src/lib_interface.c @@ -0,0 +1,122 @@ +/** + * @file lib_interface.c + * @date 01/09/2022 + * @author JackCarterSmith + * @copyright GPL-v3.0 + * @brief Interface functions to external RSP libraries. + * + */ + +#include +#include +#if defined(_WIN32) + #include + #include +#else + #include +#endif +#include "options.h" +#include "lib_interface.h" + + +/* + * Global handler declaration + */ +static void* hRSPTextureLib = NULL; +__RSPTexture_getVersion RSPTexture_getVersion; +__RSPTexture_createHMT RSPTexture_createHMT; +__RSPTexture_processHMTFile RSPTexture_processHMTFile; +__RSPTexture_getMaterialFromID RSPTexture_getMaterialFromID; +__RSPTexture_getMaterialName RSPTexture_getMaterialName; +__RSPTexture_getMaterialOpacity RSPTexture_getMaterialOpacity; +__RSPTexture_getMaterialAmbient RSPTexture_getMaterialAmbient; +__RSPTexture_freeHMT RSPTexture_freeHMT; + + +/** + * Link functions proxies against RSPTextureLib dll/so. + * @param opt_ptr Table of parameters to record module loading status. + */ +void* linkTextureLib(T_PROG_OPTIONS* opt_ptr) { + if (hRSPTextureLib == NULL) { +#if defined(_WIN32) + hRSPTextureLib = LoadLibraryA(RSPTEXTURE_OSLIBFILE); + if (hRSPTextureLib) { + RSPTexture_getVersion = (__RSPTexture_getVersion)GetProcAddress( + hRSPTextureLib, RSPTEXTURE_FUNCNAME_GET_VERSION); + RSPTexture_createHMT = (__RSPTexture_createHMT)GetProcAddress( + hRSPTextureLib, RSPTEXTURE_FUNCNAME_NEW_HMT); + RSPTexture_processHMTFile = (__RSPTexture_processHMTFile)GetProcAddress( + hRSPTextureLib, RSPTEXTURE_FUNCNAME_PROC_HMT); + RSPTexture_getMaterialFromID = (__RSPTexture_getMaterialFromID)GetProcAddress( + hRSPTextureLib, RSPTEXTURE_FUNCNAME_GET_MAT); + RSPTexture_getMaterialName = (__RSPTexture_getMaterialName)GetProcAddress( + hRSPTextureLib, RSPTEXTURE_FUNCNAME_GET_NAME); + RSPTexture_getMaterialOpacity = (__RSPTexture_getMaterialOpacity)GetProcAddress( + hRSPTextureLib, RSPTEXTURE_FUNCNAME_GET_OPACITY); + RSPTexture_getMaterialAmbient = (__RSPTexture_getMaterialAmbient)GetProcAddress( + hRSPTextureLib, RSPTEXTURE_FUNCNAME_GET_AMBIENT); + RSPTexture_freeHMT = (__RSPTexture_freeHMT)GetProcAddress( + hRSPTextureLib, RSPTEXTURE_FUNCNAME_FREE_HMT); + + if (RSPTexture_getVersion && RSPTexture_createHMT && RSPTexture_processHMTFile + && RSPTexture_getMaterialFromID && RSPTexture_freeHMT && RSPTexture_getMaterialName + && RSPTexture_getMaterialOpacity && RSPTexture_getMaterialAmbient) { + opt_ptr->texture_module = 1; + printf("[INFO] Loaded RSPTextureLib v%s\n", RSPTexture_getVersion()); + } else { + printf("[INFO] RSPTextureLib linking failure. Maybe incorrect version or file corrupted?\n"); + } + } else { + printf("[INFO] RSPTextureLib not found.\n"); + } +#else + hRSPTextureLib = dlopen(RSPTEXTURE_OSLIBFILE, RTLD_LAZY | RTLD_DEEPBIND); + if (hRSPTextureLib) { + RSPTexture_getVersion = dlsym( + hRSPTextureLib, RSPTEXTURE_FUNCNAME_GET_VERSION); + RSPTexture_createHMT = dlsym( + hRSPTextureLib, RSPTEXTURE_FUNCNAME_NEW_HMT); + RSPTexture_processHMTFile = dlsym( + hRSPTextureLib, RSPTEXTURE_FUNCNAME_PROC_HMT); + RSPTexture_getMaterialFromID = dlsym( + hRSPTextureLib, RSPTEXTURE_FUNCNAME_GET_MAT); + RSPTexture_getMaterialName = dlsym( + hRSPTextureLib, RSPTEXTURE_FUNCNAME_GET_NAME); + RSPTexture_getMaterialOpacity = dlsym( + hRSPTextureLib, RSPTEXTURE_FUNCNAME_GET_OPACITY); + RSPTexture_getMaterialAmbient = dlsym( + hRSPTextureLib, RSPTEXTURE_FUNCNAME_GET_AMBIENT); + RSPTexture_freeHMT = dlsym( + hRSPTextureLib, RSPTEXTURE_FUNCNAME_FREE_HMT); + + if (RSPTexture_getVersion && RSPTexture_createHMT && RSPTexture_processHMTFile + && RSPTexture_getMaterialFromID && RSPTexture_freeHMT && RSPTexture_getMaterialName + && RSPTexture_getMaterialOpacity && RSPTexture_getMaterialAmbient) { + opt_ptr->texture_module = 1; + printf("[INFO] Loaded RSPTextureLib v%s\n", RSPTexture_getVersion()); + } else { + printf("[INFO] RSPTextureLib linking failure. Maybe incorrect version or file corrupted?\n"); + } + } else { + printf("[INFO] RSPTextureLib not found.\n"); + } +#endif + } + + return hRSPTextureLib; +} + +/** + * Release libraries from dynamic loader. + */ +void unlinkTextureLib(void) { + if (hRSPTextureLib == NULL) return; + +#if defined(_WIN32) + //FreeLibraryAndExitThread(hRSPTextureLib, 0); + FreeLibrary(hRSPTextureLib); +#else + dlclose(hRSPTextureLib); +#endif +} diff --git a/RSEModel/src/lib_interface.h b/RSEModel/src/lib_interface.h new file mode 100644 index 0000000..d94dd9a --- /dev/null +++ b/RSEModel/src/lib_interface.h @@ -0,0 +1,67 @@ +/** + * @file lib_interface.h + * @date 01/09/2022 + * @author JackCarterSmith + * @copyright GPL-v3.0 + * @brief Interface functions to external RSP libraries. + * + */ + +#include "options.h" + + +#ifndef RSEMODEL_LIB_INTERFACE_H_ +#define RSEMODEL_LIB_INTERFACE_H_ + +#define RSPTEXTURE_VERSION "21" +#define RSPTEXTURE_LIBFILE "libRSPTexture" RSPTEXTURE_VERSION +#if defined(_WIN32) + #define RSPTEXTURE_OSLIBFILE RSPTEXTURE_LIBFILE ".dll" +#else + #define RSPTEXTURE_OSLIBFILE RSPTEXTURE_LIBFILE ".so" +#endif + +#define RSPTEXTURE_FUNCNAME_GET_VERSION "RSPTexture_getVersion" +#define RSPTEXTURE_FUNCNAME_NEW_HMT "RSPTexture_createHMT" +#define RSPTEXTURE_FUNCNAME_PROC_HMT "RSPTexture_processHMTFile" +#define RSPTEXTURE_FUNCNAME_GET_MAT "RSPTexture_getMaterialFromID" +#define RSPTEXTURE_FUNCNAME_GET_NAME "RSPTexture_getMaterialName" +#define RSPTEXTURE_FUNCNAME_GET_OPACITY "RSPTexture_getMaterialOpacity" +#define RSPTEXTURE_FUNCNAME_GET_AMBIENT "RSPTexture_getMaterialAmbient" +#define RSPTEXTURE_FUNCNAME_FREE_HMT "RSPTexture_freeHMT" + +/* External libraries functions signatures */ +typedef char* (*__RSPTexture_getVersion)(void); +typedef void* (*__RSPTexture_createHMT)(void); +typedef unsigned short (*__RSPTexture_processHMTFile)( + void* hmtStruct, + const char* const filePath, + const unsigned char params + ); +typedef void* (*__RSPTexture_getMaterialFromID)( + const void* hmtStruct, + const unsigned short mat_id + ); +typedef char* (*__RSPTexture_getMaterialName)(const void* material); +typedef float (*__RSPTexture_getMaterialOpacity)(const void* material); +typedef float (*__RSPTexture_getMaterialAmbient)(const void* material); +typedef void (*__RSPTexture_freeHMT)(void* hmtStruct); + + +/* External libraries proxies functions */ +extern __RSPTexture_getVersion RSPTexture_getVersion; +extern __RSPTexture_createHMT RSPTexture_createHMT; +extern __RSPTexture_processHMTFile RSPTexture_processHMTFile; +extern __RSPTexture_getMaterialFromID RSPTexture_getMaterialFromID; +extern __RSPTexture_getMaterialName RSPTexture_getMaterialName; +extern __RSPTexture_getMaterialOpacity RSPTexture_getMaterialOpacity; +extern __RSPTexture_getMaterialAmbient RSPTexture_getMaterialAmbient; +extern __RSPTexture_freeHMT RSPTexture_freeHMT; + + +/* Linker functions declarations */ +void* linkTextureLib(T_PROG_OPTIONS* opt_ptr); +void unlinkTextureLib(void); + + +#endif /* RSEMODEL_LIB_INTERFACE_H_ */ diff --git a/RSEModel/src/model_export.c b/RSEModel/src/model_export.c index d789fee..62f3e7f 100644 --- a/RSEModel/src/model_export.c +++ b/RSEModel/src/model_export.c @@ -14,18 +14,21 @@ #include #include #include "obj/obj.h" +#include "lib_interface.h" #include "model_export.h" -unsigned char exportOBJModel(T_RSPMODEL_OBJECT* hob_objects, const char *out_path, T_PROG_OPTIONS* p_opts) { +unsigned char exportOBJModel(T_RSPMODEL_OBJECT* hob_objects, const char *out_path, void* hmt_struct, T_PROG_OPTIONS* p_opts) { char export_path[1024]; char objExport_name[128]; char mtlExport_name[128]; + char material_name[64]; obj* objConstruct = NULL; - unsigned int i,j; + void* material = NULL; + unsigned int i,j,k,a; + unsigned int poly_count = 0; int surfID = 0, materialID = 0, tmpVertex = 0, tmpIndex = 0; - int indexOffset = 0; // Used to compensate reset of indices between face group - float vertexBuff[3] = {0}, textureBuff[2] = {0}; + float vertexBuff[3] = {0}, textureBuff[2] = {0}, materialAmbient[4] = {0}; int indicesBuff[3] = {0}; if (hob_objects == NULL || out_path == NULL) @@ -41,74 +44,106 @@ unsigned char exportOBJModel(T_RSPMODEL_OBJECT* hob_objects, const char *out_pat objConstruct = obj_create(NULL); - // Build face/surface material group + //TODO: should be deconstructed in sub-functions + // For each objects sub-part, create it's faces and surfaces/materials datas for ( i = 0; i < hob_objects->object_part_count; i++) { - surfID = obj_add_surf(objConstruct); - materialID = obj_add_mtrl(objConstruct); - // Build vertex container - for ( j = 0; j < hob_objects->object_parts[i].vertex_count; j++ ) { - tmpVertex = obj_add_vert(objConstruct); - - vertexBuff[0] = ((float)1/1024) * -hob_objects->object_parts[i].vertices[j].x; // Invert X to fix mirror display - vertexBuff[1] = ((float)1/1024) * -hob_objects->object_parts[i].vertices[j].y; // Invert Y to render upside up - vertexBuff[2] = ((float)1/1024) * hob_objects->object_parts[i].vertices[j].z; - obj_set_vert_v(objConstruct, tmpVertex, vertexBuff); - } - - // Build indices container and UV mapping + // Build faces datas: vertices, indices table, materials and UV mapping for ( j = 0; j < hob_objects->object_parts[i].face_count; j++ ) { - tmpIndex = obj_add_poly(objConstruct, surfID); - indicesBuff[0] = indexOffset + (int)hob_objects->object_parts[i].faces[j].indices[0]; - indicesBuff[1] = indexOffset + (int)hob_objects->object_parts[i].faces[j].indices[1]; - indicesBuff[2] = indexOffset + (int)hob_objects->object_parts[i].faces[j].indices[2]; - obj_set_poly(objConstruct, surfID, tmpIndex, indicesBuff); + // Construct materials list - add new when first loop or mt_index change + if (j == 0 || ( hob_objects->object_parts[i].faces[j].mt_index != hob_objects->object_parts[i].faces[j-1].mt_index )) { + surfID = obj_add_surf(objConstruct); - if (hob_objects->object_parts[i].faces[j].flags_bits.fHasTexture) { - textureBuff[0] = ((float)1/4096) * hob_objects->object_parts[i].faces[j].tex_coords[0].u; - textureBuff[1] = ((float)1/4096) * hob_objects->object_parts[i].faces[j].tex_coords[0].v; - obj_set_vert_t(objConstruct, indexOffset + (int)hob_objects->object_parts[i].faces[j].indices[0], textureBuff); + if (p_opts->texture_module) { + materialID = obj_add_mtrl(objConstruct); - textureBuff[0] = ((float)1/4096) * hob_objects->object_parts[i].faces[j].tex_coords[1].u; - textureBuff[1] = ((float)1/4096) * hob_objects->object_parts[i].faces[j].tex_coords[1].v; - obj_set_vert_t(objConstruct, indexOffset + (int)hob_objects->object_parts[i].faces[j].indices[1], textureBuff); + // Set material properties for face group + material = RSPTexture_getMaterialFromID(hmt_struct, hob_objects->object_parts[i].faces[j].mt_index); + obj_set_mtrl_name(objConstruct, materialID, RSPTexture_getMaterialName(material)); + materialAmbient[0] = RSPTexture_getMaterialOpacity(material); + materialAmbient[1] = materialAmbient[0]; + materialAmbient[2] = materialAmbient[0]; + materialAmbient[3] = materialAmbient[0]; + //obj_set_mtrl_c(objConstruct, materialID, OBJ_KA, materialAmbient); + obj_set_mtrl_c(objConstruct, materialID, OBJ_KD, materialAmbient); + //obj_set_mtrl_c(objConstruct, materialID, OBJ_KS, materialAmbient); - textureBuff[0] = ((float)1/4096) * hob_objects->object_parts[i].faces[j].tex_coords[2].u; - textureBuff[1] = ((float)1/4096) * hob_objects->object_parts[i].faces[j].tex_coords[2].v; - obj_set_vert_t(objConstruct, indexOffset + (int)hob_objects->object_parts[i].faces[j].indices[2], textureBuff); + // Add image file name if textured + if (hob_objects->object_parts[i].faces[j].flags_bits.fHasTexture) { + snprintf(material_name, 64, "%s.png", RSPTexture_getMaterialName(material)); + //obj_set_mtrl_map(objConstruct, materialID, OBJ_KA, material_name); + obj_set_mtrl_map(objConstruct, materialID, OBJ_KD, material_name); + //obj_set_mtrl_map(objConstruct, materialID, OBJ_KS, material_name); + } + + // Link material to surface + obj_set_surf(objConstruct, surfID, materialID); + } } + // Add vertex corresponding to indices + for ( k = 0; k < 3; k++ ) { + tmpVertex = obj_add_vert(objConstruct); + a = hob_objects->object_parts[i].faces[j].indices[k]; + + vertexBuff[0] = ((float)1/1024) * -hob_objects->object_parts[i].vertices[a].x; // Invert X to fix mirror display + vertexBuff[1] = ((float)1/1024) * -hob_objects->object_parts[i].vertices[a].y; // Invert Y to render upside up + vertexBuff[2] = ((float)1/1024) * hob_objects->object_parts[i].vertices[a].z; + obj_set_vert_v(objConstruct, tmpVertex, vertexBuff); + + if (hob_objects->object_parts[i].faces[j].flags_bits.fHasTexture) { + textureBuff[0] = ((float)1/4096) * hob_objects->object_parts[i].faces[j].tex_coords[k].u; + textureBuff[1] = -((float)1/4096) * hob_objects->object_parts[i].faces[j].tex_coords[k].v + 1; + obj_set_vert_t(objConstruct, tmpVertex, textureBuff); + } + } + // Build indices table for this face + tmpIndex = obj_add_poly(objConstruct, surfID); + indicesBuff[0] = 3 * poly_count; + indicesBuff[1] = 3 * poly_count + 1; + indicesBuff[2] = 3 * poly_count + 2; + poly_count++; + obj_set_poly(objConstruct, surfID, tmpIndex, indicesBuff); + // Process 2 triangles if face is Quad if (hob_objects->object_parts[i].faces[j].flags_bits.fIsQuad) { - tmpIndex = obj_add_poly(objConstruct, surfID); + for ( k = 0; k < 3; k++ ) { + tmpVertex = obj_add_vert(objConstruct); + a = hob_objects->object_parts[i].faces[j].indices[(k + 2) & 0x3]; // TODO: can't be written properly? - indicesBuff[0] = indexOffset + (int)hob_objects->object_parts[i].faces[j].indices[0]; - indicesBuff[1] = indexOffset + (int)hob_objects->object_parts[i].faces[j].indices[2]; - indicesBuff[2] = indexOffset + (int)hob_objects->object_parts[i].faces[j].indices[3]; - obj_set_poly(objConstruct, surfID, tmpIndex, indicesBuff); + vertexBuff[0] = ((float)1/1024) * -hob_objects->object_parts[i].vertices[a].x; // Invert X to fix mirror display + vertexBuff[1] = ((float)1/1024) * -hob_objects->object_parts[i].vertices[a].y; // Invert Y to render upside up + vertexBuff[2] = ((float)1/1024) * hob_objects->object_parts[i].vertices[a].z; + obj_set_vert_v(objConstruct, tmpVertex, vertexBuff); - if (hob_objects->object_parts[i].faces[j].flags_bits.fHasTexture) { - textureBuff[0] = ((float)1/4096) * hob_objects->object_parts[i].faces[j].tex_coords[3].u; - textureBuff[1] = ((float)1/4096) * hob_objects->object_parts[i].faces[j].tex_coords[3].v; - obj_set_vert_t(objConstruct, indexOffset + (int)hob_objects->object_parts[i].faces[j].indices[3], textureBuff); + if (hob_objects->object_parts[i].faces[j].flags_bits.fHasTexture) { + textureBuff[0] = ((float)1/4096) * hob_objects->object_parts[i].faces[j].tex_coords[(k + 2) & 0x3].u; + textureBuff[1] = -((float)1/4096) * hob_objects->object_parts[i].faces[j].tex_coords[(k + 2) & 0x3].v + 1; + obj_set_vert_t(objConstruct, tmpVertex, textureBuff); + } } + // Build indices table for this face + tmpIndex = obj_add_poly(objConstruct, surfID); + indicesBuff[0] = 3 * poly_count; + indicesBuff[1] = 3 * poly_count + 1; + indicesBuff[2] = 3 * poly_count + 2; + poly_count++; + obj_set_poly(objConstruct, surfID, tmpIndex, indicesBuff); } } - - indexOffset = obj_num_vert(objConstruct); } if (p_opts->export_mtl) { if (p_opts->output_dir) - obj_write(objConstruct, objExport_name, mtlExport_name, export_path, 8); + obj_write(objConstruct, objExport_name, mtlExport_name, export_path, 6); else - obj_write(objConstruct, objExport_name, mtlExport_name, NULL, 8); + obj_write(objConstruct, objExport_name, mtlExport_name, NULL, 6); } else { if (p_opts->output_dir) - obj_write(objConstruct, objExport_name, NULL, export_path, 8); + obj_write(objConstruct, objExport_name, NULL, export_path, 6); else - obj_write(objConstruct, objExport_name, NULL, NULL, 8); + obj_write(objConstruct, objExport_name, NULL, NULL, 6); } obj_delete(objConstruct); diff --git a/RSEModel/src/model_export.h b/RSEModel/src/model_export.h index 82b5dba..1c9a27c 100644 --- a/RSEModel/src/model_export.h +++ b/RSEModel/src/model_export.h @@ -10,13 +10,6 @@ #ifndef MODEL_EXPORT_H_ #define MODEL_EXPORT_H_ - -typedef struct t_material { - unsigned short hasTexture; - unsigned short bpp; - unsigned int gl_tex_id; -} T_MATERIAL; - -unsigned char exportOBJModel(T_RSPMODEL_OBJECT* hob_objects, const char *out_path, T_PROG_OPTIONS* p_opts); +unsigned char exportOBJModel(T_RSPMODEL_OBJECT* hob_objects, const char *out_path, void* hmt_struct, T_PROG_OPTIONS* p_opts); #endif /* MODEL_EXPORT_H_ */ diff --git a/RSEModel/src/options.h b/RSEModel/src/options.h index 89ad7a6..2f33436 100644 --- a/RSEModel/src/options.h +++ b/RSEModel/src/options.h @@ -17,10 +17,12 @@ typedef union u_prog_options { 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 texture_module:1; //!< Set if RSPTextureLib module is present and loaded. + unsigned char output_dir:1; //!< Export extracted datas to a sub-directory. unsigned char export_mtl:1; //!< Export materials datas with object. - unsigned short reserved0:11; //!< For future use. + unsigned short reserved0:10; //!< For future use. unsigned short input_files_cnt; //!< Internal files counters. }; diff --git a/RSPModelLib/include/RSPModel_datatypes.h b/RSPModelLib/include/RSPModel_datatypes.h index 67d707b..388d900 100644 --- a/RSPModelLib/include/RSPModel_datatypes.h +++ b/RSPModelLib/include/RSPModel_datatypes.h @@ -51,7 +51,7 @@ typedef struct vertex { short x,y,z,w; } T_VERTEX; #endif #ifndef T_TEXCOORD -typedef struct tex_coord { unsigned short u,v; } T_TEXCOORD; +typedef struct tex_coord { short u,v; } T_TEXCOORD; #endif typedef struct face_flags { diff --git a/RSPModelLib/src/hob_parser.c b/RSPModelLib/src/hob_parser.c index 0fe2b2c..6c9d809 100644 --- a/RSPModelLib/src/hob_parser.c +++ b/RSPModelLib/src/hob_parser.c @@ -152,6 +152,10 @@ static unsigned short ExtractObjects(T_RSPMODEL_HOB* pHobStruct, const MEMFILE p + pHobStruct->objects[i].object_part_header_offset))->facegroup_count; if (pParams->verbose_mode) printf("[DBG] > Face groups count: %d\n", pHobStruct->objects[i].face_group_count); //TODO: Caution with obj/facegrp count difference. What is facegroup count??? + /* + * Seem "object" are independant structure like xwing, turret, etc. + * Facegroup is more like part of previous object, like wing-left, turret-barrel, etc. + */ if (pHobStruct->objects[i].object_part_count != pHobStruct->objects[i].face_group_count && (pParams->verbose_mode)) printf("[DBG] > Object parts / facegroup count are different!\n"); @@ -210,6 +214,7 @@ static unsigned short ExtractObjParts(T_RSPMODEL_OBJECT* pObject, const MEMFILE + pObject->object_parts[i].meshdef1_offset - 4))->facedef_end_offset; pObject->object_parts[i].vertex_count = ((T_HOBFILE_MESHDEF1 *)(pMemfile + pObject->object_parts[i].meshdef1_offset - 4))->vertex_count; + if (pParams->verbose_mode) printf("[DBG] > Vertex count: %d\n", pObject->object_parts[i].vertex_count); pObject->object_parts[i].face_block_offset = ((T_HOBFILE_MESHDEF1 *)(pMemfile + pObject->object_parts[i].meshdef1_offset - 4))->faceblock_offset; if (pParams->verbose_mode) printf("[DBG] > Faces offset: 0x%X\n", pObject->object_parts[i].face_block_offset); @@ -269,7 +274,7 @@ static unsigned short ExtractObjParts_faces(T_RSPMODEL_OBJ_PARTS* pObjPart, cons pObjPart->face_count = ((T_HOBFILE_FACEBLOCK *)(pMemfile + pObjPart->face_block_offset))->faceCounts; pObjPart->faces = calloc(pObjPart->face_count, sizeof(T_RSPMODEL_FACE)); for ( i = 0; i < pObjPart->face_count; i++ ) { - if (pParams->debug_mode) printf("\n----------------------Begin of FaceGroup part----------------------\n"); + if (pParams->debug_mode) printf("\n----------------------Begin of Face part----------------------\n"); // Get flags pObjPart->faces[i].flags = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset @@ -355,7 +360,7 @@ static unsigned short ExtractObjParts_faces(T_RSPMODEL_OBJ_PARTS* pObjPart, cons printf("\n"); } - if (pParams->debug_mode) printf("\n-----------------------End of FaceGroup part-----------------------\n"); + if (pParams->debug_mode) printf("\n-----------------------End of Face part-----------------------\n"); } // Get vertex datas diff --git a/RSPModelLib/src/hob_struct.h b/RSPModelLib/src/hob_struct.h index f90e5f6..c477b64 100644 --- a/RSPModelLib/src/hob_struct.h +++ b/RSPModelLib/src/hob_struct.h @@ -33,6 +33,17 @@ #pragma pack(push, 1) #endif +/* + * - Global HOB file structure- + * +------------------+--------------------------------------+----------------------------------------+ + * | T_HOBFILE_HEADER | obj_count * T_HOBFILE_OBJ_DESCRIPTOR | obj_count * T_HOBFILE_FACEGROUP_HEADER | + * +------------------+--------------------------------------+----------------------------------------+ + * + * - Facegroup sub-structure - + * +----------------------------+------------------------------------------------+ + * | T_HOBFILE_FACEGROUP_HEADER | object_part_count * T_HOBFILE_FACEGROUP_OFFSET | + * +----------------------------+------------------------------------------------+ + */ typedef struct PACK hobfile_header { unsigned int obj_count; unsigned int vertices_offset; @@ -169,7 +180,7 @@ typedef struct PACK hobfile_faceblock { typedef struct PACK hobfile_faces_header { unsigned int flags; - unsigned char b1; + unsigned char b1; // 74 = transparent / 75 = opaque unsigned char b2; unsigned char b3; unsigned char faceBlockIntSize; // Bytes size divided by 4, count as number of UInt32 type. diff --git a/RSPModelLib/src/hob_struct2.h b/RSPModelLib/src/hob_struct2.h new file mode 100644 index 0000000..80e2118 --- /dev/null +++ b/RSPModelLib/src/hob_struct2.h @@ -0,0 +1,246 @@ +/** + * @file hob_struct.h + * @date 26/07/2022 + * @author JackCarterSmith + * @copyright GPL-v3.0 + * @brief HOB file mapping definition. + * + */ + +#ifndef RSPMODELLIB_HOB_STRUCT_H_ +#define RSPMODELLIB_HOB_STRUCT_H_ + + +/* + * long = 64bits??? + * int = 32bits + * short = 16bits + * car = 8bits + */ + +#if defined(_MSC_VER) +#define PACK +#elif defined(__GNUC__) +#define PACK __attribute__((packed)) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Declaration of Memory Mapped Structure +// Caution: the place of variable is important for correct mapping! +/////////////////////////////////////////////////////////////////////////////// + +#if defined(_MSC_VER) +#pragma pack(push, 1) +#endif + +/* + * - Global HOB file structure- + * +------------------+--------------------------------------+----------------------------------------+ + * | T_HOBFILE_HEADER | obj_count * T_HOBFILE_OBJ_DESCRIPTOR | obj_count * T_HOBFILE_FACEGROUP_HEADER | --> + * +------------------+--------------------------------------+----------------------------------------+ + * + * - Facegroup sub-structure - + * +------------------------------+--------------------------------------------------+ + * --> | T_HOBFILE_FACEGROUP_HEADER_1 | object_part_count * T_HOBFILE_FACEGROUP_OFFSET_1 | + * +------------------------------+--------------------------------------------------+ + * + * - Facegroup sub-structure 2 - + * +------------------------------+------------------------------------------------------------------------+--------------------------------------------------------+ + * | T_HOBFILE_FACEGROUP_HEADER_2 | ( object_part_count + facegroup_count ) * T_HOBFILE_FACEGROUP_OFFSET_2 | ( object_part_count - 1 ) * T_HOBFILE_FACEGROUP_NAMEID | + padding + * +------------------------------+------------------------------------------------------------------------+--------------------------------------------------------+ + */ +typedef struct PACK hobfile_header { + unsigned int obj_count; + unsigned int vertices_offset; +} T_HOBFILE_HEADER; + +typedef struct PACK hobfile_obj_header { + unsigned char object_name[16]; // Name of the object + + unsigned int facegroup_start_offset; // First facegroup datas offset. Look in T_HOBFILE_FACEGROUP_HEADER for all offsets of facegroups of the current object. + unsigned int object_parts_offset; // Object parts descriptor offset + unsigned int object_parts_offset2; // Facegroup descriptor offset (subpart of Object parts descriptor) + + unsigned int opt_offset1; // Optional offset - empty on last obj_header - point to after end mask ffffff of current bloc + unsigned int opt_offset2; // Optional offset - empty on last obj_header - point to after the previous opt_offset1 + unsigned int reserved1; // Always zeros ? + + unsigned int subparts_namelist_offset; // Point to an array of string value (8 chars) + ID (2 chars - 1 to obj_parts-1). Seem like name of articulation points (some have name like "node_86"). + unsigned int effects_offset; // Empty in gun_turret and no datas after, xwing have 0x5006. worddevastator should have the answer... + unsigned int properties_offset; // Offset to different string (a_b/zf/zt/zb/etc.) Animation datas ? Empty with 6x float in train_hob + + float unknown4; // Probably scale: 1.0F/1.125F + + unsigned int reserved4; // 12B of zeros + unsigned int reserved5; + unsigned int reserved6; + + float unknown5; //Scale? ~20.0F + float unknown6; //Scale? ~77-418.0F + + float reserved7; //Translation matrix? Center of object? + float reserved8; + float reserved9; + + unsigned int footer_offset; //To redefine, seem to be a copy of following bounding box? Maybe there are 2 box: render and collision? + + float bbox_start_x; // Bounding box start vector + float bbox_start_y; + float bbox_start_z; + + float bbox_end_x; // Bounding box start vector + float bbox_end_y; + float bbox_end_z; +} T_HOBFILE_OBJ_HEADER; + +typedef struct PACK hobfile_facegroup_header_1 { + unsigned short object_part_count; + unsigned short facegroup_count; +} T_HOBFILE_FACEGROUP_HEADER_1; + +typedef struct PACK hobfile_facegroup_offset_1 { + unsigned int unknown0; // Flags? + unsigned int facegroup_offset; +} T_HOBFILE_FACEGROUP_OFFSET_1; + +typedef struct PACK hobfile_facegroup_header_2 { + unsigned short object_part_count; + unsigned short facegroup_count; +} T_HOBFILE_FACEGROUP_HEADER_2; + +typedef struct PACK hobfile_facegroup_offset_2 { + unsigned int unknownOffset0; +} T_HOBFILE_FACEGROUP_OFFSET_2; + +typedef struct PACK hobfile_facegroup_nameid { + unsigned char name[8]; + unsigned short id; +} T_HOBFILE_FACEGROUP_NAMEID; + +typedef struct PACK hobfile_meshdef0 { + unsigned int offset1; + unsigned int offset2; + unsigned int prev_meshdef0_offset; + unsigned int next_meshdef0_offset; + unsigned int meshdef1_offset_plus_4; + + unsigned int reserved1; // 8B of zeros + unsigned int reserved2; + + float unknown3; + + unsigned int reserved3; // 12B of zeros + unsigned int reserved4; + unsigned int reserved5; + + float unknown4; + + unsigned int reserved6; // 12B of zeros + unsigned int reserved7; + unsigned int reserved8; + + float unknown5; + + unsigned int reserved9; // 12B of zeros + unsigned int reserved10; + unsigned int reserved11; + + unsigned int object_id; + + float unknown12; // Can be a vector??? + float unknown13; + float unknown14; + + float unknown15; // Can be a vector??? + float unknown16; + float unknown17; + + float unknown18; // Can be a matrix??? + float unknown19; + float unknown20; + float unknown21; + + float transform_x; + float transform_y; + float transform_z; +} T_HOBFILE_MESHDEF0; + +typedef struct PACK hobfile_meshdef1 { + unsigned int facedef_end_offset; + + unsigned int reserved1; // 20B of zeros + unsigned int reserved2; + unsigned int reserved3; + unsigned int reserved4; + unsigned int reserved5; + + unsigned int vertex_count; + unsigned int unknown1; + unsigned int reserved6; + unsigned int faceblock_offset; + unsigned int vertexblocks_offset; + + unsigned int reserved7; // 52B of zeros + unsigned int reserved8; + unsigned int reserved9; + unsigned int reserved10; + unsigned int reserved11; + unsigned int reserved12; + unsigned int reserved13; + unsigned int reserved14; + unsigned int reserved15; + unsigned int reserved16; + unsigned int reserved17; + unsigned int reserved18; + unsigned int reserved19; +} T_HOBFILE_MESHDEF1; + +typedef struct PACK hobfile_faceblock { + unsigned int reserved1; // 8B of zeros + unsigned int reserved2; + + unsigned int facesOffset; + unsigned int faceCounts; +} T_HOBFILE_FACEBLOCK; + +typedef struct PACK hobfile_faces_header { + unsigned int flags; + unsigned char b1; // 74 = transparent / 75 = opaque + unsigned char b2; + unsigned char b3; + unsigned char faceBlockIntSize; // Bytes size divided by 4, count as number of UInt32 type. + unsigned short headerSeparator; + unsigned short materialIndex; + unsigned short vertexIndices[4]; // Relative to facegroup, the last value is equal to 0 when it's triangle shape. +} T_HOBFILE_FACES_HEADER; + +typedef struct PACK hobfile_faces_extra_vertex_color { + T_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 PACK hobfile_faces_extra_color { + T_RGBA rgba; +} T_HOBFILE_FACES_COLOR; + +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 PACK hobfile_vertex { + short x; + short y; + short z; + short w; +} T_HOBFILE_VERTEX; + +#if defined(_MSC_VER) +#pragma pack(pop) +#endif + +#endif /* RSPMODELLIB_HOB_STRUCT_H_ */