Push first version prototype
All checks were successful
JCS-Prod/RSE-Model/pipeline/head This commit looks good

This commit is contained in:
JackCarterSmith 2022-07-27 19:59:16 +02:00
commit 6bfecbec01
Signed by: JackCarterSmith
GPG Key ID: 832E52F4E23F8F24
11 changed files with 1024 additions and 118 deletions

View File

@ -23,8 +23,8 @@ include(CheckCSourceCompiles)
# needed packages # needed packages
find_package(GLEW REQUIRED) #find_package(GLEW REQUIRED)
include_directories(${GLEW_INCLUDE_DIR}) #include_directories(${GLEW_INCLUDE_DIR})
# define src/headers files # define src/headers files
@ -45,7 +45,7 @@ if(MSVC)
set_target_properties(rse-model PROPERTIES PREFIX "lib") set_target_properties(rse-model PROPERTIES PREFIX "lib")
set_target_properties(rse-model PROPERTIES IMPORT_PREFIX "lib") set_target_properties(rse-model PROPERTIES IMPORT_PREFIX "lib")
endif() endif()
target_link_libraries(rse-model ${GLEW_LIBRARIES}) target_link_libraries(rse-model m)
# add GPG signature command # add GPG signature command
#add_custom_command( #add_custom_command(

22
Jenkinsfile vendored
View File

@ -4,13 +4,14 @@ pipeline {
skipDefaultCheckout(true) skipDefaultCheckout(true)
} }
environment { environment {
CI_OUTPUT_NAME = "RSE_Model" CI_OUTPUT_NAME = "RSE_Texture"
CI_BUILD_NUMBER = "$BUILD_NUMBER" CI_BUILD_NUMBER = "$BUILD_NUMBER"
} }
stages { stages {
stage('Prepare') { stage('Prepare') {
steps { steps {
cleanWs() cleanWs()
rtConanClient(id: "conan", userHome: "/home/jackcartersmith")
} }
} }
stage('Build') { stage('Build') {
@ -18,14 +19,20 @@ pipeline {
parallel( parallel(
linux: { linux: {
dir("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']] cmakeBuild buildDir: 'build', installation: 'latest', steps: [[args: 'all']]
} }
}, },
windows: { windows: {
dir("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']]]) 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']]])
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']] 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}* .' sh 'cp ../linux/build/${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}* .'
} }
dir("zip_win") { 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' 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' 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' 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' sh 'mv mingw64.zip ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_mingw64.zip'
archiveArtifacts(artifacts: '*.zip')
fingerprint(targets: '*.zip')
} }
} }
stage('Sign') { stage('Sign') {
@ -50,7 +59,8 @@ pipeline {
sh 'ls -l' 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}_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' 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')
} }
} }
} }

View File

@ -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. 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 ## MODEL MODULE
It's extract texture datas from Rogue Squadron 3D (PC) game models files (HOB). 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 .
```

View File

@ -1,47 +1,109 @@
/* /*
================================================================================ ================================================================================
Name : Map-Extractor.c Name : Model-Extractor.c
Author : JackCarterSmith Author : JackCarterSmith
License : GPL-v3.0 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 <stdio.h>
#include "rlk/obj.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 int _options; // Global options settings variable
/*
* - MAIN -
*/
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
// Init buffer vars // 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 // Check if filenames arguments exist
if (argc < 2) { if (argc < 2) {
printf("\n[ERR] No input file/commands specified!\n"); printf("\n[ERR] No input file/commands specified!\n");
dispHelp(); dispHelp();
return EXIT_FAILURE; //TODO: implement own error codes system return ERROR_ARGS_NULL;
} }
_options = checkArgs(argv, argc); // Analyse program arguments _options = checkInputArgs(argc, argv); // Analyse program arguments
if (_options == -1) return EXIT_SUCCESS; if (_options == -1) return NO_ERROR;
return mainProcess(argc, argv);
}
// Do the work
for (file_index=(_options >> 8) & 0xFF; file_index<argc; file_index++) { // Manage multiple inputs files
/* /*
hmt_fdatas = extractDatasFromHMT(argv[file_index]); * Private functions definition
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)
*/ */
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;
} }
return EXIT_SUCCESS; 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);
}
}
} }
int checkArgs(char *args[], int arg_nbr) { cleanUpMemory(hobStruct);
return NO_ERROR;
}
static int checkInputArgs(int arg_nbr, char *args[]) {
int _o = 0x0002; // Default options parameters int _o = 0x0002; // Default options parameters
char test[256]; char test[256];
int i; int i;
@ -69,7 +131,7 @@ int checkArgs(char *args[], int arg_nbr) {
return _o; return _o;
} }
void createSubDir(char *dirName) { static void createSubDir(char *dirName) {
if (dirName == NULL) return; if (dirName == NULL) return;
char _dir[260]; //TODO: Change directory management char _dir[260]; //TODO: Change directory management
strcpy(_dir, dirName); strcpy(_dir, dirName);
@ -82,10 +144,27 @@ void createSubDir(char *dirName) {
#endif #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("\n");
printf("Options:\n -h Print this message\n -v Activate verbose console output\n -no-subdir Extract textures inside current folder\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("\n");
printf("Usage: RSE-Texture_%s [options] <hmt files...>\n", VERSION); printf("Usage: RSE-Model_%s [options] <hob files...>\n", VERSION);
printf("\n"); printf("\n");
} }

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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_ */