New library version of the RS parser #4

Merged
JackCarterSmith merged 4 commits from develop into master 2022-08-29 22:48:51 +02:00
33 changed files with 3984 additions and 3608 deletions

3
.gitignore vendored
View File

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

View File

@ -1,67 +1,78 @@
# CMakeLists.txt # CMakeLists.txt
# Written by JackCarterSmith, 2021 ####################################################
# Written by JackCarterSmith, 2022
# This code is released under the RSE license. # This code is released under the RSE license.
####################################################
cmake_minimum_required(VERSION 3.1)
cmake_policy(VERSION 3.1) # CMake requirement and general configuration
cmake_minimum_required(VERSION 3.12)
cmake_policy(VERSION 3.12)
set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR}) set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
if(DEFINED ENV{MS_COMPATIBLE})
# define project set(CMAKE_GNUtoMS ON) # Enable compatibility level to exported libraries
#add_definitions(-DCONF_NO_GL)
if(DEFINED ENV{CI})
project(rse-texture VERSION 1.0.1.$ENV{CI_BUILD_NUMBER} DESCRIPTION "RogueSquadron Extractor - Texture" LANGUAGES C)
set(RSE_TEX_NAME $ENV{CI_OUTPUT_NAME}-${PROJECT_VERSION})
else()
project(rse-texture VERSION 1.0.1 DESCRIPTION "RogueSquadron Extractor - Texture" LANGUAGES C)
set(RSE_TEX_NAME RSE_Texture-${PROJECT_VERSION})
endif() endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/src/config.h @ONLY)
include(CheckIncludeFile)
include(CheckCSourceCompiles)
#include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
#conan_basic_setup()
# needed packages # Project definition
if(DEFINED ENV{CI}) # Jenkins CI integration mode
find_package(ZLIB 1.2.11 EXACT REQUIRED) project(rse-texture VERSION $ENV{CI_VERSION}.$ENV{CI_BUILD_NUMBER} DESCRIPTION "RogueSquadron Extractor - Texture" LANGUAGES C)
include_directories(${ZLIB_INCLUDE_DIR}) set(RSE_TEXTURE_NAME $ENV{CI_OUTPUT_NAME})
find_package(PNG 1.6.37 EXACT REQUIRED) else() # Standalone project mode, should not be used for release.
include_directories(${PNG_INCLUDE_DIR}) project(rse-texture VERSION 2.0.0 DESCRIPTION "RogueSquadron Extractor - Texture" LANGUAGES C)
set(RSE_TEXTURE_NAME RSETexture)
# define src/headers files
FILE(GLOB_RECURSE RSE_TEX_SRCS src/*.c)
FILE(GLOB_RECURSE RSE_TEX_HRDS src/*.h)
SOURCE_GROUP("Source Files" FILES ${RSE_TEX_SRCS})
SOURCE_GROUP("Header Files" FILES ${RSE_TEX_HRDS})
# begin building RSE-Texture
#set(CMAKE_BUILD_TYPE Debug)
#include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_executable(rse-texture ${RSE_TEX_SRCS} ${RSE_TEX_HRDS})
#set_property(TARGET rse-texture PROPERTY C_STANDARD 99)
set_target_properties(rse-texture PROPERTIES OUTPUT_NAME ${RSE_TEX_NAME})
if(MSVC)
# msvc does not append 'lib' - do it here to have consistent name
#set_target_properties(rse-texture PROPERTIES PREFIX "lib")
set_target_properties(rse-texture PROPERTIES IMPORT_PREFIX "lib")
endif() endif()
target_link_libraries(rse-texture ${ZLIB_LIBRARIES} ${PNG_LIBRARIES}) set(RSP_TEXTURE_LIB_NAME RSPTexture${PROJECT_VERSION_MAJOR}${PROJECT_VERSION_MINOR})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
# add GPG signature command # Compilation option
option(RSPTEXTURE_SHARED "Build shared lib" ON)
# Push compile infos to source
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/RSPTextureLib/src/config.h @ONLY)
#configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/RSETexture/src/config.h @ONLY)
# The project is divided in two parts:
# - RSPTextureLib is the parser library for textures data, it's take HMT file as input and output extracted datas.
# It is intended to be used by others apps like rendering engine or others.
# - RSETexture is the standalone application of the library, take HMT file in argument and output PNG file.
# Artists or users can directly use this program to retrieve data in common datas format.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
add_subdirectory(RSPTextureLib)
add_subdirectory(RSETexture)
# GPG signature custom command
#add_custom_command( #add_custom_command(
# OUTPUT "" # OUTPUT ""
# COMMAND gpg --batch --detach-sign # COMMAND gpg --batch --detach-sign
# -o ${RSE_TEX_NAME}_${CI_SYS_TARGET}.gpg # -o ${RSE_MOD_NAME}_${CI_SYS_TARGET}.gpg
# ${RSE_TEX_NAME} # ${RSE_MOD_NAME}
# DEPENDS ${RSE_TEX_NAME} # DEPENDS ${RSE_MOD_NAME}
# VERBATIM # VERBATIM
#) #)
# install executable
install(TARGETS rse-texture # Install project executable
RUNTIME DESTINATION bin set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries")
set(INSTALL_INC_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Installation directory for headers")
if(RSPTEXTURE_SHARED)
set(RSE_TEXTURE_TARGETS_LIST rse-texture rsp-texture-lib rsp-texture-libstatic)
else()
set(RSE_TEXTURE_TARGETS_LIST rse-texture rsp-texture-libstatic)
endif()
install(TARGETS ${RSE_TEXTURE_TARGETS_LIST}
RUNTIME DESTINATION ${INSTALL_BIN_DIR}
LIBRARY DESTINATION ${INSTALL_LIB_DIR}
ARCHIVE DESTINATION ${INSTALL_LIB_DIR}
) )
# Install library includes
install(FILES ${RSP_PUBLIC_HRDS} DESTINATION ${INSTALL_INC_DIR})
# Install dependancies
install(FILES ${PROJECT_BINARY_DIR}/bin/libpng16.dll
DESTINATION ${INSTALL_BIN_DIR})

152
Jenkinsfile vendored
View File

@ -1,77 +1,79 @@
pipeline { pipeline {
agent any agent any
options { options {
skipDefaultCheckout(true) skipDefaultCheckout(true)
} }
environment { environment {
CI_OUTPUT_NAME = "RSE_Texture" CI_OUTPUT_NAME = "RSETexture"
CI_BUILD_NUMBER = "$BUILD_NUMBER" CI_VERSION = "2.0.0"
} CI_BUILD_NUMBER = "$BUILD_NUMBER"
stages { }
stage('Prepare') { stages {
steps { stage('Prepare') {
cleanWs() steps {
rtConanClient(id: "conan", userHome: "/home/jackcartersmith") cleanWs()
} rtConanClient(id: "conan", userHome: "/home/jackcartersmith")
} }
stage('Build') { }
steps { stage('Build') {
parallel( steps {
linux: { parallel(
dir("linux") { linux: {
checkout([$class: 'GitSCM', branches: [[name: '**']], browser: [$class: 'GiteaBrowser', repoUrl: 'https://git.jcsmith.fr/JCS-Prod/RSE-Texture'], extensions: [], userRemoteConfigs: [[credentialsId: 'jenkins-ssh', url: 'ssh://git@git.jcsmith.fr:2322/JCS-Prod/RSE-Texture.git']]]) dir("linux") {
dir("build") { checkout([$class: 'GitSCM', branches: [[name: '**']], browser: [$class: 'GiteaBrowser', repoUrl: 'https://git.jcsmith.fr/JCS-Prod/RSE-Texture'], extensions: [], userRemoteConfigs: [[credentialsId: 'jenkins-ssh', url: 'ssh://git@git.jcsmith.fr:2322/JCS-Prod/RSE-Texture.git']]])
rtConanRun(clientId: "conan", command: "install .. --build missing") sh 'git submodule update --init --recursive'
} dir("build") {
cmakeBuild buildDir: 'build', installation: 'latest', steps: [[args: 'all']] rtConanRun(clientId: "conan", command: "install .. --build=missing")
} }
}, cmakeBuild buildDir: 'build', installation: 'latest', steps: [[args: 'all']]
windows: { }
dir("windows") { },
checkout([$class: 'GitSCM', branches: [[name: '**']], browser: [$class: 'GiteaBrowser', repoUrl: 'https://git.jcsmith.fr/JCS-Prod/RSE-Texture'], extensions: [], userRemoteConfigs: [[credentialsId: 'jenkins-ssh', url: 'ssh://git@git.jcsmith.fr:2322/JCS-Prod/RSE-Texture.git']]]) windows: {
dir("build") { dir("windows") {
rtConanRun(clientId: "conan", command: "install .. --profile windows --build missing") checkout([$class: 'GitSCM', branches: [[name: '**']], browser: [$class: 'GiteaBrowser', repoUrl: 'https://git.jcsmith.fr/JCS-Prod/RSE-Terrain'], extensions: [], userRemoteConfigs: [[credentialsId: 'jenkins-ssh', url: 'ssh://git@git.jcsmith.fr:2322/JCS-Prod/RSE-Texture.git']]])
} sh 'git submodule update --init --recursive'
cmakeBuild buildDir: 'build', cmakeArgs: '-DGNU_HOST=x86_64-w64-mingw32 -DCMAKE_TOOLCHAIN_FILE=../mingw_cross_toolchain.cmake', installation: 'latest', steps: [[args: 'all']] dir("build") {
} rtConanRun(clientId: "conan", command: "install .. --profile=windows --build=missing")
} }
) cmakeBuild buildDir: 'build', cmakeArgs: '-DGNU_HOST=x86_64-w64-mingw32 -DCMAKE_TOOLCHAIN_FILE=../cmake/mingw_cross_toolchain.cmake', installation: 'latest', steps: [[args: 'all']]
} }
} }
stage('Deploy') { )
steps { }
dir("zip_linux") { }
sh 'cp ../linux/build/${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}* .' stage('Deploy') {
} steps {
dir("zip_win") { dir("zip_linux") {
sh 'cp ../windows/build/${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}* ../windows/build/*.dll .' sh 'cp -R ../linux/build/bin ../linux/build/lib ../linux/RSPTextureLib/include .'
} }
zip archive: false, dir: 'zip_linux', exclude: '', glob: '', zipFile: 'x64.zip' dir("zip_win") {
sh 'mv x64.zip ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_x64.zip' sh 'cp -R ../windows/build/bin ../windows/build/lib ../windows/RSPTextureLib/include .'
zip archive: false, dir: 'zip_win', exclude: '', glob: '', zipFile: 'mingw64.zip' }
sh 'mv mingw64.zip ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_mingw64.zip' zip archive: false, dir: 'zip_linux', exclude: '', glob: '', zipFile: 'linux_x64.zip'
archiveArtifacts(artifacts: '*.zip') sh 'mv linux_x64.zip ${CI_OUTPUT_NAME}_${CI_VERSION}.${BUILD_NUMBER}_Linux_x86_64.zip'
fingerprint(targets: '*.zip') zip archive: false, dir: 'zip_win', exclude: '', glob: '', zipFile: 'mingw64.zip'
} sh 'mv mingw64.zip ${CI_OUTPUT_NAME}_${CI_VERSION}.${BUILD_NUMBER}_mingw64.zip'
} archiveArtifacts(artifacts: '*.zip')
stage('Sign') { fingerprint(targets: '*.zip')
steps { }
sh 'ls -l' }
sh 'gpg --batch --detach-sign -o ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_x64.zip.gpg ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_x64.zip' stage('Sign') {
sh 'gpg --batch --detach-sign -o ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_mingw64.zip.gpg ${CI_OUTPUT_NAME}-1.0.1.${BUILD_NUMBER}_mingw64.zip' steps {
archiveArtifacts(artifacts: '*.gpg') sh 'gpg --batch --detach-sign -o ${CI_OUTPUT_NAME}_${CI_VERSION}.${BUILD_NUMBER}_Linux_x86_64.zip.gpg ${CI_OUTPUT_NAME}_${CI_VERSION}.${BUILD_NUMBER}_Linux_x86_64.zip'
fingerprint(targets: '*.gpg') sh 'gpg --batch --detach-sign -o ${CI_OUTPUT_NAME}_${CI_VERSION}.${BUILD_NUMBER}_mingw64.zip.gpg ${CI_OUTPUT_NAME}_${CI_VERSION}.${BUILD_NUMBER}_mingw64.zip'
} archiveArtifacts(artifacts: '*.gpg')
} fingerprint(targets: '*.gpg')
} }
/* }
post { }
always { /*
cleanWs(cleanWhenNotBuilt: false, post {
deleteDirs: true, always {
disableDeferredWipeout: true, cleanWs(cleanWhenNotBuilt: false,
notFailBuild: true) deleteDirs: true,
} disableDeferredWipeout: true,
} notFailBuild: true)
*/ }
}
*/
} }

View File

@ -1,21 +0,0 @@
Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jean-loup Gailly Mark Adler
jloup@gzip.org madler@alumni.caltech.edu

View File

@ -7,7 +7,7 @@ The collection consist of few independants modules, each of them deals with spec
All modules are independants. This is the **'TEXTURE'** module. All modules are independants. This is the **'TEXTURE'** module.
:exclamation: **Master branch is ugly for now and should not be used, please take only released versions.** :exclamation: [![Build Status](https://ci.jcsmith.fr/job/JCS-Prod/job/RSE-Texture/job/master/badge/icon)](https://ci.jcsmith.fr/job/JCS-Prod/job/RSE-Texture/job/master/)
## TEXTURE MODULE ## TEXTURE MODULE
@ -20,9 +20,14 @@ This module can do:
- Manage transparent textures, - Manage transparent textures,
- Fixed some errored RGB color encoding. - Fixed some errored RGB color encoding.
## TODO
- Discover all last unknowns fields, etc.
- Parse TEXT format for terrain module
### Using ### Using
`RSE-Texture_"version" [options] <hmt files...>` or you can simply drag&drop hmt files on it. `RSETexture [options] <hmt files...>` or you can simply drag&drop hmt files on it.
A futur main program can extract all HMT files directly from DAT file. A futur main program can extract all HMT files directly from DAT file.
Due to issue with copyrights, I can't provide samples... You need to extract HMT files yourself. Due to issue with copyrights, I can't provide samples... You need to extract HMT files yourself.
@ -32,20 +37,19 @@ Due to issue with copyrights, I can't provide samples... You need to extract HMT
### Options ### Options
- -h Print this message - -h Print this message
- -v Activate verbose output - -v,-vv Activate verbose/debug output mode respectively
- -no-subdir Extract textures directly inside current folder - -no-subdir Extract textures directly inside current folder
### Dependencies ### Dependencies
Necessary libs (provided only in windows release) for running and for compiling. Necessary libs (provided only in windows release) for running and for compiling.
- zlib (1.2.11)
- libpng (1.6.37) - libpng (1.6.37)
### Compiling ### Compiling
You can compile on both Windows (MinGW) or native Linux system thanks to CMake, you only need to adjust your dependencies on Windows or use Conan packages manager (https://conan.io). You can compile on both Windows (MinGW) or native Linux system thanks to CMake, you only need to adjust your dependencies on Windows or use Conan packages manager (https://conan.io).
zlib-dev (zlib1g-dev) and libpng16-dev distrib packages can be used on debian/ubuntu. libpng16-dev distrib package can be used on debian/ubuntu.
To compile, just clone and launch cmake: To compile, just clone and launch cmake:
@ -60,14 +64,14 @@ On Windows system, I can suggest you to use Conan support to help you with depen
```shell ```shell
mkdir build mkdir build
cd build cd build
conan install .. --build=libpng --build=zlib conan install .. --build=missing
cmake .. -G "MinGW Makefiles" cmake .. -G "MinGW Makefiles"
make make
``` ```
If you want to do it manually without Conan support, you will probably need to specify the dependency flags for CMake. Ex: If you want to do it manually without Conan support, you will probably need to specify the dependency flags for CMake. Ex:
`cmake.exe -D"ZLIB_INCLUDE_DIR=zlib/1.2.11/include" -D"ZLIB_LIBRARY=zlib/1.2.11/lib/libzlib.dll.a" -D"PNG_PNG_INCLUDE_DIR=libpng/1.6.37/include" -D"PNG_LIBRARY=libpng/1.6.37/lib/libpng.dll.a" . -G "MinGW Makefiles"` `cmake.exe -D"ZLIB_INCLUDE_DIR=zlib/1.2.12/include" -D"ZLIB_LIBRARY=zlib/1.2.12/lib/libzlib.dll.a" -D"PNG_PNG_INCLUDE_DIR=libpng/1.6.37/include" -D"PNG_LIBRARY=libpng/1.6.37/lib/libpng.dll.a" . -G "MinGW Makefiles"`
We can also use cross-compilation (after installing `mingw64` and `cmake` packages on your distrib): We can also use cross-compilation (after installing `mingw64` and `cmake` packages on your distrib):
@ -75,8 +79,8 @@ We can also use cross-compilation (after installing `mingw64` and `cmake` packag
mkdir build && cd build mkdir build && cd build
cmake -DGNU_HOST=x86_64-w64-mingw32 \ cmake -DGNU_HOST=x86_64-w64-mingw32 \
-DCMAKE_TOOLCHAIN_FILE=../mingw_cross_toolchain.cmake \ -DCMAKE_TOOLCHAIN_FILE=../mingw_cross_toolchain.cmake \
-D"ZLIB_INCLUDE_DIR=zlib/1.2.11/include" \ -D"ZLIB_INCLUDE_DIR=zlib/1.2.12/include" \
-D"ZLIB_LIBRARY=zlib/1.2.11/lib/libzlib.dll.a" \ -D"ZLIB_LIBRARY=zlib/1.2.12/lib/libzlib.dll.a" \
-D"PNG_PNG_INCLUDE_DIR=libpng/1.6.37/include" \ -D"PNG_PNG_INCLUDE_DIR=libpng/1.6.37/include" \
-D"PNG_LIBRARY=libpng/1.6.37/lib/libpng.dll.a" \ -D"PNG_LIBRARY=libpng/1.6.37/lib/libpng.dll.a" \
.. ..

43
RSETexture/CMakeLists.txt Normal file
View File

@ -0,0 +1,43 @@
# CMakeLists.txt
####################################################
# Written by JackCarterSmith, 2022
# This code is released under the RSE license.
####################################################
# General configuration
include(CheckIncludeFile)
include(CheckCSourceCompiles)
# Import needed packages and references their include path
find_package(PNG 1.6.37 REQUIRED)
include_directories(${PNG_INCLUDE_DIR})
# Define src/headers files
file(GLOB_RECURSE RSE_TEXTURE_SOURCES ./src/*.c)
source_group("Source Files" FILES ${RSE_TEXTURE_SOURCES})
# Building instructions for RSE-Texture
if(DEFINED ENV{CI})
set(CMAKE_BUILD_TYPE RELEASE)
endif()
# Declare standalone application
add_executable(rse-texture ${RSE_TEXTURE_SOURCES})
set_property(TARGET rse-texture PROPERTY C_STANDARD 90)
#target_include_directories(rse-texture PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
set_target_properties(rse-texture PROPERTIES OUTPUT_NAME ${RSE_TEXTURE_NAME})
# Link externals libraries to the linker
if(MSVC)
# msvc does not append 'lib' - do it here to have consistent name
set_target_properties(rse-texture PROPERTIES IMPORT_PREFIX "lib")
target_link_libraries(rse-texture PRIVATE rsp-texture-libstatic ${PNG_LIBRARIES})
else()
target_link_libraries(rse-texture PRIVATE rsp-texture-libstatic ${PNG_LIBRARIES})
endif()

179
RSETexture/src/RSETexture.c Normal file
View File

@ -0,0 +1,179 @@
/**
* @file RSETexture.c
* @date 28/08/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief HMT texture parser and export to PNG format.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(_WIN32)
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include "options.h"
#include <RSPTexture.h>
#include <RSPTexture_errordefs.h>
#include "texture_export.h"
/*
* Internal functions declarations
*/
static unsigned int mainProcess(int args_cnt, char* args_value[], T_PROG_OPTIONS* opt_ptr);
static void createSubDir(char *dirName);
static unsigned short checkInputArgs(T_PROG_OPTIONS* opt_ptr, int p_arg_nbr, char* p_args[]);
static void dispHelp();
/*
* - MAIN -
*/
int main(int argc, char *argv[]) {
T_PROG_OPTIONS _opts;
unsigned char p;
// Hello world!
printf("\n*~[ Rogue Squadron Extractor (RSE) - RSPTextureLib v%s ]~*\n", RSPTexture_getVersion());
// Check for arguments
if (argc < 2) {
printf("\n[ERR] No input file/commands specified!\n");
dispHelp();
return RSPLIB_ERROR_ARGS_NULL;
}
// Create options for programs according to user's arguments.
p = checkInputArgs(&_opts, argc, argv);
if ( p == RSPLIB_ERROR_GENERIC ) return RSPLIB_SUCCESS;
else if ( p != RSPLIB_SUCCESS ) return p;
return mainProcess(argc, argv, &_opts);
}
/*
* Private functions definition
*/
static unsigned int mainProcess(int args_cnt, char* args_value[], T_PROG_OPTIONS* p_opts) {
unsigned short file_index;
RSPTEXTURE_PARAMETERS libParams;
T_RSPTEXTURE_HMT* hmtStruct = NULL;
unsigned int i;
libParams.raw = p_opts->raw & 0x7;
// Manage multiple inputs files
for ( file_index = p_opts->input_files_cnt; file_index < args_cnt; file_index++ )
{
printf("\n=============================================\n[INFO] - Parsing file: %s ...\n", args_value[file_index]);
// Allocate T_RSPTEXTURE_HMT structure to store extracted datas.
hmtStruct = calloc(1, sizeof(T_RSPTEXTURE_HMT));
if (hmtStruct) {
// Parse data from HMT file and put in T_RSPTEXTURE_HMT structure.
if (RSPTexture_processHMTFile(hmtStruct, args_value[file_index], libParams) != RSPLIB_SUCCESS) {
printf("[ERR] Failed to parse datas from %s\n", args_value[file_index]);
RSPTexture_freeHMT(hmtStruct);
return RSPLIB_ERROR_PROCESS;
}
} else return RSPLIB_ERROR_MEMORY;
// Create output folders structure.
if (p_opts->output_dir) createSubDir(args_value[file_index]);
// Export each texture as a PNG picture.
for ( i = 0; i < hmtStruct->textures_count; i++ ) {
switch (hmtStruct->textures[i].type) {
case 0:
case 1:
case 3:
case 4:
case 5:
if (exportPNGTexture(&(hmtStruct->textures[i]), args_value[file_index], p_opts) == RSPLIB_SUCCESS)
printf("[INFO] Successfully exported texture %s to PNG format.\n", hmtStruct->textures[i].name);
else
printf("[ERR] Failed to export texture %s to PNG format!\n", hmtStruct->textures[i].name);
break;
default:
printf("[WARN] Can't export %s ! Image type %d not currently supported!\n", hmtStruct->textures[i].name, hmtStruct->textures[i].type);
}
}
RSPTexture_freeHMT(hmtStruct);
}
return RSPLIB_SUCCESS;
}
static unsigned short checkInputArgs(T_PROG_OPTIONS* opt_ptr, int p_arg_nbr, char* p_args[]) {
char test[256];
int i;
// Set default options
opt_ptr->raw = 0;
opt_ptr->output_dir = 1;
if (p_arg_nbr > 1) {
for ( i = 1; i < p_arg_nbr; i++) {
strcpy(test, p_args[i]);
if (p_args[i][0] != '-') break;
if (strcmp(p_args[i], "-h") == 0) {
dispHelp();
return RSPLIB_ERROR_GENERIC;
} else if (strcmp(p_args[i], "-v") == 0) {
opt_ptr->verbose_mode = 1;
printf("[OPTN] Verbose enabled.\n");
} else if (strcmp(p_args[i], "-vv") == 0) {
opt_ptr->verbose_mode = 1;
opt_ptr->debug_mode = 1;
printf("[OPTN] Debug enabled.\n");
} else if (strcmp(p_args[i], "-vvv") == 0) {
opt_ptr->verbose_mode = 1;
opt_ptr->debug_mode = 1;
opt_ptr->god_mode = 1;
printf("[OPTN] God damn it!\n");
} else if (strcmp(p_args[i], "-no-subdir") == 0) {
opt_ptr->output_dir = 0;
printf("[OPTN] Export to current directory.\n");
} else {
printf("[ERR] Unknown option: %s\n", p_args[i]);
}
}
opt_ptr->input_files_cnt = i;
return RSPLIB_SUCCESS;
}
return RSPLIB_ERROR_ARGS_NULL;
}
static void createSubDir(char *dirName) {
if (dirName == NULL) return;
char _dir[1024];
snprintf(_dir, 1024, "%s-out", dirName);
#ifdef _WIN32
CreateDirectory(_dir, NULL);
#else
mkdir(_dir, 0755);
#endif
}
static void dispHelp() {
printf("\n");
printf("Options:\n -h Print this message\n");
printf(" -v -vv Activate verbose console output\n");
printf(" -no-subdir Export models inside current folder\n");
printf("\n");
printf("Usage: RSETexture [options] <hmt_files...>\n");
printf("\n");
}

29
RSETexture/src/options.h Normal file
View File

@ -0,0 +1,29 @@
/**
* @file options.h
* @date 29/07/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Shared options structure definition and declaration.
*
*/
#ifndef OPTIONS_H_
#define OPTIONS_H_
/// Options structure
typedef union u_prog_options {
struct {
unsigned char verbose_mode:1; //!< Output simple details about ID and other "light" things.
unsigned char debug_mode:1; //!< Output all values of faces, indices and vertices and others "heavy" things.
unsigned char god_mode:1; //!< Dev only. Output experimental values.
unsigned char output_dir:1; //!< Export extracted datas to a sub-directory.
unsigned short reserved0:12; //!< For future use.
unsigned short input_files_cnt; //!< Internal files counters.
};
unsigned int raw; //!< Raw options access for bit-masking or memory copy/compare.
} T_PROG_OPTIONS ;
#endif /* OPTIONS_H_ */

View File

@ -0,0 +1,96 @@
/**
* @file texture_export.c
* @date 29/08/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Export texture datas to PNG format.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <png.h>
#include "options.h"
#include <RSPTexture_datatypes.h>
#include <RSPTexture_errordefs.h>
#include "texture_export.h"
static inline T_R8G8B8A8 *getPixelAt(const T_RSPTEXTURE_TEXTURE *tex, const unsigned int posX , const unsigned int posY) {
return tex->pixels + tex->width * posY + posX;
}
unsigned char exportPNGTexture(const T_RSPTEXTURE_TEXTURE* pTextureObj, const char* out_path, T_PROG_OPTIONS* p_opts) {
char export_path[1024];
FILE *_png_f = NULL;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
size_t x,y;
png_byte **row_ptrs = NULL;
T_R8G8B8A8 *pixel = NULL;
//int pixel_size = 3;
//int depth = 8; //bit par color channel (RGB)
if (pTextureObj == NULL || out_path == NULL)
return RSPLIB_ERROR_ARGS_NULL;
#ifdef _WIN32
if (p_opts->output_dir)
snprintf(export_path, 1024, "%s-out\\%s.png", out_path, pTextureObj->name);
else
snprintf(export_path, 1024, "%s.png", pTextureObj->name);
#else
if (p_opts->output_dir)
snprintf(export_path, 1024, "%s-out/%s.png", out_path, pTextureObj->name);
else
snprintf(export_path, 1024, "%s.png", pTextureObj->name);
#endif
// Open export file and add PNG header
_png_f = fopen(export_path, "wb");
if (_png_f == NULL) return RSPLIB_ERROR_MEMORY;
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fclose(_png_f);
return RSPLIB_ERROR_MEMORY;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fclose(_png_f);
return RSPLIB_ERROR_MEMORY;
}
// Set image attributes
png_set_IHDR(png_ptr, info_ptr, pTextureObj->width, pTextureObj->height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
// Store PNG datas in buffer
row_ptrs = png_malloc(png_ptr, pTextureObj->height * sizeof(png_byte *));
for ( y = 0; y < pTextureObj->height; y++ ) {
png_byte *row = png_malloc(png_ptr, pTextureObj->width * sizeof(T_R8G8B8A8));
row_ptrs[y] = row;
for ( x = 0; x < pTextureObj->width; x++ ) {
pixel = getPixelAt(pTextureObj, x , y);
*row++ = pixel->r;
*row++ = pixel->g;
*row++ = pixel->b;
*row++ = pixel->a;
}
}
// Write pixels datas
png_init_io(png_ptr, _png_f);
png_set_rows(png_ptr, info_ptr, row_ptrs);
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
// Clean up
for ( y = 0; y < pTextureObj->height; y++ ) {
png_free(png_ptr, row_ptrs[y]);
}
png_free(png_ptr, row_ptrs);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(_png_f);
return RSPLIB_SUCCESS;
}

View File

@ -0,0 +1,15 @@
/**
* @file texture_export.h
* @date 29/08/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Export texture datas to PNG format.
*
*/
#ifndef TEXTURE_EXPORT_H_
#define TEXTURE_EXPORT_H_
unsigned char exportPNGTexture(const T_RSPTEXTURE_TEXTURE* pTextureObj, const char* out_path, T_PROG_OPTIONS* p_opts);
#endif /* TEXTURE_EXPORT_H_ */

View File

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

View File

@ -0,0 +1,101 @@
/**
* @file RSPTexture.h
* @date 25/08/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Rogue Squadron Parser texture library, used to decode HMT datas
* from original game file and access them through public interface.
*
*/
#include "RSPTexture_datatypes.h"
#ifndef RSPTEXTURELIB_H_
#define RSPTEXTURELIB_H_
#if defined(_MSC_VER)
# define RSPTEXTURE_ABI_EXPORT __declspec(dllexport)
# define RSPTEXTURE_ABI_IMPORT __declspec(dllimport)
#elif __GNUC__ >= 4
# define RSPTEXTURE_ABI_EXPORT __attribute__ ((visibility("default")))
# define RSPTEXTURE_ABI_IMPORT __attribute__ ((visibility("default")))
#else
# define RSPTEXTURE_ABI_EXPORT
# define RSPTEXTURE_ABI_IMPORT
#endif
#if defined(RSPTEXTURE_DLL)
# if defined(WIN32)
# if defined(RSPTEXTURE_DLLBUILD)
# define RSPTEXTURE_EXTERN extern RSPTEXTURE_ABI_EXPORT
# else
# define RSPTEXTURE_EXTERN extern RSPTEXTURE_ABI_IMPORT
# endif
# endif
#endif
#ifndef RSPTEXTURE_EXTERN
# define RSPTEXTURE_EXTERN extern
#endif
#ifdef __cplusplus
extern "C" {
#endif
///////////////////////////////////////////////////////////////////////////////
// Library's functions declaration
///////////////////////////////////////////////////////////////////////////////
/**
* @brief Get the current library version.
* @return Char array of the version, escape char included.
*/
RSPTEXTURE_EXTERN char* RSPTexture_getVersion( void );
/**
* @brief Run texture parser for the specified file in file system.
* @details Texture library can process HMT file from file system. It's a easy
* approach using this library for debugging purpose.
*
* @param[out] hmtStruct HMT texture structure to be filled with parsed datas.
* @param[in] filePath Path to the HMT file in system.
* @param[in] params Parser options. See RSPTEXTURE_PARAMETERS.
*
* @return Error status, return RSPLIB_SUCCESS in nominal case.
*/
RSPTEXTURE_EXTERN unsigned short RSPTexture_processHMTFile(
T_RSPTEXTURE_HMT* hmtStruct, const char* const filePath,
const RSPTEXTURE_PARAMETERS params
);
/**
* @brief Run texture parser for the specified file in memory.
* @details Texture library can process HMT file directly stored in RAM memory,
* you must load the file beforehand through a malloc/memcpy call.
* @warning No controls routines are implemented to verify file length!
*
* @param[out] hmtStruct HMT texture structure to be filled with parsed datas.
* @param[in] memFilePtr Pointer to the beginning of the file in memory.
* @param[in] memFileSize Size of the file in bytes.
* @param[in] params Parser options. See RSPTEXTURE_PARAMETERS.
*
* @return Error status, return RSPLIB_SUCCESS in nominal case.
*/
RSPTEXTURE_EXTERN unsigned short RSPTexture_processHMTFileMemory(
T_RSPTEXTURE_HMT* hmtStruct, const void* const memFilePtr, const long memFileSize,
const RSPTEXTURE_PARAMETERS params
);
/**
* @brief Clean HMT object and it's childrens from memory.
* @param[in] hmtStruct Pointer to data to be cleaned up.
*/
RSPTEXTURE_EXTERN void RSPTexture_freeHMT( T_RSPTEXTURE_HMT* hmtStruct );
#ifdef __cplusplus
}
#endif
#endif /* RSPTEXTURELIB_H_ */

View File

@ -0,0 +1,86 @@
/**
* @file RSPTexture_datatypes.h
* @date 25/08/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief RSP Texture workflow structures definitions
*
*/
#ifndef RSPTEXTURELIB_DATATYPES_H_
#define RSPTEXTURELIB_DATATYPES_H_
#ifdef __cplusplus
extern "C" {
#endif
///////////////////////////////////////////////////////////////////////////////
// Configuration structure
///////////////////////////////////////////////////////////////////////////////
typedef union u_rsptexture_parameters {
struct {
unsigned char verbose_mode:1; //!< Output simple details about ID and other "light" things.
unsigned char debug_mode:1; //!< Output all values of faces, indices and vertices and others "heavy" things.
unsigned char god_mode:1; //!< Dev only. Output experimental values.
unsigned char reserved0:5; //!< For future use.
};
unsigned char raw; //!< Raw options access for bit-masking or memory copy/compare.
} RSPTEXTURE_PARAMETERS ;
////////////////////////////////////////////////////////////////////////////////
// Lib's structure definitions
////////////////////////////////////////////////////////////////////////////////
#ifndef MEMFILE
typedef char* MEMFILE;
#endif
#ifndef T_R8G8B8
typedef struct r8g8b8 { unsigned char r,g,b; } T_R8G8B8;
#endif
#ifndef T_R8G8B8A8
typedef struct r8g8b8a8 { unsigned char r,g,b,a; } T_R8G8B8A8;
#endif
typedef unsigned char T_SAMPLE;
typedef struct rsptexture_material {
unsigned char name[17]; // 16 + 1 string ending \0
unsigned short type;
unsigned short texture_index; //TODO: pointer to a T_RSPTEXTURE_TEXTURE element?
} T_RSPTEXTURE_MATERIAL;
typedef struct rsptexture_texture {
unsigned char name[17]; // 16 + 1 string ending \0
unsigned short width;
unsigned short height;
unsigned char type;
unsigned char sample_bits;
unsigned int palette_entries;
T_R8G8B8A8 alpha_color;
unsigned int palette_offset; //TODO: useless?
unsigned int pixels_offset; //TODO: useless?
T_R8G8B8A8* pixels;
} T_RSPTEXTURE_TEXTURE;
typedef struct rsptexture_hmt {
unsigned int materials_count;
unsigned int textures_count;
unsigned int texture_offset; //TODO: useless?
T_RSPTEXTURE_MATERIAL* materials;
T_RSPTEXTURE_TEXTURE* textures;
} T_RSPTEXTURE_HMT;
#ifdef __cplusplus
}
#endif
#endif /* RSPTEXTURELIB_DATATYPES_H_ */

View File

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

View File

@ -0,0 +1,53 @@
/**
* @file RSPTexture.c
* @date 25/08/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief HMT textures datas parser and export to PNG format.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "RSPTexture_errordefs.h"
#include "RSPTexture_datatypes.h"
#include "hmt_parser.h"
#include "RSPTexture.h"
inline char* RSPTexture_getVersion( void ) {
return PRG_VERSION;
}
unsigned short RSPTexture_processHMTFile( T_RSPTEXTURE_HMT* hmtStruct, const char* const filePath,
const RSPTEXTURE_PARAMETERS params ) {
if ( hmtStruct == NULL || filePath == NULL ) return RSPLIB_ERROR_ARGS_NULL;
return RSP_TextureLib_ParseHMTFile(filePath, hmtStruct, &params);
}
unsigned short RSPTexture_processHMTFileMemory( T_RSPTEXTURE_HMT* hmtStruct, const void* const memFilePtr,
const long memFileSize, const RSPTEXTURE_PARAMETERS params ) {
if ( hmtStruct == NULL || memFilePtr == NULL ) return RSPLIB_ERROR_ARGS_NULL;
return RSP_TextureLib_ParseHMTMemFile((MEMFILE)memFilePtr, hmtStruct, &params);
}
void RSPTexture_freeHMT(T_RSPTEXTURE_HMT* hmtStruct) {
unsigned int i;
if (hmtStruct == NULL) return;
if ((hmtStruct->textures_count > 0) && hmtStruct->textures) {
for ( i = 0; i < hmtStruct->textures_count; i++ )
if (hmtStruct->textures[i].pixels) free(hmtStruct->textures[i].pixels);
}
if (hmtStruct->materials) free(hmtStruct->materials);
free(hmtStruct);
}

View File

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

View File

@ -0,0 +1,424 @@
/**
* @file hmt_parser.c
* @date 26/08/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Process HMT file structure and extract its datas.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "RSPTexture_errordefs.h"
#include "RSPTexture_datatypes.h"
#include "hmt_struct.h"
#include "hmt_parser.h"
////////////////////////////////////////////////////////////////////////////////
// Private functions declarations
////////////////////////////////////////////////////////////////////////////////
static unsigned short ExtractTextureHMT(T_RSPTEXTURE_HMT*, const MEMFILE, const RSPTEXTURE_PARAMETERS*);
static unsigned short ExtractMaterials(T_RSPTEXTURE_HMT*, const MEMFILE, const RSPTEXTURE_PARAMETERS*);
static unsigned short ExtractTextures(T_RSPTEXTURE_HMT*, const MEMFILE, const RSPTEXTURE_PARAMETERS*);
static unsigned short TranslatePixels(T_RSPTEXTURE_TEXTURE*, const T_SAMPLE*, const T_R8G8B8*);
static unsigned short isTransparentColor(const T_R8G8B8A8, const T_R8G8B8A8);
static void convert4bitsGreyTo32bitsRGBA(T_R8G8B8A8*, const T_SAMPLE*, const unsigned int, const T_R8G8B8A8);
static void convert4bitsTo32bitsRGBA(T_R8G8B8A8*, const T_SAMPLE*, const unsigned int, const T_R8G8B8*, const T_R8G8B8A8);
static void convert8bitsTo32bitsRGBA(T_R8G8B8A8*, const T_SAMPLE*, const unsigned int, const T_R8G8B8*, const T_R8G8B8A8);
static void useOddBytes(T_R8G8B8A8*, const T_SAMPLE*, const unsigned int);
////////////////////////////////////////////////////////////////////////////////
// Public functions definition
////////////////////////////////////////////////////////////////////////////////
unsigned short RSP_TextureLib_ParseHMTMemFile(const MEMFILE pMemFile, T_RSPTEXTURE_HMT* hmtStruct, const RSPTEXTURE_PARAMETERS* pParams) {
unsigned char err = RSPLIB_SUCCESS;
if (hmtStruct != NULL && pMemFile != NULL) {
// Do the magic!
err = ExtractTextureHMT(hmtStruct, pMemFile, pParams);
} else err = RSPLIB_ERROR_ARGS_NULL;
return err;
}
unsigned short RSP_TextureLib_ParseHMTFile(const char* fileName, T_RSPTEXTURE_HMT* hmtStruct, const RSPTEXTURE_PARAMETERS* pParams) {
unsigned char err = RSPLIB_SUCCESS;
long fileSize;
FILE* fStream = NULL;
MEMFILE memFile = NULL;
if (hmtStruct != NULL && fileName != NULL) {
// Open file
fStream = fopen(fileName, "rb");
if (fStream != NULL) {
// Determine file size in bytes
fseek(fStream, 0, SEEK_END);
fileSize = ftell(fStream);
fseek(fStream, 0, SEEK_SET);
if (pParams->verbose_mode) printf("[DBG] > Input file size: %ld bytes\n", fileSize);
memFile = malloc(fileSize + 1);
if (memFile != NULL) {
// Copy file in RAM
fread(memFile, fileSize, 1, fStream);
fclose(fStream);
// Do the magic!
err = ExtractTextureHMT(hmtStruct, memFile, pParams);
free(memFile);
} else {
fclose(fStream);
err = RSPLIB_ERROR_MEMORY;
if (pParams->verbose_mode) printf("[ERR] Can't allocate enough memory for file processing!\n");
}
} else {
err = RSPLIB_ERROR_IO;
if (pParams->verbose_mode) printf("[ERR] Input file %s not found!\n", fileName);
}
} else err = RSPLIB_ERROR_ARGS_NULL;
return err;
}
////////////////////////////////////////////////////////////////////////////////
// Private functions definition
////////////////////////////////////////////////////////////////////////////////
/**
* @brief Extract datas from texture HMT in memory.
*
* @param[out] pHmtStruct Take T_RSPTEXTURE_HMT structure to fill with parsed 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 ExtractTextureHMT(T_RSPTEXTURE_HMT* pHmtStruct, const MEMFILE pMemfile, const RSPTEXTURE_PARAMETERS* pParams) {
unsigned short errorCode = RSPLIB_SUCCESS;
if (pHmtStruct == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL;
// Get global infos
pHmtStruct->materials_count = ((T_HMTFILE_HEADER1 *)pMemfile)->materials_count;
pHmtStruct->texture_offset = ((T_HMTFILE_HEADER1 *)pMemfile)->textures_offset;
pHmtStruct->textures_count = ((T_HMTFILE_HEADER2 *)(pMemfile + pHmtStruct->texture_offset))->textures_count;
printf("[INFO] > Materials count: %d\n", pHmtStruct->materials_count);
printf("[INFO] > Textures count: %d\n", pHmtStruct->textures_count);
if (pParams->verbose_mode) printf("[DBG] > Texture offset: 0x%X\n", pHmtStruct->texture_offset);
printf("\n");
// Get materials if any
if (pHmtStruct->materials_count > 0)
errorCode |= ExtractMaterials(pHmtStruct, pMemfile, pParams);
// Get textures if any
if (pHmtStruct->textures_count > 0)
errorCode |= ExtractTextures(pHmtStruct, pMemfile, pParams);
return errorCode;
}
/**
* @brief Retrieve materials datas from HMT file.
*
* @param[in|out] pHmt Take HMT structure to get the T_HMTFILE_MATERIAL buffer and 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 ExtractMaterials(T_RSPTEXTURE_HMT* pHmt, const MEMFILE pMemfile, const RSPTEXTURE_PARAMETERS* pParams) {
unsigned int i;
if (pHmt == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL;
pHmt->materials = (T_RSPTEXTURE_MATERIAL *)calloc(pHmt->materials_count, sizeof(T_RSPTEXTURE_MATERIAL));
if (pHmt->materials == NULL) return RSPLIB_ERROR_MEMORY;
for ( i = 0; i < pHmt->materials_count; i++ ) {
if (pParams->debug_mode) printf("\n-----------------------Begin of material #%d-------------------------\n", i);
// Get material name
//memcpy(pHmt->materials[i].name, ((T_HMTFILE_MATERIAL *)(pMemfile + sizeof(T_HMTFILE_MATERIAL) * (i + 1)))->name, 16);
snprintf((char *)pHmt->materials[i].name, 16, "%s", ((T_HMTFILE_MATERIAL *)(pMemfile +
sizeof(T_HMTFILE_HEADER1) + sizeof(T_HMTFILE_MATERIAL) * i))->name);
// Get material datas
pHmt->materials[i].type = ((T_HMTFILE_MATERIAL *)(pMemfile +
sizeof(T_HMTFILE_HEADER1) + sizeof(T_HMTFILE_MATERIAL) * i))->type;
pHmt->materials[i].texture_index = ((T_HMTFILE_MATERIAL *)(pMemfile +
sizeof(T_HMTFILE_HEADER1) + sizeof(T_HMTFILE_MATERIAL) * i))->texture_index;
if (pParams->verbose_mode) {
printf("[INFO] > Material name: %s\n", pHmt->materials[i].name);
printf("[INFO] > Material type: %d\n", pHmt->materials[i].type);
printf("[INFO] > Material text. index: %d\n", pHmt->materials[i].texture_index);
}
if (pParams->debug_mode) {
printf("[DBG] > Material reserved0: %.8f\n", ((T_HMTFILE_MATERIAL *)(pMemfile +
sizeof(T_HMTFILE_HEADER1) + sizeof(T_HMTFILE_MATERIAL) * i))->reserved0);
printf("[DBG] > Material reserved1: %.8f\n", ((T_HMTFILE_MATERIAL *)(pMemfile +
sizeof(T_HMTFILE_HEADER1) + sizeof(T_HMTFILE_MATERIAL) * i))->reserved1);
printf("[DBG] > Material reserved2 (zero): 0x%X\n", ((T_HMTFILE_MATERIAL *)(pMemfile +
sizeof(T_HMTFILE_HEADER1) + sizeof(T_HMTFILE_MATERIAL) * i))->reserved2);
printf("[DBG] > Material reserved3 (0xA): 0x%X\n", ((T_HMTFILE_MATERIAL *)(pMemfile +
sizeof(T_HMTFILE_HEADER1) + sizeof(T_HMTFILE_MATERIAL) * i))->reserved3);
}
if (pParams->debug_mode) printf("\n-----------------------End of material #%d---------------------------\n", i);
}
return RSPLIB_SUCCESS;
}
/**
* @brief Retrieve textures datas from HMT file.
*
* @param[in|out] pHmt Take HMT structure to get the T_HMTFILE_TEXTURE_HEADER buffer and 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 ExtractTextures(T_RSPTEXTURE_HMT* pHmt, const MEMFILE pMemfile, const RSPTEXTURE_PARAMETERS* pParams) {
T_R8G8B8* _palette = NULL;
T_SAMPLE* _samples = NULL;
unsigned int i;
if (pHmt == NULL || pMemfile == NULL) return RSPLIB_ERROR_ARGS_NULL;
pHmt->textures = (T_RSPTEXTURE_TEXTURE *)calloc(pHmt->textures_count, sizeof(T_RSPTEXTURE_TEXTURE));
if (pHmt->textures == NULL) return RSPLIB_ERROR_MEMORY;
for ( i = 0; i < pHmt->textures_count; i++ ) {
if (pParams->debug_mode) printf("\n-----------------------Begin of texture #%d-------------------------\n", i);
// Get texture size infos
pHmt->textures[i].width = ((T_HMTFILE_TEXTURE_HEADER *)(pMemfile + pHmt->texture_offset +
sizeof(T_HMTFILE_HEADER2) + sizeof(T_HMTFILE_TEXTURE_HEADER) * i))->tex_width;
pHmt->textures[i].height = ((T_HMTFILE_TEXTURE_HEADER *)(pMemfile + pHmt->texture_offset +
sizeof(T_HMTFILE_HEADER2) + sizeof(T_HMTFILE_TEXTURE_HEADER) * i))->tex_height;
pHmt->textures[i].type = ((T_HMTFILE_TEXTURE_HEADER *)(pMemfile + pHmt->texture_offset +
sizeof(T_HMTFILE_HEADER2) + sizeof(T_HMTFILE_TEXTURE_HEADER) * i))->tex_format.type;
switch (pHmt->textures[i].type) {
case 0:
pHmt->textures[i].sample_bits = 4;
pHmt->textures[i].palette_entries = 16;
break;
case 1:
pHmt->textures[i].sample_bits = 8;
pHmt->textures[i].palette_entries = 256;
break;
case 2:
pHmt->textures[i].sample_bits = 16;
pHmt->textures[i].palette_entries = 0;
break;
case 3:
pHmt->textures[i].sample_bits = 32;
pHmt->textures[i].palette_entries = 0;
break;
case 4:
pHmt->textures[i].sample_bits = 4;
pHmt->textures[i].palette_entries = 0;
break;
case 5:
pHmt->textures[i].sample_bits = 8;
pHmt->textures[i].palette_entries = 0;
break;
default:
pHmt->textures[i].sample_bits = 0;
pHmt->textures[i].palette_entries = 0;
}
memcpy(&pHmt->textures[i].alpha_color, &((T_HMTFILE_TEXTURE_HEADER *)(pMemfile + pHmt->texture_offset +
sizeof(T_HMTFILE_HEADER2) + sizeof(T_HMTFILE_TEXTURE_HEADER) * i))->tex_format.transparent_color, sizeof(T_R8G8B8A8));
// Get texture datas offsets
pHmt->textures[i].pixels_offset = ((T_HMTFILE_TEXTURE_HEADER *)(pMemfile + pHmt->texture_offset +
sizeof(T_HMTFILE_HEADER2) + sizeof(T_HMTFILE_TEXTURE_HEADER) * i))->pixels_offset;
pHmt->textures[i].palette_offset = ((T_HMTFILE_TEXTURE_HEADER *)(pMemfile + pHmt->texture_offset +
sizeof(T_HMTFILE_HEADER2) + sizeof(T_HMTFILE_TEXTURE_HEADER) * i))->palette_offset;
// Get texture name
//memcpy(pHmt->textures[i].name, pMemfile + ((T_HMTFILE_TEXTURE_HEADER *)(pMemfile + pHmt->texture_offset + sizeof(T_HMTFILE_TEXTURE_HEADER) * (i + 1)))->texname_offset, 16);
snprintf((char *)pHmt->textures[i].name, 16, "%s", pMemfile + ((T_HMTFILE_TEXTURE_HEADER *)(pMemfile + pHmt->texture_offset +
sizeof(T_HMTFILE_HEADER2) + sizeof(T_HMTFILE_TEXTURE_HEADER) * i))->texname_offset);
if (pParams->verbose_mode) {
printf("[INFO] > Texture name: %s\n", pHmt->textures[i].name);
printf("[INFO] > Texture size: %dx%d\n", pHmt->textures[i].width, pHmt->textures[i].height);
printf("[INFO] > Texture type: %d\n", pHmt->textures[i].type);
printf("[INFO] > Samplebits: %d\n", pHmt->textures[i].sample_bits);
printf("[INFO] > Palette entries: %d\n", pHmt->textures[i].palette_entries);
printf("[INFO] > Texture bits per sample: %d\n", ((T_HMTFILE_TEXTURE_HEADER *)(pMemfile + pHmt->texture_offset + sizeof(T_HMTFILE_HEADER2) + sizeof(T_HMTFILE_TEXTURE_HEADER) * i))->tex_format.sample_bitsize);
printf("[INFO] > Texture transparent color: %d %d %d %d\n", pHmt->textures[i].alpha_color.r, pHmt->textures[i].alpha_color.g, pHmt->textures[i].alpha_color.b, pHmt->textures[i].alpha_color.a);
}
if (pParams->debug_mode) {
printf("[DBG] > Texture unknown0: 0x%X\n", ((T_HMTFILE_TEXTURE_HEADER *)(pMemfile + pHmt->texture_offset + sizeof(T_HMTFILE_HEADER2) + sizeof(T_HMTFILE_TEXTURE_HEADER) * i))->tex_format.unknown0);
if (((T_HMTFILE_TEXTURE_HEADER *)(pMemfile + pHmt->texture_offset + sizeof(T_HMTFILE_HEADER2) + sizeof(T_HMTFILE_TEXTURE_HEADER) * i))->tex_format.reserved0 != 1)
printf("[DBG] > Texture: Always 1 different.\n");
printf("[DBG] > Texture palette offset: 0x%X\n", pHmt->textures[i].palette_offset);
printf("[DBG] > Texture pixels offset: 0x%X\n", pHmt->textures[i].pixels_offset);
}
// Retrieve palette datas from HMT file
switch (pHmt->textures[i].palette_entries) {
case 16:
case 256:
_palette = (T_R8G8B8 *)malloc(sizeof(T_R8G8B8) * pHmt->textures[i].palette_entries);
if (_palette)
memcpy(_palette, pMemfile + pHmt->textures[i].palette_offset, sizeof(T_R8G8B8) * pHmt->textures[i].palette_entries);
else return RSPLIB_ERROR_MEMORY;
break;
default:
break;
}
// Retrieve samples from HMT file
//TODO: better approach?
_samples = (T_SAMPLE *)malloc(pHmt->textures[i].width * pHmt->textures[i].height * pHmt->textures[i].sample_bits / 8);
if (_samples) {
memcpy(_samples, pMemfile + pHmt->textures[i].pixels_offset, pHmt->textures[i].width * pHmt->textures[i].height * pHmt->textures[i].sample_bits / 8);
//if (pHmt->textures[i].type == 2) memcpy(pHmt->textures[i].samples, pMemfile + pHmt->textures[i].pixels_offset, pHmt->textures[i].width * pHmt->textures[i].height * pHmt->textures[i].sample_bits / (8 * 4)); //TODO: manage texture type 2
} else return RSPLIB_ERROR_MEMORY;
// Decode palette and samples to pixels datas
if (_palette && _samples) TranslatePixels(&(pHmt->textures[i]), _samples, _palette);
if (pParams->debug_mode) printf("\n-----------------------End of texture #%d---------------------------\n", i);
}
return RSPLIB_SUCCESS;
}
/**
* @brief Convert samples to pixels using palette and texture informations.
*
* @param[in|out] pTexture Take texture structure to get the pixels buffer and texture datas.
* @param[in] pSamples Pointer to samples buffer.
* @param[in] pPalette Pointer to palette buffer.
*
* @return Error code, RSPLIB_SUCCESS when no error.
*/
static unsigned short TranslatePixels(T_RSPTEXTURE_TEXTURE* pTexture, const T_SAMPLE* pSamples, const T_R8G8B8* pPalette) {
unsigned int size;
if (pTexture == NULL || pSamples == NULL || pPalette == NULL) return RSPLIB_ERROR_ARGS_NULL;
if (!(pTexture->type == 0 ||
pTexture->type == 1 ||
pTexture->type == 2 ||
pTexture->type == 3 ||
pTexture->type == 4 ||
pTexture->type == 5)) return RSPLIB_ERROR_PROCESS;
size = pTexture->height * pTexture->width;
switch (pTexture->sample_bits) {
case 32:
pTexture->pixels = (T_R8G8B8A8 *)calloc(size, sizeof(T_R8G8B8A8));
memcpy(pTexture->pixels, pSamples, size * sizeof(T_R8G8B8A8));
break;
case 4:
pTexture->pixels = (T_R8G8B8A8 *)calloc(size, sizeof(T_R8G8B8A8));
if (pTexture->palette_entries == 0) {
convert4bitsGreyTo32bitsRGBA(pTexture->pixels, pSamples, size, pTexture->alpha_color);
} else if (pTexture->palette_entries == 16) {
convert4bitsTo32bitsRGBA(pTexture->pixels, pSamples, size, pPalette, pTexture->alpha_color);
}
break;
case 8:
if (pTexture->palette_entries == 0) {
pTexture->pixels = (T_R8G8B8A8 *)calloc(size, 1);
memcpy(pTexture->pixels, pSamples, size);
} else if (pTexture->palette_entries == 256) {
pTexture->pixels = (T_R8G8B8A8 *)calloc(size, sizeof(T_R8G8B8A8));
convert8bitsTo32bitsRGBA(pTexture->pixels, pSamples, size, pPalette, pTexture->alpha_color);
}
break;
case 16:
pTexture->pixels = (T_R8G8B8A8 *)calloc(size, 1);
useOddBytes(pTexture->pixels, pSamples, size);
break;
default:
break;
}
return RSPLIB_SUCCESS;
}
static unsigned short isTransparentColor(const T_R8G8B8A8 testColor, const T_R8G8B8A8 transp_color) {
if (!(testColor.r == transp_color.r)) return RSPLIB_ERROR_PROCESS;
if (!(testColor.g == transp_color.g)) return RSPLIB_ERROR_PROCESS;
if (!(testColor.b == transp_color.b)) return RSPLIB_ERROR_PROCESS;
return RSPLIB_SUCCESS;
}
static void convert4bitsGreyTo32bitsRGBA(T_R8G8B8A8* pPixels, const T_SAMPLE* pSamples, const unsigned int sampling, const T_R8G8B8A8 transp_color) {
unsigned int i;
T_SAMPLE p;
for ( i = 0; i < (sampling / 2); i++ ) {
p = pSamples[i];
pPixels[i * 2].r = div((p >> 4 & 0xF) * 256, 16).quot;
pPixels[i * 2].g = div((p >> 4 & 0xF) * 256, 16).quot;
pPixels[i * 2].b = div((p >> 4 & 0xF) * 256, 16).quot;
pPixels[i * 2].a = isTransparentColor(pPixels[i * 2], transp_color) ? 255 : 255 - transp_color.a;
pPixels[i * 2 + 1].r = div((p & 0xF) * 256, 16).quot;
pPixels[i * 2 + 1].g = div((p & 0xF) * 256, 16).quot;
pPixels[i * 2 + 1].b = div((p & 0xF) * 256, 16).quot;
pPixels[i * 2 + 1].a = isTransparentColor(pPixels[i * 2 + 1], transp_color) ? 255 : 255 - transp_color.a;
}
}
static void convert4bitsTo32bitsRGBA(T_R8G8B8A8* pPixels, const T_SAMPLE* pSamples, const unsigned int sampling, const T_R8G8B8* pal, const T_R8G8B8A8 transp_color) {
unsigned int i;
T_SAMPLE p;
for ( i = 0; i < (sampling / 2); i++ ) {
p = pSamples[i];
pPixels[i * 2].r = pal[(p >> 4) & 0xF].r;
pPixels[i * 2].g = pal[(p >> 4) & 0xF].g;
pPixels[i * 2].b = pal[(p >> 4) & 0xF].b;
pPixels[i * 2].a = isTransparentColor(pPixels[i * 2], transp_color) ? 255 : 255 - transp_color.a;
pPixels[i * 2 + 1].r = pal[p & 0xF].r;
pPixels[i * 2 + 1].g = pal[p & 0xF].g;
pPixels[i * 2 + 1].b = pal[p & 0xF].b;
pPixels[i * 2 + 1].a = isTransparentColor(pPixels[i * 2 + 1], transp_color) ? 255 : 255 - transp_color.a;
}
}
static void convert8bitsTo32bitsRGBA(T_R8G8B8A8* pPixels, const T_SAMPLE* pSamples, const unsigned int sampling, const T_R8G8B8* pal, const T_R8G8B8A8 transp_color) {
unsigned int i;
T_SAMPLE p;
for ( i = 0; i < sampling; i++ ) {
p = pSamples[i];
pPixels[i].r = pal[p].r;
pPixels[i].g = pal[p].g;
pPixels[i].b = pal[p].b;
pPixels[i].a = isTransparentColor(pPixels[i], transp_color) ? 255 : 255 - transp_color.a;
}
}
static void useOddBytes(T_R8G8B8A8* pPixels, const T_SAMPLE* pSamples, const unsigned int sampling) {
unsigned int i;
for ( i = 0; i < (sampling - 1); i++ ) {
//dst[i] = src[i*2+1]; //FIXME: Implement optimized byte shifting
//dst[i]._red = src[i*2+1];
//dst[i]._green = src[i*2+1];
//dst[i]._blue = src[i*2+1];
}
}

View File

@ -0,0 +1,51 @@
/**
* @file hmt_parser.h
* @date 26/08/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Process HMP file structure and extract its datas.
*
*/
#include "RSPTexture_datatypes.h"
#ifndef RSPTEXTURELIB_HMT_PARSER_H_
#define RSPTEXTURELIB_HMT_PARSER_H_
/**
* @brief Process HMT file stored in memory.
* @details Parser will directly extract tiles count and information stored in
* HMT file and store them in T_RSPTEXTURE_HMT structure.
* @note Unmanaged mode
*
* @param[in] pMemFile Pointer to an in-memory HOB file location.
* @param[out] hmtStruct Allocated empty T_RSPTEXTURE_HMT structure instance to
* be filled with HMP datas.
* @param[in] pParams Parser options. See RSPTEXTURE_PARAMETERS.
*
* @return Processing error code, RSPLIB_SUCCESS if no error.
*/
unsigned short RSP_TextureLib_ParseHMTMemFile(const MEMFILE pMemFile,
T_RSPTEXTURE_HMT* hmtStruct, const RSPTEXTURE_PARAMETERS* pParams);
/**
* @brief Process HMT file in file system.
* @details HMP 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 tiles count and information stored in HMT file
* and store them in T_RSPTEXTURE_HMT structure.
* @note Managed mode
*
* @param[in] fileName String value of file name/path.
* @param[out] hmtStruct Allocated empty T_RSPTEXTURE_HMT structure instance to
* be filled with HMP datas.
* @param[in] pParams Parser options. See RSPTEXTURE_PARAMETERS.
*
* @return Processing error code, RSPLIB_SUCCESS if no error.
*/
unsigned short RSP_TextureLib_ParseHMTFile(const char* fileName,
T_RSPTEXTURE_HMT* hmtStruct, const RSPTEXTURE_PARAMETERS* pParams);
#endif /* RSPTEXTURELIB_HMT_PARSER_H_ */

View File

@ -0,0 +1,135 @@
/**
* @file hmt_struct.h
* @date 26/08/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief HMT file mapping definition.
*
*/
#ifndef RSPTEXTURELIB_HMT_STRUCT_H_
#define RSPTEXTURELIB_HMT_STRUCT_H_
/*
* long = 64bits??? (8 Bytes)
* int = 32bits (4 Bytes)
* short = 16bits (2 Bytes)
* char = 8bits (1 Bytes)
*/
#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
typedef struct PACK hmtfile_header1 {
unsigned int materials_count;
unsigned int textures_offset;
} T_HMTFILE_HEADER1;
typedef struct PACK hmtfile_header2 {
unsigned int textures_count;
} T_HMTFILE_HEADER2;
typedef struct PACK hmtfile_material {
unsigned short type; // 1 - Material with texture / 2 - Material without texture
unsigned short texture_index;
float reserved0; // misc.
float reserved1; // Always 1.0f
unsigned int reserved2; // Zero
unsigned int reserved3; // 0x0A
unsigned char name[16];
} T_HMTFILE_MATERIAL;
typedef struct PACK hmtfile_texture_format {
unsigned char reserved0; // Always 1 ?
unsigned char sample_bitsize;
unsigned char type;
/*
0 - palette 16x3B RGB, 4bit per pixel
1 - 256x3B palette RGB, 8bit per pixel
3 - RGBA 32bpp
4 - greyscale, 4bpp
5 - grayscale, 8bpp
*/
unsigned char unknown0; // 0x40 / 0x80
unsigned int transparent_color; //TODO: replace by T_PIXEL type
} T_HMTFILE_TEXTURE_FORMAT;
typedef struct PACK hmtfile_texture_header {
unsigned int pixels_offset;
unsigned int reserved0; // 28B zeros
unsigned int reserved1;
unsigned int reserved2;
unsigned int reserved3;
unsigned int reserved4;
unsigned int reserved5;
unsigned int reserved6;
unsigned int palette_offset; // 0 = no palette
unsigned int texname_offset;
unsigned short tex_width;
unsigned short tex_height;
T_HMTFILE_TEXTURE_FORMAT tex_format;
} T_HMTFILE_TEXTURE_HEADER;
typedef struct PACK hmtfile_image_attributes {
unsigned short width; // Must be increased to a multiple of 2 if odd.
unsigned short height;
unsigned char reserved0; // 0x01
unsigned char bit_per_pixel; // 0 - 4bits / 1 - 8bits
unsigned char subtype; // 3 - RGBA / 4 - greyscale / 5 - ov_rdir
unsigned char reserved1; // 0x80/128
} T_HMTFILE_IMAGE_ATTRIBUTES;
typedef struct PACK hmtfile_image {
unsigned int data_size;
unsigned int pixels_offset;
unsigned int reserved0; // 32B zeros
unsigned int reserved1;
unsigned int reserved2;
unsigned int reserved3;
unsigned int reserved4;
unsigned int reserved5;
unsigned int reserved6;
unsigned int reserved7;
unsigned int desc_offset;
T_HMTFILE_IMAGE_ATTRIBUTES attributes;
unsigned int transparent_color; //TODO: replace by T_PIXEL type
unsigned int unknown0;
} T_HMTFILE_IMAGE;
typedef struct PACK hmtfile_texture {
unsigned char name[16]; // Normally = material name
unsigned int RGB_palette; //TODO: to define
unsigned int pixels_samples; //TODO: to define
} T_HMTFILE_TEXTURE;
#if defined(_MSC_VER)
#pragma pack(pop)
#endif
#endif /* RSPTEXTURELIB_HMT_STRUCT_H_ */

View File

@ -1,5 +1,5 @@
[requires] [requires]
zlib/1.2.11 zlib/1.2.12
libpng/1.6.37 libpng/1.6.37
[generators] [generators]
@ -7,8 +7,7 @@ cmake
cmake_find_package cmake_find_package
[options] [options]
zlib:shared=True
libpng:shared=True libpng:shared=True
[imports] [imports]
bin, *.dll -> . bin, *.dll -> ./bin

6
config.h.in Normal file
View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,167 +0,0 @@
#include "HMT_Parser.h"
HMT_FILE *parseHMTFile(FILE *hmt_src) {
int i;
HMT_FILE *_buff = NULL;
if (hmt_src == NULL) return NULL;
_buff = calloc(1, sizeof(HMT_FILE));
rewind(hmt_src); //Rewind file at the start
fread(&(_buff->material_count), 4, 1, hmt_src); // Extract first usefull datas
fread(&(_buff->texture_offset), 4, 1, hmt_src);
// Read materials
printf("[INFO] Materials detected: %d\n", _buff->material_count);
_buff->materials_list = calloc(_buff->material_count, sizeof(HMT_MATERIAL)); // Create a big list of materials entries
for (i=0; i<_buff->material_count; i++) {
// Extract materials datas
if (readMaterial(&(_buff->materials_list[i]), hmt_src) != 0) {
purgeHMTFromMemory(_buff);
return NULL;
}
}
// Read textures
fseek(hmt_src, _buff->texture_offset, SEEK_SET);
fread(&(_buff->texture_count), 4, 1, hmt_src);
printf("[INFO] Textures detected: %d\n", _buff->texture_count);
if (_buff->texture_count > 0) {
_buff->textures_list = calloc(_buff->texture_count, sizeof(HMT_TEXTURE)); // Create a big list of textures entries
for (i=0; i<_buff->texture_count; i++) {
// Extract textures datas
if (readTexture(&(_buff->textures_list[i]), hmt_src) != 0) {
purgeHMTFromMemory(_buff);
return NULL;
}
}
}
return _buff;
}
int readMaterial(HMT_MATERIAL *mat, FILE *hmt_src) {
if (mat == NULL || hmt_src == NULL) return EXIT_FAILURE;
fread(mat, sizeof(HMT_MATERIAL), 1, hmt_src);
if (_options & 0x1) {
if (mat->zero != 0 || mat->hex_a != 0x0A) printf("\n Uncommon file detected!\n");
printf(" Material type: %d\n Texture index: %d\n\n", mat->type_, mat->texture_index); //TODO: To develop?!
}
return EXIT_SUCCESS;
}
int readTexture(HMT_TEXTURE *tex, FILE *hmt_src) {
unsigned char u0,u1,bpp;
long pos;
RS_IMAGE_DESC desc;
fread(&(tex->data_offset), 4, 1, hmt_src);
fseek(hmt_src, 28, SEEK_CUR); // Skip zeros area
fread(&(tex->palette_offset), 4, 1, hmt_src);
fread(&(tex->textureName_offset), 4, 1, hmt_src);
fread(&(tex->width), 2, 1, hmt_src);
fread(&(tex->height), 2, 1, hmt_src);
fread(&u0, 1, 1, hmt_src);
fread(&bpp, 1, 1, hmt_src);
fread(&(tex->image.type_), 1, 1, hmt_src);
fread(&u1, 1, 1, hmt_src);
fread(&(tex->image.alpha_color._red), 1, 1, hmt_src);
fread(&(tex->image.alpha_color._green), 1, 1, hmt_src);
fread(&(tex->image.alpha_color._blue), 1, 1, hmt_src);
fread(&(tex->image.alpha_color._alpha), 1, 1, hmt_src);
pos = ftell(hmt_src);
fseek(hmt_src, tex->textureName_offset, SEEK_SET);
fread(&(tex->name), 16, 1, hmt_src);
fseek(hmt_src, pos, SEEK_SET);
desc = getImageDescFromType(tex->image.type_);
tex->image.paletteEntries = desc.palette_entries;
tex->image.sampleBits = desc.sample_bits;
tex->image.width = tex->width;
tex->image.height = tex->height;
if (_options & VERBOSE_ENABLED) {
printf(" Texture name: %s\n", tex->name);
printf(" Size w: %ld h: %ld\n", tex->width, tex->height);
printf(" u0: %d u1: %d\n", u0, u1);
printf(" Texture type: %d\n", tex->image.type_);
printf(" Samplebits: %d\n", tex->image.sampleBits);
printf(" Palette entries: %d\n", tex->image.paletteEntries);
printf(" Transparent color (RGB): %X %X %X\n", tex->image.alpha_color._red, tex->image.alpha_color._green, tex->image.alpha_color._blue);
printf(" Palette offset: %d\n", tex->palette_offset);
printf(" Data offset: %d\n", tex->data_offset);
printf("\n");
}
if (tex->palette_offset > 0) {
if (_options & VERBOSE_ENABLED) printf("\nPalette entries: %d\n", tex->image.paletteEntries);
fseek(hmt_src, tex->palette_offset, SEEK_SET);
getPaletteFromFile(&(tex->image), hmt_src);
}
fseek(hmt_src, tex->data_offset, SEEK_SET);
getSamplesFromFile(&(tex->image), hmt_src);
decodePixels(&(tex->image));
fseek(hmt_src, pos, SEEK_SET);
return EXIT_SUCCESS;
}
int getPaletteFromFile(RS_IMAGE *img, FILE *f) {
int entries = img->paletteEntries;
switch (entries) {
case 16:
case 256:
fread(img->palette, sizeof(PIXEL), entries, f);
break;
default:
break;
}
return EXIT_SUCCESS;
}
int getSamplesFromFile(RS_IMAGE *img, FILE *f) {
int sample_bits = img->sampleBits;
int size = div(img->width*img->height*sample_bits, 8).quot;
#ifdef _WIN32
if (f->_bufsiz >= ftell(f)+size) {
printf("[ERR] WARNING! Please fix size/sample.");
return EXIT_FAILURE;
}
#else
if (__fbufsize(f) >= ftell(f)+size) {
printf("[ERR] WARNING! Please fix size/sample.");
return EXIT_FAILURE;
}
#endif
img->samples = calloc(1, size);
fread(img->samples, size, 1, f);
if (img->type_ == 2) fread(img->samples, div(size, 4).quot, 1, f);
return EXIT_SUCCESS;
}
void purgeHMTFromMemory(HMT_FILE *_f) {
if (_f == NULL) return;
if (_f->textures_list != NULL) {
if (_f->textures_list->image.pixels != NULL) free(_f->textures_list->image.pixels);
if (_f->textures_list->image.samples != NULL) free(_f->textures_list->image.samples);
}
free(_f->textures_list);
if (_f->materials_list != NULL) free(_f->materials_list);
free(_f);
}

View File

@ -1,111 +0,0 @@
#ifndef HMT_PARSER_H_
#define HMT_PARSER_H_
#include <stdio.h>
#ifndef _WIN32
#include <stdio_ext.h>
#endif
#include <stdlib.h>
#include "options.h"
#include "RS_images.h"
/////////////////////////////
///// Define HMT types //////
/////////////////////////////
/**
* @brief Material struct inside HMT file type
*
* Actual RE material struct:\n
* 4B material entry count MC\n
* 4B offset after material entries / offset to textures\n
* MC * material entry (36B)\n
* [\n
* 2B int material/texture type:\n
* 1 - material with texture\n
* 2 - material without texture\n
* 2B int texture index\n
* 4B float (scale factor?)\n
* 4B float (always 1.0)\n
* 4B int zero\n
* 4B int 0x0A\n
* 16B name\n
* ]\n
*
* @image html hmt_materialDef.png
*/
typedef struct HMTMaterial {
short type_; /**< Material type:\n 1 = Material with texture\n 2 = Material without texture */
short texture_index;
float unknow1,unknow2;
int zero;
int hex_a;
char name[16];
}HMT_MATERIAL;
/**
* @brief Texture struct inside HMT file type
*
* Actual RE texture struct:\n
* 4B int texcount Tc\n
* TC * texture entry 52B\n
* [\n
* 4B int pixel offset\n
* 28B zero\n
* 4B int palette offset, 0 = no palette\n
* 4B int texname offset\n
* 2B int width\n
* 2B int height\n
* 8B texture format [\n
* 1B int : always 1?\n
* 1B int : bits per sample?\n
* 1B int : subtype:\n
* -0 - palette 16x3B RGB, 4bit per pixel\n
* -1 - 256x3B palette RGB, 8bit per pixel\n
* -3 - RGBA 32bpp\n
* -4 - greyscale, 4bpp\n
* -5 - grayscale, 8bpp\n
* 1B int ? 0, 0x40, 0x80\n
* 4B RGBA transparent color?\n
* ]\n
* ]\n
*
* @image html hmt_textureDef.png
*/
typedef struct HMTTexture {
int data_offset;
int palette_offset;
int textureName_offset;
unsigned long width, height;
char name[16];
RS_IMAGE image;
}HMT_TEXTURE;
/**
* @brief Instance of HMTFile in memory
* This structure contain all parsed data for a single HMT file.
*/
typedef struct HMTFile {
int material_count; /**< Number of materials registered inside HMTFile instance. */
int texture_offset; /**< Address from which texture data begins. */
int texture_count; /**< Number of textures registered inside HMTFile instance. */
HMT_MATERIAL *materials_list; /**< Starting pointer of the materials list. Managed like an array and declared as a pointer */
HMT_TEXTURE *textures_list; /**< Starting pointer of the textures list. Managed like an array and declared as a pointer*/
}HMT_FILE;
/////////////////////////////
///// Declare functions /////
/////////////////////////////
HMT_FILE *parseHMTFile(FILE *hmt_src);
int readMaterial(HMT_MATERIAL *mat, FILE *hmt_src);
int readTexture(HMT_TEXTURE *tex, FILE *hmt_src);
HMT_MATERIAL *getMaterialFromIndex(int i);
HMT_MATERIAL *getMaterialFromName(char *matName);
HMT_TEXTURE *getTextureFromIndex(int i);
HMT_TEXTURE *getTextureFromMaterial(HMT_MATERIAL *mat);
int getPaletteFromFile(RS_IMAGE *img, FILE *f);
int getSamplesFromFile(RS_IMAGE *img, FILE *f);
void purgeHMTFromMemory(HMT_FILE *_f);
#endif

View File

@ -1,72 +0,0 @@
#include "Image_Exporter.h"
int saveToPNG(RS_IMAGE *img, char *tex_path, char *hmt_fileName) {
if (tex_path == NULL || img == NULL) return EXIT_FAILURE;
char export_path[128];
FILE *_png_f = NULL;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
size_t x,y;
png_byte **row_ptrs = NULL;
PIXEL_A *pixel = NULL;
//int pixel_size = 3;
//int depth = 8; //bit par color channel (RGB)
if (_options & OUTPUT_DIR) {
strcpy(export_path, hmt_fileName);
#ifdef _WIN32
strcat(export_path, "-out\\");
#else
strcat(export_path, "-out/");
#endif
strcat(export_path, tex_path);
} else {
strcpy(export_path, tex_path);
}
strcat(export_path, ".png");
_png_f = fopen(export_path, "wb");
if (_png_f == NULL) return EXIT_FAILURE;
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fclose(_png_f);
return EXIT_FAILURE;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fclose(_png_f);
return EXIT_FAILURE;
}
// Set image attributes
png_set_IHDR(png_ptr, info_ptr, img->width, img->height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
// Init PNG datas
row_ptrs = png_malloc(png_ptr, img->height * sizeof(png_byte *));
for (y=0; y<img->height; y++) {
png_byte *row = png_malloc(png_ptr, img->width*sizeof(PIXEL_A));
row_ptrs[y] = row;
for (x=0; x<img->width; x++) {
pixel = pixelAt(img, x , y);
if(pixel == NULL) return EXIT_FAILURE;
*row++ = pixel->_red;
*row++ = pixel->_green;
*row++ = pixel->_blue;
*row++ = pixel->_alpha;
}
}
png_init_io(png_ptr, _png_f);
png_set_rows(png_ptr, info_ptr, row_ptrs);
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
for (y=0; y<img->height; y++) {
png_free(png_ptr, row_ptrs[y]);
}
png_free(png_ptr, row_ptrs);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(_png_f);
return EXIT_SUCCESS;
}

View File

@ -1,12 +0,0 @@
#ifndef IMAGE_EXPORTER_H_
#define IMAGE_EXPORTER_H_
#include "options.h"
#include "RS_images.h"
#include <zlib.h>
#include <png.h>
int saveToPNG(RS_IMAGE *img, char *tex_name, char *hmt_fileName);
#endif

View File

@ -1,152 +0,0 @@
#include "RS_images.h"
//extern int _options; // Global options settings variable
void decodePixels(RS_IMAGE *img) {
int size;
//img->pixels = NULL;
if (!(img->type_ == 0 ||
img->type_ == 1 ||
img->type_ == 2 ||
img->type_ == 3 ||
img->type_ == 4 ||
img->type_ == 5)) return;
size = img->height * img->width;
switch (img->sampleBits) {
case 32:
img->pixels = calloc(1, size * sizeof(PIXEL_A));
memcpy(img->pixels, img->samples, size * sizeof(PIXEL_A));
break;
case 4:
img->pixels = calloc(1, size * sizeof(PIXEL_A));
if (img->paletteEntries == 0) {
convert4bitsGreyTo32bitsRGBA(img->samples, img->pixels, size, &(img->alpha_color));
} else if (img->paletteEntries == 16) {
convert4bitsTo32bitsRGBA(img->samples, img->pixels, size, img->palette, &(img->alpha_color));
}
break;
case 8:
if (img->paletteEntries == 0) {
img->pixels = calloc(1, size);
memcpy(img->pixels, img->samples, size);
} else if (img->paletteEntries == 256) {
img->pixels = calloc(1, size * sizeof(PIXEL_A));
convert8bitsTo32bitsRGBA(img->samples, img->pixels, size, img->palette, &(img->alpha_color));
}
break;
case 16:
img->pixels = calloc(1, size);
useOddBytes(img->samples, img->pixels, size);
break;
default:
break;
}
}
int isTransparentColor(PIXEL_A *testColor, PIXEL_A *transp_color) {
if (transp_color == NULL || testColor == NULL) return -2;
if (!(testColor->_red == transp_color->_red)) return -1;
if (!(testColor->_green == transp_color->_green)) return -1;
if (!(testColor->_blue == transp_color->_blue)) return -1;
return 0;
}
void convert4bitsGreyTo32bitsRGBA(unsigned char *samples_tab, PIXEL_A *pixels_tab, int sampling, PIXEL_A *transp_color) {
int i;
unsigned char v;
for(i=0; i<div(sampling,2).quot; i++) {
v = samples_tab[i];
pixels_tab[i*2]._red = div((v >> 4 & 0xF) * 256, 16).quot;
pixels_tab[i*2]._green = div((v >> 4 & 0xF) * 256, 16).quot;
pixels_tab[i*2]._blue = div((v >> 4 & 0xF) * 256, 16).quot;
if (isTransparentColor(&(pixels_tab[i*2]), transp_color) == 0) pixels_tab[i*2]._alpha = 0xFF - transp_color->_alpha; else pixels_tab[i*2]._alpha = 0xFF; // Test if color is a transparent color and adjust alpha layer
pixels_tab[i*2+1]._red = div((v & 0xF) * 256, 16).quot;
pixels_tab[i*2+1]._green = div((v & 0xF) * 256, 16).quot;
pixels_tab[i*2+1]._blue = div((v & 0xF) * 256, 16).quot;
if (isTransparentColor(&(pixels_tab[i*2+1]), transp_color) == 0) pixels_tab[i*2+1]._alpha = 0xFF - transp_color->_alpha; else pixels_tab[i*2+1]._alpha = 0xFF; // Test if color is a transparent color and adjust alpha layer
}
}
void convert4bitsTo32bitsRGBA(unsigned char *samples_tab, PIXEL_A *pixels_tab, int size, PIXEL *pal, PIXEL_A *transp_color) {
int i,index;
for(i=0; i<div(size,2).quot; i++) {
index = samples_tab[i];
pixels_tab[i*2]._red = pal[(index >> 4) & 0xF]._red;
pixels_tab[i*2]._green = pal[(index >> 4) & 0xF]._green;
pixels_tab[i*2]._blue = pal[(index >> 4) & 0xF]._blue;
if (isTransparentColor(&(pixels_tab[i*2]), transp_color) == 0) pixels_tab[i*2]._alpha = 0xFF - transp_color->_alpha; else pixels_tab[i*2]._alpha = 0xFF; // Test if color is a transparent color and adjust alpha layer
pixels_tab[i*2+1]._red = pal[index & 0xF]._red;
pixels_tab[i*2+1]._green = pal[index & 0xF]._green;
pixels_tab[i*2+1]._blue = pal[index & 0xF]._blue;
if (isTransparentColor(&(pixels_tab[i*2+1]), transp_color) == 0) pixels_tab[i*2]._alpha = 0xFF - transp_color->_alpha; else pixels_tab[i*2+1]._alpha = 0xFF; // Test if color is a transparent color and adjust alpha layer
}
}
void convert8bitsTo32bitsRGBA(unsigned char *samples_tab, PIXEL_A *pixels_tab, int size, PIXEL *pal, PIXEL_A *transp_color) {
int i,index;
for(i=0; i<size; i++) {
index = samples_tab[i];
pixels_tab[i]._red = pal[index]._red;
pixels_tab[i]._green = pal[index]._green;
pixels_tab[i]._blue = pal[index]._blue;
if (isTransparentColor(&(pixels_tab[i]), transp_color) == 0) pixels_tab[i]._alpha = 0xFF - transp_color->_alpha; else pixels_tab[i]._alpha = 0xFF; // Test if color is a transparent color and adjust alpha layer
}
}
void useOddBytes(unsigned char *src, PIXEL_A *dst, int size) {
int i;
for(i=0; i<(size-1); i++) {
//dst[i] = src[i*2+1]; //FIXME: Implement optimized byte shifting
//dst[i]._red = src[i*2+1];
//dst[i]._green = src[i*2+1];
//dst[i]._blue = src[i*2+1];
}
}
PIXEL_A *pixelAt(RS_IMAGE *img, int posX , int posY) {
return img->pixels + img->width * posY + posX;
}
RS_IMAGE_DESC getImageDescFromType(unsigned char type) {
RS_IMAGE_DESC desc;
switch(type) {
case 0:
desc.palette_entries = 16;
desc.sample_bits = 4;
break;
case 1:
desc.palette_entries = 256;
desc.sample_bits = 8;
break;
case 2:
desc.palette_entries = 0;
desc.sample_bits = 16;
break;
case 3:
desc.palette_entries = 0;
desc.sample_bits = 32;
break;
case 4:
desc.palette_entries = 0;
desc.sample_bits = 4;
break;
case 5:
desc.palette_entries = 0;
desc.sample_bits = 8;
break;
default:
break;
}
return desc;
}

View File

@ -1,85 +0,0 @@
#ifndef RS_IMAGES_H_
#define RS_IMAGES_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include "options.h"
/**
* @brief Constant contain the number of channel inside a PIXEL definition.
*/
#define PIXEL_MEMBERS_NBR 4
/////////////////////////////
///// Define new types //////
/////////////////////////////
/**
* @brief RGBA pixel structure, used to store datas for implementation inside PNG files.
*/
typedef struct PixelRGBA {
unsigned char _red;
unsigned char _green;
unsigned char _blue;
unsigned char _alpha;
}PIXEL_A;
/**
* @brief RGB pixel structure, used to store datas for implementation inside PNG files, optimised version without alpha channel support.
*/
typedef struct PixelRGB {
unsigned char _red;
unsigned char _green;
unsigned char _blue;
}PIXEL;
/**
* @brief Image definition from Rogue Squadron HMT files
*/
typedef struct RSImage {
int data_size; /**< Image bytes size */
int width, height;
unsigned char type_; /**< Image type (0 = RBG/4bits per pixel, 1 = RBG/8bpp, 3 = RGBA/32bpp , 4 = grayscale/4bpp, 5 = grayscale/8bpp */
unsigned char sampleBits; /**< Bits per samble */
int paletteEntries;
PIXEL_A alpha_color;
PIXEL_A *pixels; /**< Image pixels list, managed like an array and declared as a pointer */
unsigned char *samples; /**< Image samples list managed like an array and declared as a pointer */
PIXEL palette[256]; /**< Image palette definition */ //TODO: Create union struct type instead
}RS_IMAGE;
typedef struct RSImage_desc {
int palette_entries;
int sample_bits;
}RS_IMAGE_DESC;
/////////////////////////////
///// Declare functions /////
/////////////////////////////
/**
* @brief Conversion table for image type using RS_IMAGE_DESC.
* Return RS_IMAGE_DESC by providing image type as int\n
*
* Detailed conversion:\n\n
* Type 0 -> Palette entries: 16 ; Sample bits: 4\n
* Type 1 -> Palette entries: 256 ; Sample bits: 8\n
* Type 2 -> Palette entries: 0 ; Sample bits: 16\n
* Type 3 -> Palette entries: 0 ; Sample bits: 32\n
* Type 4 -> Palette entries: 0 ; Sample bits: 4\n
* Type 5 -> Palette entries: 0 ; Sample bits: 8\n
*/
RS_IMAGE_DESC getImageDescFromType(unsigned char type); //TODO: Optimise function
int isTransparentColor(PIXEL_A *testColor, PIXEL_A *transp_color);
void convert4bitsGreyTo32bitsRGBA(unsigned char *samples_tab, PIXEL_A *pixels_tab, int sampling, PIXEL_A *transp_color);
void convert4bitsTo32bitsRGBA(unsigned char *samples_tab, PIXEL_A *pixels_tab, int size, PIXEL *pal, PIXEL_A *transp_color);
void convert8bitsTo32bitsRGBA(unsigned char *samples_tab, PIXEL_A *pixels_tab, int size, PIXEL *pal, PIXEL_A *transp_color);
void useOddBytes(unsigned char *src, PIXEL_A *dst, int size);
void decodePixels(RS_IMAGE *img);
PIXEL_A *pixelAt(RS_IMAGE *img, int posX , int posY);
#endif

View File

@ -1,133 +0,0 @@
/*
================================================================================
Name : Texture-Extractor.c
Author : JackCarterSmith
License : GPL-v3.0
Description : DAT textures extractor to PNG format with enhanced function in C
================================================================================
*/
#include "Texture-Extractor.h"
int _options; // Global options settings variable
int main(int argc, char *argv[]) {
// Init buffer vars
HMT_FILE *hmt_fdatas = NULL;
int file_index;
printf("\n*** RogueSquadron Extractor (RSE) - TEXTURE module - v%s ***\n", VERSION);
// Check if filenames arguments exist
if (argc < 2) {
printf("\n[ERR] No input file/commands specified!\n");
dispHelp();
return EXIT_FAILURE; //TODO: implement own error codes system
}
_options = checkArgs(argv, argc); // Analyse program arguments
if (_options == -1) return EXIT_SUCCESS;
// Do the work
for (file_index=(_options >> 8) & 0xFF; file_index<argc; file_index++) { // Manage multiple inputs files
hmt_fdatas = extractDatasFromHMT(argv[file_index]);
if (hmt_fdatas == NULL) return EXIT_FAILURE;
if (exportTextures(hmt_fdatas, argv[file_index]) == EXIT_FAILURE) return EXIT_FAILURE;
purgeHMTFromMemory(hmt_fdatas); // Clean up memory (because I'm a good boy)
}
return EXIT_SUCCESS;
}
int checkArgs(char *args[], int arg_nbr) {
int _o = 0x0002; // Default options parameters
char test[256];
int i;
if (arg_nbr > 1) {
for (i=1; i<arg_nbr; i++) {
strcpy(test, args[i]);
if (args[i][0] != '-') break;
if (strcmp(args[i], "-h") == 0) {
dispHelp();
return -1;
} else if (strcmp(args[i], "-v") == 0) {
_o |= VERBOSE_ENABLED;
printf("[OPTN] Verbose enabled.\n");
} else if (strcmp(args[i], "-no-subdir") == 0) {
_o &= ~OUTPUT_DIR;
printf("[OPTN] Extract to current directory.\n");
} else {
printf("[ERR] Unknown option: %s\n", args[i]);
}
}
_o = (i << 8) | (_o & 0x00FF);
}
return _o;
}
void createSubDir(char *dirName) {
if (dirName == NULL) return;
char _dir[260]; //TODO: Change directory management
strcpy(_dir, dirName);
strcat(_dir, "-out");
#ifdef _WIN32
CreateDirectory(_dir, NULL);
#else
mkdir(_dir, 0755);
#endif
}
HMT_FILE *extractDatasFromHMT(char *hmt_filename) {
FILE *_hmtFile = NULL;
HMT_FILE *hmt_fdatas = NULL;
_hmtFile = fopen(hmt_filename, "rb");
if (_hmtFile != NULL) {
printf("\n=============================================\n[INFO] - Parsing file: %s ...\n", hmt_filename);
hmt_fdatas = parseHMTFile(_hmtFile);
if (hmt_fdatas == NULL) printf("[ERR] Failed to parse datas from %s\n", hmt_filename);
} else {
printf("\n[ERR] Input file %s not found!\n", hmt_filename);
}
fclose(_hmtFile);
return hmt_fdatas;
}
int exportTextures(HMT_FILE *hmt_f, char *filename) {
int i;
if(hmt_f->texture_count > 0) {
if (_options & OUTPUT_DIR) createSubDir(filename);
for (i=0; i<hmt_f->texture_count; i++) {
switch (hmt_f->textures_list[i].image.type_) {
case 0:
case 1:
case 3:
case 4:
case 5:
if (saveToPNG(&(hmt_f->textures_list[i].image), hmt_f->textures_list[i].name, filename)) {
printf("[ERR] Failed saving image file: %s\n", hmt_f->textures_list[i].name);
return EXIT_FAILURE;
} else printf("[INFO] Saved image file: %s\n", hmt_f->textures_list[i].name);
break;
default:
printf("[WARN] Can't export %s ! Image type %d not currently supported! (WIP)\n", hmt_f->textures_list[i].name, hmt_f->textures_list[i].image.type_);
}
}
}
return EXIT_SUCCESS;
}
void dispHelp() {
printf("\n");
printf("Options:\n -h Print this message\n -v Activate verbose console output\n -no-subdir Extract textures inside current folder\n");
printf("\n");
printf("Usage: RSE-Texture_%s [options] <hmt files...>\n", VERSION);
printf("\n");
}

View File

@ -1,26 +0,0 @@
#ifndef TEXTURE_EXTRACTOR_H_
#define TEXTURE_EXTRACTOR_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(_WIN32)
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include "config.h"
#include "options.h"
#include "HMT_Parser.h"
#include "RS_images.h"
#include "Image_Exporter.h"
void createSubDir(char *dirName);
int checkArgs(char *args[], int arg_nbr);
HMT_FILE *extractDatasFromHMT(char* hmt_filename);
int exportTextures(HMT_FILE *hmt_f, char *filename);
void dispHelp();
#endif

View File

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

View File

@ -1,9 +0,0 @@
#ifndef OPTIONS_H_
#define OPTIONS_H_
#define VERBOSE_ENABLED 0x0001
#define OUTPUT_DIR 0x0002
extern int _options;
#endif