diff --git a/src/tools/pcb_reader/exportmgr.h b/src/tools/pcb_reader/exportmgr.h index 7673dc34..656e15f7 100644 --- a/src/tools/pcb_reader/exportmgr.h +++ b/src/tools/pcb_reader/exportmgr.h @@ -2,13 +2,17 @@ #define EXPORTMGR_H #include "exporter.h" +#include "navmesh_exporter.h" #include "obj_exporter.h" #include "threadpool.h" class ExportMgr { public: - ExportMgr(){} + ExportMgr( unsigned int maxJobs = 0 ) + { + m_threadpool.addWorkers( maxJobs ); + } ~ExportMgr() { waitForTasks(); @@ -20,6 +24,10 @@ public: { 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 ) @@ -28,6 +36,10 @@ public: { m_threadpool.queue( [zoneName, group](){ ObjExporter::exportGroup( zoneName, group ); } ); } + if( exportFileTypes & ExportFileType::Navmesh ) + { + m_threadpool.queue( [zoneName, group](){ NavmeshExporter::exportGroup( zoneName, group ); } ); + } } void waitForTasks() diff --git a/src/tools/pcb_reader/lgb.h b/src/tools/pcb_reader/lgb.h index bf2a3157..21628b68 100644 --- a/src/tools/pcb_reader/lgb.h +++ b/src/tools/pcb_reader/lgb.h @@ -295,7 +295,7 @@ struct LGB_GROUP } catch( std::exception& e ) { - std::cout << name << " " << e.what() << std::endl; + std::cout << ( name + " " + e.what() + "\n" ); } } }; diff --git a/src/tools/pcb_reader/main.cpp b/src/tools/pcb_reader/main.cpp index dcc498ba..53a1bb7c 100644 --- a/src/tools/pcb_reader/main.cpp +++ b/src/tools/pcb_reader/main.cpp @@ -29,12 +29,6 @@ #include #include -#include - -#include -#include - - // garbage to ignore models 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; uint32_t zoneId; + std::set< std::string > zoneDumpList; 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 = std::string( "ffxiv/" ) + path; 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 { 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; @@ -145,7 +140,7 @@ int main( int argc, char* argv[] ) } catch( std::exception& e ) { - std::cout << "Unable to initialise EXD! Usage: pcb_reader \"path/to/FINAL FANTASY XIV - A REALM REBORN/game/sqpack\"" << std::endl; + printf( "Unable to initialise EXD! Usage: pcb_reader \"path/to/FINAL FANTASY XIV - A REALM REBORN/game/sqpack\" [--no-obj, --dump-all, --navmesh]" ); return -1; } ExportMgr exportMgr; @@ -221,211 +216,205 @@ int main( int argc, char* argv[] ) uint32_t max_index = 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& pcb_file = *pPcbFile.get(); - 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 ) + ExportedModel model; + model.name = name + "_" + std::to_string( totalModels++ ); + model.meshes.resize( pcb_file.entries.size() ); + + uint32_t meshCount = 0; + for( const auto& entry : pcb_file.entries ) { - - auto& pcb_file = *pPcbFile.get(); + ExportedMesh mesh; - ExportedModel model; - model.name = name + "_" + std::to_string( totalModels++ ); - model.meshes.resize( pcb_file.entries.size() ); + mesh.verts.resize( ( entry.header.num_vertices + entry.header.num_v16 ) * 3 ); + mesh.indices.resize( entry.header.num_indices * 3 ); - uint32_t groupCount = 0; - 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 ) ); + float z_base = abs( float( entry.header.z1 - entry.header.z ) ); + + auto makeTranslation = [ & ]( vec3& v ) { - ExportedMesh mesh; - - 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 ) { - 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; - 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; + buildModelEntry( pPcbFile, exportedGroup, fileName, group.name, scale, rotation, translation, pModel ); } - - 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; - } - + return true; }; - for( auto& vertex : entry.data.vertices ) + switch( pEntry->getType() ) { - 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; - } - - //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 + case LgbEntryType::BgParts: { - if( auto pPcbFile = pCache->getPcbFile( fileName ) ) - { - buildModelEntry( pPcbFile, exportedGroup, fileName, group.name, scale, rotation, translation, pModel ); - } - return true; - }; + auto pBgParts = static_cast(pEntry.get()); + fileName = pBgParts->collisionFileName; + pcbTransformModel( fileName, &pBgParts->header.scale, &pBgParts->header.rotation, + &pBgParts->header.translation ); + } + break; - switch( pEntry->getType() ) + // gimmick entry + case LgbEntryType::Gimmick: { - case LgbEntryType::BgParts: + auto pGimmick = static_cast( pEntry.get() ); + if( auto pSgbFile = pCache->getSgbFile( pGimmick->gimmickFileName ) ) { - auto pBgParts = static_cast(pEntry.get()); - fileName = pBgParts->collisionFileName; - writeOutput( fileName, &pBgParts->header.scale, &pBgParts->header.rotation, - &pBgParts->header.translation ); - } - break; - - // gimmick entry - case LgbEntryType::Gimmick: - { - auto pGimmick = static_cast(pEntry.get()); - if (auto pSgbFile = pCache->getSgbFile(pGimmick->gimmickFileName)) + const auto& sgbFile = *pSgbFile; + for( const auto& group : sgbFile.entries ) { - const auto& sgbFile = *pSgbFile; - for (const auto& group : sgbFile.entries) + for( const auto& pEntry : group.entries ) { - for (const auto& pEntry : group.entries) - { - auto pModel = dynamic_cast(pEntry.get()); - fileName = pModel->collisionFileName; - writeOutput( fileName, &pGimmick->header.scale, &pGimmick->header.rotation, - &pGimmick->header.translation, pModel ); - } + auto pModel = dynamic_cast< SGB_MODEL_ENTRY* >( pEntry.get() ); + fileName = pModel->collisionFileName; + pcbTransformModel( 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 " << - std::chrono::duration_cast< std::chrono::seconds >( - std::chrono::high_resolution_clock::now() - entryStartTime ).count() << " seconds\n"; + case LgbEntryType::EventObject: + { + 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 ) { - std::cout << "[Error] " << e.what() << std::endl; - std::cout << "[Error] " - << "Unable to extract collision data.\n" - << std::endl; - std::cout << std::endl; - std::cout << "[Info] " << "Usage: pcb_reader2 territory \"path/to/game/sqpack/ffxiv\" " << std::endl; + printf( ( std::string( e.what() ) + "\n" ).c_str() ); + printf( "Unable to extract collision data.\n" ); + printf( "Usage: pcb_reader2 territory \"path/to/game/sqpack/ffxiv\"\n" ); } } exportMgr.waitForTasks(); std::cout << "\n\n\n"; - std::cout << "\n\n\n[Success] Finished all tasks in " << - std::chrono::duration_cast< std::chrono::seconds >( std::chrono::high_resolution_clock::now() - startTime ).count() - << " seconds\n"; + printf( "Finished all tasks in %u seconds\n", + std::chrono::duration_cast< std::chrono::seconds >( std::chrono::high_resolution_clock::now() - startTime ).count() ); getchar(); diff --git a/src/tools/pcb_reader/navmesh_exporter.h b/src/tools/pcb_reader/navmesh_exporter.h index d4580d95..be3fb349 100644 --- a/src/tools/pcb_reader/navmesh_exporter.h +++ b/src/tools/pcb_reader/navmesh_exporter.h @@ -1,5 +1,5 @@ -#ifndef OBJ_EXPORTER_H -#define OBJ_EXPORTER_H +#ifndef NAVMESH_EXPORTER_H +#define NAVMESH_EXPORTER_H #include #include @@ -10,7 +10,12 @@ #include "exporter.h" -static class ObjExporter : public Exporter +#include +#include +#include +#include + +class NavmeshExporter : public Exporter { public: static void exportZone( const ExportedZone& zone ) @@ -20,8 +25,9 @@ public: auto fileName = zone.name + ".obj"; auto end = std::chrono::high_resolution_clock::now(); - std::cout << ( "Finished exporting " + fileName + " in " + - std::to_string( std::chrono::duration_cast< std::chrono::seconds >( end - start ).count() ) + " seconds\n" ); + printf( "[Navmesh] Finished exporting %s in %u ms\n", + fileName, + std::chrono::duration_cast< std::chrono::milliseconds >( end - start ).count() ); } static void exportGroup( const std::string& zoneName, const ExportedGroup& group ) @@ -32,8 +38,9 @@ public: auto end = std::chrono::high_resolution_clock::now(); - std::cout << ( "Finished exporting " + fileName + " in " + - std::to_string( std::chrono::duration_cast< std::chrono::seconds >( end - start ).count() ) + " seconds\n" ); + printf( "[Navmesh] Finished exporting %s in %u ms\n", + fileName, + std::chrono::duration_cast< std::chrono::milliseconds >( end - start ).count() ); } private: static void exportGroup( const ExportedGroup& group, std::ofstream& of, int& indicesOffset, int& modelCount ) diff --git a/src/tools/pcb_reader/obj_exporter.h b/src/tools/pcb_reader/obj_exporter.h index 0ff70213..2a39850d 100644 --- a/src/tools/pcb_reader/obj_exporter.h +++ b/src/tools/pcb_reader/obj_exporter.h @@ -1,22 +1,38 @@ #ifndef OBJ_EXPORTER_H #define OBJ_EXPORTER_H +#include #include +#include #include #include -#include #include "exporter.h" + class ObjExporter : public Exporter { public: 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 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 ); int indicesOffset = 0; int meshesCount = 0; @@ -34,15 +50,29 @@ public: } auto end = std::chrono::high_resolution_clock::now(); - std::cout << ( "Finished exporting " + fileName + " in " + - std::to_string( std::chrono::duration_cast< std::chrono::milliseconds >( end - start ).count() ) + "ms \n" ); + printf( "[Obj] Finished exporting %s in %u ms\n", + fileName, + std::chrono::duration_cast< std::chrono::milliseconds >( end - start ).count() ); } 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 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 ); int indicesOffset = 0; int modelCount = 0; @@ -57,42 +87,47 @@ public: } auto end = std::chrono::high_resolution_clock::now(); - std::cout << ( "Finished exporting " + fileName + " in " + - std::to_string( std::chrono::duration_cast< std::chrono::milliseconds >( end - start ).count() ) + "ms\n" ); + printf( "[Obj] Finished exporting %s in %u ms\n", + fileName.c_str(), + std::chrono::duration_cast< std::chrono::milliseconds >( end - start ).count() ); } private: static void exportGroup( const ExportedGroup& group, std::ofstream& of, int& indicesOffset, int& 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 ) { - 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; 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 << ( - "v " + std::to_string( mesh.verts[ i ] ) + " " + - std::to_string( mesh.verts[ i + 1 ] ) + " " + - std::to_string( mesh.verts[ i + 2 ] ) + "\n" - ); + of << "v " << + std::to_string( mesh.verts[ i ] ) << ' ' << + std::to_string( mesh.verts[ i + 1 ] ) << ' ' << + 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 << ( - "f " + std::to_string( mesh.indices[ i ] + indicesOffset + 1 ) + " " + - std::to_string( mesh.indices[i + 1] + indicesOffset + 1 ) + " " + - std::to_string( mesh.indices[i + 2] + indicesOffset + 1 ) + "\n" - ); + of << "f " << + std::to_string( mesh.indices[ i ] + indicesOffset + 1 ) << ' ' << + std::to_string( mesh.indices[ i + 1 ] + indicesOffset + 1 ) << ' ' + + 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 diff --git a/src/tools/pcb_reader/sgb.h b/src/tools/pcb_reader/sgb.h index c6972a84..6e471be5 100644 --- a/src/tools/pcb_reader/sgb.h +++ b/src/tools/pcb_reader/sgb.h @@ -213,7 +213,7 @@ struct SGB_FILE } catch( std::exception& e ) { - std::cout << e.what() << "\n"; + std::cout << ( std::string( e.what() ) + "\n" ); } }; }; diff --git a/src/tools/pcb_reader/threadpool.h b/src/tools/pcb_reader/threadpool.h index 23c542bd..7ae96891 100644 --- a/src/tools/pcb_reader/threadpool.h +++ b/src/tools/pcb_reader/threadpool.h @@ -13,12 +13,9 @@ class ThreadPool { 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() @@ -26,6 +23,17 @@ public: 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&() > > std::future< Ret > queue( Func&& f ) { @@ -50,10 +58,12 @@ public: 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_workers.clear();