2018-02-26 23:50:50 +01:00
|
|
|
#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;
|
|
|
|
|
|
|
|
|
2019-10-21 23:24:26 +02:00
|
|
|
enum SgbDataType : uint32_t
|
2018-02-26 23:50:50 +01:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
Unknown0008 = 0x0008,
|
|
|
|
Group = 0x0100,
|
2018-02-26 23:50:50 +01:00
|
|
|
};
|
|
|
|
|
2019-10-21 23:24:26 +02:00
|
|
|
enum SgbGroupEntryType : uint32_t
|
2018-02-26 23:50:50 +01:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
Model = 0x01,
|
2019-04-11 19:06:27 +10:00
|
|
|
Gimmick = 0x06,
|
2018-02-26 23:50:50 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct SGB_GROUP_HEADER
|
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
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;
|
2018-02-26 23:50:50 +01:00
|
|
|
};
|
|
|
|
|
2019-04-11 19:06:27 +10:00
|
|
|
struct SGB_GROUP1C_HEADER
|
|
|
|
{
|
|
|
|
SgbDataType type;
|
|
|
|
int32_t nameOffset;
|
|
|
|
uint32_t unknown08;
|
|
|
|
|
|
|
|
int32_t entryCount;
|
|
|
|
uint32_t unknown14;
|
|
|
|
int32_t modelFileOffset;
|
|
|
|
vec3 unknownFloat3;
|
|
|
|
vec3 unknownFloat3_2;
|
|
|
|
int32_t stateOffset;
|
|
|
|
int32_t modelFileOffset2;
|
|
|
|
uint32_t unknown3;
|
|
|
|
float unknown4;
|
|
|
|
int32_t nameOffset2;
|
|
|
|
vec3 unknownFloat3_3;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SGB_GROUP1C_ENTRY
|
|
|
|
{
|
|
|
|
uint32_t unk;
|
|
|
|
uint32_t unk2;
|
|
|
|
int32_t nameOffset;
|
|
|
|
uint32_t index;
|
|
|
|
uint32_t unk3;
|
|
|
|
int32_t modelFileOffset;
|
|
|
|
};
|
|
|
|
|
2018-02-26 23:50:50 +01:00
|
|
|
struct SGB_GROUP_ENTRY
|
|
|
|
{
|
|
|
|
public:
|
2018-08-29 21:40:59 +02:00
|
|
|
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()
|
|
|
|
{
|
|
|
|
};
|
2018-02-26 23:50:50 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct SGB_ENTRY_HEADER
|
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
SgbGroupEntryType type;
|
|
|
|
uint32_t unknown2;
|
|
|
|
int32_t nameOffset;
|
|
|
|
vec3 translation;
|
|
|
|
vec3 rotation;
|
|
|
|
vec3 scale;
|
2018-02-26 23:50:50 +01:00
|
|
|
};
|
|
|
|
|
2019-10-21 23:24:26 +02:00
|
|
|
struct SGB_MODEL_HEADER : public SGB_ENTRY_HEADER
|
2018-02-26 23:50:50 +01:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
int32_t modelFileOffset;
|
|
|
|
int32_t collisionFileOffset;
|
2018-02-26 23:50:50 +01:00
|
|
|
};
|
|
|
|
|
2019-10-21 23:24:26 +02:00
|
|
|
struct SGB_MODEL_ENTRY : public SGB_GROUP_ENTRY
|
2018-02-26 23:50:50 +01:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
SGB_MODEL_HEADER header;
|
|
|
|
SgbGroupEntryType type;
|
|
|
|
std::string name;
|
|
|
|
std::string modelFileName;
|
|
|
|
std::string collisionFileName;
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
SGB_MODEL_ENTRY( char* buf, size_t offset, SgbGroupEntryType type )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2019-04-11 19:06:27 +10:00
|
|
|
this->type = type;
|
2018-08-29 21:40:59 +02:00
|
|
|
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 );
|
|
|
|
}
|
2018-02-26 23:50:50 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct SGB_GROUP
|
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
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 fileSize, 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 ) ) );
|
|
|
|
if( entryOffset > fileSize )
|
|
|
|
throw std::runtime_error( "SGB_GROUP entry offset was larger than SGB file size!" );
|
|
|
|
auto type = *reinterpret_cast< uint32_t* >( buf + entryOffset );
|
2019-04-11 19:06:27 +10:00
|
|
|
if( type == SgbGroupEntryType::Model || type == SgbGroupEntryType::Gimmick )
|
2018-02-26 23:50:50 +01:00
|
|
|
{
|
2019-04-11 19:06:27 +10:00
|
|
|
entries.push_back( std::make_shared< SGB_MODEL_ENTRY >( buf, entryOffset, ( SgbGroupEntryType )type ) );
|
2018-02-26 23:50:50 +01:00
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// std::cout << "\t\tUnknown SGB entry! Group: " << name << " type: " << type << " index: " << i << " entryOffset: " << entryOffset << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-02-26 23:50:50 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct SGB_HEADER
|
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
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 statesOffset;
|
|
|
|
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;
|
2018-02-26 23:50:50 +01:00
|
|
|
};
|
|
|
|
|
2022-02-16 22:18:55 +01:00
|
|
|
enum eCollisionState
|
|
|
|
{
|
|
|
|
NoChange = 0x0,
|
|
|
|
On = 0x1,
|
|
|
|
Off = 0x2,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-03-04 00:16:44 +01:00
|
|
|
struct SGB_STATE_HEADER
|
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
uint32_t id;
|
|
|
|
uint32_t nameOffset;
|
2022-02-16 22:18:55 +01:00
|
|
|
int Binders;
|
|
|
|
int BinderCount;
|
|
|
|
int BinaryAssetPath;
|
|
|
|
int Binary;
|
|
|
|
int BinaryCount;
|
|
|
|
uint32_t TimelineID;
|
|
|
|
int8_t AutoPlay;
|
|
|
|
int8_t LoopPlayback;
|
|
|
|
uint8_t Padding00[2];
|
|
|
|
eCollisionState CollisionState;
|
|
|
|
uint32_t Reserved[1];
|
2018-03-04 00:16:44 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct SGB_STATE_ENTRY
|
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
SGB_STATE_HEADER header;
|
|
|
|
std::string name;
|
|
|
|
|
|
|
|
SGB_STATE_ENTRY( char* buf )
|
|
|
|
{
|
|
|
|
header = *reinterpret_cast< SGB_STATE_HEADER* >( buf );
|
|
|
|
name = std::string( buf + header.nameOffset );
|
|
|
|
}
|
2018-03-04 00:16:44 +01:00
|
|
|
};
|
|
|
|
|
2018-02-26 23:50:50 +01:00
|
|
|
struct SGB_FILE
|
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
SGB_HEADER header;
|
|
|
|
std::vector< SGB_GROUP > entries;
|
|
|
|
std::vector< SGB_STATE_ENTRY > stateEntries;
|
|
|
|
|
|
|
|
SGB_FILE()
|
|
|
|
{
|
|
|
|
memset( &header, 0, sizeof( header ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
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!" );
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
auto group = SGB_GROUP( buf, this, header.fileSize, baseOffset + header.sharedOffset );
|
|
|
|
entries.push_back( group );
|
|
|
|
auto group2 = SGB_GROUP( buf, this, header.fileSize, baseOffset + header.offset1C );
|
|
|
|
entries.push_back( group2 );
|
|
|
|
uint32_t stateCount = *reinterpret_cast< uint32_t* >( buf + baseOffset + header.statesOffset + 4 );
|
|
|
|
if( stateCount > 0 )
|
2018-02-26 23:50:50 +01:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
stateCount = stateCount;
|
2021-11-27 00:53:57 +01:00
|
|
|
for( size_t i = 0; i < stateCount; ++i )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
|
|
|
auto state = SGB_STATE_ENTRY( buf + baseOffset + header.statesOffset + 8 + i * sizeof( SGB_STATE_HEADER ) );
|
|
|
|
stateEntries.push_back( state );
|
|
|
|
std::cout << state.name << "\n";
|
|
|
|
}
|
2018-02-26 23:50:50 +01:00
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
|
|
|
catch( std::exception& e )
|
|
|
|
{
|
|
|
|
std::cout << e.what() << "\n";
|
|
|
|
}
|
|
|
|
};
|
2018-02-26 23:50:50 +01:00
|
|
|
};
|
|
|
|
|
2019-04-11 19:06:27 +10:00
|
|
|
#endif // !_SGB_H
|