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
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
View File

@ -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')
}
}
}

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.
: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 .
```

View File

@ -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");
}

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