RDI/tools/RDIDebug.cpp
JackCarterSmith 05b3c1e88a
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
2023-02-03 18:12:04 +01:00

307 lines
8.1 KiB
C++

/**
* @file RDIDebug.cpp
* @date 01/02/2023
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Debug app to test functions of RDI library.
*
*/
#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;
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;
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;
ProcessModels();
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;
}