mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-05-02 08:57:44 +00:00
slightly cleaned up PCB reader, added some exception logging
This commit is contained in:
parent
ae1b8a393e
commit
2e13df1934
2 changed files with 277 additions and 256 deletions
|
@ -57,6 +57,26 @@ enum class LgbEntryType : uint32_t
|
||||||
SphereCastRange = 75,
|
SphereCastRange = 75,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LGB_MODEL_ENTRY
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
char* m_buf;
|
||||||
|
uint32_t m_offset;
|
||||||
|
|
||||||
|
LGB_MODEL_ENTRY()
|
||||||
|
{
|
||||||
|
m_buf = nullptr;
|
||||||
|
m_offset = 0;
|
||||||
|
};
|
||||||
|
LGB_MODEL_ENTRY( char* buf, uint32_t offset )
|
||||||
|
{
|
||||||
|
m_buf = buf;
|
||||||
|
m_offset = offset;
|
||||||
|
};
|
||||||
|
virtual ~LGB_MODEL_ENTRY() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct LGB_BGPARTS_HEADER
|
struct LGB_BGPARTS_HEADER
|
||||||
{
|
{
|
||||||
LgbEntryType type;
|
LgbEntryType type;
|
||||||
|
@ -75,25 +95,6 @@ struct LGB_BGPARTS_HEADER
|
||||||
uint32_t unknown9;
|
uint32_t unknown9;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LGB_MODEL_ENTRY
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
char* m_buf;
|
|
||||||
uint32_t m_offset;
|
|
||||||
|
|
||||||
LGB_MODEL_ENTRY()
|
|
||||||
{
|
|
||||||
m_buf = nullptr;
|
|
||||||
m_offset = 0;
|
|
||||||
};
|
|
||||||
LGB_MODEL_ENTRY(char* buf, uint32_t offset)
|
|
||||||
{
|
|
||||||
m_buf = buf;
|
|
||||||
m_offset = offset;
|
|
||||||
};
|
|
||||||
virtual ~LGB_MODEL_ENTRY(){};
|
|
||||||
};
|
|
||||||
|
|
||||||
class LGB_BGPARTS_ENTRY : public LGB_MODEL_ENTRY
|
class LGB_BGPARTS_ENTRY : public LGB_MODEL_ENTRY
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -101,13 +102,13 @@ public:
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string modelFileName;
|
std::string modelFileName;
|
||||||
std::string collisionFileName;
|
std::string collisionFileName;
|
||||||
LGB_BGPARTS_ENTRY(){};
|
LGB_BGPARTS_ENTRY() {};
|
||||||
LGB_BGPARTS_ENTRY(char* buf, uint32_t offset)
|
LGB_BGPARTS_ENTRY( char* buf, uint32_t offset )
|
||||||
{
|
{
|
||||||
header = *reinterpret_cast<LGB_BGPARTS_HEADER*>(buf + offset);
|
header = *reinterpret_cast<LGB_BGPARTS_HEADER*>(buf + offset);
|
||||||
name = std::string(buf + offset + header.nameOffset);
|
name = std::string( buf + offset + header.nameOffset );
|
||||||
modelFileName = std::string(buf + offset + header.modelFileOffset);
|
modelFileName = std::string( buf + offset + header.modelFileOffset );
|
||||||
collisionFileName = std::string(buf + offset + header.collisionFileOffset);
|
collisionFileName = std::string( buf + offset + header.collisionFileOffset );
|
||||||
//std::cout << "BGPARTS_ENTRY " << name << "\n";
|
//std::cout << "BGPARTS_ENTRY " << name << "\n";
|
||||||
//std::cout << " " << modelFileName << "\n";
|
//std::cout << " " << modelFileName << "\n";
|
||||||
//std::cout << " " << collisionFileName << "\n";
|
//std::cout << " " << collisionFileName << "\n";
|
||||||
|
@ -132,10 +133,10 @@ public:
|
||||||
LGB_GIMMICK_HEADER header;
|
LGB_GIMMICK_HEADER header;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
LGB_GIMMICK_ENTRY(char* buf, uint32_t offset)
|
LGB_GIMMICK_ENTRY( char* buf, uint32_t offset )
|
||||||
{
|
{
|
||||||
header = *reinterpret_cast<LGB_GIMMICK_HEADER*>(buf + offset);
|
header = *reinterpret_cast<LGB_GIMMICK_HEADER*>(buf + offset);
|
||||||
name = std::string(buf + offset + header.nameOffset);
|
name = std::string( buf + offset + header.nameOffset );
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -163,40 +164,40 @@ struct LGB_GROUP
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<std::shared_ptr<LGB_MODEL_ENTRY>> entries;
|
std::vector<std::shared_ptr<LGB_MODEL_ENTRY>> entries;
|
||||||
|
|
||||||
LGB_GROUP(char* buf, LGB_FILE* parentStruct, uint32_t offset)
|
LGB_GROUP( char* buf, LGB_FILE* parentStruct, uint32_t offset )
|
||||||
{
|
{
|
||||||
parent = parentStruct;
|
parent = parentStruct;
|
||||||
header = *reinterpret_cast<LGB_GROUP_HEADER*>(buf + offset);
|
header = *reinterpret_cast<LGB_GROUP_HEADER*>(buf + offset);
|
||||||
name = std::string(buf + offset + header.groupNameOffset);
|
name = std::string( buf + offset + header.groupNameOffset );
|
||||||
entries.resize(header.entryCount);
|
entries.resize( header.entryCount );
|
||||||
//std::cout << name << std::endl;
|
//std::cout << name << std::endl;
|
||||||
auto entriesOffset = offset + header.entriesOffset;
|
auto entriesOffset = offset + header.entriesOffset;
|
||||||
for( auto i = 0; i < header.entryCount; ++i )
|
for( auto i = 0; i < header.entryCount; ++i )
|
||||||
{
|
{
|
||||||
auto entryOffset = entriesOffset + *reinterpret_cast<int32_t*>(buf + (entriesOffset + i * 4));
|
auto entryOffset = entriesOffset + *reinterpret_cast<int32_t*>(buf + (entriesOffset + i * 4));
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
|
||||||
auto type = *reinterpret_cast<LgbEntryType*>(buf + entryOffset);
|
|
||||||
LGB_MODEL_ENTRY* entry;
|
|
||||||
if (type == LgbEntryType::BgParts)
|
|
||||||
{
|
{
|
||||||
entries[i] = std::make_shared<LGB_BGPARTS_ENTRY>(buf, entryOffset);
|
auto type = *reinterpret_cast<LgbEntryType*>(buf + entryOffset);
|
||||||
|
LGB_MODEL_ENTRY* entry;
|
||||||
|
if( type == LgbEntryType::BgParts )
|
||||||
|
{
|
||||||
|
entries[i] = std::make_shared<LGB_BGPARTS_ENTRY>( buf, entryOffset );
|
||||||
|
}
|
||||||
|
else if( type == LgbEntryType::Gimmick )
|
||||||
|
{
|
||||||
|
entries[i] = std::make_shared<LGB_GIMMICK_ENTRY>( buf, entryOffset );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entries[i] = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (type == LgbEntryType::Gimmick)
|
catch( std::exception& e )
|
||||||
{
|
{
|
||||||
entries[i] = std::make_shared<LGB_GIMMICK_ENTRY>(buf, entryOffset);
|
std::cout << name << " " << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
|
||||||
entries[i] = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (std::exception& e)
|
|
||||||
{
|
|
||||||
std::cout << name << " " << e.what() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -218,46 +219,46 @@ struct LGB_FILE
|
||||||
LGB_FILE_HEADER header;
|
LGB_FILE_HEADER header;
|
||||||
std::vector<LGB_GROUP> groups;
|
std::vector<LGB_GROUP> groups;
|
||||||
|
|
||||||
LGB_FILE(char* buf)
|
LGB_FILE( char* buf )
|
||||||
{
|
{
|
||||||
header = *reinterpret_cast<LGB_FILE_HEADER*>(buf);
|
header = *reinterpret_cast<LGB_FILE_HEADER*>(buf);
|
||||||
if (strncmp(&header.magic[0], "LGB1", 4) != 0 || strncmp(&header.magic2[0], "LGP1", 4) != 0)
|
if( strncmp( &header.magic[0], "LGB1", 4 ) != 0 || strncmp( &header.magic2[0], "LGP1", 4 ) != 0 )
|
||||||
throw std::exception("Invalid LGB file!");
|
throw std::exception( "Invalid LGB file!" );
|
||||||
|
|
||||||
//groups.resize(header.groupCount);
|
//groups.resize(header.groupCount);
|
||||||
|
|
||||||
auto baseOffset = sizeof(header);
|
auto baseOffset = sizeof( header );
|
||||||
for(auto i = 0; i < header.groupCount; ++i)
|
for( auto i = 0; i < header.groupCount; ++i )
|
||||||
{
|
{
|
||||||
auto groupOffset = baseOffset + *reinterpret_cast<int32_t*>(buf + (baseOffset + i * 4));
|
auto groupOffset = baseOffset + *reinterpret_cast<int32_t*>(buf + (baseOffset + i * 4));
|
||||||
auto group = LGB_GROUP(buf, this, groupOffset);
|
auto group = LGB_GROUP( buf, this, groupOffset );
|
||||||
groups.push_back(group);
|
groups.push_back( group );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
std::map<std::string, LGB_FILE> getLgbFiles(const std::string& dir)
|
std::map<std::string, LGB_FILE> getLgbFiles( const std::string& dir )
|
||||||
{
|
{
|
||||||
namespace fs = std::experimental::filesystem;
|
namespace fs = std::experimental::filesystem;
|
||||||
std::map<std::string, LGB_FILE> fileMap;
|
std::map<std::string, LGB_FILE> fileMap;
|
||||||
for (const auto& path : fs::recursive_directory_iterator(dir))
|
for( const auto& path : fs::recursive_directory_iterator( dir ) )
|
||||||
{
|
{
|
||||||
if (path.path().extension() == ".lgb")
|
if( path.path().extension() == ".lgb" )
|
||||||
{
|
{
|
||||||
auto strPath = path.path().string();
|
auto strPath = path.path().string();
|
||||||
auto f = fopen(strPath.c_str(), "rb");
|
auto f = fopen( strPath.c_str(), "rb" );
|
||||||
fseek(f, 0, SEEK_END);
|
fseek( f, 0, SEEK_END );
|
||||||
auto size = ftell(f);
|
auto size = ftell( f );
|
||||||
std::vector<char> bytes(size);
|
std::vector<char> bytes( size );
|
||||||
rewind(f);
|
rewind( f );
|
||||||
fread(bytes.data(), 1, size, f);
|
fread( bytes.data(), 1, size, f );
|
||||||
fclose(f);
|
fclose( f );
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LGB_FILE lgbFile(bytes.data());
|
LGB_FILE lgbFile( bytes.data() );
|
||||||
fileMap.insert(std::make_pair(strPath, lgbFile));
|
fileMap.insert( std::make_pair( strPath, lgbFile ) );
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch( std::exception& e )
|
||||||
{
|
{
|
||||||
std::cout << "Unable to load " << strPath << std::endl;
|
std::cout << "Unable to load " << strPath << std::endl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,10 @@
|
||||||
#include <Exd.h>
|
#include <Exd.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
namespace fs = std::experimental::filesystem;
|
namespace fs = std::experimental::filesystem;
|
||||||
struct face
|
struct face
|
||||||
{
|
{
|
||||||
|
@ -28,7 +32,7 @@ int parseBlockEntry( char* data, std::vector<PCB_BLOCK_ENTRY>& entries, int gOff
|
||||||
{
|
{
|
||||||
PCB_BLOCK_ENTRY block_entry;
|
PCB_BLOCK_ENTRY block_entry;
|
||||||
memcpy( &block_entry.header, data + offset, sizeof( block_entry.header ) );
|
memcpy( &block_entry.header, data + offset, sizeof( block_entry.header ) );
|
||||||
isgroup = block_entry.header.type == 0x30 ? true : false;
|
isgroup = block_entry.header.type == 0x30;
|
||||||
|
|
||||||
//printf( " BLOCKHEADER_%X: type: %i, group_size: %i\n", gOff + offset, block_entry.header.type, block_entry.header.group_size );
|
//printf( " BLOCKHEADER_%X: type: %i, group_size: %i\n", gOff + offset, block_entry.header.type, block_entry.header.group_size );
|
||||||
|
|
||||||
|
@ -115,6 +119,8 @@ std::string zoneNameToPath( const std::string& name )
|
||||||
|
|
||||||
int main( int argc, char* argv[] )
|
int main( int argc, char* argv[] )
|
||||||
{
|
{
|
||||||
|
auto startTime = std::chrono::system_clock::now();
|
||||||
|
|
||||||
std::string gamePath = "C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv";
|
std::string gamePath = "C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv";
|
||||||
std::string zoneName = "r1f1";
|
std::string zoneName = "r1f1";
|
||||||
|
|
||||||
|
@ -128,219 +134,233 @@ int main( int argc, char* argv[] )
|
||||||
}
|
}
|
||||||
const auto& zonePath = zoneNameToPath( zoneName );
|
const auto& zonePath = zoneNameToPath( zoneName );
|
||||||
|
|
||||||
xiv::dat::GameData data1( gamePath );
|
try
|
||||||
xiv::exd::ExdData eData( data1 );
|
|
||||||
|
|
||||||
const xiv::dat::Cat& test = data1.get_category( "bg" );
|
|
||||||
|
|
||||||
auto &test_file = data1.get_file( "bg/ffxiv/" + zonePath + "/level/bg.lgb" );
|
|
||||||
auto §ion = test_file->access_data_sections().at( 0 );
|
|
||||||
int32_t list_offset = *( uint32_t* ) §ion[0x18];
|
|
||||||
int32_t size = *( uint32_t* ) §ion[4];
|
|
||||||
|
|
||||||
std::vector<std::string> stringList;
|
|
||||||
std::vector<std::string> stringList2;
|
|
||||||
|
|
||||||
auto &test_file1 = data1.get_file( "bg/ffxiv/" + zonePath + "/collision/list.pcb" );
|
|
||||||
auto §ion1 = test_file1->access_data_sections().at( 0 );
|
|
||||||
std::string path = "bg/ffxiv/" + zonePath + "/collision/";
|
|
||||||
int offset1 = 0x20;
|
|
||||||
for( ; ; )
|
|
||||||
{
|
{
|
||||||
|
xiv::dat::GameData data1( gamePath );
|
||||||
|
xiv::exd::ExdData eData( data1 );
|
||||||
|
|
||||||
uint16_t trId = *( uint16_t* ) §ion1[offset1];
|
const xiv::dat::Cat& test = data1.get_category( "bg" );
|
||||||
|
|
||||||
char someString[200];
|
auto &test_file = data1.get_file( "bg/ffxiv/" + zonePath + "/level/bg.lgb" );
|
||||||
sprintf( someString, "%str%04d.pcb", path.c_str(), trId );
|
auto §ion = test_file->access_data_sections().at( 0 );
|
||||||
stringList.push_back( std::string( someString ) );
|
int32_t list_offset = *(uint32_t*)§ion[0x18];
|
||||||
//std::cout << someString << "\n";
|
int32_t size = *(uint32_t*)§ion[4];
|
||||||
offset1 += 0x20;
|
|
||||||
|
|
||||||
if( offset1 >= section1.size() )
|
std::vector<std::string> stringList;
|
||||||
|
|
||||||
|
auto &test_file1 = data1.get_file( "bg/ffxiv/" + zonePath + "/collision/list.pcb" );
|
||||||
|
auto §ion1 = test_file1->access_data_sections().at( 0 );
|
||||||
|
std::string path = "bg/ffxiv/" + zonePath + "/collision/";
|
||||||
|
int offset1 = 0x20;
|
||||||
|
for( ; ; )
|
||||||
{
|
{
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LGB_FILE bgLgb(§ion[0]);
|
uint16_t trId = *(uint16_t*)§ion1[offset1];
|
||||||
|
|
||||||
int max_index = 0;
|
char someString[200];
|
||||||
|
sprintf( someString, "%str%04d.pcb", path.c_str(), trId );
|
||||||
|
stringList.push_back( std::string( someString ) );
|
||||||
|
//std::cout << someString << "\n";
|
||||||
|
offset1 += 0x20;
|
||||||
|
|
||||||
std::vector<std::string> vertices;
|
if( offset1 >= section1.size() )
|
||||||
std::vector<std::string> indices;
|
|
||||||
|
|
||||||
char *data;
|
|
||||||
int counter = 0;
|
|
||||||
|
|
||||||
// dont bother if we cant write to a file
|
|
||||||
auto fp_out = fopen( (zoneName + ".obj").c_str(), "w" );
|
|
||||||
if( fp_out )
|
|
||||||
{
|
|
||||||
fprintf( fp_out, "\n" );
|
|
||||||
fclose( fp_out );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw std::exception( "Cannot create new file. Run as admin." );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_out = fopen( (zoneName + ".obj").c_str(), "ab+" );
|
|
||||||
if( fp_out )
|
|
||||||
{
|
|
||||||
std::map<std::string, PCB_FILE> pcbFiles;
|
|
||||||
std::map<std::string, uint32_t> objCount;
|
|
||||||
auto loadPcbFile = [&]( const std::string& fileName )
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
//std::cout << fileName << " ";
|
break;
|
||||||
auto file = data1.get_file( fileName );
|
}
|
||||||
auto sections = file->get_data_sections();
|
}
|
||||||
auto dataSection = §ions.at( 0 )[0];
|
|
||||||
|
|
||||||
//std::cout << sections.size() << "\n";
|
LGB_FILE bgLgb( §ion[0] );
|
||||||
|
|
||||||
uint32_t offset = 0;
|
int max_index = 0;
|
||||||
|
|
||||||
|
std::vector<std::string> vertices;
|
||||||
|
std::vector<std::string> indices;
|
||||||
|
|
||||||
|
char *data;
|
||||||
|
int counter = 0;
|
||||||
|
|
||||||
|
// dont bother if we cant write to a file
|
||||||
|
auto fp_out = fopen( (zoneName + ".obj").c_str(), "w" );
|
||||||
|
if( fp_out )
|
||||||
|
{
|
||||||
|
fprintf( fp_out, "\n" );
|
||||||
|
fclose( fp_out );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string errorMessage( "Cannot create " + zoneName + ".obj\n" +
|
||||||
|
" Check no programs have a handle to file and run as admin.\n" );
|
||||||
|
std::cout << errorMessage;
|
||||||
|
throw std::exception( errorMessage.c_str() );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_out = fopen( (zoneName + ".obj").c_str(), "ab+" );
|
||||||
|
if( fp_out )
|
||||||
|
{
|
||||||
|
std::map<std::string, PCB_FILE> pcbFiles;
|
||||||
|
std::map<std::string, uint32_t> objCount;
|
||||||
|
auto loadPcbFile = [&]( const std::string& fileName )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//std::cout << fileName << " ";
|
||||||
|
auto file = data1.get_file( fileName );
|
||||||
|
auto sections = file->get_data_sections();
|
||||||
|
auto dataSection = §ions.at( 0 )[0];
|
||||||
|
|
||||||
|
//std::cout << sections.size() << "\n";
|
||||||
|
|
||||||
|
uint32_t offset = 0;
|
||||||
|
uint32_t groupCount = 0;
|
||||||
|
PCB_FILE pcb_file;
|
||||||
|
memcpy( &pcb_file.header, &dataSection[0], sizeof( pcb_file.header ) );
|
||||||
|
offset += sizeof( pcb_file.header );
|
||||||
|
|
||||||
|
bool isgroup = true;
|
||||||
|
while( isgroup )
|
||||||
|
{
|
||||||
|
PCB_BLOCK_ENTRY block_entry;
|
||||||
|
memcpy( &block_entry.header, &dataSection[0] + offset, sizeof( block_entry.header ) );
|
||||||
|
isgroup = block_entry.header.type == 0x30;
|
||||||
|
|
||||||
|
//printf( "BLOCKHEADER_%X: type: %i, group_size: %i\n", offset, block_entry.header.type, block_entry.header.group_size );
|
||||||
|
//
|
||||||
|
if( isgroup )
|
||||||
|
{
|
||||||
|
parseBlockEntry( &dataSection[0] + offset + 0x30, pcb_file.entries, offset );
|
||||||
|
offset += block_entry.header.group_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parseBlockEntry( &dataSection[0] + offset, pcb_file.entries, offset );
|
||||||
|
}
|
||||||
|
groupCount++;
|
||||||
|
}
|
||||||
|
pcbFiles.insert( std::make_pair( fileName, pcb_file ) );
|
||||||
|
}
|
||||||
|
catch( std::exception& e )
|
||||||
|
{
|
||||||
|
std::cout << "Unable to load collision mesh " << fileName << "\n\tError:\n\t" << e.what() << "\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto pushVerts = [&]( const PCB_FILE& pcb_file, const std::string& name, const vec3* scale = nullptr, const vec3* rotation = nullptr, const vec3* translation = nullptr )
|
||||||
|
{
|
||||||
|
std::string name2 = (name + "_" + std::to_string( objCount[name]++ ));
|
||||||
|
fprintf( fp_out, "o %s\n", name2.c_str() );
|
||||||
uint32_t groupCount = 0;
|
uint32_t groupCount = 0;
|
||||||
PCB_FILE pcb_file;
|
for( auto &entry : pcb_file.entries )
|
||||||
memcpy( &pcb_file.header, &dataSection[0], sizeof( pcb_file.header ) );
|
|
||||||
offset += sizeof( pcb_file.header );
|
|
||||||
|
|
||||||
bool isgroup = true;
|
|
||||||
while( isgroup )
|
|
||||||
{
|
{
|
||||||
PCB_BLOCK_ENTRY block_entry;
|
float x_base = abs( float( entry.header.x1 - entry.header.x ) );
|
||||||
memcpy( &block_entry.header, &dataSection[0] + offset, sizeof( block_entry.header ) );
|
float y_base = abs( float( entry.header.y1 - entry.header.y ) );
|
||||||
isgroup = block_entry.header.type == 0x30 ? true : false;
|
float z_base = abs( float( entry.header.z1 - entry.header.z ) );
|
||||||
|
|
||||||
//printf( "BLOCKHEADER_%X: type: %i, group_size: %i\n", offset, block_entry.header.type, block_entry.header.group_size );
|
auto makeTranslation = [&]( vec3& v )
|
||||||
//
|
|
||||||
if( isgroup )
|
|
||||||
{
|
{
|
||||||
parseBlockEntry( &dataSection[0] + offset + 0x30, pcb_file.entries, offset );
|
if( scale )
|
||||||
offset += block_entry.header.group_size;
|
{
|
||||||
}
|
v.x *= scale->x;
|
||||||
else
|
v.y *= scale->y;
|
||||||
|
v.z *= scale->z;
|
||||||
|
|
||||||
|
v = v * matrix4::rotateX( rotation->x );
|
||||||
|
v = v * matrix4::rotateY( rotation->y );
|
||||||
|
v = v * matrix4::rotateZ( rotation->z );
|
||||||
|
|
||||||
|
v.x += translation->x;
|
||||||
|
v.y += translation->y;
|
||||||
|
v.z += translation->z;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
for( auto &vertex : entry.data.vertices )
|
||||||
{
|
{
|
||||||
parseBlockEntry( &dataSection[0] + offset, pcb_file.entries, offset );
|
vec3 v( vertex.x, vertex.y, vertex.z );
|
||||||
|
makeTranslation( v );
|
||||||
|
fprintf( fp_out, "v %f %f %f\n", v.x, v.y, v.z );
|
||||||
}
|
}
|
||||||
groupCount++;
|
|
||||||
|
for( const auto &link : entry.data.vertices_i16 )
|
||||||
|
{
|
||||||
|
vec3 v( float( link.x ) / 0xFFFF, float( link.y ) / 0xFFFF, float( link.z ) / 0xFFFF );
|
||||||
|
|
||||||
|
v.x = v.x * x_base + entry.header.x;
|
||||||
|
v.y = v.y * y_base + entry.header.y;
|
||||||
|
v.z = v.z * z_base + entry.header.z;
|
||||||
|
|
||||||
|
makeTranslation( v );
|
||||||
|
fprintf( fp_out, "v %f %f %f\n", v.x, v.y, v.z );
|
||||||
|
}
|
||||||
|
|
||||||
|
//fprintf( fp_out, "g %s_", (name2 + "_" + std::to_string( groupCount++ )).c_str() );
|
||||||
|
for( const auto &index : entry.data.indices )
|
||||||
|
{
|
||||||
|
//if( index.index[0] != 0 || index.index[1] != 0 || index.index[2] != 0 )
|
||||||
|
{
|
||||||
|
fprintf( fp_out, "f %i %i %i\n",
|
||||||
|
index.index[0] + max_index + 1,
|
||||||
|
index.index[1] + max_index + 1,
|
||||||
|
index.index[2] + max_index + 1 );
|
||||||
|
}
|
||||||
|
//std::cout << std::to_string( index.unknown[0] )<< " " << std::to_string( index.unknown[1] )<< " " << std::to_string( index.unknown[2]) << std::endl;
|
||||||
|
}
|
||||||
|
max_index += entry.data.vertices.size() + entry.data.vertices_i16.size();
|
||||||
}
|
}
|
||||||
pcbFiles.insert( std::make_pair( fileName, pcb_file ) );
|
};
|
||||||
}
|
|
||||||
catch( std::exception& e )
|
for( const auto& fileName : stringList )
|
||||||
{
|
{
|
||||||
std::cout << "Unable to load collision mesh " << fileName << "\n\tError:\n\t" << e.what() << "\n";
|
loadPcbFile( fileName );
|
||||||
|
pushVerts( pcbFiles[fileName], fileName );
|
||||||
}
|
}
|
||||||
};
|
std::cout << "Writing obj file " << "\n";
|
||||||
auto pushVerts = [&]( const PCB_FILE& pcb_file, const std::string& name, const vec3* scale = nullptr, const vec3* rotation = nullptr, const vec3* translation = nullptr )
|
std::cout << bgLgb.groups.size() << " entries " << "\n";
|
||||||
{
|
for( const auto& group : bgLgb.groups )
|
||||||
std::string name2 = (name + "_" + std::to_string( objCount[name]++ ));
|
|
||||||
fprintf( fp_out, "o %s\n", name2.c_str() );
|
|
||||||
uint32_t groupCount = 0;
|
|
||||||
for( auto &entry : pcb_file.entries )
|
|
||||||
{
|
{
|
||||||
float x_base = abs( float( entry.header.x1 - entry.header.x ) );
|
for( const auto pEntry : group.entries )
|
||||||
float y_base = abs( float( entry.header.y1 - entry.header.y ) );
|
|
||||||
float z_base = abs( float( entry.header.z1 - entry.header.z ) );
|
|
||||||
|
|
||||||
auto makeTranslation = [&]( vec3& v )
|
|
||||||
{
|
{
|
||||||
if( scale )
|
if( !pEntry )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto pBgParts = dynamic_cast<LGB_BGPARTS_ENTRY*>(pEntry.get());
|
||||||
|
if( pBgParts && pBgParts->collisionFileName.empty() )
|
||||||
{
|
{
|
||||||
v.x *= scale->x;
|
pBgParts->collisionFileName = pBgParts->modelFileName;
|
||||||
v.y *= scale->y;
|
boost::replace_all( pBgParts->collisionFileName, "bgparts", "collision" );
|
||||||
v.z *= scale->z;
|
boost::replace_all( pBgParts->collisionFileName, ".mdl", ".pcb" );
|
||||||
|
//std::cout << pBgParts->collisionFileName << " renamed\n";
|
||||||
v = v * matrix4::rotateX( rotation->x );
|
|
||||||
v = v * matrix4::rotateY( rotation->y );
|
|
||||||
v = v * matrix4::rotateZ( rotation->z );
|
|
||||||
|
|
||||||
v.x += translation->x;
|
|
||||||
v.y += translation->y;
|
|
||||||
v.z += translation->z;
|
|
||||||
}
|
}
|
||||||
|
if( !pBgParts || pBgParts->collisionFileName.empty() )
|
||||||
|
//|| std::find( stringList.begin(), stringList.end(), pBgParts->collisionFileName ) != stringList.end() )
|
||||||
|
continue;
|
||||||
|
|
||||||
};
|
auto it = pcbFiles.find( pBgParts->collisionFileName );
|
||||||
|
if( it == pcbFiles.end() )
|
||||||
for( auto &vertex_list : entry.data.vertices )
|
|
||||||
{
|
|
||||||
vec3 v;
|
|
||||||
v.x = vertex_list.x;
|
|
||||||
v.y = vertex_list.y;
|
|
||||||
v.z = vertex_list.z;
|
|
||||||
makeTranslation( v );
|
|
||||||
fprintf( fp_out, "v %f %f %f\n", v.x, v.y, v.z );
|
|
||||||
}
|
|
||||||
|
|
||||||
for( const auto &link : entry.data.vertices_i16 )
|
|
||||||
{
|
|
||||||
vec3 v( float( link.x ) / 0xFFFF, float( link.y ) / 0xFFFF, float( link.z ) / 0xFFFF );
|
|
||||||
|
|
||||||
v.x = v.x * x_base + entry.header.x;
|
|
||||||
v.y = v.y * y_base + entry.header.y;
|
|
||||||
v.z = v.z * z_base + entry.header.z;
|
|
||||||
|
|
||||||
makeTranslation( v );
|
|
||||||
fprintf( fp_out, "v %f %f %f\n", v.x, v.y, v.z );
|
|
||||||
}
|
|
||||||
|
|
||||||
//fprintf( fp_out, "g %s_", (name2 + "_" + std::to_string( groupCount++ )).c_str() );
|
|
||||||
for( const auto &index : entry.data.indices )
|
|
||||||
{
|
|
||||||
//if( index.index[0] != 0 || index.index[1] != 0 || index.index[2] != 0 )
|
|
||||||
{
|
{
|
||||||
face f;
|
loadPcbFile( pBgParts->collisionFileName );
|
||||||
f.f1 = index.index[0] + max_index;
|
//std::cout << "\t\tLoaded PCB File " << pBgParts->collisionFileName << "\n";
|
||||||
f.f2 = index.index[1] + max_index;
|
|
||||||
f.f3 = index.index[2] + max_index;
|
|
||||||
|
|
||||||
fprintf( fp_out, "f %i %i %i\n", f.f1 + 1, f.f2 + 1, f.f3 + 1 );
|
|
||||||
}
|
}
|
||||||
//std::cout << std::to_string( index.unknown[0] )<< " " << std::to_string( index.unknown[1] )<< " " << std::to_string( index.unknown[2]) << std::endl;
|
if( it != pcbFiles.end() )
|
||||||
}
|
{
|
||||||
//max_index = vertices.size();
|
//std::cout << pBgParts->collisionFileName << "\n";
|
||||||
max_index += entry.data.vertices.size() + entry.data.vertices_i16.size();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for( const auto& fileName : stringList )
|
const auto* scale = &pBgParts->header.scale;
|
||||||
{
|
const auto* rotation = &pBgParts->header.rotation;
|
||||||
loadPcbFile( fileName );
|
const auto* translation = &pBgParts->header.translation;
|
||||||
pushVerts( pcbFiles[fileName], fileName );
|
|
||||||
}
|
|
||||||
std::cout << "Writing obj file " << "\n";
|
|
||||||
std::cout << bgLgb.groups.size() << " entries " << "\n";
|
|
||||||
for( const auto& group : bgLgb.groups )
|
|
||||||
{
|
|
||||||
for( const auto pEntry : group.entries )
|
|
||||||
{
|
|
||||||
if( !pEntry )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto pBgParts = dynamic_cast<LGB_BGPARTS_ENTRY*>(pEntry.get());
|
const auto& pcb_file = it->second;
|
||||||
if( !pBgParts || pBgParts->collisionFileName.empty()
|
pushVerts( pcb_file, pBgParts->collisionFileName, scale, rotation, translation );
|
||||||
|| std::find( stringList.begin(), stringList.end(), pBgParts->collisionFileName ) != stringList.end() )
|
}
|
||||||
continue;
|
|
||||||
auto it = pcbFiles.find( pBgParts->collisionFileName );
|
|
||||||
if( it == pcbFiles.end() )
|
|
||||||
{
|
|
||||||
loadPcbFile( pBgParts->collisionFileName );
|
|
||||||
}
|
|
||||||
if( it != pcbFiles.end() )
|
|
||||||
{
|
|
||||||
//std::cout << pBgParts->collisionFileName << "\n";
|
|
||||||
|
|
||||||
const auto* scale = &pBgParts->header.scale;
|
|
||||||
const auto* rotation = &pBgParts->header.rotation;
|
|
||||||
const auto* translation = &pBgParts->header.translation;
|
|
||||||
|
|
||||||
const auto& pcb_file = it->second;
|
|
||||||
pushVerts( pcb_file, pBgParts->collisionFileName, scale, rotation, translation );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::cout << "Finished exporting " << zoneName << " in " <<
|
||||||
|
std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - startTime).count() << " seconds\n";
|
||||||
|
}
|
||||||
|
catch( std::exception& e )
|
||||||
|
{
|
||||||
|
std::cout << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue