diff --git a/conanfile.txt b/conanfile.txt index e12cdf7..e115130 100644 --- a/conanfile.txt +++ b/conanfile.txt @@ -1,6 +1,6 @@ [requires] rspmodellib/2.3.0 -rspterrainlib/2.0.4 +rspterrainlib/2.1.0 rsptexturelib/2.1.0 boost/1.81.0 diff --git a/include/FileHandler/Generic.h b/include/FileHandler/Generic.hpp similarity index 100% rename from include/FileHandler/Generic.h rename to include/FileHandler/Generic.hpp diff --git a/include/FileHandler/HMT.h b/include/FileHandler/HMT.hpp similarity index 89% rename from include/FileHandler/HMT.h rename to include/FileHandler/HMT.hpp index c0c41bc..e59e80e 100644 --- a/include/FileHandler/HMT.h +++ b/include/FileHandler/HMT.hpp @@ -7,7 +7,7 @@ * */ -#include +#include #ifndef HMT_H_ diff --git a/include/FileHandler/HOB.h b/include/FileHandler/HOB.hpp similarity index 98% rename from include/FileHandler/HOB.h rename to include/FileHandler/HOB.hpp index 48f9ff2..91c38c6 100644 --- a/include/FileHandler/HOB.h +++ b/include/FileHandler/HOB.hpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #ifndef HOB_H_ diff --git a/include/FileHandler/LVL.hpp b/include/FileHandler/LVL.hpp new file mode 100644 index 0000000..3d3741a --- /dev/null +++ b/include/FileHandler/LVL.hpp @@ -0,0 +1,129 @@ +/** + * @file LVL.h + * @date 07/02/2023 + * @author JackCarterSmith + * @copyright GPL-v3.0 + * @brief LVL object class. + * + * This special handler concatenate all levels resources in one class for easy access. + * + * Game level is represented by 3 elements : + * - HMP: heightmap and tiles textures mappings + * - DAT: globals levels informations like name, win conditions, spawns rules, etc. + * - GVM: Unknown usage for now + * + * Others level elements: + * - opkg_HOB: level specific models + * - ref_TM: Unknown usage for now + * + */ + +#include +#include +#include +#include + + +#ifndef LVL_H_ +#define LVL_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 LVL 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 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 { + std::vector*> vertices; + //std::vector indices; //TODO: Replaced by 32bits integer until indices optimization + std::vector indices; + }; + + /* -------------------------------------------------------------------------- */ + LVL( DatFile::DatFileEntryFile* hDat, DatFile::DatFileEntryFile* hHmp, DatFile::DatFileEntryFile* hGvm ); + ~LVL(); + + LVL(const LVL&) = default; + LVL& operator=(const LVL&) = default; + + LVL(LVL&&) = default; + LVL& operator=(LVL&&) = default; + + // Mandatory function from base class + RDI_EXTERN void Load(); + RDI_EXTERN void Dispose(); + + // Specific handler methods override for level instance + std::string getFileName() const { return levelName; } + std::string getFullPath() const { return fullLevelDirPath; } + + /* -------------------------------------------------------------------------- */ + RDI_EXTERN LVL::Mesh* getLevelMesh() const { + if (!this->isLoaded()) + throw std::runtime_error("LVL handler has not been loaded prior to function calling."); + + return mapMesh; + } + + //std::vector getLevelTextures(); + //ObjectTexture* getLevelTileTexture( const unsigned short x, const unsigned short y ); + + +private: + std::string levelName, fullLevelDirPath; + + unsigned long hmpFileSize, gvmFileSize; + MEMFILE pHmpMemLoc = nullptr; + MEMFILE pGvmMemLoc = nullptr; + + void* hmpInstance = nullptr; // RSPTerrain mesh instance + void* txtInstance = nullptr; // RSPTexture instance + + LVL::Mesh* mapMesh = nullptr; + +}; + +} + +#endif /* LVL_H_ */ diff --git a/include/RDI.hpp b/include/RDI.hpp index 376ed5e..1fb8e2f 100644 --- a/include/RDI.hpp +++ b/include/RDI.hpp @@ -9,7 +9,7 @@ #include #include -#include "FileHandler/HOB.h" +#include #ifndef RDI_HPP_ @@ -86,11 +86,12 @@ namespace RDI { /* -------------------------------------------------------------------------- */ /* Krennic specific methods */ - RDI_EXTERN const std::vector RDI_getLevelsName( void ); - RDI_EXTERN const std::vector RDI_getModelsName( void ); - RDI_EXTERN const std::vector RDI_getTexturesName( void ); - RDI_EXTERN const std::vector RDI_getMusicsName( void ); + RDI_EXTERN const std::vector RDI_getLevelsName( void ) noexcept; + RDI_EXTERN const std::vector RDI_getModelsName( void ) noexcept; + RDI_EXTERN const std::vector RDI_getTexturesName( void ) noexcept; + RDI_EXTERN const std::vector RDI_getMusicsName( void ) noexcept; + RDI_EXTERN LVL* RDI_getLevel( std::string levelName ); RDI_EXTERN HOB* RDI_getModel( std::string modelName ); diff --git a/include/RDI_FileHandlers.hpp b/include/RDI_FileHandlers.hpp new file mode 100644 index 0000000..bea6a44 --- /dev/null +++ b/include/RDI_FileHandlers.hpp @@ -0,0 +1,19 @@ +/** + * @file RDI_FileHandlers.h + * @date 04/02/2023 + * @author JackCarterSmith + * @copyright GPL-v3.0 + * @brief FileHandlers global interface header. + * + */ + +#ifndef RDI_FILEHANDLERS_HPP_ +#define RDI_FILEHANDLERS_HPP_ + +#include +#include +#include +#include + + +#endif /* RDI_FILEHANDLERS_HPP_ */ diff --git a/src/DatFileEntry.cpp b/src/DatFileEntry.cpp index bc88b81..0ff2e18 100644 --- a/src/DatFileEntry.cpp +++ b/src/DatFileEntry.cpp @@ -9,8 +9,8 @@ #include #include -#include #include "DatFileEntry.hpp" +#include using std::string; using std::vector; diff --git a/src/DatFileEntry.hpp b/src/DatFileEntry.hpp index ed58170..4b6628a 100644 --- a/src/DatFileEntry.hpp +++ b/src/DatFileEntry.hpp @@ -12,7 +12,7 @@ * */ -#include +#include #include #include diff --git a/src/Erso.cpp b/src/Erso.cpp index 619dd5a..190d2d6 100644 --- a/src/Erso.cpp +++ b/src/Erso.cpp @@ -12,11 +12,11 @@ #include #include #include -#include #include //TODO: Should be removed with RDI_RESULT #include "files_mms/data_struct.h" #include "DatFileEntry.hpp" #include "Erso.hpp" +#include using std::string; using std::ios; diff --git a/src/Erso.hpp b/src/Erso.hpp index 5ac784f..a5ce2d5 100644 --- a/src/Erso.hpp +++ b/src/Erso.hpp @@ -29,8 +29,8 @@ */ #include +#include #include -#include #include //TODO: Should be removed with RDI_RESULT #include "DatFileEntry.hpp" diff --git a/src/Krennic.cpp b/src/Krennic.cpp index 9704ba5..79aed5d 100644 --- a/src/Krennic.cpp +++ b/src/Krennic.cpp @@ -17,12 +17,13 @@ #include #include #include -#include -#include -#include #include "Erso.hpp" #include "Krennic.hpp" +#include +#include +#include + using std::string; using std::vector; using std::array; @@ -62,11 +63,31 @@ void Krennic::BuildLevelFileList( Erso* pErso ) { PathDescriptor("data/level", true) }; + DatFileEntryFile* datFile = nullptr; + DatFileEntryFile* hmpFile = nullptr; + DatFileEntryFile* gvmFile = nullptr; + 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()); + for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyLvlSubpath.path), "lv_", legacyLvlSubpath.isRecursive)) { + if (file->isDirectory()) { + DatFileEntryDirectory* lvlDir = dynamic_cast(file); + for ( DatFileEntry* lvlFile : lvlDir->getFiles() ) { + if (lvlFile->getName().compare("dat") == 0) + datFile = dynamic_cast(lvlFile); + else if (lvlFile->getName().compare("hmp") == 0) + hmpFile = dynamic_cast(lvlFile); + else if (lvlFile->getName().compare("gvm") == 0) + gvmFile = dynamic_cast(lvlFile); + } + + if (datFile == nullptr || hmpFile == nullptr || gvmFile == nullptr) + throw std::runtime_error("One or more level files can't be found!"); + + auto lvlObj = new LVL(datFile, hmpFile, gvmFile); + listLevels.push_back(lvlObj); + listLevelsName.push_back(lvlObj->getFullPath()); + } } } } @@ -94,7 +115,7 @@ void Krennic::BuildModelFileList( Erso* pErso ) { for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyModelSubpath.path), "_HOB", legacyModelSubpath.isRecursive)) { auto hobObj = new HOB(dynamic_cast(file)); listModels.push_back(hobObj); - listModelsName.push_back(file->getPath()); + listModelsName.push_back(hobObj->getFullPath()); } } if (pErso->isUpdatedVersion()) { @@ -102,7 +123,7 @@ void Krennic::BuildModelFileList( Erso* pErso ) { for (DatFileEntry* file : pErso->getElements(boost::filesystem::path(legacyModelSubpath2.path), "_HOB", legacyModelSubpath2.isRecursive)) { auto hobObj = new HOB(dynamic_cast(file)); listModels.push_back(hobObj); - listModelsName.push_back(file->getPath()); + listModelsName.push_back(hobObj->getFullPath()); } } } @@ -161,7 +182,18 @@ void Krennic::BuildSampleFileList( Erso* pErso ) { } -//void* Krennic::getLevel( std::string name ) {} +LVL* Krennic::getLevel( string name ) { + unsigned int i = 0; + + for (string fileName : listLevelsName) { + if (fileName.find(name) != string::npos) { + return listLevels.at(i); + } + i++; + } + + throw std::invalid_argument("Krennic can't found the requested level."); +} HOB* Krennic::getModel( string name ) { unsigned int i = 0; @@ -176,11 +208,11 @@ HOB* Krennic::getModel( string name ) { throw std::invalid_argument("Krennic can't found the requested model."); } -//HMT* Krennic::getTexture( std::string name ) {} +//HMT* Krennic::getTexture( string name ) {} -//void* Krennic::getMusic( std::string name ) {} +//void* Krennic::getMusic( string name ) {} -//void* Krennic::getSample( std::string name ) {} +//void* Krennic::getSample( string name ) {} void Krennic::DisposeLevels() {} diff --git a/src/Krennic.hpp b/src/Krennic.hpp index 20743a2..d447e40 100644 --- a/src/Krennic.hpp +++ b/src/Krennic.hpp @@ -1,6 +1,6 @@ /** * @file Krennic.hpp - * @date 18/01/2023 + * @date 04/02/2023 * @author JackCarterSmith * @copyright GPL-v3.0 * @brief Main game assets parser and interface. @@ -13,9 +13,8 @@ #include #include #include -#include -#include -#include +#include + #include "Erso.hpp" @@ -47,7 +46,7 @@ public: * @return File type class handler. */ ///@{ - void* getLevel( std::string name ); + LVL* getLevel( std::string name ); HOB* getModel( std::string name ); HMT* getTexture( std::string name ); void* getMusic( std::string name ); @@ -65,7 +64,11 @@ public: GenericFile *getFile( boost::filesystem::path vPath ); private: + std::vector listLevels; std::vector listModels; + //std::vector listTextures; + //std::vector listMusics; + //std::vector listSamples; std::vector listLevelsName; std::vector listModelsName; diff --git a/src/KrennicHandlerGeneric.cpp b/src/KrennicHandlerGeneric.cpp index 5b31aa2..e9dfabf 100644 --- a/src/KrennicHandlerGeneric.cpp +++ b/src/KrennicHandlerGeneric.cpp @@ -7,9 +7,9 @@ * */ +#include #include #include "DatFileEntry.hpp" -#include using namespace RDI::DatFile; diff --git a/src/KrennicHandlerHMT.cpp b/src/KrennicHandlerHMT.cpp index 885e10f..25f3919 100644 --- a/src/KrennicHandlerHMT.cpp +++ b/src/KrennicHandlerHMT.cpp @@ -7,8 +7,8 @@ * */ -#include -#include +#include +#include using namespace RDI::DatFile; diff --git a/src/KrennicHandlerHOB.cpp b/src/KrennicHandlerHOB.cpp index ba9f959..0fc7526 100644 --- a/src/KrennicHandlerHOB.cpp +++ b/src/KrennicHandlerHOB.cpp @@ -10,11 +10,11 @@ #include #include #include +#include #include #include #include "DatFileEntry.hpp" -#include -#include +#include using std::runtime_error; using std::out_of_range; @@ -54,7 +54,7 @@ void HOB::Load() { rspParams.raw = 0; result = RSPModel_processHOBFileMemory(hobInstancePtr, this->pMemLoc, this->size, rspParams); if (result != RSPLIB_SUCCESS) { - RSPModel_freeHOB(static_cast(this->hobInstance)); + RSPModel_freeHOB(hobInstancePtr); delete static_cast(this->hobInstance); if (result == RSPLIB_ERROR_GENERIC) @@ -68,7 +68,7 @@ void HOB::Load() { for ( i = 0; i < this->objCnt; i++ ) this->objectMeshList[string(hobInstancePtr->objects[i].name)] = BuildObjectMesh(hobInstancePtr->objects + i); - RSPModel_freeHOB(static_cast(this->hobInstance)); + RSPModel_freeHOB(hobInstancePtr); // Must be called last to set loaded state GenericFile::Load(); diff --git a/src/KrennicHandlerLVL.cpp b/src/KrennicHandlerLVL.cpp new file mode 100644 index 0000000..61097bf --- /dev/null +++ b/src/KrennicHandlerLVL.cpp @@ -0,0 +1,130 @@ +/** + * @file KrennicHandlerLVL.cpp + * @date 07/02/2023 + * @author JackCarterSmith + * @copyright GPL-v3.0 + * @brief LVL object class. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "DatFileEntry.hpp" +#include + +using std::runtime_error; +using std::invalid_argument; +using std::string; +using namespace RDI::DatFile; +using namespace boost::qvm; + + +namespace RDI { + +LVL::Mesh* BuildMapMesh( const T_RSPTERRAIN_MESH& hobPtr ); + + +/* -------------------------------------------------------------------------- */ +LVL::LVL( DatFileEntryFile* hDat, DatFileEntryFile* hHmp, DatFileEntryFile* hGvm ) + : GenericFile(hDat), hmpFileSize(hHmp->getSize()), gvmFileSize(hGvm->getSize()), + pHmpMemLoc(hHmp->getDatas()), pGvmMemLoc(hGvm->getDatas()) { + this->fileExtension = "lvl"; + this->levelName = boost::filesystem::path(hDat->getPath()).parent_path().filename().string(); + this->fullLevelDirPath = boost::filesystem::path(hDat->getPath()).parent_path().string(); +} + +LVL::~LVL() { + Dispose(); +} + + +/* -------------------------------------------------------------------------- */ +void LVL::Load() { + RSPTERRAIN_PARAMETERS rspParams; + T_RSPTERRAIN_MESH intermediateMesh; + unsigned short result = RSPLIB_SUCCESS; + + if (this->isLoaded()) return; + + this->hmpInstance = new T_RSPTERRAIN_HMP{}; + auto hmpInstancePtr = static_cast(this->hmpInstance); + rspParams.raw = 0; + rspParams.invertZ = true; + + result = RSPTerrain_processHMPFileMemory(hmpInstancePtr, this->pHmpMemLoc, this->hmpFileSize, rspParams); + if (result != RSPLIB_SUCCESS) { + RSPTerrain_freeHMP(hmpInstancePtr); + delete static_cast(this->hmpInstance); + + throw runtime_error("HMP handler processing failed with error: " + std::to_string(result)); + } + + // Use RSPTerrainLib to build our level mesh and convert it to generic mesh format + RSPTerrain_terrainToMesh(&intermediateMesh, hmpInstancePtr, 0.1f); + this->mapMesh = BuildMapMesh(intermediateMesh); + + RSPTerrain_freeHMP(hmpInstancePtr); + + // Must be called last to set loaded state + GenericFile::Load(); +} + +void LVL::Dispose() { + if (!this->isLoaded()) return; + + delete this->mapMesh; + delete static_cast(this->hmpInstance); + + // Must be called last to unset loaded state + GenericFile::Dispose(); +} + + +/* -------------------------------------------------------------------------- */ + + + +/* -------------------------------------------------------------------------- */ +LVL::Mesh* BuildMapMesh( const T_RSPTERRAIN_MESH& terrainMesh ) { + unsigned int i,j; + auto mapMesh = new LVL::Mesh(); + + mapMesh->indices.clear(); + mapMesh->vertices.clear(); + mapMesh->indices.reserve((terrainMesh.height-1) * (terrainMesh.width-1)); + mapMesh->vertices.reserve(terrainMesh.vertices_count); + + for (i = 0; i < terrainMesh.vertices_count; i++) { + auto v = new vec(); + + v->a[0] = terrainMesh.verticesmap[i].x; + v->a[1] = terrainMesh.verticesmap[i].y; + v->a[2] = terrainMesh.verticesmap[i].z; + + mapMesh->vertices.push_back(v); + } + + for ( i = 0; i < static_cast(terrainMesh.height) - 1; i++ ) { + for ( j = 0; j < static_cast(terrainMesh.width) - 1; j++ ) { + //uint16_t indice = static_cast(i * terrainMesh.width + j); + uint32_t indice = static_cast(i * terrainMesh.width + j); + + mapMesh->indices.push_back(indice); + mapMesh->indices.push_back(indice + 1); + mapMesh->indices.push_back(indice + terrainMesh.width); + + mapMesh->indices.push_back(indice + 1); + mapMesh->indices.push_back(indice + terrainMesh.width + 1); + mapMesh->indices.push_back(indice + terrainMesh.width); + } + } + + return mapMesh; +} + +} diff --git a/src/RDI.cpp b/src/RDI.cpp index e9149c1..db788f3 100644 --- a/src/RDI.cpp +++ b/src/RDI.cpp @@ -1,6 +1,6 @@ /** * @file RDI.cpp - * @date 22/01/2023 + * @date 04/02/2023 * @author JackCarterSmith * @copyright GPL-v3.0 * @brief Rogue Data Interface library main entry abstraction file. @@ -21,11 +21,12 @@ #include #include #include // Only for version getting, no processing. +#include // Only for version getting, no processing. #include "config.h" #include "Erso.hpp" #include "DatFileEntry.hpp" #include "Krennic.hpp" -#include +#include #include "RDI.hpp" using namespace RDI::DatFile; @@ -45,10 +46,10 @@ const std::string RDI::RDI_getLibVersion() noexcept { 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; + std::cout << std::endl << "[RDI][DBG] Running RDI v" << std::string(RDI::RDI_getLibVersion()) << std::endl; + std::cout << "[RDI][DBG] - RSPModelLib v" << std::string(RSPModel_getVersion()) << std::endl; + std::cout << "[RDI][DBG] - RSPTerrainLib v" << std::string(RSPTerrain_getVersion()) << std::endl; + std::cout << "[RDI][DBG] - RSPTextureLib v" << "N/A" << std::endl; #endif // Create new instance of Erso module @@ -132,22 +133,31 @@ const bool RDI::RDI_isElementDirectory( std::string path ) { /* -------------------------------------------------------------------------- */ -const std::vector RDI::RDI_getLevelsName( void ) { +const std::vector RDI::RDI_getLevelsName( void ) noexcept { return KrennicModule->getLevelsList(); } -const std::vector RDI::RDI_getModelsName( void ) { +const std::vector RDI::RDI_getModelsName( void ) noexcept { return KrennicModule->getModelsList(); } -const std::vector RDI::RDI_getTexturesName( void ) { +const std::vector RDI::RDI_getTexturesName( void ) noexcept { return KrennicModule->getTexturesList(); } -const std::vector RDI::RDI_getMusicsName( void ) { +const std::vector RDI::RDI_getMusicsName( void ) noexcept { return KrennicModule->getMusicsList(); } +RDI::LVL* RDI::RDI_getLevel( std::string levelName ) { + try { + return KrennicModule->getLevel(levelName); + } + catch (std::invalid_argument const &ex) { // Can't find level, incorrect name? + throw std::invalid_argument(ex); + } +} + RDI::HOB* RDI::RDI_getModel( std::string modelName ) { try { return KrennicModule->getModel(modelName); diff --git a/tools/RDIDebug.cpp b/tools/RDIDebug.cpp index d2dac38..670595e 100644 --- a/tools/RDIDebug.cpp +++ b/tools/RDIDebug.cpp @@ -30,15 +30,15 @@ #include #endif -using namespace boost::filesystem; using namespace std; +static vector levelCollection; static vector modelCollection; -static void PrintVirtualDirectoryContents( path p, bool unicode, string outPrefix = "" ) { +static void PrintVirtualDirectoryContents( boost::filesystem::path p, bool unicode, string outPrefix = "" ) { auto curDirElementsName = RDI::RDI_getDirectoryElements(p.string()); - auto newPath = path(p); + auto newPath = boost::filesystem::path(p); auto newOutPrefix = string(outPrefix); for ( string eName : curDirElementsName ) { @@ -95,30 +95,60 @@ static void PrintModel( const RDI::HOB::Mesh* mesh, string prefix = "" ) { } } +static void GenerateLevelOBJ( const RDI::LVL::Mesh* mesh, const string outFolder ) { + if (mesh == nullptr || outFolder.empty()) + return; + + unsigned long i; + + try { + ofstream objFile("objOut/" + outFolder + "/mapmesh.obj"); + + for ( auto v : mesh->vertices ) { + objFile << "v " << v->a[0] << " " << v->a[1] << " " << v->a[2] << endl; + } + objFile << endl; + for ( i = 0; i < mesh->indices.size(); i += 3 ) { + objFile << "f " << mesh->indices[i]+1; + objFile << " " << mesh->indices[i+1]+1; + objFile << " " << mesh->indices[i+2]+1 << endl; + } + objFile << endl; + + objFile.close(); + } catch (exception const& ex) { + throw exception(ex); + } +} + 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"); + try { + 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; + 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(); + i_offset += submesh->vertices.size(); + } + + objFile.close(); + } catch (exception const& ex) { + throw exception(ex); } - - objFile.close(); } #ifdef USE_MULTITHREADING @@ -130,25 +160,14 @@ static void GenerateModelOBJThreaded() { 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 + filesystem::create_directories("./objOut/" + parentPath); // Create initial threads for files processing for ( i = 0; i < maxThreads; i++ ) { @@ -185,13 +204,58 @@ static void GenerateModelOBJThreaded() { } #endif +static void ProcessLevels() { + unsigned int invalid = 0; + + // Build levels collection + levelCollection.clear(); + for ( string lvlname : RDI::RDI_getLevelsName() ) { + + auto filePath = boost::filesystem::path(lvlname); + levelCollection.push_back(RDI::RDI_getLevel(filePath.string())); + } + + // Try to load level using low-level library + for ( RDI::LVL* lvlFile : levelCollection ) { + try { + lvlFile->Load(); + if (lvlFile->getLevelMesh()->vertices.empty()) + invalid++; + } catch (exception const &ex) { + cout << "Failed loading level file!" << endl; + } + } + cout << "Number of invalid memory allocation: " << invalid << endl; + + // Launch level map OBJ file building + for ( RDI::LVL* lvlFile : levelCollection ) { + if (lvlFile->isLoaded()) { + filesystem::create_directories("./objOut/" + lvlFile->getFullPath()); + + cout << " " << lvlFile->getFullPath() << "..."; + try { + GenerateLevelOBJ(lvlFile->getLevelMesh(), lvlFile->getFullPath()); + cout << " OK" << endl; + } catch (exception const& ex) { + cout << " FAIL" << endl; + } + } + } + + // Unload models + for ( RDI::LVL* lvlFile : levelCollection ) { + lvlFile->Dispose(); + levelCollection.clear(); + } +} + static void ProcessModels() { unsigned int i,invalid = 0; // Build models collection modelCollection.clear(); for ( string mdname : RDI::RDI_getModelsName() ) { - auto filePath = path(mdname); + auto filePath = boost::filesystem::path(mdname); modelCollection.push_back(RDI::RDI_getModel(filePath.string())); } @@ -200,10 +264,8 @@ static void ProcessModels() { try { hobFile->Load(); for ( i = 0; i < hobFile->getObjectCount(); i++ ) { - if (hobFile->getMeshFromObject(i)->subMeshs.empty()) { - cout << "Memory allocation failure!" << endl; + if (hobFile->getMeshFromObject(i)->subMeshs.empty()) invalid++; - } } } catch (out_of_range const &ex) { //cout << "Empty object" << endl; @@ -217,15 +279,18 @@ static void ProcessModels() { for ( RDI::HOB* hobFile : modelCollection ) { if (hobFile->isLoaded() && hobFile->getObjectCount()) { - string parentPath = path(hobFile->getFullPath()).string(); - replace(parentPath.begin(), parentPath.end(), '/', '\\'); + string parentPath = boost::filesystem::path(hobFile->getFullPath()).string(); - filesystem::create_directories(".\\objOut\\" + hobFile->getFullPath()); + 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; + cout << " " << hobFile->getFullPath() << "/" << *(hobFile->getObjectName(i)) << "..."; + try { + GenerateModelOBJ(hobFile->getMeshFromObject(i), parentPath, hobFile->getObjectName(i)); + cout << " OK" << endl; + } catch (exception const& ex) { + cout << " FAIL" << endl; + } } } } @@ -239,14 +304,15 @@ static void ProcessModels() { int main( int argc, char *argv[] ) { unsigned int i; - path pathBuilder; + boost::filesystem::path pathBuilder; bool use_unicode = true; + chrono::_V2::system_clock::time_point t_start, t_end; #ifdef _WIN32 SetConsoleOutputCP(CP_UTF8); #endif - cout << "RDIDebug tool - using RDI lib v" << RDI::RDI_getLibVersion() << endl << endl; + cout << "RDIDebug tool started..." << endl; // Initialize RDI (Erso and Krennic module) with folder provided in program // argument, or the current directory by default @@ -260,7 +326,6 @@ int main( int argc, char *argv[] ) { } // 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; @@ -281,15 +346,16 @@ int main( int argc, char *argv[] ) { // 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; - } + t_start = chrono::high_resolution_clock::now(); + ProcessLevels(); + t_end = chrono::high_resolution_clock::now(); + cout << endl << "Levels processing in " << chrono::duration_cast(t_end - t_start).count() << "s" << endl; cout << endl << "> Models found: " << RDI::RDI_getModelsName().size() << endl; - auto t_start = chrono::high_resolution_clock::now(); + t_start = chrono::high_resolution_clock::now(); ProcessModels(); - auto t_end = chrono::high_resolution_clock::now(); - cout << "Models processing in " << chrono::duration_cast(t_end - t_start).count() << "s" << endl; + t_end = chrono::high_resolution_clock::now(); + cout << endl << "Models processing in " << chrono::duration_cast(t_end - t_start).count() << "s" << endl; cout << endl << "> Textures found: " << RDI::RDI_getTexturesName().size() << endl; for ( std::string txname : RDI::RDI_getTexturesName() ) {