Final lib structure of RDI v1 #3
@ -7,26 +7,14 @@
|
|||||||
|
|
||||||
|
|
||||||
# CMake requirement and general configuration
|
# CMake requirement and general configuration
|
||||||
cmake_minimum_required(VERSION 3.12)
|
cmake_minimum_required(VERSION 3.15)
|
||||||
cmake_policy(VERSION 3.12)
|
cmake_policy(VERSION 3.15)
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
|
set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
|
||||||
if(DEFINED ENV{MS_COMPATIBLE})
|
if(DEFINED ENV{MS_COMPATIBLE})
|
||||||
set(CMAKE_GNUtoMS ON) # Enable compatibility level to exported libraries
|
set(CMAKE_GNUtoMS ON) # Enable compatibility level to exported libraries
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
# Import needed packages and references their include path
|
|
||||||
find_package(RSPModel 2.2 REQUIRED)
|
|
||||||
include_directories(${RSPModel_INCLUDE_DIR})
|
|
||||||
find_package(RSPTerrain 2.0 REQUIRED)
|
|
||||||
include_directories(${RSPTerrain_INCLUDE_DIR})
|
|
||||||
find_package(RSPTexture 2.1 REQUIRED)
|
|
||||||
include_directories(${RSPTexture_INCLUDE_DIR})
|
|
||||||
find_package(Boost 1.80.0 EXACT REQUIRED)
|
|
||||||
include_directories(${Boost_INCLUDE_DIR})
|
|
||||||
add_definitions(-DBOOST_ALL_NO_LIB)
|
|
||||||
|
|
||||||
|
|
||||||
# Project definition
|
# Project definition
|
||||||
if(DEFINED ENV{CI}) # Jenkins CI integration mode
|
if(DEFINED ENV{CI}) # Jenkins CI integration mode
|
||||||
project(rdi VERSION $ENV{CI_VERSION}.$ENV{CI_BUILD_NUMBER} DESCRIPTION "Rogue Data Interface" LANGUAGES C CXX)
|
project(rdi VERSION $ENV{CI_VERSION}.$ENV{CI_BUILD_NUMBER} DESCRIPTION "Rogue Data Interface" LANGUAGES C CXX)
|
||||||
@ -37,8 +25,13 @@ else() # Standalone project mode, should not be used for release.
|
|||||||
endif()
|
endif()
|
||||||
#set(RDI_LIB_NAME RDI${PROJECT_VERSION_MAJOR}${PROJECT_VERSION_MINOR})
|
#set(RDI_LIB_NAME RDI${PROJECT_VERSION_MAJOR}${PROJECT_VERSION_MINOR})
|
||||||
set(RDI_LIB_NAME RDI)
|
set(RDI_LIB_NAME RDI)
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
|
if(NOT MSVC)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||||
|
else()
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Wall")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Wall")
|
||||||
|
endif()
|
||||||
|
|
||||||
set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
|
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_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries")
|
||||||
@ -49,6 +42,17 @@ option(RDI_SHARED "Build shared lib" ON)
|
|||||||
option(RDI_STATIC "Build static lib" ON)
|
option(RDI_STATIC "Build static lib" ON)
|
||||||
option(BUILD_TOOLS "Build lib tools" ON)
|
option(BUILD_TOOLS "Build lib tools" ON)
|
||||||
|
|
||||||
|
# Import needed packages and references their include path
|
||||||
|
find_package(RSPModel 2.3 REQUIRED)
|
||||||
|
include_directories(${RSPModel_INCLUDE_DIR})
|
||||||
|
find_package(RSPTerrain 2.0 REQUIRED)
|
||||||
|
include_directories(${RSPTerrain_INCLUDE_DIR})
|
||||||
|
find_package(RSPTexture 2.1 REQUIRED)
|
||||||
|
include_directories(${RSPTexture_INCLUDE_DIR})
|
||||||
|
find_package(Boost 1.81.0 REQUIRED)
|
||||||
|
include_directories(${Boost_INCLUDE_DIR})
|
||||||
|
add_definitions(-DBOOST_ALL_NO_LIB)
|
||||||
|
|
||||||
|
|
||||||
# Push compile infos to source
|
# Push compile infos to source
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/src/config.h @ONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/src/config.h @ONLY)
|
||||||
@ -65,7 +69,7 @@ unset(RDI_TARGETS_LIST)
|
|||||||
# Define src/headers files
|
# Define src/headers files
|
||||||
file(GLOB_RECURSE RDI_LIB_SOURCES ./src/*.cpp ./src/*.c)
|
file(GLOB_RECURSE RDI_LIB_SOURCES ./src/*.cpp ./src/*.c)
|
||||||
source_group("Source Files" FILES ${RDI_LIB_SOURCES})
|
source_group("Source Files" FILES ${RDI_LIB_SOURCES})
|
||||||
file(GLOB RSP_LIB_PUBLIC_HRDS ./include/*.h)
|
file(GLOB_RECURSE RSP_LIB_PUBLIC_HRDS ./include/*.hpp ./include/*.h)
|
||||||
|
|
||||||
|
|
||||||
# Building instructions for RSP-Texture library
|
# Building instructions for RSP-Texture library
|
||||||
@ -76,14 +80,22 @@ endif()
|
|||||||
# Declare the shared library instance
|
# Declare the shared library instance
|
||||||
if(RDI_SHARED)
|
if(RDI_SHARED)
|
||||||
add_library(rdi-lib SHARED ${RDI_LIB_SOURCES})
|
add_library(rdi-lib SHARED ${RDI_LIB_SOURCES})
|
||||||
set_property(TARGET rdi-lib PROPERTY C_STANDARD 90)
|
set_property(TARGET rdi-lib PROPERTY C_STANDARD 17)
|
||||||
set_property(TARGET rdi-lib PROPERTY CXX_STANDARD 17)
|
set_property(TARGET rdi-lib PROPERTY CXX_STANDARD 17)
|
||||||
|
set_property(TARGET rdi-lib PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||||
set_target_properties(rdi-lib PROPERTIES VERSION 1.0.0)
|
set_target_properties(rdi-lib PROPERTIES VERSION 1.0.0)
|
||||||
|
|
||||||
target_include_directories(rdi-lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
target_include_directories(rdi-lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
set_target_properties(rdi-lib PROPERTIES OUTPUT_NAME "${RDI_LIB_NAME}")
|
set_target_properties(rdi-lib PROPERTIES OUTPUT_NAME "${RDI_LIB_NAME}")
|
||||||
|
|
||||||
|
# As GNU-GCC have different runtime lib, we statically link them for this type of build
|
||||||
|
if (NOT MSVC)
|
||||||
|
target_link_libraries(rdi-lib PRIVATE
|
||||||
|
-static-libgcc
|
||||||
|
-static-libstdc++
|
||||||
|
)
|
||||||
|
endif()
|
||||||
target_link_libraries(rdi-lib PRIVATE
|
target_link_libraries(rdi-lib PRIVATE
|
||||||
${RSPModel_LIBRARIES}
|
${RSPModel_LIBRARIES}
|
||||||
${RSPTerrain_LIBRARIES}
|
${RSPTerrain_LIBRARIES}
|
||||||
@ -109,11 +121,20 @@ endif()
|
|||||||
# Declare the static library instance
|
# Declare the static library instance
|
||||||
if(RDI_STATIC)
|
if(RDI_STATIC)
|
||||||
add_library(rdi-libstatic STATIC ${RDI_LIB_SOURCES})
|
add_library(rdi-libstatic STATIC ${RDI_LIB_SOURCES})
|
||||||
set_property(TARGET rdi-libstatic PROPERTY C_STANDARD 90)
|
set_property(TARGET rdi-libstatic PROPERTY C_STANDARD 17)
|
||||||
set_property(TARGET rdi-libstatic PROPERTY CXX_STANDARD 17)
|
set_property(TARGET rdi-libstatic PROPERTY CXX_STANDARD 17)
|
||||||
|
set_property(TARGET rdi-libstatic PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||||
|
set_target_properties(rdi-libstatic PROPERTIES VERSION 1.0.0)
|
||||||
|
|
||||||
target_include_directories(rdi-libstatic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
target_include_directories(rdi-libstatic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
|
# As GNU-GCC have different runtime lib, we statically link them for this type of build
|
||||||
|
if (NOT MSVC)
|
||||||
|
target_link_libraries(rdi-libstatic PRIVATE
|
||||||
|
-static-libgcc
|
||||||
|
-static-libstdc++
|
||||||
|
)
|
||||||
|
endif()
|
||||||
target_link_libraries(rdi-libstatic PRIVATE
|
target_link_libraries(rdi-libstatic PRIVATE
|
||||||
${RSPModel_LIBRARIES}
|
${RSPModel_LIBRARIES}
|
||||||
${RSPTerrain_LIBRARIES}
|
${RSPTerrain_LIBRARIES}
|
||||||
@ -149,24 +170,45 @@ endif()
|
|||||||
|
|
||||||
if(BUILD_TOOLS)
|
if(BUILD_TOOLS)
|
||||||
# Add lib debug tool to buildchain
|
# Add lib debug tool to buildchain
|
||||||
file(GLOB_RECURSE RDI_TOOLS_SOURCES ./tools/*.cpp ./tools/*.c)
|
#file(GLOB_RECURSE RDI_TOOLS_SOURCES ./tools/*.cpp ./tools/*.c)
|
||||||
source_group("Tools src files" FILES ${RDI_TOOLS_SOURCES})
|
#source_group("Tools src files" FILES ${RDI_TOOLS_SOURCES})
|
||||||
|
|
||||||
add_executable(rdi-debug-tools ${RDI_TOOLS_SOURCES})
|
#add_executable(rdi-debug-tools ${RDI_TOOLS_SOURCES})
|
||||||
set_property(TARGET rdi-debug-tools PROPERTY C_STANDARD 90)
|
add_executable(rdi-debug-tools ./tools/RDIDebug.cpp)
|
||||||
|
set_property(TARGET rdi-debug-tools PROPERTY C_STANDARD 17)
|
||||||
|
set_property(TARGET rdi-debug-tools PROPERTY CXX_STANDARD 17)
|
||||||
set_target_properties(rdi-debug-tools PROPERTIES OUTPUT_NAME "RDI-debug")
|
set_target_properties(rdi-debug-tools PROPERTIES OUTPUT_NAME "RDI-debug")
|
||||||
list(APPEND RDI_TARGETS_LIST rdi-debug-tools)
|
list(APPEND RDI_TARGETS_LIST rdi-debug-tools)
|
||||||
|
|
||||||
|
add_executable(erso-debug-tools ./tools/ErsoDebug.cpp)
|
||||||
|
set_property(TARGET erso-debug-tools PROPERTY C_STANDARD 17)
|
||||||
|
set_property(TARGET erso-debug-tools PROPERTY CXX_STANDARD 17)
|
||||||
|
set_target_properties(erso-debug-tools PROPERTIES OUTPUT_NAME "Erso-debug")
|
||||||
|
list(APPEND RDI_TARGETS_LIST erso-debug-tools)
|
||||||
|
|
||||||
|
add_executable(krennic-debug-tools ./tools/KrennicDebug.cpp)
|
||||||
|
set_property(TARGET krennic-debug-tools PROPERTY C_STANDARD 17)
|
||||||
|
set_property(TARGET krennic-debug-tools PROPERTY CXX_STANDARD 17)
|
||||||
|
set_target_properties(krennic-debug-tools PROPERTIES OUTPUT_NAME "Krennic-debug")
|
||||||
|
list(APPEND RDI_TARGETS_LIST krennic-debug-tools)
|
||||||
|
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
# msvc does not append 'lib' - do it here to have consistent name
|
# msvc does not append 'lib' - do it here to have consistent name
|
||||||
set_target_properties(rdi-debug-tools PROPERTIES IMPORT_PREFIX "lib")
|
set_target_properties(rdi-debug-tools PROPERTIES IMPORT_PREFIX "lib")
|
||||||
|
set_target_properties(erso-debug-tools PROPERTIES IMPORT_PREFIX "lib")
|
||||||
|
set_target_properties(krennic-debug-tools PROPERTIES IMPORT_PREFIX "lib")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Static libgcc and libstdc++ already linked in library
|
||||||
if(RDI_SHARED)
|
if(RDI_SHARED)
|
||||||
target_link_libraries(rdi-debug-tools PRIVATE rdi-lib)
|
target_link_libraries(rdi-debug-tools PRIVATE rdi-lib ${Boost_LIBRARIES})
|
||||||
|
target_link_libraries(erso-debug-tools PRIVATE rdi-lib)
|
||||||
|
target_link_libraries(krennic-debug-tools PRIVATE rdi-lib)
|
||||||
elseif(RDI_STATIC)
|
elseif(RDI_STATIC)
|
||||||
target_link_libraries(rdi-debug-tools PRIVATE rdi-libstatic)
|
target_link_libraries(rdi-debug-tools PRIVATE rdi-libstatic ${Boost_LIBRARIES})
|
||||||
|
target_link_libraries(erso-debug-tools PRIVATE rdi-libstatic)
|
||||||
|
target_link_libraries(krennic-debug-tools PRIVATE rdi-libstatic)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
[requires]
|
[requires]
|
||||||
rspmodellib/2.2.0
|
rspmodellib/2.3.0
|
||||||
rspterrainlib/2.0.4
|
rspterrainlib/2.0.4
|
||||||
rsptexturelib/2.1.0
|
rsptexturelib/2.1.0
|
||||||
boost/1.80.0
|
boost/1.81.0
|
||||||
|
|
||||||
[generators]
|
[generators]
|
||||||
cmake
|
cmake
|
||||||
|
61
include/FileHandler/Generic.h
Normal file
61
include/FileHandler/Generic.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* @file GenericFile.h
|
||||||
|
* @date 01/02/2023
|
||||||
|
* @author JackCarterSmith
|
||||||
|
* @copyright GPL-v3.0
|
||||||
|
* @brief Generic file object class.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../RDI_Datatypes.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef GENERICFILE_H_
|
||||||
|
#define GENERICFILE_H_
|
||||||
|
|
||||||
|
namespace RDI {
|
||||||
|
|
||||||
|
namespace DatFile {
|
||||||
|
class DatFileEntryFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GenericFile {
|
||||||
|
public:
|
||||||
|
// Default constructor
|
||||||
|
// Set the default class members and link against correct MEMFILE
|
||||||
|
GenericFile( DatFile::DatFileEntryFile* hDat );
|
||||||
|
virtual ~GenericFile();
|
||||||
|
|
||||||
|
GenericFile(const GenericFile&) = default;
|
||||||
|
GenericFile& operator=(const GenericFile&) = default;
|
||||||
|
|
||||||
|
GenericFile(GenericFile&&) = default;
|
||||||
|
GenericFile& operator=(GenericFile&&) = default;
|
||||||
|
|
||||||
|
// Primary datas parsing/loading function
|
||||||
|
// This function must be called to load datas in memory and access to others function
|
||||||
|
void Load();
|
||||||
|
bool isLoaded() const { return loaded; }
|
||||||
|
|
||||||
|
// Free memory of object datas
|
||||||
|
// Should be called after using it
|
||||||
|
void Dispose();
|
||||||
|
|
||||||
|
std::string getFileName() const { return fileName; }
|
||||||
|
std::string getFullPath() const { return fullFilePath; }
|
||||||
|
std::string getFileExtension() const { return fileExtension; }
|
||||||
|
MEMFILE get() { return pMemLoc; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
unsigned long size;
|
||||||
|
std::string fileName, fullFilePath, fileExtension;
|
||||||
|
MEMFILE pMemLoc = nullptr;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool loaded = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* GENERICFILE_H_ */
|
@ -7,17 +7,20 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SRC_DATFILES_HMT_H_
|
#include <FileHandler/Generic.h>
|
||||||
#define SRC_DATFILES_HMT_H_
|
|
||||||
|
|
||||||
|
#ifndef HMT_H_
|
||||||
|
#define HMT_H_
|
||||||
|
|
||||||
namespace RDI {
|
namespace RDI {
|
||||||
|
|
||||||
class HMT {
|
class HMT : public GenericFile {
|
||||||
public:
|
public:
|
||||||
HMT();
|
HMT( DatFile::DatFileEntryFile* hDat );
|
||||||
virtual ~HMT();
|
virtual ~HMT();
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace RDI */
|
}
|
||||||
|
|
||||||
#endif /* SRC_DATFILES_HMT_H_ */
|
#endif /* HMT_H_ */
|
120
include/FileHandler/HOB.h
Normal file
120
include/FileHandler/HOB.h
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/**
|
||||||
|
* @file HOB.h
|
||||||
|
* @date 31/01/2023
|
||||||
|
* @author JackCarterSmith
|
||||||
|
* @copyright GPL-v3.0
|
||||||
|
* @brief HOB file object class.
|
||||||
|
*
|
||||||
|
* Rogue data files use a specific (and size optimized) storage method of model.
|
||||||
|
* HOB handler parse these datas and store them in a more GPU-frienly BOOST-Lib
|
||||||
|
* type.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <boost/qvm_lite.hpp>
|
||||||
|
#include <FileHandler/Generic.h>
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef HOB_H_
|
||||||
|
#define HOB_H_
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# define RDI_ABI_EXPORT __declspec(dllexport)
|
||||||
|
# define RDI_ABI_IMPORT __declspec(dllimport)
|
||||||
|
#elif __GNUC__ >= 4
|
||||||
|
# define RDI_ABI_EXPORT __attribute__ ((visibility("default")))
|
||||||
|
# define RDI_ABI_IMPORT __attribute__ ((visibility("default")))
|
||||||
|
#else
|
||||||
|
# define RDI_ABI_EXPORT
|
||||||
|
# define RDI_ABI_IMPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(RDI_DLL)
|
||||||
|
# if defined(WIN32)
|
||||||
|
# if defined(RDI_DLLBUILD)
|
||||||
|
# define RDI_EXTERN RDI_ABI_EXPORT
|
||||||
|
# else
|
||||||
|
# define RDI_EXTERN RDI_ABI_IMPORT
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RDI_EXTERN
|
||||||
|
# define RDI_EXTERN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace RDI {
|
||||||
|
|
||||||
|
class HOB final : public GenericFile {
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
struct Vertex {
|
||||||
|
Vertex() noexcept = default;
|
||||||
|
Vertex(float x, float y, float z) noexcept
|
||||||
|
: x(x),y(y),z(z) {}
|
||||||
|
Vertex(std::array<float, 3> vArray) noexcept
|
||||||
|
: x(vArray[0]),y(vArray[1]),z(vArray[2]) {}
|
||||||
|
|
||||||
|
Vertex(const Vertex&) = default;
|
||||||
|
Vertex& operator=(const Vertex&) = default;
|
||||||
|
|
||||||
|
Vertex(Vertex&&) = default;
|
||||||
|
Vertex& operator=(Vertex&&) = default;
|
||||||
|
|
||||||
|
float x = 0.0f, y = 0.0f, z = 0.0f;
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct Mesh {
|
||||||
|
// Empty vertices mesh should be considered as root/main mesh struct.
|
||||||
|
std::vector<boost::qvm::vec<float, 3>*> vertices;
|
||||||
|
std::vector<uint16_t> indices;
|
||||||
|
|
||||||
|
// Transform matrix not used for now, equal to identity matrix.
|
||||||
|
boost::qvm::mat<float,4,4> transform;
|
||||||
|
//Material material;
|
||||||
|
|
||||||
|
// Submesh are divided by material/texture
|
||||||
|
std::vector<HOB::Mesh*> subMeshs;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
HOB( DatFile::DatFileEntryFile* hDat );
|
||||||
|
~HOB();
|
||||||
|
|
||||||
|
HOB(const HOB&) = default;
|
||||||
|
HOB& operator=(const HOB&) = default;
|
||||||
|
|
||||||
|
HOB(HOB&&) = default;
|
||||||
|
HOB& operator=(HOB&&) = default;
|
||||||
|
|
||||||
|
// Mandatory function from base class
|
||||||
|
RDI_EXTERN void Load();
|
||||||
|
RDI_EXTERN void Dispose();
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
RDI_EXTERN unsigned int getObjectCount() const;
|
||||||
|
RDI_EXTERN std::string* getObjectName( unsigned short index ) const;
|
||||||
|
|
||||||
|
RDI_EXTERN HOB::Mesh* getMeshFromObject( unsigned short index ) const;
|
||||||
|
RDI_EXTERN HOB::Mesh* getMeshFromObject( std::string name ) const;
|
||||||
|
|
||||||
|
//ObjectMaterials getMaterialFromObject( unsigned short index, unsigned short materialIndex );
|
||||||
|
//ObjectMaterials getMaterialFromObject( std::string name, unsigned short materialIndex );
|
||||||
|
//std::vector<ObjectMaterials> getMaterialsFromObject( unsigned short index );
|
||||||
|
//std::vector<ObjectMaterials> getMaterialsFromObject( std::string name );
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
void* hobInstance = nullptr;
|
||||||
|
unsigned int objCnt = 0;
|
||||||
|
std::unordered_map<std::string, HOB::Mesh*> objectMeshList; // Each object mesh ordered by index
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HOB_H_ */
|
@ -1,77 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file RDI.h
|
|
||||||
* @date 15/09/2022
|
|
||||||
* @author JackCarterSmith
|
|
||||||
* @copyright GPL-v3.0
|
|
||||||
* @brief Rogue Data Interface library main entry file.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "RDI_Datatypes.h"
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef RDI_H_
|
|
||||||
#define RDI_H_
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
# define RDI_ABI_EXPORT __declspec(dllexport)
|
|
||||||
# define RDI_ABI_IMPORT __declspec(dllimport)
|
|
||||||
#elif __GNUC__ >= 4
|
|
||||||
# define RDI_ABI_EXPORT __attribute__ ((visibility("default")))
|
|
||||||
# define RDI_ABI_IMPORT __attribute__ ((visibility("default")))
|
|
||||||
#else
|
|
||||||
# define RDI_ABI_EXPORT
|
|
||||||
# define RDI_ABI_IMPORT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(RDI_DLL)
|
|
||||||
# if defined(WIN32)
|
|
||||||
# if defined(RDI_DLLBUILD)
|
|
||||||
# define RDI_EXTERN RDI_ABI_EXPORT
|
|
||||||
# else
|
|
||||||
# define RDI_EXTERN RDI_ABI_IMPORT
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef RDI_EXTERN
|
|
||||||
# define RDI_EXTERN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
namespace RDI {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the current library version.
|
|
||||||
* @return String of the version.
|
|
||||||
*/
|
|
||||||
RDI_EXTERN std::string getLibVersion( void );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create a new Rogue Data file instance.
|
|
||||||
* @details Try to open DATA.DAT file at location specified by roguePath.
|
|
||||||
* If file can be opened, it's mapped in memory and process files list.
|
|
||||||
*
|
|
||||||
* @param[in] roguePath Path to DATA.DAT and DATA.HDR location.
|
|
||||||
*
|
|
||||||
* @return Handler of RogueData file, should be used with other function of this lib.
|
|
||||||
*/
|
|
||||||
RDI_EXTERN void CreateRDatHandler( std::string roguePath );
|
|
||||||
|
|
||||||
RDI_EXTERN unsigned char getSectionCount( void );
|
|
||||||
RDI_EXTERN std::string getSectionName( unsigned char id );
|
|
||||||
RDI_EXTERN unsigned int getSectionOffset( unsigned char id );
|
|
||||||
|
|
||||||
RDI_EXTERN unsigned int getDirectoryElementCount( std::string path );
|
|
||||||
RDI_EXTERN std::vector<std::string> getDirectoryElements( std::string path );
|
|
||||||
RDI_EXTERN bool isElementDirectory( std::string path );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Clean up global resources.
|
|
||||||
*/
|
|
||||||
RDI_EXTERN void DestroyRDatHandler( void );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* RDI_H_ */
|
|
89
include/RDI.hpp
Normal file
89
include/RDI.hpp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
* @file RDI.hpp
|
||||||
|
* @date 22/01/2023
|
||||||
|
* @author JackCarterSmith
|
||||||
|
* @copyright GPL-v3.0
|
||||||
|
* @brief Rogue Data Interface library main entry file.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "RDI_Datatypes.h"
|
||||||
|
#include "FileHandler/HOB.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef RDI_HPP_
|
||||||
|
#define RDI_HPP_
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# define RDI_ABI_EXPORT __declspec(dllexport)
|
||||||
|
# define RDI_ABI_IMPORT __declspec(dllimport)
|
||||||
|
#elif __GNUC__ >= 4
|
||||||
|
# define RDI_ABI_EXPORT __attribute__ ((visibility("default")))
|
||||||
|
# define RDI_ABI_IMPORT __attribute__ ((visibility("default")))
|
||||||
|
#else
|
||||||
|
# define RDI_ABI_EXPORT
|
||||||
|
# define RDI_ABI_IMPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(RDI_DLL)
|
||||||
|
# if defined(WIN32)
|
||||||
|
# if defined(RDI_DLLBUILD)
|
||||||
|
# define RDI_EXTERN RDI_ABI_EXPORT
|
||||||
|
# else
|
||||||
|
# define RDI_EXTERN RDI_ABI_IMPORT
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RDI_EXTERN
|
||||||
|
# define RDI_EXTERN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace RDI {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the current library version.
|
||||||
|
* @return String of the version.
|
||||||
|
*/
|
||||||
|
RDI_EXTERN const std::string RDI_getLibVersion( void ) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate memory and create default structure to access datas.
|
||||||
|
* @details Try to open DATA.DAT file at location specified by roguePath.
|
||||||
|
* If file can be opened, it's mapped in memory and process files list.
|
||||||
|
* @param[in] roguePath Path to DATA.DAT and DATA.HDR location.
|
||||||
|
*/
|
||||||
|
RDI_EXTERN void RDI_Init( std::string roguePath );
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Erso specific methods */
|
||||||
|
RDI_EXTERN const unsigned char RDI_getSectionCount( void );
|
||||||
|
RDI_EXTERN const std::string RDI_getSectionName( unsigned char id );
|
||||||
|
RDI_EXTERN const unsigned int RDI_getSectionOffset( unsigned char id );
|
||||||
|
|
||||||
|
RDI_EXTERN const unsigned int RDI_getDirectoryElementCount( std::string path );
|
||||||
|
RDI_EXTERN const std::vector<std::string> RDI_getDirectoryElements( std::string path );
|
||||||
|
RDI_EXTERN const bool RDI_isElementDirectory( std::string path );
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Krennic specific methods */
|
||||||
|
RDI_EXTERN const std::vector<std::string> RDI_getLevelsName( void );
|
||||||
|
RDI_EXTERN const std::vector<std::string> RDI_getModelsName( void );
|
||||||
|
RDI_EXTERN const std::vector<std::string> RDI_getTexturesName( void );
|
||||||
|
RDI_EXTERN const std::vector<std::string> RDI_getMusicsName( void );
|
||||||
|
|
||||||
|
RDI_EXTERN HOB* RDI_getModel( std::string modelName );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clean up global resources.
|
||||||
|
*/
|
||||||
|
RDI_EXTERN void RDI_CleanUp( void );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* RDI_HPP_ */
|
@ -1,68 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file DatEntry.cpp
|
|
||||||
* @date 20/09/2022
|
|
||||||
* @author JackCarterSmith
|
|
||||||
* @copyright GPL-v3.0
|
|
||||||
* @brief Data file entry descriptor class.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "DatEntry.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace RDI {
|
|
||||||
|
|
||||||
FileEntry::FileEntry( std::string name, DAT_FILE_FLAGS fFlags, unsigned int size, MEMFILE fPtr ) {
|
|
||||||
this->name = name;
|
|
||||||
this->size = size;
|
|
||||||
this->fFlags.raw = fFlags.raw;
|
|
||||||
this->fileMemPtr = fPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
FileEntry::~FileEntry() {}
|
|
||||||
|
|
||||||
/*std::string FileEntry::toString() {
|
|
||||||
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
DirectoryEntry::DirectoryEntry( std::string name ) {
|
|
||||||
this->name = name;
|
|
||||||
this->fFlags.raw = 0;
|
|
||||||
this->rootDir = true;
|
|
||||||
vSubFiles = new std::vector<DatEntry*>;
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectoryEntry::DirectoryEntry( std::string name, DAT_FILE_FLAGS fFlags ) {
|
|
||||||
this->name = name;
|
|
||||||
this->fFlags.raw = fFlags.raw;
|
|
||||||
this->rootDir = false;
|
|
||||||
vSubFiles = new std::vector<DatEntry*>;
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectoryEntry::DirectoryEntry( std::string name, DAT_FILE_FLAGS fFlags, DatEntry* hFileEntry ) {
|
|
||||||
this->name = name;
|
|
||||||
this->fFlags.raw = fFlags.raw;
|
|
||||||
vSubFiles = new std::vector<DatEntry*>;
|
|
||||||
AddEntry(hFileEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectoryEntry::~DirectoryEntry() {
|
|
||||||
for ( DatEntry* e : *vSubFiles )
|
|
||||||
delete e;
|
|
||||||
delete vSubFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*std::string DirectoryEntry::toString() {
|
|
||||||
|
|
||||||
}*/
|
|
||||||
|
|
||||||
void DirectoryEntry::ClearLinkedFiles() {
|
|
||||||
vSubFiles->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DirectoryEntry::AddEntry( DatEntry* hFileEntry ) {
|
|
||||||
vSubFiles->push_back(hFileEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file DatEntry.h
|
|
||||||
* @date 20/09/2022
|
|
||||||
* @author JackCarterSmith
|
|
||||||
* @copyright GPL-v3.0
|
|
||||||
* @brief Data file entry descriptor class.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "RDI_Datatypes.h"
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef DATENTRY_H_
|
|
||||||
#define DATENTRY_H_
|
|
||||||
|
|
||||||
|
|
||||||
namespace RDI {
|
|
||||||
|
|
||||||
typedef union u_file_flags {
|
|
||||||
struct {
|
|
||||||
// LSB
|
|
||||||
unsigned short unknown0:1;
|
|
||||||
unsigned short isFile:1;
|
|
||||||
unsigned short unknown1:5;
|
|
||||||
unsigned short isDirectory:1;
|
|
||||||
unsigned short unknown2:8;
|
|
||||||
// MSB
|
|
||||||
};
|
|
||||||
unsigned short raw;
|
|
||||||
} DAT_FILE_FLAGS;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DatEntry {
|
|
||||||
public:
|
|
||||||
virtual ~DatEntry() = 0;
|
|
||||||
virtual bool isDirectory() = 0;
|
|
||||||
virtual bool isRootDirectory() = 0;
|
|
||||||
//virtual std::string toString() = 0;
|
|
||||||
virtual unsigned int getSize() = 0;
|
|
||||||
|
|
||||||
std::string getName() { return name; };
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::string name;
|
|
||||||
DAT_FILE_FLAGS fFlags;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline DatEntry::~DatEntry() {}
|
|
||||||
|
|
||||||
class FileEntry : public DatEntry {
|
|
||||||
public:
|
|
||||||
FileEntry( std::string name, DAT_FILE_FLAGS fFlags, unsigned int size, MEMFILE fPtr );
|
|
||||||
~FileEntry();
|
|
||||||
|
|
||||||
MEMFILE getDatas() { return fileMemPtr; }
|
|
||||||
|
|
||||||
//std::string toString();
|
|
||||||
bool isDirectory() { return false; }
|
|
||||||
bool isRootDirectory() { return false; }
|
|
||||||
unsigned int getSize() { return size; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
MEMFILE fileMemPtr;
|
|
||||||
unsigned int size;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class DirectoryEntry : public DatEntry {
|
|
||||||
public:
|
|
||||||
DirectoryEntry( std::string name );
|
|
||||||
DirectoryEntry( std::string name, DAT_FILE_FLAGS fFlags );
|
|
||||||
DirectoryEntry( std::string name, DAT_FILE_FLAGS fFlags, DatEntry* hFileEntry );
|
|
||||||
~DirectoryEntry();
|
|
||||||
|
|
||||||
void ClearLinkedFiles();
|
|
||||||
void AddEntry( DatEntry* hFileEntry );
|
|
||||||
std::vector<DatEntry*> getFiles() { return *vSubFiles; }
|
|
||||||
|
|
||||||
//std::string toString();
|
|
||||||
bool isDirectory() { return true; }
|
|
||||||
bool isRootDirectory() { return rootDir; }
|
|
||||||
unsigned int getSize() { return vSubFiles->size(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool rootDir;
|
|
||||||
std::vector<DatEntry*> *vSubFiles;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* DATENTRY_H_ */
|
|
59
src/DatFileEntry.cpp
Normal file
59
src/DatFileEntry.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* @file DatFileEntry.cpp
|
||||||
|
* @date 12/01/2023
|
||||||
|
* @author JackCarterSmith
|
||||||
|
* @copyright GPL-v3.0
|
||||||
|
* @brief Data file entry descriptor objects helper class.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <RDI_Datatypes.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include "DatFileEntry.hpp"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
|
|
||||||
|
namespace RDI {
|
||||||
|
namespace DatFile {
|
||||||
|
|
||||||
|
DatFileEntryFile::DatFileEntryFile( string name, string path, DAT_FILE_FLAGS fFlags, unsigned int size, MEMFILE fPtr )
|
||||||
|
: DatFileEntry::DatFileEntry(name, path, fFlags), size(size), fileMemPtr(fPtr) {}
|
||||||
|
|
||||||
|
DatFileEntryFile::~DatFileEntryFile() {}
|
||||||
|
|
||||||
|
|
||||||
|
DatFileEntryDirectory::DatFileEntryDirectory( string name, string path )
|
||||||
|
: DatFileEntry::DatFileEntry(name, path), rootDir(true) {
|
||||||
|
vSubFiles = new vector<DatFileEntry*>;
|
||||||
|
}
|
||||||
|
|
||||||
|
DatFileEntryDirectory::DatFileEntryDirectory( string name, string path, DAT_FILE_FLAGS fFlags )
|
||||||
|
: DatFileEntry::DatFileEntry(name, path, fFlags), rootDir(false) {
|
||||||
|
vSubFiles = new vector<DatFileEntry*>;
|
||||||
|
}
|
||||||
|
|
||||||
|
DatFileEntryDirectory::DatFileEntryDirectory( string name, string path, DAT_FILE_FLAGS fFlags, DatFileEntry* hFileEntry )
|
||||||
|
: DatFileEntry::DatFileEntry(name, path, fFlags), rootDir(false) {
|
||||||
|
vSubFiles = new vector<DatFileEntry*>;
|
||||||
|
AddEntry(hFileEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
DatFileEntryDirectory::~DatFileEntryDirectory() {
|
||||||
|
for ( DatFileEntry* e : *vSubFiles )
|
||||||
|
delete e;
|
||||||
|
delete vSubFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatFileEntryDirectory::ClearLinkedFiles() {
|
||||||
|
vSubFiles->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatFileEntryDirectory::AddEntry( DatFileEntry* hFileEntry ) {
|
||||||
|
vSubFiles->push_back(hFileEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
106
src/DatFileEntry.hpp
Normal file
106
src/DatFileEntry.hpp
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/**
|
||||||
|
* @file DatFileEntry.hpp
|
||||||
|
* @date 12/01/2023
|
||||||
|
* @author JackCarterSmith
|
||||||
|
* @copyright GPL-v3.0
|
||||||
|
* @brief Data file entry descriptor objects helper class.
|
||||||
|
*
|
||||||
|
* DATA and BUNDLE file store in different location file's header and
|
||||||
|
* file's data. This helper class it's used to provide a more convenient
|
||||||
|
* access to the corresponding file inside memory (after Erso module's
|
||||||
|
* initialization).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <RDI_Datatypes.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ERSOENTRY_HPP_
|
||||||
|
#define ERSOENTRY_HPP_
|
||||||
|
|
||||||
|
|
||||||
|
namespace RDI {
|
||||||
|
namespace DatFile {
|
||||||
|
|
||||||
|
typedef union u_file_flags {
|
||||||
|
struct {
|
||||||
|
// LSB
|
||||||
|
unsigned short unknown0:1;
|
||||||
|
unsigned short isFile:1;
|
||||||
|
unsigned short unknown1:5;
|
||||||
|
unsigned short isDirectory:1;
|
||||||
|
unsigned short unknown2:8;
|
||||||
|
// MSB
|
||||||
|
};
|
||||||
|
unsigned short raw;
|
||||||
|
} DAT_FILE_FLAGS;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DatFileEntry {
|
||||||
|
public:
|
||||||
|
virtual ~DatFileEntry() = 0;
|
||||||
|
virtual bool isDirectory() = 0;
|
||||||
|
virtual bool isRootDirectory() = 0;
|
||||||
|
virtual unsigned int getSize() = 0;
|
||||||
|
|
||||||
|
std::string getName() { return name; }
|
||||||
|
std::string getPath() { return virtualAbsPath; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
DatFileEntry( std::string name, std::string path ) : name(name), virtualAbsPath(path) {
|
||||||
|
this->fFlags.raw = 0;
|
||||||
|
}
|
||||||
|
DatFileEntry( std::string name, std::string path, DAT_FILE_FLAGS fFlags )
|
||||||
|
: name(name), virtualAbsPath(path), fFlags(fFlags) {}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
std::string virtualAbsPath;
|
||||||
|
DAT_FILE_FLAGS fFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline DatFileEntry::~DatFileEntry() {}
|
||||||
|
|
||||||
|
class DatFileEntryFile : public DatFileEntry {
|
||||||
|
public:
|
||||||
|
DatFileEntryFile( std::string name, std::string path, DAT_FILE_FLAGS fFlags, unsigned int size, MEMFILE fPtr );
|
||||||
|
~DatFileEntryFile();
|
||||||
|
|
||||||
|
MEMFILE getDatas() { return fileMemPtr; }
|
||||||
|
|
||||||
|
bool isDirectory() { return false; }
|
||||||
|
bool isRootDirectory() { return false; }
|
||||||
|
unsigned int getSize() { return size; } // In bytes
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int size;
|
||||||
|
MEMFILE fileMemPtr;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DatFileEntryDirectory : public DatFileEntry {
|
||||||
|
public:
|
||||||
|
DatFileEntryDirectory( std::string name, std::string path );
|
||||||
|
DatFileEntryDirectory( std::string name, std::string path, DAT_FILE_FLAGS fFlags );
|
||||||
|
DatFileEntryDirectory( std::string name, std::string path, DAT_FILE_FLAGS fFlags, DatFileEntry* hFileEntry );
|
||||||
|
~DatFileEntryDirectory();
|
||||||
|
|
||||||
|
void ClearLinkedFiles();
|
||||||
|
void AddEntry( DatFileEntry* hFileEntry );
|
||||||
|
std::vector<DatFileEntry*> getFiles() { return *vSubFiles; }
|
||||||
|
|
||||||
|
bool isDirectory() { return true; }
|
||||||
|
bool isRootDirectory() { return rootDir; }
|
||||||
|
unsigned int getSize() { return vSubFiles->size(); } // In number of elements
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool rootDir;
|
||||||
|
std::vector<DatFileEntry*> *vSubFiles;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ERSOENTRY_HPP_ */
|
354
src/Erso.cpp
Normal file
354
src/Erso.cpp
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
/**
|
||||||
|
* @file Erso.cpp
|
||||||
|
* @date 11/01/2023
|
||||||
|
* @author JackCarterSmith
|
||||||
|
* @copyright GPL-v3.0
|
||||||
|
* @brief Rogue DATA/BUNDLE file parser and interface.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <RDI_Datatypes.h>
|
||||||
|
#include "files_mms/data_struct.h"
|
||||||
|
#include "DatFileEntry.hpp"
|
||||||
|
#include "Erso.hpp"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
using std::ios;
|
||||||
|
using std::vector;
|
||||||
|
using boost::filesystem::path;
|
||||||
|
using boost::filesystem::file_size;
|
||||||
|
|
||||||
|
using namespace RDI::DatFile;
|
||||||
|
|
||||||
|
|
||||||
|
namespace RDI {
|
||||||
|
|
||||||
|
Erso::Erso( string fPath ) : workingDir(fPath)
|
||||||
|
{
|
||||||
|
Process();
|
||||||
|
}
|
||||||
|
|
||||||
|
Erso::Erso( string fPath, RDI_RESULT* outResult ) :
|
||||||
|
workingDir(fPath)
|
||||||
|
{
|
||||||
|
if (outResult) *outResult = Process();
|
||||||
|
else Process();
|
||||||
|
}
|
||||||
|
|
||||||
|
Erso::~Erso()
|
||||||
|
{
|
||||||
|
DisposeFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string Erso::getDataSectionName( unsigned char id ) const { return pDatSection->at(id).name; }
|
||||||
|
unsigned int Erso::getDataSectionOffset( unsigned char id ) const { return pDatSection->at(id).offset; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the current working directory.
|
||||||
|
* This action will reconstruct files tree, all previous file entries became invalid.
|
||||||
|
*
|
||||||
|
* @param newPath New working directory path
|
||||||
|
*
|
||||||
|
* @return Error status.
|
||||||
|
*/
|
||||||
|
RDI_RESULT Erso::setWorkingDirectory( std::string newPath ) {
|
||||||
|
RDI_RESULT errCode = RDI_OK;
|
||||||
|
|
||||||
|
DisposeFile();
|
||||||
|
|
||||||
|
this->workingDir = newPath;
|
||||||
|
Process();
|
||||||
|
|
||||||
|
return errCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------------------- */
|
||||||
|
RDI_RESULT Erso::Process() {
|
||||||
|
RDI_RESULT errCode = RDI_OK;
|
||||||
|
|
||||||
|
// Process header file and dump data file in memory.
|
||||||
|
errCode = DataFilesDumping();
|
||||||
|
if (errCode == RDI_ERROR_FILESYSTEM) {
|
||||||
|
std::cout << "Data files (DATA.DAT/DATA.HDR) not found! Interrupt." << std::endl;
|
||||||
|
return errCode;
|
||||||
|
} else if (errCode == RDI_ERROR_MEMORY) {
|
||||||
|
std::cout << "Memory allocation or file access failed! Interrupt." << std::endl;
|
||||||
|
return errCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process data file tree and filter file subtype into list.
|
||||||
|
CreateDataFilesTree();
|
||||||
|
|
||||||
|
return errCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to search for legacy DATA.DAT/HDR and dump it in memory.
|
||||||
|
*
|
||||||
|
* @return Error status.
|
||||||
|
*/
|
||||||
|
RDI_RESULT Erso::DataFilesDumping() {
|
||||||
|
unsigned int i;
|
||||||
|
path fp(workingDir);
|
||||||
|
MEMFILE pTmpFile;
|
||||||
|
|
||||||
|
// If input as a directory, assume it's contain DATA.DAT/HDR.
|
||||||
|
if (boost::filesystem::is_directory(fp)) fp.append("DATA.HDR");
|
||||||
|
|
||||||
|
// If file specified in input is the "datas" file, process the header (HDR) before.
|
||||||
|
if (fp.extension() == ".DAT") fp.replace_extension(".HDR");
|
||||||
|
|
||||||
|
// Open and parse data header file.
|
||||||
|
//if (boost::filesystem::exists(fp)) return RDI_ERROR_FILESYSTEM;
|
||||||
|
pTmpFile = CreateMemFile(fp);
|
||||||
|
if (!pTmpFile) return RDI_ERROR_MEMORY;
|
||||||
|
|
||||||
|
cDatSection = file_size(fp) / sizeof(T_HDR_ENTRY);
|
||||||
|
pDatSection = new vector<struct dataSection>(cDatSection);
|
||||||
|
for ( i = 0; i < pDatSection->size(); i++ ) {
|
||||||
|
// Store header infos into structure to make easier access later.
|
||||||
|
pDatSection->at(i).name.append(((T_HDR_ENTRY*)(pTmpFile + i * sizeof(T_HDR_ENTRY)))->section_name);
|
||||||
|
pDatSection->at(i).offset = ((T_HDR_ENTRY*)(pTmpFile + i * sizeof(T_HDR_ENTRY)))->section_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(pTmpFile);
|
||||||
|
|
||||||
|
// Dump data file and store it's pointer into class member.
|
||||||
|
fp.replace_extension(".DAT");
|
||||||
|
//if (boost::filesystem::exists(fp)) return RDI_ERROR_FILESYSTEM;
|
||||||
|
rDatPtr = CreateMemFile(fp);
|
||||||
|
if (!rDatPtr) return RDI_ERROR_MEMORY;
|
||||||
|
|
||||||
|
return RDI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump file into to newly allocated memory.
|
||||||
|
* @param filePath File path.
|
||||||
|
*
|
||||||
|
* @return Start memory pointer of the file.
|
||||||
|
*/
|
||||||
|
MEMFILE Erso::CreateMemFile( path filePath ) {
|
||||||
|
const unsigned int size = file_size(filePath);
|
||||||
|
std::fstream rdf;
|
||||||
|
MEMFILE fPtr = NULL;
|
||||||
|
|
||||||
|
rdf.open(filePath.string(), ios::in | ios::binary);
|
||||||
|
if (rdf.is_open()) {
|
||||||
|
fPtr = (MEMFILE)malloc(size);
|
||||||
|
rdf.read(fPtr, size);
|
||||||
|
rdf.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return fPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to process files content for further use in this library.
|
||||||
|
*
|
||||||
|
* @return Error status.
|
||||||
|
*/
|
||||||
|
RDI_RESULT Erso::CreateDataFilesTree() {
|
||||||
|
unsigned int curEntriesCount = 0, i;
|
||||||
|
DatFileEntryDirectory* curDir = nullptr;
|
||||||
|
MEMFILE pFileDescriptors = nullptr;
|
||||||
|
|
||||||
|
// Create new root files tree. One per data section.
|
||||||
|
pFTRoot = new std::vector<DatFileEntryDirectory*>;
|
||||||
|
pFTRoot->clear();
|
||||||
|
for ( i = 0; i < cDatSection; i++ ) {
|
||||||
|
curDir = new DatFileEntryDirectory(pDatSection->at(i).name, pDatSection->at(i).name);
|
||||||
|
pFTRoot->push_back(curDir);
|
||||||
|
|
||||||
|
// Recalculate files descriptor offset for current section.
|
||||||
|
pFileDescriptors = rDatPtr + pDatSection->at(i).offset +
|
||||||
|
((T_DAT_SECTION*)(rDatPtr + pDatSection->at(i).offset))->file_headers_offset;
|
||||||
|
curEntriesCount = (((T_DAT_SECTION*)(rDatPtr + pDatSection->at(i).offset))->file_headers_size) / 32;
|
||||||
|
|
||||||
|
// Process arborescente in recursive method.
|
||||||
|
ProcessTreeDirectoryContents(curDir, pFileDescriptors, curEntriesCount, rDatPtr + pDatSection->at(i).offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RDI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursive function to process all sub-directory from a specific DatFileEntryDirectory root.
|
||||||
|
*
|
||||||
|
* @param pCurDir Root/current DatFileEntryDirectory from which the function begin to dig into
|
||||||
|
* @param pDesc MEMFILE pointer to the first entry of directory to be parsed
|
||||||
|
* @param count Number of elements in the pCurDir directory
|
||||||
|
* @param pSectionStart MEMFILE pointer to the beginning of parsed file
|
||||||
|
*
|
||||||
|
* @return Error status.
|
||||||
|
*/
|
||||||
|
RDI_RESULT Erso::ProcessTreeDirectoryContents( DatFileEntryDirectory* pCurDir, MEMFILE pDesc, const unsigned int count, MEMFILE pSectionStart ) {
|
||||||
|
unsigned int i, newDRECnt;
|
||||||
|
DAT_FILE_FLAGS curEntryFlags = {0};
|
||||||
|
|
||||||
|
DatFileEntryFile* newFile = nullptr;
|
||||||
|
DatFileEntryDirectory* newDir = nullptr;
|
||||||
|
std::string tmpStr;
|
||||||
|
|
||||||
|
if ( count == 0 ) return RDI_ERROR_PROCESS;
|
||||||
|
|
||||||
|
for ( i = 0; i < count; i++ ) {
|
||||||
|
curEntryFlags.raw = ((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->flags;
|
||||||
|
|
||||||
|
tmpStr.clear();
|
||||||
|
tmpStr.append(((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->name);
|
||||||
|
|
||||||
|
// Test for file or directory
|
||||||
|
if (!curEntryFlags.isDirectory) {
|
||||||
|
newFile = new DatFileEntryFile(tmpStr, pCurDir->getPath() + "/" + tmpStr, curEntryFlags,
|
||||||
|
((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->datas_size,
|
||||||
|
pSectionStart + ((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->datas_offset);
|
||||||
|
pCurDir->AddEntry(newFile);
|
||||||
|
} else {
|
||||||
|
newDir = new DatFileEntryDirectory(tmpStr, pCurDir->getPath() + "/" + tmpStr, curEntryFlags);
|
||||||
|
pCurDir->AddEntry(newDir);
|
||||||
|
|
||||||
|
// Keep entries count in new directory to jump over after processing it.
|
||||||
|
newDRECnt = (((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->dir_entries_size - sizeof(T_FILE_HEADER)) / sizeof(T_FILE_HEADER);
|
||||||
|
ProcessTreeDirectoryContents(newDir, pDesc + (i + 1) * sizeof(T_FILE_HEADER), newDRECnt, pSectionStart);
|
||||||
|
if (newDRECnt <= count) i += newDRECnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RDI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free all allocated resources for files tree and MemFile
|
||||||
|
*/
|
||||||
|
void Erso::DisposeFile() {
|
||||||
|
for ( DatFileEntryDirectory* de : *pFTRoot )
|
||||||
|
delete de;
|
||||||
|
delete pFTRoot;
|
||||||
|
free(rDatPtr);
|
||||||
|
delete pDatSection;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------------------- */
|
||||||
|
/**
|
||||||
|
* Get DatFileEntry reference from virtual path
|
||||||
|
*
|
||||||
|
* @param virtualDirPath Path to the virtual resource
|
||||||
|
*
|
||||||
|
* @return Reference to the resource from specified input path
|
||||||
|
*/
|
||||||
|
DatFileEntry *Erso::getElement( path virtualDirPath ) {
|
||||||
|
bool skip = false;
|
||||||
|
path newPath;
|
||||||
|
|
||||||
|
for ( DatFileEntry* de : *pFTRoot ) {
|
||||||
|
if (virtualDirPath.size() == 1 || virtualDirPath.begin() == --virtualDirPath.end()) {
|
||||||
|
if (de->getName() == virtualDirPath.filename().string())
|
||||||
|
return de;
|
||||||
|
} else {
|
||||||
|
if (de->getName() == virtualDirPath.begin()->string()) {
|
||||||
|
for (auto& sp : virtualDirPath) {
|
||||||
|
if (skip)
|
||||||
|
newPath.append(sp);
|
||||||
|
skip = true;
|
||||||
|
}
|
||||||
|
return SearchEntryPath(dynamic_cast<DatFileEntryDirectory*>(de), newPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of files corresponding to the specified pattern.
|
||||||
|
*
|
||||||
|
* @param virtualDirPath Origin of browsing
|
||||||
|
* @param pattern Search filename pattern
|
||||||
|
* @param recursive Do the search inside subfolders
|
||||||
|
*
|
||||||
|
* @return List of references to the files corresponding to pattern
|
||||||
|
*/
|
||||||
|
vector<DatFileEntry*> Erso::getElements( path virtualDirPath, string pattern, bool recursive ) {
|
||||||
|
vector<DatFileEntry*> result;
|
||||||
|
DatFileEntryDirectory* curDir = dynamic_cast<DatFileEntryDirectory*>(getElement(virtualDirPath));
|
||||||
|
|
||||||
|
if (recursive) {
|
||||||
|
auto recursFileList = SearchEntriesPattern(curDir, pattern);
|
||||||
|
result.insert(result.end(), recursFileList.begin(), recursFileList.end());
|
||||||
|
} else {
|
||||||
|
for ( DatFileEntry* e : curDir->getFiles() ) {
|
||||||
|
if (e->getName().find(pattern) != string::npos) //TODO: Replace using RegEx search
|
||||||
|
result.push_back(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Browse inside virtual path to the final object from specific root DatFileEntryDirectory.
|
||||||
|
*
|
||||||
|
* @param curDir Origin of browsing
|
||||||
|
* @param virtualDirPath Requested file path
|
||||||
|
*
|
||||||
|
* @return Reference to the file resource
|
||||||
|
*/
|
||||||
|
DatFileEntry* Erso::SearchEntryPath( DatFileEntryDirectory* curDir, path virtualDirPath ) {
|
||||||
|
bool skip = false;
|
||||||
|
path newPath;
|
||||||
|
|
||||||
|
for ( DatFileEntry* e : curDir->getFiles() ) {
|
||||||
|
if (virtualDirPath.size() == 1 || virtualDirPath.begin() == --virtualDirPath.end()) {
|
||||||
|
if (e->getName() == virtualDirPath.filename().string())
|
||||||
|
return e;
|
||||||
|
} else {
|
||||||
|
if (e->isDirectory() && (e->getName() == virtualDirPath.begin()->string())) {
|
||||||
|
for (auto& sp : virtualDirPath) {
|
||||||
|
if (skip)
|
||||||
|
newPath.append(sp);
|
||||||
|
skip = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SearchEntryPath(dynamic_cast<DatFileEntryDirectory*>(e), newPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Browse inside virtual path to find specific pattern and add it reference to the list in input.
|
||||||
|
*
|
||||||
|
* @param upDir Origin of browsing
|
||||||
|
* @param pattern Search filename pattern
|
||||||
|
*
|
||||||
|
* @return Vector list of DatFileEntry
|
||||||
|
*/
|
||||||
|
vector<DatFileEntry*> Erso::SearchEntriesPattern( DatFileEntryDirectory* upDir, string pattern ) {
|
||||||
|
vector<DatFileEntry*> subDatEntries;
|
||||||
|
|
||||||
|
for ( DatFileEntry* e : upDir->getFiles() )
|
||||||
|
if (e->getName().find(pattern) != string::npos) //TODO: Replace using RegEx search
|
||||||
|
subDatEntries.push_back(e);
|
||||||
|
|
||||||
|
for ( DatFileEntry* e : upDir->getFiles() ) {
|
||||||
|
if (e->isDirectory()) {
|
||||||
|
auto recursFileList = SearchEntriesPattern(dynamic_cast<DatFileEntryDirectory*>(e), pattern);
|
||||||
|
subDatEntries.insert(subDatEntries.end(), recursFileList.begin(), recursFileList.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return subDatEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
106
src/Erso.hpp
Normal file
106
src/Erso.hpp
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/**
|
||||||
|
* @file Erso.hpp
|
||||||
|
* @date 11/01/2023
|
||||||
|
* @author JackCarterSmith
|
||||||
|
* @copyright GPL-v3.0
|
||||||
|
* @brief Rogue DATA/BUNDLE file parser and interface.
|
||||||
|
* @warning This module should be initialized before every others modules call of RDI library.
|
||||||
|
*
|
||||||
|
* Erso is the first module of the RDI library, it's use research work of
|
||||||
|
* <rogue_dev_team>, dpethes and myself to parse legacy data files of Rogue
|
||||||
|
* game.
|
||||||
|
* Currently compatible legacy files are :
|
||||||
|
* - DATA.DAT/HDR: as primary elements package containing all levels, sound,
|
||||||
|
* textures, etc.
|
||||||
|
* - BUNDLE.000: as title menu resources like pictures, buttons and cursor
|
||||||
|
* textures, menu sounds, menu macro-scripting.
|
||||||
|
* - BUNDLE.001: not known for now.
|
||||||
|
*
|
||||||
|
* This module should be initialized before every others modules call of RDI
|
||||||
|
* library.
|
||||||
|
*
|
||||||
|
* Standard usage:
|
||||||
|
* - Create a single Erso object with the folder path of datas files as input
|
||||||
|
* argument.
|
||||||
|
* - All supported data files will be parsed and a virtual tree view will be
|
||||||
|
* created.
|
||||||
|
* - The virtual tree view can be browse using appropriate 'get' functions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <vector>
|
||||||
|
#include "RDI_Datatypes.h"
|
||||||
|
|
||||||
|
#include "DatFileEntry.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ERSO_HPP_
|
||||||
|
#define ERSO_HPP_
|
||||||
|
|
||||||
|
namespace RDI {
|
||||||
|
|
||||||
|
struct dataSection {
|
||||||
|
std::string name = "";
|
||||||
|
unsigned int offset = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erso is class codename of the DATA/BUNDLE file parser of RDI library.
|
||||||
|
*
|
||||||
|
* @pre RDI should construct Erso class before doing anything on datas.
|
||||||
|
*/
|
||||||
|
class Erso final {
|
||||||
|
public:
|
||||||
|
Erso( std::string fPath );
|
||||||
|
Erso( std::string fPath, RDI_RESULT* outResult );
|
||||||
|
~Erso();
|
||||||
|
|
||||||
|
MEMFILE getRDat() const { return rDatPtr; }
|
||||||
|
|
||||||
|
/* Workspace management */
|
||||||
|
std::string getWorkingDirectory() const { return workingDir; }
|
||||||
|
RDI_RESULT setWorkingDirectory( std::string newPath );
|
||||||
|
|
||||||
|
/* Generals informations getters */
|
||||||
|
unsigned char getDataSectionCount() const { return cDatSection; }
|
||||||
|
std::string getDataSectionName( unsigned char id ) const;
|
||||||
|
unsigned int getDataSectionOffset( unsigned char id ) const;
|
||||||
|
bool isUpdatedVersion() const { return (cDatSection > 2); }
|
||||||
|
|
||||||
|
/* Tree manipulation/parse methods */
|
||||||
|
DatFile::DatFileEntry* getElement( boost::filesystem::path virtualDirPath );
|
||||||
|
std::vector<DatFile::DatFileEntry*> getElements( boost::filesystem::path virtualDirPath, std::string pattern, bool recursive );
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string workingDir = ".";
|
||||||
|
|
||||||
|
unsigned char cDatSection = 0;
|
||||||
|
std::vector<struct dataSection> *pDatSection = nullptr;
|
||||||
|
MEMFILE rDatPtr = nullptr;
|
||||||
|
|
||||||
|
std::vector<DatFile::DatFileEntryDirectory*> *pFTRoot = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
/* File processing methods */
|
||||||
|
RDI_RESULT Process();
|
||||||
|
RDI_RESULT DataFilesDumping();
|
||||||
|
MEMFILE CreateMemFile( boost::filesystem::path filePath );
|
||||||
|
RDI_RESULT CreateDataFilesTree();
|
||||||
|
RDI_RESULT ProcessTreeDirectoryContents(
|
||||||
|
DatFile::DatFileEntryDirectory* pCurDir,
|
||||||
|
MEMFILE pDesc,
|
||||||
|
const unsigned int count,
|
||||||
|
MEMFILE pSectionStart
|
||||||
|
);
|
||||||
|
void DisposeFile();
|
||||||
|
|
||||||
|
/* Tree manipulation/parse methods */
|
||||||
|
DatFile::DatFileEntry* SearchEntryPath( DatFile::DatFileEntryDirectory *curDir, boost::filesystem::path virtualDirPath);
|
||||||
|
std::vector<DatFile::DatFileEntry*> SearchEntriesPattern(DatFile::DatFileEntryDirectory *upDir, std::string pattern);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace RDI */
|
||||||
|
|
||||||
|
#endif /* ERSO_HPP_ */
|
203
src/Krennic.cpp
Normal file
203
src/Krennic.cpp
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
/**
|
||||||
|
* @file Krennic.cpp
|
||||||
|
* @date 18/09/2023
|
||||||
|
* @author JackCarterSmith
|
||||||
|
* @copyright GPL-v3.0
|
||||||
|
* @brief Main game assets parser and interface.
|
||||||
|
*
|
||||||
|
* Complete class would take Erso legacy files tree and extract levels, objects,
|
||||||
|
* textures, animations, etc. adapted datas for OpenGL/Direct3D application.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
#include <array>
|
||||||
|
#include <RSPModel.h>
|
||||||
|
#include <RSPTerrain.h>
|
||||||
|
#include <RSPTexture.h>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <FileHandler/Generic.h>
|
||||||
|
#include <FileHandler/HMT.h>
|
||||||
|
#include <FileHandler/HOB.h>
|
||||||
|
#include "Erso.hpp"
|
||||||
|
#include "Krennic.hpp"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
using std::vector;
|
||||||
|
using std::array;
|
||||||
|
|
||||||
|
using namespace RDI::DatFile;
|
||||||
|
|
||||||
|
|
||||||
|
namespace RDI {
|
||||||
|
|
||||||
|
struct PathDescriptor {
|
||||||
|
PathDescriptor(string p, bool r) noexcept
|
||||||
|
: path(p), isRecursive(r) {}
|
||||||
|
|
||||||
|
PathDescriptor(const PathDescriptor&) = default;
|
||||||
|
PathDescriptor& operator=(const PathDescriptor&) = default;
|
||||||
|
|
||||||
|
PathDescriptor(PathDescriptor&&) = default;
|
||||||
|
PathDescriptor& operator=(PathDescriptor&&) = default;
|
||||||
|
|
||||||
|
string path;
|
||||||
|
bool isRecursive;
|
||||||
|
};
|
||||||
|
|
||||||
|
Krennic::Krennic( Erso* pErso ) {
|
||||||
|
BuildLevelFileList(pErso);
|
||||||
|
BuildModelFileList(pErso);
|
||||||
|
BuildTextureFileList(pErso);
|
||||||
|
BuildMusicFileList(pErso);
|
||||||
|
BuildSampleFileList(pErso);
|
||||||
|
}
|
||||||
|
|
||||||
|
Krennic::~Krennic() {}
|
||||||
|
|
||||||
|
|
||||||
|
void Krennic::BuildLevelFileList( Erso* pErso ) {
|
||||||
|
const static array<PathDescriptor, 1> legacyLvlPath = {
|
||||||
|
PathDescriptor("data/level", true)
|
||||||
|
};
|
||||||
|
|
||||||
|
listLevelsName.clear();
|
||||||
|
for (PathDescriptor legacyLvlSubpath : legacyLvlPath) {
|
||||||
|
for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyLvlSubpath.path), "dat", legacyLvlSubpath.isRecursive)) {
|
||||||
|
//TODO: level-class builder
|
||||||
|
listLevelsName.push_back(file->getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Krennic::BuildModelFileList( Erso* pErso ) {
|
||||||
|
const static array<PathDescriptor, 9> legacyModelPath = {
|
||||||
|
PathDescriptor("data", false),
|
||||||
|
PathDescriptor("data/pl_crafts", false),
|
||||||
|
PathDescriptor("data/reb_stuff", false),
|
||||||
|
PathDescriptor("data/imp_stuff", false),
|
||||||
|
PathDescriptor("data/gnrc_stuff", false),
|
||||||
|
PathDescriptor("data/level", true),
|
||||||
|
PathDescriptor("data/frontend", true),
|
||||||
|
PathDescriptor("data/dbg", false),
|
||||||
|
PathDescriptor("dbg_data", false)
|
||||||
|
};
|
||||||
|
// Update version game legacy assets paths
|
||||||
|
const static array<PathDescriptor, 1> legacyModelPath2= {
|
||||||
|
PathDescriptor("data2", false)
|
||||||
|
};
|
||||||
|
|
||||||
|
listModels.clear();
|
||||||
|
listModelsName.clear();
|
||||||
|
for (PathDescriptor legacyModelSubpath : legacyModelPath) {
|
||||||
|
for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyModelSubpath.path), "_HOB", legacyModelSubpath.isRecursive)) {
|
||||||
|
auto hobObj = new HOB(dynamic_cast<DatFileEntryFile*>(file));
|
||||||
|
listModels.push_back(hobObj);
|
||||||
|
listModelsName.push_back(file->getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pErso->isUpdatedVersion()) {
|
||||||
|
for (PathDescriptor legacyModelSubpath2 : legacyModelPath2) {
|
||||||
|
for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyModelSubpath2.path), "_HOB", legacyModelSubpath2.isRecursive)) {
|
||||||
|
auto hobObj = new HOB(dynamic_cast<DatFileEntryFile*>(file));
|
||||||
|
listModels.push_back(hobObj);
|
||||||
|
listModelsName.push_back(file->getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Krennic::BuildTextureFileList( Erso* pErso ) {
|
||||||
|
// Base game legacy assets paths
|
||||||
|
const static array<PathDescriptor, 9> legacyTexturePath = {
|
||||||
|
PathDescriptor("data", false),
|
||||||
|
PathDescriptor("data/pl_crafts", false),
|
||||||
|
PathDescriptor("data/reb_stuff", false),
|
||||||
|
PathDescriptor("data/imp_stuff", false),
|
||||||
|
PathDescriptor("data/gnrc_stuff", false),
|
||||||
|
PathDescriptor("data/level", true),
|
||||||
|
PathDescriptor("data/frontend", true),
|
||||||
|
PathDescriptor("data/dbg", false),
|
||||||
|
PathDescriptor("dbg_data", false)
|
||||||
|
};
|
||||||
|
// Update version game legacy assets paths
|
||||||
|
const static array<PathDescriptor, 1> legacyTexturePath2= {
|
||||||
|
PathDescriptor("data2", false)
|
||||||
|
};
|
||||||
|
|
||||||
|
listTexturesName.clear();
|
||||||
|
for (PathDescriptor legacyTextureSubpath : legacyTexturePath) {
|
||||||
|
for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyTextureSubpath.path), "_HMT", legacyTextureSubpath.isRecursive)) {
|
||||||
|
//TODO: texture-class builder
|
||||||
|
listTexturesName.push_back(file->getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pErso->isUpdatedVersion()) {
|
||||||
|
for (PathDescriptor legacyTextureSubpath2 : legacyTexturePath2) {
|
||||||
|
for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyTextureSubpath2.path), "_HMT", legacyTextureSubpath2.isRecursive)) {
|
||||||
|
//TODO: texture-class builder
|
||||||
|
listTexturesName.push_back(file->getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Krennic::BuildMusicFileList( Erso* pErso ) {
|
||||||
|
const static array<PathDescriptor, 1> legacyLvlPath = {
|
||||||
|
PathDescriptor("data/sound", false)
|
||||||
|
};
|
||||||
|
|
||||||
|
listMusicsName.clear();
|
||||||
|
for (PathDescriptor legacyMusicSubpath : legacyLvlPath) {
|
||||||
|
for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyMusicSubpath.path), "_SNG", legacyMusicSubpath.isRecursive)) {
|
||||||
|
//TODO: MusyX-Class builder
|
||||||
|
listMusicsName.push_back(file->getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Krennic::BuildSampleFileList( Erso* pErso ) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//void* Krennic::getLevel( std::string name ) {}
|
||||||
|
|
||||||
|
HOB* Krennic::getModel( string name ) {
|
||||||
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
for (string fileName : listModelsName) {
|
||||||
|
if (fileName.find(name) != string::npos) {
|
||||||
|
return listModels.at(i);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::invalid_argument("Krennic can't found the requested model.");
|
||||||
|
}
|
||||||
|
|
||||||
|
//HMT* Krennic::getTexture( std::string name ) {}
|
||||||
|
|
||||||
|
//void* Krennic::getMusic( std::string name ) {}
|
||||||
|
|
||||||
|
//void* Krennic::getSample( std::string name ) {}
|
||||||
|
|
||||||
|
|
||||||
|
void Krennic::DisposeLevels() {}
|
||||||
|
|
||||||
|
void Krennic::DisposeModels() {
|
||||||
|
for (HOB* hobObj : listModels) {
|
||||||
|
if (hobObj->isLoaded())
|
||||||
|
hobObj->Dispose();
|
||||||
|
|
||||||
|
delete hobObj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Krennic::DisposeTextures() {}
|
||||||
|
|
||||||
|
void Krennic::DisposeMusics() {}
|
||||||
|
|
||||||
|
void Krennic::DisposeSamples() {}
|
||||||
|
|
||||||
|
}
|
91
src/Krennic.hpp
Normal file
91
src/Krennic.hpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/**
|
||||||
|
* @file Krennic.hpp
|
||||||
|
* @date 18/01/2023
|
||||||
|
* @author JackCarterSmith
|
||||||
|
* @copyright GPL-v3.0
|
||||||
|
* @brief Main game assets parser and interface.
|
||||||
|
*
|
||||||
|
* Complete class would take Erso legacy files tree and extract levels, objects,
|
||||||
|
* textures, animations, etc. adapted datas for OpenGL/Direct3D application.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <FileHandler/Generic.h>
|
||||||
|
#include <FileHandler/HMT.h>
|
||||||
|
#include <FileHandler/HOB.h>
|
||||||
|
#include "Erso.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef KRENNIC_HPP_
|
||||||
|
#define KRENNIC_HPP_
|
||||||
|
|
||||||
|
namespace RDI {
|
||||||
|
|
||||||
|
class Krennic final {
|
||||||
|
public:
|
||||||
|
Krennic( Erso* pErso );
|
||||||
|
~Krennic();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve know list of legacy game files type.
|
||||||
|
* @return Array of filtered elements.
|
||||||
|
*/
|
||||||
|
///@{
|
||||||
|
std::vector<std::string> getLevelsList() { return listLevelsName; }
|
||||||
|
std::vector<std::string> getModelsList() { return listModelsName; }
|
||||||
|
std::vector<std::string> getTexturesList() { return listTexturesName; }
|
||||||
|
std::vector<std::string> getMusicsList() { return listMusicsName; }
|
||||||
|
std::vector<std::string> getSamplesList() { return listSamplesName; }
|
||||||
|
///@}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the class interface for datas in specified file type.
|
||||||
|
* @param name Name of the file, should be in list.
|
||||||
|
* @return File type class handler.
|
||||||
|
*/
|
||||||
|
///@{
|
||||||
|
void* getLevel( std::string name );
|
||||||
|
HOB* getModel( std::string name );
|
||||||
|
HMT* getTexture( std::string name );
|
||||||
|
void* getMusic( std::string name );
|
||||||
|
void* getSample( std::string name );
|
||||||
|
///@}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieve default file instance.
|
||||||
|
* @details Unknown file type can be wrapped in dummy class to access raw
|
||||||
|
* content without parsing or other type of processing.
|
||||||
|
*
|
||||||
|
* @param[in] vPath Virtual path to the file.
|
||||||
|
* @return Generic file type class handler.
|
||||||
|
*/
|
||||||
|
GenericFile *getFile( boost::filesystem::path vPath );
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<HOB*> listModels;
|
||||||
|
|
||||||
|
std::vector<std::string> listLevelsName;
|
||||||
|
std::vector<std::string> listModelsName;
|
||||||
|
std::vector<std::string> listTexturesName;
|
||||||
|
std::vector<std::string> listMusicsName;
|
||||||
|
std::vector<std::string> listSamplesName;
|
||||||
|
|
||||||
|
void BuildLevelFileList( Erso* pErso );
|
||||||
|
void BuildModelFileList( Erso* pErso );
|
||||||
|
void BuildTextureFileList( Erso* pErso );
|
||||||
|
void BuildMusicFileList( Erso* pErso );
|
||||||
|
void BuildSampleFileList( Erso* pErso );
|
||||||
|
|
||||||
|
void DisposeLevels();
|
||||||
|
void DisposeModels();
|
||||||
|
void DisposeTextures();
|
||||||
|
void DisposeMusics();
|
||||||
|
void DisposeSamples();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* KRENNIC_HPP_ */
|
27
src/KrennicHandlerGeneric.cpp
Normal file
27
src/KrennicHandlerGeneric.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* @file GenericFile.cpp
|
||||||
|
* @date 01/02/2023
|
||||||
|
* @author JackCarterSmith
|
||||||
|
* @copyright GPL-v3.0
|
||||||
|
* @brief Generic file object class.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "DatFileEntry.hpp"
|
||||||
|
#include <FileHandler/Generic.h>
|
||||||
|
|
||||||
|
using namespace RDI::DatFile;
|
||||||
|
|
||||||
|
|
||||||
|
namespace RDI {
|
||||||
|
|
||||||
|
GenericFile::GenericFile( DatFile::DatFileEntryFile* hDat )
|
||||||
|
: size(hDat->getSize()), fileName(hDat->getName()), fullFilePath(hDat->getPath()), pMemLoc(hDat->getDatas()) {}
|
||||||
|
|
||||||
|
GenericFile::~GenericFile() {}
|
||||||
|
|
||||||
|
void GenericFile::Load() { this->loaded = true; }
|
||||||
|
void GenericFile::Dispose() { this->loaded = false; }
|
||||||
|
|
||||||
|
}
|
24
src/KrennicHandlerHMT.cpp
Normal file
24
src/KrennicHandlerHMT.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* @file HMT.cpp
|
||||||
|
* @date 15/09/2022
|
||||||
|
* @author JackCarterSmith
|
||||||
|
* @copyright GPL-v3.0
|
||||||
|
* @brief HMT file object class.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <FileHandler/Generic.h>
|
||||||
|
#include <FileHandler/HMT.h>
|
||||||
|
|
||||||
|
using namespace RDI::DatFile;
|
||||||
|
|
||||||
|
|
||||||
|
namespace RDI {
|
||||||
|
|
||||||
|
HMT::HMT( DatFile::DatFileEntryFile* hDat ): GenericFile( hDat ) {
|
||||||
|
this->fileExtension = "hmt";
|
||||||
|
}
|
||||||
|
|
||||||
|
HMT::~HMT() {}
|
||||||
|
|
||||||
|
}
|
189
src/KrennicHandlerHOB.cpp
Normal file
189
src/KrennicHandlerHOB.cpp
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
/**
|
||||||
|
* @file KrennicHandlerHOB.cpp
|
||||||
|
* @date 19/01/2023
|
||||||
|
* @author JackCarterSmith
|
||||||
|
* @copyright GPL-v3.0
|
||||||
|
* @brief HOB file object class.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <boost/qvm_lite.hpp>
|
||||||
|
#include <RSPModel.h>
|
||||||
|
#include <RSPModel_errordefs.h>
|
||||||
|
#include "DatFileEntry.hpp"
|
||||||
|
#include <FileHandler/Generic.h>
|
||||||
|
#include <FileHandler/HOB.h>
|
||||||
|
|
||||||
|
using std::runtime_error;
|
||||||
|
using std::out_of_range;
|
||||||
|
using std::invalid_argument;
|
||||||
|
using std::string;
|
||||||
|
using namespace RDI::DatFile;
|
||||||
|
using namespace boost::qvm;
|
||||||
|
|
||||||
|
|
||||||
|
namespace RDI {
|
||||||
|
|
||||||
|
HOB::Mesh* BuildObjectMesh( const T_RSPMODEL_OBJECT* hobPtr );
|
||||||
|
HOB::Mesh* FillMesh( const T_RSPMODEL_OBJ_PARTS* objPtr );
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
HOB::HOB( DatFileEntryFile* hDat )
|
||||||
|
: GenericFile(hDat) {
|
||||||
|
this->fileExtension = "hob";
|
||||||
|
}
|
||||||
|
|
||||||
|
HOB::~HOB() {
|
||||||
|
Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
void HOB::Load() {
|
||||||
|
unsigned int i;
|
||||||
|
RSPMODEL_PARAMETERS rspParams;
|
||||||
|
unsigned short result = RSPLIB_SUCCESS;
|
||||||
|
|
||||||
|
if (this->isLoaded()) return;
|
||||||
|
|
||||||
|
this->hobInstance = new T_RSPMODEL_HOB{};
|
||||||
|
auto hobInstancePtr = static_cast<T_RSPMODEL_HOB*>(this->hobInstance);
|
||||||
|
rspParams.raw = 0;
|
||||||
|
result = RSPModel_processHOBFileMemory(hobInstancePtr, this->pMemLoc, this->size, rspParams);
|
||||||
|
if (result != RSPLIB_SUCCESS) {
|
||||||
|
RSPModel_freeHOB(static_cast<T_RSPMODEL_HOB*>(this->hobInstance));
|
||||||
|
delete static_cast<T_RSPMODEL_HOB*>(this->hobInstance);
|
||||||
|
|
||||||
|
if (result == RSPLIB_ERROR_GENERIC)
|
||||||
|
throw out_of_range("HOB handler tried to process empty file.");
|
||||||
|
else
|
||||||
|
throw runtime_error("HOB handler processing failed with error: " + std::to_string(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
this->objCnt = hobInstancePtr->obj_count;
|
||||||
|
this->objectMeshList.clear();
|
||||||
|
for ( i = 0; i < this->objCnt; i++ )
|
||||||
|
this->objectMeshList[string(hobInstancePtr->objects[i].name)] = BuildObjectMesh(hobInstancePtr->objects + i);
|
||||||
|
|
||||||
|
RSPModel_freeHOB(static_cast<T_RSPMODEL_HOB*>(this->hobInstance));
|
||||||
|
|
||||||
|
// Must be called last to set loaded state
|
||||||
|
GenericFile::Load();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HOB::Dispose() {
|
||||||
|
if (!this->isLoaded()) return;
|
||||||
|
|
||||||
|
for ( const auto& [objName, objMesh] : this->objectMeshList ) {
|
||||||
|
for ( auto v : objMesh->vertices)
|
||||||
|
delete v;
|
||||||
|
|
||||||
|
for ( auto sm : objMesh->subMeshs)
|
||||||
|
delete sm;
|
||||||
|
|
||||||
|
delete objMesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->objectMeshList.clear();
|
||||||
|
delete static_cast<T_RSPMODEL_HOB*>(this->hobInstance);
|
||||||
|
|
||||||
|
// Must be called last to unset loaded state
|
||||||
|
GenericFile::Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
unsigned int HOB::getObjectCount() const {
|
||||||
|
if (this->isLoaded())
|
||||||
|
return this->objCnt;
|
||||||
|
|
||||||
|
return RSPModel_getHOBFileMemObjCount(this->pMemLoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string* HOB::getObjectName( unsigned short index ) const {
|
||||||
|
if (!this->isLoaded())
|
||||||
|
throw runtime_error("HOB handler has not been loaded prior to function calling.");
|
||||||
|
|
||||||
|
if (index >= this->objCnt)
|
||||||
|
throw out_of_range("HOB handler object index out of range!");
|
||||||
|
|
||||||
|
auto entry = objectMeshList.begin();
|
||||||
|
std::advance(entry, index);
|
||||||
|
return new string(entry->first);
|
||||||
|
}
|
||||||
|
|
||||||
|
HOB::Mesh* HOB::getMeshFromObject( unsigned short index ) const {
|
||||||
|
if (!this->isLoaded())
|
||||||
|
throw runtime_error("HOB handler has not been loaded prior to function calling.");
|
||||||
|
|
||||||
|
if (index >= this->objCnt)
|
||||||
|
throw out_of_range("HOB handler object index out of range!");
|
||||||
|
|
||||||
|
auto entry = objectMeshList.begin();
|
||||||
|
std::advance(entry, index);
|
||||||
|
return entry->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
HOB::Mesh* HOB::getMeshFromObject( string name ) const {
|
||||||
|
if (!this->isLoaded())
|
||||||
|
throw runtime_error("HOB handler has not been loaded prior to function calling.");
|
||||||
|
|
||||||
|
for ( const auto& [objName, objMesh] : this->objectMeshList )
|
||||||
|
if (objName == name) return objMesh;
|
||||||
|
|
||||||
|
throw invalid_argument("HOB handler can't find requested object name.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
HOB::Mesh* BuildObjectMesh( const T_RSPMODEL_OBJECT* hobPtr ) {
|
||||||
|
unsigned int i;
|
||||||
|
auto meshObj = new HOB::Mesh();
|
||||||
|
|
||||||
|
meshObj->indices.clear();
|
||||||
|
meshObj->vertices.clear();
|
||||||
|
meshObj->subMeshs.clear();
|
||||||
|
|
||||||
|
meshObj->transform = identity_mat<float, 4>();
|
||||||
|
for (i = 0; i < hobPtr->object_part_count; i++)
|
||||||
|
meshObj->subMeshs.push_back(FillMesh(hobPtr->object_parts + i));
|
||||||
|
|
||||||
|
return meshObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
HOB::Mesh* FillMesh( const T_RSPMODEL_OBJ_PARTS* objPtr ) {
|
||||||
|
unsigned int i;
|
||||||
|
auto meshObj = new HOB::Mesh();
|
||||||
|
|
||||||
|
meshObj->indices.clear();
|
||||||
|
meshObj->vertices.clear();
|
||||||
|
meshObj->subMeshs.clear();
|
||||||
|
|
||||||
|
//meshObj->transform = mat<float,4,4>();
|
||||||
|
meshObj->transform = identity_mat<float, 4>();
|
||||||
|
for (i = 0; i < objPtr->vertex_count; i++) {
|
||||||
|
auto v = new vec<float, 3>();
|
||||||
|
v->a[0] = static_cast<float>(-(objPtr->vertices[i].x)) / 1024.0;
|
||||||
|
v->a[1] = static_cast<float>(-(objPtr->vertices[i].y)) / 1024.0;
|
||||||
|
v->a[2] = static_cast<float>((objPtr->vertices[i].z)) / 1024.0;
|
||||||
|
meshObj->vertices.push_back(v);
|
||||||
|
}
|
||||||
|
for (i = 0; i < objPtr->face_count; i++) {
|
||||||
|
meshObj->indices.push_back(static_cast<uint16_t>(objPtr->faces[i].indices[0]));
|
||||||
|
meshObj->indices.push_back(static_cast<uint16_t>(objPtr->faces[i].indices[1]));
|
||||||
|
meshObj->indices.push_back(static_cast<uint16_t>(objPtr->faces[i].indices[2]));
|
||||||
|
|
||||||
|
if (objPtr->faces[i].flags_bits.fIsQuad) {
|
||||||
|
meshObj->indices.push_back(static_cast<uint16_t>(objPtr->faces[i].indices[2]));
|
||||||
|
meshObj->indices.push_back(static_cast<uint16_t>(objPtr->faces[i].indices[3]));
|
||||||
|
meshObj->indices.push_back(static_cast<uint16_t>(objPtr->faces[i].indices[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return meshObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
124
src/RDI.cpp
124
src/RDI.cpp
@ -1,9 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* @file RDI.cpp
|
* @file RDI.cpp
|
||||||
* @date 15/09/2022
|
* @date 22/01/2023
|
||||||
* @author JackCarterSmith
|
* @author JackCarterSmith
|
||||||
* @copyright GPL-v3.0
|
* @copyright GPL-v3.0
|
||||||
* @brief Rogue Data Interface library main entry file.
|
* @brief Rogue Data Interface library main entry abstraction file.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -15,67 +15,99 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <RSPModel.h> // Only for version getting, no processing.
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "RDat.h"
|
#include "Erso.hpp"
|
||||||
#include "DatEntry.h"
|
#include "DatFileEntry.hpp"
|
||||||
#include "RDI.h"
|
#include "Krennic.hpp"
|
||||||
|
#include <FileHandler/HOB.h>
|
||||||
|
#include "RDI.hpp"
|
||||||
|
|
||||||
|
using namespace RDI::DatFile;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal variable
|
* Internal modules instance
|
||||||
*/
|
*/
|
||||||
static RDI::RDat *hRDat = nullptr;
|
static RDI::Erso *ErsoModule = nullptr;
|
||||||
|
static RDI::Krennic *KrennicModule = nullptr;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Libs interface
|
* Libs interface
|
||||||
*/
|
*/
|
||||||
|
const std::string RDI::RDI_getLibVersion() noexcept { return PRG_VERSION; }
|
||||||
|
|
||||||
std::string RDI::getLibVersion() { return PRG_VERSION; }
|
void RDI::RDI_Init( std::string roguePath ) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::cout << std::endl << "Running RDI v" << std::string(RDI::RDI_getLibVersion()) << std::endl;
|
||||||
|
std::cout << "> RSPModelLib v" << std::string(RSPModel_getVersion()) << std::endl;
|
||||||
|
std::cout << "> RSPTerrainLib v" << "N/A" << std::endl;
|
||||||
|
std::cout << "> RSPTextureLib v" << "N/A" << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
void RDI::CreateRDatHandler( std::string roguePath ){
|
// Create new instance of Erso module
|
||||||
if (hRDat == nullptr) hRDat = new RDI::RDat(roguePath);
|
// Load and extract datas files from DATA.DAT
|
||||||
|
if (ErsoModule == nullptr) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::cout << "[RDI][DBG] Loading Erso module..." << std::endl;
|
||||||
|
#endif
|
||||||
|
ErsoModule = new RDI::Erso(roguePath);
|
||||||
|
}
|
||||||
|
|
||||||
//return hRDat;
|
// Create new instance of Krennic module
|
||||||
|
// Process datas from Erso and build new dataset to be used outside this library
|
||||||
|
if (ErsoModule != nullptr && KrennicModule == nullptr) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::cout << "[RDI][DBG] Loading Krennic module..." << std::endl;
|
||||||
|
#endif
|
||||||
|
KrennicModule = new RDI::Krennic(ErsoModule);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned char RDI::getSectionCount() {
|
|
||||||
if (hRDat == nullptr) return 0;
|
|
||||||
else return hRDat->getDataSectionCount();
|
|
||||||
|
|
||||||
|
const unsigned char RDI::RDI_getSectionCount() {
|
||||||
|
if (ErsoModule == nullptr) return 0;
|
||||||
|
else return ErsoModule->getDataSectionCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RDI::getSectionName( unsigned char id ) {
|
const std::string RDI::RDI_getSectionName( unsigned char id ) {
|
||||||
if (hRDat == nullptr) return "";
|
if (ErsoModule == nullptr) return "";
|
||||||
else return hRDat->getDataSectionName(id);
|
else return ErsoModule->getDataSectionName(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int RDI::getSectionOffset( unsigned char id ) {
|
const unsigned int RDI::RDI_getSectionOffset( unsigned char id ) {
|
||||||
if (hRDat == nullptr) return 0;
|
if (ErsoModule == nullptr) return 0;
|
||||||
else return hRDat->getDataSectionOffset(id);
|
else return ErsoModule->getDataSectionOffset(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int RDI::getDirectoryElementCount( std::string path ) {
|
const unsigned int RDI::RDI_getDirectoryElementCount( std::string path ) {
|
||||||
DirectoryEntry* result = nullptr;
|
DatFileEntryDirectory* result = nullptr;
|
||||||
|
|
||||||
if (path.empty()) return 0;
|
if (path.empty()) return 0;
|
||||||
|
|
||||||
result = dynamic_cast<DirectoryEntry *>(hRDat->getElement(boost::filesystem::path(path)));
|
result = dynamic_cast<DatFileEntryDirectory *>(ErsoModule->getElement(boost::filesystem::path(path)));
|
||||||
|
|
||||||
if (result == nullptr) return 0;
|
if (result == nullptr) return 0;
|
||||||
else return result->getSize();
|
else return result->getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> RDI::getDirectoryElements( std::string path ) {
|
const std::vector<std::string> RDI::RDI_getDirectoryElements( std::string path ) {
|
||||||
DirectoryEntry* de = nullptr;
|
DatFileEntryDirectory* de = nullptr;
|
||||||
std::vector<std::string> elementsNameArray;
|
std::vector<std::string> elementsNameArray;
|
||||||
elementsNameArray.clear();
|
elementsNameArray.clear();
|
||||||
|
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
de = dynamic_cast<DirectoryEntry *>(hRDat->getElement(boost::filesystem::path(path)));
|
de = dynamic_cast<DatFileEntryDirectory *>(ErsoModule->getElement(boost::filesystem::path(path)));
|
||||||
|
|
||||||
if (de != nullptr && de->isDirectory()) {
|
if (de != nullptr && de->isDirectory()) {
|
||||||
for (DatEntry* de2 : de->getFiles())
|
for (DatFileEntry* de2 : de->getFiles())
|
||||||
elementsNameArray.push_back(de2->getName());
|
elementsNameArray.push_back(de2->getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,18 +115,46 @@ std::vector<std::string> RDI::getDirectoryElements( std::string path ) {
|
|||||||
return elementsNameArray;
|
return elementsNameArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RDI::isElementDirectory( std::string path ) {
|
const bool RDI::RDI_isElementDirectory( std::string path ) {
|
||||||
DatEntry* result = nullptr;
|
DatFileEntry* result = nullptr;
|
||||||
|
|
||||||
if (path.empty()) return false;
|
if (path.empty()) return false;
|
||||||
|
|
||||||
result = hRDat->getElement(boost::filesystem::path(path));
|
result = ErsoModule->getElement(boost::filesystem::path(path));
|
||||||
|
|
||||||
if (result == nullptr) return false;
|
if (result == nullptr) return false;
|
||||||
else return (result->isDirectory() || result->isRootDirectory());
|
else return (result->isDirectory() || result->isRootDirectory());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RDI::DestroyRDatHandler(){
|
/* -------------------------------------------------------------------------- */
|
||||||
if (hRDat) delete hRDat;
|
const std::vector<std::string> RDI::RDI_getLevelsName( void ) {
|
||||||
|
return KrennicModule->getLevelsList();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string> RDI::RDI_getModelsName( void ) {
|
||||||
|
return KrennicModule->getModelsList();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string> RDI::RDI_getTexturesName( void ) {
|
||||||
|
return KrennicModule->getTexturesList();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string> RDI::RDI_getMusicsName( void ) {
|
||||||
|
return KrennicModule->getMusicsList();
|
||||||
|
}
|
||||||
|
|
||||||
|
RDI::HOB* RDI::RDI_getModel( std::string modelName ) {
|
||||||
|
try {
|
||||||
|
return KrennicModule->getModel(modelName);
|
||||||
|
}
|
||||||
|
catch (std::invalid_argument const &ex) { // Can't find model, incorrect name?
|
||||||
|
throw std::invalid_argument(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
void RDI::RDI_CleanUp(){
|
||||||
|
if (KrennicModule) delete KrennicModule;
|
||||||
|
if (ErsoModule) delete ErsoModule;
|
||||||
}
|
}
|
||||||
|
236
src/RDat.cpp
236
src/RDat.cpp
@ -1,236 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file RDat.cpp
|
|
||||||
* @date 20/09/2022
|
|
||||||
* @author JackCarterSmith
|
|
||||||
* @copyright GPL-v3.0
|
|
||||||
* @brief Rogue Dat file class interface.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <vector>
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
#include <RSPModel.h>
|
|
||||||
#include <RSPTerrain.h>
|
|
||||||
#include <RSPTexture.h>
|
|
||||||
#include <RDI_Datatypes.h>
|
|
||||||
#include "DatEntry.h"
|
|
||||||
#include "data_struct.h"
|
|
||||||
#include "RDat.h"
|
|
||||||
|
|
||||||
|
|
||||||
using std::string;
|
|
||||||
using std::ios;
|
|
||||||
using std::vector;
|
|
||||||
using boost::filesystem::path;
|
|
||||||
using boost::filesystem::file_size;
|
|
||||||
|
|
||||||
|
|
||||||
namespace RDI {
|
|
||||||
|
|
||||||
RDat::RDat( string fPath ) {
|
|
||||||
RDI_RESULT errCode = RDI_OK;
|
|
||||||
|
|
||||||
this->workingDir = fPath;
|
|
||||||
|
|
||||||
// Process header file and dump data file in memory.
|
|
||||||
errCode = DumpLegacyFiles();
|
|
||||||
if (errCode == RDI_ERROR_FILESYSTEM) {
|
|
||||||
std::cout << "Data files (DATA.DAT/DATA.HDR) not found! Interrupt." << std::endl;
|
|
||||||
return;
|
|
||||||
} else if (errCode == RDI_ERROR_MEMORY) {
|
|
||||||
std::cout << "Memory allocation or file access failed! Interrupt." << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process data file tree and filter file subtype into list.
|
|
||||||
ProcessFilesTree();
|
|
||||||
}
|
|
||||||
|
|
||||||
RDat::~RDat() {
|
|
||||||
for ( DirectoryEntry* de : *pFTRoot )
|
|
||||||
delete de;
|
|
||||||
delete pFTRoot;
|
|
||||||
free(rDatPtr);
|
|
||||||
delete pDatSection;
|
|
||||||
}
|
|
||||||
|
|
||||||
string RDat::getDataSectionName( unsigned char id ) { return pDatSection->at(id).name; }
|
|
||||||
unsigned int RDat::getDataSectionOffset( unsigned char id ) { return pDatSection->at(id).offset; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to search for legacy DATA.DAT/HDR and dump it in memory.
|
|
||||||
*
|
|
||||||
* @return Error status.
|
|
||||||
*/
|
|
||||||
RDI_RESULT RDat::DumpLegacyFiles() {
|
|
||||||
unsigned int i;
|
|
||||||
path fp(workingDir);
|
|
||||||
MEMFILE pTmpFile;
|
|
||||||
|
|
||||||
// If input as a directory, assume it's contain DATA.DAT/HDR.
|
|
||||||
if (boost::filesystem::is_directory(fp)) fp.append("DATA.HDR");
|
|
||||||
|
|
||||||
// If file specified in input is the "datas" file, process the header (HDR) before.
|
|
||||||
if (fp.extension() == ".DAT") fp.replace_extension(".HDR");
|
|
||||||
|
|
||||||
// Open and parse data header file.
|
|
||||||
//if (boost::filesystem::exists(fp)) return RDI_ERROR_FILESYSTEM;
|
|
||||||
pTmpFile = MallocFile(fp);
|
|
||||||
if (!pTmpFile) return RDI_ERROR_MEMORY;
|
|
||||||
|
|
||||||
cDatSection = file_size(fp) / sizeof(T_HDR_ENTRY);
|
|
||||||
pDatSection = new vector<struct dataSection>(cDatSection);
|
|
||||||
for ( i = 0; i < pDatSection->size(); i++ ) {
|
|
||||||
// Store header infos into structure to make easier access later.
|
|
||||||
pDatSection->at(i).name.append(((T_HDR_ENTRY*)(pTmpFile + i * sizeof(T_HDR_ENTRY)))->section_name);
|
|
||||||
pDatSection->at(i).offset = ((T_HDR_ENTRY*)(pTmpFile + i * sizeof(T_HDR_ENTRY)))->section_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(pTmpFile);
|
|
||||||
|
|
||||||
// Dump data file and store it's pointer into class member.
|
|
||||||
fp.replace_extension(".DAT");
|
|
||||||
//if (boost::filesystem::exists(fp)) return RDI_ERROR_FILESYSTEM;
|
|
||||||
rDatPtr = MallocFile(fp);
|
|
||||||
if (!rDatPtr) return RDI_ERROR_MEMORY;
|
|
||||||
|
|
||||||
return RDI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dump file into to newly allocated memory.
|
|
||||||
* @param filePath File path.
|
|
||||||
*
|
|
||||||
* @return Start memory pointer of the file.
|
|
||||||
*/
|
|
||||||
MEMFILE RDat::MallocFile( path filePath ) {
|
|
||||||
const unsigned int size = file_size(filePath);
|
|
||||||
std::fstream rdf;
|
|
||||||
MEMFILE fPtr = NULL;
|
|
||||||
|
|
||||||
rdf.open(filePath.string(), ios::in | ios::binary);
|
|
||||||
if (rdf.is_open()) {
|
|
||||||
fPtr = (MEMFILE)malloc(size);
|
|
||||||
rdf.read(fPtr, size);
|
|
||||||
rdf.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return fPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to process files content for further use in this library.
|
|
||||||
*
|
|
||||||
* @return Error status.
|
|
||||||
*/
|
|
||||||
RDI_RESULT RDat::ProcessFilesTree() {
|
|
||||||
unsigned int curEntriesCount = 0, i;
|
|
||||||
DirectoryEntry* curDir = nullptr;
|
|
||||||
MEMFILE pFileDescriptors = nullptr;
|
|
||||||
|
|
||||||
// Create new root files tree. One per data section.
|
|
||||||
pFTRoot = new std::vector<DirectoryEntry*>;
|
|
||||||
pFTRoot->clear();
|
|
||||||
for ( i = 0; i < cDatSection; i++ ) {
|
|
||||||
curDir = new DirectoryEntry(pDatSection->at(i).name);
|
|
||||||
pFTRoot->push_back(curDir);
|
|
||||||
|
|
||||||
// Recalculate files descriptor offset for current section.
|
|
||||||
pFileDescriptors = rDatPtr + pDatSection->at(i).offset +
|
|
||||||
((T_DAT_SECTION*)(rDatPtr + pDatSection->at(i).offset))->file_headers_offset;
|
|
||||||
curEntriesCount = (((T_DAT_SECTION*)(rDatPtr + pDatSection->at(i).offset))->file_headers_size) / 32;
|
|
||||||
|
|
||||||
// Process arborescente in recursive method.
|
|
||||||
ProcessDirectoryContents(curDir, pFileDescriptors, curEntriesCount, rDatPtr + pDatSection->at(i).offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
return RDI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
RDI_RESULT RDat::ProcessDirectoryContents( DirectoryEntry* pCurDir, MEMFILE pDesc, const unsigned int count, MEMFILE pSectionStart ) {
|
|
||||||
unsigned int i, newDRECnt;
|
|
||||||
DAT_FILE_FLAGS curEntryFlags = {0};
|
|
||||||
|
|
||||||
FileEntry* newFile = nullptr;
|
|
||||||
DirectoryEntry* newDir = nullptr;
|
|
||||||
std::string tmpStr;
|
|
||||||
|
|
||||||
if ( count == 0) return RDI_ERROR_PROCESS;
|
|
||||||
|
|
||||||
for ( i = 0; i < count; i++ ) {
|
|
||||||
curEntryFlags.raw = ((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->flags;
|
|
||||||
|
|
||||||
tmpStr.clear();
|
|
||||||
tmpStr.append(((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->name);
|
|
||||||
|
|
||||||
// Test for file or directory
|
|
||||||
if (!curEntryFlags.isDirectory) {
|
|
||||||
newFile = new FileEntry(tmpStr, curEntryFlags,
|
|
||||||
((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->datas_size,
|
|
||||||
pSectionStart + ((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->datas_offset);
|
|
||||||
pCurDir->AddEntry(newFile);
|
|
||||||
} else {
|
|
||||||
newDir = new DirectoryEntry(tmpStr, curEntryFlags);
|
|
||||||
pCurDir->AddEntry(newDir);
|
|
||||||
|
|
||||||
// Keep entries count in new directory to jump over after processing it.
|
|
||||||
newDRECnt = (((T_FILE_HEADER*)(pDesc + i * sizeof(T_FILE_HEADER)))->dir_entries_size - sizeof(T_FILE_HEADER)) / sizeof(T_FILE_HEADER);
|
|
||||||
ProcessDirectoryContents(newDir, pDesc + (i + 1) * sizeof(T_FILE_HEADER), newDRECnt, pSectionStart);
|
|
||||||
if (newDRECnt <= count) i += newDRECnt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return RDI_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
DatEntry *RDat::getElement( boost::filesystem::path virtualDirPath ) {
|
|
||||||
bool skip = false;
|
|
||||||
boost::filesystem::path newPath;
|
|
||||||
|
|
||||||
for ( DatEntry* de : *pFTRoot ) {
|
|
||||||
if (virtualDirPath.size() == 1 || virtualDirPath.begin() == --virtualDirPath.end()) {
|
|
||||||
if (de->getName() == virtualDirPath.filename().string())
|
|
||||||
return de;
|
|
||||||
} else {
|
|
||||||
if (de->getName() == virtualDirPath.begin()->string()) {
|
|
||||||
for (auto& sp : virtualDirPath) {
|
|
||||||
if (skip)
|
|
||||||
newPath.append(sp);
|
|
||||||
skip = true;
|
|
||||||
}
|
|
||||||
return SearchSectionForEntry(dynamic_cast<DirectoryEntry *>(de), newPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
DatEntry *RDat::SearchSectionForEntry( DirectoryEntry *curDir, boost::filesystem::path virtualDirPath ) {
|
|
||||||
bool skip = false;
|
|
||||||
boost::filesystem::path newPath;
|
|
||||||
|
|
||||||
for ( DatEntry* e : curDir->getFiles() ) {
|
|
||||||
if (virtualDirPath.size() == 1 || virtualDirPath.begin() == --virtualDirPath.end()) {
|
|
||||||
if (e->getName() == virtualDirPath.filename().string())
|
|
||||||
return e;
|
|
||||||
} else {
|
|
||||||
if (e->isDirectory() && (e->getName() == virtualDirPath.begin()->string())) {
|
|
||||||
for (auto& sp : virtualDirPath) {
|
|
||||||
if (skip)
|
|
||||||
newPath.append(sp);
|
|
||||||
skip = true;
|
|
||||||
}
|
|
||||||
//TODO: add safety when trying to access inside a file
|
|
||||||
return SearchSectionForEntry(dynamic_cast<DirectoryEntry *>(e), newPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
71
src/RDat.h
71
src/RDat.h
@ -1,71 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file RDat.h
|
|
||||||
* @date 15/09/2022
|
|
||||||
* @author JackCarterSmith
|
|
||||||
* @copyright GPL-v3.0
|
|
||||||
* @brief Rogue Dat file class interface.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
#include <vector>
|
|
||||||
#include "DatEntry.h"
|
|
||||||
#include "RDI_Datatypes.h"
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef RDAT_H_
|
|
||||||
#define RDAT_H_
|
|
||||||
|
|
||||||
namespace RDI {
|
|
||||||
|
|
||||||
struct dataSection {
|
|
||||||
std::string name = "";
|
|
||||||
unsigned int offset = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RDat final {
|
|
||||||
public:
|
|
||||||
RDat( std::string fPath );
|
|
||||||
~RDat();
|
|
||||||
|
|
||||||
MEMFILE getRDat() {
|
|
||||||
return rDatPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getWorkingDirectory() { return workingDir; }
|
|
||||||
void setWorkingDirectory( std::string newPath ) { workingDir = newPath; }
|
|
||||||
|
|
||||||
unsigned char getDataSectionCount() { return cDatSection; }
|
|
||||||
std::string getDataSectionName( unsigned char id );
|
|
||||||
unsigned int getDataSectionOffset( unsigned char id );
|
|
||||||
|
|
||||||
DatEntry *getElement( boost::filesystem::path virtualDirPath );
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string workingDir = ".";
|
|
||||||
|
|
||||||
unsigned char cDatSection = 0;
|
|
||||||
std::vector<struct dataSection> *pDatSection = nullptr;
|
|
||||||
MEMFILE rDatPtr = nullptr;
|
|
||||||
|
|
||||||
std::vector<DirectoryEntry*> *pFTRoot = nullptr;
|
|
||||||
|
|
||||||
/* File processing methods */
|
|
||||||
RDI_RESULT DumpLegacyFiles();
|
|
||||||
MEMFILE MallocFile( boost::filesystem::path filePath );
|
|
||||||
RDI_RESULT ProcessFilesTree();
|
|
||||||
RDI_RESULT ProcessDirectoryContents(
|
|
||||||
DirectoryEntry* pCurDir,
|
|
||||||
MEMFILE pDesc,
|
|
||||||
const unsigned int count,
|
|
||||||
MEMFILE pSectionStart
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Tree manipulation/parse methods */
|
|
||||||
DatEntry *SearchSectionForEntry( DirectoryEntry *curDir, boost::filesystem::path virtualDirPath);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} /* namespace RDI */
|
|
||||||
|
|
||||||
#endif /* RDAT_H_ */
|
|
@ -1,23 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file HMT.cpp
|
|
||||||
* @date 15/09/2022
|
|
||||||
* @author JackCarterSmith
|
|
||||||
* @copyright GPL-v3.0
|
|
||||||
* @brief HMT file object class.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "HMT.h"
|
|
||||||
|
|
||||||
namespace RDI {
|
|
||||||
|
|
||||||
HMT::HMT() {
|
|
||||||
// TODO Auto-generated constructor stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
HMT::~HMT() {
|
|
||||||
// TODO Auto-generated destructor stub
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace RDI */
|
|
16
tools/ErsoDebug.cpp
Normal file
16
tools/ErsoDebug.cpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* @file ErsoDebug.cpp
|
||||||
|
* @date 24/09/2022
|
||||||
|
* @author JackCarterSmith
|
||||||
|
* @copyright GPL-v3.0
|
||||||
|
* @brief Debug app to test Erso module of RDI library.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <RDI.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
int main( int argc, char *argv[] ) {
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
16
tools/KrennicDebug.cpp
Normal file
16
tools/KrennicDebug.cpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* @file KrennicDebug.cpp
|
||||||
|
* @date 24/09/2022
|
||||||
|
* @author JackCarterSmith
|
||||||
|
* @copyright GPL-v3.0
|
||||||
|
* @brief Debug app to test Krennic module of RDI library.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <RDI.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
int main( int argc, char *argv[] ) {
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
308
tools/RDIDebug.cpp
Normal file
308
tools/RDIDebug.cpp
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
/**
|
||||||
|
* @file RDIDebug.cpp
|
||||||
|
* @date 01/02/2023
|
||||||
|
* @author JackCarterSmith
|
||||||
|
* @copyright GPL-v3.0
|
||||||
|
* @brief Debug app to test functions of RDI library.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if __cplusplus < 201703L
|
||||||
|
#error "This code run on C++17 or upper."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
#ifdef USE_MULTITHREADING
|
||||||
|
#include <deque>
|
||||||
|
#include <thread>
|
||||||
|
#endif
|
||||||
|
#include <filesystem>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <RDI.hpp>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace boost::filesystem;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
static vector<RDI::HOB*> modelCollection;
|
||||||
|
|
||||||
|
static void PrintVirtualDirectoryContents( path p, bool unicode, string outPrefix = "" ) {
|
||||||
|
auto curDirElementsName = RDI::RDI_getDirectoryElements(p.string());
|
||||||
|
auto newPath = path(p);
|
||||||
|
auto newOutPrefix = string(outPrefix);
|
||||||
|
|
||||||
|
for ( string eName : curDirElementsName ) {
|
||||||
|
newPath.clear();
|
||||||
|
newPath.concat(p);
|
||||||
|
newOutPrefix.clear();
|
||||||
|
newOutPrefix.append(outPrefix);
|
||||||
|
|
||||||
|
newPath.append(eName);
|
||||||
|
if (RDI::RDI_isElementDirectory(newPath.string())) {
|
||||||
|
if (unicode) {
|
||||||
|
if (*--curDirElementsName.end() == eName) {
|
||||||
|
cout << outPrefix << "\u2514 " << eName << endl;
|
||||||
|
newOutPrefix.append(" ");
|
||||||
|
} else {
|
||||||
|
cout << outPrefix << "\u251C " << eName << endl;
|
||||||
|
newOutPrefix.append("\u2502 ");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (*--curDirElementsName.end() == eName) {
|
||||||
|
cout << outPrefix << "\\ " << eName << endl;
|
||||||
|
newOutPrefix.append(" ");
|
||||||
|
} else {
|
||||||
|
cout << outPrefix << "\\ " << eName << endl;
|
||||||
|
newOutPrefix.append("| ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrintVirtualDirectoryContents(newPath, unicode, newOutPrefix);
|
||||||
|
} else {
|
||||||
|
if (unicode) {
|
||||||
|
if (*--curDirElementsName.end() == eName)
|
||||||
|
cout << newOutPrefix << "\u2514 " << eName << endl;
|
||||||
|
else
|
||||||
|
cout << newOutPrefix << "\u251C " << eName << endl;
|
||||||
|
} else {
|
||||||
|
cout << newOutPrefix << "+ " << eName << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PrintModel( const RDI::HOB::Mesh* mesh, string prefix = "" ) {
|
||||||
|
if (mesh == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string newPrefix = string(prefix);
|
||||||
|
|
||||||
|
for ( auto submesh : mesh->subMeshs ) {
|
||||||
|
for ( auto v : submesh->vertices )
|
||||||
|
cout << "[ " << v->a[0] << "; " << v->a[1] << "; " << v->a[2] << " ]" << endl;
|
||||||
|
|
||||||
|
newPrefix.append(" ");
|
||||||
|
PrintModel(submesh, newPrefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GenerateModelOBJ( const RDI::HOB::Mesh* mesh, const string outFolder, const string* name ) {
|
||||||
|
if (mesh == nullptr || name == nullptr || outFolder.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned long i, i_offset = 0;
|
||||||
|
|
||||||
|
ofstream objFile(".\\objOut\\" + outFolder + "\\" + (*name) + ".obj");
|
||||||
|
|
||||||
|
for ( auto submesh : mesh->subMeshs ) {
|
||||||
|
for ( auto v : submesh->vertices ) {
|
||||||
|
objFile << "v " << v->a[0] << " " << v->a[1] << " " << v->a[2] << endl;
|
||||||
|
}
|
||||||
|
objFile << endl;
|
||||||
|
for ( i = 0; i < submesh->indices.size(); i += 3 ) {
|
||||||
|
objFile << "f " << submesh->indices[i]+i_offset+1;
|
||||||
|
objFile << " " << submesh->indices[i+1]+i_offset+1;
|
||||||
|
objFile << " " << submesh->indices[i+2]+i_offset+1 << endl;
|
||||||
|
}
|
||||||
|
objFile << endl;
|
||||||
|
|
||||||
|
i_offset += submesh->vertices.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
objFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_MULTITHREADING
|
||||||
|
static void GenerateModelOBJThreaded() {
|
||||||
|
unsigned int i, successCnt;
|
||||||
|
deque<thread*> process;
|
||||||
|
const unsigned int maxThreads = thread::hardware_concurrency();
|
||||||
|
|
||||||
|
if (modelCollection.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
CreateDirectory(".\\objOut", NULL);
|
||||||
|
#else
|
||||||
|
mkdir("./objOut");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for ( RDI::HOB* hobFile : modelCollection ) {
|
||||||
|
successCnt = 0;
|
||||||
|
cout << " Processing " << hobFile->getFullPath() << "..." << endl;
|
||||||
|
if (hobFile->isLoaded() && (hobFile->getObjectCount() > 0)) {
|
||||||
|
|
||||||
|
string parentPath = path(hobFile->getFullPath()).parent_path().filename().string();
|
||||||
|
replace(parentPath.begin(), parentPath.end(), '/', '\\');
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
CreateDirectory((".\\objOut\\" + parentPath).c_str(), NULL);
|
||||||
|
#else
|
||||||
|
mkdir(("./objOut/" + parentPath).c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Create initial threads for files processing
|
||||||
|
for ( i = 0; i < maxThreads; i++ ) {
|
||||||
|
if (i >= hobFile->getObjectCount())
|
||||||
|
break;
|
||||||
|
|
||||||
|
process.push_back(new thread(
|
||||||
|
GenerateModelOBJ,
|
||||||
|
hobFile->getMeshFromObject(i),
|
||||||
|
parentPath,
|
||||||
|
hobFile->getObjectName(i)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop until all threads finished and no more file should be processed
|
||||||
|
while (true) {
|
||||||
|
process.front()->join();
|
||||||
|
//delete process.front();
|
||||||
|
process.pop_front();
|
||||||
|
++successCnt;
|
||||||
|
|
||||||
|
if (successCnt >= hobFile->getObjectCount())
|
||||||
|
break;
|
||||||
|
|
||||||
|
process.push_back(new thread(
|
||||||
|
GenerateModelOBJ,
|
||||||
|
hobFile->getMeshFromObject(successCnt),
|
||||||
|
parentPath,
|
||||||
|
hobFile->getObjectName(successCnt)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void ProcessModels() {
|
||||||
|
unsigned int i,invalid = 0;
|
||||||
|
|
||||||
|
// Build models collection
|
||||||
|
modelCollection.clear();
|
||||||
|
for ( string mdname : RDI::RDI_getModelsName() ) {
|
||||||
|
auto filePath = path(mdname);
|
||||||
|
modelCollection.push_back(RDI::RDI_getModel(filePath.string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load models using low-level library
|
||||||
|
for ( RDI::HOB* hobFile : modelCollection ) {
|
||||||
|
try {
|
||||||
|
hobFile->Load();
|
||||||
|
for ( i = 0; i < hobFile->getObjectCount(); i++ ) {
|
||||||
|
if (hobFile->getMeshFromObject(i)->subMeshs.empty()) {
|
||||||
|
cout << "Memory allocation failure!" << endl;
|
||||||
|
invalid++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (out_of_range const &ex) {
|
||||||
|
//cout << "Empty object" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cout << "Number of invalid memory allocation: " << invalid << endl;
|
||||||
|
|
||||||
|
// Launch threaded OBJ file building
|
||||||
|
//GenerateModelOBJThreaded();
|
||||||
|
//PrintModel(meshCollection.back());
|
||||||
|
|
||||||
|
for ( RDI::HOB* hobFile : modelCollection ) {
|
||||||
|
if (hobFile->isLoaded() && hobFile->getObjectCount()) {
|
||||||
|
string parentPath = path(hobFile->getFullPath()).string();
|
||||||
|
replace(parentPath.begin(), parentPath.end(), '/', '\\');
|
||||||
|
|
||||||
|
filesystem::create_directories(".\\objOut\\" + hobFile->getFullPath());
|
||||||
|
|
||||||
|
for ( i = 0; i < hobFile->getObjectCount(); i++ ) {
|
||||||
|
cout << hobFile->getFullPath() << "/" << *(hobFile->getObjectName(i)) << "...";
|
||||||
|
GenerateModelOBJ(hobFile->getMeshFromObject(i), parentPath, hobFile->getObjectName(i));
|
||||||
|
cout << " OK" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unload models
|
||||||
|
for ( RDI::HOB* hobFile : modelCollection ) {
|
||||||
|
hobFile->Dispose();
|
||||||
|
modelCollection.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main( int argc, char *argv[] ) {
|
||||||
|
unsigned int i;
|
||||||
|
path pathBuilder;
|
||||||
|
bool use_unicode = true;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
SetConsoleOutputCP(CP_UTF8);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cout << "RDIDebug tool - using RDI lib v" << RDI::RDI_getLibVersion() << endl << endl;
|
||||||
|
|
||||||
|
// Initialize RDI (Erso and Krennic module) with folder provided in program
|
||||||
|
// argument, or the current directory by default
|
||||||
|
if ( argc > 2 ) {
|
||||||
|
use_unicode = atoi(argv[2]);
|
||||||
|
RDI::RDI_Init(argv[1]);
|
||||||
|
} else if (argc > 1) {
|
||||||
|
RDI::RDI_Init(argv[1]);
|
||||||
|
} else {
|
||||||
|
RDI::RDI_Init(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print details about legacy DATA.DAT file
|
||||||
|
//cout << "> Section found: " << RDI::RDI_getSectionCount() << endl;
|
||||||
|
printf("> Section found: %d\n", RDI::RDI_getSectionCount());
|
||||||
|
for ( i = 0; i < RDI::RDI_getSectionCount(); i++ ) {
|
||||||
|
cout << " -Section " << i << " name: " << RDI::RDI_getSectionName(i) << endl;
|
||||||
|
cout << " -Section " << i << " offset: 0x" << hex << uppercase << RDI::RDI_getSectionOffset(i) << dec << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print DATA.DAT tree view with unicode "style"
|
||||||
|
cout << endl << "DATA.DAT files tree view:" << endl;
|
||||||
|
for ( i = 0; i < RDI::RDI_getSectionCount(); i++ ) {
|
||||||
|
cout << RDI::RDI_getSectionName(i) << ":" << endl;
|
||||||
|
|
||||||
|
pathBuilder.clear();
|
||||||
|
pathBuilder.concat(RDI::RDI_getSectionName(i));
|
||||||
|
|
||||||
|
PrintVirtualDirectoryContents(pathBuilder, use_unicode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print game elements Krennic module found
|
||||||
|
cout << endl << "Legacy files processing result:";
|
||||||
|
cout << endl << "> Levels found: " << RDI::RDI_getLevelsName().size() << endl;
|
||||||
|
for ( std::string lname : RDI::RDI_getLevelsName() ) {
|
||||||
|
cout << " " << lname << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << endl << "> Models found: " << RDI::RDI_getModelsName().size() << endl;
|
||||||
|
auto t_start = chrono::high_resolution_clock::now();
|
||||||
|
ProcessModels();
|
||||||
|
auto t_end = chrono::high_resolution_clock::now();
|
||||||
|
cout << "Models processing in " << chrono::duration_cast<chrono::seconds>(t_end - t_start).count() << "s" << endl;
|
||||||
|
|
||||||
|
cout << endl << "> Textures found: " << RDI::RDI_getTexturesName().size() << endl;
|
||||||
|
for ( std::string txname : RDI::RDI_getTexturesName() ) {
|
||||||
|
cout << " " << txname << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << endl << "> Musics found: " << RDI::RDI_getMusicsName().size() << endl;
|
||||||
|
for ( std::string mname : RDI::RDI_getMusicsName() ) {
|
||||||
|
cout << " " << mname << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release RDI library
|
||||||
|
RDI::RDI_CleanUp();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,75 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file RDIdebug.cpp
|
|
||||||
* @date 17/09/2022
|
|
||||||
* @author JackCarterSmith
|
|
||||||
* @copyright GPL-v3.0
|
|
||||||
* @brief Debug app to test functions of RDI library.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
#include <RDI.h>
|
|
||||||
|
|
||||||
|
|
||||||
void PrintVirtualDirectoryContents( boost::filesystem::path, std::string );
|
|
||||||
|
|
||||||
int main( int argc, char *argv[] ) {
|
|
||||||
unsigned int i;
|
|
||||||
boost::filesystem::path pathBuilder;
|
|
||||||
std::string prefix;
|
|
||||||
|
|
||||||
printf("Using RDI lib v%s\n\n", RDI::getLibVersion().c_str());
|
|
||||||
//cout << "Using RDI lib v" << RDI::getLibVersion() << endl << endl;
|
|
||||||
|
|
||||||
if ( argc > 1 )
|
|
||||||
RDI::CreateRDatHandler(argv[1]);
|
|
||||||
else
|
|
||||||
RDI::CreateRDatHandler(".");
|
|
||||||
|
|
||||||
printf("> Section found: %d\n", RDI::getSectionCount());
|
|
||||||
for ( i = 0; i < RDI::getSectionCount(); i++ ) {
|
|
||||||
printf(" -Section %d name: %s\n", i, RDI::getSectionName(i).c_str());
|
|
||||||
printf(" -Section %d offset: 0x%X\n", i, RDI::getSectionOffset(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
//prefix.append("\t");
|
|
||||||
prefix.append(" ");
|
|
||||||
printf("\nSections files root:\n");
|
|
||||||
for ( i = 0; i < RDI::getSectionCount(); i++ ) {
|
|
||||||
printf("%s:\n", RDI::getSectionName(i).c_str()); // Print root trees
|
|
||||||
|
|
||||||
pathBuilder.clear();
|
|
||||||
pathBuilder.concat(RDI::getSectionName(i));
|
|
||||||
|
|
||||||
PrintVirtualDirectoryContents(pathBuilder, prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
RDI::DestroyRDatHandler();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrintVirtualDirectoryContents( boost::filesystem::path path, std::string outPrefix ) {
|
|
||||||
auto curDirElementsName = RDI::getDirectoryElements(path.string());
|
|
||||||
auto newPath = boost::filesystem::path(path);
|
|
||||||
auto newOutPrefix = std::string(outPrefix);
|
|
||||||
|
|
||||||
for ( std::string eName : curDirElementsName ) {
|
|
||||||
newPath.clear();
|
|
||||||
newPath.concat(path);
|
|
||||||
newOutPrefix.clear();
|
|
||||||
newOutPrefix.append(outPrefix);
|
|
||||||
|
|
||||||
newPath.append(eName);
|
|
||||||
if (RDI::isElementDirectory(newPath.string())) {
|
|
||||||
printf("%s%s:\n", outPrefix.c_str(), eName.c_str());
|
|
||||||
//newOutPrefix.append("\t");
|
|
||||||
newOutPrefix.append(" ");
|
|
||||||
PrintVirtualDirectoryContents(newPath, newOutPrefix);
|
|
||||||
} else {
|
|
||||||
printf("%s%s\n", newOutPrefix.c_str(), eName.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user