Push first version prototype
All checks were successful
JCS-Prod/RSE-Model/pipeline/head This commit looks good
All checks were successful
JCS-Prod/RSE-Model/pipeline/head This commit looks good
This commit is contained in:
commit
6bfecbec01
@ -23,8 +23,8 @@ include(CheckCSourceCompiles)
|
||||
|
||||
# needed packages
|
||||
|
||||
find_package(GLEW REQUIRED)
|
||||
include_directories(${GLEW_INCLUDE_DIR})
|
||||
#find_package(GLEW REQUIRED)
|
||||
#include_directories(${GLEW_INCLUDE_DIR})
|
||||
|
||||
# define src/headers files
|
||||
|
||||
@ -45,7 +45,7 @@ if(MSVC)
|
||||
set_target_properties(rse-model PROPERTIES PREFIX "lib")
|
||||
set_target_properties(rse-model PROPERTIES IMPORT_PREFIX "lib")
|
||||
endif()
|
||||
target_link_libraries(rse-model ${GLEW_LIBRARIES})
|
||||
target_link_libraries(rse-model m)
|
||||
|
||||
# add GPG signature command
|
||||
#add_custom_command(
|
||||
|
22
Jenkinsfile
vendored
22
Jenkinsfile
vendored
@ -4,13 +4,14 @@ pipeline {
|
||||
skipDefaultCheckout(true)
|
||||
}
|
||||
environment {
|
||||
CI_OUTPUT_NAME = "RSE_Model"
|
||||
CI_OUTPUT_NAME = "RSE_Texture"
|
||||
CI_BUILD_NUMBER = "$BUILD_NUMBER"
|
||||
}
|
||||
stages {
|
||||
stage('Prepare') {
|
||||
steps {
|
||||
cleanWs()
|
||||
rtConanClient(id: "conan", userHome: "/home/jackcartersmith")
|
||||
}
|
||||
}
|
||||
stage('Build') {
|
||||
@ -18,14 +19,20 @@ pipeline {
|
||||
parallel(
|
||||
linux: {
|
||||
dir("linux") {
|
||||
checkout([$class: 'GitSCM', branches: [[name: '**']], browser: [$class: 'GiteaBrowser', repoUrl: 'https://git.jcsmith.fr/jackcartersmith/RSE-Model.git'], extensions: [], userRemoteConfigs: [[credentialsId: 'jenkins-ssh', url: 'ssh://git@git.jcsmith.fr:2322/JCS-Prod/RSE-Model.git']]])
|
||||
checkout([$class: 'GitSCM', branches: [[name: '**']], browser: [$class: 'GiteaBrowser', repoUrl: 'https://git.jcsmith.fr/JCS-Prod/RSE-Texture'], extensions: [], userRemoteConfigs: [[credentialsId: 'jenkins-ssh', url: 'ssh://git@git.jcsmith.fr:2322/JCS-Prod/RSE-Texture.git']]])
|
||||
dir("build") {
|
||||
rtConanRun(clientId: "conan", command: "install .. --build missing")
|
||||
}
|
||||
cmakeBuild buildDir: 'build', installation: 'latest', steps: [[args: 'all']]
|
||||
}
|
||||
},
|
||||
windows: {
|
||||
dir("windows") {
|
||||
checkout([$class: 'GitSCM', branches: [[name: '**']], browser: [$class: 'GiteaBrowser', repoUrl: 'https://git.jcsmith.fr/jackcartersmith/RSE-Model.git'], extensions: [], userRemoteConfigs: [[credentialsId: 'jenkins-ssh', url: 'ssh://git@git.jcsmith.fr:2322/JCS-Prod/RSE-Model.git']]])
|
||||
cmakeBuild buildDir: 'build', cmakeArgs: '-DGNU_HOST=x86_64-w64-mingw32 -DCMAKE_TOOLCHAIN_FILE=../mingw_cross_toolchain.cmake -D"ZLIB_INCLUDE_DIR=/mnt/cc-libs/mingw64/zlib/1.2.11/include" -D"ZLIB_LIBRARY=/mnt/cc-libs/mingw64/zlib/1.2.11/lib/libzlib.dll.a" -D"PNG_PNG_INCLUDE_DIR=/mnt/cc-libs/mingw64/libpng/1.6.37/include" -D"PNG_LIBRARY=/mnt/cc-libs/mingw64/libpng/1.6.37/lib/libpng.dll.a"', installation: 'latest', steps: [[args: 'all']]
|
||||
checkout([$class: 'GitSCM', branches: [[name: '**']], browser: [$class: 'GiteaBrowser', repoUrl: 'https://git.jcsmith.fr/JCS-Prod/RSE-Texture'], extensions: [], userRemoteConfigs: [[credentialsId: 'jenkins-ssh', url: 'ssh://git@git.jcsmith.fr:2322/JCS-Prod/RSE-Texture.git']]])
|
||||
dir("build") {
|
||||
rtConanRun(clientId: "conan", command: "install .. --profile windows --build missing")
|
||||
}
|
||||
cmakeBuild buildDir: 'build', cmakeArgs: '-DGNU_HOST=x86_64-w64-mingw32 -DCMAKE_TOOLCHAIN_FILE=../mingw_cross_toolchain.cmake', installation: 'latest', steps: [[args: 'all']]
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -37,12 +44,14 @@ pipeline {
|
||||
sh 'cp ../linux/build/${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}* .'
|
||||
}
|
||||
dir("zip_win") {
|
||||
sh 'cp ../windows/build/${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}* /mnt/cc-libs/mingw64/zlib/1.2.11/bin/libzlib.dll /mnt/cc-libs/mingw64/libpng/1.6.37/bin/libpng16.dll .'
|
||||
sh 'cp ../windows/build/${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}* ../windows/build/*.dll .'
|
||||
}
|
||||
zip archive: false, dir: 'zip_linux', exclude: '', glob: '', zipFile: 'x64.zip'
|
||||
sh 'mv x64.zip ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_x64.zip'
|
||||
zip archive: false, dir: 'zip_win', exclude: '', glob: '', zipFile: 'mingw64.zip'
|
||||
sh 'mv mingw64.zip ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_mingw64.zip'
|
||||
archiveArtifacts(artifacts: '*.zip')
|
||||
fingerprint(targets: '*.zip')
|
||||
}
|
||||
}
|
||||
stage('Sign') {
|
||||
@ -50,7 +59,8 @@ pipeline {
|
||||
sh 'ls -l'
|
||||
sh 'gpg --batch --detach-sign -o ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_x64.zip.gpg ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_x64.zip'
|
||||
sh 'gpg --batch --detach-sign -o ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_mingw64.zip.gpg ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_mingw64.zip'
|
||||
archiveArtifacts(artifacts: '*.zip,*.gpg')
|
||||
archiveArtifacts(artifacts: '*.gpg')
|
||||
fingerprint(targets: '*.gpg')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
53
README.md
53
README.md
@ -7,8 +7,57 @@ The collection consist of few independants modules, each of them deals with spec
|
||||
|
||||
All modules are independants. This is the **'MODEL'** module.
|
||||
|
||||
:exclamation: **Master branch is ugly for now and should not be used, please take only released versions.** :exclamation:
|
||||
|
||||
## MODEL MODULE
|
||||
|
||||
It's extract texture datas from Rogue Squadron 3D (PC) game models files (HOB).
|
||||
|
||||
This module can do:
|
||||
- Extract objects inside HOB files to Wavefront OBJ format,
|
||||
- Extract automatically inside subfolder (usefull when you have multiples objects to extract),
|
||||
- Multiple inputs files.
|
||||
|
||||
## TODO
|
||||
|
||||
- Add textures to models.
|
||||
- Discover all unknow fields, animation, bones mesh, etc.
|
||||
|
||||
### Using
|
||||
|
||||
`RSE-Model_"version" [options] <hob files...>` or you can simply drag&drop HOB files on it.
|
||||
|
||||
A futur main program can extract all HOB files directly from DAT file.
|
||||
Due to issue with copyrights, I can't provide samples... You need to extract HOB files yourself.
|
||||
|
||||
<img src="https://repo.jcsmith.fr/pictures/rse-model.gif" width="620" height="400" />
|
||||
|
||||
### Options
|
||||
|
||||
- -h Print this message
|
||||
- -v Activate verbose output
|
||||
- -no-subdir Extract textures directly inside current folder
|
||||
|
||||
### Dependencies
|
||||
|
||||
- obj-lib: as obj file exporter. (https://github.com/rlk/obj)
|
||||
|
||||
### Compiling
|
||||
|
||||
You can compile on both Windows (MinGW) or native Linux system thanks to CMake.
|
||||
|
||||
To compile, just clone and launch cmake:
|
||||
|
||||
```shell
|
||||
cmake .
|
||||
make
|
||||
make install
|
||||
```
|
||||
|
||||
We can also use cross-compilation (after installing `mingw64` and `cmake` packages on your distrib):
|
||||
|
||||
```shell
|
||||
mkdir build && cd build
|
||||
cmake -DGNU_HOST=x86_64-w64-mingw32 \
|
||||
-DCMAKE_TOOLCHAIN_FILE=../mingw_cross_toolchain.cmake \
|
||||
..
|
||||
cmake --build .
|
||||
```
|
@ -1,47 +1,109 @@
|
||||
/*
|
||||
================================================================================
|
||||
Name : Map-Extractor.c
|
||||
Name : Model-Extractor.c
|
||||
Author : JackCarterSmith
|
||||
License : GPL-v3.0
|
||||
Description : DAT textures extractor to PNG format with enhanced function in C
|
||||
Description : HOB model parser and export to Waveform OBJ format.
|
||||
================================================================================
|
||||
*/
|
||||
|
||||
#include "Model-Extractor.h"
|
||||
#include "rlk/obj.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include "errors_types.h"
|
||||
#include "config.h"
|
||||
#include "options.h"
|
||||
#include "hob_struct.h"
|
||||
#include "hob_parser.h"
|
||||
#include "obj_exporter.h"
|
||||
|
||||
|
||||
/*
|
||||
* Internal functions declarations
|
||||
*/
|
||||
|
||||
static unsigned int mainProcess(int args_cnt, char *args_value[]);
|
||||
static void createSubDir(char *dirName);
|
||||
static int checkInputArgs(int arg_nbr, char *args[]);
|
||||
static void cleanUpMemory(T_HOB* hobStruct);
|
||||
//int exportTextures(HMT_FILE *hmt_f, char *filename);
|
||||
static inline void dispHelp();
|
||||
|
||||
|
||||
/*
|
||||
* Global variables declaration
|
||||
*/
|
||||
|
||||
int _options; // Global options settings variable
|
||||
|
||||
|
||||
/*
|
||||
* - MAIN -
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
// Init buffer vars
|
||||
int file_index;
|
||||
|
||||
printf("\n*** RogueSquadron Extractor (RSE) - MAP module - v%s ***\n", VERSION);
|
||||
|
||||
printf("\n*** RogueSquadron Extractor (RSE) - MODEL module - v%s ***\n", VERSION);
|
||||
|
||||
// Check if filenames arguments exist
|
||||
if (argc < 2) {
|
||||
printf("\n[ERR] No input file/commands specified!\n");
|
||||
dispHelp();
|
||||
return EXIT_FAILURE; //TODO: implement own error codes system
|
||||
return ERROR_ARGS_NULL;
|
||||
}
|
||||
_options = checkArgs(argv, argc); // Analyse program arguments
|
||||
if (_options == -1) return EXIT_SUCCESS;
|
||||
_options = checkInputArgs(argc, argv); // Analyse program arguments
|
||||
if (_options == -1) return NO_ERROR;
|
||||
|
||||
// Do the work
|
||||
for (file_index=(_options >> 8) & 0xFF; file_index<argc; file_index++) { // Manage multiple inputs files
|
||||
/*
|
||||
hmt_fdatas = extractDatasFromHMT(argv[file_index]);
|
||||
if (hmt_fdatas == NULL) return EXIT_FAILURE;
|
||||
if (exportTextures(hmt_fdatas, argv[file_index]) == EXIT_FAILURE) return EXIT_FAILURE;
|
||||
purgeHMTFromMemory(hmt_fdatas); // Clean up memory (because I'm a good boy)
|
||||
*/
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
return mainProcess(argc, argv);
|
||||
}
|
||||
|
||||
int checkArgs(char *args[], int arg_nbr) {
|
||||
|
||||
/*
|
||||
* Private functions definition
|
||||
*/
|
||||
|
||||
static unsigned int mainProcess(int args_cnt, char *args_value[]) {
|
||||
unsigned short file_index;
|
||||
T_HOB* hobStruct = NULL;
|
||||
int i;
|
||||
|
||||
// Manage multiple inputs files
|
||||
for (file_index=(_options >> 8) & 0xFF; file_index < args_cnt; file_index++)
|
||||
{
|
||||
printf("\n=============================================\n[INFO] - Parsing file: %s ...\n", args_value[file_index]);
|
||||
hobStruct = calloc(1, sizeof(T_HOB));
|
||||
// Parse data from HOB file and put in T_HOB structure.
|
||||
if (parseHOBFile(args_value[file_index], hobStruct) != NO_ERROR) {
|
||||
printf("[ERR] Failed to parse datas from %s\n", args_value[file_index]);
|
||||
free(hobStruct);
|
||||
return ERROR_PROCESS;
|
||||
}
|
||||
|
||||
if (hobStruct->obj_count > 0) {
|
||||
if (_options & OUTPUT_DIR) createSubDir(args_value[file_index]);
|
||||
|
||||
for ( i = 0; i < hobStruct->obj_count; i++ ) {
|
||||
if (exportOBJModel(&(hobStruct->objects[i]), args_value[file_index]) != NO_ERROR)
|
||||
printf("[ERR] Failed to export %s object in OBJ format!\n", hobStruct->objects[i].name);
|
||||
else
|
||||
printf("[INFO] Successfully exported %s object in OBJ format.\n", hobStruct->objects[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanUpMemory(hobStruct);
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
static int checkInputArgs(int arg_nbr, char *args[]) {
|
||||
int _o = 0x0002; // Default options parameters
|
||||
char test[256];
|
||||
int i;
|
||||
@ -69,7 +131,7 @@ int checkArgs(char *args[], int arg_nbr) {
|
||||
return _o;
|
||||
}
|
||||
|
||||
void createSubDir(char *dirName) {
|
||||
static void createSubDir(char *dirName) {
|
||||
if (dirName == NULL) return;
|
||||
char _dir[260]; //TODO: Change directory management
|
||||
strcpy(_dir, dirName);
|
||||
@ -82,10 +144,27 @@ void createSubDir(char *dirName) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void dispHelp() {
|
||||
static void cleanUpMemory(T_HOB* hobStruct) {
|
||||
int i,j;
|
||||
|
||||
for ( i=0; i<hobStruct->obj_count; i++ ) {
|
||||
for ( j=0; j<hobStruct->objects[i].face_group_count; j++ ) {
|
||||
|
||||
free(hobStruct->objects[i].face_groups[j].faces);
|
||||
free(hobStruct->objects[i].face_groups[j].vertices);
|
||||
}
|
||||
|
||||
free(hobStruct->objects[i].face_groups);
|
||||
}
|
||||
|
||||
free(hobStruct->objects);
|
||||
free(hobStruct);
|
||||
}
|
||||
|
||||
static inline void dispHelp() {
|
||||
printf("\n");
|
||||
printf("Options:\n -h Print this message\n -v Activate verbose console output\n -no-subdir Extract textures inside current folder\n");
|
||||
printf("\n");
|
||||
printf("Usage: RSE-Texture_%s [options] <hmt files...>\n", VERSION);
|
||||
printf("Usage: RSE-Model_%s [options] <hob files...>\n", VERSION);
|
||||
printf("\n");
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
#ifndef MAP_EXTRACTOR_H_
|
||||
#define MAP_EXTRACTOR_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include "config.h"
|
||||
#include "options.h"
|
||||
|
||||
|
||||
void createSubDir(char *dirName);
|
||||
int checkArgs(char *args[], int arg_nbr);
|
||||
//int exportTextures(HMT_FILE *hmt_f, char *filename);
|
||||
void dispHelp();
|
||||
|
||||
#endif
|
25
src/errors_types.h
Normal file
25
src/errors_types.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* errors_types.h
|
||||
*
|
||||
* Created on: 26 juil. 2022
|
||||
* Author: JackCarterSmith
|
||||
*/
|
||||
|
||||
#include "error.h" //TODO: use it as base for error ID
|
||||
|
||||
|
||||
#ifndef SRC_ERRORS_TYPES_H_
|
||||
#define SRC_ERRORS_TYPES_H_
|
||||
|
||||
#define NO_ERROR 0
|
||||
#define ERROR_GENERIC 1
|
||||
#define ERROR_MEMORY 2
|
||||
#define ERROR_IO 3
|
||||
#define ERROR_PROCESS 4
|
||||
|
||||
#define ERROR_ARGS_NULL 10
|
||||
#define ERROR_ARGS_RANGE 11
|
||||
|
||||
#define ERROR_REALITY_BROKED -1
|
||||
|
||||
#endif /* SRC_ERRORS_TYPES_H_ */
|
373
src/hob_parser.c
Normal file
373
src/hob_parser.c
Normal file
@ -0,0 +1,373 @@
|
||||
/*
|
||||
* hob_parser.c
|
||||
*
|
||||
* Created on: 26 juil. 2022
|
||||
* Author: JackCarterSmith
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "errors_types.h"
|
||||
#include "options.h"
|
||||
#include "hob_struct.h"
|
||||
#include "hob_parser.h"
|
||||
|
||||
|
||||
unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct) {
|
||||
unsigned char err = NO_ERROR;
|
||||
long fileSize;
|
||||
FILE* fStream = NULL;
|
||||
char* memFile = NULL;
|
||||
unsigned int i,j,k;
|
||||
unsigned int facesExtraOffset;
|
||||
int* offset_index = NULL;
|
||||
|
||||
if (hob_struct != NULL && fileName != NULL) {
|
||||
// Open file
|
||||
fStream = fopen(fileName, "rb");
|
||||
|
||||
if (fStream != NULL) {
|
||||
// Determine file size in bytes
|
||||
fseek(fStream, 0, SEEK_END);
|
||||
fileSize = ftell(fStream);
|
||||
fseek(fStream, 0, SEEK_SET);
|
||||
if (_options & VERBOSE_ENABLED) printf("[DBG] > Input file size: %ld bytes\n", fileSize);
|
||||
|
||||
memFile = malloc(fileSize + 1);
|
||||
if (memFile != NULL) {
|
||||
// Copy file in RAM
|
||||
fread(memFile, fileSize, 1, fStream);
|
||||
fclose(fStream);
|
||||
|
||||
// Retrieve object count from the header
|
||||
hob_struct->obj_count = ((T_HOBFILE_HEADER *)memFile)->obj_count;
|
||||
printf("[INFO] - Object(s) quantity: %d\n", hob_struct->obj_count);
|
||||
|
||||
if (hob_struct->obj_count > 0) {
|
||||
// Populate HOB structure with object descriptor
|
||||
hob_struct->objects = calloc(hob_struct->obj_count, sizeof(T_HOB_OBJECT));
|
||||
for ( i = 0; i < hob_struct->obj_count; i++ ) {
|
||||
// Get object name
|
||||
memcpy(hob_struct->objects[i].name, ((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile
|
||||
+ sizeof(T_HOBFILE_HEADER)
|
||||
+ sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->object_name, 16);
|
||||
if (_options & VERBOSE_ENABLED) printf("\n");
|
||||
printf("[INFO] - Process %s object...\n", hob_struct->objects[i].name);
|
||||
|
||||
// Get offsets
|
||||
hob_struct->objects[i].face_group_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile
|
||||
+ sizeof(T_HOBFILE_HEADER)
|
||||
+ sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->facegroup_offset;
|
||||
if (_options & VERBOSE_ENABLED) printf("[DBG] > Face group offset: 0x%X\n", hob_struct->objects[i].face_group_offset);
|
||||
hob_struct->objects[i].face_group_header_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile
|
||||
+ sizeof(T_HOBFILE_HEADER)
|
||||
+ sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->object_parts_offset;
|
||||
if (_options & VERBOSE_ENABLED) printf("[DBG] > Face group header/object parts offset: 0x%X\n", hob_struct->objects[i].face_group_header_offset);
|
||||
hob_struct->objects[i].face_group_header2_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile
|
||||
+ sizeof(T_HOBFILE_HEADER)
|
||||
+ sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->facegroup_header_2_offset;
|
||||
if (_options & VERBOSE_ENABLED) printf("[DBG] > Face group header2 offset: 0x%X\n", hob_struct->objects[i].face_group_header2_offset);
|
||||
|
||||
// Get count and offsets from the facegroup header
|
||||
hob_struct->objects[i].face_group_count = ((T_HOBFILE_FACEGROUP_HEADER *)(memFile
|
||||
+ hob_struct->objects[i].face_group_header_offset))->facegroup_count;
|
||||
if (_options & VERBOSE_ENABLED) printf("[DBG] > Face group count: %d\n", hob_struct->objects[i].face_group_count);
|
||||
hob_struct->objects[i].face_group_count0 = ((T_HOBFILE_FACEGROUP_HEADER *)(memFile
|
||||
+ hob_struct->objects[i].face_group_header_offset))->facegroup_count0;
|
||||
if (_options & VERBOSE_ENABLED) printf("[DBG] > Face group count0: %d\n", hob_struct->objects[i].face_group_count0);
|
||||
if (hob_struct->objects[i].face_group_count != hob_struct->objects[i].face_group_count0 && (_options & VERBOSE_ENABLED)) printf("[DBG] > Facegroup count are different!\n");
|
||||
|
||||
// Get facegroup datas
|
||||
offset_index = calloc(hob_struct->objects[i].face_group_count, sizeof(int));
|
||||
hob_struct->objects[i].face_groups = calloc(hob_struct->objects[i].face_group_count, sizeof(T_HOB_FACE_GROUP));
|
||||
for ( j = 0; j < hob_struct->objects[i].face_group_count; j++ ) {
|
||||
offset_index[j] = ((T_HOBFILE_FACEGROUP_OFFSET *)(memFile + hob_struct->objects[i].face_group_header_offset
|
||||
+ sizeof(T_HOBFILE_FACEGROUP_HEADER)
|
||||
+ sizeof(T_HOBFILE_FACEGROUP_OFFSET) * j))->facegroup_offset;
|
||||
if (_options & VERBOSE_ENABLED) printf("\n[DBG] > Face group meshdef0 offset: 0x%X\n", offset_index[j]);
|
||||
|
||||
// Get meshdef1 (mesh descriptor) offset
|
||||
hob_struct->objects[i].face_groups[j].meshdef1_offset = ((T_HOBFILE_MESHDEF0_0 *)(memFile
|
||||
+ offset_index[j]))->meshdef1_offset_plus_4;
|
||||
if (_options & VERBOSE_ENABLED) printf("[DBG] > Face group meshdef1 offset: 0x%X\n", hob_struct->objects[i].face_groups[j].meshdef1_offset);
|
||||
|
||||
if (hob_struct->objects[i].face_groups[j].meshdef1_offset > 0) {
|
||||
// Read meshdef1 datas
|
||||
hob_struct->objects[i].face_groups[j].face_block_end_offset = ((T_HOBFILE_MESHDEF1 *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].meshdef1_offset - 4))->facedef_end_offset;
|
||||
hob_struct->objects[i].face_groups[j].vertex_count = ((T_HOBFILE_MESHDEF1 *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].meshdef1_offset - 4))->vertex_count;
|
||||
hob_struct->objects[i].face_groups[j].face_block_offset = ((T_HOBFILE_MESHDEF1 *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].meshdef1_offset - 4))->faceblock_offset;
|
||||
if (_options & VERBOSE_ENABLED) printf("[DBG] > Faces offset: 0x%X\n", hob_struct->objects[i].face_groups[j].face_block_offset);
|
||||
hob_struct->objects[i].face_groups[j].vertex_block_offset = ((T_HOBFILE_MESHDEF1 *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].meshdef1_offset - 4))->vertexblocks_offset;
|
||||
if (_options & VERBOSE_ENABLED) printf("[DBG] > Vertex offset: 0x%X\n\n", hob_struct->objects[i].face_groups[j].vertex_block_offset);
|
||||
|
||||
// Get face datas
|
||||
if( ((T_HOBFILE_FACEBLOCK *)(memFile + hob_struct->objects[i].face_groups[j].face_block_offset))->reserved1 != 0 ||
|
||||
((T_HOBFILE_FACEBLOCK *)(memFile + hob_struct->objects[i].face_groups[j].face_block_offset))->reserved2 != 0 ) {
|
||||
if (_options & VERBOSE_ENABLED) printf("[DBG] > Face block: uncommon zero header!\n");
|
||||
}
|
||||
if ( ((T_HOBFILE_FACEBLOCK *)(memFile + hob_struct->objects[i].face_groups[j].face_block_offset))->facesOffset !=
|
||||
hob_struct->objects[i].face_groups[j].face_block_offset + sizeof(T_HOBFILE_FACEBLOCK)) {
|
||||
if (_options & VERBOSE_ENABLED) printf("[DBG] > Face block: uncommon face data offset position!\n");
|
||||
}
|
||||
hob_struct->objects[i].face_groups[j].face_count = ((T_HOBFILE_FACEBLOCK *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset))->faceCounts;
|
||||
hob_struct->objects[i].face_groups[j].faces = calloc(hob_struct->objects[i].face_groups[j].face_count, sizeof(T_HOB_FACE));
|
||||
facesExtraOffset = 0;
|
||||
for ( k = 0; k < hob_struct->objects[i].face_groups[j].face_count; k++ ) {
|
||||
// Get flags
|
||||
hob_struct->objects[i].face_groups[j].faces[k].flags = ((T_HOBFILE_FACES_HEADER *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->flags;
|
||||
|
||||
// Get unknown bytes
|
||||
hob_struct->objects[i].face_groups[j].faces[k].b1 = ((T_HOBFILE_FACES_HEADER *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->b1;
|
||||
hob_struct->objects[i].face_groups[j].faces[k].b2 = ((T_HOBFILE_FACES_HEADER *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->b2;
|
||||
hob_struct->objects[i].face_groups[j].faces[k].b3 = ((T_HOBFILE_FACES_HEADER *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->b3;
|
||||
|
||||
hob_struct->objects[i].face_groups[j].faces[k].bsize = ((T_HOBFILE_FACES_HEADER *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->faceBlockIntSize * 4; // Multiply by 4 to get the bytes exact number
|
||||
if (((T_HOBFILE_FACES_HEADER *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->headerSeparator != 0) {
|
||||
if (_options & VERBOSE_ENABLED) printf("[DBG] > Face header: uncommon separator!\n");
|
||||
}
|
||||
|
||||
// Get materials index
|
||||
hob_struct->objects[i].face_groups[j].faces[k].material_index = ((T_HOBFILE_FACES_HEADER *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->materialIndex;
|
||||
|
||||
// Get vertex indices
|
||||
memcpy(hob_struct->objects[i].face_groups[j].faces[k].indices,
|
||||
((T_HOBFILE_FACES_HEADER *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->vertexIndices,
|
||||
sizeof(unsigned short) * 4);
|
||||
|
||||
// Recalculate the dynamic extra bytes offset size - if present
|
||||
if (hob_struct->objects[i].face_groups[j].faces[k].flags_bits.fHasExtraBytesBeforeColor) facesExtraOffset += 8;
|
||||
|
||||
// Get vertex color - if present
|
||||
if (hob_struct->objects[i].face_groups[j].faces[k].flags_bits.fHasColor) {
|
||||
if (hob_struct->objects[i].face_groups[j].faces[k].flags_bits.fSeparateColorVertex) {
|
||||
hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[0] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->v1_rgba;
|
||||
hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[1] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->v2_rgba;
|
||||
hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[2] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->v3_rgba;
|
||||
if (hob_struct->objects[i].face_groups[j].faces[k].flags_bits.fIsQuad) {
|
||||
hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[3] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->v4_rgba;
|
||||
facesExtraOffset += sizeof(T_HOBFILE_FACES_VERTEX_COLOR);
|
||||
} else {
|
||||
facesExtraOffset += sizeof(T_HOBFILE_FACES_VERTEX_COLOR) - sizeof(T_RGBA);
|
||||
}
|
||||
} else {
|
||||
hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[0] = ((T_HOBFILE_FACES_COLOR *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->rgba;
|
||||
hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[1] = ((T_HOBFILE_FACES_COLOR *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->rgba;
|
||||
hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[2] = ((T_HOBFILE_FACES_COLOR *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->rgba;
|
||||
hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[3] = ((T_HOBFILE_FACES_COLOR *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->rgba;
|
||||
facesExtraOffset += sizeof(T_HOBFILE_FACES_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
// Get UV map - if present
|
||||
if (hob_struct->objects[i].face_groups[j].faces[k].flags_bits.fHasTexture) {
|
||||
hob_struct->objects[i].face_groups[j].faces[k].tex_coords[0] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->v1_texcoord;
|
||||
hob_struct->objects[i].face_groups[j].faces[k].tex_coords[1] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->v2_texcoord;
|
||||
hob_struct->objects[i].face_groups[j].faces[k].tex_coords[2] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->v3_texcoord;
|
||||
if (hob_struct->objects[i].face_groups[j].faces[k].flags_bits.fIsQuad) {
|
||||
hob_struct->objects[i].face_groups[j].faces[k].tex_coords[3] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].face_block_offset
|
||||
+ sizeof(T_HOBFILE_FACEBLOCK)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER)
|
||||
+ sizeof(T_HOBFILE_FACES_HEADER) * k
|
||||
+ facesExtraOffset))->v4_texcoord;
|
||||
facesExtraOffset += sizeof(T_HOBFILE_FACES_VERTEX_TEXTURE);
|
||||
} else {
|
||||
facesExtraOffset += sizeof(T_HOBFILE_FACES_VERTEX_TEXTURE) - sizeof(T_TEXCOORD);
|
||||
}
|
||||
}
|
||||
|
||||
if (_options & VERBOSE_ENABLED) {
|
||||
printf("[DBG] > Face %d details: 0x%X, %d, %d, %d, %d\n", k,
|
||||
hob_struct->objects[i].face_groups[j].faces[k].flags,
|
||||
hob_struct->objects[i].face_groups[j].faces[k].b1,
|
||||
hob_struct->objects[i].face_groups[j].faces[k].b2,
|
||||
hob_struct->objects[i].face_groups[j].faces[k].b3,
|
||||
hob_struct->objects[i].face_groups[j].faces[k].bsize
|
||||
);
|
||||
printf("[DBG] - Type is Quad: %d\n", hob_struct->objects[i].face_groups[j].faces[k].flags_bits.fIsQuad);
|
||||
printf("[DBG] - Material offset: 0x%X\n", hob_struct->objects[i].face_groups[j].faces[k].material_index);
|
||||
printf("[DBG] - Vertex indices: %d, %d, %d, %d\n",
|
||||
hob_struct->objects[i].face_groups[j].faces[k].indices[0],
|
||||
hob_struct->objects[i].face_groups[j].faces[k].indices[1],
|
||||
hob_struct->objects[i].face_groups[j].faces[k].indices[2],
|
||||
hob_struct->objects[i].face_groups[j].faces[k].indices[3]
|
||||
);
|
||||
printf("[DBG] - Vertex colors: 0x%X, 0x%X, 0x%X, 0x%X\n",
|
||||
hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[0],
|
||||
hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[1],
|
||||
hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[2],
|
||||
hob_struct->objects[i].face_groups[j].faces[k].vertex_colors[3]
|
||||
);
|
||||
printf("[DBG] - Vertex UV coord (divided by 4096):\n");
|
||||
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
|
||||
((double) 1/4096) * hob_struct->objects[i].face_groups[j].faces[k].tex_coords[0].u,
|
||||
hob_struct->objects[i].face_groups[j].faces[k].tex_coords[0].u,
|
||||
((double) 1/4096) * hob_struct->objects[i].face_groups[j].faces[k].tex_coords[0].v,
|
||||
hob_struct->objects[i].face_groups[j].faces[k].tex_coords[0].v
|
||||
);
|
||||
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
|
||||
((double) 1/4096) * hob_struct->objects[i].face_groups[j].faces[k].tex_coords[1].u,
|
||||
hob_struct->objects[i].face_groups[j].faces[k].tex_coords[1].u,
|
||||
((double) 1/4096) * hob_struct->objects[i].face_groups[j].faces[k].tex_coords[1].v,
|
||||
hob_struct->objects[i].face_groups[j].faces[k].tex_coords[1].v
|
||||
);
|
||||
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
|
||||
((double) 1/4096) * hob_struct->objects[i].face_groups[j].faces[k].tex_coords[2].u,
|
||||
hob_struct->objects[i].face_groups[j].faces[k].tex_coords[2].u,
|
||||
((double) 1/4096) * hob_struct->objects[i].face_groups[j].faces[k].tex_coords[2].v,
|
||||
hob_struct->objects[i].face_groups[j].faces[k].tex_coords[2].v
|
||||
);
|
||||
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
|
||||
((double) 1/4096) * hob_struct->objects[i].face_groups[j].faces[k].tex_coords[3].u,
|
||||
hob_struct->objects[i].face_groups[j].faces[k].tex_coords[3].u,
|
||||
((double) 1/4096) * hob_struct->objects[i].face_groups[j].faces[k].tex_coords[3].v,
|
||||
hob_struct->objects[i].face_groups[j].faces[k].tex_coords[3].v
|
||||
);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Get vertex datas
|
||||
hob_struct->objects[i].face_groups[j].vertices = calloc(hob_struct->objects[i].face_groups[j].vertex_count, sizeof(T_VERTEX));
|
||||
for ( k = 0; k < hob_struct->objects[i].face_groups[j].vertex_count; k++ ) {
|
||||
hob_struct->objects[i].face_groups[j].vertices[k].x = ((T_HOBFILE_VERTEX *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].vertex_block_offset
|
||||
+ sizeof(T_VERTEX) * k))->x;
|
||||
|
||||
hob_struct->objects[i].face_groups[j].vertices[k].y = ((T_HOBFILE_VERTEX *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].vertex_block_offset
|
||||
+ sizeof(T_VERTEX) * k))->y;
|
||||
|
||||
hob_struct->objects[i].face_groups[j].vertices[k].z = ((T_HOBFILE_VERTEX *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].vertex_block_offset
|
||||
+ sizeof(T_VERTEX) * k))->z;
|
||||
|
||||
hob_struct->objects[i].face_groups[j].vertices[k].w = ((T_HOBFILE_VERTEX *)(memFile
|
||||
+ hob_struct->objects[i].face_groups[j].vertex_block_offset
|
||||
+ sizeof(T_VERTEX) * k))->w; // Always 0???
|
||||
|
||||
if (_options & VERBOSE_ENABLED) printf("[DBG] > Found vertex %d: (%d, %d, %d)\n", k,
|
||||
hob_struct->objects[i].face_groups[j].vertices[k].x,
|
||||
hob_struct->objects[i].face_groups[j].vertices[k].y,
|
||||
hob_struct->objects[i].face_groups[j].vertices[k].z
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(offset_index);
|
||||
|
||||
} else {
|
||||
err = ERROR_GENERIC;
|
||||
printf("[INFO] Can't process empty file!\n");
|
||||
}
|
||||
|
||||
free(memFile);
|
||||
|
||||
} else {
|
||||
fclose(fStream);
|
||||
err = ERROR_MEMORY;
|
||||
if (_options & VERBOSE_ENABLED) printf("[ERR] Can't allocate enough memory for file processing!\n");
|
||||
}
|
||||
} else {
|
||||
err = ERROR_IO;
|
||||
if (_options & VERBOSE_ENABLED) printf("[ERR] Input file %s not found!\n", fileName);
|
||||
}
|
||||
} else err = ERROR_ARGS_NULL;
|
||||
|
||||
return err;
|
||||
}
|
14
src/hob_parser.h
Normal file
14
src/hob_parser.h
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* hob_parser.h
|
||||
*
|
||||
* Created on: 26 juil. 2022
|
||||
* Author: JackCarterSmith
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SRC_HOB_PARSER_H_
|
||||
#define SRC_HOB_PARSER_H_
|
||||
|
||||
unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct);
|
||||
|
||||
#endif /* SRC_HOB_PARSER_H_ */
|
264
src/hob_struct.h
Normal file
264
src/hob_struct.h
Normal file
@ -0,0 +1,264 @@
|
||||
/*
|
||||
* hob_struct.h
|
||||
*
|
||||
* Created on: 26 juil. 2022
|
||||
* Author: JackCarterSmith
|
||||
*/
|
||||
|
||||
#ifndef SRC_HOB_STRUCT_H_
|
||||
#define SRC_HOB_STRUCT_H_
|
||||
|
||||
|
||||
/*
|
||||
* long = 64bits???
|
||||
* int = 32bits
|
||||
* short = 16bits
|
||||
* car = 8bits
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// HOB file structure
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef unsigned int T_RGBA;
|
||||
|
||||
typedef struct vertex { short x,y,z,w; } T_VERTEX;
|
||||
|
||||
typedef struct tex_coord { unsigned short u,v; } T_TEXCOORD;
|
||||
|
||||
typedef struct face_flags {
|
||||
unsigned int fUnknown0:1;
|
||||
unsigned int fUnknown1:1;
|
||||
unsigned int fHasTexture:1;
|
||||
unsigned int fIsQuad:1;
|
||||
unsigned int fSeparateColorVertex:1;
|
||||
unsigned int fHasColor:1;
|
||||
unsigned int fHasExtraBytesBeforeColor:1;
|
||||
unsigned int fUnknown7:1;
|
||||
unsigned int fUnknown8:1;
|
||||
unsigned int fUnknown9:1;
|
||||
unsigned int fUnknown10:1;
|
||||
|
||||
unsigned int reserved:21;
|
||||
} FACE_FLAGS;
|
||||
|
||||
typedef struct hob_face {
|
||||
union {
|
||||
unsigned int flags;
|
||||
FACE_FLAGS flags_bits;
|
||||
};
|
||||
unsigned char b1;
|
||||
unsigned char b2;
|
||||
unsigned char b3;
|
||||
unsigned char bsize;
|
||||
unsigned short material_index;
|
||||
unsigned short indices[4];
|
||||
T_RGBA vertex_colors[4]; //TODO: convert in R:8_G:8_B:8_A:8 format? Caution with BE/LE conversion
|
||||
T_TEXCOORD tex_coords[4];
|
||||
} T_HOB_FACE;
|
||||
|
||||
typedef struct hob_face_group {
|
||||
unsigned int meshdef1_offset;
|
||||
|
||||
unsigned int face_block_end_offset;
|
||||
unsigned int face_block_offset;
|
||||
unsigned int vertex_block_offset;
|
||||
|
||||
unsigned int face_count;
|
||||
T_HOB_FACE* faces;
|
||||
|
||||
unsigned int vertex_count;
|
||||
T_VERTEX* vertices;
|
||||
} T_HOB_FACE_GROUP;
|
||||
|
||||
typedef struct hob_object {
|
||||
char name[16];
|
||||
unsigned int face_group_offset;
|
||||
unsigned int face_group_header_offset;
|
||||
unsigned int face_group_header2_offset;
|
||||
|
||||
unsigned int face_group_count;
|
||||
unsigned int face_group_count0;
|
||||
|
||||
T_HOB_FACE_GROUP* face_groups;
|
||||
} T_HOB_OBJECT;
|
||||
|
||||
/**
|
||||
* \brief Model-Extractor HOB structure of an HOB file content.
|
||||
* \details Used with malloc to create a clean method of bufferized
|
||||
* model datas before saving it.
|
||||
* \todo Export format to use it directly in other program.
|
||||
*/
|
||||
typedef struct hob {
|
||||
unsigned int obj_count;
|
||||
T_HOB_OBJECT* objects;
|
||||
} T_HOB;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Declaration of Memory Mapped Structure
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct __attribute__((packed)) hobfile_header {
|
||||
unsigned int obj_count;
|
||||
unsigned int vertices_offset;
|
||||
} T_HOBFILE_HEADER;
|
||||
|
||||
typedef struct __attribute__((packed)) hobfile_obj_descriptor {
|
||||
unsigned char object_name[16];
|
||||
unsigned int facegroup_offset;
|
||||
unsigned int object_parts_offset;
|
||||
unsigned int facegroup_header_2_offset;
|
||||
|
||||
unsigned int reserved1; // 12B of zeros
|
||||
unsigned int reserved2;
|
||||
unsigned int reserved3;
|
||||
|
||||
unsigned int unknown1;
|
||||
unsigned int unknown2;
|
||||
unsigned int unknown3;
|
||||
float unknown4;
|
||||
|
||||
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;
|
||||
|
||||
typedef struct __attribute__((packed)) hobfile_facegroup_header {
|
||||
unsigned short facegroup_count;
|
||||
unsigned short facegroup_count0;
|
||||
} T_HOBFILE_FACEGROUP_HEADER;
|
||||
|
||||
typedef struct __attribute__((packed)) hobfile_facegroup_offset {
|
||||
unsigned int unknown1;
|
||||
unsigned int facegroup_offset;
|
||||
} T_HOBFILE_FACEGROUP_OFFSET;
|
||||
|
||||
typedef struct __attribute__((packed)) hobfile_meshdef0_0 {
|
||||
unsigned int next_meshdef0_offset;
|
||||
unsigned int prev_meshdef0_offset_unsure;
|
||||
unsigned int offset_beginning_if_not_first;
|
||||
unsigned int offset_end_if_next_equal_0;
|
||||
unsigned int meshdef1_offset_plus_4;
|
||||
|
||||
unsigned int reserved1; // 8B of zeros
|
||||
unsigned int reserved2;
|
||||
} T_HOBFILE_MESHDEF0_0;
|
||||
|
||||
typedef struct __attribute__((packed)) hobfile_meshdef0_1 {
|
||||
float unknown1;
|
||||
|
||||
unsigned int reserved1; // 12B of zeros
|
||||
unsigned int reserved2;
|
||||
unsigned int reserved3;
|
||||
} T_HOBFILE_MESHDEF0_1;
|
||||
|
||||
typedef struct __attribute__((packed)) hobfile_meshdef0_2 {
|
||||
unsigned int Unknown1;
|
||||
|
||||
float unknown2; // Can be a vector???
|
||||
float unknown3;
|
||||
float unknown4;
|
||||
|
||||
float unknown5; // Can be a vector???
|
||||
float unknown6;
|
||||
float unknown7;
|
||||
|
||||
float unknown8; // Can be a matrix???
|
||||
float unknown9;
|
||||
float unknown10;
|
||||
float unknown11;
|
||||
|
||||
float unknown12; // Can be a vector???
|
||||
float unknown13;
|
||||
float unknown14;
|
||||
} T_HOBFILE_MESHDEF0_2;
|
||||
|
||||
typedef struct __attribute__((packed)) hobfile_meshdef1 {
|
||||
unsigned int facedef_end_offset;
|
||||
|
||||
unsigned int reserved1; // 20B of zeros
|
||||
unsigned int reserved2;
|
||||
unsigned int reserved3;
|
||||
unsigned int reserved4;
|
||||
unsigned int reserved5;
|
||||
|
||||
unsigned int vertex_count;
|
||||
unsigned int 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 __attribute__((packed)) hobfile_faceblock {
|
||||
unsigned int reserved1; // 8B of zeros
|
||||
unsigned int reserved2;
|
||||
|
||||
unsigned int facesOffset;
|
||||
unsigned int faceCounts;
|
||||
} T_HOBFILE_FACEBLOCK;
|
||||
|
||||
typedef struct __attribute__((packed)) hobfile_faces_header {
|
||||
unsigned int flags;
|
||||
unsigned char b1;
|
||||
unsigned char b2;
|
||||
unsigned char b3;
|
||||
unsigned char faceBlockIntSize; // Bytes size divided by 4, count as number of UInt32 type.
|
||||
unsigned short headerSeparator;
|
||||
unsigned short materialIndex;
|
||||
unsigned short vertexIndices[4]; // Relative to facegroup, the last value is equal to 0 when it's triangle shape.
|
||||
} T_HOBFILE_FACES_HEADER;
|
||||
|
||||
typedef struct __attribute__((packed)) hobfile_faces_extra_vertex_color {
|
||||
T_RGBA v1_rgba;
|
||||
T_RGBA v2_rgba;
|
||||
T_RGBA v3_rgba;
|
||||
T_RGBA v4_rgba; // Used with quad type face
|
||||
} T_HOBFILE_FACES_VERTEX_COLOR;
|
||||
|
||||
typedef struct __attribute__((packed)) hobfile_faces_extra_color {
|
||||
T_RGBA rgba;
|
||||
} T_HOBFILE_FACES_COLOR;
|
||||
|
||||
typedef struct __attribute__((packed)) hobfile_faces_extra_vertex_texture {
|
||||
T_TEXCOORD v1_texcoord; // Should be divided (no shifting) by 4096 to get 0...1 range
|
||||
T_TEXCOORD v2_texcoord;
|
||||
T_TEXCOORD v3_texcoord;
|
||||
T_TEXCOORD v4_texcoord; // Used with quad type face
|
||||
} T_HOBFILE_FACES_VERTEX_TEXTURE;
|
||||
|
||||
typedef struct __attribute__((packed)) hobfile_vertex {
|
||||
short x;
|
||||
short y;
|
||||
short z;
|
||||
short w;
|
||||
} T_HOBFILE_VERTEX;
|
||||
|
||||
#endif /* SRC_HOB_STRUCT_H_ */
|
94
src/obj_exporter.c
Normal file
94
src/obj_exporter.c
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* obj_exporter.c
|
||||
*
|
||||
* Created on: 27 juil. 2022
|
||||
* Author: JackCarterSmith
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "errors_types.h"
|
||||
#include "options.h"
|
||||
#include "hob_struct.h"
|
||||
#include "rlk/obj.h"
|
||||
#include "obj_exporter.h"
|
||||
|
||||
|
||||
unsigned char exportOBJModel(T_HOB_OBJECT* hob_objects, const char *out_path) {
|
||||
char objExport_path[128];
|
||||
char mtlExport_path[128];
|
||||
obj* objConstruct = NULL;
|
||||
unsigned int i,j;
|
||||
int surfID = 0, materialID = 0, tmpVertex = 0, tmpIndex = 0;
|
||||
float vertexBuff[3] = {0}, textureBuff[2] = {0};
|
||||
int indicesBuff[3] = {0};
|
||||
|
||||
if (hob_objects == NULL || out_path == NULL)
|
||||
return ERROR_ARGS_NULL;
|
||||
|
||||
if (_options & OUTPUT_DIR) {
|
||||
strcpy(objExport_path, out_path);
|
||||
#ifdef _WIN32
|
||||
strcat(objExport_path, "-out\\");
|
||||
#else
|
||||
strcat(objExport_path, "-out/");
|
||||
#endif
|
||||
strcat(objExport_path, hob_objects->name);
|
||||
} else {
|
||||
strcpy(objExport_path, hob_objects->name);
|
||||
}
|
||||
strcpy(mtlExport_path, objExport_path);
|
||||
strcat(objExport_path, ".obj");
|
||||
strcat(mtlExport_path, ".mtl");
|
||||
|
||||
objConstruct = obj_create(NULL);
|
||||
|
||||
// Build face/surface material group
|
||||
for ( i = 0; i < hob_objects->face_group_count; i++) {
|
||||
surfID = obj_add_surf(objConstruct);
|
||||
materialID = obj_add_mtrl(objConstruct);
|
||||
|
||||
// Build vertex container
|
||||
for ( j = 0; j < hob_objects->face_groups[i].vertex_count; j++ ) {
|
||||
tmpVertex = obj_add_vert(objConstruct);
|
||||
|
||||
vertexBuff[0] = ((float)1/1024) * -hob_objects->face_groups[i].vertices[j].x; // Invert X to fix mirror display
|
||||
vertexBuff[1] = ((float)1/1024) * -hob_objects->face_groups[i].vertices[j].y; // Invert Y to render upside up
|
||||
vertexBuff[2] = ((float)1/1024) * hob_objects->face_groups[i].vertices[j].z;
|
||||
|
||||
obj_set_vert_v(objConstruct, tmpVertex, vertexBuff);
|
||||
|
||||
//textureBuff[0] = ((float)1/1) * hob_objects->face_groups[i].
|
||||
|
||||
//obj_set_vert_t(objConstruct, tmpVertex, textureBuff);
|
||||
}
|
||||
|
||||
// Build indices container
|
||||
for ( j = 0; j < hob_objects->face_groups[i].face_count; j++ ) {
|
||||
tmpIndex = obj_add_poly(objConstruct, surfID);
|
||||
|
||||
indicesBuff[0] = (int)hob_objects->face_groups[i].faces[j].indices[0];
|
||||
indicesBuff[1] = (int)hob_objects->face_groups[i].faces[j].indices[1];
|
||||
indicesBuff[2] = (int)hob_objects->face_groups[i].faces[j].indices[2];
|
||||
|
||||
obj_set_poly(objConstruct, surfID, tmpIndex, indicesBuff);
|
||||
|
||||
// Process 2 triangles if face is Quad
|
||||
if (hob_objects->face_groups[i].faces[j].flags_bits.fIsQuad) {
|
||||
tmpIndex = obj_add_poly(objConstruct, surfID);
|
||||
|
||||
indicesBuff[0] = (int)hob_objects->face_groups[i].faces[j].indices[0];
|
||||
indicesBuff[1] = (int)hob_objects->face_groups[i].faces[j].indices[2];
|
||||
indicesBuff[2] = (int)hob_objects->face_groups[i].faces[j].indices[3];
|
||||
|
||||
obj_set_poly(objConstruct, surfID, tmpIndex, indicesBuff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
obj_write(objConstruct, objExport_path, NULL, 8);
|
||||
obj_delete(objConstruct);
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
20
src/obj_exporter.h
Normal file
20
src/obj_exporter.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* obj_exporter.h
|
||||
*
|
||||
* Created on: 27 juil. 2022
|
||||
* Author: JackCarterSmith
|
||||
*/
|
||||
|
||||
#ifndef SRC_OBJ_EXPORTER_H_
|
||||
#define SRC_OBJ_EXPORTER_H_
|
||||
|
||||
|
||||
typedef struct t_material {
|
||||
unsigned short hasTexture;
|
||||
unsigned short bpp;
|
||||
unsigned int gl_tex_id;
|
||||
} T_MATERIAL;
|
||||
|
||||
unsigned char exportOBJModel(T_HOB_OBJECT* hob_objects, const char *out_path);
|
||||
|
||||
#endif /* SRC_OBJ_EXPORTER_H_ */
|
Loading…
x
Reference in New Issue
Block a user