1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-28 07:07:45 +00:00

clean up some includes in pcb_reader

- fix deadlock
This commit is contained in:
Tahir Akhlaq 2019-01-20 20:14:40 +00:00
parent fb99dfc915
commit 3348cc9c47
7 changed files with 277 additions and 224 deletions

View file

@ -2,13 +2,17 @@
#define EXPORTMGR_H #define EXPORTMGR_H
#include "exporter.h" #include "exporter.h"
#include "navmesh_exporter.h"
#include "obj_exporter.h" #include "obj_exporter.h"
#include "threadpool.h" #include "threadpool.h"
class ExportMgr class ExportMgr
{ {
public: public:
ExportMgr(){} ExportMgr( unsigned int maxJobs = 0 )
{
m_threadpool.addWorkers( maxJobs );
}
~ExportMgr() ~ExportMgr()
{ {
waitForTasks(); waitForTasks();
@ -20,6 +24,10 @@ public:
{ {
m_threadpool.queue( [zone](){ ObjExporter::exportZone( zone ); } ); m_threadpool.queue( [zone](){ ObjExporter::exportZone( zone ); } );
} }
if( exportFileTypes & ExportFileType::Navmesh )
{
m_threadpool.queue( [zone](){ NavmeshExporter::exportZone( zone ); } );
}
} }
void exportGroup( const std::string& zoneName, const ExportedGroup& group, ExportFileType exportFileTypes ) void exportGroup( const std::string& zoneName, const ExportedGroup& group, ExportFileType exportFileTypes )
@ -28,6 +36,10 @@ public:
{ {
m_threadpool.queue( [zoneName, group](){ ObjExporter::exportGroup( zoneName, group ); } ); m_threadpool.queue( [zoneName, group](){ ObjExporter::exportGroup( zoneName, group ); } );
} }
if( exportFileTypes & ExportFileType::Navmesh )
{
m_threadpool.queue( [zoneName, group](){ NavmeshExporter::exportGroup( zoneName, group ); } );
}
} }
void waitForTasks() void waitForTasks()

View file

@ -295,7 +295,7 @@ struct LGB_GROUP
} }
catch( std::exception& e ) catch( std::exception& e )
{ {
std::cout << name << " " << e.what() << std::endl; std::cout << ( name + " " + e.what() + "\n" );
} }
} }
}; };

View file

@ -29,12 +29,6 @@
#include <ExdCat.h> #include <ExdCat.h>
#include <Exd.h> #include <Exd.h>
#include <condition_variable>
#include <recastnavigation/Recast/Include/Recast.h>
#include <recastnavigation/Recast/Include/RecastAlloc.h>
// garbage to ignore models // garbage to ignore models
bool noObj = false; bool noObj = false;
@ -42,6 +36,7 @@ std::string gamePath( "C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\
std::unordered_map< uint16_t, std::string > zoneNameMap; std::unordered_map< uint16_t, std::string > zoneNameMap;
uint32_t zoneId; uint32_t zoneId;
std::set< std::string > zoneDumpList; std::set< std::string > zoneDumpList;
std::shared_ptr< Cache > pCache; std::shared_ptr< Cache > pCache;
@ -96,12 +91,12 @@ std::string zoneNameToPath( const std::string& name )
//path = path.substr( path.find_first_of( "/" ) + 1, path.size() - path.find_first_of( "/" )); //path = path.substr( path.find_first_of( "/" ) + 1, path.size() - path.find_first_of( "/" ));
//path = std::string( "ffxiv/" ) + path; //path = std::string( "ffxiv/" ) + path;
path = std::string( "bg/" ) + path.substr( 0, path.find( "/level/" ) ); path = std::string( "bg/" ) + path.substr( 0, path.find( "/level/" ) );
std::cout << "[Info] " << "Found path for " << name << ": " << path << std::endl; printf( "[Info] Found path for %s\n", name.c_str() );
} }
else else
{ {
throw std::runtime_error( "Unable to find path for " + name + throw std::runtime_error( "Unable to find path for " + name +
".\n\tPlease double check spelling or open 0a0000.win32.index with FFXIV Explorer and extract territorytype.exh as CSV\n\tand copy territorytype.exh.csv into pcb_reader.exe directory if using standalone" ); ".\n\tPlease double check spelling." );
} }
return path; return path;
@ -145,7 +140,7 @@ int main( int argc, char* argv[] )
} }
catch( std::exception& e ) catch( std::exception& e )
{ {
std::cout << "Unable to initialise EXD! Usage: pcb_reader <teri> \"path/to/FINAL FANTASY XIV - A REALM REBORN/game/sqpack\"" << std::endl; printf( "Unable to initialise EXD! Usage: pcb_reader <teri> \"path/to/FINAL FANTASY XIV - A REALM REBORN/game/sqpack\" [--no-obj, --dump-all, --navmesh]" );
return -1; return -1;
} }
ExportMgr exportMgr; ExportMgr exportMgr;
@ -221,211 +216,205 @@ int main( int argc, char* argv[] )
uint32_t max_index = 0; uint32_t max_index = 0;
int totalModels = 0; int totalModels = 0;
auto buildModelEntry = [ & ]( std::shared_ptr< PCB_FILE > pPcbFile, ExportedGroup& exportedGroup,
const std::string& name, const std::string& groupName,
const vec3* scale = nullptr,
const vec3* rotation = nullptr,
const vec3* translation = nullptr,
const SGB_MODEL_ENTRY* pSgbEntry = nullptr )
{ {
auto buildModelEntry = [ & ]( std::shared_ptr< PCB_FILE > pPcbFile, ExportedGroup& exportedGroup, auto& pcb_file = *pPcbFile.get();
const std::string& name, const std::string& groupName,
const vec3* scale = nullptr, ExportedModel model;
const vec3* rotation = nullptr, model.name = name + "_" + std::to_string( totalModels++ );
const vec3* translation = nullptr, model.meshes.resize( pcb_file.entries.size() );
const SGB_MODEL_ENTRY* pSgbEntry = nullptr )
uint32_t meshCount = 0;
for( const auto& entry : pcb_file.entries )
{ {
ExportedMesh mesh;
auto& pcb_file = *pPcbFile.get(); mesh.verts.resize( ( entry.header.num_vertices + entry.header.num_v16 ) * 3 );
mesh.indices.resize( entry.header.num_indices * 3 );
ExportedModel model; float x_base = abs( float( entry.header.x1 - entry.header.x ) );
model.name = name + "_" + std::to_string( totalModels++ ); float y_base = abs( float( entry.header.y1 - entry.header.y ) );
model.meshes.resize( pcb_file.entries.size() ); float z_base = abs( float( entry.header.z1 - entry.header.z ) );
uint32_t groupCount = 0; auto makeTranslation = [ & ]( vec3& v )
for( const auto& entry : pcb_file.entries )
{ {
ExportedMesh mesh; if( pSgbEntry )
int verts = 0;
int indices = 0;
mesh.verts.resize( ( entry.header.num_vertices + entry.header.num_v16 ) * 3 );
mesh.indices.resize( entry.header.num_indices * 3 );
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( pSgbEntry ) v.x *= pSgbEntry->header.scale.x;
v.y *= pSgbEntry->header.scale.y;
v.z *= pSgbEntry->header.scale.z;
v = v * matrix4::rotateX( pSgbEntry->header.rotation.x );
v = v * matrix4::rotateY( pSgbEntry->header.rotation.y );
v = v * matrix4::rotateZ( pSgbEntry->header.rotation.z );
v.x += pSgbEntry->header.translation.x;
v.y += pSgbEntry->header.translation.y;
v.z += pSgbEntry->header.translation.z;
}
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;
}
};
int verts = 0;
int indices = 0;
for( auto& vertex : entry.data.vertices )
{
vec3 v( vertex.x, vertex.y, vertex.z );
makeTranslation( v );
mesh.verts[ verts++ ] = v.x;
mesh.verts[ verts++ ] = v.y;
mesh.verts[ verts++ ] = 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 );
mesh.verts[ verts++ ] = v.x;
mesh.verts[ verts++ ] = v.y;
mesh.verts[ verts++ ] = v.z;
}
for( const auto& index : entry.data.indices )
{
mesh.indices[ indices++ ] = index.index[ 0 ];
mesh.indices[ indices++ ] = index.index[ 1 ];
mesh.indices[ indices++ ] = index.index[ 2 ];
// 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();
model.meshes[ meshCount++ ] = mesh;
}
exportedGroup.models[model.name] = model;
};
ExportedGroup exportedTerrainGroup;
exportedTerrainGroup.name = zoneName + "_terrain";
for( const auto& fileName : stringList )
{
if( auto pPcbFile = pCache->getPcbFile( fileName ) )
buildModelEntry( pPcbFile, exportedTerrainGroup, fileName, zoneName );
}
exportMgr.exportGroup( zoneName, exportedTerrainGroup, ( ExportFileType )exportFileType );
for( const auto& lgb : lgbList )
{
for( const auto& group : lgb.groups )
{
ExportedGroup exportedGroup;
exportedGroup.name = group.name;
max_index = 0;
//std::cout << "\t" << group.name << " Size " << group.header.entryCount << "\n";
for( const auto& pEntry : group.entries )
{
std::string fileName( "" );
fileName.resize( 256 );
// write files
auto pcbTransformModel = [&]( const std::string& fileName, const vec3* scale, const vec3* rotation,
const vec3* translation, const SGB_MODEL_ENTRY* pModel = nullptr )-> bool
{
if( auto pPcbFile = pCache->getPcbFile( fileName ) )
{ {
v.x *= pSgbEntry->header.scale.x; buildModelEntry( pPcbFile, exportedGroup, fileName, group.name, scale, rotation, translation, pModel );
v.y *= pSgbEntry->header.scale.y;
v.z *= pSgbEntry->header.scale.z;
v = v * matrix4::rotateX( pSgbEntry->header.rotation.x );
v = v * matrix4::rotateY( pSgbEntry->header.rotation.y );
v = v * matrix4::rotateZ( pSgbEntry->header.rotation.z );
v.x += pSgbEntry->header.translation.x;
v.y += pSgbEntry->header.translation.y;
v.z += pSgbEntry->header.translation.z;
} }
return true;
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 ) switch( pEntry->getType() )
{ {
vec3 v( vertex.x, vertex.y, vertex.z ); case LgbEntryType::BgParts:
makeTranslation( v );
mesh.verts[ verts++ ] = v.x;
mesh.verts[ verts++ ] = v.y;
mesh.verts[ verts++ ] = 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 );
mesh.verts[ verts++ ] = v.x;
mesh.verts[ verts++ ] = v.y;
mesh.verts[ verts++ ] = v.z;
}
//fprintf( fp_out, "g %s_", (name2 + "_" + std::to_string( groupCount++ )).c_str() );
for( const auto& index : entry.data.indices )
{
mesh.indices[ indices++ ] = index.index[ 0 ];
mesh.indices[ indices++ ] = index.index[ 1 ];
mesh.indices[ indices++ ] = index.index[ 2 ];
// 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();
model.meshes.push_back( mesh );
}
exportedGroup.models[model.name] = model;
};
ExportedGroup exportedTerrainGroup;
exportedTerrainGroup.name = zoneName;
for( const auto& fileName : stringList )
{
if( auto pPcbFile = pCache->getPcbFile( fileName ) )
buildModelEntry( pPcbFile, exportedTerrainGroup, fileName, zoneName );
}
for( const auto& lgb : lgbList )
{
for( const auto& group : lgb.groups )
{
ExportedGroup exportedGroup;
exportedGroup.name = group.name;
max_index = 0;
//std::cout << "\t" << group.name << " Size " << group.header.entryCount << "\n";
for( const auto& pEntry : group.entries )
{
std::string fileName( "" );
fileName.resize( 256 );
// write files
auto writeOutput = [&](const std::string& fileName, const vec3* scale, const vec3* rotation,
const vec3* translation, const SGB_MODEL_ENTRY* pModel = nullptr)->bool
{ {
if( auto pPcbFile = pCache->getPcbFile( fileName ) ) auto pBgParts = static_cast<LGB_BGPARTS_ENTRY*>(pEntry.get());
{ fileName = pBgParts->collisionFileName;
buildModelEntry( pPcbFile, exportedGroup, fileName, group.name, scale, rotation, translation, pModel ); pcbTransformModel( fileName, &pBgParts->header.scale, &pBgParts->header.rotation,
} &pBgParts->header.translation );
return true; }
}; break;
switch( pEntry->getType() ) // gimmick entry
case LgbEntryType::Gimmick:
{ {
case LgbEntryType::BgParts: auto pGimmick = static_cast<LGB_GIMMICK_ENTRY*>( pEntry.get() );
if( auto pSgbFile = pCache->getSgbFile( pGimmick->gimmickFileName ) )
{ {
auto pBgParts = static_cast<LGB_BGPARTS_ENTRY*>(pEntry.get()); const auto& sgbFile = *pSgbFile;
fileName = pBgParts->collisionFileName; for( const auto& group : sgbFile.entries )
writeOutput( fileName, &pBgParts->header.scale, &pBgParts->header.rotation,
&pBgParts->header.translation );
}
break;
// gimmick entry
case LgbEntryType::Gimmick:
{
auto pGimmick = static_cast<LGB_GIMMICK_ENTRY*>(pEntry.get());
if (auto pSgbFile = pCache->getSgbFile(pGimmick->gimmickFileName))
{ {
const auto& sgbFile = *pSgbFile; for( const auto& pEntry : group.entries )
for (const auto& group : sgbFile.entries)
{ {
for (const auto& pEntry : group.entries) auto pModel = dynamic_cast< SGB_MODEL_ENTRY* >( pEntry.get() );
{ fileName = pModel->collisionFileName;
auto pModel = dynamic_cast<SGB_MODEL_ENTRY*>(pEntry.get()); pcbTransformModel( fileName, &pGimmick->header.scale, &pGimmick->header.rotation,
fileName = pModel->collisionFileName; &pGimmick->header.translation, pModel );
writeOutput( fileName, &pGimmick->header.scale, &pGimmick->header.rotation,
&pGimmick->header.translation, pModel );
}
} }
} }
} }
case LgbEntryType::EventObject:
{
writeOutput( fileName, &pEntry->header.scale, &pEntry->header.rotation, &pEntry->header.translation );
}
break;
default:
break;
} }
}
exportMgr.exportGroup( zoneName, exportedGroup, ( ExportFileType )exportFileType );
//exportedZone.groups.emplace( group.name, exportedGroup );
}
}
//exportMgr.exportZone( exportedZone, ( ExportFileType )exportFileType );
//std::cout << "[Info] " << "Loaded " << pcbFiles.size() << " PCB Files \n";
std::cout << "[Info] " << "Total Groups " << totalGroups << "\n";
}
std::cout << "[Success] " << "Exported " << zoneName << " in " << case LgbEntryType::EventObject:
std::chrono::duration_cast< std::chrono::seconds >( {
std::chrono::high_resolution_clock::now() - entryStartTime ).count() << " seconds\n"; pcbTransformModel( fileName, &pEntry->header.scale, &pEntry->header.rotation, &pEntry->header.translation );
}
break;
default:
break;
}
}
exportMgr.exportGroup( zoneName, exportedGroup, ( ExportFileType )exportFileType );
//exportedZone.groups.emplace( group.name, exportedGroup );
}
}
//exportMgr.exportZone( exportedZone, ( ExportFileType )exportFileType );
printf( "Exported %s in %u seconds \n",
zoneName.c_str(),
std::chrono::duration_cast< std::chrono::seconds >( std::chrono::high_resolution_clock::now() - entryStartTime ) );
} }
catch( std::exception& e ) catch( std::exception& e )
{ {
std::cout << "[Error] " << e.what() << std::endl; printf( ( std::string( e.what() ) + "\n" ).c_str() );
std::cout << "[Error] " printf( "Unable to extract collision data.\n" );
<< "Unable to extract collision data.\n" printf( "Usage: pcb_reader2 territory \"path/to/game/sqpack/ffxiv\"\n" );
<< std::endl;
std::cout << std::endl;
std::cout << "[Info] " << "Usage: pcb_reader2 territory \"path/to/game/sqpack/ffxiv\" " << std::endl;
} }
} }
exportMgr.waitForTasks(); exportMgr.waitForTasks();
std::cout << "\n\n\n"; std::cout << "\n\n\n";
std::cout << "\n\n\n[Success] Finished all tasks in " << printf( "Finished all tasks in %u seconds\n",
std::chrono::duration_cast< std::chrono::seconds >( std::chrono::high_resolution_clock::now() - startTime ).count() std::chrono::duration_cast< std::chrono::seconds >( std::chrono::high_resolution_clock::now() - startTime ).count() );
<< " seconds\n";
getchar(); getchar();

View file

@ -1,5 +1,5 @@
#ifndef OBJ_EXPORTER_H #ifndef NAVMESH_EXPORTER_H
#define OBJ_EXPORTER_H #define NAVMESH_EXPORTER_H
#include <iostream> #include <iostream>
#include <cstdint> #include <cstdint>
@ -10,7 +10,12 @@
#include "exporter.h" #include "exporter.h"
static class ObjExporter : public Exporter #include <recastnavigation/Recast/Include/Recast.h>
#include <recastnavigation/Recast/Include/RecastAlloc.h>
#include <recastnavigation/Detour/Include/DetourNavMesh.h>
#include <recastnavigation/Detour/Include/DetourNavMeshBuilder.h>
class NavmeshExporter : public Exporter
{ {
public: public:
static void exportZone( const ExportedZone& zone ) static void exportZone( const ExportedZone& zone )
@ -20,8 +25,9 @@ public:
auto fileName = zone.name + ".obj"; auto fileName = zone.name + ".obj";
auto end = std::chrono::high_resolution_clock::now(); auto end = std::chrono::high_resolution_clock::now();
std::cout << ( "Finished exporting " + fileName + " in " + printf( "[Navmesh] Finished exporting %s in %u ms\n",
std::to_string( std::chrono::duration_cast< std::chrono::seconds >( end - start ).count() ) + " seconds\n" ); fileName,
std::chrono::duration_cast< std::chrono::milliseconds >( end - start ).count() );
} }
static void exportGroup( const std::string& zoneName, const ExportedGroup& group ) static void exportGroup( const std::string& zoneName, const ExportedGroup& group )
@ -32,8 +38,9 @@ public:
auto end = std::chrono::high_resolution_clock::now(); auto end = std::chrono::high_resolution_clock::now();
std::cout << ( "Finished exporting " + fileName + " in " + printf( "[Navmesh] Finished exporting %s in %u ms\n",
std::to_string( std::chrono::duration_cast< std::chrono::seconds >( end - start ).count() ) + " seconds\n" ); fileName,
std::chrono::duration_cast< std::chrono::milliseconds >( end - start ).count() );
} }
private: private:
static void exportGroup( const ExportedGroup& group, std::ofstream& of, int& indicesOffset, int& modelCount ) static void exportGroup( const ExportedGroup& group, std::ofstream& of, int& indicesOffset, int& modelCount )

View file

@ -1,22 +1,38 @@
#ifndef OBJ_EXPORTER_H #ifndef OBJ_EXPORTER_H
#define OBJ_EXPORTER_H #define OBJ_EXPORTER_H
#include <chrono>
#include <cstdint> #include <cstdint>
#include <experimental/filesystem>
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <chrono>
#include "exporter.h" #include "exporter.h"
class ObjExporter : public Exporter class ObjExporter : public Exporter
{ {
public: public:
static void exportZone( const ExportedZone& zone ) static void exportZone( const ExportedZone& zone )
{ {
static std::string currPath = std::experimental::filesystem::current_path().string();
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
auto fileName = zone.name + ".obj"; auto dir = currPath + "/" + zone.name + "/";
auto fileName = dir + "/" + zone.name + ".obj";
std::error_code e;
if( !std::experimental::filesystem::exists( dir, e ) )
{
if( !std::experimental::filesystem::create_directory( dir, e ) )
{
printf( "Unable to create directory '%s'", ( dir ).c_str() );
return;
}
}
std::ofstream of( fileName, std::ios::trunc ); std::ofstream of( fileName, std::ios::trunc );
int indicesOffset = 0; int indicesOffset = 0;
int meshesCount = 0; int meshesCount = 0;
@ -34,15 +50,29 @@ public:
} }
auto end = std::chrono::high_resolution_clock::now(); auto end = std::chrono::high_resolution_clock::now();
std::cout << ( "Finished exporting " + fileName + " in " + printf( "[Obj] Finished exporting %s in %u ms\n",
std::to_string( std::chrono::duration_cast< std::chrono::milliseconds >( end - start ).count() ) + "ms \n" ); fileName,
std::chrono::duration_cast< std::chrono::milliseconds >( end - start ).count() );
} }
static void exportGroup( const std::string& zoneName, const ExportedGroup& group ) static void exportGroup( const std::string& zoneName, const ExportedGroup& group )
{ {
static std::string currPath = std::experimental::filesystem::current_path().string();
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
auto fileName = zoneName + "_" + group.name + ".obj"; auto dir = currPath + "/" + zoneName + "/";
auto fileName = dir + "/" + group.name + ".obj";
std::error_code e;
if( !std::experimental::filesystem::exists( dir, e ) )
{
if( !std::experimental::filesystem::create_directory( dir, e ) )
{
printf( "Unable to create directory '%s'", ( dir ).c_str() );
return;
}
}
std::ofstream of( fileName, std::ios::trunc ); std::ofstream of( fileName, std::ios::trunc );
int indicesOffset = 0; int indicesOffset = 0;
int modelCount = 0; int modelCount = 0;
@ -57,42 +87,47 @@ public:
} }
auto end = std::chrono::high_resolution_clock::now(); auto end = std::chrono::high_resolution_clock::now();
std::cout << ( "Finished exporting " + fileName + " in " + printf( "[Obj] Finished exporting %s in %u ms\n",
std::to_string( std::chrono::duration_cast< std::chrono::milliseconds >( end - start ).count() ) + "ms\n" ); fileName.c_str(),
std::chrono::duration_cast< std::chrono::milliseconds >( end - start ).count() );
} }
private: private:
static void exportGroup( const ExportedGroup& group, std::ofstream& of, int& indicesOffset, int& modelCount ) static void exportGroup( const ExportedGroup& group, std::ofstream& of, int& indicesOffset, int& modelCount )
{ {
int currModelCount = modelCount; int currModelCount = modelCount;
//of << ( "o " + group.name + "_" + std::to_string( currModelCount ) + "\n" ); of << "o " << group.name << '_' << std::to_string( currModelCount ) << '\n';
for( const auto& model : group.models ) for( const auto& model : group.models )
{ {
of << ( "o " + model.second.name + "_" + std::to_string( currModelCount ) + "_" + std::to_string( modelCount++ ) + "\n" ); modelCount++;
of << "o " << model.second.name << '_' << std::to_string( currModelCount ) << '_' << std::to_string( modelCount ) << '\n';
int meshCount = 0; int meshCount = 0;
for( const auto& mesh : model.second.meshes ) for( const auto& mesh : model.second.meshes )
{ {
for( int i = 0; i + 2 < mesh.verts.size(); i += 3 ) for( int i = 0; i < mesh.verts.size(); i += 3 )
{ {
of << ( of << "v " <<
"v " + std::to_string( mesh.verts[ i ] ) + " " + std::to_string( mesh.verts[ i ] ) << ' ' <<
std::to_string( mesh.verts[ i + 1 ] ) + " " + std::to_string( mesh.verts[ i + 1 ] ) << ' ' <<
std::to_string( mesh.verts[ i + 2 ] ) + "\n" std::to_string( mesh.verts[ i + 2 ] ) << '\n';
);
} }
//of << ( "g " + model.second.name + "_" + std::to_string( currModelCount ) + "_" + std::to_string( modelCount ) + "_" + std::to_string( meshCount++ ) + "\n" );
for( int i = 0; i + 2 < mesh.indices.size(); i += 3 ) of << "g " <<
model.second.name << '_' <<
std::to_string( currModelCount ) << '_' << std::to_string( modelCount ) << '_' << std::to_string( meshCount++ ) << '\n';
for( int i = 0; i < mesh.indices.size(); i += 3 )
{ {
of << ( of << "f " <<
"f " + std::to_string( mesh.indices[ i ] + indicesOffset + 1 ) + " " + std::to_string( mesh.indices[ i ] + indicesOffset + 1 ) << ' ' <<
std::to_string( mesh.indices[i + 1] + indicesOffset + 1 ) + " " + std::to_string( mesh.indices[ i + 1 ] + indicesOffset + 1 ) << ' ' +
std::to_string( mesh.indices[i + 2] + indicesOffset + 1 ) + "\n" std::to_string( mesh.indices[ i + 2 ] + indicesOffset + 1 ) << '\n';
);
} }
indicesOffset += mesh.indices.size(); indicesOffset += mesh.verts.size() / 3;
} }
} }
//of.flush();
} }
}; };
#endif // !OBJ_EXPORTER_H #endif // !OBJ_EXPORTER_H

View file

@ -213,7 +213,7 @@ struct SGB_FILE
} }
catch( std::exception& e ) catch( std::exception& e )
{ {
std::cout << e.what() << "\n"; std::cout << ( std::string( e.what() ) + "\n" );
} }
}; };
}; };

View file

@ -13,12 +13,9 @@
class ThreadPool class ThreadPool
{ {
public: public:
ThreadPool( unsigned int numJobs = std::thread::hardware_concurrency() ) ThreadPool()
{ {
for( auto i = 0; i < numJobs; ++i )
{
m_workers.push_back( std::async( std::launch::async, [this]{ run(); } ) );
}
} }
~ThreadPool() ~ThreadPool()
@ -26,6 +23,17 @@ public:
complete(); complete();
} }
void addWorkers( unsigned int num )
{
if( num == 0 )
num = std::thread::hardware_concurrency() - 1;
for( auto i = 0; i < num; ++i )
{
m_workers.push_back( std::async( std::launch::async, [this]{ run(); } ) );
}
}
template< class Func, class Ret = std::result_of_t< Func&() > > template< class Func, class Ret = std::result_of_t< Func&() > >
std::future< Ret > queue( Func&& f ) std::future< Ret > queue( Func&& f )
{ {
@ -50,10 +58,12 @@ public:
bool complete() bool complete()
{ {
std::unique_lock lock( m_mutex );
for( auto&& worker : m_workers )
{ {
m_pendingJobs.push_back( {} ); std::scoped_lock lock( m_mutex );
for( auto&& worker : m_workers )
{
m_pendingJobs.push_back( {} );
}
} }
m_cv.notify_all(); m_cv.notify_all();
m_workers.clear(); m_workers.clear();