mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-27 06:47:45 +00:00
fixed collision dumping
- added saintcoinach's sgb parsing
This commit is contained in:
parent
a90fd345dc
commit
bc89049ada
3 changed files with 285 additions and 30 deletions
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "matrix4.h"
|
#include "matrix4.h"
|
||||||
#include "vec3.h"
|
#include "vec3.h"
|
||||||
|
#include "sgb.h"
|
||||||
|
|
||||||
// all credit to
|
// all credit to
|
||||||
// https://github.com/ufx/SaintCoinach/blob/master/SaintCoinach/Graphics/Lgb/
|
// https://github.com/ufx/SaintCoinach/blob/master/SaintCoinach/Graphics/Lgb/
|
||||||
|
@ -134,11 +135,13 @@ class LGB_GIMMICK_ENTRY : public LGB_MODEL_ENTRY
|
||||||
public:
|
public:
|
||||||
LGB_GIMMICK_HEADER header;
|
LGB_GIMMICK_HEADER header;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
std::string gimmickFileName;
|
||||||
|
|
||||||
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 );
|
||||||
|
gimmickFileName = std::string( buf + offset + header.gimmickFileOffset );
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -185,11 +188,11 @@ struct LGB_GROUP
|
||||||
{
|
{
|
||||||
entries.push_back( std::make_shared<LGB_BGPARTS_ENTRY>( buf, entryOffset ) );
|
entries.push_back( std::make_shared<LGB_BGPARTS_ENTRY>( buf, entryOffset ) );
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
else if( type == LgbEntryType::Gimmick )
|
else if( type == LgbEntryType::Gimmick )
|
||||||
{
|
{
|
||||||
//entries[i] = std::make_shared<LGB_GIMMICK_ENTRY>( buf, entryOffset );
|
entries.push_back( std::make_shared<LGB_GIMMICK_ENTRY>( buf, entryOffset ) );
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//entries[i] = nullptr;
|
//entries[i] = nullptr;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "pcb.h"
|
#include "pcb.h"
|
||||||
#include "lgb.h"
|
#include "lgb.h"
|
||||||
|
#include "sgb.h"
|
||||||
|
|
||||||
#include <GameData.h>
|
#include <GameData.h>
|
||||||
#include <File.h>
|
#include <File.h>
|
||||||
|
@ -198,8 +199,9 @@ int main( int argc, char* argv[] )
|
||||||
if( fp_out )
|
if( fp_out )
|
||||||
{
|
{
|
||||||
std::map<std::string, PCB_FILE> pcbFiles;
|
std::map<std::string, PCB_FILE> pcbFiles;
|
||||||
|
std::map<std::string, SGB_FILE> sgbFiles;
|
||||||
std::map<std::string, uint32_t> objCount;
|
std::map<std::string, uint32_t> objCount;
|
||||||
auto loadPcbFile = [&]( const std::string& fileName )
|
auto loadPcbFile = [&]( const std::string& fileName ) -> bool
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -214,7 +216,7 @@ int main( int argc, char* argv[] )
|
||||||
PCB_FILE pcb_file;
|
PCB_FILE pcb_file;
|
||||||
memcpy( &pcb_file.header, &dataSection[0], sizeof( pcb_file.header ) );
|
memcpy( &pcb_file.header, &dataSection[0], sizeof( pcb_file.header ) );
|
||||||
offset += sizeof( pcb_file.header );
|
offset += sizeof( pcb_file.header );
|
||||||
|
pcb_file.entries.resize( pcb_file.header.num_entries );
|
||||||
bool isgroup = true;
|
bool isgroup = true;
|
||||||
while( isgroup )
|
while( isgroup )
|
||||||
{
|
{
|
||||||
|
@ -235,16 +237,38 @@ int main( int argc, char* argv[] )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pcbFiles.insert( std::make_pair( fileName, pcb_file ) );
|
pcbFiles.insert( std::make_pair( fileName, pcb_file ) );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
catch( std::exception& e )
|
catch( std::exception& e )
|
||||||
{
|
{
|
||||||
std::cout << "Unable to load collision mesh " << fileName << "\n\tError:\n\t" << e.what() << "\n";
|
std::cout << "Unable to load collision mesh " << fileName << "\n\tError:\n\t" << e.what() << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto loadSgbFile = [&]( const std::string& fileName ) -> bool
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto file = data1.get_file( fileName );
|
||||||
|
auto sections = file->get_data_sections();
|
||||||
|
auto dataSection = §ions.at( 0 )[0];
|
||||||
|
SGB_FILE sgbFile = SGB_FILE( &dataSection[0] );
|
||||||
|
sgbFiles.insert( std::make_pair( fileName, sgbFile ) );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch( std::exception& e )
|
||||||
|
{
|
||||||
|
std::cout << "Unable to load SGB " << fileName << "\n\tError:\n\t" << e.what() << "\n";
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
auto pushVerts = [&]( const PCB_FILE& pcb_file, const std::string& name, const vec3* scale = nullptr, const vec3* rotation = nullptr, const vec3* translation = nullptr )
|
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]++ ) );
|
char name2[0x7F];
|
||||||
fprintf( fp_out, "o %s\n", name2.c_str() );
|
memset( name2, 0, 0x7F );
|
||||||
|
sprintf(&name2[0], "%s_%u", &name[0], objCount[name]++ );
|
||||||
|
fprintf( fp_out, "o %s\n", &name2[0] );
|
||||||
uint32_t groupCount = 0;
|
uint32_t groupCount = 0;
|
||||||
for( const auto &entry : pcb_file.entries )
|
for( const auto &entry : pcb_file.entries )
|
||||||
{
|
{
|
||||||
|
@ -321,37 +345,76 @@ int main( int argc, char* argv[] )
|
||||||
totalGroups++;
|
totalGroups++;
|
||||||
for( const auto pEntry : group.entries )
|
for( const auto pEntry : group.entries )
|
||||||
{
|
{
|
||||||
auto pBgParts = static_cast<LGB_BGPARTS_ENTRY*>( pEntry.get() );
|
LGB_GIMMICK_ENTRY* pGimmick = nullptr;
|
||||||
auto& fileName = pBgParts->collisionFileName;
|
auto pBgParts = dynamic_cast<LGB_BGPARTS_ENTRY*>( pEntry.get() );
|
||||||
|
if( pBgParts && pBgParts->header.type != LgbEntryType::BgParts )
|
||||||
|
pBgParts = nullptr;
|
||||||
|
|
||||||
if( fileName.empty() )
|
auto& fileName = pBgParts ? pBgParts->collisionFileName : "";
|
||||||
|
|
||||||
|
if( pBgParts && fileName.empty() )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// write files
|
||||||
|
auto writeOutput = [&]()
|
||||||
{
|
{
|
||||||
//boost::replace_all( fileName, "bgparts", "collision" );
|
|
||||||
//boost::replace_all( fileName, ".mdl", ".pcb" );
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const auto& it = pcbFiles.find( fileName );
|
|
||||||
if( it == pcbFiles.end() )
|
|
||||||
{
|
{
|
||||||
loadPcbFile( fileName );
|
const auto& it = pcbFiles.find( fileName );
|
||||||
//std::cout << "\t\tLoaded PCB File " << pBgParts->collisionFileName << "\n";
|
if( it == pcbFiles.end() )
|
||||||
|
{
|
||||||
|
if( !fileName.empty() )
|
||||||
|
loadPcbFile( fileName );
|
||||||
|
//std::cout << "\t\tLoaded PCB File " << pBgParts->collisionFileName << "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
const auto& it = pcbFiles.find( fileName );
|
||||||
const auto& it = pcbFiles.find( fileName );
|
if( it != pcbFiles.end() )
|
||||||
if( it != pcbFiles.end() )
|
{
|
||||||
|
totalGroupEntries++;
|
||||||
|
|
||||||
|
const auto* scale = pBgParts ? &pBgParts->header.scale : &pGimmick->header.scale;
|
||||||
|
const auto* rotation = pBgParts ? &pBgParts->header.rotation : &pGimmick->header.rotation;
|
||||||
|
const auto* translation = pBgParts ? &pBgParts->header.translation : &pGimmick->header.translation;
|
||||||
|
|
||||||
|
const auto& pcb_file = it->second;
|
||||||
|
pushVerts( pcb_file, fileName, scale, rotation, translation );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// gimmick entry
|
||||||
|
if( !pBgParts )
|
||||||
{
|
{
|
||||||
totalGroupEntries++;
|
pGimmick = dynamic_cast<LGB_GIMMICK_ENTRY*>( pEntry.get() );
|
||||||
|
{
|
||||||
|
const auto& it = sgbFiles.find( pGimmick->gimmickFileName );
|
||||||
|
if( it == sgbFiles.end() )
|
||||||
|
{
|
||||||
|
loadSgbFile( pGimmick->gimmickFileName );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto& it = sgbFiles.find( pGimmick->gimmickFileName );
|
||||||
|
if( it != sgbFiles.end() )
|
||||||
|
{
|
||||||
|
totalGroupEntries++;
|
||||||
|
const auto& sgbFile = it->second;
|
||||||
|
|
||||||
const auto* scale = &pBgParts->header.scale;
|
for( const auto& group : sgbFile.entries )
|
||||||
const auto* rotation = &pBgParts->header.rotation;
|
{
|
||||||
const auto* translation = &pBgParts->header.translation;
|
for( const auto& pEntry : group.entries )
|
||||||
|
{
|
||||||
const auto& pcb_file = it->second;
|
auto pModel = dynamic_cast<SGB_MODEL_ENTRY*>( pEntry.get() );
|
||||||
pushVerts( pcb_file, fileName, scale, rotation, translation );
|
if( !pModel->collisionFileName.empty() )
|
||||||
|
{
|
||||||
|
fileName = pModel->collisionFileName;
|
||||||
|
writeOutput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
// bgparts
|
||||||
|
writeOutput();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::cout << "\n\nLoaded " << pcbFiles.size() << " PCB Files \n";
|
std::cout << "\n\nLoaded " << pcbFiles.size() << " PCB Files \n";
|
||||||
|
|
189
src/tools/pcb_reader/sgb.h
Normal file
189
src/tools/pcb_reader/sgb.h
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
#ifndef _SGB_H
|
||||||
|
#define _SGB_H
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "vec3.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// ported from https://github.com/ufx/SaintCoinach/blob/master/SaintCoinach/Graphics/Sgb/SgbDataType.cs
|
||||||
|
|
||||||
|
struct SGB_FILE;
|
||||||
|
struct SGB_HEADER;
|
||||||
|
struct SGB_MODEL_ENTRY;
|
||||||
|
struct SGB_MODEL_HEADER;
|
||||||
|
struct SGB_GROUP;
|
||||||
|
struct SGB_GROUP_HEADER;
|
||||||
|
|
||||||
|
|
||||||
|
enum SgbDataType : uint32_t
|
||||||
|
{
|
||||||
|
Unknown0008 = 0x0008,
|
||||||
|
Group = 0x0100,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SgbGroupEntryType : uint32_t
|
||||||
|
{
|
||||||
|
Model = 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SGB_GROUP_HEADER
|
||||||
|
{
|
||||||
|
SgbDataType type;
|
||||||
|
int32_t nameOffset;
|
||||||
|
uint32_t unknown08;
|
||||||
|
uint32_t unknown0C;
|
||||||
|
|
||||||
|
uint32_t unknown10;
|
||||||
|
uint32_t unknown14;
|
||||||
|
uint32_t unknown18;
|
||||||
|
uint32_t unknown1C;
|
||||||
|
|
||||||
|
int32_t entryCount;
|
||||||
|
uint32_t unknown24;
|
||||||
|
uint32_t unknown28;
|
||||||
|
uint32_t unknown2C;
|
||||||
|
|
||||||
|
uint32_t unknown30;
|
||||||
|
uint32_t unknown34;
|
||||||
|
uint32_t unknown38;
|
||||||
|
uint32_t unknown3C;
|
||||||
|
|
||||||
|
uint32_t unknown40;
|
||||||
|
uint32_t unknown44;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SGB_GROUP_ENTRY
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
char* m_buf;
|
||||||
|
uint32_t m_offset;
|
||||||
|
|
||||||
|
SGB_GROUP_ENTRY()
|
||||||
|
{
|
||||||
|
m_buf = nullptr;
|
||||||
|
m_offset = 0;
|
||||||
|
};
|
||||||
|
SGB_GROUP_ENTRY( char* buf, uint32_t offset )
|
||||||
|
{
|
||||||
|
m_buf = buf;
|
||||||
|
m_offset = offset;
|
||||||
|
};
|
||||||
|
virtual ~SGB_GROUP_ENTRY() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SGB_MODEL_HEADER
|
||||||
|
{
|
||||||
|
SgbGroupEntryType type;
|
||||||
|
uint32_t unknown2;
|
||||||
|
int32_t nameOffset;
|
||||||
|
vec3 translation;
|
||||||
|
vec3 rotation;
|
||||||
|
vec3 scale;
|
||||||
|
int32_t modelFileOffset;
|
||||||
|
int32_t collisionFileOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SGB_MODEL_ENTRY : public SGB_GROUP_ENTRY
|
||||||
|
{
|
||||||
|
SGB_MODEL_HEADER header;
|
||||||
|
SgbGroupEntryType type;
|
||||||
|
std::string name;
|
||||||
|
std::string modelFileName;
|
||||||
|
std::string collisionFileName;
|
||||||
|
|
||||||
|
SGB_MODEL_ENTRY( char* buf, uint32_t offset )
|
||||||
|
{
|
||||||
|
header = *reinterpret_cast<SGB_MODEL_HEADER*>( buf + offset );
|
||||||
|
name = std::string( buf + offset + header.nameOffset );
|
||||||
|
modelFileName = std::string( buf + offset + header.modelFileOffset );
|
||||||
|
collisionFileName = std::string( buf + offset + header.collisionFileOffset );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SGB_GROUP
|
||||||
|
{
|
||||||
|
SGB_GROUP_HEADER header;
|
||||||
|
std::string name;
|
||||||
|
SGB_FILE* parent;
|
||||||
|
std::vector<std::shared_ptr<SGB_GROUP_ENTRY>> entries;
|
||||||
|
|
||||||
|
SGB_GROUP( char* buf, SGB_FILE* file, uint32_t offset )
|
||||||
|
{
|
||||||
|
parent = file;
|
||||||
|
header = *reinterpret_cast<SGB_GROUP_HEADER*>( buf + offset );
|
||||||
|
name = std::string( buf + offset + header.nameOffset );
|
||||||
|
|
||||||
|
auto entriesOffset = offset + sizeof( header );
|
||||||
|
for( auto i = 0; i < header.entryCount; ++i )
|
||||||
|
{
|
||||||
|
auto entryOffset = entriesOffset + *reinterpret_cast<uint32_t*>( buf + ( entriesOffset + i * 4 ) );
|
||||||
|
|
||||||
|
auto type = *reinterpret_cast<uint32_t*>( buf + entryOffset );
|
||||||
|
if( type == SgbGroupEntryType::Model )
|
||||||
|
{
|
||||||
|
entries.push_back( std::make_shared<SGB_MODEL_ENTRY>( buf, entryOffset ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SGB_HEADER
|
||||||
|
{
|
||||||
|
char magic[4]; // SGB1
|
||||||
|
uint32_t fileSize;
|
||||||
|
uint32_t unknown1;
|
||||||
|
char magic2[4]; // SCN1
|
||||||
|
|
||||||
|
uint32_t unknown10;
|
||||||
|
int32_t sharedOffset;
|
||||||
|
uint32_t unknown18;
|
||||||
|
int32_t offset1C;
|
||||||
|
|
||||||
|
uint32_t unknown20;
|
||||||
|
uint32_t unknown24;
|
||||||
|
uint32_t unknown28;
|
||||||
|
uint32_t unknown2C;
|
||||||
|
|
||||||
|
uint32_t unknown30;
|
||||||
|
uint32_t unknown34;
|
||||||
|
uint32_t unknown38;
|
||||||
|
uint32_t unknown3C;
|
||||||
|
|
||||||
|
uint32_t unknown40;
|
||||||
|
uint32_t unknown44;
|
||||||
|
uint32_t unknown48;
|
||||||
|
uint32_t unknown4C;
|
||||||
|
|
||||||
|
uint32_t unknown50;
|
||||||
|
uint32_t unknown54;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SGB_FILE
|
||||||
|
{
|
||||||
|
SGB_HEADER header;
|
||||||
|
std::vector<SGB_GROUP> entries;
|
||||||
|
|
||||||
|
SGB_FILE( char* buf )
|
||||||
|
{
|
||||||
|
constexpr int baseOffset = 0x14;
|
||||||
|
header = *reinterpret_cast<SGB_HEADER*>( buf );
|
||||||
|
|
||||||
|
if( strncmp( &header.magic[0], "SGB1", 4 ) != 0 || strncmp( &header.magic2[0], "SCN1", 4 ) != 0 )
|
||||||
|
throw std::runtime_error( "Unable to load SGB File!" );
|
||||||
|
|
||||||
|
auto group = SGB_GROUP( buf, this, baseOffset + header.sharedOffset );
|
||||||
|
//auto group2 = SGB_GROUP( buf, this, baseOffset + header.offset1C );
|
||||||
|
entries.push_back( group );
|
||||||
|
//entries.push_back( group2 );
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // !_SGB_H
|
Loading…
Add table
Reference in a new issue