Compare commits

...

10 Commits

Author SHA1 Message Date
7114278842
Conan asspain
All checks were successful
JCS-Prod/RSE-Model/pipeline/head This commit looks good
2025-02-01 16:09:06 +01:00
1dbe69cd8b
Final work on Conan v2 support
All checks were successful
JCS-Prod/RSE-Model/pipeline/pr-master This commit looks good
JCS-Prod/RSE-Model/pipeline/head This commit looks good
2024-09-22 15:11:49 +02:00
1dbe9df091
Checked transform types
Obj exporter include divide by 1024 (10bits rsh), keep this value in mind during parsing
2024-05-19 10:26:02 +02:00
88c90b39bb
Find new transform elements 2024-05-19 10:26:00 +02:00
023c63617d
Validated conan v2 migration
Some checks failed
JCS-Prod/RSE-Model/pipeline/head There was a failure building this commit
2024-05-19 10:23:14 +02:00
9e551619a1
Refactor parser with cleaned code
All checks were successful
JCS-Prod/RSE-Model/pipeline/pr-master This commit looks good
JCS-Prod/RSE-Model/pipeline/head This commit looks good
Finally made separation btw obj_parts and face_groups
2023-02-23 19:18:53 +01:00
1deb5eae2c
Upgrade HOB struct with new uncovered fields 2023-02-21 19:30:24 +01:00
ec82ff4158
More details on hob struct 2023-02-20 22:25:57 +01:00
3307cfaab7
Change face parsing counter 2023-02-16 16:59:55 +01:00
3614742343
Convert bytes flag to hex for better reading 2023-02-13 18:04:18 +01:00
14 changed files with 726 additions and 598 deletions

1
.gitignore vendored
View File

@ -75,3 +75,4 @@ install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps
CMakeUserPresets.json

View File

@ -7,8 +7,8 @@
# CMake requirement and general configuration
cmake_minimum_required(VERSION 3.12)
cmake_policy(VERSION 3.12)
cmake_minimum_required(VERSION 3.15)
cmake_policy(VERSION 3.15)
set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
if(DEFINED ENV{MS_COMPATIBLE})
set(CMAKE_GNUtoMS ON) # Enable compatibility level to exported libraries
@ -20,11 +20,10 @@ 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.3.0 DESCRIPTION "RogueSquadron Extractor - Model" LANGUAGES C)
project(rse-model VERSION 2.4.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})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries")

15
Jenkinsfile vendored
View File

@ -5,14 +5,13 @@ pipeline {
}
environment {
CI_OUTPUT_NAME = "RSEModel"
CI_VERSION = "2.3.0"
CI_VERSION = "2.3.1"
CI_BUILD_NUMBER = "$BUILD_NUMBER"
}
stages {
stage('Prepare') {
steps {
cleanWs()
rtConanClient(id: "conan", userHome: "/home/jackcartersmith")
}
}
stage('Build') {
@ -22,20 +21,16 @@ pipeline {
dir("linux") {
checkout([$class: 'GitSCM', branches: [[name: '**']], browser: [$class: 'GiteaBrowser', repoUrl: 'https://git.jcsmith.fr/JCS-Prod/RSE-Model'], extensions: [], userRemoteConfigs: [[credentialsId: 'jenkins-ssh', url: 'ssh://git@git.jcsmith.fr:2322/JCS-Prod/RSE-Model.git']]])
sh 'git submodule update --init --recursive'
dir("build") {
rtConanRun(clientId: "conan", command: "install .. -pr:b=default -pr:h=default --build=missing")
}
cmakeBuild buildDir: 'build', installation: 'latest', steps: [[args: 'all']]
sh 'conan install . -of build -s build_type=Release -o "&:tools=True" -pr:b=default -pr:h=default --build=missing'
cmakeBuild buildDir: 'build', cmakeArgs: '-DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DRSPMODEL_SHARED=ON -DRSPMODEL_STATIC=OFF -DBUILD_TOOLS=ON -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_BUILD_TYPE=Release', installation: 'latest', steps: [[args: 'all']]
}
},
windows: {
dir("windows") {
checkout([$class: 'GitSCM', branches: [[name: '**']], browser: [$class: 'GiteaBrowser', repoUrl: 'https://git.jcsmith.fr/JCS-Prod/RSE-Model'], extensions: [], userRemoteConfigs: [[credentialsId: 'jenkins-ssh', url: 'ssh://git@git.jcsmith.fr:2322/JCS-Prod/RSE-Model.git']]])
sh 'git submodule update --init --recursive'
dir("build") {
rtConanRun(clientId: "conan", command: "install .. -pr:b=default -pr:h=windows --build=missing")
}
cmakeBuild buildDir: 'build', cmakeArgs: '-DGNU_HOST=x86_64-w64-mingw32 -DCMAKE_TOOLCHAIN_FILE=../cmake/mingw_cross_toolchain.cmake', installation: 'latest', steps: [[args: 'all']]
sh 'conan install . -of build -s build_type=Release -o "&:tools=True" -pr:b=default -pr:h=windows --build=missing'
cmakeBuild buildDir: 'build', cmakeArgs: '-DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DRSPMODEL_SHARED=ON -DRSPMODEL_STATIC=OFF -DBUILD_TOOLS=ON -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc -DCMAKE_RC_COMPILER=x86_64-w64-mingw32-windres', installation: 'latest', steps: [[args: 'all']]
}
}
)

View File

@ -46,22 +46,12 @@ Due to issues with copyrights, I can't provide samples and my DAT file parser is
### Compiling
You can compile on both Windows (MinGW/MSVC) or native Linux system thanks to CMake.
To compile, just clone (**don't forget git submodules**) and launch cmake:
I've a preference for compiling libraries by hand, mainly for backward compatibility, but I recommend using Conan packages manager (https://conan.io) for simplicity. (**Don't forget git submodules**)
```shell
cmake .
make
make install
conan install . -of build -b missing -s build_type=Release -o tools=True -pr:b=default -pr:h=default
cmake --preset conan-release -G "Unix Makefiles"
cmake --build --preset conan-release
```
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 .
```
On Windows environment, you can use MinGW `-G "MinGW Makefiles"` or Ninja `-G "Ninja"` as CMake generator.

View File

@ -46,11 +46,13 @@ if(BUILD_TOOLS)
endif()
# Link externals libraries to the linker
if (TARGET GLEW::GLEW)
if(RSPMODEL_SHARED)
#target_link_libraries(rse-model PRIVATE rsp-model-lib ${GLEW_LIBRARIES} ${Vulkan_LIBRARIES} ${AUX_LIBS})
target_link_libraries(rse-model PRIVATE rsp-model-lib ${GLEW_LIBRARIES} ${AUX_LIBS})
target_link_libraries(rse-model PRIVATE rsp-model-lib GLEW::GLEW ${AUX_LIBS})
elseif(RSPMODEL_STATIC)
#target_link_libraries(rse-model PRIVATE rsp-model-libstatic ${GLEW_LIBRARIES} ${Vulkan_LIBRARIES} ${AUX_LIBS})
target_link_libraries(rse-model PRIVATE rsp-model-libstatic ${GLEW_LIBRARIES} ${AUX_LIBS})
target_link_libraries(rse-model PRIVATE rsp-model-libstatic GLEW::GLEW ${AUX_LIBS})
endif()
endif()
endif()

View File

@ -104,7 +104,7 @@ static unsigned int mainProcess(int args_cnt, char* args_value[], T_PROG_OPTIONS
}
// If Texture module loaded, process HMT file for mtl naming (doesn't extract texture!)
if (p_opts->texture_module) {
if (p_opts->texture_module && p_opts->export_mtl) {
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);

View File

@ -1,6 +1,6 @@
/**
* @file RSPModel_datatypes.h
* @date 11/08/2022
* @date 21/02/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief RSP Model workflow structures definitions
@ -46,20 +46,24 @@ typedef struct rspmodel_vertex { short x,y,z,w; } T_RSPMODEL_VERTEX;
typedef struct rspmodel_texcoord { short u,v; } T_RSPMODEL_TEXCOORD;
typedef struct rspmodel_bbox { T_RSPMODEL_VECTOR3 start,end; } T_RSPMODEL_BBOX;
typedef struct face_flags {
unsigned int fUnknown0:1;
unsigned int fUnknown1:1;
unsigned int fUnused0:1; //TODO: Parse all HOB to find anyone with this field different of 0
unsigned int fUnused1:1; //TODO: Parse all HOB to find anyone with this field different of 0
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 fNoCulled:1; // Face with this flag always be rendered without culling, usefull to render "flat" object
unsigned int fUnknown8:1;
unsigned int fUnknown9:1;
unsigned int fUnknown10:1;
unsigned int reserved:21;
unsigned int fReserved:21;
} FACE_FLAGS;
typedef struct hob_face {
@ -78,6 +82,7 @@ typedef struct hob_face {
} T_RSPMODEL_FACE;
typedef struct rspmodel_obj_parts {
unsigned int meshdef0_offset;
unsigned int meshdef1_offset;
unsigned int face_block_end_offset;
@ -85,7 +90,10 @@ typedef struct rspmodel_obj_parts {
unsigned int vertex_block_offset;
unsigned int id;
T_RSPMODEL_VECTOR3 transform;
T_RSPMODEL_VECTOR3 offset_transform;
T_RSPMODEL_VECTOR3 scale_transform;
T_RSPMODEL_VECTOR3 rotate_transform;
T_RSPMODEL_VECTOR3 translate_transform;
unsigned int face_count;
T_RSPMODEL_FACE* faces;
@ -97,8 +105,16 @@ typedef struct rspmodel_obj_parts {
typedef struct rspmodel_object {
char name[16];
unsigned int face_group_offset;
unsigned int object_part_header_offset;
unsigned int face_group_header_offset;
unsigned int object_parts_header_offset;
unsigned int object_parts_header_offset2;
unsigned int object_parts_header2_offset;
unsigned int object_parts_header2_offset2;
unsigned int object_subparts_names_offset;
unsigned int effects_offset;
unsigned int properties_offset2;
T_RSPMODEL_BBOX bounding_box;
unsigned int object_part_count;
unsigned int face_group_count;

View File

@ -1,6 +1,6 @@
/**
* @file hob_parser.c
* @date 18/01/2023
* @date 21/02/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Process HOB file structure and extract its datas.
@ -12,8 +12,8 @@
#include <string.h>
#include "RSPModel_errordefs.h"
#include "RSPModel_datatypes.h"
#include "hob_struct.h"
#include "hob_parser.h"
#include "hob_struct.h"
////////////////////////////////////////////////////////////////////////////////
@ -21,8 +21,15 @@
////////////////////////////////////////////////////////////////////////////////
static unsigned short ExtractObjects(T_RSPMODEL_HOB*, const MEMFILE, const RSPMODEL_PARAMETERS*);
static unsigned short ExtractObjParts(T_RSPMODEL_OBJECT*, const MEMFILE, const RSPMODEL_PARAMETERS*);
static unsigned short ExtractObjParts_faces(T_RSPMODEL_OBJ_PARTS*, const MEMFILE, const RSPMODEL_PARAMETERS*);
static unsigned short ParseObjectHeader(T_RSPMODEL_OBJECT*, const MEMFILE, const unsigned char, const RSPMODEL_PARAMETERS*);
static unsigned short ParseObjectPartsHeaders(T_RSPMODEL_OBJECT*, const MEMFILE, const RSPMODEL_PARAMETERS*);
static unsigned short ParseObjectPartHeader(T_RSPMODEL_OBJ_PARTS*, const MEMFILE, const int, const unsigned char, const RSPMODEL_PARAMETERS*);
static unsigned short ParseObjectMeshDef(T_RSPMODEL_OBJ_PARTS*, const MEMFILE, const RSPMODEL_PARAMETERS*);
static unsigned short ParseObjectFaceblockHeader(T_RSPMODEL_OBJ_PARTS*, const MEMFILE, const RSPMODEL_PARAMETERS*);
static unsigned short ParseObjectFace(T_RSPMODEL_FACE*, const MEMFILE, unsigned int* const, const unsigned int, const RSPMODEL_PARAMETERS*);
static unsigned short ParseObjectFaceVertices(T_RSPMODEL_VERTEX*, const MEMFILE, const unsigned int, const unsigned int, const RSPMODEL_PARAMETERS*);
static unsigned short ExtractObjpart_Face_Colors(T_RSPMODEL_FACE*, const char*);
static unsigned short ExtractObjpart_Face_UVMaps(T_RSPMODEL_FACE*, const char*);
@ -102,7 +109,8 @@ unsigned short RSP_ModelLib_FreeHOBFile(const MEMFILE* memFile) {
* @return Error code, RSPLIB_SUCCESS when no error.
*/
static unsigned short ExtractObjects(T_RSPMODEL_HOB* pHobStruct, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) {
unsigned int i;
unsigned int i, j, k;
unsigned int faceExtraOffset = 0;
if (pHobStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL;
@ -119,272 +127,450 @@ static unsigned short ExtractObjects(T_RSPMODEL_HOB* pHobStruct, const MEMFILE p
if (pHobStruct->objects == NULL) return RSPLIB_ERROR_MEMORY;
for ( i = 0; i < pHobStruct->obj_count; i++ ) {
if (pParams->debug_mode) printf("\n-=====================-Begin of Object part-======================-\n");
if (pParams->debug_mode) printf("\n-=======================- Begin of Object -=======================-\n");
// Get object name
memcpy(pHobStruct->objects[i].name, ((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER)
+ sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->object_name, 16);
// Parse object headers
ParseObjectHeader(&pHobStruct->objects[i], pMemfile, i, pParams);
if (pParams->verbose_mode) printf("\n[INFO] - Process %s object...\n", pHobStruct->objects[i].name);
// Extract object parts
ParseObjectPartsHeaders(&pHobStruct->objects[i], pMemfile, pParams);
pHobStruct->objects[i].object_parts = calloc(pHobStruct->objects[i].object_part_count, sizeof(T_RSPMODEL_OBJ_PARTS));
if (pHobStruct->objects[i].object_parts == NULL) return RSPLIB_ERROR_MEMORY;
// Get offsets
pHobStruct->objects[i].face_group_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER)
+ sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->facegroup_offset;
if (pParams->verbose_mode) printf("[DBG] > Face group offset: 0x%X\n", pHobStruct->objects[i].face_group_offset);
pHobStruct->objects[i].object_part_header_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER)
+ sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->object_parts_offset;
if (pParams->verbose_mode) printf("[DBG] > Face group header/object parts offset: 0x%X\n", pHobStruct->objects[i].object_part_header_offset);
pHobStruct->objects[i].face_group_header_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER)
+ sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->facegroup_header_2_offset;
if (pParams->verbose_mode) printf("[DBG] > Face group header2 offset: 0x%X\n", pHobStruct->objects[i].face_group_header_offset);
for ( j = 0; j < pHobStruct->objects[i].object_part_count; j++ ) {
if (pParams->debug_mode) printf("\n-~~~~~~~~~~~~~~~~~~~~~- Begin of obj. part -~~~~~~~~~~~~~~~~~~~~~~-\n");
if (pParams->god_mode) {
printf("[DBG] > Face group unknown1: %d\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknownOffset1);
printf("[DBG] > Face group unknown2: %d\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknownOffset2);
printf("[DBG] > Face group unknown3: %d\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknownOffset3);
printf("[DBG] > Face group unknown4: %.8f\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknown4);
}
// Parse object parts headers
ParseObjectPartHeader(&pHobStruct->objects[i].object_parts[j], pMemfile, pHobStruct->objects[i].object_parts_header_offset, j, pParams);
// Get count and offsets from the facegroup header
pHobStruct->objects[i].object_part_count = ((T_HOBFILE_FACEGROUP_HEADER *)(pMemfile
+ pHobStruct->objects[i].object_part_header_offset))->object_part_count;
if (pParams->verbose_mode) printf("[DBG] > Object parts count: %d\n", pHobStruct->objects[i].object_part_count);
pHobStruct->objects[i].face_group_count = ((T_HOBFILE_FACEGROUP_HEADER *)(pMemfile
+ pHobStruct->objects[i].object_part_header_offset))->facegroup_count;
if (pParams->verbose_mode) printf("[DBG] > Face groups count: %d\n", pHobStruct->objects[i].face_group_count);
//TODO: Caution with obj/facegrp count difference. What is facegroup count???
/*
* Seem "object" are independant structure like xwing, turret, etc.
* Facegroup is more like part of previous object, like wing-left, turret-barrel, etc.
*/
if (pHobStruct->objects[i].object_part_count != pHobStruct->objects[i].face_group_count)
if (pParams->verbose_mode) printf("[DBG] > Object parts / facegroup count are different!\n");
// Parse object meshdef
ParseObjectMeshDef(&pHobStruct->objects[i].object_parts[j], pMemfile, pParams);
// Get facegroup datas
ExtractObjParts(&pHobStruct->objects[i], pMemfile, pParams);
}
if (pHobStruct->objects[i].object_parts[j].meshdef1_offset) {
if (pParams->debug_mode) printf("\n------------------------- Begin of Mesh -------------------------\n");
return RSPLIB_SUCCESS;
}
// Extract object faces header datas
ParseObjectFaceblockHeader(&pHobStruct->objects[i].object_parts[j], pMemfile, pParams);
/**
* @brief Count object's sub-part and extract datas from them.
*
* @param[in|out] pObject Take object structure to get the T_RSPMODEL_OBJ_PARTS buffer and object datas.
* @param[in] pMemfile Pointer to an in-memory file location.
* @param[in] pParams Program option, used to tune parser features.
*
* @return Error code, RSPLIB_SUCCESS when no error.
*/
static unsigned short ExtractObjParts(T_RSPMODEL_OBJECT* pObject, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) {
unsigned int i, subpart_offset = 0;
pHobStruct->objects[i].object_parts[j].faces = calloc(pHobStruct->objects[i].object_parts[j].face_count, sizeof(T_RSPMODEL_FACE));
if (pHobStruct->objects[i].object_parts[j].faces == NULL) return RSPLIB_ERROR_MEMORY;
if (pObject == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL;
faceExtraOffset = pHobStruct->objects[i].object_parts[j].face_block_offset + sizeof(T_HOBFILE_FACEBLOCK);
for ( k = 0; k < pHobStruct->objects[i].object_parts[j].face_count; k++ ) {
if (pParams->debug_mode) printf("\n-......................- Begin of Face -.....................-\n");
pObject->object_parts = calloc(pObject->object_part_count, sizeof(T_RSPMODEL_OBJ_PARTS));
if (pObject->object_parts == NULL) return RSPLIB_ERROR_MEMORY;
ParseObjectFace(&pHobStruct->objects[i].object_parts[j].faces[k], pMemfile, &faceExtraOffset, k, pParams);
for ( i = 0; i < pObject->object_part_count; i++ ) {
if (pParams->debug_mode) printf("\n-----------------------Begin of Mesh part-------------------------\n");
subpart_offset = ((T_HOBFILE_FACEGROUP_OFFSET *)(pMemfile + pObject->object_part_header_offset
+ sizeof(T_HOBFILE_FACEGROUP_HEADER) + sizeof(T_HOBFILE_FACEGROUP_OFFSET) * i))->facegroup_offset;
if (pParams->verbose_mode) printf("\n[DBG] > Face group meshdef0 offset: 0x%X\n", subpart_offset);
// Get meshdef0 datas
if (pParams->god_mode) printf("[DBG] > meshdef0 offset1: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->offset1);
if (pParams->god_mode) printf("[DBG] > meshdef0 offset2: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->offset2);
if (pParams->verbose_mode) printf("[DBG] > Prev meshdef0 offset: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->prev_meshdef0_offset);
if (pParams->verbose_mode) printf("[DBG] > Next meshdef0 offset: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->next_meshdef0_offset);
if (pParams->god_mode) printf("[DBG] > meshdef0 unknown3: %.8f\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->unknown3);
if (pParams->god_mode) printf("[DBG] > meshdef0 unknown4: %.8f\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->unknown4);
if (pParams->god_mode) printf("[DBG] > meshdef0 unknown5: %.8f\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->unknown5);
// Get meshdef1 (mesh descriptor) offset
pObject->object_parts[i].meshdef1_offset = ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->meshdef1_offset_plus_4;
if (pParams->verbose_mode) printf("\n[DBG] > Face group meshdef1 offset: 0x%X\n", pObject->object_parts[i].meshdef1_offset);
if( ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->reserved1 != 0 ||
((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->reserved2 != 0 ) {
if (pParams->god_mode) printf("[DBG] > Face group meshdef0: no 0!\n");
}
if (pObject->object_parts[i].meshdef1_offset > 0) {
// Read meshdef1 datas
pObject->object_parts[i].face_block_end_offset = ((T_HOBFILE_MESHDEF1 *)(pMemfile
+ pObject->object_parts[i].meshdef1_offset - 4))->facedef_end_offset;
pObject->object_parts[i].vertex_count = ((T_HOBFILE_MESHDEF1 *)(pMemfile
+ pObject->object_parts[i].meshdef1_offset - 4))->vertex_count;
if (pParams->verbose_mode) printf("[DBG] > Vertex count: %d\n", pObject->object_parts[i].vertex_count);
pObject->object_parts[i].face_block_offset = ((T_HOBFILE_MESHDEF1 *)(pMemfile
+ pObject->object_parts[i].meshdef1_offset - 4))->faceblock_offset;
if (pParams->verbose_mode) printf("[DBG] > Faces offset: 0x%X\n", pObject->object_parts[i].face_block_offset);
pObject->object_parts[i].vertex_block_offset = ((T_HOBFILE_MESHDEF1 *)(pMemfile
+ pObject->object_parts[i].meshdef1_offset - 4))->vertexblocks_offset;
if (pParams->verbose_mode) printf("[DBG] > Vertex offset: 0x%X\n\n", pObject->object_parts[i].vertex_block_offset);
// Get faces datas
ExtractObjParts_faces(&pObject->object_parts[i], pMemfile, pParams);
}
// Get object part ID, used by animation? bones?
pObject->object_parts[i].id = ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->object_id;
if (pParams->verbose_mode) printf("\n[DBG] > Facegroup/object ID: %d\n", pObject->object_parts[i].id);
// Get the transform matrix, used by at-st and at-at (at this time)
pObject->object_parts[i].transform.x = ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->transform_x;
pObject->object_parts[i].transform.y = ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->transform_y;
pObject->object_parts[i].transform.z = ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->transform_z;
if (pParams->god_mode) printf("\n[DBG] > Facegroup/object transform matrix: [%.8f %.8f %.8f]\n",
pObject->object_parts[i].transform.x,
pObject->object_parts[i].transform.y,
pObject->object_parts[i].transform.z
);
if (pParams->debug_mode) printf("\n-----------------------End of Mesh part---------------------------\n");
}
if (pParams->debug_mode) printf("\n-=====================-End of Object part-========================-\n");
return RSPLIB_SUCCESS;
}
/**
* @brief Extract datas from faces from object sub-part.
*
* @param[in|out] pObjPart Take object sub-part structure to get the T_RSPMODEL_FACE buffer and object sub-part datas.
* @param[in] pMemfile Pointer to an in-memory file location.
* @param[in] pParams Program option, used to tune parser features.
*
* @return Error code, RSPLIB_SUCCESS when no error.
*/
static unsigned short ExtractObjParts_faces(T_RSPMODEL_OBJ_PARTS* pObjPart, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) {
unsigned int i, facesExtraOffset = 0;
if (pObjPart == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL;
if( ((T_HOBFILE_FACEBLOCK *)(pMemfile + pObjPart->face_block_offset))->reserved1 != 0 ||
((T_HOBFILE_FACEBLOCK *)(pMemfile + pObjPart->face_block_offset))->reserved2 != 0 ) {
if (pParams->god_mode) printf("[DBG] > Face block: uncommon zero header!\n");
}
if ( ((T_HOBFILE_FACEBLOCK *)(pMemfile + pObjPart->face_block_offset))->facesOffset !=
pObjPart->face_block_offset + sizeof(T_HOBFILE_FACEBLOCK)) {
if (pParams->god_mode) printf("[DBG] > Face block: uncommon face data offset position!\n");
}
pObjPart->face_count = ((T_HOBFILE_FACEBLOCK *)(pMemfile + pObjPart->face_block_offset))->faceCounts;
pObjPart->faces = calloc(pObjPart->face_count, sizeof(T_RSPMODEL_FACE));
for ( i = 0; i < pObjPart->face_count; i++ ) {
if (pParams->debug_mode) printf("\n----------------------Begin of Face part----------------------\n");
// Get flags
pObjPart->faces[i].flags = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->flags;
// Get unknown bytes
pObjPart->faces[i].b1 = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->b1;
pObjPart->faces[i].b2 = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->b2;
pObjPart->faces[i].b3 = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->b3;
pObjPart->faces[i].bsize = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->faceBlockIntSize * 4; // Multiply by 4 to get the bytes exact number
if (((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset + sizeof(T_HOBFILE_FACEBLOCK)
+ sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->headerSeparator != 0) {
if (pParams->god_mode) printf("[DBG] > Face header: uncommon separator!\n");
}
// Get materials index
pObjPart->faces[i].mt_index = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->materialIndex;
// Get vertex indices
memcpy(pObjPart->faces[i].indices, ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->vertexIndices,
sizeof(unsigned short) * 4);
// Recalculate the dynamic extra bytes offset size - if present
if (pObjPart->faces[i].flags_bits.fHasExtraBytesBeforeColor) facesExtraOffset += 8;
// Get vertex color - if present
if (pObjPart->faces[i].flags_bits.fHasColor) {
facesExtraOffset += ExtractObjpart_Face_Colors(&pObjPart->faces[i], pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) + sizeof(T_HOBFILE_FACES_HEADER) * i
+ facesExtraOffset);
}
// Get UV map - if present
if (pObjPart->faces[i].flags_bits.fHasTexture) {
facesExtraOffset += ExtractObjpart_Face_UVMaps(&pObjPart->faces[i], pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) + sizeof(T_HOBFILE_FACES_HEADER) * i
+ facesExtraOffset);
}
if (pParams->debug_mode) {
printf("[DBG] > Face %d details: flags:0x%X b1:%d b2:%d b3%d bsize:%d\n", i, pObjPart->faces[i].flags,
pObjPart->faces[i].b1, pObjPart->faces[i].b2, pObjPart->faces[i].b3, pObjPart->faces[i].bsize);
printf("[DBG] - Type is Quad: %d\n", pObjPart->faces[i].flags_bits.fIsQuad);
printf("[DBG] - Have color: %d\n", pObjPart->faces[i].flags_bits.fHasColor);
printf("[DBG] - Have texture: %d\n", pObjPart->faces[i].flags_bits.fHasTexture);
printf("[DBG] - Material/texture index: %d\n", pObjPart->faces[i].mt_index);
printf("[DBG] - Vertex indices: %d, %d, %d, %d\n", pObjPart->faces[i].indices[0], pObjPart->faces[i].indices[1],
pObjPart->faces[i].indices[2], pObjPart->faces[i].indices[3]);
printf("[DBG] - Vertex colors: 0x%X, 0x%X, 0x%X, 0x%X\n", pObjPart->faces[i].vertex_colors[0],
pObjPart->faces[i].vertex_colors[1], pObjPart->faces[i].vertex_colors[2], pObjPart->faces[i].vertex_colors[3]);
printf("[DBG] - Vertex UV coord (divided by 4096):\n");
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
((double) 1/4096) * pObjPart->faces[i].tex_coords[0].u,
pObjPart->faces[i].tex_coords[0].u,
((double) 1/4096) * pObjPart->faces[i].tex_coords[0].v,
pObjPart->faces[i].tex_coords[0].v
);
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
((double) 1/4096) * pObjPart->faces[i].tex_coords[1].u,
pObjPart->faces[i].tex_coords[1].u,
((double) 1/4096) * pObjPart->faces[i].tex_coords[1].v,
pObjPart->faces[i].tex_coords[1].v
);
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
((double) 1/4096) * pObjPart->faces[i].tex_coords[2].u,
pObjPart->faces[i].tex_coords[2].u,
((double) 1/4096) * pObjPart->faces[i].tex_coords[2].v,
pObjPart->faces[i].tex_coords[2].v
);
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
((double) 1/4096) * pObjPart->faces[i].tex_coords[3].u,
pObjPart->faces[i].tex_coords[3].u,
((double) 1/4096) * pObjPart->faces[i].tex_coords[3].v,
pObjPart->faces[i].tex_coords[3].v
);
printf("\n");
}
if (pParams->debug_mode) printf("\n-----------------------End of Face part-----------------------\n");
if (pParams->debug_mode) printf("\n-.......................- End of Face -......................-\n");
}
// Get vertex datas
pObjPart->vertices = calloc(pObjPart->vertex_count, sizeof(T_RSPMODEL_VERTEX));
if (pObjPart->vertices == NULL) return RSPLIB_ERROR_MEMORY;
pHobStruct->objects[i].object_parts[j].vertices = calloc(pHobStruct->objects[i].object_parts[j].vertex_count, sizeof(T_RSPMODEL_VERTEX));
if (pHobStruct->objects[i].object_parts[j].vertices == NULL) return RSPLIB_ERROR_MEMORY;
for ( i = 0; i < pObjPart->vertex_count; i++ ) {
pObjPart->vertices[i].x =
((T_HOBFILE_VERTEX *)(pMemfile + pObjPart->vertex_block_offset + sizeof(T_RSPMODEL_VERTEX) * i))->x;
for ( k = 0; k < pHobStruct->objects[i].object_parts[j].vertex_count; k++ ) {
ParseObjectFaceVertices(&pHobStruct->objects[i].object_parts[j].vertices[k], pMemfile,
pHobStruct->objects[i].object_parts[j].vertex_block_offset + sizeof(T_RSPMODEL_VERTEX) * k, k, pParams);
}
pObjPart->vertices[i].y =
((T_HOBFILE_VERTEX *)(pMemfile + pObjPart->vertex_block_offset + sizeof(T_RSPMODEL_VERTEX) * i))->y;
if (pParams->debug_mode) printf("\n------------------------- End of Mesh ---------------------------\n");
}
pObjPart->vertices[i].z =
((T_HOBFILE_VERTEX *)(pMemfile + pObjPart->vertex_block_offset + sizeof(T_RSPMODEL_VERTEX) * i))->z;
if (pParams->debug_mode) printf("\n-~~~~~~~~~~~~~~~~~~~~~~- End of obj. part -~~~~~~~~~~~~~~~~~~~~~~~-\n");
}
pObjPart->vertices[i].w =
((T_HOBFILE_VERTEX *)(pMemfile + pObjPart->vertex_block_offset + sizeof(T_RSPMODEL_VERTEX) * i))->w; // Always 0???
if (pParams->debug_mode) printf("\n-=======================- End of Object -=========================-\n");
}
if (pParams->debug_mode) printf("[DBG] > Found vertex %d: (%d, %d, %d)\n", i,
pObjPart->vertices[i].x, pObjPart->vertices[i].y, pObjPart->vertices[i].z
return RSPLIB_SUCCESS;
}
/**
* @brief Parse datas from object's header
*
* @param[in|out] pObjStruct Take object structure and fill it with header datas.
* @param[in] pMemfile Pointer to an in-memory file location.
* @param[in] objIndex Object index for correct offset align.
* @param[in] pParams Program option, used to tune parser features.
*
* @return Error code, RSPLIB_SUCCESS when no error.
*/
static unsigned short ParseObjectHeader(T_RSPMODEL_OBJECT* pObjStruct, const MEMFILE pMemfile, const unsigned char objIndex, const RSPMODEL_PARAMETERS* pParams) {
if (pObjStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL;
// Create struct casting for clean code reading
const T_HOBFILE_OBJ_HEADER* const hobObjHeader =
((T_HOBFILE_OBJ_HEADER*)(pMemfile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_HEADER) * objIndex));
// Get object name
memcpy(pObjStruct->name, hobObjHeader->object_name, 16);
if (pParams->verbose_mode) printf("\n[INFO] - Process %s object...\n", pObjStruct->name);
// Get offsets
pObjStruct->face_group_offset = hobObjHeader->facegroup_start_offset;
pObjStruct->object_parts_header_offset = hobObjHeader->object_parts_offset;
pObjStruct->object_parts_header_offset2 = hobObjHeader->object_parts_offset2;
pObjStruct->object_parts_header2_offset = hobObjHeader->object_parts2_offset;
pObjStruct->object_parts_header2_offset2 = hobObjHeader->object_parts2_offset2;
pObjStruct->object_subparts_names_offset = hobObjHeader->subparts_namelist_offset;
pObjStruct->effects_offset = hobObjHeader->effects_offset;
pObjStruct->properties_offset2 = hobObjHeader->properties_offset;
if (pParams->verbose_mode) {
printf("[DBG] > Face group start offset: 0x%X\n", pObjStruct->face_group_offset);
printf("[DBG] > Object parts 1st header offset (main): 0x%X\n", pObjStruct->object_parts_header_offset);
printf("[DBG] > Object parts 1st header offset (aux): 0x%X\n", pObjStruct->object_parts_header_offset2);
printf("[DBG] > Object parts 2nd header offset (main): 0x%X\n", pObjStruct->object_parts_header2_offset);
printf("[DBG] > Object parts 2nd header offset (aux): 0x%X\n", pObjStruct->object_parts_header2_offset2);
printf("[DBG] > Object subparts names offset: 0x%X\n", pObjStruct->object_subparts_names_offset);
printf("[DBG] > Object effects offset: 0x%X\n", pObjStruct->effects_offset);
printf("[DBG] > Object properties offset: 0x%X\n", pObjStruct->properties_offset2);
}
// Get bounding box
pObjStruct->bounding_box.start.x = hobObjHeader->bbox_start_x;
pObjStruct->bounding_box.start.y = hobObjHeader->bbox_start_y;
pObjStruct->bounding_box.start.z = hobObjHeader->bbox_start_z;
pObjStruct->bounding_box.end.x = hobObjHeader->bbox_end_x;
pObjStruct->bounding_box.end.y = hobObjHeader->bbox_end_y;
pObjStruct->bounding_box.end.z = hobObjHeader->bbox_end_z;
if (pParams->verbose_mode) {
printf("[DBG] > Bounding box start: (%.8f, %.8f, %.8f)\n",
pObjStruct->bounding_box.start.x,
pObjStruct->bounding_box.start.y,
pObjStruct->bounding_box.start.z
);
printf("[DBG] > Bounding box end: (%.8f, %.8f, %.8f)\n",
pObjStruct->bounding_box.end.x,
pObjStruct->bounding_box.end.y,
pObjStruct->bounding_box.end.z
);
}
if (pParams->god_mode) {
printf("[DBG] > Object header unknown4: %.8f\n", hobObjHeader->unknown4);
}
return RSPLIB_SUCCESS;
}
/**
* @brief Parse datas from object parts's headers
*
* "objects" are individual, independent from each others, element of the game world.
* "object parts" are a group of mesh isolated by their animation attribute (and probably others physics attributes...)
* "facegroup" are like object parts but isolated by their rendering properties like associated texture, lighting properties, etc.
*
* @param[in|out] pObjStruct Take object structure and fill it with header datas.
* @param[in] pMemfile Pointer to an in-memory file location.
* @param[in] pParams Program option, used to tune parser features.
*
* @return Error code, RSPLIB_SUCCESS when no error.
*/
static unsigned short ParseObjectPartsHeaders(T_RSPMODEL_OBJECT* pObjStruct, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) {
unsigned int i;
char tmpStr[9] = {0};
if (pObjStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL;
// Create struct casting for clean code reading
const T_HOBFILE_OBJPARTS_HEADER* const hobObjPartsHeader1 = ((T_HOBFILE_OBJPARTS_HEADER*)(pMemfile + pObjStruct->object_parts_header_offset));
const T_HOBFILE_OBJPARTS_NAMEID* const hobObjPartsNames = ((T_HOBFILE_OBJPARTS_NAMEID*)(pMemfile + pObjStruct->object_subparts_names_offset));
// Get count and offsets from the facegroup header
pObjStruct->object_part_count = hobObjPartsHeader1->object_part_count;
pObjStruct->face_group_count = hobObjPartsHeader1->facegroup_count;
if (pParams->verbose_mode) {
printf("\n");
printf("[DBG] > Object parts count: %d\n", pObjStruct->object_part_count);
printf("[DBG] > Face groups count: %d\n", pObjStruct->face_group_count);
}
//TODO: others T_HOBFILE_FACEGROUP_XXXXXXX parsing
// Get names from object parts and ID association
printf("\n");
for (i = 0; i < (pObjStruct->object_part_count - 1); i++) { // object_part_count minus 1 because the first one (id=0) is always the root part
memcpy(tmpStr, hobObjPartsNames[i].name, 8);
if (pParams->verbose_mode)
printf("[DBG] > Object parts ID/name found: %d/%s\n", hobObjPartsNames[i].id, tmpStr);
if (pParams->god_mode && hobObjPartsNames[i].unknown0)
printf("[DBG] > Object parts ID unknown0 unexpected: 0x%X\n", hobObjPartsNames[i].unknown0);
}
return RSPLIB_SUCCESS;
}
/**
* @brief Parse datas from the specific object header.
*
* @param[in|out] pObjPartStruct Take object part structure and fill it with header datas.
* @param[in] pMemfile Pointer to an in-memory file location.
* @param[in] objPartIndex Object part index for correct offset align.
* @param[in] pParams Program option, used to tune parser features.
*
* @return Error code, RSPLIB_SUCCESS when no error.
*/
static unsigned short ParseObjectPartHeader(T_RSPMODEL_OBJ_PARTS* pObjPartStruct, const MEMFILE pMemfile,
const int objPartHdrOffset, const unsigned char objPartIndex, const RSPMODEL_PARAMETERS* pParams) {
if (pObjPartStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL;
// Create struct casting for clean code reading
const T_HOBFILE_OBJPART_HEADER* const hobObjPartHeader = ((T_HOBFILE_OBJPART_HEADER *)(pMemfile + objPartHdrOffset
+ sizeof(T_HOBFILE_OBJPARTS_HEADER) + sizeof(T_HOBFILE_OBJPART_HEADER) * objPartIndex));
// Get object part datas offset
pObjPartStruct->meshdef0_offset = hobObjPartHeader->facegroup_offset;
if (pParams->verbose_mode) printf("[DBG] > Obj. part %d facegroup (meshdef0) array offset: 0x%X\n", objPartIndex, pObjPartStruct->meshdef0_offset);
if (pParams->god_mode) printf("[DBG] > Obj. part unknown0: 0x%X\n", hobObjPartHeader->unknown0);
return RSPLIB_SUCCESS;
}
/**
* @brief Parse datas from object mesh definition.
*
* MeshDef (or Facegroup) is a compact structure containing the global geometry informations of a specific mesh.
* It's split in 2 parts: meshdef0 and meshdef1, meshdef1 offset is indicated in meshdef0 struct.
*
* @param[in|out] pObjPartStruct Take object part structure and fill it with header datas.
* @param[in] pMemfile Pointer to an in-memory file location.
* @param[in] pParams Program option, used to tune parser features.
*
* @return Error code, RSPLIB_SUCCESS when no error.
*/
static unsigned short ParseObjectMeshDef(T_RSPMODEL_OBJ_PARTS* pObjPartStruct, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) {
if (pObjPartStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL;
// Create struct casting for clean code reading
const T_HOBFILE_MESHDEF0* const hobObjMeshDef0 = ((T_HOBFILE_MESHDEF0*)(pMemfile + pObjPartStruct->meshdef0_offset));
// Get meshdef0 datas
//pObjPartStruct->id = hobObjMeshDef0->object_id; // Get object part ID, used by animation? bones?
pObjPartStruct->offset_transform.x = hobObjMeshDef0->offsett_x; // used by complex/animated objects like at-st, at-at, xwing, etc.
pObjPartStruct->offset_transform.y = hobObjMeshDef0->offsett_y;
pObjPartStruct->offset_transform.z = hobObjMeshDef0->offsett_z;
pObjPartStruct->scale_transform.x = hobObjMeshDef0->scalet_x; // used by complex/animated objects like at-st, at-at, xwing, etc.
pObjPartStruct->scale_transform.y = hobObjMeshDef0->scalet_y;
pObjPartStruct->scale_transform.z = hobObjMeshDef0->scalet_z;
pObjPartStruct->rotate_transform.x = hobObjMeshDef0->rott_x; // used by complex/animated objects like at-st, at-at, xwing, etc.
pObjPartStruct->rotate_transform.y = hobObjMeshDef0->rott_y;
pObjPartStruct->rotate_transform.z = hobObjMeshDef0->rott_z;
pObjPartStruct->translate_transform.x = hobObjMeshDef0->transt_x; // used by complex/animated objects like at-st, at-at, xwing, etc.
pObjPartStruct->translate_transform.y = hobObjMeshDef0->transt_y;
pObjPartStruct->translate_transform.z = hobObjMeshDef0->transt_z;
if (pParams->verbose_mode) {
printf("[DBG] > Parent meshdef0 offset: 0x%X\n", hobObjMeshDef0->parent_meshdef0_offset);
printf("[DBG] > Children meshdef0 offset: 0x%X\n", hobObjMeshDef0->children_meshdef0_offset);
printf("[DBG] > Have offset transform: %d\n", (hobObjMeshDef0->vecsFlags & 0x1)?1:0);
printf("[DBG] > Have scaling? vector: %d\n", (hobObjMeshDef0->vecsFlags & 0x2)?1:0);
printf("[DBG] > Have translation? vector: %d\n", (hobObjMeshDef0->vecsFlags & 0x4)?1:0);
printf("[DBG] > Have offset? vector: %d\n", (hobObjMeshDef0->vecsFlags & 0x8)?1:0);
printf("[DBG] > ObjPart offset transform: [%.8f %.8f %.8f]\n",
pObjPartStruct->offset_transform.x,
pObjPartStruct->offset_transform.y,
pObjPartStruct->offset_transform.z
);
printf("[DBG] > ObjPart scale transform: [%.8f %.8f %.8f]\n",
pObjPartStruct->scale_transform.x,
pObjPartStruct->scale_transform.y,
pObjPartStruct->scale_transform.z
);
printf("[DBG] > ObjPart rotate transform: [%.8f %.8f %.8f]\n",
pObjPartStruct->rotate_transform.x,
pObjPartStruct->rotate_transform.y,
pObjPartStruct->rotate_transform.z
);
printf("[DBG] > ObjPart translate transform: [%.8f %.8f %.8f]\n",
pObjPartStruct->translate_transform.x,
pObjPartStruct->translate_transform.y,
pObjPartStruct->translate_transform.z
);
}
if (pParams->god_mode) {
printf("[DBG] > meshdef0 offset1: 0x%X\n", hobObjMeshDef0->offset1);
printf("[DBG] > meshdef0 offset2: 0x%X\n", hobObjMeshDef0->offset2);
printf("[DBG] > meshdef0 unknown3: %.8f\n", hobObjMeshDef0->unknown3);
printf("[DBG] > meshdef0 unknown4: %.8f\n", hobObjMeshDef0->unknown4);
printf("[DBG] > meshdef0 unknown5: %.8f\n", hobObjMeshDef0->unknown5);
printf("[DBG] > meshdef0 unknown16: %.8f\n", hobObjMeshDef0->unknown16);
}
// Get meshdef1 (mesh descriptor) offset
pObjPartStruct->meshdef1_offset = hobObjMeshDef0->meshdef1_offset_plus_4;
if (pObjPartStruct->meshdef1_offset > 0) {
const T_HOBFILE_MESHDEF1* const hobObjMeshDef1 = ((T_HOBFILE_MESHDEF1*)(pMemfile + pObjPartStruct->meshdef1_offset - 4));
// Read meshdef1 datas
pObjPartStruct->face_block_end_offset = hobObjMeshDef1->facedef_end_offset;
pObjPartStruct->vertex_count = hobObjMeshDef1->vertex_count;
pObjPartStruct->face_block_offset = hobObjMeshDef1->faceblock_offset;
pObjPartStruct->vertex_block_offset = hobObjMeshDef1->vertexblocks_offset;
if (pParams->verbose_mode) {
printf("\n[DBG] > Facegroup vertices descriptor (meshdef1) offset: 0x%X\n", pObjPartStruct->meshdef1_offset);
printf("[DBG] > Vertex count: %d\n", pObjPartStruct->vertex_count);
printf("[DBG] > Faces offset: 0x%X\n", pObjPartStruct->face_block_offset);
printf("[DBG] > Vertex offset: 0x%X\n", pObjPartStruct->vertex_block_offset);
}
} else {
if (pParams->verbose_mode) printf("\n[DBG] > No vertices datas (meshdef1 = 0x0).\n");
}
return RSPLIB_SUCCESS;
}
/**
* @brief Parse datas from object faceblock header.
*
* Faceblock is group of faces elements with header.
* Meshdef have one associated faceblock.
*
* @param[in|out] pObjPartStruct Take object part structure and fill it with header datas.
* @param[in] pMemfile Pointer to an in-memory file location.
* @param[in] pParams Program option, used to tune parser features.
*
* @return Error code, RSPLIB_SUCCESS when no error.
*/
static unsigned short ParseObjectFaceblockHeader(T_RSPMODEL_OBJ_PARTS* pObjPartStruct, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) {
if (pObjPartStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL;
// Create struct casting for clean code reading
const T_HOBFILE_FACEBLOCK* const hobObjFaceblock = ((T_HOBFILE_FACEBLOCK*)(pMemfile + pObjPartStruct->face_block_offset));
// Get faces count
pObjPartStruct->face_count = hobObjFaceblock->faceCounts;
if (pParams->debug_mode) printf("[DBG] > Faces count: %d\n", pObjPartStruct->face_count);
if (pParams->god_mode) {
if( hobObjFaceblock->reserved1 != 0 || hobObjFaceblock->reserved2 != 0 ) {
printf("[DBG] > Faceblock: uncommon zero header! (0x%X) (0x%X)\n", hobObjFaceblock->reserved1, hobObjFaceblock->reserved2);
}
if ( hobObjFaceblock->facesOffset != pObjPartStruct->face_block_offset + sizeof(T_HOBFILE_FACEBLOCK) ) {
printf("[DBG] > Faceblock: uncommon face data offset position!\n");
}
}
return RSPLIB_SUCCESS;
}
/**
* @brief Parse datas from object face.
*
* @param[in|out] pFaceStruct Take face structure and fill it with face datas.
* @param[in] pMemfile Pointer to an in-memory file location.
* @param[in|out] facesExtraOffset Face correction offset to correctly align with datas
* @param[in] faceNbr Face number (for debug print only)
* @param[in] pParams Program option, used to tune parser features.
*
* @return Error code, RSPLIB_SUCCESS when no error.
*/
static unsigned short ParseObjectFace(T_RSPMODEL_FACE* pFaceStruct, const MEMFILE pMemfile,
unsigned int* const facesExtraOffset, const unsigned int faceNbr, const RSPMODEL_PARAMETERS* pParams) {
unsigned int localOffset;
if (pFaceStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL;
// Create struct casting for clean code reading
const T_HOBFILE_FACES_HEADER* const hobObjFace = ((T_HOBFILE_FACES_HEADER*)(pMemfile + *facesExtraOffset));
// Get flags
pFaceStruct->flags = hobObjFace->flags;
// Get unknown bytes
pFaceStruct->b1 = hobObjFace->b1;
pFaceStruct->b2 = hobObjFace->b2;
pFaceStruct->b3 = hobObjFace->b3;
pFaceStruct->bsize = hobObjFace->faceBlockIntSize * 4; // Multiply by 4 to get the bytes exact number
if (hobObjFace->headerSeparator != 0) {
if (pParams->god_mode) printf("[DBG] > Face header: uncommon separator! (0x%X)\n", hobObjFace->headerSeparator);
}
// Get materials index
pFaceStruct->mt_index = hobObjFace->materialIndex;
// Get vertex indices
memcpy(pFaceStruct->indices, hobObjFace->vertexIndices, sizeof(unsigned short) * 4);
// Recalculate the dynamic extra bytes offset size - if present
//if (pObjPart->faces[i].flags_bits.fHasExtraBytesBeforeColor) facesExtraOffset += 8;
localOffset = pFaceStruct->flags_bits.fHasExtraBytesBeforeColor ? 8 : 0;
// Get vertex color - if present
if (pFaceStruct->flags_bits.fHasColor) {
localOffset += ExtractObjpart_Face_Colors(pFaceStruct, pMemfile + *facesExtraOffset + sizeof(T_HOBFILE_FACES_HEADER) + localOffset);
}
// Get UV map - if present
if (pFaceStruct->flags_bits.fHasTexture) {
localOffset += ExtractObjpart_Face_UVMaps(pFaceStruct, pMemfile + *facesExtraOffset + sizeof(T_HOBFILE_FACES_HEADER) + localOffset);
}
// Recalculate the extra bytes offset (it's assume the faces are parsed in order)
*facesExtraOffset += pFaceStruct->bsize;
if (pParams->debug_mode) {
printf("[DBG] > Face %d details: flags:0x%X b1:0x%X b2:0x%X b3:0x%X bsize:%d\n", faceNbr,
pFaceStruct->flags, pFaceStruct->b1, pFaceStruct->b2, pFaceStruct->b3, pFaceStruct->bsize);
printf("[DBG] - Type is Quad: %d\n", pFaceStruct->flags_bits.fIsQuad);
printf("[DBG] - Have color: %d\n", pFaceStruct->flags_bits.fHasColor);
printf("[DBG] - Have texture: %d\n", pFaceStruct->flags_bits.fHasTexture);
printf("[DBG] - Material/texture index: %d\n", pFaceStruct->mt_index);
printf("[DBG] - Vertex indices: %d, %d, %d, %d\n", pFaceStruct->indices[0], pFaceStruct->indices[1], pFaceStruct->indices[2], pFaceStruct->indices[3]);
printf("[DBG] - Vertex colors: 0x%X, 0x%X, 0x%X, 0x%X\n", pFaceStruct->vertex_colors[0], pFaceStruct->vertex_colors[1], pFaceStruct->vertex_colors[2], pFaceStruct->vertex_colors[3]);
printf("[DBG] - Vertex UV coord (divided by 4096):\n");
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
((double) 1/4096) * pFaceStruct->tex_coords[0].u, pFaceStruct->tex_coords[0].u,
((double) 1/4096) * pFaceStruct->tex_coords[0].v, pFaceStruct->tex_coords[0].v
);
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
((double) 1/4096) * pFaceStruct->tex_coords[1].u, pFaceStruct->tex_coords[1].u,
((double) 1/4096) * pFaceStruct->tex_coords[1].v, pFaceStruct->tex_coords[1].v
);
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
((double) 1/4096) * pFaceStruct->tex_coords[2].u, pFaceStruct->tex_coords[2].u,
((double) 1/4096) * pFaceStruct->tex_coords[2].v, pFaceStruct->tex_coords[2].v
);
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
((double) 1/4096) * pFaceStruct->tex_coords[3].u, pFaceStruct->tex_coords[3].u,
((double) 1/4096) * pFaceStruct->tex_coords[3].v, pFaceStruct->tex_coords[3].v
);
}
return RSPLIB_SUCCESS;
}
/**
* @brief Parse datas from object face.
*
* @param[in|out] pVertexStruct Take vertex structure and fill it with vertices datas.
* @param[in] pMemfile Pointer to an in-memory file location.
* @param[in] verticesOffset Vertices area offset to correctly align with datas
* @param[in] vertexNbr Vertex number (for debug print only)
* @param[in] pParams Program option, used to tune parser features.
*
* @return Error code, RSPLIB_SUCCESS when no error.
*/
static unsigned short ParseObjectFaceVertices(T_RSPMODEL_VERTEX* pVertexStruct, const MEMFILE pMemfile,
const unsigned int verticesOffset, const unsigned int vertexNbr, const RSPMODEL_PARAMETERS* pParams) {
if (pVertexStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL;
// Create struct casting for clean code reading
const T_HOBFILE_VERTEX* const hobObjVertex = ((T_HOBFILE_VERTEX*)(pMemfile + verticesOffset));
pVertexStruct->x = hobObjVertex->x;
pVertexStruct->y = hobObjVertex->y;
pVertexStruct->z = hobObjVertex->z;
pVertexStruct->w = hobObjVertex->w; // Always 0???
if (pParams->debug_mode) {
printf("[DBG] > Found vertex %d: (%d, %d, %d)\n", vertexNbr, pVertexStruct->x, pVertexStruct->y, pVertexStruct->z);
}
return RSPLIB_SUCCESS;

View File

@ -1,6 +1,6 @@
/**
* @file hob_parser.h
* @date 18/01/2023
* @date 21/02/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Process HOB file structure and extract its datas.

View File

@ -1,6 +1,6 @@
/**
* @file hob_struct.h
* @date 26/07/2022
* @date 18/09/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief HOB file mapping definition.
@ -36,108 +36,158 @@
/*
* - Global HOB file structure-
* +------------------+--------------------------------------+----------------------------------------+
* | T_HOBFILE_HEADER | obj_count * T_HOBFILE_OBJ_DESCRIPTOR | obj_count * T_HOBFILE_FACEGROUP_HEADER |
* | 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 |
* +----------------------------+------------------------------------------------+
* +------------------------------+--------------------------------------------------+
* --> | 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_descriptor {
unsigned char object_name[16];
unsigned int facegroup_offset;
unsigned int object_parts_offset;
unsigned int facegroup_header_2_offset;
typedef struct PACK hobfile_obj_header {
unsigned char object_name[16]; // Name of the object
unsigned int reserved1; // 12B of zeros
unsigned int reserved2;
unsigned int reserved3;
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 unknownOffset1;
unsigned int unknownOffset2;
unsigned int unknownOffset3;
float unknown4;
unsigned int object_parts2_offset; // Optional offset - seem present in tieinter_HOB - point just after the 0xFFFFFFFF of the first one
unsigned int object_parts2_offset2; // Optional offset - seem present in tieinter_HOB
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, present in koelsch. worddevastator can have more answers...
unsigned int properties_offset; // Offset to different string (a_b/zf/zt/zb/etc.) Animation datas ? Empty with 6x float in train_hob, a_b object is canon beams in gun_turret
float unknown4; // 1.0F/1.125F - Look forward angle correction?
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;
float unknown5; // Something related to culling camera frustum (when reduced value, the gun_turret didn't render before getting out of camera view)
float unknown6; // Something related to collision detection (bigger float >100.0f)
typedef struct PACK hobfile_facegroup_header {
float reserved7; // Something related to collision detection Translation matrix? Center of object?
float reserved8; // Something related to collision detection Translation matrix? Center of object?
float reserved9; // Something related to collision detection Translation matrix? Center of object?
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;
/*
* T_HOBFILE_OBJPARTS_HEADER
* |
* \
* |T_HOBFILE_OBJPART_HEADER
* \
* T_HOBFILE_OBJPART_HEADER
* |
* \
* |T_HOBFILE_FACEGROUP_HEADER
* \
* T_HOBFILE_FACEGROUP_HEADER
*/
typedef struct PACK hobfile_objparts_header {
unsigned short object_part_count;
unsigned short facegroup_count; //aka. meshdef count
} T_HOBFILE_OBJPARTS_HEADER;
typedef struct PACK hobfile_objpart_header {
unsigned int unknown0; // It is flags?
unsigned int facegroup_offset;
} T_HOBFILE_OBJPART_HEADER;
/* TODO: Not sure these exist
typedef struct PACK hobfile_facegroup_header_2 { //TODO: This is part of a bigger one
unsigned short object_part_count;
unsigned short facegroup_count;
} T_HOBFILE_FACEGROUP_HEADER;
} T_HOBFILE_FACEGROUP_HEADER_2;
typedef struct PACK hobfile_facegroup_offset {
unsigned int unknown1;
unsigned int facegroup_offset;
} T_HOBFILE_FACEGROUP_OFFSET;
typedef struct PACK hobfile_facegroup_offset_2 { //TODO: This is part of a bigger one
unsigned int unknownOffset0;
} T_HOBFILE_FACEGROUP_OFFSET_2;
*/
typedef struct PACK hobfile_objparts_nameid {
unsigned char name[8];
unsigned char unknown0; // Always zeros ?
unsigned char id;
} T_HOBFILE_OBJPARTS_NAMEID;
/* TODO:
typedef struct PACK hobfile_effects {
unsigned char something0;
unsigned short something1;
} T_HOBFILE_EFFECTS;
*/
typedef struct PACK hobfile_meshdef0 {
unsigned int offset1;
unsigned int offset2;
unsigned int prev_meshdef0_offset;
unsigned int next_meshdef0_offset;
unsigned int offset1; // Brothers meshdef?
unsigned int offset2; // Brothers meshdef?
unsigned int parent_meshdef0_offset;
unsigned int children_meshdef0_offset;
unsigned int meshdef1_offset_plus_4;
unsigned int reserved1; // 8B of zeros
unsigned int reserved2;
float unknown3;
float unknown3; // Always 1.0f?
unsigned int reserved3; // 12B of zeros
unsigned int reserved4;
unsigned int reserved5;
float unknown4;
float unknown4; // Always 1.0f?
unsigned int reserved6; // 12B of zeros
unsigned int reserved7;
unsigned int reserved8;
float unknown5;
float unknown5; // Always 1.0f?
unsigned int reserved9; // 12B of zeros
unsigned int reserved10;
unsigned int reserved11;
unsigned int object_id;
unsigned int vecsFlags; // Enabled local transforms (bit0=offset #1; bit1=scale #2; bit2=rotation #3; bit3=translation;)
float unknown12; // Can be a vector???
float unknown13;
float unknown14;
float offsett_x; // Offset transform (aka. reverse translation)
float offsett_y;
float offsett_z;
float unknown15; // Can be a vector???
float unknown16;
float unknown17;
float scalet_x; // Local transform - Scale
float scalet_y;
float scalet_z;
float unknown18; // Can be a matrix???
float unknown19;
float unknown20;
float unknown21;
float rott_x; // Local transform - Rotation
float rott_y;
float rott_z;
float transform_x;
float transform_y;
float transform_z;
float unknown16; // Always 0?
float transt_x; // Local transform - Translation
float transt_y;
float transt_z;
} T_HOBFILE_MESHDEF0;
typedef struct PACK hobfile_meshdef1 {
@ -180,11 +230,11 @@ typedef struct PACK 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 b1; // Seem to alter texture mapping on face, 49 -> quad face, 48 -> tri face, 47 -> N/A
unsigned char b2; // 61 -> texture right rotation, 71 -> little red overlay, 81 -> bigger red overlay, x1 -> don't do anything
unsigned char b3; // Seem to alter rendering matrix or maybe vertices position relative to
unsigned char faceBlockIntSize; // Bytes size divided by 4, count as number of UInt32 type.
unsigned short headerSeparator;
unsigned short headerSeparator; // If header it's uncommon, it's probably because you made a wrong parsing
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;

View File

@ -1,246 +0,0 @@
/**
* @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_RSPMODEL_RGBA v1_rgba;
T_RSPMODEL_RGBA v2_rgba;
T_RSPMODEL_RGBA v3_rgba;
T_RSPMODEL_RGBA v4_rgba; // Used with quad type face
} T_HOBFILE_FACES_VERTEX_COLOR;
typedef struct PACK hobfile_faces_extra_color {
T_RSPMODEL_RGBA rgba;
} T_HOBFILE_FACES_COLOR;
typedef struct PACK hobfile_faces_extra_vertex_texture {
T_RSPMODEL_TEXCOORD v1_texcoord; // Should be divided (no shifting) by 4096 to get 0...1 range
T_RSPMODEL_TEXCOORD v2_texcoord;
T_RSPMODEL_TEXCOORD v3_texcoord;
T_RSPMODEL_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_ */

View File

@ -0,0 +1,21 @@
/**
* @file mesh_builder.h
* @date 18/01/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Mesh constructor of HOB objects.
*
*/
#include "RSPModel_datatypes.h"
#ifndef MESH_BUILDER_H_
#define MESH_BUILDER_H_
unsigned short RSP_ModelLib_HOBObjectToGL( const T_RSPMODEL_OBJECT* objStruct );
/*
unsigned short RSP_ModelLib_HOBObjectToGL( const T_RSPMODEL_OBJECT* objStruct, void* glObj );
unsigned short RSP_ModelLib_HOBObjectToD3D( const T_RSPMODEL_OBJECT* objStruct, void* D3DObj );
*/
#endif /* MESH_BUILDER_H_ */

132
conanfile.py Normal file
View File

@ -0,0 +1,132 @@
import os
from conan import ConanFile
from conan.tools.cmake import CMakeToolchain, CMakeDeps, CMake
from conan.tools.files import copy
from conan.tools.scm import Git, Version
required_conan_version = ">=2.3"
class rse_model(ConanFile):
name = "rspmodellib"
package_type = "library"
version = "2.3.1"
revision_mode = "scm"
license = "GPL-3.0"
author = "JackCarterSmith <jackcartersmith@jcsmith.fr>"
url = "https://git.jcsmith.fr/JCS-Prod/RSE-Model"
description = "Rogue Squadron 3D (PC) game models files (HOB) extractor"
settings = "os", "compiler", "build_type", "arch"
generators = "CMakeDeps"
options = {
"shared": [True, False],
"tools": [True, False],
"fPIC": [True, False]
}
default_options = {
"shared": True,
"tools": False,
"fPIC": True
}
@property
def _is_msvc(self):
return str(self.settings.compiler) in ["Visual Studio", "msvc"]
#def validate(self):
# if self.settings.os == "Macos":
# raise ConanInvalidConfiguration("MacOS not supported")
def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC
def configure(self):
self.options["glew"].shared = True
#self.options["vulkan-loader"].shared = True
if self.options.shared:
self.options.rm_safe("fPIC")
def requirements(self):
if self.options.tools:
#self.requires("opengl/system")
#self.requires("glu/system")
self.requires("glew/2.2.0")
#self.requires("vulkan-headers/1.3.236.0")
#self.requires("vulkan-memory-allocator/3.0.1")
#self.requires("vulkan-loader/1.3.236.0")
def source(self):
git = Git(self)
cargs = ['--single-branch', '--recursive', '--depth', '1', '--branch', 'v' + self.version]
git.clone(url="https://git.jcsmith.fr/JCS-Prod/RSE-Model.git", target=".", args=cargs)
# def _patch(self):
# replace_in_file(self, os.path.join(self.source_folder, "RSPModelLib", "CMakeLists.txt"),
# 'set_target_properties(rsp-texture-libstatic PROPERTIES OUTPUT_NAME "${RSP_TEXTURE_LIB_NAME}_static")',
# 'set_target_properties(rsp-texture-libstatic PROPERTIES OUTPUT_NAME "${RSP_TEXTURE_LIB_NAME}")')
def export_sources(self):
copy(self, "CMakeLists.txt", self.recipe_folder, self.export_sources_folder)
# def layout(self):
# cmake_layout(self, src_folder='.', build_folder='build')
def generate(self):
tc = CMakeToolchain(self)
tc.cache_variables["RSPMODEL_SHARED"] = self.options.shared
tc.cache_variables["RSPMODEL_STATIC"] = not self.options.shared
tc.cache_variables["BUILD_TOOLS"] = self.options.tools
#tc.cache_variables["BUILD_DEBUG"] = self.settings.build_type == "Debug"
tc.generate()
#cmdeps = CMakeDeps(self)
#cmpdeps.set_property("glew", "cmake_find_mode", "both")
#if self.options.shared:
#cmdeps.configuration = "ReleaseShared"
#cmdeps.generate()
for dep in self.dependencies.values():
if len(dep.cpp_info.bindirs) > 0:
if self.settings.os == "Windows":
if self._is_msvc:
copy(self, "*.dll", dep.cpp_info.bindirs[0], os.path.join(self.build_folder, "bin", str(self.settings.build_type)))
else:
copy(self, "*.dll", dep.cpp_info.bindirs[0], os.path.join(self.build_folder, "bin"))
else:
copy(self, "*.so", dep.cpp_info.bindirs[0], os.path.join(self.build_folder, "bin"))
def build(self):
cmbuilder = CMake(self)
#self._patch()
cmbuilder.configure()
cmbuilder.build()
def package(self):
copy(self, "LICENSE", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"))
copy(self, pattern="*.h", src=os.path.join(self.source_folder, "include"), dst=os.path.join(self.package_folder, "include"))
copy(self, pattern="*.a", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
copy(self, pattern="*.so", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
copy(self, pattern="*.lib", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
copy(self, pattern="*.dll", src=self.build_folder, dst=os.path.join(self.package_folder, "bin"), keep_path=False)
def package_info(self):
self.cpp_info.set_property("cmake_file_name", "RSEModel")
self.cpp_info.set_property("cmake_target_name", "RSEModel")
self.cpp_info.set_property("cmake_module_target_name", "RSEModel::RSEModel")
self.cpp_info.set_property("cmake_find_mode", "both")
self.cpp_info.names["cmake_find_package"] = "RSEModel"
self.cpp_info.names["cmake_find_package_multi"] = "RSEModel"
self.cpp_info.includedirs = ["include"]
prefix = "lib" if self._is_msvc else ""
#suffix = "d" if self.settings.build_type == "Debug" else ""
suffix = ""
major_min_version = f"{Version(self.version).major}{Version(self.version).minor}"
self.cpp_info.libs = ["{}RSEModel{}{}".format(prefix, major_min_version, suffix)]
if self.settings.os in ["Linux", "Android", "FreeBSD", "SunOS", "AIX"]:
self.cpp_info.system_libs.append("m")
self.cpp_info.system_libs.append("dl")

View File

@ -1,18 +0,0 @@
[requires]
#opengl/system
#glu/system
glew/2.2.0
#vulkan-headers/1.3.236.0
#vulkan-memory-allocator/3.0.1
#vulkan-loader/1.3.236.0
[generators]
cmake
cmake_find_package
[options]
glew:shared=True
vulkan-loader:shared=True
[imports]
bin, *.dll -> ./bin