309 lines
8.3 KiB
C++
309 lines
8.3 KiB
C++
/**
|
|
* @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) && !(_MSVC_LANG < 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;
|
|
}
|