From 04c53a9181e9ea728fb33d51b8ee16204aa0d938 Mon Sep 17 00:00:00 2001 From: Tahir Akhlaq Date: Mon, 16 Oct 2017 15:47:48 +0100 Subject: [PATCH 01/11] added list.pcb file mapping - added LGB parser (all credit for LGB to contributor, lgb.h is simply their work ported to c++) - todo: correct object placement --- src/tools/pcb_reader/lgb.h | 267 ++++++++++++++++++++++++++++++++++ src/tools/pcb_reader/main.cpp | 170 +++++++++++++--------- src/tools/pcb_reader/pcb.h | 29 +++- 3 files changed, 395 insertions(+), 71 deletions(-) create mode 100644 src/tools/pcb_reader/lgb.h diff --git a/src/tools/pcb_reader/lgb.h b/src/tools/pcb_reader/lgb.h new file mode 100644 index 00000000..091ae3b0 --- /dev/null +++ b/src/tools/pcb_reader/lgb.h @@ -0,0 +1,267 @@ +#ifndef _LGB_H +#define _LGB_H + +#include +#include +#include +#include +#include +#include + +// all credit to +// https://github.com/ufx/SaintCoinach/blob/master/SaintCoinach/Graphics/Lgb/ +// this is simply their work ported to c++ since we dont c# +struct LGB_FILE; +struct LGB_FILE_HEADER; +struct LGB_GROUP; +struct LGB_GROUP_HEADER; + +struct vec3 +{ + float x, y, z; +}; + +enum class LgbEntryType : uint32_t +{ + BgParts = 1, + Light = 3, + Vfx = 4, + PositionMarker = 5, + Gimmick = 6, + SharedGroup6 = 6,// secondary variable is set to 2 + Sound = 7, + EventNpc = 8, + BattleNpc = 9, + Aetheryte = 12, + EnvSpace = 13, + Gathering = 14, + SharedGroup15 = 15,// secondary variable is set to 13 + Treasure = 16, + Weapon = 39, + PopRange = 40, + ExitRange = 41, + MapRange = 43, + NaviMeshRange = 44, + EventObject = 45, + EnvLocation = 47, + EventRange = 49, + QuestMarker = 51, + CollisionBox = 57, + DoorRange = 58, + LineVfx = 59, + ClientPath = 65, + ServerPath = 66, + GimmickRange = 67, + TargetMarker = 68, + ChairMarker = 69, + ClickableRange = 70, + PrefetchRange = 71, + FateRange = 72, + SphereCastRange = 75, +}; + +struct LGB_BGPARTS_HEADER +{ + LgbEntryType type; + uint32_t unknown2; + uint32_t nameOffset; + vec3 translation; + vec3 rotation; + vec3 scale; + uint32_t modelFileOffset; + uint32_t collisionFileOffset; + uint32_t unknown4; + uint32_t unknown5; + uint32_t unknown6; + uint32_t unknown7; + uint32_t unknown8; + 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 +{ +public: + LGB_BGPARTS_HEADER header; + std::string name; + std::string modelFileName; + std::string collisionFileName; + LGB_BGPARTS_ENTRY(){}; + LGB_BGPARTS_ENTRY(char* buf, uint32_t offset) + { + header = *reinterpret_cast(buf + offset); + name = std::string(buf + offset + header.nameOffset); + modelFileName = std::string(buf + offset + header.modelFileOffset); + collisionFileName = std::string(buf + offset + header.collisionFileOffset); + //std::cout << "BGPARTS_ENTRY " << name << "\n"; + //std::cout << " " << modelFileName << "\n"; + //std::cout << " " << collisionFileName << "\n"; + }; +}; + +struct LGB_GIMMICK_HEADER +{ + LgbEntryType type; + uint32_t unknown; + uint32_t nameOffset; + vec3 translation; + vec3 rotation; + vec3 scale; + uint32_t gimmickFileOffset; + char unknownBytes[100]; +}; + +class LGB_GIMMICK_ENTRY : public LGB_MODEL_ENTRY +{ +public: + LGB_GIMMICK_HEADER header; + std::string name; + + LGB_GIMMICK_ENTRY(char* buf, uint32_t offset) + { + header = *reinterpret_cast(buf + offset); + name = std::string(buf + offset + header.nameOffset); + }; +}; + +struct LGB_GROUP_HEADER +{ + uint32_t unknown; + int32_t groupNameOffset; + int32_t entriesOffset; + int32_t entryCount; + uint32_t unknown2; + uint32_t unknown3; + uint32_t unknown4; + uint32_t unknown5; + uint32_t unknown6; + uint32_t unknown7; + uint32_t unknown8; + uint32_t unknown9; + uint32_t unknown10; +}; + +struct LGB_GROUP +{ + LGB_FILE* parent; + LGB_GROUP_HEADER header; + std::string name; + std::vector> entries; + + LGB_GROUP(char* buf, LGB_FILE* parentStruct, uint32_t offset) + { + parent = parentStruct; + header = *reinterpret_cast(buf + offset); + name = std::string(buf + offset + header.groupNameOffset); + entries.resize(header.entryCount); + //std::cout << name << std::endl; + auto entriesOffset = offset + header.entriesOffset; + for( auto i = 0; i < header.entryCount; ++i) + { + auto entryOffset = entriesOffset + *reinterpret_cast(buf + (entriesOffset + i * 4)); + + try + { + auto type = *reinterpret_cast(buf + entryOffset); + LGB_MODEL_ENTRY* entry; + if (type == LgbEntryType::BgParts) + { + entries[i] = std::make_shared(buf, entryOffset); + } + else if (type == LgbEntryType::Gimmick) + { + entries[i] = std::make_shared(buf, entryOffset); + } + } + catch (std::exception& e) + { + std::cout << e.what() << std::endl; + } + } + }; +}; + +struct LGB_FILE_HEADER +{ + char magic[4]; // LGB 1 + uint32_t fileSize; + uint32_t unknown; + char magic2[4]; // LGP1 + uint32_t unknown2; + uint32_t unknown3; + uint32_t unknown4; + uint32_t unknown5; + int32_t groupCount; +}; + +struct LGB_FILE +{ + LGB_FILE_HEADER header; + std::vector groups; + + LGB_FILE(char* buf) + { + header = *reinterpret_cast(buf); + if (strncmp(&header.magic[0], "LGB1", 4) != 0 || strncmp(&header.magic2[0], "LGP1", 4) != 0) + throw std::exception("Invalid LGB file!"); + + //groups.resize(header.groupCount); + + auto baseOffset = sizeof(header); + for(auto i = 0; i < header.groupCount; ++i) + { + auto groupOffset = baseOffset + *reinterpret_cast(buf + (baseOffset + i * 4)); + auto group = LGB_GROUP(buf, this, groupOffset); + groups.push_back(group); + } + }; +}; + +std::map getLgbFiles(const std::string& dir) +{ + namespace fs = std::experimental::filesystem; + std::map fileMap; + for (const auto& path : fs::recursive_directory_iterator(dir)) + { + if (path.path().extension() == ".lgb") + { + auto strPath = path.path().string(); + auto f = fopen(strPath.c_str(), "rb"); + fseek(f, 0, SEEK_END); + auto size = ftell(f); + std::vector bytes(size); + rewind(f); + fread(bytes.data(), 1, size, f); + fclose(f); + try + { + LGB_FILE lgbFile(bytes.data()); + fileMap.insert(std::make_pair(strPath, lgbFile)); + } + catch (std::exception& e) + { + std::cout << "Unable to load " << strPath << std::endl; + } + } + } + return fileMap; +} +#endif \ No newline at end of file diff --git a/src/tools/pcb_reader/main.cpp b/src/tools/pcb_reader/main.cpp index 6da22cd5..3cb02fed 100644 --- a/src/tools/pcb_reader/main.cpp +++ b/src/tools/pcb_reader/main.cpp @@ -1,17 +1,41 @@ #include -#include -#include +#include +#include +#include #include "pcb.h" +#include "lgb.h" #include +namespace fs = std::experimental::filesystem; -int parseBlockEntry( char* data, std::vector& entries, int gOff ) +std::vector loadDir(const std::string& dir) +{ + std::vector files; + + auto fsDir = fs::current_path().append(fs::path(dir)); + std::cout << fsDir.string() << "\n"; + if (fs::exists(fsDir)) + { + for (const auto& entry : fs::directory_iterator(fsDir)) + { + auto filename = entry.path().filename(); + if (filename.string().find("~") == -1) + files.push_back(entry.path().string()); + if (filename.string().find("list") != std::string::npos) + std::cout << filename.string() << "\n"; + } + } + return files; +} + +int parseBlockEntry( char* data, std::vector& entries, int gOff, uint32_t& groupCount, LGB_BGPARTS_ENTRY& bgParts ) { int offset = 0; bool isgroup = true; while( isgroup ) { + groupCount++; PCB_BLOCK_ENTRY block_entry; memcpy( &block_entry.header, data + offset, sizeof( block_entry.header ) ); isgroup = block_entry.header.type == 0x30 ? true : false; @@ -20,14 +44,13 @@ int parseBlockEntry( char* data, std::vector& entries, int gOff if( isgroup ) { - parseBlockEntry( data + offset + 0x30, entries, gOff + offset ); + parseBlockEntry( data + offset + 0x30, entries, gOff + offset, groupCount, bgParts ); offset += block_entry.header.group_size; - } else { - printf( "\tnum_v16: %i, num_indices: %i, num_vertices: %i\n\n", - block_entry.header.num_v16, block_entry.header.num_indices, block_entry.header.num_vertices ); + //printf( "\tnum_v16: %i, num_indices: %i, num_vertices: %i\n\n", + // block_entry.header.num_v16, block_entry.header.num_indices, block_entry.header.num_vertices ); int doffset = sizeof( block_entry.header ) + offset; uint16_t block_size = sizeof( block_entry.header ) + block_entry.header.num_vertices * 3 * 4 + @@ -58,18 +81,18 @@ int parseBlockEntry( char* data, std::vector& entries, int gOff } entries.push_back( block_entry ); - /* printf( "Vertices: \n" ); + //printf( "Vertices: \n" ); for( auto& entry1 : block_entry.data.vertices ) { - printf( "\t %f, %f, %f \n", - entry1.x, entry1.y, entry1.z ); + // printf( "\t %f, %f, %f \n", + // entry1.x, entry1.y, entry1.z ); } float x_base = abs( float( block_entry.header.x1 - block_entry.header.x ) ); float y_base = abs( float( block_entry.header.y1 - block_entry.header.y ) ); float z_base = abs( float( block_entry.header.z1 - block_entry.header.z ) ); - printf( "Vertices I16: \n" ); + //printf( "Vertices I16: \n" ); for( auto& entry1 : block_entry.data.vertices_i16 ) { uint16_t var1 = entry1.x; @@ -78,12 +101,12 @@ int parseBlockEntry( char* data, std::vector& entries, int gOff float x = ( var1 ); float y = ( var2 ); float z = ( var3 ); - printf( "\t%f, ", ( x / 0xFFFF ) * x_base + block_entry.header.x ); - printf( "%f, ", ( y / 0xFFFF ) * y_base + block_entry.header.y ); - printf( "%f ", ( z / 0xFFFF ) * z_base + block_entry.header.z ); - printf( "\n" ); + //printf( "\t%f, ", ( x / 0xFFFF ) * x_base + block_entry.header.x ); + //printf( "%f, ", ( y / 0xFFFF ) * y_base + block_entry.header.y ); + //printf( "%f ", ( z / 0xFFFF ) * z_base + block_entry.header.z ); + //printf( "\n" ); - }*/ + } } } @@ -96,56 +119,69 @@ int main() uint32_t offset = 0; //r1f1_b1_dor00.pcb + PCB_LIST_FILE listFile; + int groupsCount = 0; + //auto list = loadDir("bg/ffxiv/roc_r1/collision"); + auto lgbFiles = getLgbFiles("bg/ffxiv/roc_r1/"); - //std::string filename( "f1h0_s_rof0003.pcb" ); - std::string filename( "tr0924.pcb" ); - FILE *fp = nullptr; - fp = fopen( filename.c_str(), "rb" ); - if( fp == nullptr ) + std::cout << "Loaded " << lgbFiles.size() << " LGB files" << std::endl; + + uint64_t vertexCount = 0; + std::map groupCounts; + for (const auto& pair : lgbFiles) { - return 0; - } - - fseek( fp, 0, SEEK_END ); - int32_t size = ftell( fp ); - data = new char[size]; - rewind( fp ); - fread( data, sizeof( char ), size, fp ); - fclose( fp ); - - PCB_FILE pcb_file; - memcpy( &pcb_file.header, data, sizeof( pcb_file.header ) ); - offset += sizeof( pcb_file.header ); - - - - std::vector entries; - - bool isgroup = true; - while( isgroup ) - { - PCB_BLOCK_ENTRY block_entry; - memcpy( &block_entry.header, data + offset, sizeof( block_entry.header ) ); - isgroup = block_entry.header.type == 0x30 ? true : false; - - //printf( "BLOCKHEADER_%X: type: %i, group_size: %i\n", offset, block_entry.header.type, block_entry.header.group_size ); - - if( isgroup ) + for (const auto& group : pair.second.groups) { - std::vector data_block( block_entry.header.group_size ); - memcpy( &data_block[0], data + offset, block_entry.header.group_size ); - parseBlockEntry( (char*)&data_block[0] + 0x30, entries, offset ); - offset += block_entry.header.group_size; - } - else - { - parseBlockEntry( data + offset, entries, offset ); - } - + uint32_t bgPartsCount = 0; + std::cout << group.name << "\n"; + for (auto entry : group.entries) + { + if (dynamic_cast(entry.get())) + bgPartsCount++; + } + for (auto entry : group.entries) + { + auto bgParts = dynamic_cast(entry.get()); + if (!bgParts) + continue; + const auto& filename = bgParts->collisionFileName; + std::cout << filename << std::endl; + //std::string filename( "f1h0_s_rof0003.pcb" ); + //std::string filename("tr0924.pcb"); + FILE *fp = nullptr; + fp = fopen(filename.c_str(), "rb"); + if (fp == nullptr) + { + return 0; + } + + fseek(fp, 0, SEEK_END); + int32_t size = ftell(fp); + data = new char[size]; + rewind(fp); + fread(data, sizeof(char), size, fp); + fclose(fp); + + PCB_FILE pcb_file; + memcpy(&pcb_file.header, data, sizeof(pcb_file.header)); + auto offset = sizeof(pcb_file.header); + try + { + parseBlockEntry(data + offset, pcb_file.entries, offset, groupCounts[filename], *bgParts); + } + catch(std::exception& e) + { + std::cout << filename << " " << e.what() << "\n"; + } + } + } } + return 0; +} +/* for( uint16_t i = 0; i <= pcb_file.header.num_entries; i++ ) { PCB_BLOCK_ENTRY block_entry; @@ -187,7 +223,7 @@ int main() rest = 0x10 - rest; } offset += rest ; - + pcb_file.entries.push_back( block_entry ); } @@ -197,14 +233,14 @@ int main() fclose( fp_out1 ); FILE* fp_out = fopen( std::string( filename + ".plain" ).c_str(), "w+" ); - + fprintf( fp_out, "HEADER: num_entries: %i, total_indices: %i, unknown_1: %i\n\n", pcb_file.header.num_entries, pcb_file.header.total_indices, pcb_file.header.unknown_1 ); int block_cnt = 0; for( auto& entry : pcb_file.entries ) { - - fprintf( fp_out, "BLOCKHEADER_%i: type: %i, group_size: %i\n ", + + fprintf( fp_out, "BLOCKHEADER_%i: type: %i, group_size: %i\n ", block_cnt, entry.header.type, entry.header.group_size ); fprintf( fp_out, "\tAABB: x: %f, y: %f, z: %f\n ", entry.header.x, entry.header.y, entry.header.z ); @@ -219,7 +255,7 @@ int main() fprintf( fp_out, "\t %f, %f, %f \n", entry1.x, entry1.y, entry1.z ); } - + float x_base = abs( float( entry.header.x1 - entry.header.x ) ); float y_base = abs( float( entry.header.y1 - entry.header.y ) ); float z_base = abs( float( entry.header.z1 - entry.header.z ) ); @@ -240,7 +276,7 @@ int main() } - + fprintf( fp_out, "Indices: \n" ); @@ -253,6 +289,4 @@ int main() } fclose( fp_out ); - - return 0; -} +*/ \ No newline at end of file diff --git a/src/tools/pcb_reader/pcb.h b/src/tools/pcb_reader/pcb.h index a9c65e2e..0139c431 100644 --- a/src/tools/pcb_reader/pcb.h +++ b/src/tools/pcb_reader/pcb.h @@ -1,3 +1,6 @@ +#ifndef _PCB_H +#define _PCB_H + #include #include @@ -6,7 +9,7 @@ struct PCB_HEADER uint32_t unknown_1; uint32_t unknown_2; uint32_t num_entries; // count starts at 0 - uint32_t total_indices; + uint32_t total_indices; uint64_t padding; }; @@ -15,13 +18,13 @@ struct PCB_BLOCK_HEADER uint32_t type; // 0 for entry, 0x30 for group uint32_t group_size; // when group size in bytes for the group block // bounding box - float x; + float x; float y; float z; float x1; float y1; float z1; - // number of vertices packed into 16 bit + // number of vertices packed into 16 bit uint16_t num_v16; // number of indices uint16_t num_indices; @@ -67,3 +70,23 @@ struct PCB_FILE PCB_HEADER header; std::vector< PCB_BLOCK_ENTRY > entries; }; + +struct PCB_LIST_ENTRY +{ + uint32_t id; + float x, y, z, x2, y2, z2, rot; +}; + +struct PCB_LIST_BASE_ENTRY +{ + float x, y, z, x2, y2, z2, rot; +}; + +struct PCB_LIST_FILE +{ + uint32_t count; + PCB_LIST_BASE_ENTRY entry; + std::vector entries; +}; + +#endif \ No newline at end of file From 87447d1a73fb048978204b7b27f42d5d60354801 Mon Sep 17 00:00:00 2001 From: Tahir Akhlaq Date: Mon, 16 Oct 2017 20:31:47 +0100 Subject: [PATCH 02/11] added wavefront obj dump (doesnt work yet) --- src/tools/pcb_reader/lgb.h | 15 +- src/tools/pcb_reader/main.cpp | 304 ++++++++++++++------------------- src/tools/pcb_reader/matrix4.h | 86 ++++++++++ src/tools/pcb_reader/pcb.h | 1 - src/tools/pcb_reader/vec3.h | 31 ++++ 5 files changed, 257 insertions(+), 180 deletions(-) create mode 100644 src/tools/pcb_reader/matrix4.h create mode 100644 src/tools/pcb_reader/vec3.h diff --git a/src/tools/pcb_reader/lgb.h b/src/tools/pcb_reader/lgb.h index 091ae3b0..a4ef3977 100644 --- a/src/tools/pcb_reader/lgb.h +++ b/src/tools/pcb_reader/lgb.h @@ -1,6 +1,8 @@ #ifndef _LGB_H #define _LGB_H +#include "matrix4.h" +#include "vec3.h" #include #include #include @@ -16,11 +18,6 @@ struct LGB_FILE_HEADER; struct LGB_GROUP; struct LGB_GROUP_HEADER; -struct vec3 -{ - float x, y, z; -}; - enum class LgbEntryType : uint32_t { BgParts = 1, @@ -174,7 +171,7 @@ struct LGB_GROUP entries.resize(header.entryCount); //std::cout << name << std::endl; 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(buf + (entriesOffset + i * 4)); @@ -190,10 +187,14 @@ struct LGB_GROUP { entries[i] = std::make_shared(buf, entryOffset); } + else + { + entries[i] = nullptr; + } } catch (std::exception& e) { - std::cout << e.what() << std::endl; + std::cout << name << " " << e.what() << std::endl; } } }; diff --git a/src/tools/pcb_reader/main.cpp b/src/tools/pcb_reader/main.cpp index 3cb02fed..52b2686a 100644 --- a/src/tools/pcb_reader/main.cpp +++ b/src/tools/pcb_reader/main.cpp @@ -29,13 +29,12 @@ std::vector loadDir(const std::string& dir) return files; } -int parseBlockEntry( char* data, std::vector& entries, int gOff, uint32_t& groupCount, LGB_BGPARTS_ENTRY& bgParts ) +int parseBlockEntry( char* data, std::vector& entries, int gOff ) { int offset = 0; bool isgroup = true; while( isgroup ) { - groupCount++; PCB_BLOCK_ENTRY block_entry; memcpy( &block_entry.header, data + offset, sizeof( block_entry.header ) ); isgroup = block_entry.header.type == 0x30 ? true : false; @@ -44,13 +43,13 @@ int parseBlockEntry( char* data, std::vector& entries, int gOff if( isgroup ) { - parseBlockEntry( data + offset + 0x30, entries, gOff + offset, groupCount, bgParts ); + parseBlockEntry( data + offset + 0x30, entries, gOff + offset ); offset += block_entry.header.group_size; } else { - //printf( "\tnum_v16: %i, num_indices: %i, num_vertices: %i\n\n", - // block_entry.header.num_v16, block_entry.header.num_indices, block_entry.header.num_vertices ); + /* printf( "\tnum_v16: %i, num_indices: %i, num_vertices: %i\n\n", + block_entry.header.num_v16, block_entry.header.num_indices, block_entry.header.num_vertices );*/ int doffset = sizeof( block_entry.header ) + offset; uint16_t block_size = sizeof( block_entry.header ) + block_entry.header.num_vertices * 3 * 4 + @@ -80,39 +79,35 @@ int parseBlockEntry( char* data, std::vector& entries, int gOff doffset += size_indexbuffer; } entries.push_back( block_entry ); - - //printf( "Vertices: \n" ); - for( auto& entry1 : block_entry.data.vertices ) - { - // printf( "\t %f, %f, %f \n", - // entry1.x, entry1.y, entry1.z ); - } - - float x_base = abs( float( block_entry.header.x1 - block_entry.header.x ) ); - float y_base = abs( float( block_entry.header.y1 - block_entry.header.y ) ); - float z_base = abs( float( block_entry.header.z1 - block_entry.header.z ) ); - - //printf( "Vertices I16: \n" ); - for( auto& entry1 : block_entry.data.vertices_i16 ) - { - uint16_t var1 = entry1.x; - uint16_t var2 = entry1.y; - uint16_t var3 = entry1.z; - float x = ( var1 ); - float y = ( var2 ); - float z = ( var3 ); - //printf( "\t%f, ", ( x / 0xFFFF ) * x_base + block_entry.header.x ); - //printf( "%f, ", ( y / 0xFFFF ) * y_base + block_entry.header.y ); - //printf( "%f ", ( z / 0xFFFF ) * z_base + block_entry.header.z ); - //printf( "\n" ); - - } } } return 0; } +void toFile(const std::string& fileName, const std::vector& vertices, const std::vector& indices) +{ + auto fp_out = fopen(fileName.c_str(), "w"); + if (fp_out) + { + fprintf(fp_out, "\n"); + fclose(fp_out); + } + fp_out = fopen(fileName.c_str(), "ab+"); + if (fp_out) + { + for (const auto& v : vertices) + { + fprintf(fp_out, "v %f %f %f\n", v.x, v.y, v.z); + } + for (auto i = 2002; i < indices.size(); i += 3) + { + fprintf(fp_out, "f %i %i %i\n", indices[i], indices[i + 1], indices[i + 2]); + } + fclose(fp_out); + } +} + int main() { char *data; @@ -126,167 +121,132 @@ int main() std::cout << "Loaded " << lgbFiles.size() << " LGB files" << std::endl; - uint64_t vertexCount = 0; std::map groupCounts; + std::map pcbFiles; + + int total_vertices = 0; + int total_indices = 0; + int max_index = 0; + + std::vector vertices; + std::vector indices; + for (const auto& pair : lgbFiles) { + std::cout << "FILE " << pair.first << "\n"; for (const auto& group : pair.second.groups) { + uint32_t groupEntryCount = 0; uint32_t bgPartsCount = 0; - std::cout << group.name << "\n"; + //std::cout << "GROUP " << group.name << "\n"; for (auto entry : group.entries) { if (dynamic_cast(entry.get())) bgPartsCount++; } - for (auto entry : group.entries) + for (auto pEntry : group.entries) { - auto bgParts = dynamic_cast(entry.get()); - if (!bgParts) + if (!pEntry) continue; - const auto& filename = bgParts->collisionFileName; - std::cout << filename << std::endl; - //std::string filename( "f1h0_s_rof0003.pcb" ); - //std::string filename("tr0924.pcb"); - FILE *fp = nullptr; - fp = fopen(filename.c_str(), "rb"); - if (fp == nullptr) + auto pBgParts = dynamic_cast(pEntry.get()); + + if (!pBgParts || pBgParts->collisionFileName.empty()) + continue; + + auto filename = pBgParts->collisionFileName; + if(!groupCounts[filename]) + std::cout << "GROUP " << group.name << " " << pBgParts->collisionFileName << "\n"; + + PCB_FILE pcb_file = PCB_FILE(); + if(pcbFiles.find(filename) == pcbFiles.end()) { - return 0; + FILE *fp = nullptr; + fp = fopen(filename.c_str(), "rb"); + if (fp == nullptr) + return 0; + + fseek(fp, 0, SEEK_END); + int32_t size = ftell(fp); + data = new char[size]; + rewind(fp); + fread(data, 1, size, fp); + fclose(fp); + + memcpy(&pcb_file.header, data, sizeof(pcb_file.header)); + auto offset = sizeof(pcb_file.header); + try + { + parseBlockEntry(data + offset, pcb_file.entries, offset); + } + catch(std::exception& e) + { + std::cout << "Unable to parse " << filename << " " << e.what() << "\n"; + } + } + else + { + pcb_file = pcbFiles[filename]; } - fseek(fp, 0, SEEK_END); - int32_t size = ftell(fp); - data = new char[size]; - rewind(fp); - fread(data, sizeof(char), size, fp); - fclose(fp); + for( auto &entry : pcb_file.entries ) + { + total_vertices += entry.header.num_vertices; + total_vertices += entry.header.num_v16; - PCB_FILE pcb_file; - memcpy(&pcb_file.header, data, sizeof(pcb_file.header)); - auto offset = sizeof(pcb_file.header); - try - { - parseBlockEntry(data + offset, pcb_file.entries, offset, groupCounts[filename], *bgParts); - } - catch(std::exception& e) - { - std::cout << filename << " " << e.what() << "\n"; + total_indices += entry.header.num_indices; + /* + const auto& translationVec = pBgParts->header.translation; + const auto& rotationVec = pBgParts->header.rotation; + const auto& scaleVec = pBgParts->header.scale; + + auto xrot = matrix4::rotateX(rotationVec.x); + auto yrot = matrix4::rotateY(rotationVec.y); + auto zrot = matrix4::rotateZ(rotationVec.z); + */ + for( auto &vertex_list : entry.data.vertices ) + { + vec3 v; + v.x = vertex_list.x; + v.y = vertex_list.y; + v.z = vertex_list.z; + vertices.push_back( v ); + } + + float x_base = abs( float( entry.header.x1 - entry.header.x ) ); + float y_base = abs( float( entry.header.y1 - entry.header.y ) ); + float z_base = abs( float( entry.header.z1 - entry.header.z ) ); + + for( const auto &link : entry.data.vertices_i16 ) + { + vec3 v(float( link.x ) / 0xFFFF, float( link.y ) / 0xFFFF, float( link.z ) / 0xFFFF); + + float x = float( link.x ); + float y = float( link.y ); + float z = float( link.z ); + v.x = ( x / 0xFFFF ) * x_base + entry.header.x; + v.y = ( y / 0xFFFF ) * y_base + entry.header.y; + v.z = ( z / 0xFFFF ) * z_base + entry.header.z; + vertices.push_back( v ); + } + + + for( const auto &index : entry.data.indices ) + { + indices.push_back( int( index.index[0] ) + max_index ); + indices.push_back( int( index.index[1] ) + max_index ); + indices.push_back( int( index.index[2] ) + max_index ); + //std::cout << std::to_string( index.unknown[0] )<< " " << std::to_string( index.unknown[1] )<< " " << std::to_string( index.unknown[2]) << std::endl; + } + max_index = vertices.size(); } + //toFile("test.obj", vertices, indices); + //break; } } } + toFile("test.obj", vertices, indices); + std::cout << "vertices " << vertices.size() << " indices " << indices.size() / 3 << " expected indices " << vertices.size() << " total " << total_indices << "\n"; return 0; -} - -/* - for( uint16_t i = 0; i <= pcb_file.header.num_entries; i++ ) - { - PCB_BLOCK_ENTRY block_entry; - memcpy( &block_entry.header, data + offset, sizeof( block_entry.header ) ); - offset += sizeof( block_entry.header ); - - uint16_t block_size = sizeof( block_entry.header ) + - block_entry.header.num_vertices * 3 * 4 + - block_entry.header.num_v16 * 6 + - block_entry.header.num_indices * 6; - - if( block_entry.header.num_vertices != 0 ) - { - block_entry.data.vertices.resize( block_entry.header.num_vertices ); - - int32_t size_vertexbuffer = block_entry.header.num_vertices * 3; - memcpy( &block_entry.data.vertices[0], data + offset, size_vertexbuffer * 4 ); - offset += size_vertexbuffer * 4; - } - if( block_entry.header.num_v16 != 0 ) - { - block_entry.data.vertices_i16.resize( block_entry.header.num_v16 ); - int32_t size_unknownbuffer = block_entry.header.num_v16 * 6; - memcpy( &block_entry.data.vertices_i16[0], data + offset, size_unknownbuffer ); - offset += block_entry.header.num_v16 * 6; - } - if( block_entry.header.num_indices != 0 ) - { - block_entry.data.indices.resize( block_entry.header.num_indices ); - int32_t size_indexbuffer = block_entry.header.num_indices * 6; - memcpy( &block_entry.data.indices[0], data + offset, size_indexbuffer ); - offset += size_indexbuffer; - } - - // blocks always align to 16 bytes + 8 bytes padding till the next block - int rest = ( offset % 16 ); - if( rest > 0 ) - { - rest = 0x10 - rest; - } - offset += rest ; - - - pcb_file.entries.push_back( block_entry ); - } - - FILE* fp_out1 = fopen( std::string( filename + ".plain" ).c_str(), "w" ); - fprintf( fp_out1, ""); - fclose( fp_out1 ); - - FILE* fp_out = fopen( std::string( filename + ".plain" ).c_str(), "w+" ); - - fprintf( fp_out, "HEADER: num_entries: %i, total_indices: %i, unknown_1: %i\n\n", pcb_file.header.num_entries, pcb_file.header.total_indices, pcb_file.header.unknown_1 ); - - int block_cnt = 0; - for( auto& entry : pcb_file.entries ) - { - - fprintf( fp_out, "BLOCKHEADER_%i: type: %i, group_size: %i\n ", - block_cnt, entry.header.type, entry.header.group_size ); - fprintf( fp_out, "\tAABB: x: %f, y: %f, z: %f\n ", - entry.header.x, entry.header.y, entry.header.z ); - fprintf( fp_out, "\t\t x1: %f, y1: %f, z1: %f\n ", - entry.header.x1, entry.header.y1, entry.header.z1 ); - fprintf( fp_out, "\tnum_v16: %i, num_indices: %i, num_vertices: %i\n\n", - entry.header.num_v16, entry.header.num_indices, entry.header.num_vertices ); - - fprintf( fp_out, "Vertices: \n"); - for( auto& entry1 : entry.data.vertices ) - { - fprintf( fp_out, "\t %f, %f, %f \n", - entry1.x, entry1.y, entry1.z ); - } - - float x_base = abs( float( entry.header.x1 - entry.header.x ) ); - float y_base = abs( float( entry.header.y1 - entry.header.y ) ); - float z_base = abs( float( entry.header.z1 - entry.header.z ) ); - - fprintf( fp_out, "Vertices I16: \n" ); - for( auto& entry1 : entry.data.vertices_i16 ) - { - uint16_t var1 = entry1.x; - uint16_t var2 = entry1.y; - uint16_t var3 = entry1.z; - float x = ( var1 ); - float y = ( var2 ); - float z = ( var3 ); - fprintf( fp_out, "\t%f, ", (x / 0xFFFF) * x_base + entry.header.x ); - fprintf( fp_out, "%f, ", (y / 0xFFFF) * y_base + entry.header.y ); - fprintf( fp_out, "%f ", (z / 0xFFFF) * z_base + entry.header.z ); - fprintf( fp_out, "\n"); - - } - - - - - fprintf( fp_out, "Indices: \n" ); - for( auto& entry1 : entry.data.indices ) - { - fprintf( fp_out, "\t %i, %i, %i - %x,%x,%x \n", - entry1.index[0], entry1.index[1], entry1.index[2], entry1.unknown[0], entry1.unknown[1], entry1.unknown[2] ); - } - fprintf( fp_out, "\n" ); - } - - fclose( fp_out ); -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/src/tools/pcb_reader/matrix4.h b/src/tools/pcb_reader/matrix4.h new file mode 100644 index 00000000..c19808e2 --- /dev/null +++ b/src/tools/pcb_reader/matrix4.h @@ -0,0 +1,86 @@ +#ifndef _MATRIX4_H +#define _MATRIX4_H + +#include + +// https://github.com/jpd002/Play--Framework/tree/master/include/math +struct matrix4 +{ + // 4x4 + float grid[16]; + matrix4() + { + memset(&grid[0], 0, sizeof(grid)); + } + + float operator()(int row, int col) const + { + return grid[(row * 4) + col]; + } + + float& operator()(int row, int col) + { + return grid[(row * 4) + col]; + } + static matrix4 rotateX(float angle) + { + matrix4 ret = matrix4(); + ret(0, 0) = 1.000000000f; + ret(1, 1) = cos(angle); + ret(1, 2) = -sin(angle); + ret(2, 1) = sin(angle); + ret(2, 2) = cos(angle); + ret(3, 3) = 1.000000000f; + return ret; + } + + static matrix4 rotateY(float angle) + { + matrix4 ret = matrix4(); + ret(0, 0) = cos(angle); + ret(0, 2) = sin(angle); + ret(1, 1) = 1.000000000f; + ret(2, 0) = -sin(angle); + ret(2, 2) = cos(angle); + ret(3, 3) = 1.000000000f; + return ret; + } + + static matrix4 rotateZ(float angle) + { + matrix4 ret = matrix4(); + ret(0, 0) = cos(angle); + ret(0, 1) = -sin(angle); + ret(1, 0) = sin(angle); + ret(1, 1) = cos(angle); + ret(2, 2) = 1.000000000f; + ret(3, 3) = 1.000000000f; + return ret; + } + + static matrix4 scale(float x, float y, float z) + { + matrix4 ret = matrix4(); + ret(0, 0) = x; + ret(1, 1) = y; + ret(2, 2) = z; + ret(3, 3) = 1; + + return ret; + } + + static matrix4 translate(float x, float y, float z) + { + matrix4 ret = matrix4(); + ret(0, 0) = 1; + ret(1, 1) = 1; + ret(2, 2) = 1; + ret(3, 3) = 1; + + ret(3, 0) = x; + ret(3, 1) = y; + ret(3, 2) = z; + return ret; + } +}; +#endif \ No newline at end of file diff --git a/src/tools/pcb_reader/pcb.h b/src/tools/pcb_reader/pcb.h index 0139c431..165d7f7e 100644 --- a/src/tools/pcb_reader/pcb.h +++ b/src/tools/pcb_reader/pcb.h @@ -88,5 +88,4 @@ struct PCB_LIST_FILE PCB_LIST_BASE_ENTRY entry; std::vector entries; }; - #endif \ No newline at end of file diff --git a/src/tools/pcb_reader/vec3.h b/src/tools/pcb_reader/vec3.h new file mode 100644 index 00000000..a8fdfbd1 --- /dev/null +++ b/src/tools/pcb_reader/vec3.h @@ -0,0 +1,31 @@ +#ifndef _VEC3_H +#define _VEC3_H + +#include +#include "matrix4.h" + +struct vec3 +{ + float x, y, z; + vec3() + { + x = 0.0f; + y = 0.0f; + z = 0.0f; + } + vec3(float x, float y, float z) + { + this->x = x; + this->y = y; + this->z = z; + }; +}; +static vec3 operator *(const vec3& lhs, const matrix4& rhs) +{ + vec3 ret; + ret.x = rhs(0, 0) * lhs.x + rhs(0, 1) * lhs.y + rhs(0, 2) * lhs.z; + ret.y = rhs(1, 0) * lhs.x + rhs(1, 1) * lhs.y + rhs(1, 2) * lhs.z; + ret.z = rhs(2, 0) * lhs.x + rhs(2, 1) * lhs.y + rhs(2, 2) * lhs.z; + return ret; +}; +#endif \ No newline at end of file From c7a864335f31d14f81e2e0c7b5e3743cbed1ff6f Mon Sep 17 00:00:00 2001 From: Mordred Date: Mon, 16 Oct 2017 23:54:27 +0200 Subject: [PATCH 03/11] hopefully fixed issues with pcb --- CMakeLists.txt | 1 + src/tools/pcb_reader/CMakeLists.txt | 15 +- src/tools/pcb_reader/main.cpp | 209 ++++++++++++++++++++++++++-- src/tools/pcb_reader/pcb.h | 1 + 4 files changed, 203 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e9a4b09..c153a1ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,3 +59,4 @@ add_subdirectory("src/servers") add_subdirectory("src/libraries/sapphire/datReader") add_subdirectory("src/tools/exd_common_gen") add_subdirectory("src/tools/quest_parser") +add_subdirectory("src/tools/pcb_reader") diff --git a/src/tools/pcb_reader/CMakeLists.txt b/src/tools/pcb_reader/CMakeLists.txt index 9bd07e39..6a314a46 100644 --- a/src/tools/pcb_reader/CMakeLists.txt +++ b/src/tools/pcb_reader/CMakeLists.txt @@ -6,18 +6,13 @@ include_directories("../") file(GLOB SERVER_PUBLIC_INCLUDE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*") file(GLOB SERVER_SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}*.cpp") -SET(Boost_USE_STATIC_LIBS ON) -set(Boost_INCLUDE_DIR /opt/build_libs/boost_1_60_0) -set(Boost_LIBRARY_DIR /opt/build_libs/boost_1_60_0/stage/lib) -set(SERVER_COMMON_DIR ../../servers/Server_Common) -find_package(Boost COMPONENTS log log_setup thread date_time filesystem system REQUIRED) -include_directories(${Boost_INCLUDE_DIR}) - -link_directories(${Boost_LIBRARY_DIR}) -link_directories(${SERVER_COMMON_DIR}) #set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ".") add_executable(pcb_parser2 ${SERVER_PUBLIC_INCLUDE_FILES} ${SERVER_SOURCE_FILES}) -target_link_libraries (pcb_parser2 server_common.a pthread mysqlclient dl z) +if (UNIX) + target_link_libraries (pcb_parser2 Common xivdat pthread mysqlclient dl z) +else() + target_link_libraries (pcb_parser2 Common xivdat libmysql zlib1) +endif() target_link_libraries(pcb_parser2 ${Boost_LIBRARIES} ${Boost_LIBRARIES}) diff --git a/src/tools/pcb_reader/main.cpp b/src/tools/pcb_reader/main.cpp index 52b2686a..d3372689 100644 --- a/src/tools/pcb_reader/main.cpp +++ b/src/tools/pcb_reader/main.cpp @@ -6,6 +6,13 @@ #include "pcb.h" #include "lgb.h" +#include +#include +#include +#include +#include +#include + #include namespace fs = std::experimental::filesystem; @@ -74,7 +81,7 @@ int parseBlockEntry( char* data, std::vector& entries, int gOff if( block_entry.header.num_indices != 0 ) { block_entry.data.indices.resize( block_entry.header.num_indices ); - int32_t size_indexbuffer = block_entry.header.num_indices * 6; + int32_t size_indexbuffer = block_entry.header.num_indices * 12; memcpy( &block_entry.data.indices[0], data + doffset, size_indexbuffer ); doffset += size_indexbuffer; } @@ -100,9 +107,10 @@ void toFile(const std::string& fileName, const std::vector& vertices, cons { fprintf(fp_out, "v %f %f %f\n", v.x, v.y, v.z); } - for (auto i = 2002; i < indices.size(); i += 3) + for (auto i = 0; i < indices.size(); i += 3) { - fprintf(fp_out, "f %i %i %i\n", indices[i], indices[i + 1], indices[i + 2]); + //if( indices[i]!= 0 || indices[i + 1] != 0 || indices[i+ 2] != 0) + fprintf(fp_out, "f %i %i %i\n", indices[i] + 1, indices[i + 1] + 1, indices[i + 2] + 1); } fclose(fp_out); } @@ -110,7 +118,169 @@ void toFile(const std::string& fileName, const std::vector& vertices, cons int main() { + + xiv::dat::GameData data1( "C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv" ); + xiv::exd::ExdData eData( data1 ); + + const xiv::dat::Cat& test = data1.get_category( "bg" ); + + auto &test_file = data1.get_file( "bg/ffxiv/sea_s1/fld/s1f5/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 stringList; + + uint32_t offset = list_offset + 0x14; + + for( ; ; ) + { + std::string entry( §ion[offset] ); + offset += entry.size() + 1; + if( entry.find( "bgcommon" ) == std::string::npos && entry.find( ".mdl" ) == std::string::npos && entry.find( ".pcb" ) != std::string::npos ) + { + //stringList.push_back( entry ); + } + + if( offset >= size ) + { + break; + } + } + + auto &test_file1 = data1.get_file( "bg/ffxiv/roc_r1/fld/r1f1/collision/list.pcb" ); + auto §ion1 = test_file1->access_data_sections().at( 0 ); + std::string path = "bg/ffxiv/roc_r1/fld/r1f1/collision/"; + int offset1 = 0x20; + for( ; ; ) + { + + uint16_t trId = *( uint16_t* ) §ion1[offset1]; + + char someString[200]; + sprintf( someString, "%str%04d.pcb", path.c_str(), trId ); + stringList.push_back( std::string( someString ) ); + std::cout << someString << "\n"; + offset1 += 0x20; + + if( offset1 >= section1.size() ) + { + break; + } + } + + int total_vertices = 0; + int total_indices = 0; + int max_index = 0; + + std::vector vertices; + std::vector indices; + char *data; + int counter = 0; + for( auto fileName : stringList ) + { + std::cout << fileName << " "; + auto file = data1.get_file( fileName ); + auto sections = file->get_data_sections(); + + auto dataSection = sections[0]; + + std::cout << sections.size() << "\n"; + + + /*if( fileName != "collision1\\s1fa_t1_hasi1.pcb" ) + { + std::cout << fileName; + continue; + }*/ + + uint32_t offset = 0; + + PCB_FILE pcb_file; + memcpy( &pcb_file.header, &dataSection[0], sizeof( pcb_file.header ) ); + offset += sizeof( pcb_file.header ); + + std::vector entries; + + 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 ? true : false; + + //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 ); + } + + } + + + for( auto &entry : pcb_file.entries ) + { + total_vertices += entry.header.num_vertices; + total_vertices += entry.header.num_v16; + + total_indices += entry.header.num_indices; + + for( auto &vertex_list : entry.data.vertices ) + { + vec3 v; + v.x = vertex_list.x; + v.y = vertex_list.y; + v.z = vertex_list.z; + vertices.push_back( v ); + } + + float x_base = abs( float( entry.header.x1 - entry.header.x ) ); + float y_base = abs( float( entry.header.y1 - entry.header.y ) ); + float z_base = abs( float( entry.header.z1 - entry.header.z ) ); + + for( const auto &link : entry.data.vertices_i16 ) + { + vec3 v(float( link.x ) / 0xFFFF, float( link.y ) / 0xFFFF, float( link.z ) / 0xFFFF); + + float x = float( link.x ); + float y = float( link.y ); + float z = float( link.z ); + v.x = ( x / 0xFFFF ) * x_base + entry.header.x; + v.y = ( y / 0xFFFF ) * y_base + entry.header.y; + v.z = ( z / 0xFFFF ) * z_base + entry.header.z; + vertices.push_back( v ); + } + + + for( const auto &index : entry.data.indices ) + { + //if( index.index[0] != 0 || index.index[1] != 0 || index.index[2] != 0 ) + { + indices.push_back(int(index.index[0]) + max_index ); + indices.push_back(int(index.index[1]) + max_index ); + indices.push_back(int(index.index[2]) + max_index ); + } + //std::cout << std::to_string( index.unknown[0] )<< " " << std::to_string( index.unknown[1] )<< " " << std::to_string( index.unknown[2]) << std::endl; + } + max_index = vertices.size(); + } + //for( auto block : pcb_file.entries ) + //{ + // auto pMesh3 = createBoundMeshFromPcbBlock( block ); + // if( pMesh3 ) + // m_pMeshList3.push_back( pMesh3 ); + //} + + } + toFile("test.obj", vertices, indices); + /* char *data; uint32_t offset = 0; //r1f1_b1_dor00.pcb @@ -178,12 +348,33 @@ int main() auto offset = sizeof(pcb_file.header); try { - parseBlockEntry(data + offset, pcb_file.entries, offset); + bool isgroup = true; + while( isgroup ) + { + PCB_BLOCK_ENTRY block_entry; + memcpy(&block_entry.header, data + offset, sizeof(block_entry.header)); + isgroup = block_entry.header.type == 0x30 ? true : false; + + //printf( "BLOCKHEADER_%X: type: %i, group_size: %i\n", offset, block_entry.header.type, block_entry.header.group_size ); + // + if( isgroup ) + { + std::cout << "ISGROUP" << "\n"; + parseBlockEntry(data + offset + 0x30, pcb_file.entries, offset); + offset += block_entry.header.group_size; + } + else + { + parseBlockEntry(data + offset, pcb_file.entries, offset); + } + } } catch(std::exception& e) { std::cout << "Unable to parse " << filename << " " << e.what() << "\n"; } + + } else { @@ -196,15 +387,7 @@ int main() total_vertices += entry.header.num_v16; total_indices += entry.header.num_indices; - /* - const auto& translationVec = pBgParts->header.translation; - const auto& rotationVec = pBgParts->header.rotation; - const auto& scaleVec = pBgParts->header.scale; - auto xrot = matrix4::rotateX(rotationVec.x); - auto yrot = matrix4::rotateY(rotationVec.y); - auto zrot = matrix4::rotateZ(rotationVec.z); - */ for( auto &vertex_list : entry.data.vertices ) { vec3 v; @@ -247,6 +430,6 @@ int main() } } toFile("test.obj", vertices, indices); - std::cout << "vertices " << vertices.size() << " indices " << indices.size() / 3 << " expected indices " << vertices.size() << " total " << total_indices << "\n"; + std::cout << "vertices " << vertices.size() << " indices " << indices.size() / 3 << " expected indices " << vertices.size() << " total " << total_indices << "\n";*/ return 0; } \ No newline at end of file diff --git a/src/tools/pcb_reader/pcb.h b/src/tools/pcb_reader/pcb.h index 165d7f7e..b8f451a9 100644 --- a/src/tools/pcb_reader/pcb.h +++ b/src/tools/pcb_reader/pcb.h @@ -43,6 +43,7 @@ struct PCB_INDEXDATA { uint8_t index[3]; uint8_t unknown[3]; + uint8_t unknown1[6]; }; struct PCB_VERTEXDATAI16 From 4e2bcbfa9cf56cc4cbe8eed729c9f9746d0754eb Mon Sep 17 00:00:00 2001 From: Tahir Akhlaq Date: Tue, 17 Oct 2017 12:15:46 +0100 Subject: [PATCH 04/11] exported collision maps correctly now (i think) --- src/tools/pcb_reader/CMakeLists.txt | 37 ++- src/tools/pcb_reader/main.cpp | 402 +++++++++++----------------- src/tools/pcb_reader/matrix4.h | 29 +- 3 files changed, 210 insertions(+), 258 deletions(-) diff --git a/src/tools/pcb_reader/CMakeLists.txt b/src/tools/pcb_reader/CMakeLists.txt index 6a314a46..85329b26 100644 --- a/src/tools/pcb_reader/CMakeLists.txt +++ b/src/tools/pcb_reader/CMakeLists.txt @@ -1,18 +1,39 @@ -set( CMAKE_CXX_FLAGS "-std=c++11 -m32") +cmake_minimum_required(VERSION 2.6) +cmake_policy(SET CMP0015 NEW) +project(Tool_pcb_reader2) -include_directories("../../") +set(SAPPHIRE_BOOST_VER 1.63.0) +set(SAPPHIRE_BOOST_FOLDER_NAME boost_1_63_0) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin/") + +include_directories("../../lib/ChaiScript-6.0.0/include/") + +include_directories("../../sapphire/datReader/") +include_directories("../../sapphire/") include_directories("../") file(GLOB SERVER_PUBLIC_INCLUDE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*") -file(GLOB SERVER_SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}*.cpp") +file(GLOB SERVER_SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}*.c*") -#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ".") -add_executable(pcb_parser2 ${SERVER_PUBLIC_INCLUDE_FILES} ${SERVER_SOURCE_FILES}) + +#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "../bin/") +add_executable(pcb_reader2 ${SERVER_PUBLIC_INCLUDE_FILES} ${SERVER_SOURCE_FILES}) + +set_target_properties(pcb_reader2 PROPERTIES + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON + CXX_EXTENSIONS ON + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../bin/" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../bin/" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../bin/" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../bin/" +) if (UNIX) - target_link_libraries (pcb_parser2 Common xivdat pthread mysqlclient dl z) + target_link_libraries (pcb_reader2 Common xivdat pthread mysqlclient dl z) else() - target_link_libraries (pcb_parser2 Common xivdat libmysql zlib1) + target_link_libraries (pcb_reader2 Common xivdat libmysql zlib1) endif() -target_link_libraries(pcb_parser2 ${Boost_LIBRARIES} ${Boost_LIBRARIES}) + +target_link_libraries(pcb_reader2 ${Boost_LIBRARIES} ${Boost_LIBRARIES}) diff --git a/src/tools/pcb_reader/main.cpp b/src/tools/pcb_reader/main.cpp index d3372689..b9735514 100644 --- a/src/tools/pcb_reader/main.cpp +++ b/src/tools/pcb_reader/main.cpp @@ -16,26 +16,6 @@ #include namespace fs = std::experimental::filesystem; -std::vector loadDir(const std::string& dir) -{ - std::vector files; - - auto fsDir = fs::current_path().append(fs::path(dir)); - std::cout << fsDir.string() << "\n"; - if (fs::exists(fsDir)) - { - for (const auto& entry : fs::directory_iterator(fsDir)) - { - auto filename = entry.path().filename(); - if (filename.string().find("~") == -1) - files.push_back(entry.path().string()); - if (filename.string().find("list") != std::string::npos) - std::cout << filename.string() << "\n"; - } - } - return files; -} - int parseBlockEntry( char* data, std::vector& entries, int gOff ) { int offset = 0; @@ -109,46 +89,78 @@ void toFile(const std::string& fileName, const std::vector& vertices, cons } for (auto i = 0; i < indices.size(); i += 3) { - //if( indices[i]!= 0 || indices[i + 1] != 0 || indices[i+ 2] != 0) fprintf(fp_out, "f %i %i %i\n", indices[i] + 1, indices[i + 1] + 1, indices[i + 2] + 1); } fclose(fp_out); } } -int main() +std::string zoneNameToPath( const std::string& name ) { + char teri = name[0]; + char region = name[1]; + char type = name[2]; + char zone = name[3]; + static std::map teriMap + { + { 'r', "roc" }, + { 'w', "wil" }, + { 'l', "lak" }, + { 'o', "ocn" }, + { 'f', "fst" }, + { 'a', "air" }, + { 's', "sea" }, + { 'z', "zon" } + }; - xiv::dat::GameData data1( "C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv" ); + static std::map typeMap + { + { 'f', "fld" }, + { 't', "twn" }, + { 'd', "dun" }, + { 'b', "bah" }, + { 'i', "ind" }, + { 'e', "evt" }, + }; + std::string ret; + const auto& teriRet = teriMap[teri]; + const auto& typeRet = typeMap[type]; + ret += teriRet + "_"; + ret += teri; + ret += region; + ret += "/" + typeRet + "/" + name; + return ret; +} + +int main( int argc, char* argv[] ) +{ + std::string gamePath = "C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv"; + std::string zoneName = "r1f1"; + + if( argc > 1 ) + { + gamePath = argv[1]; + if( argc > 2 ) + { + zoneName = argv[2]; + } + } + const auto& zonePath = zoneNameToPath( zoneName ); + + xiv::dat::GameData data1( gamePath ); xiv::exd::ExdData eData( data1 ); const xiv::dat::Cat& test = data1.get_category( "bg" ); - auto &test_file = data1.get_file( "bg/ffxiv/sea_s1/fld/s1f5/level/bg.lgb" ); + 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 stringList; + std::vector stringList2; - uint32_t offset = list_offset + 0x14; - - for( ; ; ) - { - std::string entry( §ion[offset] ); - offset += entry.size() + 1; - if( entry.find( "bgcommon" ) == std::string::npos && entry.find( ".mdl" ) == std::string::npos && entry.find( ".pcb" ) != std::string::npos ) - { - //stringList.push_back( entry ); - } - - if( offset >= size ) - { - break; - } - } - - auto &test_file1 = data1.get_file( "bg/ffxiv/roc_r1/fld/r1f1/collision/list.pcb" ); + 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/roc_r1/fld/r1f1/collision/"; int offset1 = 0x20; @@ -160,7 +172,7 @@ int main() char someString[200]; sprintf( someString, "%str%04d.pcb", path.c_str(), trId ); stringList.push_back( std::string( someString ) ); - std::cout << someString << "\n"; + //std::cout << someString << "\n"; offset1 += 0x20; if( offset1 >= section1.size() ) @@ -168,6 +180,7 @@ int main() break; } } + LGB_FILE bgLgb(§ion[0]); int total_vertices = 0; int total_indices = 0; @@ -178,59 +191,87 @@ int main() char *data; int counter = 0; - for( auto fileName : stringList ) + + + std::map pcbFiles; + + auto loadPcbFile = [&]( const std::string& fileName) { - std::cout << fileName << " "; - auto file = data1.get_file( fileName ); - auto sections = file->get_data_sections(); - - auto dataSection = sections[0]; - - std::cout << sections.size() << "\n"; - - - /*if( fileName != "collision1\\s1fa_t1_hasi1.pcb" ) + try { - std::cout << fileName; - continue; - }*/ + //std::cout << fileName << " "; + auto file = data1.get_file( fileName ); + auto sections = file->get_data_sections(); + auto dataSection = §ions.at( 0 )[0]; - uint32_t offset = 0; + //std::cout << sections.size() << "\n"; - PCB_FILE pcb_file; - memcpy( &pcb_file.header, &dataSection[0], sizeof( pcb_file.header ) ); - offset += sizeof( pcb_file.header ); + 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 ); - std::vector entries; - - 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 ? true : false; - - //printf( "BLOCKHEADER_%X: type: %i, group_size: %i\n", offset, block_entry.header.type, block_entry.header.group_size ); - // - if( isgroup ) + bool isgroup = true; + while( 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 ); - } + PCB_BLOCK_ENTRY block_entry; + memcpy( &block_entry.header, &dataSection[0] + offset, sizeof( block_entry.header ) ); + isgroup = block_entry.header.type == 0x30 ? true : false; + //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 vec3* scale = nullptr, const vec3* rotation = nullptr, const vec3* translation = nullptr) + { for( auto &entry : pcb_file.entries ) { total_vertices += entry.header.num_vertices; total_vertices += entry.header.num_v16; total_indices += entry.header.num_indices; + float x_base = abs( float( entry.header.x1 - entry.header.x ) ); + 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 ) + { + v.x *= scale->x; + v.y *= scale->y; + v.z *= scale->z; + } + if( rotation ) + { + v = v * matrix4::rotateX( rotation->x ); + v = v * matrix4::rotateY( rotation->y ); + v = v * matrix4::rotateZ( rotation->z ); + } + if( translation ) + { + v.x += translation->x; + v.y += translation->y; + v.z += translation->z; + } + }; for( auto &vertex_list : entry.data.vertices ) { @@ -238,198 +279,75 @@ int main() v.x = vertex_list.x; v.y = vertex_list.y; v.z = vertex_list.z; + makeTranslation( v ); vertices.push_back( v ); } - float x_base = abs( float( entry.header.x1 - entry.header.x ) ); - float y_base = abs( float( entry.header.y1 - entry.header.y ) ); - float z_base = abs( float( entry.header.z1 - entry.header.z ) ); - for( const auto &link : entry.data.vertices_i16 ) { - vec3 v(float( link.x ) / 0xFFFF, float( link.y ) / 0xFFFF, float( link.z ) / 0xFFFF); + vec3 v( float( link.x ) / 0xFFFF, float( link.y ) / 0xFFFF, float( link.z ) / 0xFFFF ); float x = float( link.x ); float y = float( link.y ); float z = float( link.z ); - v.x = ( x / 0xFFFF ) * x_base + entry.header.x; - v.y = ( y / 0xFFFF ) * y_base + entry.header.y; - v.z = ( z / 0xFFFF ) * z_base + entry.header.z; + v.x = (x / 0xFFFF) * x_base + entry.header.x; + v.y = (y / 0xFFFF) * y_base + entry.header.y; + v.z = (z / 0xFFFF) * z_base + entry.header.z; + + makeTranslation( v ); vertices.push_back( v ); } - for( const auto &index : entry.data.indices ) { //if( index.index[0] != 0 || index.index[1] != 0 || index.index[2] != 0 ) { - indices.push_back(int(index.index[0]) + max_index ); - indices.push_back(int(index.index[1]) + max_index ); - indices.push_back(int(index.index[2]) + max_index ); + indices.push_back( int( index.index[0] ) + max_index ); + indices.push_back( int( index.index[1] ) + max_index ); + indices.push_back( int( index.index[2] ) + max_index ); } //std::cout << std::to_string( index.unknown[0] )<< " " << std::to_string( index.unknown[1] )<< " " << std::to_string( index.unknown[2]) << std::endl; } max_index = vertices.size(); } - //for( auto block : pcb_file.entries ) - //{ - // auto pMesh3 = createBoundMeshFromPcbBlock( block ); - // if( pMesh3 ) - // m_pMeshList3.push_back( pMesh3 ); - //} + }; - } - toFile("test.obj", vertices, indices); - /* char *data; - - uint32_t offset = 0; - //r1f1_b1_dor00.pcb - PCB_LIST_FILE listFile; - int groupsCount = 0; - //auto list = loadDir("bg/ffxiv/roc_r1/collision"); - auto lgbFiles = getLgbFiles("bg/ffxiv/roc_r1/"); - - std::cout << "Loaded " << lgbFiles.size() << " LGB files" << std::endl; - - std::map groupCounts; - std::map pcbFiles; - - int total_vertices = 0; - int total_indices = 0; - int max_index = 0; - - std::vector vertices; - std::vector indices; - - for (const auto& pair : lgbFiles) + for( const auto& fileName : stringList ) { - std::cout << "FILE " << pair.first << "\n"; - for (const auto& group : pair.second.groups) + loadPcbFile( fileName ); + pushVerts( pcbFiles[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 ) { - uint32_t groupEntryCount = 0; - uint32_t bgPartsCount = 0; - //std::cout << "GROUP " << group.name << "\n"; - for (auto entry : group.entries) + if( !pEntry ) + continue; + + auto pBgParts = dynamic_cast( pEntry.get() ); + 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() ) { - if (dynamic_cast(entry.get())) - bgPartsCount++; + loadPcbFile( pBgParts->collisionFileName ); } - - for (auto pEntry : group.entries) + if( it != pcbFiles.end() ) { - if (!pEntry) - continue; + //std::cout << pBgParts->collisionFileName << "\n"; - auto pBgParts = dynamic_cast(pEntry.get()); + const auto* scale = &pBgParts->header.scale; + const auto* rotation = &pBgParts->header.rotation; + const auto* translation = &pBgParts->header.translation; - if (!pBgParts || pBgParts->collisionFileName.empty()) - continue; - - auto filename = pBgParts->collisionFileName; - if(!groupCounts[filename]) - std::cout << "GROUP " << group.name << " " << pBgParts->collisionFileName << "\n"; - - PCB_FILE pcb_file = PCB_FILE(); - if(pcbFiles.find(filename) == pcbFiles.end()) - { - FILE *fp = nullptr; - fp = fopen(filename.c_str(), "rb"); - if (fp == nullptr) - return 0; - - fseek(fp, 0, SEEK_END); - int32_t size = ftell(fp); - data = new char[size]; - rewind(fp); - fread(data, 1, size, fp); - fclose(fp); - - memcpy(&pcb_file.header, data, sizeof(pcb_file.header)); - auto offset = sizeof(pcb_file.header); - try - { - bool isgroup = true; - while( isgroup ) - { - PCB_BLOCK_ENTRY block_entry; - memcpy(&block_entry.header, data + offset, sizeof(block_entry.header)); - isgroup = block_entry.header.type == 0x30 ? true : false; - - //printf( "BLOCKHEADER_%X: type: %i, group_size: %i\n", offset, block_entry.header.type, block_entry.header.group_size ); - // - if( isgroup ) - { - std::cout << "ISGROUP" << "\n"; - parseBlockEntry(data + offset + 0x30, pcb_file.entries, offset); - offset += block_entry.header.group_size; - } - else - { - parseBlockEntry(data + offset, pcb_file.entries, offset); - } - } - } - catch(std::exception& e) - { - std::cout << "Unable to parse " << filename << " " << e.what() << "\n"; - } - - - } - else - { - pcb_file = pcbFiles[filename]; - } - - for( auto &entry : pcb_file.entries ) - { - total_vertices += entry.header.num_vertices; - total_vertices += entry.header.num_v16; - - total_indices += entry.header.num_indices; - - for( auto &vertex_list : entry.data.vertices ) - { - vec3 v; - v.x = vertex_list.x; - v.y = vertex_list.y; - v.z = vertex_list.z; - vertices.push_back( v ); - } - - float x_base = abs( float( entry.header.x1 - entry.header.x ) ); - float y_base = abs( float( entry.header.y1 - entry.header.y ) ); - float z_base = abs( float( entry.header.z1 - entry.header.z ) ); - - for( const auto &link : entry.data.vertices_i16 ) - { - vec3 v(float( link.x ) / 0xFFFF, float( link.y ) / 0xFFFF, float( link.z ) / 0xFFFF); - - float x = float( link.x ); - float y = float( link.y ); - float z = float( link.z ); - v.x = ( x / 0xFFFF ) * x_base + entry.header.x; - v.y = ( y / 0xFFFF ) * y_base + entry.header.y; - v.z = ( z / 0xFFFF ) * z_base + entry.header.z; - vertices.push_back( v ); - } - - - for( const auto &index : entry.data.indices ) - { - indices.push_back( int( index.index[0] ) + max_index ); - indices.push_back( int( index.index[1] ) + max_index ); - indices.push_back( int( index.index[2] ) + max_index ); - //std::cout << std::to_string( index.unknown[0] )<< " " << std::to_string( index.unknown[1] )<< " " << std::to_string( index.unknown[2]) << std::endl; - } - max_index = vertices.size(); - } - //toFile("test.obj", vertices, indices); - //break; + const auto& pcb_file = it->second; + pushVerts( pcb_file, scale, rotation, translation ); } } } toFile("test.obj", vertices, indices); - std::cout << "vertices " << vertices.size() << " indices " << indices.size() / 3 << " expected indices " << vertices.size() << " total " << total_indices << "\n";*/ return 0; } \ No newline at end of file diff --git a/src/tools/pcb_reader/matrix4.h b/src/tools/pcb_reader/matrix4.h index c19808e2..981d5a98 100644 --- a/src/tools/pcb_reader/matrix4.h +++ b/src/tools/pcb_reader/matrix4.h @@ -10,19 +10,19 @@ struct matrix4 float grid[16]; matrix4() { - memset(&grid[0], 0, sizeof(grid)); + memset( &grid[0], 0, sizeof( grid ) ); } - float operator()(int row, int col) const + float operator()( int row, int col ) const { return grid[(row * 4) + col]; } - float& operator()(int row, int col) + float& operator()( int row, int col ) { return grid[(row * 4) + col]; } - static matrix4 rotateX(float angle) + static matrix4 rotateX( float angle ) { matrix4 ret = matrix4(); ret(0, 0) = 1.000000000f; @@ -34,7 +34,7 @@ struct matrix4 return ret; } - static matrix4 rotateY(float angle) + static matrix4 rotateY( float angle ) { matrix4 ret = matrix4(); ret(0, 0) = cos(angle); @@ -46,7 +46,7 @@ struct matrix4 return ret; } - static matrix4 rotateZ(float angle) + static matrix4 rotateZ( float angle ) { matrix4 ret = matrix4(); ret(0, 0) = cos(angle); @@ -58,7 +58,7 @@ struct matrix4 return ret; } - static matrix4 scale(float x, float y, float z) + static matrix4 scale( float x, float y, float z ) { matrix4 ret = matrix4(); ret(0, 0) = x; @@ -69,7 +69,7 @@ struct matrix4 return ret; } - static matrix4 translate(float x, float y, float z) + static matrix4 translate( float x, float y, float z ) { matrix4 ret = matrix4(); ret(0, 0) = 1; @@ -82,5 +82,18 @@ struct matrix4 ret(3, 2) = z; return ret; } + + matrix4 operator *( const matrix4& rhs ) const + { + matrix4 ret; + for( unsigned int i = 0; i < 4; i++ ) + { + ret( i, 0 ) = (*this)(i, 0) * rhs( 0, 0 ) + (*this)(i, 1) * rhs( 1, 0 ) + (*this)(i, 2) * rhs( 2, 0 ) + (*this)(i, 3) * rhs( 3, 0 ); + ret( i, 1 ) = (*this)(i, 0) * rhs( 0, 1 ) + (*this)(i, 1) * rhs( 1, 1 ) + (*this)(i, 2) * rhs( 2, 1 ) + (*this)(i, 3) * rhs( 3, 1 ); + ret( i, 2 ) = (*this)(i, 0) * rhs( 0, 2 ) + (*this)(i, 1) * rhs( 1, 2 ) + (*this)(i, 2) * rhs( 2, 2 ) + (*this)(i, 3) * rhs( 3, 2 ); + ret( i, 3 ) = (*this)(i, 0) * rhs( 0, 3 ) + (*this)(i, 1) * rhs( 1, 3 ) + (*this)(i, 2) * rhs( 2, 3 ) + (*this)(i, 3) * rhs( 3, 3 ); + } + return ret; + } }; #endif \ No newline at end of file From edd529297c3676e59da1b42b65699cc329dfd793 Mon Sep 17 00:00:00 2001 From: Tahir Akhlaq Date: Tue, 17 Oct 2017 15:14:48 +0100 Subject: [PATCH 05/11] cleaned up collision map exporter - export by object --- src/tools/pcb_reader/main.cpp | 319 +++++++++++++++++----------------- 1 file changed, 156 insertions(+), 163 deletions(-) diff --git a/src/tools/pcb_reader/main.cpp b/src/tools/pcb_reader/main.cpp index b9735514..9374f70c 100644 --- a/src/tools/pcb_reader/main.cpp +++ b/src/tools/pcb_reader/main.cpp @@ -15,6 +15,10 @@ #include namespace fs = std::experimental::filesystem; +struct face +{ + int32_t f1, f2, f3; +}; int parseBlockEntry( char* data, std::vector& entries, int gOff ) { @@ -72,29 +76,6 @@ int parseBlockEntry( char* data, std::vector& entries, int gOff return 0; } -void toFile(const std::string& fileName, const std::vector& vertices, const std::vector& indices) -{ - auto fp_out = fopen(fileName.c_str(), "w"); - if (fp_out) - { - fprintf(fp_out, "\n"); - fclose(fp_out); - } - fp_out = fopen(fileName.c_str(), "ab+"); - if (fp_out) - { - for (const auto& v : vertices) - { - fprintf(fp_out, "v %f %f %f\n", v.x, v.y, v.z); - } - for (auto i = 0; i < indices.size(); i += 3) - { - fprintf(fp_out, "f %i %i %i\n", indices[i] + 1, indices[i + 1] + 1, indices[i + 2] + 1); - } - fclose(fp_out); - } -} - std::string zoneNameToPath( const std::string& name ) { char teri = name[0]; @@ -162,7 +143,7 @@ int main( int argc, char* argv[] ) 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/roc_r1/fld/r1f1/collision/"; + std::string path = "bg/ffxiv/" + zonePath + "/collision/"; int offset1 = 0x20; for( ; ; ) { @@ -180,174 +161,186 @@ int main( int argc, char* argv[] ) break; } } + LGB_FILE bgLgb(§ion[0]); - int total_vertices = 0; - int total_indices = 0; int max_index = 0; - std::vector vertices; - std::vector indices; + std::vector vertices; + std::vector indices; char *data; int counter = 0; - - std::map pcbFiles; - - auto loadPcbFile = [&]( const std::string& fileName) + // dont bother if we cant write to a file + auto fp_out = fopen( (zoneName + ".obj").c_str(), "w" ); + if( fp_out ) { - try + 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 pcbFiles; + std::map objCount; + auto loadPcbFile = [&]( const std::string& fileName ) { - //std::cout << fileName << " "; - auto file = data1.get_file( fileName ); - auto sections = file->get_data_sections(); - auto dataSection = §ions.at( 0 )[0]; + 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"; + //std::cout << sections.size() << "\n"; - uint32_t offset = 0; + 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 ? true : false; + + //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; - PCB_FILE pcb_file; - memcpy( &pcb_file.header, &dataSection[0], sizeof( pcb_file.header ) ); - offset += sizeof( pcb_file.header ); - - bool isgroup = true; - while( isgroup ) + for( auto &entry : pcb_file.entries ) { - PCB_BLOCK_ENTRY block_entry; - memcpy( &block_entry.header, &dataSection[0] + offset, sizeof( block_entry.header ) ); - isgroup = block_entry.header.type == 0x30 ? true : false; + float x_base = abs( float( entry.header.x1 - entry.header.x ) ); + float y_base = abs( float( entry.header.y1 - entry.header.y ) ); + 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 ); - // - if( isgroup ) + auto makeTranslation = [&]( vec3& v ) { - parseBlockEntry( &dataSection[0] + offset + 0x30, pcb_file.entries, offset ); - offset += block_entry.header.group_size; - } - else + if( scale ) + { + v.x *= scale->x; + 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_list : entry.data.vertices ) { - parseBlockEntry( &dataSection[0] + offset, pcb_file.entries, offset ); + 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 ); } - 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 ) + { + face f; + f.f1 = index.index[0] + max_index; + 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; + } + //max_index = vertices.size(); + 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 ); } - }; - auto pushVerts = [&]( const PCB_FILE& pcb_file, const vec3* scale = nullptr, const vec3* rotation = nullptr, const vec3* translation = nullptr) - { - for( auto &entry : pcb_file.entries ) + std::cout << "Writing obj file " << "\n"; + std::cout << bgLgb.groups.size() << " entries " << "\n"; + for( const auto& group : bgLgb.groups ) { - total_vertices += entry.header.num_vertices; - total_vertices += entry.header.num_v16; - - total_indices += entry.header.num_indices; - float x_base = abs( float( entry.header.x1 - entry.header.x ) ); - 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 ) + for( const auto pEntry : group.entries ) { - if( scale ) + if( !pEntry ) + continue; + + auto pBgParts = dynamic_cast(pEntry.get()); + 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() ) { - v.x *= scale->x; - v.y *= scale->y; - v.z *= scale->z; + loadPcbFile( pBgParts->collisionFileName ); } - if( rotation ) + if( it != pcbFiles.end() ) { - v = v * matrix4::rotateX( rotation->x ); - v = v * matrix4::rotateY( rotation->y ); - v = v * matrix4::rotateZ( rotation->z ); + //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 ); } - if( translation ) - { - v.x += translation->x; - v.y += translation->y; - v.z += translation->z; - } - }; - - 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 ); - vertices.push_back( v ); - } - - for( const auto &link : entry.data.vertices_i16 ) - { - vec3 v( float( link.x ) / 0xFFFF, float( link.y ) / 0xFFFF, float( link.z ) / 0xFFFF ); - - float x = float( link.x ); - float y = float( link.y ); - float z = float( link.z ); - v.x = (x / 0xFFFF) * x_base + entry.header.x; - v.y = (y / 0xFFFF) * y_base + entry.header.y; - v.z = (z / 0xFFFF) * z_base + entry.header.z; - - makeTranslation( v ); - vertices.push_back( v ); - } - - for( const auto &index : entry.data.indices ) - { - //if( index.index[0] != 0 || index.index[1] != 0 || index.index[2] != 0 ) - { - indices.push_back( int( index.index[0] ) + max_index ); - indices.push_back( int( index.index[1] ) + max_index ); - indices.push_back( int( index.index[2] ) + max_index ); - } - //std::cout << std::to_string( index.unknown[0] )<< " " << std::to_string( index.unknown[1] )<< " " << std::to_string( index.unknown[2]) << std::endl; - } - max_index = vertices.size(); - } - }; - - for( const auto& fileName : stringList ) - { - loadPcbFile( fileName ); - pushVerts( pcbFiles[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( pEntry.get() ); - 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() ) - { - 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, scale, rotation, translation ); } } } - toFile("test.obj", vertices, indices); return 0; } \ No newline at end of file From c35795a9f37cddf26bc5e906f48b986d287bbb21 Mon Sep 17 00:00:00 2001 From: Tahir Akhlaq Date: Tue, 17 Oct 2017 21:49:01 +0100 Subject: [PATCH 06/11] slightly cleaned up PCB reader, added some exception logging --- src/tools/pcb_reader/lgb.h | 149 ++++++------- src/tools/pcb_reader/main.cpp | 384 ++++++++++++++++++---------------- 2 files changed, 277 insertions(+), 256 deletions(-) diff --git a/src/tools/pcb_reader/lgb.h b/src/tools/pcb_reader/lgb.h index a4ef3977..d783c36f 100644 --- a/src/tools/pcb_reader/lgb.h +++ b/src/tools/pcb_reader/lgb.h @@ -57,6 +57,26 @@ enum class LgbEntryType : uint32_t 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 { LgbEntryType type; @@ -75,25 +95,6 @@ struct LGB_BGPARTS_HEADER 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 { public: @@ -101,13 +102,13 @@ public: std::string name; std::string modelFileName; std::string collisionFileName; - LGB_BGPARTS_ENTRY(){}; - LGB_BGPARTS_ENTRY(char* buf, uint32_t offset) + LGB_BGPARTS_ENTRY() {}; + LGB_BGPARTS_ENTRY( char* buf, uint32_t offset ) { header = *reinterpret_cast(buf + offset); - name = std::string(buf + offset + header.nameOffset); - modelFileName = std::string(buf + offset + header.modelFileOffset); - collisionFileName = std::string(buf + offset + header.collisionFileOffset); + name = std::string( buf + offset + header.nameOffset ); + modelFileName = std::string( buf + offset + header.modelFileOffset ); + collisionFileName = std::string( buf + offset + header.collisionFileOffset ); //std::cout << "BGPARTS_ENTRY " << name << "\n"; //std::cout << " " << modelFileName << "\n"; //std::cout << " " << collisionFileName << "\n"; @@ -132,10 +133,10 @@ public: LGB_GIMMICK_HEADER header; std::string name; - LGB_GIMMICK_ENTRY(char* buf, uint32_t offset) + LGB_GIMMICK_ENTRY( char* buf, uint32_t offset ) { header = *reinterpret_cast(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::vector> entries; - LGB_GROUP(char* buf, LGB_FILE* parentStruct, uint32_t offset) + LGB_GROUP( char* buf, LGB_FILE* parentStruct, uint32_t offset ) { - parent = parentStruct; - header = *reinterpret_cast(buf + offset); - name = std::string(buf + offset + header.groupNameOffset); - entries.resize(header.entryCount); - //std::cout << name << std::endl; - auto entriesOffset = offset + header.entriesOffset; - for( auto i = 0; i < header.entryCount; ++i ) - { - auto entryOffset = entriesOffset + *reinterpret_cast(buf + (entriesOffset + i * 4)); + parent = parentStruct; + header = *reinterpret_cast(buf + offset); + name = std::string( buf + offset + header.groupNameOffset ); + entries.resize( header.entryCount ); + //std::cout << name << std::endl; + auto entriesOffset = offset + header.entriesOffset; + for( auto i = 0; i < header.entryCount; ++i ) + { + auto entryOffset = entriesOffset + *reinterpret_cast(buf + (entriesOffset + i * 4)); - try - { - auto type = *reinterpret_cast(buf + entryOffset); - LGB_MODEL_ENTRY* entry; - if (type == LgbEntryType::BgParts) + try { - entries[i] = std::make_shared(buf, entryOffset); + auto type = *reinterpret_cast(buf + entryOffset); + LGB_MODEL_ENTRY* entry; + if( type == LgbEntryType::BgParts ) + { + entries[i] = std::make_shared( buf, entryOffset ); + } + else if( type == LgbEntryType::Gimmick ) + { + entries[i] = std::make_shared( buf, entryOffset ); + } + else + { + entries[i] = nullptr; + } } - else if (type == LgbEntryType::Gimmick) + catch( std::exception& e ) { - entries[i] = std::make_shared(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; std::vector groups; - LGB_FILE(char* buf) + LGB_FILE( char* buf ) { header = *reinterpret_cast(buf); - if (strncmp(&header.magic[0], "LGB1", 4) != 0 || strncmp(&header.magic2[0], "LGP1", 4) != 0) - throw std::exception("Invalid LGB file!"); + if( strncmp( &header.magic[0], "LGB1", 4 ) != 0 || strncmp( &header.magic2[0], "LGP1", 4 ) != 0 ) + throw std::exception( "Invalid LGB file!" ); //groups.resize(header.groupCount); - auto baseOffset = sizeof(header); - for(auto i = 0; i < header.groupCount; ++i) + auto baseOffset = sizeof( header ); + for( auto i = 0; i < header.groupCount; ++i ) { auto groupOffset = baseOffset + *reinterpret_cast(buf + (baseOffset + i * 4)); - auto group = LGB_GROUP(buf, this, groupOffset); - groups.push_back(group); + auto group = LGB_GROUP( buf, this, groupOffset ); + groups.push_back( group ); } }; }; -std::map getLgbFiles(const std::string& dir) +std::map getLgbFiles( const std::string& dir ) { namespace fs = std::experimental::filesystem; std::map 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 f = fopen(strPath.c_str(), "rb"); - fseek(f, 0, SEEK_END); - auto size = ftell(f); - std::vector bytes(size); - rewind(f); - fread(bytes.data(), 1, size, f); - fclose(f); + auto f = fopen( strPath.c_str(), "rb" ); + fseek( f, 0, SEEK_END ); + auto size = ftell( f ); + std::vector bytes( size ); + rewind( f ); + fread( bytes.data(), 1, size, f ); + fclose( f ); try { - LGB_FILE lgbFile(bytes.data()); - fileMap.insert(std::make_pair(strPath, lgbFile)); + LGB_FILE lgbFile( bytes.data() ); + fileMap.insert( std::make_pair( strPath, lgbFile ) ); } - catch (std::exception& e) + catch( std::exception& e ) { std::cout << "Unable to load " << strPath << std::endl; } diff --git a/src/tools/pcb_reader/main.cpp b/src/tools/pcb_reader/main.cpp index 9374f70c..1a655888 100644 --- a/src/tools/pcb_reader/main.cpp +++ b/src/tools/pcb_reader/main.cpp @@ -14,6 +14,10 @@ #include #include +#include +#include + +using namespace std::chrono_literals; namespace fs = std::experimental::filesystem; struct face { @@ -28,7 +32,7 @@ int parseBlockEntry( char* data, std::vector& entries, int gOff { PCB_BLOCK_ENTRY block_entry; 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 ); @@ -115,6 +119,8 @@ std::string zoneNameToPath( const std::string& name ) 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 zoneName = "r1f1"; @@ -128,219 +134,233 @@ int main( int argc, char* argv[] ) } const auto& zonePath = zoneNameToPath( zoneName ); - xiv::dat::GameData data1( gamePath ); - 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 stringList; - std::vector 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( ; ; ) + try { + 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]; - sprintf( someString, "%str%04d.pcb", path.c_str(), trId ); - stringList.push_back( std::string( someString ) ); - //std::cout << someString << "\n"; - offset1 += 0x20; + 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]; - if( offset1 >= section1.size() ) + std::vector 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 vertices; - std::vector 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 pcbFiles; - std::map objCount; - auto loadPcbFile = [&]( const std::string& fileName ) - { - try + if( offset1 >= section1.size() ) { - //std::cout << fileName << " "; - auto file = data1.get_file( fileName ); - auto sections = file->get_data_sections(); - auto dataSection = §ions.at( 0 )[0]; + break; + } + } - //std::cout << sections.size() << "\n"; + LGB_FILE bgLgb( §ion[0] ); - uint32_t offset = 0; + int max_index = 0; + + std::vector vertices; + std::vector 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 pcbFiles; + std::map 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; - PCB_FILE pcb_file; - memcpy( &pcb_file.header, &dataSection[0], sizeof( pcb_file.header ) ); - offset += sizeof( pcb_file.header ); - - bool isgroup = true; - while( isgroup ) + for( auto &entry : pcb_file.entries ) { - PCB_BLOCK_ENTRY block_entry; - memcpy( &block_entry.header, &dataSection[0] + offset, sizeof( block_entry.header ) ); - isgroup = block_entry.header.type == 0x30 ? true : false; + float x_base = abs( float( entry.header.x1 - entry.header.x ) ); + float y_base = abs( float( entry.header.y1 - entry.header.y ) ); + 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 ); - // - if( isgroup ) + auto makeTranslation = [&]( vec3& v ) { - parseBlockEntry( &dataSection[0] + offset + 0x30, pcb_file.entries, offset ); - offset += block_entry.header.group_size; - } - else + if( scale ) + { + v.x *= scale->x; + 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 ); } - }; - 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; - for( auto &entry : pcb_file.entries ) + std::cout << "Writing obj file " << "\n"; + std::cout << bgLgb.groups.size() << " entries " << "\n"; + for( const auto& group : bgLgb.groups ) { - float x_base = abs( float( entry.header.x1 - entry.header.x ) ); - 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 ) + for( const auto pEntry : group.entries ) { - if( scale ) + if( !pEntry ) + continue; + + auto pBgParts = dynamic_cast(pEntry.get()); + if( pBgParts && pBgParts->collisionFileName.empty() ) { - v.x *= scale->x; - 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; + pBgParts->collisionFileName = pBgParts->modelFileName; + boost::replace_all( pBgParts->collisionFileName, "bgparts", "collision" ); + boost::replace_all( pBgParts->collisionFileName, ".mdl", ".pcb" ); + //std::cout << pBgParts->collisionFileName << " renamed\n"; } + if( !pBgParts || pBgParts->collisionFileName.empty() ) + //|| std::find( stringList.begin(), stringList.end(), pBgParts->collisionFileName ) != stringList.end() ) + continue; - }; - - 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 ) + auto it = pcbFiles.find( pBgParts->collisionFileName ); + if( it == pcbFiles.end() ) { - face f; - f.f1 = index.index[0] + max_index; - 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 ); + loadPcbFile( pBgParts->collisionFileName ); + //std::cout << "\t\tLoaded PCB File " << pBgParts->collisionFileName << "\n"; } - //std::cout << std::to_string( index.unknown[0] )<< " " << std::to_string( index.unknown[1] )<< " " << std::to_string( index.unknown[2]) << std::endl; - } - //max_index = vertices.size(); - max_index += entry.data.vertices.size() + entry.data.vertices_i16.size(); - } - }; + if( it != pcbFiles.end() ) + { + //std::cout << pBgParts->collisionFileName << "\n"; - for( const auto& fileName : stringList ) - { - loadPcbFile( fileName ); - 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; + const auto* scale = &pBgParts->header.scale; + const auto* rotation = &pBgParts->header.rotation; + const auto* translation = &pBgParts->header.translation; - auto pBgParts = dynamic_cast(pEntry.get()); - 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() ) - { - 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 ); + 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::system_clock::now() - startTime).count() << " seconds\n"; + } + catch( std::exception& e ) + { + std::cout << e.what() << std::endl; } return 0; } \ No newline at end of file From 7b127e20df034fb4e509f8f6edc0b1cf4731f0da Mon Sep 17 00:00:00 2001 From: Tahir Akhlaq Date: Wed, 18 Oct 2017 13:26:06 +0100 Subject: [PATCH 07/11] fixed issue with missing objects --- src/tools/pcb_reader/lgb.h | 11 +++++---- src/tools/pcb_reader/main.cpp | 44 +++++++++++++++++++++-------------- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/tools/pcb_reader/lgb.h b/src/tools/pcb_reader/lgb.h index d783c36f..9de026ff 100644 --- a/src/tools/pcb_reader/lgb.h +++ b/src/tools/pcb_reader/lgb.h @@ -169,7 +169,7 @@ struct LGB_GROUP parent = parentStruct; header = *reinterpret_cast(buf + offset); name = std::string( buf + offset + header.groupNameOffset ); - entries.resize( header.entryCount ); + //entries.resize( header.entryCount ); //std::cout << name << std::endl; auto entriesOffset = offset + header.entriesOffset; for( auto i = 0; i < header.entryCount; ++i ) @@ -179,19 +179,20 @@ struct LGB_GROUP try { auto type = *reinterpret_cast(buf + entryOffset); - LGB_MODEL_ENTRY* entry; if( type == LgbEntryType::BgParts ) { - entries[i] = std::make_shared( buf, entryOffset ); + entries.push_back(std::make_shared( buf, entryOffset )); } + /* else if( type == LgbEntryType::Gimmick ) { - entries[i] = std::make_shared( buf, entryOffset ); + //entries[i] = std::make_shared( buf, entryOffset ); } else { - entries[i] = nullptr; + //entries[i] = nullptr; } + */ } catch( std::exception& e ) { diff --git a/src/tools/pcb_reader/main.cpp b/src/tools/pcb_reader/main.cpp index 1a655888..81ac0ebd 100644 --- a/src/tools/pcb_reader/main.cpp +++ b/src/tools/pcb_reader/main.cpp @@ -303,7 +303,7 @@ int main( int argc, char* argv[] ) 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; +// 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(); } @@ -315,34 +315,42 @@ int main( int argc, char* argv[] ) pushVerts( pcbFiles[fileName], fileName ); } std::cout << "Writing obj file " << "\n"; - std::cout << bgLgb.groups.size() << " entries " << "\n"; + std::cout << bgLgb.groups.size() << " groups " << "\n"; + uint32_t totalGroups = 0; + uint32_t totalGroupEntries = 0; for( const auto& group : bgLgb.groups ) { + //std::cout << "\t" << group.name << " Size " << group.header.entryCount << "\n"; + totalGroups++; for( const auto pEntry : group.entries ) { - if( !pEntry ) - continue; - auto pBgParts = dynamic_cast(pEntry.get()); - if( pBgParts && pBgParts->collisionFileName.empty() ) + + auto& fileName = pBgParts->collisionFileName; + if( pBgParts ) { - pBgParts->collisionFileName = pBgParts->modelFileName; - boost::replace_all( pBgParts->collisionFileName, "bgparts", "collision" ); - boost::replace_all( pBgParts->collisionFileName, ".mdl", ".pcb" ); - //std::cout << pBgParts->collisionFileName << " renamed\n"; + if ( fileName.empty() ) + fileName = pBgParts->modelFileName; + boost::replace_all( fileName, "bgparts", "collision" ); + boost::replace_all( fileName, ".mdl", ".pcb" ); } - if( !pBgParts || pBgParts->collisionFileName.empty() ) - //|| std::find( stringList.begin(), stringList.end(), pBgParts->collisionFileName ) != stringList.end() ) + + if( !pBgParts || fileName.empty() ) continue; - auto it = pcbFiles.find( pBgParts->collisionFileName ); - if( it == pcbFiles.end() ) { - loadPcbFile( pBgParts->collisionFileName ); - //std::cout << "\t\tLoaded PCB File " << pBgParts->collisionFileName << "\n"; + const auto& it = pcbFiles.find( fileName ); + if( it == pcbFiles.end() ) + { + loadPcbFile( fileName ); + //std::cout << "\t\tLoaded PCB File " << pBgParts->collisionFileName << "\n"; + } } + const auto& it = pcbFiles.find( fileName ); if( it != pcbFiles.end() ) { + totalGroupEntries++; + //std::cout << pBgParts->collisionFileName << "\n"; const auto* scale = &pBgParts->header.scale; @@ -350,10 +358,12 @@ int main( int argc, char* argv[] ) const auto* translation = &pBgParts->header.translation; const auto& pcb_file = it->second; - pushVerts( pcb_file, pBgParts->collisionFileName, scale, rotation, translation ); + pushVerts( pcb_file, fileName, scale, rotation, translation ); } } } + std::cout << "\n\nLoaded " << pcbFiles.size() << " PCB Files \n"; + std::cout << "Total Groups " << totalGroups << " Total entries " << totalGroupEntries << "\n"; } std::cout << "Finished exporting " << zoneName << " in " << std::chrono::duration_cast(std::chrono::system_clock::now() - startTime).count() << " seconds\n"; From acbc33063a94834f32321383fe97aa0b8e297bac Mon Sep 17 00:00:00 2001 From: Tahir Akhlaq Date: Wed, 18 Oct 2017 15:06:10 +0100 Subject: [PATCH 08/11] const all the things for readability - removed .mdl collision loading since game doesnt use it fixed style issues in pcb_reader --- .travis.yml | 10 +++--- src/tools/pcb_reader/CMakeLists.txt | 2 +- src/tools/pcb_reader/lgb.h | 43 +++++++++++++++----------- src/tools/pcb_reader/main.cpp | 48 ++++++++++++----------------- src/tools/pcb_reader/matrix4.h | 3 +- src/tools/pcb_reader/pcb.h | 12 ++++---- 6 files changed, 60 insertions(+), 58 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5a08c891..6c5c62cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,17 +6,19 @@ before_install: - sudo apt-get update - sudo apt-get install -y software-properties-common - sudo apt-get update - - sudo apt-get install gcc-4.9 g++-4.9 gcc-4.9-multilib g++-4.9-multilib cmake3 -y + - sudo apt-get install gcc-7 g++-7 gcc-7-multilib g++-7-multilib cmake3 -y - sudo apt-get install libboost-dev libboost-all-dev libmysqlclient-dev -y - - sudo apt-get install libmysqlcppconn-dev -y + - sudo apt-get install libmysqlcppconn-dev -y + compiler: - - gcc + - g++ # Build steps script: + - g++ --version - mkdir build - cd build - - cmake .. -DSAPPHIRE_BOOST_VER="1.54.0" -DCMAKE_CXX_COMPILER=g++-4.9 -DCMAKE_C_COMPILER=gcc-4.9 && make -j 3 + - cmake .. -DSAPPHIRE_BOOST_VER="1.54.0" -DCMAKE_CXX_COMPILER=g++-7 && make -j 3 - cd .. - bash sql_import.sh diff --git a/src/tools/pcb_reader/CMakeLists.txt b/src/tools/pcb_reader/CMakeLists.txt index 85329b26..a73b4816 100644 --- a/src/tools/pcb_reader/CMakeLists.txt +++ b/src/tools/pcb_reader/CMakeLists.txt @@ -20,7 +20,7 @@ file(GLOB SERVER_SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}*.c*") add_executable(pcb_reader2 ${SERVER_PUBLIC_INCLUDE_FILES} ${SERVER_SOURCE_FILES}) set_target_properties(pcb_reader2 PROPERTIES - CXX_STANDARD 17 + CXX_STANDARD 14 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS ON RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../bin/" diff --git a/src/tools/pcb_reader/lgb.h b/src/tools/pcb_reader/lgb.h index 9de026ff..3ad58b89 100644 --- a/src/tools/pcb_reader/lgb.h +++ b/src/tools/pcb_reader/lgb.h @@ -1,14 +1,16 @@ #ifndef _LGB_H #define _LGB_H -#include "matrix4.h" -#include "vec3.h" +#include #include #include #include #include #include -#include +#include + +#include "matrix4.h" +#include "vec3.h" // all credit to // https://github.com/ufx/SaintCoinach/blob/master/SaintCoinach/Graphics/Lgb/ @@ -105,7 +107,7 @@ public: LGB_BGPARTS_ENTRY() {}; LGB_BGPARTS_ENTRY( char* buf, uint32_t offset ) { - header = *reinterpret_cast(buf + offset); + header = *reinterpret_cast( buf + offset ); name = std::string( buf + offset + header.nameOffset ); modelFileName = std::string( buf + offset + header.modelFileOffset ); collisionFileName = std::string( buf + offset + header.collisionFileOffset ); @@ -135,7 +137,7 @@ public: LGB_GIMMICK_ENTRY( char* buf, uint32_t offset ) { - header = *reinterpret_cast(buf + offset); + header = *reinterpret_cast( buf + offset ); name = std::string( buf + offset + header.nameOffset ); }; }; @@ -167,21 +169,21 @@ struct LGB_GROUP LGB_GROUP( char* buf, LGB_FILE* parentStruct, uint32_t offset ) { parent = parentStruct; - header = *reinterpret_cast(buf + offset); + header = *reinterpret_cast( buf + offset ); name = std::string( buf + offset + header.groupNameOffset ); //entries.resize( header.entryCount ); //std::cout << name << std::endl; - auto entriesOffset = offset + header.entriesOffset; + const auto entriesOffset = offset + header.entriesOffset; for( auto i = 0; i < header.entryCount; ++i ) { - auto entryOffset = entriesOffset + *reinterpret_cast(buf + (entriesOffset + i * 4)); + const auto entryOffset = entriesOffset + *reinterpret_cast( buf + ( entriesOffset + i * 4 ) ); try { - auto type = *reinterpret_cast(buf + entryOffset); + const auto type = *reinterpret_cast( buf + entryOffset ); if( type == LgbEntryType::BgParts ) { - entries.push_back(std::make_shared( buf, entryOffset )); + entries.push_back( std::make_shared( buf, entryOffset ) ); } /* else if( type == LgbEntryType::Gimmick ) @@ -222,22 +224,25 @@ struct LGB_FILE LGB_FILE( char* buf ) { - header = *reinterpret_cast(buf); + header = *reinterpret_cast( buf ); if( strncmp( &header.magic[0], "LGB1", 4 ) != 0 || strncmp( &header.magic2[0], "LGP1", 4 ) != 0 ) - throw std::exception( "Invalid LGB file!" ); + throw std::runtime_error( "Invalid LGB file!" ); //groups.resize(header.groupCount); - auto baseOffset = sizeof( header ); + constexpr auto baseOffset = sizeof( header ); for( auto i = 0; i < header.groupCount; ++i ) { - auto groupOffset = baseOffset + *reinterpret_cast(buf + (baseOffset + i * 4)); - auto group = LGB_GROUP( buf, this, groupOffset ); + const auto groupOffset = baseOffset + *reinterpret_cast( buf + ( baseOffset + i * 4 ) ); + const auto group = LGB_GROUP( buf, this, groupOffset ); groups.push_back( group ); } }; }; +/* +#if __cplusplus >= 201703L +#include std::map getLgbFiles( const std::string& dir ) { namespace fs = std::experimental::filesystem; @@ -246,10 +251,10 @@ std::map getLgbFiles( const std::string& dir ) { if( path.path().extension() == ".lgb" ) { - auto strPath = path.path().string(); + const auto& strPath = path.path().string(); auto f = fopen( strPath.c_str(), "rb" ); fseek( f, 0, SEEK_END ); - auto size = ftell( f ); + const auto size = ftell( f ); std::vector bytes( size ); rewind( f ); fread( bytes.data(), 1, size, f ); @@ -267,4 +272,6 @@ std::map getLgbFiles( const std::string& dir ) } return fileMap; } -#endif \ No newline at end of file +#endif +*/ +#endif diff --git a/src/tools/pcb_reader/main.cpp b/src/tools/pcb_reader/main.cpp index 81ac0ebd..e6dbffd5 100644 --- a/src/tools/pcb_reader/main.cpp +++ b/src/tools/pcb_reader/main.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include "pcb.h" #include "lgb.h" @@ -18,7 +17,7 @@ #include using namespace std::chrono_literals; -namespace fs = std::experimental::filesystem; + struct face { int32_t f1, f2, f3; @@ -141,15 +140,15 @@ int main( int argc, char* argv[] ) 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 ); + auto test_file = data1.get_file( "bg/ffxiv/" + zonePath + "/level/bg.lgb" ); + auto section = test_file->access_data_sections().at( 0 ); int32_t list_offset = *(uint32_t*)§ion[0x18]; int32_t size = *(uint32_t*)§ion[4]; std::vector stringList; - auto &test_file1 = data1.get_file( "bg/ffxiv/" + zonePath + "/collision/list.pcb" ); - auto §ion1 = test_file1->access_data_sections().at( 0 ); + auto test_file1 = data1.get_file( "bg/ffxiv/" + zonePath + "/collision/list.pcb" ); + auto section1 = test_file1->access_data_sections().at( 0 ); std::string path = "bg/ffxiv/" + zonePath + "/collision/"; int offset1 = 0x20; for( ; ; ) @@ -180,7 +179,7 @@ int main( int argc, char* argv[] ) int counter = 0; // dont bother if we cant write to a file - auto fp_out = fopen( (zoneName + ".obj").c_str(), "w" ); + auto fp_out = fopen( ( zoneName + ".obj" ).c_str(), "w" ); if( fp_out ) { fprintf( fp_out, "\n" ); @@ -191,11 +190,11 @@ int main( int argc, char* argv[] ) 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() ); + throw std::runtime_error( errorMessage.c_str() ); return 0; } - fp_out = fopen( (zoneName + ".obj").c_str(), "ab+" ); + fp_out = fopen( ( zoneName + ".obj" ).c_str(), "ab+" ); if( fp_out ) { std::map pcbFiles; @@ -212,7 +211,6 @@ int main( int argc, char* argv[] ) //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 ); @@ -235,7 +233,6 @@ int main( int argc, char* argv[] ) { parseBlockEntry( &dataSection[0] + offset, pcb_file.entries, offset ); } - groupCount++; } pcbFiles.insert( std::make_pair( fileName, pcb_file ) ); } @@ -246,10 +243,10 @@ int main( int argc, char* argv[] ) }; 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]++ )); + 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 ) + for( const auto &entry : pcb_file.entries ) { float x_base = abs( float( entry.header.x1 - entry.header.x ) ); float y_base = abs( float( entry.header.y1 - entry.header.y ) ); @@ -303,7 +300,7 @@ int main( int argc, char* argv[] ) 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; + // 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(); } @@ -324,20 +321,17 @@ int main( int argc, char* argv[] ) totalGroups++; for( const auto pEntry : group.entries ) { - auto pBgParts = dynamic_cast(pEntry.get()); - + auto pBgParts = static_cast( pEntry.get() ); auto& fileName = pBgParts->collisionFileName; - if( pBgParts ) - { - if ( fileName.empty() ) - fileName = pBgParts->modelFileName; - boost::replace_all( fileName, "bgparts", "collision" ); - boost::replace_all( fileName, ".mdl", ".pcb" ); - } - if( !pBgParts || fileName.empty() ) + if( fileName.empty() ) continue; + { + //boost::replace_all( fileName, "bgparts", "collision" ); + //boost::replace_all( fileName, ".mdl", ".pcb" ); + } + { const auto& it = pcbFiles.find( fileName ); if( it == pcbFiles.end() ) @@ -351,8 +345,6 @@ int main( int argc, char* argv[] ) { totalGroupEntries++; - //std::cout << pBgParts->collisionFileName << "\n"; - const auto* scale = &pBgParts->header.scale; const auto* rotation = &pBgParts->header.rotation; const auto* translation = &pBgParts->header.translation; @@ -366,11 +358,11 @@ int main( int argc, char* argv[] ) std::cout << "Total Groups " << totalGroups << " Total entries " << totalGroupEntries << "\n"; } std::cout << "Finished exporting " << zoneName << " in " << - std::chrono::duration_cast(std::chrono::system_clock::now() - startTime).count() << " seconds\n"; + std::chrono::duration_cast( std::chrono::system_clock::now() - startTime ).count() << " seconds\n"; } catch( std::exception& e ) { std::cout << e.what() << std::endl; } return 0; -} \ No newline at end of file +} diff --git a/src/tools/pcb_reader/matrix4.h b/src/tools/pcb_reader/matrix4.h index 981d5a98..d02d2c84 100644 --- a/src/tools/pcb_reader/matrix4.h +++ b/src/tools/pcb_reader/matrix4.h @@ -2,6 +2,7 @@ #define _MATRIX4_H #include +#include // https://github.com/jpd002/Play--Framework/tree/master/include/math struct matrix4 @@ -96,4 +97,4 @@ struct matrix4 return ret; } }; -#endif \ No newline at end of file +#endif diff --git a/src/tools/pcb_reader/pcb.h b/src/tools/pcb_reader/pcb.h index b8f451a9..4b775d84 100644 --- a/src/tools/pcb_reader/pcb.h +++ b/src/tools/pcb_reader/pcb.h @@ -74,19 +74,19 @@ struct PCB_FILE struct PCB_LIST_ENTRY { - uint32_t id; - float x, y, z, x2, y2, z2, rot; + uint32_t id; + float x, y, z, x2, y2, z2, rot; }; struct PCB_LIST_BASE_ENTRY { - float x, y, z, x2, y2, z2, rot; + float x, y, z, x2, y2, z2, rot; }; struct PCB_LIST_FILE { - uint32_t count; - PCB_LIST_BASE_ENTRY entry; - std::vector entries; + uint32_t count; + PCB_LIST_BASE_ENTRY entry; + std::vector entries; }; #endif \ No newline at end of file From 842199b735118e69a3fdc270ee312d163a1c9fa4 Mon Sep 17 00:00:00 2001 From: Tahir Akhlaq Date: Thu, 19 Oct 2017 16:29:17 +0100 Subject: [PATCH 09/11] fixed collision dumping - added saintcoinach's sgb parsing --- src/tools/pcb_reader/lgb.h | 11 +- src/tools/pcb_reader/main.cpp | 115 ++++++++++++++++----- src/tools/pcb_reader/sgb.h | 189 ++++++++++++++++++++++++++++++++++ 3 files changed, 285 insertions(+), 30 deletions(-) create mode 100644 src/tools/pcb_reader/sgb.h diff --git a/src/tools/pcb_reader/lgb.h b/src/tools/pcb_reader/lgb.h index 3ad58b89..eb337ef6 100644 --- a/src/tools/pcb_reader/lgb.h +++ b/src/tools/pcb_reader/lgb.h @@ -11,6 +11,7 @@ #include "matrix4.h" #include "vec3.h" +#include "sgb.h" // all credit to // https://github.com/ufx/SaintCoinach/blob/master/SaintCoinach/Graphics/Lgb/ @@ -134,11 +135,13 @@ class LGB_GIMMICK_ENTRY : public LGB_MODEL_ENTRY public: LGB_GIMMICK_HEADER header; std::string name; - + std::string gimmickFileName; + LGB_GIMMICK_ENTRY( char* buf, uint32_t offset ) { header = *reinterpret_cast( buf + offset ); name = std::string( buf + offset + header.nameOffset ); + gimmickFileName = std::string( buf + offset + header.gimmickFileOffset ); }; }; @@ -184,12 +187,12 @@ struct LGB_GROUP if( type == LgbEntryType::BgParts ) { entries.push_back( std::make_shared( buf, entryOffset ) ); - } - /* + } else if( type == LgbEntryType::Gimmick ) { - //entries[i] = std::make_shared( buf, entryOffset ); + entries.push_back( std::make_shared( buf, entryOffset ) ); } + /* else { //entries[i] = nullptr; diff --git a/src/tools/pcb_reader/main.cpp b/src/tools/pcb_reader/main.cpp index e6dbffd5..2774f30f 100644 --- a/src/tools/pcb_reader/main.cpp +++ b/src/tools/pcb_reader/main.cpp @@ -4,6 +4,7 @@ #include "pcb.h" #include "lgb.h" +#include "sgb.h" #include #include @@ -198,8 +199,9 @@ int main( int argc, char* argv[] ) if( fp_out ) { std::map pcbFiles; + std::map sgbFiles; std::map objCount; - auto loadPcbFile = [&]( const std::string& fileName ) + auto loadPcbFile = [&]( const std::string& fileName ) -> bool { try { @@ -214,7 +216,7 @@ int main( int argc, char* argv[] ) PCB_FILE pcb_file; memcpy( &pcb_file.header, &dataSection[0], sizeof( pcb_file.header ) ); offset += sizeof( pcb_file.header ); - + pcb_file.entries.resize( pcb_file.header.num_entries ); bool isgroup = true; while( isgroup ) { @@ -235,16 +237,38 @@ int main( int argc, char* argv[] ) } } pcbFiles.insert( std::make_pair( fileName, pcb_file ) ); + return true; } catch( std::exception& e ) { 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 ) { - std::string name2 = ( name + "_" + std::to_string( objCount[name]++ ) ); - fprintf( fp_out, "o %s\n", name2.c_str() ); + char name2[0x7F]; + 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; for( const auto &entry : pcb_file.entries ) { @@ -321,37 +345,76 @@ int main( int argc, char* argv[] ) totalGroups++; for( const auto pEntry : group.entries ) { - auto pBgParts = static_cast( pEntry.get() ); - auto& fileName = pBgParts->collisionFileName; + LGB_GIMMICK_ENTRY* pGimmick = nullptr; + auto pBgParts = dynamic_cast( pEntry.get() ); + if( pBgParts && pBgParts->header.type != LgbEntryType::BgParts ) + pBgParts = nullptr; - if( fileName.empty() ) + auto& fileName = pBgParts ? pBgParts->collisionFileName : ""; + + if( pBgParts && fileName.empty() ) 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 ); - //std::cout << "\t\tLoaded PCB File " << pBgParts->collisionFileName << "\n"; + const auto& it = pcbFiles.find( fileName ); + if( it == pcbFiles.end() ) + { + if( !fileName.empty() ) + loadPcbFile( fileName ); + //std::cout << "\t\tLoaded PCB File " << pBgParts->collisionFileName << "\n"; + } } - } - const auto& it = pcbFiles.find( fileName ); - if( it != pcbFiles.end() ) + const auto& it = pcbFiles.find( fileName ); + 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( 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; - const auto* rotation = &pBgParts->header.rotation; - const auto* translation = &pBgParts->header.translation; - - const auto& pcb_file = it->second; - pushVerts( pcb_file, fileName, scale, rotation, translation ); + for( const auto& group : sgbFile.entries ) + { + for( const auto& pEntry : group.entries ) + { + auto pModel = dynamic_cast( pEntry.get() ); + if( !pModel->collisionFileName.empty() ) + { + fileName = pModel->collisionFileName; + writeOutput(); + } + } + } + } + continue; } + // bgparts + writeOutput(); } } std::cout << "\n\nLoaded " << pcbFiles.size() << " PCB Files \n"; diff --git a/src/tools/pcb_reader/sgb.h b/src/tools/pcb_reader/sgb.h new file mode 100644 index 00000000..5ca9e3a4 --- /dev/null +++ b/src/tools/pcb_reader/sgb.h @@ -0,0 +1,189 @@ +#ifndef _SGB_H +#define _SGB_H + +#include +#include +#include +#include +#include +#include +#include + +#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( 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> entries; + + SGB_GROUP( char* buf, SGB_FILE* file, uint32_t offset ) + { + parent = file; + header = *reinterpret_cast( 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( buf + ( entriesOffset + i * 4 ) ); + + auto type = *reinterpret_cast( buf + entryOffset ); + if( type == SgbGroupEntryType::Model ) + { + entries.push_back( std::make_shared( 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 entries; + + SGB_FILE( char* buf ) + { + constexpr int baseOffset = 0x14; + header = *reinterpret_cast( 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 From 3b2b3c73492d7f4ac1269b07320f94148ea886d9 Mon Sep 17 00:00:00 2001 From: Tahir Akhlaq Date: Thu, 19 Oct 2017 17:26:01 +0100 Subject: [PATCH 10/11] fix pcb linux build --- src/tools/pcb_reader/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/pcb_reader/main.cpp b/src/tools/pcb_reader/main.cpp index 2774f30f..c5497ad5 100644 --- a/src/tools/pcb_reader/main.cpp +++ b/src/tools/pcb_reader/main.cpp @@ -350,7 +350,7 @@ int main( int argc, char* argv[] ) if( pBgParts && pBgParts->header.type != LgbEntryType::BgParts ) pBgParts = nullptr; - auto& fileName = pBgParts ? pBgParts->collisionFileName : ""; + auto& fileName = pBgParts ? pBgParts->collisionFileName : std::string(); if( pBgParts && fileName.empty() ) continue; From 4f557340c51f33edf99c7ec45974289516e1fded Mon Sep 17 00:00:00 2001 From: Tahir Akhlaq Date: Thu, 19 Oct 2017 17:49:08 +0100 Subject: [PATCH 11/11] fix linux build for pcb reader --- src/tools/pcb_reader/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/pcb_reader/main.cpp b/src/tools/pcb_reader/main.cpp index c5497ad5..412695ce 100644 --- a/src/tools/pcb_reader/main.cpp +++ b/src/tools/pcb_reader/main.cpp @@ -350,7 +350,7 @@ int main( int argc, char* argv[] ) if( pBgParts && pBgParts->header.type != LgbEntryType::BgParts ) pBgParts = nullptr; - auto& fileName = pBgParts ? pBgParts->collisionFileName : std::string(); + auto fileName = pBgParts ? pBgParts->collisionFileName : std::string(""); if( pBgParts && fileName.empty() ) continue;