HOB file management

HOB file handler prototype

Mesh building should be moved to RSPModel lib

Tree rendering unicode chars fix


Updated version detection


HOB file handler




Debug HOB handler

Pointer probably deallocated, need to check it

Fix HOB loader and disposer


Using HOB instance instead of static methods


Review DLL support for MSVC build


Vertices values calculation fix


Added export obj method to debug tool


Missed levels name separation


Cleaned model processing

Multithreading branch reported to later
This commit is contained in:
JackCarterSmith 2023-02-02 19:45:59 +01:00
parent 4a0b0df410
commit 05b3c1e88a
Signed by: JackCarterSmith
GPG Key ID: 832E52F4E23F8F24
14 changed files with 779 additions and 139 deletions

View File

@ -7,8 +7,8 @@
# CMake requirement and general configuration
cmake_minimum_required(VERSION 3.12)
cmake_policy(VERSION 3.12)
cmake_minimum_required(VERSION 3.15)
cmake_policy(VERSION 3.15)
set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
if(DEFINED ENV{MS_COMPATIBLE})
set(CMAKE_GNUtoMS ON) # Enable compatibility level to exported libraries
@ -27,10 +27,10 @@ endif()
set(RDI_LIB_NAME RDI)
if(NOT MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++17 -static-libgcc -static-libstdc++")
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 /std:c++17")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Wall")
endif()
set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
@ -43,13 +43,13 @@ option(RDI_STATIC "Build static lib" ON)
option(BUILD_TOOLS "Build lib tools" ON)
# Import needed packages and references their include path
find_package(RSPModel 2.2 REQUIRED)
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.80.0 EXACT REQUIRED)
find_package(Boost 1.81.0 REQUIRED)
include_directories(${Boost_INCLUDE_DIR})
add_definitions(-DBOOST_ALL_NO_LIB)
@ -80,14 +80,22 @@ endif()
# Declare the shared library instance
if(RDI_SHARED)
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 MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
set_target_properties(rdi-lib PROPERTIES VERSION 1.0.0)
target_include_directories(rdi-lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
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
${RSPModel_LIBRARIES}
${RSPTerrain_LIBRARIES}
@ -113,11 +121,20 @@ endif()
# Declare the static library instance
if(RDI_STATIC)
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 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)
# 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
${RSPModel_LIBRARIES}
${RSPTerrain_LIBRARIES}
@ -158,17 +175,20 @@ if(BUILD_TOOLS)
#add_executable(rdi-debug-tools ${RDI_TOOLS_SOURCES})
add_executable(rdi-debug-tools ./tools/RDIDebug.cpp)
set_property(TARGET rdi-debug-tools PROPERTY C_STANDARD 90)
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")
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 90)
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 90)
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)
@ -180,6 +200,7 @@ if(BUILD_TOOLS)
set_target_properties(krennic-debug-tools PROPERTIES IMPORT_PREFIX "lib")
endif()
# Static libgcc and libstdc++ already linked in library
if(RDI_SHARED)
target_link_libraries(rdi-debug-tools PRIVATE rdi-lib ${Boost_LIBRARIES})
target_link_libraries(erso-debug-tools PRIVATE rdi-lib)

View File

@ -1,8 +1,8 @@
[requires]
rspmodellib/2.2.0
rspmodellib/2.3.0
rspterrainlib/2.0.4
rsptexturelib/2.1.0
boost/1.80.0
boost/1.81.0
[generators]
cmake

View File

@ -1,6 +1,6 @@
/**
* @file GenericFile.h
* @date 23/09/2022
* @date 01/02/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Generic file object class.
@ -22,15 +22,38 @@ namespace DatFile {
class GenericFile {
public:
GenericFile( DatFile::DatFileEntryFile &hDat );
// 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, fileExtension;
std::string fileName, fullFilePath, fileExtension;
MEMFILE pMemLoc = nullptr;
private:
bool loaded = false;
};
}

View File

@ -17,7 +17,7 @@ namespace RDI {
class HMT : public GenericFile {
public:
HMT( DatFile::DatFileEntryFile &hDat );
HMT( DatFile::DatFileEntryFile* hDat );
virtual ~HMT();
};

120
include/FileHandler/HOB.h Normal file
View 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_ */

View File

@ -1,6 +1,6 @@
/**
* @file RDI.hpp
* @date 24/09/2022
* @date 22/01/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Rogue Data Interface library main entry file.
@ -10,6 +10,7 @@
#include <string>
#include <vector>
#include "RDI_Datatypes.h"
#include "FileHandler/HOB.h"
#ifndef RDI_HPP_
@ -48,7 +49,7 @@ namespace RDI {
* @brief Get the current library version.
* @return String of the version.
*/
RDI_EXTERN std::string RDI_getLibVersion( void );
RDI_EXTERN const std::string RDI_getLibVersion( void ) noexcept;
/**
* @brief Allocate memory and create default structure to access datas.
@ -58,20 +59,26 @@ namespace RDI {
*/
RDI_EXTERN void RDI_Init( std::string roguePath );
/* -------------------------------------------------------------------------- */
/* Erso specific methods */
RDI_EXTERN unsigned char RDI_getSectionCount( void );
RDI_EXTERN std::string RDI_getSectionName( unsigned char id );
RDI_EXTERN unsigned int RDI_getSectionOffset( unsigned char id );
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 unsigned int RDI_getDirectoryElementCount( std::string path );
RDI_EXTERN std::vector<std::string> RDI_getDirectoryElements( std::string path );
RDI_EXTERN bool RDI_isElementDirectory( std::string path );
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 std::vector<std::string> RDI_getLevelsName( void );
RDI_EXTERN std::vector<std::string> RDI_getModelsName( void );
RDI_EXTERN std::vector<std::string> RDI_getTexturesName( void );
RDI_EXTERN std::vector<std::string> RDI_getMusicsName( void );
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.

View File

@ -59,13 +59,14 @@ public:
MEMFILE getRDat() const { return rDatPtr; }
/* Workspace management */
std::string getWorkingDirectory() { return workingDir; }
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 );

View File

@ -1,6 +1,6 @@
/**
* @file Krennic.cpp
* @date 24/09/2022
* @date 18/09/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Main game assets parser and interface.
@ -10,15 +10,22 @@
*
*/
#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;
@ -40,32 +47,32 @@ struct PathDescriptor {
};
Krennic::Krennic( Erso* pErso ) {
BuildLevelList(pErso);
BuildModelList(pErso);
BuildTextureList(pErso);
BuildMusicList(pErso);
BuildSampleList(pErso);
BuildLevelFileList(pErso);
BuildModelFileList(pErso);
BuildTextureFileList(pErso);
BuildMusicFileList(pErso);
BuildSampleFileList(pErso);
}
Krennic::~Krennic() {}
void Krennic::BuildLevelList( Erso* pErso ) {
const static vector<PathDescriptor> legacyLvlPath = {
void Krennic::BuildLevelFileList( Erso* pErso ) {
const static array<PathDescriptor, 1> legacyLvlPath = {
PathDescriptor("data/level", true)
};
listLevel.clear();
listLevelsName.clear();
for (PathDescriptor legacyLvlSubpath : legacyLvlPath) {
for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyLvlSubpath.path), "dat", legacyLvlSubpath.isRecursive)) {
//TODO: level-class builder
listLevel.push_back(file->getPath());
listLevelsName.push_back(file->getPath());
}
}
}
void Krennic::BuildModelList( Erso* pErso ) {
const static vector<PathDescriptor> legacyModelPath = {
void Krennic::BuildModelFileList( Erso* pErso ) {
const static array<PathDescriptor, 9> legacyModelPath = {
PathDescriptor("data", false),
PathDescriptor("data/pl_crafts", false),
PathDescriptor("data/reb_stuff", false),
@ -74,20 +81,36 @@ void Krennic::BuildModelList( Erso* pErso ) {
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)
};
listModel.clear();
listModels.clear();
listModelsName.clear();
for (PathDescriptor legacyModelSubpath : legacyModelPath) {
for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyModelSubpath.path), "_HOB", legacyModelSubpath.isRecursive)) {
//TODO: model-class builder
listModel.push_back(file->getPath());
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::BuildTextureList( Erso* pErso ) {
const static vector<PathDescriptor> legacyTexturePath = {
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),
@ -96,34 +119,85 @@ void Krennic::BuildTextureList( Erso* pErso ) {
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)
};
listTexture.clear();
listTexturesName.clear();
for (PathDescriptor legacyTextureSubpath : legacyTexturePath) {
for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyTextureSubpath.path), "_HMT", legacyTextureSubpath.isRecursive)) {
//TODO: texture-class builder
listTexture.push_back(file->getPath());
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::BuildMusicList( Erso* pErso ) {
const static vector<PathDescriptor> legacyLvlPath = {
void Krennic::BuildMusicFileList( Erso* pErso ) {
const static array<PathDescriptor, 1> legacyLvlPath = {
PathDescriptor("data/sound", false)
};
listMusic.clear();
listMusicsName.clear();
for (PathDescriptor legacyMusicSubpath : legacyLvlPath) {
for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyMusicSubpath.path), "_SNG", legacyMusicSubpath.isRecursive)) {
//TODO: MusyX-Class builder
listMusic.push_back(file->getPath());
listMusicsName.push_back(file->getPath());
}
}
}
void Krennic::BuildSampleList( Erso* pErso ) {
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() {}
}

View File

@ -1,6 +1,6 @@
/**
* @file Krennic.hpp
* @date 24/09/2022
* @date 18/01/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Main game assets parser and interface.
@ -15,6 +15,7 @@
#include <boost/filesystem.hpp>
#include <FileHandler/Generic.h>
#include <FileHandler/HMT.h>
#include <FileHandler/HOB.h>
#include "Erso.hpp"
@ -33,11 +34,11 @@ public:
* @return Array of filtered elements.
*/
///@{
std::vector<std::string> getLevelsList() { return listLevel; }
std::vector<std::string> getModelsList() { return listModel; }
std::vector<std::string> getTexturesList() { return listTexture; }
std::vector<std::string> getMusicsList() { return listMusic; }
std::vector<std::string> getSamplesList() { return listSample; }
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; }
///@}
/**
@ -47,7 +48,7 @@ public:
*/
///@{
void* getLevel( std::string name );
void* getModel( std::string name );
HOB* getModel( std::string name );
HMT* getTexture( std::string name );
void* getMusic( std::string name );
void* getSample( std::string name );
@ -64,17 +65,25 @@ public:
GenericFile *getFile( boost::filesystem::path vPath );
private:
std::vector<std::string> listLevel;
std::vector<std::string> listModel;
std::vector<std::string> listTexture;
std::vector<std::string> listMusic;
std::vector<std::string> listSample;
std::vector<HOB*> listModels;
void BuildLevelList( Erso* pErso );
void BuildModelList( Erso* pErso );
void BuildTextureList( Erso* pErso );
void BuildMusicList( Erso* pErso );
void BuildSampleList( Erso* pErso );
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();
};
}

View File

@ -1,6 +1,6 @@
/**
* @file GenericFile.cpp
* @date 23/09/2022
* @date 01/02/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Generic file object class.
@ -16,13 +16,12 @@ using namespace RDI::DatFile;
namespace RDI {
GenericFile::GenericFile( DatFile::DatFileEntryFile &hDat ) {
this->size = hDat.getSize();
this->fileName = hDat.getName();
this->fileExtension = "";
this->pMemLoc = hDat.getDatas();
}
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; }
}

View File

@ -15,7 +15,7 @@ using namespace RDI::DatFile;
namespace RDI {
HMT::HMT( DatFile::DatFileEntryFile &hDat ): GenericFile( hDat ) {
HMT::HMT( DatFile::DatFileEntryFile* hDat ): GenericFile( hDat ) {
this->fileExtension = "hmt";
}

189
src/KrennicHandlerHOB.cpp Normal file
View 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;
}
}

View File

@ -1,6 +1,6 @@
/**
* @file RDI.cpp
* @date 24/09/2022
* @date 22/01/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Rogue Data Interface library main entry abstraction file.
@ -15,10 +15,13 @@
#include <string>
#include <vector>
#include <fstream>
#include <stdexcept>
#include <RSPModel.h> // Only for version getting, no processing.
#include "config.h"
#include "Erso.hpp"
#include "DatFileEntry.hpp"
#include "Krennic.hpp"
#include <FileHandler/HOB.h>
#include "RDI.hpp"
using namespace RDI::DatFile;
@ -34,12 +37,12 @@ static RDI::Krennic *KrennicModule = nullptr;
/*
* Libs interface
*/
std::string RDI::RDI_getLibVersion() { return PRG_VERSION; }
const std::string RDI::RDI_getLibVersion() noexcept { return PRG_VERSION; }
void RDI::RDI_Init( std::string roguePath ) {
#ifdef DEBUG
std::cout << std::endl << "Running RDI v" << RDI_getLibVersion() << std::endl;
std::cout << "> RSPModelLib v" << "N/A" << std::endl;
#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
@ -47,7 +50,7 @@ void RDI::RDI_Init( std::string roguePath ) {
// Create new instance of Erso module
// Load and extract datas files from DATA.DAT
if (ErsoModule == nullptr) {
#ifdef DEBUG
#ifndef NDEBUG
std::cout << "[RDI][DBG] Loading Erso module..." << std::endl;
#endif
ErsoModule = new RDI::Erso(roguePath);
@ -56,7 +59,7 @@ void RDI::RDI_Init( std::string roguePath ) {
// 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) {
#ifdef DEBUG
#ifndef NDEBUG
std::cout << "[RDI][DBG] Loading Krennic module..." << std::endl;
#endif
KrennicModule = new RDI::Krennic(ErsoModule);
@ -68,23 +71,23 @@ void RDI::RDI_Init( std::string roguePath ) {
unsigned char RDI::RDI_getSectionCount() {
const unsigned char RDI::RDI_getSectionCount() {
if (ErsoModule == nullptr) return 0;
else return ErsoModule->getDataSectionCount();
}
std::string RDI::RDI_getSectionName( unsigned char id ) {
const std::string RDI::RDI_getSectionName( unsigned char id ) {
if (ErsoModule == nullptr) return "";
else return ErsoModule->getDataSectionName(id);
}
unsigned int RDI::RDI_getSectionOffset( unsigned char id ) {
const unsigned int RDI::RDI_getSectionOffset( unsigned char id ) {
if (ErsoModule == nullptr) return 0;
else return ErsoModule->getDataSectionOffset(id);
}
unsigned int RDI::RDI_getDirectoryElementCount( std::string path ) {
const unsigned int RDI::RDI_getDirectoryElementCount( std::string path ) {
DatFileEntryDirectory* result = nullptr;
if (path.empty()) return 0;
@ -95,7 +98,7 @@ unsigned int RDI::RDI_getDirectoryElementCount( std::string path ) {
else return result->getSize();
}
std::vector<std::string> RDI::RDI_getDirectoryElements( std::string path ) {
const std::vector<std::string> RDI::RDI_getDirectoryElements( std::string path ) {
DatFileEntryDirectory* de = nullptr;
std::vector<std::string> elementsNameArray;
elementsNameArray.clear();
@ -112,7 +115,7 @@ std::vector<std::string> RDI::RDI_getDirectoryElements( std::string path ) {
return elementsNameArray;
}
bool RDI::RDI_isElementDirectory( std::string path ) {
const bool RDI::RDI_isElementDirectory( std::string path ) {
DatFileEntry* result = nullptr;
if (path.empty()) return false;
@ -124,22 +127,33 @@ bool RDI::RDI_isElementDirectory( std::string path ) {
}
std::vector<std::string> RDI::RDI_getLevelsName( void ) {
/* -------------------------------------------------------------------------- */
const std::vector<std::string> RDI::RDI_getLevelsName( void ) {
return KrennicModule->getLevelsList();
}
std::vector<std::string> RDI::RDI_getModelsName( void ) {
const std::vector<std::string> RDI::RDI_getModelsName( void ) {
return KrennicModule->getModelsList();
}
std::vector<std::string> RDI::RDI_getTexturesName( void ) {
const std::vector<std::string> RDI::RDI_getTexturesName( void ) {
return KrennicModule->getTexturesList();
}
std::vector<std::string> RDI::RDI_getMusicsName( void ) {
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;

View File

@ -1,6 +1,6 @@
/**
* @file RDIDebug.cpp
* @date 12/01/2023
* @date 01/02/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Debug app to test functions of RDI library.
@ -8,31 +8,249 @@
*/
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <stdexcept>
#include <vector>
#ifdef USE_MULTITHREADING
#include <deque>
#include <thread>
#endif
#include <boost/filesystem.hpp>
#include <RDI.hpp>
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/stat.h>
#endif
using namespace boost::filesystem;
using namespace std;
void PrintVirtualDirectoryContents( path, string, bool );
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());
#ifdef _WIN32
CreateDirectory(".\\objOut", NULL);
#else
mkdir("./objOut");
#endif
for ( RDI::HOB* hobFile : modelCollection ) {
if (hobFile->getObjectCount()) {
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
for ( i = 0; i < hobFile->getObjectCount(); i++ ) {
cout << " Processing " << hobFile->getFullPath() << "..." << endl;
GenerateModelOBJ(hobFile->getMeshFromObject(i), parentPath, hobFile->getObjectName(i));
}
}
}
// Unload models
for ( RDI::HOB* hobFile : modelCollection ) {
hobFile->Dispose();
modelCollection.clear();
}
}
int main( int argc, char *argv[] ) {
unsigned int i;
path pathBuilder;
string prefix;
bool use_unicode = true;
#ifdef _WIN32
SetConsoleOutputCP(CP_UTF8);
#endif
cout << "Using RDI lib v" << RDI::RDI_getLibVersion() << endl << endl;
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
@ -46,7 +264,8 @@ int main( int argc, char *argv[] ) {
}
// Print details about legacy DATA.DAT file
cout << "> Section found: " << RDI::RDI_getSectionCount() << endl;
//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;
@ -60,7 +279,7 @@ int main( int argc, char *argv[] ) {
pathBuilder.clear();
pathBuilder.concat(RDI::RDI_getSectionName(i));
PrintVirtualDirectoryContents(pathBuilder, prefix, use_unicode);
PrintVirtualDirectoryContents(pathBuilder, use_unicode);
}
// Print game elements Krennic module found
@ -70,9 +289,7 @@ int main( int argc, char *argv[] ) {
cout << " " << lname << endl;
}
cout << endl << "> Models found: " << RDI::RDI_getModelsName().size() << endl;
for ( std::string mdname : RDI::RDI_getModelsName() ) {
cout << " " << mdname << endl;
}
ProcessModels();
cout << endl << "> Textures found: " << RDI::RDI_getTexturesName().size() << endl;
for ( std::string txname : RDI::RDI_getTexturesName() ) {
cout << " " << txname << endl;
@ -87,37 +304,3 @@ int main( int argc, char *argv[] ) {
return 0;
}
void PrintVirtualDirectoryContents( path p, string outPrefix, bool unicode ) {
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) {
cout << outPrefix << "\u251C " << eName << endl;
newOutPrefix.append("\u2502 ");
} else {
cout << outPrefix << "\\ " << eName << endl;
newOutPrefix.append("| ");
}
PrintVirtualDirectoryContents(newPath, newOutPrefix, unicode);
} else {
if (unicode) {
if (*--curDirElementsName.end() == eName)
cout << newOutPrefix << "\u2514 " << eName << endl;
else
cout << newOutPrefix << "\u251C " << eName << endl;
} else {
cout << newOutPrefix << "+ " << eName << endl;
}
}
}
}