Compare commits

...

13 Commits

Author SHA1 Message Date
7114278842
Conan asspain
All checks were successful
JCS-Prod/RSE-Model/pipeline/head This commit looks good
2025-02-01 16:09:06 +01:00
1dbe69cd8b
Final work on Conan v2 support
All checks were successful
JCS-Prod/RSE-Model/pipeline/pr-master This commit looks good
JCS-Prod/RSE-Model/pipeline/head This commit looks good
2024-09-22 15:11:49 +02:00
1dbe9df091
Checked transform types
Obj exporter include divide by 1024 (10bits rsh), keep this value in mind during parsing
2024-05-19 10:26:02 +02:00
88c90b39bb
Find new transform elements 2024-05-19 10:26:00 +02:00
023c63617d
Validated conan v2 migration
Some checks failed
JCS-Prod/RSE-Model/pipeline/head There was a failure building this commit
2024-05-19 10:23:14 +02:00
9e551619a1
Refactor parser with cleaned code
All checks were successful
JCS-Prod/RSE-Model/pipeline/pr-master This commit looks good
JCS-Prod/RSE-Model/pipeline/head This commit looks good
Finally made separation btw obj_parts and face_groups
2023-02-23 19:18:53 +01:00
1deb5eae2c
Upgrade HOB struct with new uncovered fields 2023-02-21 19:30:24 +01:00
ec82ff4158
More details on hob struct 2023-02-20 22:25:57 +01:00
3307cfaab7
Change face parsing counter 2023-02-16 16:59:55 +01:00
3614742343
Convert bytes flag to hex for better reading 2023-02-13 18:04:18 +01:00
c0b26e7b42
Fix HOB deallocation
All checks were successful
JCS-Prod/RSE-Model/pipeline/head This commit looks good
Removed logging in library by default
2023-02-05 15:32:51 +01:00
7ba1037230
Okay fuck it stupid dirty dependency
All checks were successful
JCS-Prod/RSE-Model/pipeline/pr-master This commit looks good
JCS-Prod/RSE-Model/pipeline/head This commit looks good
I'll take cate of you later
2023-01-18 19:46:42 +01:00
d40a9f921c
Minor feature update
Some checks failed
JCS-Prod/RSE-Model/pipeline/pr-master There was a failure building this commit
> New Load/Free mecanism for file memory management
> Added prototype of simple header parser for fast infos access
> Fix seg. fault when forcing mtl export without RSPTextureLib dll
> Added dependencies to Vulkan driver
2023-01-18 19:07:09 +01:00
19 changed files with 1093 additions and 692 deletions

1
.gitignore vendored
View File

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

View File

@ -1,14 +1,14 @@
# CMakeLists.txt
####################################################
# Written by JackCarterSmith, 2022
# Written by JackCarterSmith, 2023
# This code is released under the RSE license.
####################################################
# CMake requirement and general configuration
cmake_minimum_required(VERSION 3.12)
cmake_policy(VERSION 3.12)
cmake_minimum_required(VERSION 3.15)
cmake_policy(VERSION 3.15)
set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
if(DEFINED ENV{MS_COMPATIBLE})
set(CMAKE_GNUtoMS ON) # Enable compatibility level to exported libraries
@ -20,11 +20,10 @@ if(DEFINED ENV{CI}) # Jenkins CI integration mode
project(rse-model VERSION $ENV{CI_VERSION}.$ENV{CI_BUILD_NUMBER} DESCRIPTION "RogueSquadron Extractor - Model" LANGUAGES C)
set(RSE_MODEL_NAME $ENV{CI_OUTPUT_NAME})
else() # Standalone project mode, should not be used for release.
project(rse-model VERSION 2.2.0 DESCRIPTION "RogueSquadron Extractor - Model" LANGUAGES C)
project(rse-model VERSION 2.4.0 DESCRIPTION "RogueSquadron Extractor - Model" LANGUAGES C)
set(RSE_MODEL_NAME RSEModel)
endif()
set(RSP_MODEL_LIB_NAME RSPModel${PROJECT_VERSION_MAJOR}${PROJECT_VERSION_MINOR})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries")
@ -82,7 +81,7 @@ endif()
# Install dependancies
install(FILES ${PROJECT_BINARY_DIR}/bin/glew32.dll
install(FILES ${PROJECT_BINARY_DIR}/bin/glew32.dll ${PROJECT_BINARY_DIR}/bin/vulkan-1.dll
DESTINATION ${INSTALL_BIN_DIR})
# Install library includes

15
Jenkinsfile vendored
View File

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

207
LICENSE-vulkan Normal file
View File

@ -0,0 +1,207 @@
The majority of files in this project use the Apache 2.0 License.
There are a few exceptions and their license can be found in the source.
Any license deviations from Apache 2.0 are "more permissive" licenses.
===========================================================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -22,13 +22,14 @@ This module can do:
- Add textures to models.
- Discover all unknowns fields, animations, bones mesh, etc.
- Full Conan build pipeline
### Using
`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.
Due to issues with copyrights, I can't provide samples and my DAT file parser is unfinished... You need to extract HOB files yourself.
<img src="https://repo.jcsmith.fr/pictures/rse-model.gif" width="620" height="400" />
@ -45,22 +46,12 @@ Due to issue with copyrights, I can't provide samples... You need to extract HOB
### Compiling
You can compile on both Windows (MinGW) or native Linux system thanks to CMake.
To compile, just clone (**don't forget git submodules**) and launch cmake:
I've a preference for compiling libraries by hand, mainly for backward compatibility, but I recommend using Conan packages manager (https://conan.io) for simplicity. (**Don't forget git submodules**)
```shell
cmake .
make
make install
conan install . -of build -b missing -s build_type=Release -o tools=True -pr:b=default -pr:h=default
cmake --preset conan-release -G "Unix Makefiles"
cmake --build --preset conan-release
```
We can also use cross-compilation (after installing `mingw64` and `cmake` packages on your distrib):
```shell
mkdir build && cd build
cmake -DGNU_HOST=x86_64-w64-mingw32 \
-DCMAKE_TOOLCHAIN_FILE=../mingw_cross_toolchain.cmake \
..
cmake --build .
```
On Windows environment, you can use MinGW `-G "MinGW Makefiles"` or Ninja `-G "Ninja"` as CMake generator.

View File

@ -1,7 +1,7 @@
# CMakeLists.txt
####################################################
# Written by JackCarterSmith, 2022
# Written by JackCarterSmith, 2023
# This code is released under the RSE license.
####################################################
@ -14,6 +14,10 @@ if(BUILD_TOOLS)
# Import needed packages and references their include path
find_package(GLEW REQUIRED)
include_directories(${GLEW_INCLUDE_DIR})
#find_package(Vulkan REQUIRED)
#include_directories(${Vulkan_INCLUDE_DIR})
#find_package(vulkan-memory-allocator REQUIRED)
#include_directories(${vulkan-memory-allocator_INCLUDE_DIR})
# Define src/headers files
@ -42,9 +46,13 @@ if(BUILD_TOOLS)
endif()
# Link externals libraries to the linker
if(RSPMODEL_SHARED)
target_link_libraries(rse-model PRIVATE rsp-model-lib ${GLEW_LIBRARIES} ${AUX_LIBS})
elseif(RSPMODEL_STATIC)
target_link_libraries(rse-model PRIVATE rsp-model-libstatic ${GLEW_LIBRARIES} ${AUX_LIBS})
if (TARGET GLEW::GLEW)
if(RSPMODEL_SHARED)
#target_link_libraries(rse-model PRIVATE rsp-model-lib ${GLEW_LIBRARIES} ${Vulkan_LIBRARIES} ${AUX_LIBS})
target_link_libraries(rse-model PRIVATE rsp-model-lib GLEW::GLEW ${AUX_LIBS})
elseif(RSPMODEL_STATIC)
#target_link_libraries(rse-model PRIVATE rsp-model-libstatic ${GLEW_LIBRARIES} ${Vulkan_LIBRARIES} ${AUX_LIBS})
target_link_libraries(rse-model PRIVATE rsp-model-libstatic GLEW::GLEW ${AUX_LIBS})
endif()
endif()
endif()

View File

@ -99,11 +99,12 @@ static unsigned int mainProcess(int args_cnt, char* args_value[], T_PROG_OPTIONS
if (RSPModel_processHOBFile(hobStruct, args_value[file_index], libParams) != RSPLIB_SUCCESS) {
printf("[ERR] Failed to parse datas from %s\n", args_value[file_index]);
RSPModel_freeHOB(hobStruct);
free(hobStruct);
return RSPLIB_ERROR_PROCESS;
}
// If Texture module loaded, process HMT file for mtl naming (doesn't extract texture!)
if (p_opts->texture_module) {
if (p_opts->texture_module && p_opts->export_mtl) {
if (strlen(args_value[file_index]) >= MAX_STR_VAR) return RSPLIB_ERROR_GENERIC;
strncpy(hmt_filename, args_value[file_index], strlen(args_value[file_index]) - 3);
@ -132,10 +133,11 @@ static unsigned int mainProcess(int args_cnt, char* args_value[], T_PROG_OPTIONS
}
}
RSPTexture_freeHMT(hmtStruct);
if (p_opts->texture_module) RSPTexture_freeHMT(hmtStruct);
}
RSPModel_freeHOB(hobStruct);
free(hobStruct);
return RSPLIB_SUCCESS;
}

View File

@ -1,7 +1,7 @@
# CMakeLists.txt
####################################################
# Written by JackCarterSmith, 2022
# Written by JackCarterSmith, 2023
# This code is released under the RSE license.
####################################################
@ -31,8 +31,8 @@ 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)
set_target_properties(rsp-model-lib PROPERTIES VERSION 2.1.0)
set_property(TARGET rsp-model-lib PROPERTY C_STANDARD 11)
set_target_properties(rsp-model-lib PROPERTIES VERSION 2.3.0)
target_include_directories(rsp-model-lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
@ -53,7 +53,7 @@ endif()
# Declare the static library instance
if(RSPMODEL_STATIC)
add_library(rsp-model-libstatic STATIC ${RSP_MOD_SOURCES})
set_property(TARGET rsp-model-libstatic PROPERTY C_STANDARD 90)
set_property(TARGET rsp-model-libstatic PROPERTY C_STANDARD 11)
target_include_directories(rsp-model-libstatic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

View File

@ -1,6 +1,6 @@
/**
* @file RSPModel.h
* @date 11/08/2022
* @date 18/01/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Rogue Squadron Parser model library, used to decode decode datas
@ -48,6 +48,7 @@ extern "C" {
// Library's functions declaration
///////////////////////////////////////////////////////////////////////////////
/* ------------------------------------------------------------------------- */
/**
* @brief Get the current library version.
* @return Char array of the version, escape char included.
@ -88,6 +89,36 @@ RSPMODEL_EXTERN unsigned short RSPModel_processHOBFileMemory(
const RSPMODEL_PARAMETERS params
);
/**
* @brief Clean HOB object and it's childrens from memory.
* @param[in] hobStruct Pointer to data to be cleaned up.
*/
RSPMODEL_EXTERN void RSPModel_freeHOB( T_RSPMODEL_HOB* hobStruct );
/* ------------------------------------------------------------------------- */
/**
* @brief Get number of model objects inside specified memFilePtr without
* fully parsing it.
*
* @param[in] filePath Path to the HOB file in system.
*
* @return Number of model objects.
*/
RSPMODEL_EXTERN unsigned int RSPModel_getHOBFileObjCount( const char* const filePath );
/**
* @brief Get number of model objects inside specified memFilePtr without
* fully parsing it.
*
* @param[in] memFilePtr Pointer to the beginning of the file in memory.
*
* @return Number of model objects.
*/
RSPMODEL_EXTERN unsigned int RSPModel_getHOBFileMemObjCount( const void* const memFilePtr );
/* ------------------------------------------------------------------------- */
/**
* @brief Convert HOB's object datas to GL compatible format.
* @note Only available if GL module as specified at compilation.
@ -114,12 +145,6 @@ RSPMODEL_EXTERN unsigned short RSPModel_objectToD3D(
const T_RSPMODEL_OBJECT* objStruct, void* D3DObj
);
/**
* @brief Clean HOB object and it's childrens from memory.
* @param[in] hobStruct Pointer to data to be cleaned up.
*/
RSPMODEL_EXTERN void RSPModel_freeHOB( T_RSPMODEL_HOB* hobStruct );
#ifdef __cplusplus
}
#endif

View File

@ -1,6 +1,6 @@
/**
* @file RSPModel_datatypes.h
* @date 11/08/2022
* @date 21/02/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief RSP Model workflow structures definitions
@ -39,40 +39,31 @@ typedef char* MEMFILE;
#define MEMFILE_DEF
#endif
#ifndef T_RGBA_DEF
typedef unsigned int T_RGBA;
#define T_RGBA_DEF
#endif
typedef unsigned int T_RSPMODEL_RGBA;
#ifndef T_VECTOR3_DEF
typedef struct vector3 { float x,y,z; } T_VECTOR3;
#define T_VECTOR3_DEF
#endif
typedef struct rspmodel_vector3 { float x,y,z; } T_RSPMODEL_VECTOR3;
typedef struct rspmodel_vertex { short x,y,z,w; } T_RSPMODEL_VERTEX;
#ifndef T_VERTEX_DEF
typedef struct vertex { short x,y,z,w; } T_VERTEX;
#define T_VERTEX_DEF
#endif
typedef struct rspmodel_texcoord { short u,v; } T_RSPMODEL_TEXCOORD;
#ifndef T_TEXCOORD_DEF
typedef struct tex_coord { short u,v; } T_TEXCOORD;
#define T_TEXCOORD_DEF
#endif
typedef struct rspmodel_bbox { T_RSPMODEL_VECTOR3 start,end; } T_RSPMODEL_BBOX;
typedef struct face_flags {
unsigned int fUnknown0:1;
unsigned int fUnknown1:1;
unsigned int fUnused0:1; //TODO: Parse all HOB to find anyone with this field different of 0
unsigned int fUnused1:1; //TODO: Parse all HOB to find anyone with this field different of 0
unsigned int fHasTexture:1;
unsigned int fIsQuad:1;
unsigned int fSeparateColorVertex:1;
unsigned int fHasColor:1;
unsigned int fHasExtraBytesBeforeColor:1;
unsigned int fUnknown7:1;
unsigned int fNoCulled:1; // Face with this flag always be rendered without culling, usefull to render "flat" object
unsigned int fUnknown8:1;
unsigned int fUnknown9:1;
unsigned int fUnknown10:1;
unsigned int reserved:21;
unsigned int fReserved:21;
} FACE_FLAGS;
typedef struct hob_face {
@ -86,11 +77,12 @@ typedef struct hob_face {
unsigned char bsize;
unsigned short mt_index; // Material/texture index, if texture it's correspond to texture_index, otherwise it's mat_'X'
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_RGBA vertex_colors[4]; //TODO: convert in R:8_G:8_B:8_A:8 format? Caution with BE/LE conversion
T_RSPMODEL_TEXCOORD tex_coords[4];
} T_RSPMODEL_FACE;
typedef struct rspmodel_obj_parts {
unsigned int meshdef0_offset;
unsigned int meshdef1_offset;
unsigned int face_block_end_offset;
@ -98,20 +90,31 @@ typedef struct rspmodel_obj_parts {
unsigned int vertex_block_offset;
unsigned int id;
T_VECTOR3 transform;
T_RSPMODEL_VECTOR3 offset_transform;
T_RSPMODEL_VECTOR3 scale_transform;
T_RSPMODEL_VECTOR3 rotate_transform;
T_RSPMODEL_VECTOR3 translate_transform;
unsigned int face_count;
T_RSPMODEL_FACE* faces;
unsigned int vertex_count;
T_VERTEX* vertices;
T_RSPMODEL_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_parts_header_offset;
unsigned int object_parts_header_offset2;
unsigned int object_parts_header2_offset;
unsigned int object_parts_header2_offset2;
unsigned int object_subparts_names_offset;
unsigned int effects_offset;
unsigned int properties_offset2;
T_RSPMODEL_BBOX bounding_box;
unsigned int object_part_count;
unsigned int face_group_count;

View File

@ -1,6 +1,6 @@
/**
* @file RSPModel.c
* @date 11/08/2022
* @date 18/01/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief HOB model parser and export to Waveform OBJ format.
@ -27,38 +27,27 @@ inline char* RSPModel_getVersion( void ) {
unsigned short RSPModel_processHOBFile( T_RSPMODEL_HOB* hob, const char* const filePath,
const RSPMODEL_PARAMETERS params ) {
unsigned short result = RSPLIB_SUCCESS;
MEMFILE pMemFile = NULL;
if ( hob == NULL || filePath == NULL ) return RSPLIB_ERROR_ARGS_NULL;
RSP_ModelLib_ParseHOBFile(filePath, hob, &params);
RSP_ModelLib_LoadHOBFile(&pMemFile, filePath, &params);
result = RSP_ModelLib_ProcessHOBMemFile(hob, pMemFile, &params);
RSP_ModelLib_FreeHOBFile(&pMemFile);
return RSPLIB_SUCCESS;
return result;
}
unsigned short RSPModel_processHOBFileMemory( T_RSPMODEL_HOB* hob, const void* const memFilePtr,
const long memFileSize, const RSPMODEL_PARAMETERS params ) {
unsigned short result = RSPLIB_SUCCESS;
if ( hob == NULL || memFilePtr == NULL ) return RSPLIB_ERROR_ARGS_NULL;
RSP_ModelLib_ParseHOBMemFile((MEMFILE)memFilePtr, hob, &params);
result = RSP_ModelLib_ProcessHOBMemFile(hob, (MEMFILE)memFilePtr, &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;
return result;
}
void RSPModel_freeHOB( T_RSPMODEL_HOB* hobStruct ) {
@ -82,6 +71,41 @@ void RSPModel_freeHOB( T_RSPMODEL_HOB* hobStruct ) {
}
free(hobStruct->objects);
}
free(hobStruct);
}
/* ------------------------------------------------------------------------- */
unsigned int RSPModel_getHOBFileObjCount( const char* const filePath ) {
unsigned int result = 0;
MEMFILE pMemFile = NULL;
if (filePath != NULL) {
RSP_ModelLib_LoadHOBFile(&pMemFile, filePath, 0);
result = RSP_ModelLib_getObjectsCount(pMemFile);
RSP_ModelLib_FreeHOBFile(&pMemFile);
}
return result;
}
unsigned int RSPModel_getHOBFileMemObjCount( const void* const memFilePtr ) {
return RSP_ModelLib_getObjectsCount((MEMFILE)memFilePtr);
}
/* ------------------------------------------------------------------------- */
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

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

View File

@ -1,6 +1,6 @@
/**
* @file hob_parser.h
* @date 18/08/2022
* @date 21/02/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Process HOB file structure and extract its datas.
@ -8,6 +8,7 @@
*/
#include "RSPModel_datatypes.h"
#include "hob_struct.h"
#ifndef RSPMODELLIB_HOB_PARSER_H_
@ -19,33 +20,45 @@
* 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] pMemFile Pointer to an in-memory HOB file location.
* @param[in] pParams Parser options. See RSPMODEL_PARAMETERS.
*
* @return Processing error code, RSPLIB_SUCCESS if no error.
*/
unsigned short RSP_ModelLib_ParseHOBMemFile(const MEMFILE pMemFile,
T_RSPMODEL_HOB* hobStruct, const RSPMODEL_PARAMETERS* pParams);
unsigned short RSP_ModelLib_ProcessHOBMemFile(T_RSPMODEL_HOB* hobStruct,
const MEMFILE pMemFile, 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
* @brief Load file in memory and store it access in pointer.
*
* @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[out newMemFile Newly created HOB file pointer, NULL if failure.
* @param[in] fileName File path in the filesystem.
* @param[in] pParams Parser options. See RSPMODEL_PARAMETERS.
*
* @return Processing error code, RSPLIB_SUCCESS if no error.
*/
unsigned short RSP_ModelLib_ParseHOBFile(const char* fileName,
T_RSPMODEL_HOB* hobStruct, const RSPMODEL_PARAMETERS* pParams);
unsigned short RSP_ModelLib_LoadHOBFile(MEMFILE* newMemFile, const char* fileName, const RSPMODEL_PARAMETERS* pParams);
/**
* @brief Clean memory of file created with RSP_ModelLib_LoadHOBFile().
*
* @param[in] memFile Pointer to an in-memory HOB file location.
*
* @return Processing error code, RSPLIB_SUCCESS if no error.
*/
unsigned short RSP_ModelLib_FreeHOBFile(const MEMFILE* memFile);
/**
* @brief Return number of model objects inside specified pMemfile.
*
* @param[in] pMemfile Pointer to an in-memory HOB file location.
*
* @return Number of model objects
*/
static inline unsigned int RSP_ModelLib_getObjectsCount(const MEMFILE pMemfile) {
return ((T_HOBFILE_HEADER*)pMemfile)->obj_count;
}
#endif /* RSPMODELLIB_HOB_PARSER_H_ */

View File

@ -1,6 +1,6 @@
/**
* @file hob_struct.h
* @date 26/07/2022
* @date 18/09/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief HOB file mapping definition.
@ -36,108 +36,158 @@
/*
* - Global HOB file structure-
* +------------------+--------------------------------------+----------------------------------------+
* | T_HOBFILE_HEADER | obj_count * T_HOBFILE_OBJ_DESCRIPTOR | obj_count * T_HOBFILE_FACEGROUP_HEADER |
* | T_HOBFILE_HEADER | obj_count * T_HOBFILE_OBJ_DESCRIPTOR | obj_count * T_HOBFILE_FACEGROUP_HEADER | -->
* +------------------+--------------------------------------+----------------------------------------+
*
* - Facegroup sub-structure -
* +----------------------------+------------------------------------------------+
* | T_HOBFILE_FACEGROUP_HEADER | object_part_count * T_HOBFILE_FACEGROUP_OFFSET |
* +----------------------------+------------------------------------------------+
* +------------------------------+--------------------------------------------------+
* --> | T_HOBFILE_FACEGROUP_HEADER_1 | object_part_count * T_HOBFILE_FACEGROUP_OFFSET_1 |
* +------------------------------+--------------------------------------------------+
*
* - Facegroup sub-structure 2 -
* +------------------------------+------------------------------------------------------------------------+--------------------------------------------------------+
* | T_HOBFILE_FACEGROUP_HEADER_2 | ( object_part_count + facegroup_count ) * T_HOBFILE_FACEGROUP_OFFSET_2 | ( object_part_count - 1 ) * T_HOBFILE_FACEGROUP_NAMEID | + padding
* +------------------------------+------------------------------------------------------------------------+--------------------------------------------------------+
*/
typedef struct PACK hobfile_header {
unsigned int obj_count;
unsigned int vertices_offset;
} T_HOBFILE_HEADER;
typedef struct PACK hobfile_obj_descriptor {
unsigned char object_name[16];
unsigned int facegroup_offset;
unsigned int object_parts_offset;
unsigned int facegroup_header_2_offset;
typedef struct PACK hobfile_obj_header {
unsigned char object_name[16]; // Name of the object
unsigned int reserved1; // 12B of zeros
unsigned int reserved2;
unsigned int reserved3;
unsigned int facegroup_start_offset; // First facegroup datas offset. Look in T_HOBFILE_FACEGROUP_HEADER for all offsets of facegroups of the current object.
unsigned int object_parts_offset; // Object parts descriptor offset
unsigned int object_parts_offset2; // Facegroup descriptor offset (subpart of Object parts descriptor)
unsigned int unknownOffset1;
unsigned int unknownOffset2;
unsigned int unknownOffset3;
float unknown4;
unsigned int object_parts2_offset; // Optional offset - seem present in tieinter_HOB - point just after the 0xFFFFFFFF of the first one
unsigned int object_parts2_offset2; // Optional offset - seem present in tieinter_HOB
unsigned int reserved1; // Always zeros ?
unsigned int reserved4; // 12B of zeros
unsigned int subparts_namelist_offset; // Point to an array of string value (8 chars) + ID (2 chars - 1 to obj_parts-1). Seem like name of articulation points (some have name like "node_86").
unsigned int effects_offset; // Empty in gun_turret and no datas after, xwing have 0x5006, present in koelsch. worddevastator can have more answers...
unsigned int properties_offset; // Offset to different string (a_b/zf/zt/zb/etc.) Animation datas ? Empty with 6x float in train_hob, a_b object is canon beams in gun_turret
float unknown4; // 1.0F/1.125F - Look forward angle correction?
unsigned int reserved4; // 12B of zeros
unsigned int reserved5;
unsigned int reserved6;
float reserved7;
float reserved8;
float reserved9;
float reserved10;
float reserved11;
unsigned int end_mask; // Always equal to 0xFFFFFFFF
float reserved12;
float reserved13;
float reserved14;
float reserved15;
float reserved16;
float reserved17;
} T_HOBFILE_OBJ_DESCRIPTOR;
float unknown5; // Something related to culling camera frustum (when reduced value, the gun_turret didn't render before getting out of camera view)
float unknown6; // Something related to collision detection (bigger float >100.0f)
typedef struct PACK hobfile_facegroup_header {
float reserved7; // Something related to collision detection Translation matrix? Center of object?
float reserved8; // Something related to collision detection Translation matrix? Center of object?
float reserved9; // Something related to collision detection Translation matrix? Center of object?
unsigned int footer_offset; //To redefine, seem to be a copy of following bounding box? Maybe there are 2 box: render and collision?
float bbox_start_x; // Bounding box start vector
float bbox_start_y;
float bbox_start_z;
float bbox_end_x; // Bounding box start vector
float bbox_end_y;
float bbox_end_z;
} T_HOBFILE_OBJ_HEADER;
/*
* T_HOBFILE_OBJPARTS_HEADER
* |
* \
* |T_HOBFILE_OBJPART_HEADER
* \
* T_HOBFILE_OBJPART_HEADER
* |
* \
* |T_HOBFILE_FACEGROUP_HEADER
* \
* T_HOBFILE_FACEGROUP_HEADER
*/
typedef struct PACK hobfile_objparts_header {
unsigned short object_part_count;
unsigned short facegroup_count; //aka. meshdef count
} T_HOBFILE_OBJPARTS_HEADER;
typedef struct PACK hobfile_objpart_header {
unsigned int unknown0; // It is flags?
unsigned int facegroup_offset;
} T_HOBFILE_OBJPART_HEADER;
/* TODO: Not sure these exist
typedef struct PACK hobfile_facegroup_header_2 { //TODO: This is part of a bigger one
unsigned short object_part_count;
unsigned short facegroup_count;
} T_HOBFILE_FACEGROUP_HEADER;
} T_HOBFILE_FACEGROUP_HEADER_2;
typedef struct PACK hobfile_facegroup_offset {
unsigned int unknown1;
unsigned int facegroup_offset;
} T_HOBFILE_FACEGROUP_OFFSET;
typedef struct PACK hobfile_facegroup_offset_2 { //TODO: This is part of a bigger one
unsigned int unknownOffset0;
} T_HOBFILE_FACEGROUP_OFFSET_2;
*/
typedef struct PACK hobfile_objparts_nameid {
unsigned char name[8];
unsigned char unknown0; // Always zeros ?
unsigned char id;
} T_HOBFILE_OBJPARTS_NAMEID;
/* TODO:
typedef struct PACK hobfile_effects {
unsigned char something0;
unsigned short something1;
} T_HOBFILE_EFFECTS;
*/
typedef struct PACK hobfile_meshdef0 {
unsigned int offset1;
unsigned int offset2;
unsigned int prev_meshdef0_offset;
unsigned int next_meshdef0_offset;
unsigned int offset1; // Brothers meshdef?
unsigned int offset2; // Brothers meshdef?
unsigned int parent_meshdef0_offset;
unsigned int children_meshdef0_offset;
unsigned int meshdef1_offset_plus_4;
unsigned int reserved1; // 8B of zeros
unsigned int reserved2;
float unknown3;
float unknown3; // Always 1.0f?
unsigned int reserved3; // 12B of zeros
unsigned int reserved4;
unsigned int reserved5;
float unknown4;
float unknown4; // Always 1.0f?
unsigned int reserved6; // 12B of zeros
unsigned int reserved7;
unsigned int reserved8;
float unknown5;
float unknown5; // Always 1.0f?
unsigned int reserved9; // 12B of zeros
unsigned int reserved10;
unsigned int reserved11;
unsigned int object_id;
unsigned int vecsFlags; // Enabled local transforms (bit0=offset #1; bit1=scale #2; bit2=rotation #3; bit3=translation;)
float unknown12; // Can be a vector???
float unknown13;
float unknown14;
float offsett_x; // Offset transform (aka. reverse translation)
float offsett_y;
float offsett_z;
float unknown15; // Can be a vector???
float unknown16;
float unknown17;
float scalet_x; // Local transform - Scale
float scalet_y;
float scalet_z;
float unknown18; // Can be a matrix???
float unknown19;
float unknown20;
float unknown21;
float rott_x; // Local transform - Rotation
float rott_y;
float rott_z;
float transform_x;
float transform_y;
float transform_z;
float unknown16; // Always 0?
float transt_x; // Local transform - Translation
float transt_y;
float transt_z;
} T_HOBFILE_MESHDEF0;
typedef struct PACK hobfile_meshdef1 {
@ -180,31 +230,31 @@ typedef struct PACK hobfile_faceblock {
typedef struct PACK hobfile_faces_header {
unsigned int flags;
unsigned char b1; // 74 = transparent / 75 = opaque
unsigned char b2;
unsigned char b3;
unsigned char b1; // Seem to alter texture mapping on face, 49 -> quad face, 48 -> tri face, 47 -> N/A
unsigned char b2; // 61 -> texture right rotation, 71 -> little red overlay, 81 -> bigger red overlay, x1 -> don't do anything
unsigned char b3; // Seem to alter rendering matrix or maybe vertices position relative to
unsigned char faceBlockIntSize; // Bytes size divided by 4, count as number of UInt32 type.
unsigned short headerSeparator;
unsigned short headerSeparator; // If header it's uncommon, it's probably because you made a wrong parsing
unsigned short materialIndex;
unsigned short vertexIndices[4]; // Relative to facegroup, the last value is equal to 0 when it's triangle shape.
} T_HOBFILE_FACES_HEADER;
typedef struct PACK 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_RSPMODEL_RGBA v1_rgba;
T_RSPMODEL_RGBA v2_rgba;
T_RSPMODEL_RGBA v3_rgba;
T_RSPMODEL_RGBA v4_rgba; // Used with quad type face
} T_HOBFILE_FACES_VERTEX_COLOR;
typedef struct PACK hobfile_faces_extra_color {
T_RGBA rgba;
T_RSPMODEL_RGBA rgba;
} T_HOBFILE_FACES_COLOR;
typedef struct PACK 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_RSPMODEL_TEXCOORD v1_texcoord; // Should be divided (no shifting) by 4096 to get 0...1 range
T_RSPMODEL_TEXCOORD v2_texcoord;
T_RSPMODEL_TEXCOORD v3_texcoord;
T_RSPMODEL_TEXCOORD v4_texcoord; // Used with quad type face
} T_HOBFILE_FACES_VERTEX_TEXTURE;
typedef struct PACK hobfile_vertex {

View File

@ -1,246 +0,0 @@
/**
* @file hob_struct.h
* @date 26/07/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief HOB file mapping definition.
*
*/
#ifndef RSPMODELLIB_HOB_STRUCT_H_
#define RSPMODELLIB_HOB_STRUCT_H_
/*
* long = 64bits???
* int = 32bits
* short = 16bits
* car = 8bits
*/
#if defined(_MSC_VER)
#define PACK
#elif defined(__GNUC__)
#define PACK __attribute__((packed))
#endif
///////////////////////////////////////////////////////////////////////////////
// Declaration of Memory Mapped Structure
// Caution: the place of variable is important for correct mapping!
///////////////////////////////////////////////////////////////////////////////
#if defined(_MSC_VER)
#pragma pack(push, 1)
#endif
/*
* - Global HOB file structure-
* +------------------+--------------------------------------+----------------------------------------+
* | T_HOBFILE_HEADER | obj_count * T_HOBFILE_OBJ_DESCRIPTOR | obj_count * T_HOBFILE_FACEGROUP_HEADER | -->
* +------------------+--------------------------------------+----------------------------------------+
*
* - Facegroup sub-structure -
* +------------------------------+--------------------------------------------------+
* --> | T_HOBFILE_FACEGROUP_HEADER_1 | object_part_count * T_HOBFILE_FACEGROUP_OFFSET_1 |
* +------------------------------+--------------------------------------------------+
*
* - Facegroup sub-structure 2 -
* +------------------------------+------------------------------------------------------------------------+--------------------------------------------------------+
* | T_HOBFILE_FACEGROUP_HEADER_2 | ( object_part_count + facegroup_count ) * T_HOBFILE_FACEGROUP_OFFSET_2 | ( object_part_count - 1 ) * T_HOBFILE_FACEGROUP_NAMEID | + padding
* +------------------------------+------------------------------------------------------------------------+--------------------------------------------------------+
*/
typedef struct PACK hobfile_header {
unsigned int obj_count;
unsigned int vertices_offset;
} T_HOBFILE_HEADER;
typedef struct PACK hobfile_obj_header {
unsigned char object_name[16]; // Name of the object
unsigned int facegroup_start_offset; // First facegroup datas offset. Look in T_HOBFILE_FACEGROUP_HEADER for all offsets of facegroups of the current object.
unsigned int object_parts_offset; // Object parts descriptor offset
unsigned int object_parts_offset2; // Facegroup descriptor offset (subpart of Object parts descriptor)
unsigned int opt_offset1; // Optional offset - empty on last obj_header - point to after end mask ffffff of current bloc
unsigned int opt_offset2; // Optional offset - empty on last obj_header - point to after the previous opt_offset1
unsigned int reserved1; // Always zeros ?
unsigned int subparts_namelist_offset; // Point to an array of string value (8 chars) + ID (2 chars - 1 to obj_parts-1). Seem like name of articulation points (some have name like "node_86").
unsigned int effects_offset; // Empty in gun_turret and no datas after, xwing have 0x5006. worddevastator should have the answer...
unsigned int properties_offset; // Offset to different string (a_b/zf/zt/zb/etc.) Animation datas ? Empty with 6x float in train_hob
float unknown4; // Probably scale: 1.0F/1.125F
unsigned int reserved4; // 12B of zeros
unsigned int reserved5;
unsigned int reserved6;
float unknown5; //Scale? ~20.0F
float unknown6; //Scale? ~77-418.0F
float reserved7; //Translation matrix? Center of object?
float reserved8;
float reserved9;
unsigned int footer_offset; //To redefine, seem to be a copy of following bounding box? Maybe there are 2 box: render and collision?
float bbox_start_x; // Bounding box start vector
float bbox_start_y;
float bbox_start_z;
float bbox_end_x; // Bounding box start vector
float bbox_end_y;
float bbox_end_z;
} T_HOBFILE_OBJ_HEADER;
typedef struct PACK hobfile_facegroup_header_1 {
unsigned short object_part_count;
unsigned short facegroup_count;
} T_HOBFILE_FACEGROUP_HEADER_1;
typedef struct PACK hobfile_facegroup_offset_1 {
unsigned int unknown0; // Flags?
unsigned int facegroup_offset;
} T_HOBFILE_FACEGROUP_OFFSET_1;
typedef struct PACK hobfile_facegroup_header_2 {
unsigned short object_part_count;
unsigned short facegroup_count;
} T_HOBFILE_FACEGROUP_HEADER_2;
typedef struct PACK hobfile_facegroup_offset_2 {
unsigned int unknownOffset0;
} T_HOBFILE_FACEGROUP_OFFSET_2;
typedef struct PACK hobfile_facegroup_nameid {
unsigned char name[8];
unsigned short id;
} T_HOBFILE_FACEGROUP_NAMEID;
typedef struct PACK hobfile_meshdef0 {
unsigned int offset1;
unsigned int offset2;
unsigned int prev_meshdef0_offset;
unsigned int next_meshdef0_offset;
unsigned int meshdef1_offset_plus_4;
unsigned int reserved1; // 8B of zeros
unsigned int reserved2;
float unknown3;
unsigned int reserved3; // 12B of zeros
unsigned int reserved4;
unsigned int reserved5;
float unknown4;
unsigned int reserved6; // 12B of zeros
unsigned int reserved7;
unsigned int reserved8;
float unknown5;
unsigned int reserved9; // 12B of zeros
unsigned int reserved10;
unsigned int reserved11;
unsigned int object_id;
float unknown12; // Can be a vector???
float unknown13;
float unknown14;
float unknown15; // Can be a vector???
float unknown16;
float unknown17;
float unknown18; // Can be a matrix???
float unknown19;
float unknown20;
float unknown21;
float transform_x;
float transform_y;
float transform_z;
} T_HOBFILE_MESHDEF0;
typedef struct PACK hobfile_meshdef1 {
unsigned int facedef_end_offset;
unsigned int reserved1; // 20B of zeros
unsigned int reserved2;
unsigned int reserved3;
unsigned int reserved4;
unsigned int reserved5;
unsigned int vertex_count;
unsigned int unknown1;
unsigned int reserved6;
unsigned int faceblock_offset;
unsigned int vertexblocks_offset;
unsigned int reserved7; // 52B of zeros
unsigned int reserved8;
unsigned int reserved9;
unsigned int reserved10;
unsigned int reserved11;
unsigned int reserved12;
unsigned int reserved13;
unsigned int reserved14;
unsigned int reserved15;
unsigned int reserved16;
unsigned int reserved17;
unsigned int reserved18;
unsigned int reserved19;
} T_HOBFILE_MESHDEF1;
typedef struct PACK hobfile_faceblock {
unsigned int reserved1; // 8B of zeros
unsigned int reserved2;
unsigned int facesOffset;
unsigned int faceCounts;
} T_HOBFILE_FACEBLOCK;
typedef struct PACK hobfile_faces_header {
unsigned int flags;
unsigned char b1; // 74 = transparent / 75 = opaque
unsigned char b2;
unsigned char b3;
unsigned char faceBlockIntSize; // Bytes size divided by 4, count as number of UInt32 type.
unsigned short headerSeparator;
unsigned short materialIndex;
unsigned short vertexIndices[4]; // Relative to facegroup, the last value is equal to 0 when it's triangle shape.
} T_HOBFILE_FACES_HEADER;
typedef struct PACK hobfile_faces_extra_vertex_color {
T_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 PACK hobfile_faces_extra_color {
T_RGBA rgba;
} T_HOBFILE_FACES_COLOR;
typedef struct PACK 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 PACK hobfile_vertex {
short x;
short y;
short z;
short w;
} T_HOBFILE_VERTEX;
#if defined(_MSC_VER)
#pragma pack(pop)
#endif
#endif /* RSPMODELLIB_HOB_STRUCT_H_ */

View File

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

132
conanfile.py Normal file
View File

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

View File

@ -1,12 +0,0 @@
[requires]
glew/2.2.0
[generators]
cmake
cmake_find_package
[options]
glew:shared=True
[imports]
bin, *.dll -> ./bin

View File

@ -38,7 +38,7 @@ PROJECT_NAME = RSE-Model
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 2.1.0
PROJECT_NUMBER = 2.3.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a