* -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>
|
</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()
|
PseudoCompileBSP()
|
||||||
a stripped down ProcessModels
|
a stripped down ProcessModels
|
||||||
|
|
|
||||||
|
|
@ -433,6 +433,17 @@ void HelpJson()
|
||||||
HelpOptions("BSP json export/import", 0, 80, options);
|
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()
|
void HelpCommon()
|
||||||
{
|
{
|
||||||
const std::vector<HelpOption> options = {
|
const std::vector<HelpOption> options = {
|
||||||
|
|
@ -486,6 +497,7 @@ void HelpMain(const char* arg)
|
||||||
{"-pk3", "PK3 creation"},
|
{"-pk3", "PK3 creation"},
|
||||||
{"-repack", "Maps repack creation"},
|
{"-repack", "Maps repack creation"},
|
||||||
{"-json", "BSP json export/import"},
|
{"-json", "BSP json export/import"},
|
||||||
|
{"-mergebsp", "BSP merge"},
|
||||||
};
|
};
|
||||||
void(*help_funcs[])() = {
|
void(*help_funcs[])() = {
|
||||||
HelpBsp,
|
HelpBsp,
|
||||||
|
|
@ -504,6 +516,7 @@ void HelpMain(const char* arg)
|
||||||
HelpPk3,
|
HelpPk3,
|
||||||
HelpRepack,
|
HelpRepack,
|
||||||
HelpJson,
|
HelpJson,
|
||||||
|
HelpMergeBsp,
|
||||||
};
|
};
|
||||||
|
|
||||||
if ( !strEmptyOrNull( arg ) )
|
if ( !strEmptyOrNull( arg ) )
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,11 @@ int main( int argc, char **argv ){
|
||||||
r = ConvertJsonMain( args );
|
r = ConvertJsonMain( args );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* merge two bsps */
|
||||||
|
else if ( args.takeFront( "-mergebsp" ) ) {
|
||||||
|
r = MergeBSPMain( args );
|
||||||
|
}
|
||||||
|
|
||||||
/* div0: minimap */
|
/* div0: minimap */
|
||||||
else if ( args.takeFront( "-minimap" ) ) {
|
else if ( args.takeFront( "-minimap" ) ) {
|
||||||
r = MiniMapBSPMain( args );
|
r = MiniMapBSPMain( args );
|
||||||
|
|
|
||||||
|
|
@ -1528,6 +1528,7 @@ int AnalyzeBSP( Args& args );
|
||||||
int BSPInfo( Args& args );
|
int BSPInfo( Args& args );
|
||||||
int ScaleBSPMain( Args& args );
|
int ScaleBSPMain( Args& args );
|
||||||
int ShiftBSPMain( Args& args );
|
int ShiftBSPMain( Args& args );
|
||||||
|
int MergeBSPMain( Args& args );
|
||||||
int ConvertBSPMain( Args& args );
|
int ConvertBSPMain( Args& args );
|
||||||
|
|
||||||
/* convert_map.c */
|
/* convert_map.c */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user