Merge pull request 'New library version of the RS parser' (#10) from lib-struct into master
All checks were successful
JCS-Prod/RSE-Model/pipeline/head This commit looks good

Reviewed-on: #10
This commit is contained in:
JackCarterSmith 2022-08-19 19:18:14 +02:00
commit 973f96c438
Signed by: JCS-Gitea
GPG Key ID: 7DB6770061C25C34
29 changed files with 1388 additions and 943 deletions

3
.gitignore vendored
View File

@ -15,7 +15,8 @@
# Precompiled Headers
*.gch
*.pch
src/config.h
RSPModelLib/src/config.h
RSEModel/src/config.h
# Libraries
*.lib

6
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "src/rlk"]
path = src/rlk
url = https://github.com/rlk/obj.git
[submodule "RSEModel/src/obj"]
path = RSEModel/src/obj
url = https://git.jcsmith.fr/jackcartersmith/obj.git

View File

@ -1,57 +1,52 @@
# CMakeLists.txt
# Written by JackCarterSmith, 2021
####################################################
# Written by JackCarterSmith, 2022
# This code is released under the RSE license.
####################################################
cmake_minimum_required(VERSION 3.1)
cmake_policy(VERSION 3.1)
# CMake requirement and general configuration
cmake_minimum_required(VERSION 3.12)
cmake_policy(VERSION 3.12)
set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
if(DEFINED ENV{MS_COMPATIBLE})
set(CMAKE_GNUtoMS ON) # Enable compatibility level to exported libraries
endif()
# define project
add_definitions(-DCONF_NO_GL)
if(DEFINED ENV{CI})
# Project definition
if(DEFINED ENV{CI}) # Jenkins CI integration mode
project(rse-model VERSION $ENV{CI_VERSION}.$ENV{CI_BUILD_NUMBER} DESCRIPTION "RogueSquadron Extractor - Model" LANGUAGES C)
set(RSE_MOD_NAME $ENV{CI_OUTPUT_NAME}-${PROJECT_VERSION})
else()
project(rse-model VERSION 1.0.0 DESCRIPTION "RogueSquadron Extractor - Model" LANGUAGES C)
set(RSE_MOD_NAME RSE_Model-${PROJECT_VERSION})
set(RSE_MODEL_NAME $ENV{CI_OUTPUT_NAME})
else() # Standalone project mode, should not be used for release.
project(rse-model VERSION 2.0.0 DESCRIPTION "RogueSquadron Extractor - Model" LANGUAGES C)
set(RSE_MODEL_NAME RSEModel)
endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/src/config.h @ONLY)
set(RSP_MODEL_LIB_NAME RSPModel${PROJECT_VERSION_MAJOR}${PROJECT_VERSION_MINOR})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
include(CheckIncludeFile)
include(CheckCSourceCompiles)
# Compilation option
option(RSPMODEL_SHARED "Build shared lib" ON)
# needed packages
# Push compile infos to source
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/RSPModelLib/src/config.h @ONLY)
#configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/RSEModel/src/config.h @ONLY)
#find_package(GLEW REQUIRED)
#include_directories(${GLEW_INCLUDE_DIR})
# define src/headers files
# The project is divided in two parts:
# - RSPModelLib is the parser library for model type data, it's take HOB file as input and output extracted datas.
# It is intended to be used by others apps like rendering engine or others.
# - RSEModel is the standalone application of the library, take HOB file in argument and output OBJ/MTL file.
# Artists or users can directly use this program to retrieve data in common datas format.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
add_subdirectory(RSPModelLib)
add_subdirectory(RSEModel)
FILE(GLOB_RECURSE RSE_MOD_SRCS src/*.c)
FILE(GLOB_RECURSE RSE_MOD_HRDS src/*.h)
SOURCE_GROUP("Source Files" FILES ${RSE_MOD_SRCS})
SOURCE_GROUP("Header Files" FILES ${RSE_MOD_HRDS})
# begin building RSE-Model
#set(CMAKE_BUILD_TYPE Debug)
#include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_executable(rse-model ${RSE_MOD_SRCS} ${RSE_MOD_HRDS})
#set_property(TARGET rse-model PROPERTY C_STANDARD 99)
set_target_properties(rse-model PROPERTIES OUTPUT_NAME ${RSE_MOD_NAME})
if(MSVC)
# msvc does not append 'lib' - do it here to have consistent name
#set_target_properties(rse-model PROPERTIES PREFIX "lib")
set_target_properties(rse-model PROPERTIES IMPORT_PREFIX "lib")
endif()
if(MSVC)
target_link_libraries(rse-model)
else()
target_link_libraries(rse-model m)
endif()
# add GPG signature command
# GPG signature custom command
#add_custom_command(
# OUTPUT ""
# COMMAND gpg --batch --detach-sign
@ -61,7 +56,23 @@ endif()
# VERBATIM
#)
# install executable
install(TARGETS rse-model
RUNTIME DESTINATION bin
# Install project executable
set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries")
set(INSTALL_INC_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Installation directory for headers")
if(RSPMODEL_SHARED)
set(RSE_MODEL_TARGETS_LIST rse-model rsp-model-lib rsp-model-libstatic)
else()
set(RSE_MODEL_TARGETS_LIST rse-model rsp-model-libstatic)
endif()
install(TARGETS ${RSE_MODEL_TARGETS_LIST}
RUNTIME DESTINATION ${INSTALL_BIN_DIR}
LIBRARY DESTINATION ${INSTALL_LIB_DIR}
ARCHIVE DESTINATION ${INSTALL_LIB_DIR}
)
# Install library includes
install(FILES ${RSP_PUBLIC_HRDS} DESTINATION ${INSTALL_INC_DIR})
# Install dependancies
install(FILES ${PROJECT_BINARY_DIR}/bin/glew32.dll
DESTINATION ${INSTALL_BIN_DIR})

25
Jenkinsfile vendored
View File

@ -4,8 +4,8 @@ pipeline {
skipDefaultCheckout(true)
}
environment {
CI_OUTPUT_NAME = "RSE_Model"
CI_VERSION = "1.0.1"
CI_OUTPUT_NAME = "RSEModel"
CI_VERSION = "2.0.0"
CI_BUILD_NUMBER = "$BUILD_NUMBER"
}
stages {
@ -23,7 +23,7 @@ pipeline {
checkout([$class: 'GitSCM', branches: [[name: '**']], browser: [$class: 'GiteaBrowser', repoUrl: 'https://git.jcsmith.fr/JCS-Prod/RSE-Model'], extensions: [], userRemoteConfigs: [[credentialsId: 'jenkins-ssh', url: 'ssh://git@git.jcsmith.fr:2322/JCS-Prod/RSE-Model.git']]])
sh 'git submodule update --init --recursive'
dir("build") {
rtConanRun(clientId: "conan", command: "install .. --build missing")
rtConanRun(clientId: "conan", command: "install .. --build=missing")
}
cmakeBuild buildDir: 'build', installation: 'latest', steps: [[args: 'all']]
}
@ -33,9 +33,9 @@ pipeline {
checkout([$class: 'GitSCM', branches: [[name: '**']], browser: [$class: 'GiteaBrowser', repoUrl: 'https://git.jcsmith.fr/JCS-Prod/RSE-Model'], extensions: [], userRemoteConfigs: [[credentialsId: 'jenkins-ssh', url: 'ssh://git@git.jcsmith.fr:2322/JCS-Prod/RSE-Model.git']]])
sh 'git submodule update --init --recursive'
dir("build") {
rtConanRun(clientId: "conan", command: "install .. --profile windows --build missing")
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']]
cmakeBuild buildDir: 'build', cmakeArgs: '-DGNU_HOST=x86_64-w64-mingw32 -DCMAKE_TOOLCHAIN_FILE=../cmake/mingw_cross_toolchain.cmake', installation: 'latest', steps: [[args: 'all']]
}
}
)
@ -44,16 +44,15 @@ pipeline {
stage('Deploy') {
steps {
dir("zip_linux") {
sh 'cp ../linux/build/${CI_OUTPUT_NAME}-${CI_VERSION}.${BUILD_NUMBER}* .'
sh 'cp -R ../linux/build/bin ../linux/build/lib ../linux/RSPModelLib/include .'
}
dir("zip_win") {
// sh 'cp ../windows/build/${CI_OUTPUT_NAME}-${CI_VERSION}.${BUILD_NUMBER}* ../windows/build/*.dll .'
sh 'cp ../windows/build/${CI_OUTPUT_NAME}-${CI_VERSION}.${BUILD_NUMBER}* .'
sh 'cp -R ../windows/build/bin ../windows/build/lib ../windows/RSPModelLib/include .'
}
zip archive: false, dir: 'zip_linux', exclude: '', glob: '', zipFile: 'x64.zip'
sh 'mv x64.zip ${CI_OUTPUT_NAME}-${CI_VERSION}.${BUILD_NUMBER}_x64.zip'
zip archive: false, dir: 'zip_linux', exclude: '', glob: '', zipFile: 'linux_x64.zip'
sh 'mv linux_x64.zip ${CI_OUTPUT_NAME}_${CI_VERSION}.${BUILD_NUMBER}_Linux_x86_64.zip'
zip archive: false, dir: 'zip_win', exclude: '', glob: '', zipFile: 'mingw64.zip'
sh 'mv mingw64.zip ${CI_OUTPUT_NAME}-${CI_VERSION}.${BUILD_NUMBER}_mingw64.zip'
sh 'mv mingw64.zip ${CI_OUTPUT_NAME}_${CI_VERSION}.${BUILD_NUMBER}_mingw64.zip'
archiveArtifacts(artifacts: '*.zip')
fingerprint(targets: '*.zip')
}
@ -61,8 +60,8 @@ pipeline {
stage('Sign') {
steps {
sh 'ls -l'
sh 'gpg --batch --detach-sign -o ${CI_OUTPUT_NAME}-${CI_VERSION}.${BUILD_NUMBER}_x64.zip.gpg ${CI_OUTPUT_NAME}-${CI_VERSION}.${BUILD_NUMBER}_x64.zip'
sh 'gpg --batch --detach-sign -o ${CI_OUTPUT_NAME}-${CI_VERSION}.${BUILD_NUMBER}_mingw64.zip.gpg ${CI_OUTPUT_NAME}-${CI_VERSION}.${BUILD_NUMBER}_mingw64.zip'
sh 'gpg --batch --detach-sign -o ${CI_OUTPUT_NAME}_${CI_VERSION}.${BUILD_NUMBER}_Linux_x86_64.zip.gpg ${CI_OUTPUT_NAME}_${CI_VERSION}.${BUILD_NUMBER}_Linux_x86_64.zip'
sh 'gpg --batch --detach-sign -o ${CI_OUTPUT_NAME}_${CI_VERSION}.${BUILD_NUMBER}_mingw64.zip.gpg ${CI_OUTPUT_NAME}_${CI_VERSION}.${BUILD_NUMBER}_mingw64.zip'
archiveArtifacts(artifacts: '*.gpg')
fingerprint(targets: '*.gpg')
}

73
LICENSE-glew.txt Normal file
View File

@ -0,0 +1,73 @@
The OpenGL Extension Wrangler Library
Copyright (C) 2002-2007, Milan Ikits <milan ikits[]ieee org>
Copyright (C) 2002-2007, Marcelo E. Magallon <mmagallo[]debian org>
Copyright (C) 2002, Lev Povalahev
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
Mesa 3-D graphics library
Version: 7.0
Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Copyright (c) 2007 The Khronos Group Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and/or associated documentation files (the
"Materials"), to deal in the Materials without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Materials, and to
permit persons to whom the Materials are furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Materials.
THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.

View File

@ -11,7 +11,7 @@ All modules are independants. This is the **'MODEL'** module.
## MODEL MODULE
It's extract texture datas from Rogue Squadron 3D (PC) game models files (HOB).
It's extract 3D rendering datas from Rogue Squadron 3D (PC) game models files (HOB).
This module can do:
- Extract objects inside HOB files to Wavefront OBJ format,
@ -21,11 +21,11 @@ This module can do:
## TODO
- Add textures to models.
- Discover all unknow fields, animation, bones mesh, etc.
- Discover all unknowns fields, animations, bones mesh, etc.
### Using
`RSE-Model_"version" [options] <hob files...>` or you can simply drag&drop HOB files on it.
`RSEModel [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.
@ -35,12 +35,13 @@ Due to issue with copyrights, I can't provide samples... You need to extract HOB
### Options
- -h Print this message
- -v Activate verbose output
- -v,-vv Activate verbose/debug output mode respectively
- -no-subdir Extract textures directly inside current folder
- -mtl Export materials datas with OBJ model
### Dependencies
- obj-lib: as obj file exporter. (https://github.com/rlk/obj)
- obj-lib: as obj file exporter. (https://git.jcsmith.fr/jackcartersmith/obj)
### Compiling

45
RSEModel/CMakeLists.txt Normal file
View File

@ -0,0 +1,45 @@
# CMakeLists.txt
####################################################
# Written by JackCarterSmith, 2022
# This code is released under the RSE license.
####################################################
# General configuration
include(CheckIncludeFile)
include(CheckCSourceCompiles)
add_definitions(-DCONF_NO_GL) # Used for obj-lib to not compile GL part
# Import needed packages and references their include path
#find_package(GLEW REQUIRED) # Enable when GL rendering is ready
#include_directories(${GLEW_INCLUDE_DIR})
# Define src/headers files
file(GLOB_RECURSE RSE_MOD_SOURCES ./src/*.c)
source_group("Source Files" FILES ${RSE_MOD_SOURCES})
# Building instructions for RSE-Model
if(DEFINED ENV{CI})
set(CMAKE_BUILD_TYPE RELEASE)
endif()
# Declare standalone application
add_executable(rse-model ${RSE_MOD_SOURCES})
set_property(TARGET rse-model PROPERTY C_STANDARD 90)
#target_include_directories(rse-model PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
set_target_properties(rse-model PROPERTIES OUTPUT_NAME ${RSE_MODEL_NAME})
# Link externals libraries to the linker
if(MSVC)
# msvc does not append 'lib' - do it here to have consistent name
set_target_properties(rse-model PROPERTIES IMPORT_PREFIX "lib")
target_link_libraries(rse-model PRIVATE rsp-model-libstatic ${GLEW_LIBRARIES})
else()
target_link_libraries(rse-model PRIVATE rsp-model-libstatic ${GLEW_LIBRARIES} m)
endif()

View File

@ -1,9 +1,10 @@
/**
* \file Model-Extractor.c
* \date 25/07/2022
* \author JackCarterSmith
* \copyright GPL-v3.0
* \brief HOB model parser and export to Waveform OBJ format.
* @file RSEModel.c
* @date 19/08/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief HOB model parser and export to Waveform OBJ format.
*
*/
#include <stdio.h>
@ -15,14 +16,13 @@
#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 <RSPModel.h>
#include <RSPModel_errordefs.h>
#include "obj_exporter.h"
/*
* Internal functions declarations
*/
@ -30,7 +30,7 @@
static unsigned int mainProcess(int args_cnt, char* args_value[], T_PROG_OPTIONS* opt_ptr);
static void createSubDir(char *dirName);
static unsigned char checkInputArgs(T_PROG_OPTIONS* opt_ptr, int p_arg_nbr, char* p_args[]);
static void cleanUpMemory(T_HOB* hobStruct);
static void cleanUpMemory(T_RSPMODEL_HOB* hobStruct);
static void dispHelp();
@ -42,19 +42,19 @@ int main(int argc, char *argv[]) {
unsigned char p;
// Hello world!
printf("\n*** RogueSquadron Extractor (RSE) - MODEL module - v%s ***\n", VERSION);
printf("\n*** RogueSquadron Extractor (RSE) - MODEL module - RSPModelLib v%s ***\n", RSPModel_getVersion());
// Check for arguments
if (argc < 2) {
printf("\n[ERR] No input file/commands specified!\n");
dispHelp();
return ERROR_ARGS_NULL;
return RSPLIB_ERROR_ARGS_NULL;
}
// Create options for programs according to user's arguments.
p = checkInputArgs(&_opts, argc, argv);
if ( p == ERROR_GENERIC ) return NO_ERROR;
else if ( p != NO_ERROR ) return p;
if ( p == RSPLIB_ERROR_GENERIC ) return RSPLIB_SUCCESS;
else if ( p != RSPLIB_SUCCESS ) return p;
return mainProcess(argc, argv, &_opts);
}
@ -66,26 +66,29 @@ int main(int argc, char *argv[]) {
static unsigned int mainProcess(int args_cnt, char* args_value[], T_PROG_OPTIONS* p_opts) {
unsigned short file_index;
T_HOB* hobStruct = NULL;
RSPMODEL_PARAMETERS libParams;
T_RSPMODEL_HOB* hobStruct = NULL;
int i;
libParams.raw = p_opts->raw & 0x7;
// Manage multiple inputs files
for ( file_index = p_opts->input_files_cnt; file_index < args_cnt; file_index++)
{
printf("\n=============================================\n[INFO] - Parsing file: %s ...\n", args_value[file_index]);
hobStruct = calloc(1, sizeof(T_HOB));
hobStruct = calloc(1, sizeof(T_RSPMODEL_HOB));
// Parse data from HOB file and put in T_HOB structure.
if (parseHOBFile(args_value[file_index], hobStruct, p_opts) != NO_ERROR) {
if (RSPModel_processHOBFile(hobStruct, args_value[file_index], libParams) != RSPLIB_SUCCESS) {
printf("[ERR] Failed to parse datas from %s\n", args_value[file_index]);
free(hobStruct);
return ERROR_PROCESS;
return RSPLIB_ERROR_PROCESS;
}
if (hobStruct->obj_count > 0) {
if (p_opts->output_dir) createSubDir(args_value[file_index]);
for ( i = 0; i < hobStruct->obj_count; i++ ) {
if (exportOBJModel(&(hobStruct->objects[i]), args_value[file_index], p_opts) != NO_ERROR)
if (exportOBJModel(&(hobStruct->objects[i]), args_value[file_index], p_opts) != RSPLIB_SUCCESS)
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);
@ -95,7 +98,7 @@ static unsigned int mainProcess(int args_cnt, char* args_value[], T_PROG_OPTIONS
cleanUpMemory(hobStruct);
return NO_ERROR;
return RSPLIB_SUCCESS;
}
static unsigned char checkInputArgs(T_PROG_OPTIONS* opt_ptr, int p_arg_nbr, char* p_args[]) {
@ -105,7 +108,6 @@ static unsigned char checkInputArgs(T_PROG_OPTIONS* opt_ptr, int p_arg_nbr, char
// Set default options
opt_ptr->raw = 0;
opt_ptr->output_dir = 1;
opt_ptr->export_mtl = 1;
if (p_arg_nbr > 1) {
for ( i = 1; i < p_arg_nbr; i++) {
@ -113,39 +115,42 @@ static unsigned char checkInputArgs(T_PROG_OPTIONS* opt_ptr, int p_arg_nbr, char
if (p_args[i][0] != '-') break;
if (strcmp(p_args[i], "-h") == 0) {
dispHelp();
return ERROR_GENERIC;
return RSPLIB_ERROR_GENERIC;
} else if (strcmp(p_args[i], "-v") == 0) {
opt_ptr->verbose_mode = 1;
printf("[OPTN] Verbose enabled.\n");
} else if (strcmp(p_args[i], "-vv") == 0) {
opt_ptr->verbose_mode = 1;
opt_ptr->debug_mode = 1;
printf("[OPTN] Debug enabled.\n");
} else if (strcmp(p_args[i], "-vvv") == 0) {
opt_ptr->verbose_mode = 1;
opt_ptr->debug_mode = 1;
opt_ptr->god_mode = 1;
printf("[OPTN] God damn it!\n");
} else if (strcmp(p_args[i], "-no-subdir") == 0) {
opt_ptr->output_dir = 0;
printf("[OPTN] Export to current directory.\n");
} else if (strcmp(p_args[i], "-mtl") == 0) {
opt_ptr->export_mtl = 0;
printf("[OPTN] No materials datas.\n");
opt_ptr->export_mtl = 1;
printf("[OPTN] Export materials datas.\n");
} else {
printf("[ERR] Unknown option: %s\n", p_args[i]);
}
}
opt_ptr->input_files_cnt = i;
return NO_ERROR;
return RSPLIB_SUCCESS;
}
return ERROR_ARGS_NULL;
return RSPLIB_ERROR_ARGS_NULL;
}
static void createSubDir(char *dirName) {
if (dirName == NULL) return;
char _dir[260]; //TODO: Change directory management
strcpy(_dir, dirName);
strcat(_dir, "-out");
char _dir[1024];
snprintf(_dir, 1024, "%s-out", dirName);
#ifdef _WIN32
CreateDirectory(_dir, NULL);
@ -154,7 +159,7 @@ static void createSubDir(char *dirName) {
#endif
}
static void cleanUpMemory(T_HOB* hobStruct) {
static void cleanUpMemory(T_RSPMODEL_HOB* hobStruct) {
int i,j;
for ( i=0; i<hobStruct->obj_count; i++ ) {
@ -176,8 +181,8 @@ static void dispHelp() {
printf("Options:\n -h Print this message\n");
printf(" -v -vv Activate verbose console output\n");
printf(" -no-subdir Export models inside current folder\n");
printf(" -no-mtl Disable materials datas export with model\n");
printf(" -mtl Export materials datas with model\n");
printf("\n");
printf("Usage: RSE-Model_%s [options] <hob files...>\n", VERSION);
printf("Usage: RSEModel [options] <hob files...>\n");
printf("\n");
}

1
RSEModel/src/obj Submodule

@ -0,0 +1 @@
Subproject commit 63f5977aaed661f6176daca101680bfcd80e80ec

View File

@ -1,26 +1,26 @@
/**
* \file obj_exporter.c
* \date 27/07/2022
* \author JackCarterSmith
* \copyright GPL-v3.0
* \brief Export datas to Waveform OBJ format.
* @file obj_exporter.c
* @date 27/07/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Export datas to Waveform OBJ format.
*
*/
#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 <RSPModel_datatypes.h>
#include <RSPModel_errordefs.h>
#include "obj/obj.h"
#include "obj_exporter.h"
static void mtlPathPatch(const char* out_file, const char* obj_name) ;
unsigned char exportOBJModel(T_HOB_OBJECT* hob_objects, const char *out_path, T_PROG_OPTIONS* p_opts) {
char objExport_path[128];
char mtlExport_path[128];
unsigned char exportOBJModel(T_RSPMODEL_OBJECT* hob_objects, const char *out_path, T_PROG_OPTIONS* p_opts) {
char exportPath[1024];
char objExport_name[128];
char mtlExport_name[128];
obj* objConstruct = NULL;
unsigned int i,j;
int surfID = 0, materialID = 0, tmpVertex = 0, tmpIndex = 0;
@ -29,22 +29,15 @@ unsigned char exportOBJModel(T_HOB_OBJECT* hob_objects, const char *out_path, T_
int indicesBuff[3] = {0};
if (hob_objects == NULL || out_path == NULL)
return ERROR_ARGS_NULL;
return RSPLIB_ERROR_ARGS_NULL;
if (p_opts->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\0");
strcat(mtlExport_path, ".mtl\0");
#ifdef _WIN32
snprintf(exportPath, 1024, "%s-out\\", out_path);
#else
snprintf(exportPath, 1024, "%s-out/", out_path);
#endif
snprintf(objExport_name, 128, "%s.obj", hob_objects->name);
snprintf(mtlExport_name, 128, "%s.mtl", hob_objects->name);
objConstruct = obj_create(NULL);
@ -107,61 +100,18 @@ unsigned char exportOBJModel(T_HOB_OBJECT* hob_objects, const char *out_path, T_
}
if (p_opts->export_mtl) {
obj_write(objConstruct, objExport_path, mtlExport_path, 8);
#if defined(__GNUC__) //TODO: review MSVC file management or include and rewrite obj lib?
if (p_opts->output_dir) mtlPathPatch(objExport_path, hob_objects->name);
#endif
} else obj_write(objConstruct, objExport_path, NULL, 8);
if (p_opts->output_dir)
obj_write(objConstruct, objExport_name, mtlExport_name, exportPath, 8);
else
obj_write(objConstruct, objExport_name, mtlExport_name, NULL, 8);
} else {
if (p_opts->output_dir)
obj_write(objConstruct, objExport_name, NULL, exportPath, 8);
else
obj_write(objConstruct, objExport_name, NULL, NULL, 8);
}
obj_delete(objConstruct);
return NO_ERROR;
}
static void mtlPathPatch(const char* out_file, const char* obj_name) {
FILE* obj = NULL;
char* memFile = NULL;
long fileSize,i,pos = 0,lines;
char _path[128],b;
obj = fopen(out_file, "r");
if ( obj != NULL ) {
fseek(obj, 0, SEEK_END);
fileSize = ftell(obj);
fseek(obj, 0, SEEK_SET);
// Find the end of first line
for ( i = 0; i < fileSize + 1; i++) {
b = (char)fgetc(obj);
if (b == '\n') {
if (pos == 0) pos = i;
lines++;
}
}
// Prepare mtl path for output
strcpy(_path, obj_name);
strcat(_path, ".mtl");
memFile = malloc(fileSize - (pos + lines));
if ( memFile != NULL ) {
// Read the rest of file in memory
fseek(obj, pos, SEEK_SET);
fread(memFile, fileSize - (pos + lines), 1, obj);
fclose(obj);
// Begin rewrite file
obj = fopen(out_file, "w");
fprintf(obj, "mtllib %s", _path);
#if defined(_MSC_VER)
fwrite(memFile, fileSize - pos , 1, obj);
#elif defined(__GNUC__)
fwrite(memFile, fileSize - (pos + lines), 1, obj);
#endif
free(memFile);
}
fclose(obj);
}
return RSPLIB_SUCCESS;
}

View File

@ -0,0 +1,22 @@
/**
* @file obj_exporter.h
* @date 27/07/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Export datas to Waveform OBJ format.
*
*/
#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_RSPMODEL_OBJECT* hob_objects, const char *out_path, T_PROG_OPTIONS* p_opts);
#endif /* SRC_OBJ_EXPORTER_H_ */

View File

@ -1,9 +1,10 @@
/**
* \file options.h
* \date 29/07/2022
* \author JackCarterSmith
* \copyright GPL-v3.0
* \brief Shared options structure definition and declaration.
* @file options.h
* @date 29/07/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Shared options structure definition and declaration.
*
*/
#ifndef OPTIONS_H_
@ -13,16 +14,13 @@
typedef union u_prog_options {
struct {
unsigned char verbose_mode:1; //!< Output simple details about ID and other "light" things.
unsigned char debug_mode:1; //!< Output all values of faces, indices and vertices and others "heavy" things.
unsigned char god_mode:1; //!< Dev only. Output experimental values.
unsigned char output_dir:1; //!< Export extracted datas to a sub-directory.
unsigned char export_mtl:1; //!< Export materials datas with object.
unsigned char reserved0:5; //!< For future use.
unsigned char debug_mode:1; //!< Output all values of faces, indices and vertices and others "heavy" things.
unsigned char god_mode:1; //!< Dev only. Output experimental values.
unsigned char reserved1:6; //!< For future use.
unsigned short reserved0:11; //!< For future use.
unsigned short input_files_cnt; //!< Internal files counters.
};

View File

@ -0,0 +1,67 @@
# CMakeLists.txt
####################################################
# Written by JackCarterSmith, 2022
# This code is released under the RSE license.
####################################################
# General library configuration
if(DEFINED ENV{MS_COMPATIBLE})
set(CMAKE_GNUtoMS ON) # Enable compatibility level to exported libraries
endif()
include(CheckIncludeFile)
include(CheckCSourceCompiles)
# Define src/headers files
file(GLOB_RECURSE RSP_MOD_SOURCES ./src/*.c)
source_group("Source Files" FILES ${RSP_MOD_SOURCES})
file(GLOB RSP_PUBLIC_HRDS ./include/*.h)
set(RSP_PUBLIC_HRDS ${RSP_PUBLIC_HRDS} PARENT_SCOPE)
# Building instructions for RSE-Model
if(DEFINED ENV{CI})
set(CMAKE_BUILD_TYPE RELEASE)
endif()
# Declare the shared library instance
if(RSPMODEL_SHARED)
add_library(rsp-model-lib SHARED ${RSP_MOD_SOURCES})
set_property(TARGET rsp-model-lib PROPERTY C_STANDARD 90)
target_include_directories(rsp-model-lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
set_target_properties(rsp-model-lib PROPERTIES OUTPUT_NAME ${RSP_MODEL_LIB_NAME})
set_target_properties(rsp-model-lib PROPERTIES DEFINE_SYMBOL RSPMODEL_DLL)
if(MSVC)
# msvc does not append 'lib' - do it here to have consistent name
set_target_properties(rsp-model-lib PROPERTIES PREFIX "lib")
set_target_properties(rsp-model-lib PROPERTIES IMPORT_PREFIX "lib")
endif()
endif()
# Declare the static library instance
add_library(rsp-model-libstatic STATIC ${RSP_MOD_SOURCES})
set_property(TARGET rsp-model-libstatic PROPERTY C_STANDARD 90)
target_include_directories(rsp-model-libstatic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
if(NOT MSVC)
set_target_properties(rsp-model-libstatic PROPERTIES OUTPUT_NAME "${RSP_MODEL_LIB_NAME}")
set_target_properties(rsp-model-libstatic PROPERTIES CLEAN_DIRECT_OUTPUT 1)
else()
set_target_properties(rsp-model-libstatic PROPERTIES OUTPUT_NAME "${RSP_MODEL_LIB_NAME}_static")
set_target_properties(rsp-model-libstatic PROPERTIES CLEAN_DIRECT_OUTPUT 1)
endif()
if(MSVC)
# msvc does not append 'lib' - do it here to have consistent name
set_target_properties(rsp-model-libstatic PROPERTIES PREFIX "lib")
set_target_properties(rsp-model-libstatic PROPERTIES IMPORT_PREFIX "lib")
endif()

View File

@ -0,0 +1,121 @@
/**
* @file RSPModel.h
* @date 11/08/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Rogue Squadron Parser model library, used to decode decode datas
* from original game file and access them through public interface.
*
*/
#include "RSPModel_datatypes.h"
#ifndef RSPMODEL_H_
#define RSPMODEL_H_
#if defined(_MSC_VER)
# define RSPMODEL_ABI_EXPORT __declspec(dllexport)
# define RSPMODEL_ABI_IMPORT __declspec(dllimport)
#elif __GNUC__ >= 4
# define RSPMODEL_ABI_EXPORT __attribute__ ((visibility("default")))
# define RSPMODEL_ABI_IMPORT __attribute__ ((visibility("default")))
#else
# define RSPMODEL_ABI_EXPORT
# define RSPMODEL_ABI_IMPORT
#endif
#if defined(RSPMODEL_DLL)
# if defined(WIN32)
# if defined(RSPMODEL_DLLBUILD)
# define RSPMODEL_EXTERN extern RSPMODEL_ABI_EXPORT
# else
# define RSPMODEL_EXTERN extern RSPMODEL_ABI_IMPORT
# endif
# endif
#endif
#ifndef RSPMODEL_EXTERN
# define RSPMODEL_EXTERN extern
#endif
#ifdef __cplusplus
extern "C" {
#endif
///////////////////////////////////////////////////////////////////////////////
// Library's functions declaration
///////////////////////////////////////////////////////////////////////////////
/**
* @brief Get the current library version.
* @return Char array of the version, escape char included.
*/
RSPMODEL_EXTERN char* RSPModel_getVersion( void );
/**
* @brief Run model parser for the specified file in file system.
* @details Model library can process HOB file from file system. It's a easy
* approach using this library for debugging purpose.
*
* @param[out] hob HOB structure to be filled with parsed datas.
* @param[in] filePath Path to the HOB file in system.
* @param[in] params Parser options. See RSPMODEL_PARAMETERS.
*
* @return Error status, return RSPLIB_SUCCESS in nominal case.
*/
RSPMODEL_EXTERN unsigned short RSPModel_processHOBFile(
T_RSPMODEL_HOB* hob, const char* const filePath,
const RSPMODEL_PARAMETERS params
);
/**
* @brief Run model parser for the specified file in memory.
* @details Model library can process HOB file directly stored in RAM memory,
* you must load the file beforehand through a malloc/memcpy call.
* @warning No controls routines are implemented to verify file length!
*
* @param[out] hob HOB structure to be filled with parsed datas.
* @param[in] memFilePtr Pointer to the beginning of the file in memory.
* @param[in] memFileSize Size of the file in bytes.
* @param[in] params Parser options. See RSPMODEL_PARAMETERS.
*
* @return Error status, return RSPLIB_SUCCESS in nominal case.
*/
RSPMODEL_EXTERN unsigned short RSPModel_processHOBFileMemory(
T_RSPMODEL_HOB* hob, const void* const memFilePtr, const long memFileSize,
const RSPMODEL_PARAMETERS params
);
/**
* @brief Convert HOB's object datas to GL compatible format.
* @note Only available if GL module as specified at compilation.
*
* @param[in] objStruct Object datas from previously parsed HOB file.
* @param[out] glObj GL structure.
*
* @return Error status, return RSPLIB_SUCCESS in nominal case.
*/
RSPMODEL_EXTERN unsigned short RSPModel_objectToGL(
const T_RSPMODEL_OBJECT* objStruct, void* glObj
);
/**
* @brief Convert HOB's object datas to Direct3D compatible format.
* @note Only available if D3D module as specified at compilation.
*
* @param[in] objStruct Object datas from previously parsed HOB file.
* @param[out] D3DObj Direct3D structure.
*
* @return Error status, return RSPLIB_SUCCESS in nominal case.
*/
RSPMODEL_EXTERN unsigned short RSPModel_objectToD3D(
const T_RSPMODEL_OBJECT* objStruct, void* D3DObj
);
#ifdef __cplusplus
}
#endif
#endif /* RSPMODEL_H_ */

View File

@ -0,0 +1,122 @@
/**
* @file RSPModel_datatypes.h
* @date 11/08/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief RSP Model workflow structures definitions
*
*/
#ifndef RSPMODEL_DATATYPES_H_
#define RSPMODEL_DATATYPES_H_
#ifdef __cplusplus
extern "C" {
#endif
///////////////////////////////////////////////////////////////////////////////
// Configuration structure
///////////////////////////////////////////////////////////////////////////////
typedef union u_rspmodel_parameters {
struct {
unsigned char verbose_mode:1; //!< Output simple details about ID and other "light" things.
unsigned char debug_mode:1; //!< Output all values of faces, indices and vertices and others "heavy" things.
unsigned char god_mode:1; //!< Dev only. Output experimental values.
unsigned char reserved0:5; //!< For future use.
};
unsigned char raw; //!< Raw options access for bit-masking or memory copy/compare.
} RSPMODEL_PARAMETERS ;
////////////////////////////////////////////////////////////////////////////////
// Lib's structure definitions
////////////////////////////////////////////////////////////////////////////////
typedef char* MEMFILE;
typedef unsigned int T_RGBA;
typedef struct vector3 { float x,y,z; } T_VECTOR3;
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_RSPMODEL_FACE;
typedef struct rspmodel_obj_parts {
unsigned int meshdef1_offset;
unsigned int face_block_end_offset;
unsigned int face_block_offset;
unsigned int vertex_block_offset;
unsigned int id;
T_VECTOR3 transform;
unsigned int face_count;
T_RSPMODEL_FACE* faces;
unsigned int vertex_count;
T_VERTEX* vertices;
} T_RSPMODEL_OBJ_PARTS;
typedef struct rspmodel_object {
char name[16];
unsigned int face_group_offset;
unsigned int object_part_header_offset;
unsigned int face_group_header_offset;
unsigned int object_part_count;
unsigned int face_group_count;
T_RSPMODEL_OBJ_PARTS* object_parts;
} T_RSPMODEL_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 rspmodel_hob {
unsigned int obj_count;
T_RSPMODEL_OBJECT* objects;
} T_RSPMODEL_HOB;
#ifdef __cplusplus
}
#endif
#endif /* RSPMODEL_DATATYPES_H_ */

View File

@ -0,0 +1,45 @@
/**
* @file RSPModel_errordefs.h
* @date 26/07/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Errors type definition file. Used mostly by methods in this project.
*
*/
#include <stdlib.h>
#ifndef RSPMODELLIB_ERRORS_H_
#define RSPMODELLIB_ERRORS_H_
#ifdef __cplusplus
extern "C" {
#endif
///////////////////////////////////////////////////////////////////////////////
// Errors types definitions
///////////////////////////////////////////////////////////////////////////////
#ifndef NO_ERROR
#define NO_ERROR 0 // In case of dual declaration by GCC
#endif
#define RSPLIB_SUCCESS NO_ERROR //!< All is running good!
#define RSPLIB_ERROR_GENERIC 1 //!< Misuse of the program
#define RSPLIB_ERROR_MEMORY 2 //!< Memory de/allocation failure
#define RSPLIB_ERROR_IO 3 //!< File system access failure
#define RSPLIB_ERROR_PROCESS 4 //!< Internal processing failure
#define RSPLIB_ERROR_ARGS_NULL 16 //!< Method not NULL input expected
#define RSPLIB_ERROR_ARGS_RANGE 17 //!< Method input out of expected range
#define RSPLIB_ERROR_MOD_DISABLED 64 //!< A necessary module hasn't been activated during compilation time
#define RSPLIB_ERROR_REALITY_BRK -1 //!< This error can only appear in alternate reality
#ifdef __cplusplus
}
#endif
#endif /* RSPMODELLIB_ERRORS_H_ */

View File

@ -0,0 +1,57 @@
/**
* @file RSPModel.c
* @date 11/08/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief HOB model parser and export to Waveform OBJ format.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "config.h"
#include "RSPModel_errordefs.h"
#include "hob_parser.h"
#include "RSPModel.h"
char* RSPModel_getVersion( void ) {
return PRG_VERSION;
}
unsigned short RSPModel_processHOBFile( T_RSPMODEL_HOB* hob, const char* const filePath,
const RSPMODEL_PARAMETERS params ) {
if ( hob == NULL || filePath == NULL ) return RSPLIB_ERROR_ARGS_NULL;
RSP_ModelLib_ParseHOBFile(filePath, hob, &params);
return RSPLIB_SUCCESS;
}
unsigned short RSPModel_processHOBFileMemory( T_RSPMODEL_HOB* hob, const void* const memFilePtr,
const long memFileSize, const RSPMODEL_PARAMETERS params ) {
if ( hob == NULL || memFilePtr == NULL ) return RSPLIB_ERROR_ARGS_NULL;
RSP_ModelLib_ParseHOBMemFile((MEMFILE)memFilePtr, hob, &params);
return RSPLIB_SUCCESS;
}
unsigned short RSPModel_objectToGL( const T_RSPMODEL_OBJECT* objStruct, void* glObj ) {
#ifndef GL_SUPPORT
return RSPLIB_ERROR_MOD_DISABLED;
#endif
return RSPLIB_SUCCESS;
}
unsigned short RSPModel_objectToD3D( const T_RSPMODEL_OBJECT* objStruct, void* D3DObj ) {
#ifndef D3D_SUPPORT
return RSPLIB_ERROR_MOD_DISABLED;
#endif
return RSPLIB_SUCCESS;
}

View File

@ -0,0 +1,439 @@
/**
* @file hob_parser.c
* @date 18/08/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Process HOB file structure and extract its datas.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "RSPModel_errordefs.h"
#include "RSPModel_datatypes.h"
#include "hob_struct.h"
#include "hob_parser.h"
////////////////////////////////////////////////////////////////////////////////
// Private functions declarations
////////////////////////////////////////////////////////////////////////////////
static unsigned int ExtractObjects(T_RSPMODEL_HOB*, const MEMFILE, const RSPMODEL_PARAMETERS*);
static unsigned int ExtractObjParts(T_RSPMODEL_OBJECT*, const MEMFILE, const RSPMODEL_PARAMETERS*);
static unsigned int ExtractObjParts_faces(T_RSPMODEL_OBJ_PARTS*, const MEMFILE, const RSPMODEL_PARAMETERS*);
static inline unsigned int ExtractObjpart_Face_Colors(T_RSPMODEL_FACE*, const char*);
static inline unsigned int ExtractObjpart_Face_UVMaps(T_RSPMODEL_FACE*, const char*);
////////////////////////////////////////////////////////////////////////////////
// Public functions definition
////////////////////////////////////////////////////////////////////////////////
unsigned char RSP_ModelLib_ParseHOBMemFile(const MEMFILE pMemFile, T_RSPMODEL_HOB* hobStruct, const RSPMODEL_PARAMETERS* pParams) {
unsigned char err = RSPLIB_SUCCESS;
if (hobStruct != NULL && pMemFile != NULL) {
// Do the magic!
err = ExtractObjects(hobStruct, pMemFile, pParams);
} else err = RSPLIB_ERROR_ARGS_NULL;
return err;
}
unsigned char RSP_ModelLib_ParseHOBFile(const char* fileName, T_RSPMODEL_HOB* hobStruct, const RSPMODEL_PARAMETERS* pParams) {
unsigned char err = RSPLIB_SUCCESS;
long fileSize;
FILE* fStream = NULL;
MEMFILE memFile = NULL;
if (hobStruct != 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 (pParams->verbose_mode) 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);
// Do the magic!
err = ExtractObjects(hobStruct, memFile, pParams);
free(memFile);
} else {
fclose(fStream);
err = RSPLIB_ERROR_MEMORY;
if (pParams->verbose_mode) printf("[ERR] Can't allocate enough memory for file processing!\n");
}
} else {
err = RSPLIB_ERROR_IO;
if (pParams->verbose_mode) printf("[ERR] Input file %s not found!\n", fileName);
}
} else err = RSPLIB_ERROR_ARGS_NULL;
return err;
}
////////////////////////////////////////////////////////////////////////////////
// Private functions definition
////////////////////////////////////////////////////////////////////////////////
/**
* @brief Count objects and extract datas from them.
*
* @param[in|out] pHobStruct Take root hob structure to get the T_RSPMODEL_OBJECT buffer and header datas.
* @param[in] pMemfile Pointer to an in-memory file location.
* @param[in] verbose
*
* @return Error code, RSPLIB_SUCCESS when no error.
*/
static unsigned int ExtractObjects(T_RSPMODEL_HOB* pHobStruct, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) {
unsigned int i;
if (pHobStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL;
// Retrieve object count from the header
pHobStruct->obj_count = ((T_HOBFILE_HEADER *)pMemfile)->obj_count;
printf("[INFO] - Object(s) quantity: %d\n", pHobStruct->obj_count);
if (pHobStruct->obj_count <= 0) {
printf("[INFO] Can't process empty file!\n");
return RSPLIB_ERROR_GENERIC;
}
// Populate HOB structure with object descriptor
pHobStruct->objects = calloc(pHobStruct->obj_count, sizeof(T_RSPMODEL_OBJECT));
if (pHobStruct->objects == NULL) return RSPLIB_ERROR_MEMORY;
for ( i = 0; i < pHobStruct->obj_count; i++ ) {
if (pParams->debug_mode) printf("\n-=====================-Begin of Object part-======================-\n");
// Get object name
memcpy(pHobStruct->objects[i].name, ((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER)
+ sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->object_name, 16);
if (pParams->verbose_mode) printf("\n");
printf("[INFO] - Process %s object...\n", pHobStruct->objects[i].name);
// Get offsets
pHobStruct->objects[i].face_group_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER)
+ sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->facegroup_offset;
if (pParams->verbose_mode) printf("[DBG] > Face group offset: 0x%X\n", pHobStruct->objects[i].face_group_offset);
pHobStruct->objects[i].object_part_header_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER)
+ sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->object_parts_offset;
if (pParams->verbose_mode) printf("[DBG] > Face group header/object parts offset: 0x%X\n", pHobStruct->objects[i].object_part_header_offset);
pHobStruct->objects[i].face_group_header_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER)
+ sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->facegroup_header_2_offset;
if (pParams->verbose_mode) printf("[DBG] > Face group header2 offset: 0x%X\n", pHobStruct->objects[i].face_group_header_offset);
if (pParams->god_mode) {
printf("[DBG] > Face group unknown1: %d\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknownOffset1);
printf("[DBG] > Face group unknown2: %d\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknownOffset2);
printf("[DBG] > Face group unknown3: %d\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknownOffset3);
printf("[DBG] > Face group unknown4: %.8f\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(pMemfile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknown4);
}
// Get count and offsets from the facegroup header
pHobStruct->objects[i].object_part_count = ((T_HOBFILE_FACEGROUP_HEADER *)(pMemfile
+ pHobStruct->objects[i].object_part_header_offset))->object_part_count;
if (pParams->verbose_mode) printf("[DBG] > Object parts count: %d\n", pHobStruct->objects[i].object_part_count);
pHobStruct->objects[i].face_group_count = ((T_HOBFILE_FACEGROUP_HEADER *)(pMemfile
+ pHobStruct->objects[i].object_part_header_offset))->facegroup_count;
if (pParams->verbose_mode) printf("[DBG] > Face groups count: %d\n", pHobStruct->objects[i].face_group_count);
if (pHobStruct->objects[i].object_part_count != pHobStruct->objects[i].face_group_count && (pParams->verbose_mode))
printf("[DBG] > Object parts / facegroup count are different!\n");
// Get facegroup datas
ExtractObjParts(&pHobStruct->objects[i], pMemfile, pParams);
}
return RSPLIB_SUCCESS;
}
/**
* @brief Count object's sub-part and extract datas from them.
*
* @param[in|out] pObject Take object structure to get the T_RSPMODEL_OBJ_PARTS buffer and object datas.
* @param[in] pMemfile Pointer to an in-memory file location.
* @param[in] verbose
*
* @return Error code, RSPLIB_SUCCESS when no error.
*/
static unsigned int ExtractObjParts(T_RSPMODEL_OBJECT* pObject, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) {
unsigned int i, subpart_offset = 0;
if (pObject == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL;
pObject->object_parts = calloc(pObject->object_part_count, sizeof(T_RSPMODEL_OBJ_PARTS));
if (pObject->object_parts == NULL) return RSPLIB_ERROR_MEMORY;
for ( i = 0; i < pObject->object_part_count; i++ ) {
if (pParams->debug_mode) printf("\n-----------------------Begin of Mesh part-------------------------\n");
subpart_offset = ((T_HOBFILE_FACEGROUP_OFFSET *)(pMemfile + pObject->object_part_header_offset
+ sizeof(T_HOBFILE_FACEGROUP_HEADER) + sizeof(T_HOBFILE_FACEGROUP_OFFSET) * i))->facegroup_offset;
if (pParams->verbose_mode) printf("\n[DBG] > Face group meshdef0 offset: 0x%X\n", subpart_offset);
// Get meshdef0 datas
if (pParams->god_mode) printf("[DBG] > meshdef0 offset1: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->offset1);
if (pParams->god_mode) printf("[DBG] > meshdef0 offset2: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->offset2);
if (pParams->verbose_mode) printf("[DBG] > Prev meshdef0 offset: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->prev_meshdef0_offset);
if (pParams->verbose_mode) printf("[DBG] > Next meshdef0 offset: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->next_meshdef0_offset);
if (pParams->god_mode) printf("[DBG] > meshdef0 unknown3: %.8f\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->unknown3);
if (pParams->god_mode) printf("[DBG] > meshdef0 unknown4: %.8f\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->unknown4);
if (pParams->god_mode) printf("[DBG] > meshdef0 unknown5: %.8f\n",((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->unknown5);
// Get meshdef1 (mesh descriptor) offset
pObject->object_parts[i].meshdef1_offset = ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->meshdef1_offset_plus_4;
if (pParams->verbose_mode) printf("\n[DBG] > Face group meshdef1 offset: 0x%X\n", pObject->object_parts[i].meshdef1_offset);
if( ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->reserved1 != 0 ||
((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->reserved2 != 0 ) {
if (pParams->god_mode) printf("[DBG] > Face group meshdef0: no 0!\n");
}
if (pObject->object_parts[i].meshdef1_offset > 0) {
// Read meshdef1 datas
pObject->object_parts[i].face_block_end_offset = ((T_HOBFILE_MESHDEF1 *)(pMemfile
+ pObject->object_parts[i].meshdef1_offset - 4))->facedef_end_offset;
pObject->object_parts[i].vertex_count = ((T_HOBFILE_MESHDEF1 *)(pMemfile
+ pObject->object_parts[i].meshdef1_offset - 4))->vertex_count;
pObject->object_parts[i].face_block_offset = ((T_HOBFILE_MESHDEF1 *)(pMemfile
+ pObject->object_parts[i].meshdef1_offset - 4))->faceblock_offset;
if (pParams->verbose_mode) printf("[DBG] > Faces offset: 0x%X\n", pObject->object_parts[i].face_block_offset);
pObject->object_parts[i].vertex_block_offset = ((T_HOBFILE_MESHDEF1 *)(pMemfile
+ pObject->object_parts[i].meshdef1_offset - 4))->vertexblocks_offset;
if (pParams->verbose_mode) printf("[DBG] > Vertex offset: 0x%X\n\n", pObject->object_parts[i].vertex_block_offset);
// Get faces datas
ExtractObjParts_faces(&pObject->object_parts[i], pMemfile, pParams);
}
// Get object part ID, used by animation? bones?
pObject->object_parts[i].id = ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->object_id;
if (pParams->verbose_mode) printf("\n[DBG] > Facegroup/object ID: %d\n", pObject->object_parts[i].id);
// Get the transform matrix, used by at-st and at-at (at this time)
pObject->object_parts[i].transform.x = ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->transform_x;
pObject->object_parts[i].transform.y = ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->transform_y;
pObject->object_parts[i].transform.z = ((T_HOBFILE_MESHDEF0 *)(pMemfile + subpart_offset))->transform_z;
if (pParams->god_mode) printf("\n[DBG] > Facegroup/object transform matrix: [%.8f %.8f %.8f]\n",
pObject->object_parts[i].transform.x,
pObject->object_parts[i].transform.y,
pObject->object_parts[i].transform.z
);
if (pParams->debug_mode) printf("\n-----------------------End of Mesh part---------------------------\n");
}
if (pParams->debug_mode) printf("\n-=====================-End of Object part-========================-\n");
return RSPLIB_SUCCESS;
}
/**
* @brief Extract datas from faces from object sub-part.
*
* @param[in|out] pObjPart Take object sub-part structure to get the T_RSPMODEL_FACE buffer and object sub-part datas.
* @param[in] pMemfile Pointer to an in-memory file location.
* @param[in] verbose
*
* @return Error code, RSPLIB_SUCCESS when no error.
*/
static unsigned int ExtractObjParts_faces(T_RSPMODEL_OBJ_PARTS* pObjPart, const MEMFILE pMemfile, const RSPMODEL_PARAMETERS* pParams) {
unsigned int i, facesExtraOffset = 0;
if (pObjPart == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL;
if( ((T_HOBFILE_FACEBLOCK *)(pMemfile + pObjPart->face_block_offset))->reserved1 != 0 ||
((T_HOBFILE_FACEBLOCK *)(pMemfile + pObjPart->face_block_offset))->reserved2 != 0 ) {
if (pParams->god_mode) printf("[DBG] > Face block: uncommon zero header!\n");
}
if ( ((T_HOBFILE_FACEBLOCK *)(pMemfile + pObjPart->face_block_offset))->facesOffset !=
pObjPart->face_block_offset + sizeof(T_HOBFILE_FACEBLOCK)) {
if (pParams->god_mode) printf("[DBG] > Face block: uncommon face data offset position!\n");
}
pObjPart->face_count = ((T_HOBFILE_FACEBLOCK *)(pMemfile + pObjPart->face_block_offset))->faceCounts;
pObjPart->faces = calloc(pObjPart->face_count, sizeof(T_RSPMODEL_FACE));
for ( i = 0; i < pObjPart->face_count; i++ ) {
if (pParams->debug_mode) printf("\n----------------------Begin of FaceGroup part----------------------\n");
// Get flags
pObjPart->faces[i].flags = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->flags;
// Get unknown bytes
pObjPart->faces[i].b1 = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->b1;
pObjPart->faces[i].b2 = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->b2;
pObjPart->faces[i].b3 = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->b3;
pObjPart->faces[i].bsize = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->faceBlockIntSize * 4; // Multiply by 4 to get the bytes exact number
if (((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset + sizeof(T_HOBFILE_FACEBLOCK)
+ sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->headerSeparator != 0) {
if (pParams->god_mode) printf("[DBG] > Face header: uncommon separator!\n");
}
// Get materials index
pObjPart->faces[i].material_index = ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->materialIndex;
// Get vertex indices
memcpy(pObjPart->faces[i].indices, ((T_HOBFILE_FACES_HEADER *)(pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) * i + facesExtraOffset))->vertexIndices,
sizeof(unsigned short) * 4);
// Recalculate the dynamic extra bytes offset size - if present
if (pObjPart->faces[i].flags_bits.fHasExtraBytesBeforeColor) facesExtraOffset += 8;
// Get vertex color - if present
if (pObjPart->faces[i].flags_bits.fHasColor) {
facesExtraOffset += ExtractObjpart_Face_Colors(&pObjPart->faces[i], pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) + sizeof(T_HOBFILE_FACES_HEADER) * i
+ facesExtraOffset);
}
// Get UV map - if present
if (pObjPart->faces[i].flags_bits.fHasTexture) {
facesExtraOffset += ExtractObjpart_Face_UVMaps(&pObjPart->faces[i], pMemfile + pObjPart->face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK) + sizeof(T_HOBFILE_FACES_HEADER) + sizeof(T_HOBFILE_FACES_HEADER) * i
+ facesExtraOffset);
}
if (pParams->debug_mode) {
printf("[DBG] > Face %d details: flags:0x%X b1:%d b2:%d b3%d bsize:%d\n", i, pObjPart->faces[i].flags,
pObjPart->faces[i].b1, pObjPart->faces[i].b2, pObjPart->faces[i].b3, pObjPart->faces[i].bsize);
printf("[DBG] - Type is Quad: %d\n", pObjPart->faces[i].flags_bits.fIsQuad);
printf("[DBG] - Material offset: 0x%X\n", pObjPart->faces[i].material_index);
printf("[DBG] - Vertex indices: %d, %d, %d, %d\n", pObjPart->faces[i].indices[0], pObjPart->faces[i].indices[1],
pObjPart->faces[i].indices[2], pObjPart->faces[i].indices[3]);
printf("[DBG] - Vertex colors: 0x%X, 0x%X, 0x%X, 0x%X\n", pObjPart->faces[i].vertex_colors[0],
pObjPart->faces[i].vertex_colors[1], pObjPart->faces[i].vertex_colors[2], pObjPart->faces[i].vertex_colors[3]);
printf("[DBG] - Vertex UV coord (divided by 4096):\n");
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
((double) 1/4096) * pObjPart->faces[i].tex_coords[0].u,
pObjPart->faces[i].tex_coords[0].u,
((double) 1/4096) * pObjPart->faces[i].tex_coords[0].v,
pObjPart->faces[i].tex_coords[0].v
);
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
((double) 1/4096) * pObjPart->faces[i].tex_coords[1].u,
pObjPart->faces[i].tex_coords[1].u,
((double) 1/4096) * pObjPart->faces[i].tex_coords[1].v,
pObjPart->faces[i].tex_coords[1].v
);
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
((double) 1/4096) * pObjPart->faces[i].tex_coords[2].u,
pObjPart->faces[i].tex_coords[2].u,
((double) 1/4096) * pObjPart->faces[i].tex_coords[2].v,
pObjPart->faces[i].tex_coords[2].v
);
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
((double) 1/4096) * pObjPart->faces[i].tex_coords[3].u,
pObjPart->faces[i].tex_coords[3].u,
((double) 1/4096) * pObjPart->faces[i].tex_coords[3].v,
pObjPart->faces[i].tex_coords[3].v
);
printf("\n");
}
if (pParams->debug_mode) printf("\n-----------------------End of FaceGroup part-----------------------\n");
}
// Get vertex datas
pObjPart->vertices = calloc(pObjPart->vertex_count, sizeof(T_VERTEX));
if (pObjPart->vertices == NULL) return RSPLIB_ERROR_MEMORY;
for ( i = 0; i < pObjPart->vertex_count; i++ ) {
pObjPart->vertices[i].x =
((T_HOBFILE_VERTEX *)(pMemfile + pObjPart->vertex_block_offset + sizeof(T_VERTEX) * i))->x;
pObjPart->vertices[i].y =
((T_HOBFILE_VERTEX *)(pMemfile + pObjPart->vertex_block_offset + sizeof(T_VERTEX) * i))->y;
pObjPart->vertices[i].z =
((T_HOBFILE_VERTEX *)(pMemfile + pObjPart->vertex_block_offset + sizeof(T_VERTEX) * i))->z;
pObjPart->vertices[i].w =
((T_HOBFILE_VERTEX *)(pMemfile + pObjPart->vertex_block_offset + sizeof(T_VERTEX) * i))->w; // Always 0???
if (pParams->debug_mode) printf("[DBG] > Found vertex %d: (%d, %d, %d)\n", i,
pObjPart->vertices[i].x, pObjPart->vertices[i].y, pObjPart->vertices[i].z
);
}
return RSPLIB_SUCCESS;
}
/**
* @brief Extract colors from HOB's face to T_RSPMODEL_FACE instance.
*
* @param pFace[out] Pointer to an empty instance of T_RSPMODEL_FACE.
* @param pFaceMemFileOffset[in] Pointer to the in-memory location of face HOB datas.
* @warning Access to an unallocated memory location using this function result in an ACCESS_VIOLATION.
*
* @return The size of processed data. Used to count new offset between each face in object sub-part.
*/
static inline unsigned int ExtractObjpart_Face_Colors(T_RSPMODEL_FACE* pFace, const char* pFaceMemFileOffset) {
unsigned int dynOffset = 0;
if (pFace->flags_bits.fSeparateColorVertex) {
pFace->vertex_colors[0] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(pFaceMemFileOffset))->v1_rgba;
pFace->vertex_colors[1] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(pFaceMemFileOffset))->v2_rgba;
pFace->vertex_colors[2] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(pFaceMemFileOffset))->v3_rgba;
if (pFace->flags_bits.fIsQuad) {
pFace->vertex_colors[3] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(pFaceMemFileOffset))->v4_rgba;
dynOffset += sizeof(T_HOBFILE_FACES_VERTEX_COLOR);
} else {
dynOffset += sizeof(T_HOBFILE_FACES_VERTEX_COLOR) - sizeof(T_RGBA);
}
} else {
pFace->vertex_colors[0] = ((T_HOBFILE_FACES_COLOR *)(pFaceMemFileOffset))->rgba;
pFace->vertex_colors[1] = ((T_HOBFILE_FACES_COLOR *)(pFaceMemFileOffset))->rgba;
pFace->vertex_colors[2] = ((T_HOBFILE_FACES_COLOR *)(pFaceMemFileOffset))->rgba;
pFace->vertex_colors[3] = ((T_HOBFILE_FACES_COLOR *)(pFaceMemFileOffset))->rgba;
dynOffset += sizeof(T_HOBFILE_FACES_COLOR);
}
return dynOffset;
}
/**
* @brief Extract UV maps from HOB's face to T_RSPMODEL_FACE instance.
*
* @param pFace[out] Pointer to an empty instance of T_RSPMODEL_FACE.
* @param pFaceMemFileOffset[in] Pointer to the in-memory location of face HOB datas.
* @warning Access to an unallocated memory location using this function result in an ACCESS_VIOLATION.
*
* @return The size of processed data. Used to count new offset between each face in object sub-part.
*/
static inline unsigned int ExtractObjpart_Face_UVMaps(T_RSPMODEL_FACE* pFace, const char* pFaceMemFileOffset) {
unsigned int dynOffset = 0;
pFace->tex_coords[0] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(pFaceMemFileOffset))->v1_texcoord;
pFace->tex_coords[1] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(pFaceMemFileOffset))->v2_texcoord;
pFace->tex_coords[2] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(pFaceMemFileOffset))->v3_texcoord;
if (pFace->flags_bits.fIsQuad) {
pFace->tex_coords[3] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(pFaceMemFileOffset))->v4_texcoord;
dynOffset += sizeof(T_HOBFILE_FACES_VERTEX_TEXTURE);
} else {
dynOffset += sizeof(T_HOBFILE_FACES_VERTEX_TEXTURE) - sizeof(T_TEXCOORD);
}
return dynOffset;
}

View File

@ -0,0 +1,51 @@
/**
* @file hob_parser.h
* @date 18/08/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Process HOB file structure and extract its datas.
*
*/
#include "RSPModel_datatypes.h"
#ifndef SRC_HOB_PARSER_H_
#define SRC_HOB_PARSER_H_
/**
* @brief Process HOB file stored in memory.
* @details Parser will directly extract objects count and information stored in
* HOB file and store them in T_RSPMODEL_HOB structure.
* @note Unmanaged mode
*
* @param[in] pMemFile Pointer to an in-memory HOB file location.
* @param[out] hobStruct Allocated empty T_RSPMODEL_HOB structure instance to
* be filled with HOB datas.
* @param[in] pParams Parser options. See RSPMODEL_PARAMETERS.
*
* @return Processing error code, RSPLIB_SUCCESS if no error.
*/
unsigned char RSP_ModelLib_ParseHOBMemFile(const MEMFILE pMemFile,
T_RSPMODEL_HOB* hobStruct, const RSPMODEL_PARAMETERS* pParams);
/**
* @brief Process HOB file in file system.
* @details HOB file is dumped in memory before parsing in order to enhance
* performance during parser operation and in optic to protect data
* stored in the original file (read-only).
* Parser will extract objects count and information stored in HOB file
* and store them in T_RSPMODEL_HOB structure.
* @note Managed mode
*
* @param[in] fileName String value of file name/path.
* @param[out] hobStruct Allocated empty T_RSPMODEL_HOB structure instance to
* be filled with HOB datas.
* @param[in] pParams Parser options. See RSPMODEL_PARAMETERS.
*
* @return Processing error code, RSPLIB_SUCCESS if no error.
*/
unsigned char RSP_ModelLib_ParseHOBFile(const char* fileName,
T_RSPMODEL_HOB* hobStruct, const RSPMODEL_PARAMETERS* pParams);
#endif /* SRC_HOB_PARSER_H_ */

View File

@ -1,12 +1,14 @@
/*
* hob_struct.h
/**
* @file hob_struct.h
* @date 26/07/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief HOB file mapping definition.
*
* Created on: 26 juil. 2022
* Author: JackCarterSmith
*/
#ifndef SRC_HOB_STRUCT_H_
#define SRC_HOB_STRUCT_H_
#ifndef RSPMODELLIB_HOB_STRUCT_H_
#define RSPMODELLIB_HOB_STRUCT_H_
/*
@ -22,90 +24,6 @@
#define PACK __attribute__((packed))
#endif
///////////////////////////////////////////////////////////////////////////////
// HOB file structure
///////////////////////////////////////////////////////////////////////////////
typedef unsigned int T_RGBA;
typedef struct vector3 { float x,y,z; } T_VECTOR3;
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 id;
T_VECTOR3 transform;
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 object_part_header_offset;
unsigned int face_group_header_offset;
unsigned int object_part_count;
unsigned int face_group_count;
T_HOB_FACE_GROUP* object_parts;
} 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
// Caution: the place of variable is important for correct mapping!
@ -289,4 +207,4 @@ typedef struct PACK hobfile_vertex {
#pragma pack(pop)
#endif
#endif /* SRC_HOB_STRUCT_H_ */
#endif /* RSPMODELLIB_HOB_STRUCT_H_ */

View File

@ -9,3 +9,4 @@ cmake_find_package
glew:shared=True
[imports]
bin, *.dll -> ./bin

6
config.h.in Normal file
View File

@ -0,0 +1,6 @@
#ifndef CONFIG_H_
#define CONFIG_H_
#define PRG_VERSION "@PROJECT_VERSION@"
#endif /* CONFIG_H_ */

View File

@ -1 +0,0 @@
#define VERSION "@PROJECT_VERSION@"

View File

@ -1,28 +0,0 @@
/*
* 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_
#ifdef NO_ERROR
#undef NO_ERROR
#endif
#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_ */

View File

@ -1,422 +0,0 @@
/**
* \file hob_parser.c
* \date 26/07/2022
* \author JackCarterSmith
* \copyright GPL-v3.0
* \brief Decode HOB file structure.
*/
#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, T_PROG_OPTIONS* p_opts) {
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 (p_opts->verbose_mode) 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++ ) {
if (p_opts->debug_mode) printf("\n-=====================-Begin of Object part-======================-\n");
// 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 (p_opts->verbose_mode) 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 (p_opts->verbose_mode) printf("[DBG] > Face group offset: 0x%X\n", hob_struct->objects[i].face_group_offset);
hob_struct->objects[i].object_part_header_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile
+ sizeof(T_HOBFILE_HEADER)
+ sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->object_parts_offset;
if (p_opts->verbose_mode) printf("[DBG] > Face group header/object parts offset: 0x%X\n", hob_struct->objects[i].object_part_header_offset);
hob_struct->objects[i].face_group_header_offset = ((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile
+ sizeof(T_HOBFILE_HEADER)
+ sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->facegroup_header_2_offset;
if (p_opts->verbose_mode) printf("[DBG] > Face group header2 offset: 0x%X\n", hob_struct->objects[i].face_group_header_offset);
if (p_opts->god_mode) {
printf("[DBG] > Face group unknown1: %d\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknownOffset1);
printf("[DBG] > Face group unknown2: %d\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknownOffset2);
printf("[DBG] > Face group unknown3: %d\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknownOffset3);
printf("[DBG] > Face group unknown4: %.8f\n",((T_HOBFILE_OBJ_DESCRIPTOR *)(memFile + sizeof(T_HOBFILE_HEADER) + sizeof(T_HOBFILE_OBJ_DESCRIPTOR) * i))->unknown4);
}
// Get count and offsets from the facegroup header
hob_struct->objects[i].object_part_count = ((T_HOBFILE_FACEGROUP_HEADER *)(memFile
+ hob_struct->objects[i].object_part_header_offset))->object_part_count;
if (p_opts->verbose_mode) printf("[DBG] > Object parts count: %d\n", hob_struct->objects[i].object_part_count);
hob_struct->objects[i].face_group_count = ((T_HOBFILE_FACEGROUP_HEADER *)(memFile
+ hob_struct->objects[i].object_part_header_offset))->facegroup_count;
if (p_opts->verbose_mode) printf("[DBG] > Face groups count: %d\n", hob_struct->objects[i].face_group_count);
if (hob_struct->objects[i].object_part_count != hob_struct->objects[i].face_group_count && (p_opts->verbose_mode)) printf("[DBG] > Object parts / facegroup count are different!\n");
// Get facegroup datas
offset_index = calloc(hob_struct->objects[i].object_part_count, sizeof(int));
hob_struct->objects[i].object_parts = calloc(hob_struct->objects[i].object_part_count, sizeof(T_HOB_FACE_GROUP));
for ( j = 0; j < hob_struct->objects[i].object_part_count; j++ ) {
if (p_opts->debug_mode) printf("\n-----------------------Begin of Mesh part-------------------------\n");
offset_index[j] = ((T_HOBFILE_FACEGROUP_OFFSET *)(memFile + hob_struct->objects[i].object_part_header_offset
+ sizeof(T_HOBFILE_FACEGROUP_HEADER)
+ sizeof(T_HOBFILE_FACEGROUP_OFFSET) * j))->facegroup_offset;
if (p_opts->verbose_mode) printf("\n[DBG] > Face group meshdef0 offset: 0x%X\n", offset_index[j]);
// Get meshdef0 datas
if (p_opts->god_mode) printf("[DBG] > meshdef0 offset1: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->offset1);
if (p_opts->god_mode) printf("[DBG] > meshdef0 offset2: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->offset2);
if (p_opts->verbose_mode) printf("[DBG] > Prev meshdef0 offset: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->prev_meshdef0_offset);
if (p_opts->verbose_mode) printf("[DBG] > Next meshdef0 offset: 0x%X\n",((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->next_meshdef0_offset);
if (p_opts->god_mode) printf("[DBG] > meshdef0 unknown3: %.8f\n",((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->unknown3);
if (p_opts->god_mode) printf("[DBG] > meshdef0 unknown4: %.8f\n",((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->unknown4);
if (p_opts->god_mode) printf("[DBG] > meshdef0 unknown5: %.8f\n",((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->unknown5);
// Get meshdef1 (mesh descriptor) offset
hob_struct->objects[i].object_parts[j].meshdef1_offset = ((T_HOBFILE_MESHDEF0 *)(memFile
+ offset_index[j]))->meshdef1_offset_plus_4;
if (p_opts->verbose_mode) printf("\n[DBG] > Face group meshdef1 offset: 0x%X\n", hob_struct->objects[i].object_parts[j].meshdef1_offset);
if( ((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->reserved1 != 0 ||
((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->reserved2 != 0 ) {
if (p_opts->god_mode) printf("[DBG] > Face group meshdef0: no 0!\n");
}
if (hob_struct->objects[i].object_parts[j].meshdef1_offset > 0) {
// Read meshdef1 datas
hob_struct->objects[i].object_parts[j].face_block_end_offset = ((T_HOBFILE_MESHDEF1 *)(memFile
+ hob_struct->objects[i].object_parts[j].meshdef1_offset - 4))->facedef_end_offset;
hob_struct->objects[i].object_parts[j].vertex_count = ((T_HOBFILE_MESHDEF1 *)(memFile
+ hob_struct->objects[i].object_parts[j].meshdef1_offset - 4))->vertex_count;
hob_struct->objects[i].object_parts[j].face_block_offset = ((T_HOBFILE_MESHDEF1 *)(memFile
+ hob_struct->objects[i].object_parts[j].meshdef1_offset - 4))->faceblock_offset;
if (p_opts->verbose_mode) printf("[DBG] > Faces offset: 0x%X\n", hob_struct->objects[i].object_parts[j].face_block_offset);
hob_struct->objects[i].object_parts[j].vertex_block_offset = ((T_HOBFILE_MESHDEF1 *)(memFile
+ hob_struct->objects[i].object_parts[j].meshdef1_offset - 4))->vertexblocks_offset;
if (p_opts->verbose_mode) printf("[DBG] > Vertex offset: 0x%X\n\n", hob_struct->objects[i].object_parts[j].vertex_block_offset);
// Get face datas
if( ((T_HOBFILE_FACEBLOCK *)(memFile + hob_struct->objects[i].object_parts[j].face_block_offset))->reserved1 != 0 ||
((T_HOBFILE_FACEBLOCK *)(memFile + hob_struct->objects[i].object_parts[j].face_block_offset))->reserved2 != 0 ) {
if (p_opts->god_mode) printf("[DBG] > Face block: uncommon zero header!\n");
}
if ( ((T_HOBFILE_FACEBLOCK *)(memFile + hob_struct->objects[i].object_parts[j].face_block_offset))->facesOffset !=
hob_struct->objects[i].object_parts[j].face_block_offset + sizeof(T_HOBFILE_FACEBLOCK)) {
if (p_opts->god_mode) printf("[DBG] > Face block: uncommon face data offset position!\n");
}
hob_struct->objects[i].object_parts[j].face_count = ((T_HOBFILE_FACEBLOCK *)(memFile
+ hob_struct->objects[i].object_parts[j].face_block_offset))->faceCounts;
hob_struct->objects[i].object_parts[j].faces = calloc(hob_struct->objects[i].object_parts[j].face_count, sizeof(T_HOB_FACE));
facesExtraOffset = 0;
for ( k = 0; k < hob_struct->objects[i].object_parts[j].face_count; k++ ) {
if (p_opts->debug_mode) printf("\n----------------------Begin of FaceGroup part----------------------\n");
// Get flags
hob_struct->objects[i].object_parts[j].faces[k].flags = ((T_HOBFILE_FACES_HEADER *)(memFile
+ hob_struct->objects[i].object_parts[j].face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK)
+ sizeof(T_HOBFILE_FACES_HEADER) * k
+ facesExtraOffset))->flags;
// Get unknown bytes
hob_struct->objects[i].object_parts[j].faces[k].b1 = ((T_HOBFILE_FACES_HEADER *)(memFile
+ hob_struct->objects[i].object_parts[j].face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK)
+ sizeof(T_HOBFILE_FACES_HEADER) * k
+ facesExtraOffset))->b1;
hob_struct->objects[i].object_parts[j].faces[k].b2 = ((T_HOBFILE_FACES_HEADER *)(memFile
+ hob_struct->objects[i].object_parts[j].face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK)
+ sizeof(T_HOBFILE_FACES_HEADER) * k
+ facesExtraOffset))->b2;
hob_struct->objects[i].object_parts[j].faces[k].b3 = ((T_HOBFILE_FACES_HEADER *)(memFile
+ hob_struct->objects[i].object_parts[j].face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK)
+ sizeof(T_HOBFILE_FACES_HEADER) * k
+ facesExtraOffset))->b3;
hob_struct->objects[i].object_parts[j].faces[k].bsize = ((T_HOBFILE_FACES_HEADER *)(memFile
+ hob_struct->objects[i].object_parts[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].object_parts[j].face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK)
+ sizeof(T_HOBFILE_FACES_HEADER) * k
+ facesExtraOffset))->headerSeparator != 0) {
if (p_opts->god_mode) printf("[DBG] > Face header: uncommon separator!\n");
}
// Get materials index
hob_struct->objects[i].object_parts[j].faces[k].material_index = ((T_HOBFILE_FACES_HEADER *)(memFile
+ hob_struct->objects[i].object_parts[j].face_block_offset
+ sizeof(T_HOBFILE_FACEBLOCK)
+ sizeof(T_HOBFILE_FACES_HEADER) * k
+ facesExtraOffset))->materialIndex;
// Get vertex indices
memcpy(hob_struct->objects[i].object_parts[j].faces[k].indices,
((T_HOBFILE_FACES_HEADER *)(memFile
+ hob_struct->objects[i].object_parts[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].object_parts[j].faces[k].flags_bits.fHasExtraBytesBeforeColor) facesExtraOffset += 8;
// Get vertex color - if present
if (hob_struct->objects[i].object_parts[j].faces[k].flags_bits.fHasColor) {
if (hob_struct->objects[i].object_parts[j].faces[k].flags_bits.fSeparateColorVertex) {
hob_struct->objects[i].object_parts[j].faces[k].vertex_colors[0] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(memFile
+ hob_struct->objects[i].object_parts[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].object_parts[j].faces[k].vertex_colors[1] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(memFile
+ hob_struct->objects[i].object_parts[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].object_parts[j].faces[k].vertex_colors[2] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(memFile
+ hob_struct->objects[i].object_parts[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].object_parts[j].faces[k].flags_bits.fIsQuad) {
hob_struct->objects[i].object_parts[j].faces[k].vertex_colors[3] = ((T_HOBFILE_FACES_VERTEX_COLOR *)(memFile
+ hob_struct->objects[i].object_parts[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].object_parts[j].faces[k].vertex_colors[0] = ((T_HOBFILE_FACES_COLOR *)(memFile
+ hob_struct->objects[i].object_parts[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].object_parts[j].faces[k].vertex_colors[1] = ((T_HOBFILE_FACES_COLOR *)(memFile
+ hob_struct->objects[i].object_parts[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].object_parts[j].faces[k].vertex_colors[2] = ((T_HOBFILE_FACES_COLOR *)(memFile
+ hob_struct->objects[i].object_parts[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].object_parts[j].faces[k].vertex_colors[3] = ((T_HOBFILE_FACES_COLOR *)(memFile
+ hob_struct->objects[i].object_parts[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].object_parts[j].faces[k].flags_bits.fHasTexture) {
hob_struct->objects[i].object_parts[j].faces[k].tex_coords[0] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(memFile
+ hob_struct->objects[i].object_parts[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].object_parts[j].faces[k].tex_coords[1] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(memFile
+ hob_struct->objects[i].object_parts[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].object_parts[j].faces[k].tex_coords[2] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(memFile
+ hob_struct->objects[i].object_parts[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].object_parts[j].faces[k].flags_bits.fIsQuad) {
hob_struct->objects[i].object_parts[j].faces[k].tex_coords[3] = ((T_HOBFILE_FACES_VERTEX_TEXTURE *)(memFile
+ hob_struct->objects[i].object_parts[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 (p_opts->debug_mode) {
printf("[DBG] > Face %d details: flags:0x%X b1:%d b2:%d b3%d bsize:%d\n", k,
hob_struct->objects[i].object_parts[j].faces[k].flags,
hob_struct->objects[i].object_parts[j].faces[k].b1,
hob_struct->objects[i].object_parts[j].faces[k].b2,
hob_struct->objects[i].object_parts[j].faces[k].b3,
hob_struct->objects[i].object_parts[j].faces[k].bsize
);
printf("[DBG] - Type is Quad: %d\n", hob_struct->objects[i].object_parts[j].faces[k].flags_bits.fIsQuad);
printf("[DBG] - Material offset: 0x%X\n", hob_struct->objects[i].object_parts[j].faces[k].material_index);
printf("[DBG] - Vertex indices: %d, %d, %d, %d\n",
hob_struct->objects[i].object_parts[j].faces[k].indices[0],
hob_struct->objects[i].object_parts[j].faces[k].indices[1],
hob_struct->objects[i].object_parts[j].faces[k].indices[2],
hob_struct->objects[i].object_parts[j].faces[k].indices[3]
);
printf("[DBG] - Vertex colors: 0x%X, 0x%X, 0x%X, 0x%X\n",
hob_struct->objects[i].object_parts[j].faces[k].vertex_colors[0],
hob_struct->objects[i].object_parts[j].faces[k].vertex_colors[1],
hob_struct->objects[i].object_parts[j].faces[k].vertex_colors[2],
hob_struct->objects[i].object_parts[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].object_parts[j].faces[k].tex_coords[0].u,
hob_struct->objects[i].object_parts[j].faces[k].tex_coords[0].u,
((double) 1/4096) * hob_struct->objects[i].object_parts[j].faces[k].tex_coords[0].v,
hob_struct->objects[i].object_parts[j].faces[k].tex_coords[0].v
);
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
((double) 1/4096) * hob_struct->objects[i].object_parts[j].faces[k].tex_coords[1].u,
hob_struct->objects[i].object_parts[j].faces[k].tex_coords[1].u,
((double) 1/4096) * hob_struct->objects[i].object_parts[j].faces[k].tex_coords[1].v,
hob_struct->objects[i].object_parts[j].faces[k].tex_coords[1].v
);
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
((double) 1/4096) * hob_struct->objects[i].object_parts[j].faces[k].tex_coords[2].u,
hob_struct->objects[i].object_parts[j].faces[k].tex_coords[2].u,
((double) 1/4096) * hob_struct->objects[i].object_parts[j].faces[k].tex_coords[2].v,
hob_struct->objects[i].object_parts[j].faces[k].tex_coords[2].v
);
printf("[DBG] > %.8f(%d), %.8f(%d)\n",
((double) 1/4096) * hob_struct->objects[i].object_parts[j].faces[k].tex_coords[3].u,
hob_struct->objects[i].object_parts[j].faces[k].tex_coords[3].u,
((double) 1/4096) * hob_struct->objects[i].object_parts[j].faces[k].tex_coords[3].v,
hob_struct->objects[i].object_parts[j].faces[k].tex_coords[3].v
);
printf("\n");
}
if (p_opts->debug_mode) printf("\n-----------------------End of FaceGroup part-----------------------\n");
}
// Get vertex datas
hob_struct->objects[i].object_parts[j].vertices = calloc(hob_struct->objects[i].object_parts[j].vertex_count, sizeof(T_VERTEX));
for ( k = 0; k < hob_struct->objects[i].object_parts[j].vertex_count; k++ ) {
hob_struct->objects[i].object_parts[j].vertices[k].x = ((T_HOBFILE_VERTEX *)(memFile
+ hob_struct->objects[i].object_parts[j].vertex_block_offset
+ sizeof(T_VERTEX) * k))->x;
hob_struct->objects[i].object_parts[j].vertices[k].y = ((T_HOBFILE_VERTEX *)(memFile
+ hob_struct->objects[i].object_parts[j].vertex_block_offset
+ sizeof(T_VERTEX) * k))->y;
hob_struct->objects[i].object_parts[j].vertices[k].z = ((T_HOBFILE_VERTEX *)(memFile
+ hob_struct->objects[i].object_parts[j].vertex_block_offset
+ sizeof(T_VERTEX) * k))->z;
hob_struct->objects[i].object_parts[j].vertices[k].w = ((T_HOBFILE_VERTEX *)(memFile
+ hob_struct->objects[i].object_parts[j].vertex_block_offset
+ sizeof(T_VERTEX) * k))->w; // Always 0???
if (p_opts->debug_mode) printf("[DBG] > Found vertex %d: (%d, %d, %d)\n", k,
hob_struct->objects[i].object_parts[j].vertices[k].x,
hob_struct->objects[i].object_parts[j].vertices[k].y,
hob_struct->objects[i].object_parts[j].vertices[k].z
);
}
}
// Get object part ID, used by animation? bones?
hob_struct->objects[i].object_parts[j].id = ((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->object_id;
if (p_opts->verbose_mode) printf("\n[DBG] > Facegroup/object ID: %d\n", hob_struct->objects[i].object_parts[j].id);
// Get the transform matrix, used by at-st and at-at (at this time)
hob_struct->objects[i].object_parts[j].transform.x = ((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->transform_x;
hob_struct->objects[i].object_parts[j].transform.y = ((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->transform_y;
hob_struct->objects[i].object_parts[j].transform.z = ((T_HOBFILE_MESHDEF0 *)(memFile + offset_index[j]))->transform_z;
if (p_opts->god_mode) printf("\n[DBG] > Facegroup/object transform matrix: [%.8f %.8f %.8f]\n",
hob_struct->objects[i].object_parts[j].transform.x,
hob_struct->objects[i].object_parts[j].transform.y,
hob_struct->objects[i].object_parts[j].transform.z
);
if (p_opts->debug_mode) printf("\n-----------------------End of Mesh part---------------------------\n");
}
if (p_opts->debug_mode) printf("\n-=====================-End of Object part-========================-\n");
}
free(offset_index);
} else {
err = ERROR_GENERIC;
printf("[INFO] Can't process empty file!\n");
}
free(memFile);
} else {
fclose(fStream);
err = ERROR_MEMORY;
if (p_opts->verbose_mode) printf("[ERR] Can't allocate enough memory for file processing!\n");
}
} else {
err = ERROR_IO;
if (p_opts->verbose_mode) printf("[ERR] Input file %s not found!\n", fileName);
}
} else err = ERROR_ARGS_NULL;
return err;
}

View File

@ -1,15 +0,0 @@
/**
* \file hob_parser.h
* \date 26/07/2022
* \author JackCarterSmith
* \copyright GPL-v3.0
* \brief Decode HOB file structure.
*/
#ifndef SRC_HOB_PARSER_H_
#define SRC_HOB_PARSER_H_
unsigned char parseHOBFile(const char* fileName, T_HOB* hob_struct, T_PROG_OPTIONS* p_opts);
#endif /* SRC_HOB_PARSER_H_ */

View File

@ -1,21 +0,0 @@
/**
* \file obj_exporter.h
* \date 27/07/2022
* \author JackCarterSmith
* \copyright GPL-v3.0
* \brief Export datas to Waveform OBJ format.
*/
#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, T_PROG_OPTIONS* p_opts);
#endif /* SRC_OBJ_EXPORTER_H_ */

@ -1 +0,0 @@
Subproject commit 48a6916526d043691bb3f9e38676fbc99995da10