Skip to content

Commit

Permalink
BSP Builder: Cleanup continues...
Browse files Browse the repository at this point in the history
  • Loading branch information
danij-deng committed Apr 2, 2012
1 parent e68a03b commit 9fd4f76
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 108 deletions.
47 changes: 35 additions & 12 deletions doomsday/engine/portable/include/bspbuilder/bspbuilder.hh
Expand Up @@ -45,9 +45,35 @@ namespace de {
/// Default cost factor attributed to splitting an existing half-edge.
#define BSPBUILDER_PARTITION_COST_HEDGESPLIT 7

/**
* @algorithm High-level description (courtesy of Raphael Quinet)
* 1 - Create one Seg for each SideDef: pick each LineDef in turn. If it
* has a "first" SideDef, then create a normal Seg. If it has a
* "second" SideDef, then create a flipped Seg.
* 2 - Call CreateNodes with the current list of Segs. The list of Segs is
* the only argument to CreateNodes.
* 3 - Save the Nodes, Segs and BspLeafs to disk. Start with the leaves of
* the Nodes tree and continue up to the root (last Node).
*
* CreateNodes does the following:
* 1 - Pick a nodeline amongst the Segs (minimize the number of splits and
* keep the tree as balanced as possible).
* 2 - Move all Segs on the right of the nodeline in a list (segs1) and do
* the same for all Segs on the left of the nodeline (in segs2).
* 3 - If the first list (segs1) contains references to more than one
* Sector or if the angle between two adjacent Segs is greater than
* 180 degrees, then call CreateNodes with this (smaller) list.
* Else, create a BspLeaf with all these Segs.
* 4 - Do the same for the second list (segs2).
* 5 - Return the new node (its two children are already OK).
*
* Each time CreateBspLeaf is called, the Segs are put in a global list.
* When there is no more Seg in CreateNodes' list, then they are all in the
* global list and ready to be saved to disk.
*/
class BspBuilder {
public:
BspBuilder();
BspBuilder(GameMap* map);
~BspBuilder();

BspBuilder* setSplitCostFactor(int factor)
Expand All @@ -56,18 +82,13 @@ public:
return this;
}

void initForMap(GameMap* map);
void initForMap();

/**
* Build the BSP for the given map.
*
* @param map The map to build the BSP for.
* @param vertexes Editable vertex (ptr) array.
* @param numVertexes Number of vertexes in the array.
*
* @return @c true= iff completed successfully.
*/
boolean build(GameMap* map);
boolean build();

/**
* Retrieve a pointer to the root BinaryTree node for the constructed BSP.
Expand Down Expand Up @@ -97,7 +118,7 @@ private:
return lineDefInfos[lineDef.buildData.index - 1];
}

void findMapBounds(GameMap* map, AABoxf* aaBox) const;
void findMapBounds(AABoxf* aaBox) const;

/**
* Create a new leaf from a list of half-edges.
Expand All @@ -106,14 +127,14 @@ private:

const HPlaneIntercept* makeHPlaneIntersection(HPlane& hplane, HEdge* hedge, int leftSide);

SuperBlockmap* createBlockmap(const AABoxf& mapBounds);

/**
* Initially create all half-edges, one for each side of a linedef.
*
* @return The list of created half-edges.
*/
SuperBlockmap* createInitialHEdges(GameMap* map);
void createInitialHEdges(SuperBlock& hedgeList);

void initHEdgesAndBuildBsp(SuperBlockmap& blockmap, HPlane& hplane);

void mergeIntersections(HPlane& intersections);

Expand Down Expand Up @@ -253,6 +274,8 @@ private:
private:
int splitCostFactor;

GameMap* map;

typedef std::vector<LineDefInfo> LineDefInfos;
LineDefInfos lineDefInfos;

Expand Down
40 changes: 4 additions & 36 deletions doomsday/engine/portable/include/edit_bsp.h
@@ -1,40 +1,8 @@
/**
* @file bsp_main.h
* BSP Builder. @ingroup map
*
* @algorithm High-level description (courtesy of Raphael Quinet)
* 1 - Create one Seg for each SideDef: pick each LineDef in turn. If it
* has a "first" SideDef, then create a normal Seg. If it has a
* "second" SideDef, then create a flipped Seg.
* 2 - Call CreateNodes with the current list of Segs. The list of Segs is
* the only argument to CreateNodes.
* 3 - Save the Nodes, Segs and BspLeafs to disk. Start with the leaves of
* the Nodes tree and continue up to the root (last Node).
*
* CreateNodes does the following:
* 1 - Pick a nodeline amongst the Segs (minimize the number of splits and
* keep the tree as balanced as possible).
* 2 - Move all Segs on the right of the nodeline in a list (segs1) and do
* the same for all Segs on the left of the nodeline (in segs2).
* 3 - If the first list (segs1) contains references to more than one
* Sector or if the angle between two adjacent Segs is greater than
* 180 degrees, then call CreateNodes with this (smaller) list.
* Else, create a BspLeaf with all these Segs.
* 4 - Do the same for the second list (segs2).
* 5 - Return the new node (its two children are already OK).
*
* Each time CreateBspLeaf is called, the Segs are put in a global list.
* When there is no more Seg in CreateNodes' list, then they are all in the
* global list and ready to be saved to disk.
*
* Based on glBSP 2.24 (in turn, based on BSP 2.3), which is hosted on
* SourceForge: http://sourceforge.net/projects/glbsp/
* @file edit_bsp.h
* Editable map BSP Builder. @ingroup map
*
* @authors Copyright © 2007-2012 Daniel Swanson <danij@dengine.net>
* @authors Copyright © 2000-2007 Andrew Apted <ajapted@gmail.com>
* @authors Copyright © 1998-2000 Colin Reed <cph@moria.org.uk>
* @authors Copyright © 1998-2000 Lee Killough <killough@rsn.hp.com>
* @authors Copyright © 1997-1998 Raphael.Quinet <raphael.quinet@eed.ericsson.se>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
Expand Down Expand Up @@ -71,7 +39,7 @@ extern int bspFactor;

void BspBuilder_Register(void);

BspBuilder_c* BspBuilder_New(void);
BspBuilder_c* BspBuilder_New(struct gamemap_s* map);

void BspBuilder_Delete(BspBuilder_c* builder);

Expand All @@ -86,7 +54,7 @@ struct binarytree_s* BspBuilder_Root(BspBuilder_c* builder);
*
* @return @c true= iff completed successfully.
*/
boolean BspBuilder_Build(BspBuilder_c* builder, struct gamemap_s* map);
boolean BspBuilder_Build(BspBuilder_c* builder);

#ifdef __cplusplus
} // extern "C"
Expand Down
114 changes: 56 additions & 58 deletions doomsday/engine/portable/src/bspbuilder/bspbuilder.cpp
Expand Up @@ -44,7 +44,7 @@

using namespace de;

BspBuilder::BspBuilder() :
BspBuilder::BspBuilder(GameMap* _map) :
splitCostFactor(BSPBUILDER_PARTITION_COST_HEDGESPLIT),
map(_map), lineDefInfos(0), rootNode(0), builtOK(false)
{}
Expand Down Expand Up @@ -85,9 +85,9 @@ static void initAABoxFromEditableLineDefVertexes(AABoxf* aaBox, const LineDef* l
aaBox->maxY = MAX_OF(from[VY], to[VY]);
}

void BspBuilder::findMapBounds(GameMap* map, AABoxf* aaBox) const
void BspBuilder::findMapBounds(AABoxf* aaBox) const
{
Q_ASSERT(map && aaBox);
Q_ASSERT(aaBox);

AABoxf bounds;
boolean initialized = false;
Expand Down Expand Up @@ -126,40 +126,10 @@ void BspBuilder::findMapBounds(GameMap* map, AABoxf* aaBox) const
V2f_Set(aaBox->max, DDMINFLOAT, DDMINFLOAT);
}

SuperBlockmap* BspBuilder::createBlockmap(const AABoxf& mapBoundsf)
{
AABox mapBounds;
mapBounds.minX = (int) floor(mapBoundsf.minX);
mapBounds.minY = (int) floor(mapBoundsf.minY);
mapBounds.maxX = (int) ceil(mapBoundsf.maxX);
mapBounds.maxY = (int) ceil(mapBoundsf.maxY);

AABox blockBounds;
blockBounds.minX = mapBounds.minX - (mapBounds.minX & 0x7);
blockBounds.minY = mapBounds.minY - (mapBounds.minY & 0x7);
int bw = ((mapBounds.maxX - blockBounds.minX) / 128) + 1;
int bh = ((mapBounds.maxY - blockBounds.minY) / 128) + 1;

blockBounds.maxX = blockBounds.minX + 128 * M_CeilPow2(bw);
blockBounds.maxY = blockBounds.minY + 128 * M_CeilPow2(bh);

SuperBlockmap* bmap = new SuperBlockmap(blockBounds);
return bmap;
}

SuperBlockmap* BspBuilder::createInitialHEdges(GameMap* map)
void BspBuilder::createInitialHEdges(SuperBlock& hedgeList)
{
Q_ASSERT(map);

// Find maximal vertexes.
AABoxf mapBounds;
findMapBounds(map, &mapBounds);

LOG_VERBOSE("Map bounds:")
<< " min[x:" << mapBounds.minX << ", y:" << mapBounds.minY << "]"
<< " max[x:" << mapBounds.maxX << ", y:" << mapBounds.maxY << "]";

SuperBlockmap* sbmap = createBlockmap(mapBounds);
for(uint i = 0; i < map->numLineDefs; ++i)
{
LineDef* line = GameMap_LineDef(map, i);
Expand Down Expand Up @@ -193,7 +163,7 @@ SuperBlockmap* BspBuilder::createInitialHEdges(GameMap* map)
LOG_INFO("Bad SideDef on LineDef #%d.") << line->buildData.index;

front = newHEdge(line, line, line->v[0], line->v[1], side->sector, false);
sbmap->root().hedgePush(front);
hedgeList.hedgePush(front);
}
else
{
Expand All @@ -208,7 +178,7 @@ SuperBlockmap* BspBuilder::createInitialHEdges(GameMap* map)
LOG_INFO("Bad SideDef on LineDef #%d.") << line->buildData.index;

back = newHEdge(line, line, line->v[1], line->v[0], side->sector, true);
sbmap->root().hedgePush(back);
hedgeList.hedgePush(back);

if(front)
{
Expand All @@ -232,7 +202,7 @@ SuperBlockmap* BspBuilder::createInitialHEdges(GameMap* map)
HEdge* other = newHEdge(front->bspBuildInfo->lineDef, line,
line->v[1], line->v[0], line->buildData.windowEffect, true);

sbmap->root().hedgePush(other);
hedgeList.hedgePush(other);

// Setup the twin-ing (it's very strange to have a mini
// and a normal partnered together).
Expand All @@ -251,11 +221,9 @@ SuperBlockmap* BspBuilder::createInitialHEdges(GameMap* map)
addEdgeTip(line->v[0], x2 - x1, y2 - y1, back, front);
addEdgeTip(line->v[1], x1 - x2, y1 - y2, front, back);
}

return sbmap;
}

void BspBuilder::initForMap(GameMap* map)
void BspBuilder::initForMap()
{
uint numLineDefs = GameMap_LineDefCount(map);
lineDefInfos.resize(numLineDefs);
Expand All @@ -282,29 +250,59 @@ void BspBuilder::initForMap(GameMap* map)
}
}

boolean BspBuilder::build(GameMap* map)
void BspBuilder::initHEdgesAndBuildBsp(SuperBlockmap& blockmap, HPlane& hplane)
{
initForMap(map);

// Create initial half-edges.
uint startTime = Sys_GetRealTime();

SuperBlockmap* sbmap = createInitialHEdges(map);
Q_ASSERT(map);

// How much time did we spend?
LOG_DEBUG("createInitialHEdges: Done in %.2f seconds.") << (Sys_GetRealTime() - startTime) / 1000.0f;
createInitialHEdges(blockmap.root());

// Recursively create nodes.
// Build the tree.
rootNode = NULL;
builtOK = buildNodes(sbmap->root(), &rootNode, HPlane(this));

delete sbmap;
builtOK = buildNodes(blockmap.root(), &rootNode, hplane);

// Wind the BSP tree.
// Wind the tree.
if(builtOK)
{
windLeafs(rootNode);
}
}

boolean BspBuilder::build()
{
if(!map) return false;

initForMap();

// Find maximal vertexes.
AABoxf mapBounds;
findMapBounds(&mapBounds);

LOG_VERBOSE("Map bounds:")
<< " min[x:" << mapBounds.minX << ", y:" << mapBounds.minY << "]"
<< " max[x:" << mapBounds.maxX << ", y:" << mapBounds.maxY << "]";

AABox mapBoundsi;
mapBoundsi.minX = (int) floor(mapBounds.minX);
mapBoundsi.minY = (int) floor(mapBounds.minY);
mapBoundsi.maxX = (int) ceil(mapBounds.maxX);
mapBoundsi.maxY = (int) ceil(mapBounds.maxY);

AABox blockBounds;
blockBounds.minX = mapBoundsi.minX - (mapBoundsi.minX & 0x7);
blockBounds.minY = mapBoundsi.minY - (mapBoundsi.minY & 0x7);
int bw = ((mapBoundsi.maxX - blockBounds.minX) / 128) + 1;
int bh = ((mapBoundsi.maxY - blockBounds.minY) / 128) + 1;

blockBounds.maxX = blockBounds.minX + 128 * M_CeilPow2(bw);
blockBounds.maxY = blockBounds.minY + 128 * M_CeilPow2(bh);

SuperBlockmap* blockmap = new SuperBlockmap(blockBounds);
HPlane* hplane = new HPlane(this);

initHEdgesAndBuildBsp(*blockmap, *hplane);

delete hplane;
delete blockmap;

return builtOK;
}
Expand Down Expand Up @@ -603,10 +601,10 @@ void BspBuilder_Register(void)
C_VAR_INT("bsp-factor", &bspFactor, CVF_NO_MAX, 0, 0);
}

BspBuilder_c* BspBuilder_New(void)
BspBuilder_c* BspBuilder_New(GameMap* map)
{
BspBuilder_c* builder = (BspBuilder_c*)malloc(sizeof *builder);
builder->inst = new BspBuilder();
builder->inst = new BspBuilder(map);
return builder;
}

Expand All @@ -624,10 +622,10 @@ BspBuilder_c* BspBuilder_SetSplitCostFactor(BspBuilder_c* builder, int factor)
return builder;
}

boolean BspBuilder_Build(BspBuilder_c* builder, GameMap* map)
boolean BspBuilder_Build(BspBuilder_c* builder)
{
assert(builder);
return builder->inst->build(map);
return builder->inst->build();
}

BinaryTree* BspBuilder_Root(BspBuilder_c* builder)
Expand Down
4 changes: 2 additions & 2 deletions doomsday/engine/portable/src/edit_map.c
Expand Up @@ -1663,10 +1663,10 @@ static boolean buildBsp(GameMap* gamemap)
// It begins...
startTime = Sys_GetRealTime();

bspBuilder = BspBuilder_New();
bspBuilder = BspBuilder_New(gamemap);
BspBuilder_SetSplitCostFactor(bspBuilder, bspFactor);

builtOK = BspBuilder_Build(bspBuilder, gamemap);
builtOK = BspBuilder_Build(bspBuilder);
if(builtOK)
{
MPE_SaveBsp(bspBuilder, gamemap, &map->vertexes, &map->numVertexes);
Expand Down

0 comments on commit 9fd4f76

Please sign in to comment.