* -mergebsp [options] <mainBsp.bsp> <bspToinject.bsp>: Inject latter BSP to former. Tree and vis data of the main one are preserved.
* -mergebsp -fixnames: Make incoming BSP target/targetname names unique to not collide with existing names * -mergebsp -world: Also merge worldspawn model (brushes as if they were detail, no BSP tree is affected) (only merges entities by default)
This commit is contained in:
parent
eceb2e3259
commit
a719e012fe
|
|
@ -429,6 +429,15 @@ td.formatted_questions ol { margin-top: 0px; margin-bottom: 0px; }
|
|||
</div>
|
||||
|
||||
|
||||
<h2 id="BSP-merge">BSP merge<a href="#BSP-merge" class="wiki-anchor">¶</a></h2>
|
||||
<ul>
|
||||
<li><strong><code>-mergebsp</code> ... mainBsp.bsp bspToinject.bsp:</strong> Inject latter BSP to former. Tree and vis data of the main one are preserved.</li>
|
||||
<li><strong><code>-fixnames</code>:</strong> Make incoming BSP target/targetname names unique to not collide with existing names</li>
|
||||
<li><strong><code>-world</code>:</strong> Also merge worldspawn model (brushes as if they were detail, no BSP tree is affected) (only merges entities by default)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -664,6 +664,288 @@ int ShiftBSPMain( Args& args ){
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
MergeBSPMain()
|
||||
merges two bsps
|
||||
*/
|
||||
|
||||
int MergeBSPMain( Args& args ){
|
||||
/* arg checking */
|
||||
if ( args.size() < 2 ) {
|
||||
Sys_Printf( "Usage: q3map2 [-v] -mergebsp [-fixnames] [-world] <mainBsp> <bspToinject>\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *fileName2 = args.takeBack();
|
||||
const char *fileName1 = args.takeBack();
|
||||
const auto argsToInject = args.getVector();
|
||||
|
||||
const bool fixnames = args.takeArg( "-fixnames" );
|
||||
const bool addworld = args.takeArg( "-world" );
|
||||
|
||||
/* do some path mangling */
|
||||
strcpy( source, ExpandArg( fileName2 ) );
|
||||
path_set_extension( source, ".bsp" );
|
||||
|
||||
/* load the bsp */
|
||||
Sys_Printf( "Loading %s\n", source );
|
||||
LoadBSPFile( source );
|
||||
ParseEntities();
|
||||
|
||||
struct bsp
|
||||
{
|
||||
std::vector<entity_t> entities;
|
||||
std::vector<bspModel_t> bspModels;
|
||||
std::vector<bspShader_t> bspShaders;
|
||||
std::vector<bspLeaf_t> bspLeafs;
|
||||
std::vector<bspPlane_t> bspPlanes;
|
||||
std::vector<bspNode_t> bspNodes;
|
||||
std::vector<int> bspLeafSurfaces;
|
||||
std::vector<int> bspLeafBrushes;
|
||||
std::vector<bspBrush_t> bspBrushes;
|
||||
std::vector<bspBrushSide_t> bspBrushSides;
|
||||
std::vector<byte> bspLightBytes;
|
||||
std::vector<bspGridPoint_t> bspGridPoints;
|
||||
std::vector<byte> bspVisBytes;
|
||||
std::vector<bspDrawVert_t> bspDrawVerts;
|
||||
std::vector<int> bspDrawIndexes;
|
||||
std::vector<bspDrawSurface_t> bspDrawSurfaces;
|
||||
std::vector<bspFog_t> bspFogs;
|
||||
} bsp;
|
||||
|
||||
bsp.entities = std::move( entities );
|
||||
bsp.bspModels = std::move( bspModels );
|
||||
bsp.bspShaders = std::move( bspShaders );
|
||||
bsp.bspLeafs = std::move( bspLeafs );
|
||||
bsp.bspPlanes = std::move( bspPlanes );
|
||||
bsp.bspNodes = std::move( bspNodes );
|
||||
bsp.bspLeafSurfaces = std::move( bspLeafSurfaces );
|
||||
bsp.bspLeafBrushes = std::move( bspLeafBrushes );
|
||||
bsp.bspBrushes = std::move( bspBrushes );
|
||||
bsp.bspBrushSides = std::move( bspBrushSides );
|
||||
bsp.bspLightBytes = std::move( bspLightBytes );
|
||||
bsp.bspGridPoints = std::move( bspGridPoints );
|
||||
bsp.bspVisBytes = std::move( bspVisBytes );
|
||||
bsp.bspDrawVerts = std::move( bspDrawVerts );
|
||||
bsp.bspDrawIndexes = std::move( bspDrawIndexes );
|
||||
bsp.bspDrawSurfaces = std::move( bspDrawSurfaces );
|
||||
bsp.bspFogs = std::move( bspFogs );
|
||||
|
||||
/* do some path mangling */
|
||||
strcpy( source, ExpandArg( fileName1 ) );
|
||||
path_set_extension( source, ".bsp" );
|
||||
|
||||
/* load the bsp */
|
||||
Sys_Printf( "Loading %s\n", source );
|
||||
LoadBSPFile( source );
|
||||
ParseEntities();
|
||||
|
||||
|
||||
/* reindex */
|
||||
{
|
||||
for( auto&& model : bsp.bspModels )
|
||||
{
|
||||
model.firstBSPSurface += bspDrawSurfaces.size();
|
||||
model.firstBSPBrush += bspBrushes.size();
|
||||
}
|
||||
|
||||
for( auto&& side : bsp.bspBrushSides ){
|
||||
side.planeNum += bspPlanes.size();
|
||||
side.shaderNum += bspShaders.size();
|
||||
side.surfaceNum += bspDrawSurfaces.size();
|
||||
}
|
||||
|
||||
for( auto&& brush : bsp.bspBrushes )
|
||||
{
|
||||
brush.shaderNum += bspShaders.size();
|
||||
brush.firstSide += bspBrushSides.size();
|
||||
}
|
||||
|
||||
for( auto&& fog : bsp.bspFogs )
|
||||
fog.brushNum += bspBrushes.size();
|
||||
|
||||
/* deduce max lm index, using bspLightBytes is insufficient for native external lightmaps */
|
||||
int maxLmIndex = -3;
|
||||
for( const auto& surf : bspDrawSurfaces )
|
||||
for( auto index : surf.lightmapNum )
|
||||
value_maximize( maxLmIndex, index );
|
||||
for( auto&& surf : bsp.bspDrawSurfaces )
|
||||
{
|
||||
surf.shaderNum += bspShaders.size();
|
||||
surf.fogNum += bspFogs.size();
|
||||
surf.firstVert += bspDrawVerts.size();
|
||||
surf.firstIndex += bspDrawIndexes.size();
|
||||
for( auto&& index : surf.lightmapNum )
|
||||
if( index >= 0 && maxLmIndex >= 0 )
|
||||
index += maxLmIndex + 1;
|
||||
}
|
||||
|
||||
ENSURE( bsp.entities[0].classname_is( "worldspawn" ) );
|
||||
for( auto&& e : bsp.entities )
|
||||
{
|
||||
const char *model = e.valueForKey( "model" );
|
||||
if( model[0] == '*' ){
|
||||
e.setKeyValue( "model", StringOutputStream( 8 )( '*', atoi( model + 1 ) + bspModels.size() - 1 ) ); // -1 : minus world
|
||||
}
|
||||
}
|
||||
/* make target/targetname names unique */
|
||||
if( fixnames ){ ///! assumes there are no dummy targetnames to fix in incoming bsp
|
||||
const auto has_name = []( const std::vector<entity_t>& entities, const char *name ){
|
||||
for( auto&& e : entities )
|
||||
if( striEqual( name, e.valueForKey( "target" ) )
|
||||
|| striEqual( name, e.valueForKey( "targetname" ) ) )
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
for( auto&& e : bsp.entities )
|
||||
{
|
||||
if( const char *name; e.read_keyvalue( name, "target" ) ){
|
||||
if( has_name( entities, name ) ){
|
||||
StringOutputStream newName;
|
||||
int id = 0;
|
||||
do{
|
||||
newName( name, '_', id++ );
|
||||
} while( has_name( entities, newName )
|
||||
|| has_name( bsp.entities, newName ) );
|
||||
|
||||
const CopiedString oldName = name; // backup it, original will change
|
||||
for( auto&& e : bsp.entities )
|
||||
for( auto&& ep : e.epairs )
|
||||
if( ( striEqual( ep.key.c_str(), "target" ) || striEqual( ep.key.c_str(), "targetname" ) )
|
||||
&& striEqual( ep.value.c_str(), oldName.c_str() ) )
|
||||
ep.value = newName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
entities.insert( entities.cend(), bsp.entities.cbegin() + 1, bsp.entities.cend() ); // minus world
|
||||
numBSPEntities = entities.size();
|
||||
bspModels.insert( bspModels.cend(), bsp.bspModels.cbegin() + 1, bsp.bspModels.cend() ); // minus world
|
||||
bspShaders.insert( bspShaders.cend(), bsp.bspShaders.cbegin(), bsp.bspShaders.cend() );
|
||||
// bspLeafs
|
||||
bspPlanes.insert( bspPlanes.cend(), bsp.bspPlanes.cbegin(), bsp.bspPlanes.cend() );
|
||||
// bspNodes
|
||||
// bspLeafSurfaces
|
||||
// bspLeafBrushes
|
||||
bspBrushes.insert( bspBrushes.cend(), bsp.bspBrushes.cbegin(), bsp.bspBrushes.cend() );
|
||||
bspBrushSides.insert( bspBrushSides.cend(), bsp.bspBrushSides.cbegin(), bsp.bspBrushSides.cend() );
|
||||
bspLightBytes.insert( bspLightBytes.cend(), bsp.bspLightBytes.cbegin(), bsp.bspLightBytes.cend() );
|
||||
// bspGridPoints
|
||||
// bspVisBytes
|
||||
bspDrawVerts.insert( bspDrawVerts.cend(), bsp.bspDrawVerts.cbegin(), bsp.bspDrawVerts.cend() );
|
||||
bspDrawIndexes.insert( bspDrawIndexes.cend(), bsp.bspDrawIndexes.cbegin(), bsp.bspDrawIndexes.cend() );
|
||||
bspDrawSurfaces.insert( bspDrawSurfaces.cend(), bsp.bspDrawSurfaces.cbegin(), bsp.bspDrawSurfaces.cend() );
|
||||
bspFogs.insert( bspFogs.cend(), bsp.bspFogs.cbegin(), bsp.bspFogs.cend() );
|
||||
}
|
||||
|
||||
if( addworld ){
|
||||
/* insert new world surfaces */
|
||||
const std::vector<bspDrawSurface_t> surfs( bspDrawSurfaces.cbegin() + bsp.bspModels[0].firstBSPSurface,
|
||||
bspDrawSurfaces.cbegin() + bsp.bspModels[0].firstBSPSurface + bsp.bspModels[0].numBSPSurfaces );
|
||||
bspDrawSurfaces.insert( bspDrawSurfaces.cbegin() + bspModels[0].firstBSPSurface + bspModels[0].numBSPSurfaces,
|
||||
surfs.cbegin(), surfs.cend() );
|
||||
// reindex
|
||||
for( auto&& index : bspLeafSurfaces )
|
||||
if( index >= bspModels[0].firstBSPSurface + bspModels[0].numBSPSurfaces )
|
||||
index += surfs.size();
|
||||
for( auto&& side : bspBrushSides )
|
||||
if( side.surfaceNum >= bspModels[0].firstBSPSurface + bspModels[0].numBSPSurfaces )
|
||||
side.surfaceNum += surfs.size();
|
||||
for( auto&& model : bspModels )
|
||||
if( model.firstBSPSurface >= bspModels[0].firstBSPSurface + bspModels[0].numBSPSurfaces )
|
||||
model.firstBSPSurface += surfs.size();
|
||||
bspModels[0].numBSPSurfaces += surfs.size();
|
||||
/* insert new world brushes */
|
||||
const std::vector<bspBrush_t> brushes( bspBrushes.cbegin() + bsp.bspModels[0].firstBSPBrush,
|
||||
bspBrushes.cbegin() + bsp.bspModels[0].firstBSPBrush + bsp.bspModels[0].numBSPBrushes );
|
||||
bspBrushes.insert( bspBrushes.cbegin() + bspModels[0].firstBSPBrush + bspModels[0].numBSPBrushes,
|
||||
brushes.cbegin(), brushes.cend() );
|
||||
// reindex
|
||||
for( auto&& index : bspLeafBrushes )
|
||||
if( index >= bspModels[0].firstBSPBrush + bspModels[0].numBSPBrushes )
|
||||
index += brushes.size();
|
||||
for( auto&& fog : bspFogs )
|
||||
if( fog.brushNum >= bspModels[0].firstBSPBrush + bspModels[0].numBSPBrushes )
|
||||
fog.brushNum += brushes.size();
|
||||
for( auto&& model : bspModels )
|
||||
if( model.firstBSPBrush >= bspModels[0].firstBSPBrush + bspModels[0].numBSPBrushes )
|
||||
model.firstBSPBrush += brushes.size();
|
||||
bspModels[0].numBSPBrushes += brushes.size();
|
||||
/* reference surfaces */
|
||||
for( auto end = bspDrawSurfaces.cbegin() + bspModels[0].firstBSPSurface + bspModels[0].numBSPSurfaces,
|
||||
surf = end - surfs.size(); surf != end; ++surf ){
|
||||
MinMax minmax; // cheap minmax test
|
||||
if( surf->surfaceType == MST_BAD ){
|
||||
continue;
|
||||
}
|
||||
else if( surf->surfaceType == MST_PATCH ){
|
||||
minmax = { surf->lightmapVecs[0], surf->lightmapVecs[1] };
|
||||
}
|
||||
else{
|
||||
for( int i = 0; i < surf->numIndexes; ++i )
|
||||
minmax.extend( bspDrawVerts[surf->firstVert + bspDrawIndexes[surf->firstIndex + i]].xyz );
|
||||
}
|
||||
|
||||
for( auto&& leaf : bspLeafs ){
|
||||
if( leaf.minmax.test( minmax ) ){
|
||||
for( auto&& l : bspLeafs )
|
||||
if( &l != &leaf && l.firstBSPLeafSurface >= leaf.firstBSPLeafSurface )
|
||||
++l.firstBSPLeafSurface;
|
||||
|
||||
bspLeafSurfaces.insert( bspLeafSurfaces.cbegin() + leaf.firstBSPLeafSurface, int( std::distance( bspDrawSurfaces.cbegin(), surf ) ) );
|
||||
++leaf.numBSPLeafSurfaces;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* reference brushes */
|
||||
/* convert bsp planes to map planes */
|
||||
mapplanes.resize( bspPlanes.size() );
|
||||
for ( size_t i = 0; i < bspPlanes.size(); ++i )
|
||||
{
|
||||
mapplanes[i].plane = bspPlanes[i];
|
||||
}
|
||||
|
||||
for( auto end = bspBrushes.cbegin() + bspModels[0].firstBSPBrush + bspModels[0].numBSPBrushes,
|
||||
brush = end - brushes.size(); brush != end; ++brush ){
|
||||
buildBrush.sides.clear();
|
||||
for( auto side = bspBrushSides.cbegin() + brush->firstSide, end = side + brush->numSides; side != end; ++side ){
|
||||
auto& s = buildBrush.sides.emplace_back();
|
||||
s.planenum = side->planeNum;
|
||||
}
|
||||
if( CreateBrushWindings( buildBrush ) ){
|
||||
// cheap minmax test
|
||||
for( auto&& leaf : bspLeafs ){
|
||||
if( leaf.minmax.test( buildBrush.minmax ) ){
|
||||
for( auto&& l : bspLeafs )
|
||||
if( &l != &leaf && l.firstBSPLeafBrush >= leaf.firstBSPLeafBrush )
|
||||
++l.firstBSPLeafBrush;
|
||||
|
||||
bspLeafBrushes.insert( bspLeafBrushes.cbegin() + leaf.firstBSPLeafBrush, int( std::distance( bspBrushes.cbegin(), brush ) ) );
|
||||
++leaf.numBSPLeafBrushes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* inject command line parameters */
|
||||
InjectCommandLine( "-mergebsp", argsToInject );
|
||||
|
||||
/* write the bsp */
|
||||
UnparseEntities();
|
||||
path_set_extension( source, "_merged.bsp" );
|
||||
Sys_Printf( "Writing %s\n", source );
|
||||
WriteBSPFile( source );
|
||||
|
||||
/* return to sender */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
PseudoCompileBSP()
|
||||
a stripped down ProcessModels
|
||||
|
|
|
|||
|
|
@ -433,6 +433,17 @@ void HelpJson()
|
|||
HelpOptions("BSP json export/import", 0, 80, options);
|
||||
}
|
||||
|
||||
void HelpMergeBsp()
|
||||
{
|
||||
const std::vector<HelpOption> options = {
|
||||
{"-mergebsp [options] <mainBsp.bsp> <bspToinject.bsp>", "Inject latter BSP to former. Tree and vis data of the main one are preserved."},
|
||||
{"-fixnames", "Make incoming BSP target/targetname names unique to not collide with existing names"},
|
||||
{"-world", "Also merge worldspawn model (brushes as if they were detail, no BSP tree is affected) (only merges entities by default)"},
|
||||
};
|
||||
|
||||
HelpOptions("BSP merge", 0, 80, options);
|
||||
}
|
||||
|
||||
void HelpCommon()
|
||||
{
|
||||
const std::vector<HelpOption> options = {
|
||||
|
|
@ -486,6 +497,7 @@ void HelpMain(const char* arg)
|
|||
{"-pk3", "PK3 creation"},
|
||||
{"-repack", "Maps repack creation"},
|
||||
{"-json", "BSP json export/import"},
|
||||
{"-mergebsp", "BSP merge"},
|
||||
};
|
||||
void(*help_funcs[])() = {
|
||||
HelpBsp,
|
||||
|
|
@ -504,6 +516,7 @@ void HelpMain(const char* arg)
|
|||
HelpPk3,
|
||||
HelpRepack,
|
||||
HelpJson,
|
||||
HelpMergeBsp,
|
||||
};
|
||||
|
||||
if ( !strEmptyOrNull( arg ) )
|
||||
|
|
|
|||
|
|
@ -225,6 +225,11 @@ int main( int argc, char **argv ){
|
|||
r = ConvertJsonMain( args );
|
||||
}
|
||||
|
||||
/* merge two bsps */
|
||||
else if ( args.takeFront( "-mergebsp" ) ) {
|
||||
r = MergeBSPMain( args );
|
||||
}
|
||||
|
||||
/* div0: minimap */
|
||||
else if ( args.takeFront( "-minimap" ) ) {
|
||||
r = MiniMapBSPMain( args );
|
||||
|
|
|
|||
|
|
@ -1528,6 +1528,7 @@ int AnalyzeBSP( Args& args );
|
|||
int BSPInfo( Args& args );
|
||||
int ScaleBSPMain( Args& args );
|
||||
int ShiftBSPMain( Args& args );
|
||||
int MergeBSPMain( Args& args );
|
||||
int ConvertBSPMain( Args& args );
|
||||
|
||||
/* convert_map.c */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user