Skip to content

Commit

Permalink
BSP Builder|Refactor: Segregated build completion tasks (SoC)
Browse files Browse the repository at this point in the history
The BspBuilder's destructor will now delete all biproduct objects
produced during the course of ::build().

The actual BSP data objects (BspNode, BspLeaf and HEdge) are not
destroyed as it is assumed that MPE_SaveBSP will have been called
to obtain ownership of it.

Todo: BspBuilder should fully clean up after itself regardless of
the outcome or whether anyone decides to take ownership of all the
data objects it produces.
  • Loading branch information
danij-deng committed Apr 1, 2012
1 parent 31d083d commit 6664235
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 107 deletions.
24 changes: 15 additions & 9 deletions doomsday/engine/portable/include/bspbuilder/bspbuilder.hh
Expand Up @@ -39,19 +39,13 @@ struct binarytree_s;

namespace de {

/// Number of HEdge to block allocate.
#define BSPBUILDER_HEDGE_ALLOCATOR_BLOCKSIZE 512

/// Default cost factor attributed to splitting an existing half-edge.
#define BSPBUILDER_PARTITION_COST_HEDGESPLIT 7

class BspBuilder {
public:
BspBuilder() : splitCostFactor(BSPBUILDER_PARTITION_COST_HEDGESPLIT)
{}

~BspBuilder()
{}
BspBuilder();
~BspBuilder();

BspBuilder* setSplitCostFactor(int factor)
{
Expand All @@ -70,7 +64,16 @@ public:
*
* @return @c true= iff completed successfully.
*/
boolean build(GameMap* map, Vertex*** vertexes, uint* numVertexes);
boolean build(GameMap* map);

/**
* Retrieve a pointer to the root BinaryTree node for the constructed BSP.
* Even if construction fails this will return a valid node.
*
* The only time upon which @c NULL is returned is if called prior to calling
* BspBuilder::build()
*/
struct binarytree_s* root() const;

/**
* Destroy the specified intersection.
Expand Down Expand Up @@ -237,6 +240,9 @@ private:

private:
int splitCostFactor;

struct binarytree_s* rootNode;
boolean builtOK;
};

} // namespace de
Expand Down
11 changes: 6 additions & 5 deletions doomsday/engine/portable/include/edit_bsp.h
Expand Up @@ -64,6 +64,7 @@ struct edgetip_s;
struct vertex_s;
struct sector_s;
struct gamemap_s;
struct binarytree_s;

#ifdef __cplusplus
extern "C" {
Expand All @@ -84,21 +85,21 @@ void BspBuilder_Delete(BspBuilder_c* builder);

BspBuilder_c* BspBuilder_SetSplitCostFactor(BspBuilder_c* builder, int factor);

void BspBuilder_Save(struct gamemap_s* dest, void* rootNode, struct vertex_s*** vertexes, uint* numVertexes);
struct binarytree_s* BspBuilder_Root(BspBuilder_c* builder);

/**
* 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.
* @param map The map to build the BSP for.
*
* @return @c true= iff completed successfully.
*/
boolean BspBuilder_Build(BspBuilder_c* builder, struct gamemap_s* map, struct vertex_s*** vertexes, uint* numVertexes);
boolean BspBuilder_Build(BspBuilder_c* builder, struct gamemap_s* map);

#ifdef __cplusplus
} // extern "C"
#endif

void MPE_SaveBsp(BspBuilder_c* builder, struct gamemap_s* dest, struct vertex_s*** vertexes, uint* numVertexes);

#endif /// LIBDENG_MAP_BSP_BUILDER
135 changes: 63 additions & 72 deletions doomsday/engine/portable/src/bspbuilder/bspbuilder.cpp
Expand Up @@ -54,25 +54,35 @@ void BspBuilder_Register(void)
C_VAR_INT("bsp-factor", &bspFactor, CVF_NO_MAX, 0, 0);
}

BspBuilder_c* BspBuilder_New(void)
{
BspBuilder_c* builder = (BspBuilder_c*)malloc(sizeof *builder);
builder->inst = new BspBuilder();
return builder;
}
BspBuilder::BspBuilder() :
splitCostFactor(BSPBUILDER_PARTITION_COST_HEDGESPLIT),
rootNode(0), builtOK(false)
{}

void BspBuilder_Delete(BspBuilder_c* builder)
static int C_DECL clearBspHEdgeInfo(BinaryTree* tree, void* /*parameters*/)
{
assert(builder);
delete builder->inst;
free(builder);
if(BinaryTree_IsLeaf(tree))
{
BspLeaf* leaf = static_cast<BspLeaf*>(BinaryTree_UserData(tree));
HEdge* hedge = leaf->hedge;
do
{
Z_Free(HEdge_DetachBspBuildInfo(hedge));
} while((hedge = hedge->next) != leaf->hedge);
}
return 0; // Continue iteration.
}

BspBuilder_c* BspBuilder_SetSplitCostFactor(BspBuilder_c* builder, int factor)
BspBuilder::~BspBuilder()
{
assert(builder);
builder->inst->setSplitCostFactor(factor);
return builder;
// We are finished with the BSP build data.
if(rootNode)
{
// We're done with the build info.
BinaryTree_PreOrder(rootNode, clearBspHEdgeInfo, NULL/*no parameters*/);
BinaryTree_Delete(rootNode);
}
rootNode = NULL;
}

static void initAABoxFromEditableLineDefVertexes(AABoxf* aaBox, const LineDef* line)
Expand Down Expand Up @@ -300,85 +310,33 @@ void BspBuilder::initForMap(GameMap* map)
}
}

boolean BspBuilder::build(GameMap* map, Vertex*** vertexes, uint* numVertexes)
boolean BspBuilder::build(GameMap* map)
{
BinaryTree* rootNode;
SuperBlockmap* sbmap;
boolean builtOK;
uint startTime;

VERBOSE( Con_Message("BspBuilder::build: Processing map using tunable factor of %d...\n", bspFactor) )

// It begins...
startTime = Sys_GetRealTime();

initForMap(map);

// Create initial half-edges.
sbmap = createInitialHEdges(map);

// Build the BSP.
{
uint buildStartTime = Sys_GetRealTime();
HPlane* hplane;

hplane = new HPlane(this);
SuperBlockmap* sbmap = createInitialHEdges(map);
HPlane* hplane = new HPlane(this);

// Recursively create nodes.
rootNode = NULL;
builtOK = buildNodes(sbmap->root(), &rootNode, 0, hplane);

// The intersection list is no longer needed.
delete hplane;

// How much time did we spend?
VERBOSE2( Con_Message("BspBuilder::buildNodes: Done in %.2f seconds.\n", (Sys_GetRealTime() - buildStartTime) / 1000.0f));
}

delete sbmap;

// Wind the BSP tree.
if(builtOK)
{
// Success!
long rHeight, lHeight;

// Wind the BSP tree and link to the map.
windLeafs(rootNode);
BspBuilder_Save(map, rootNode, vertexes, numVertexes);

if(rootNode && !BinaryTree_IsLeaf(rootNode))
{
rHeight = (long) BinaryTree_Height(BinaryTree_Right(rootNode));
lHeight = (long) BinaryTree_Height(BinaryTree_Left(rootNode));
}
else
{
rHeight = lHeight = 0;
}

VERBOSE(
Con_Message("BSP built: %d Nodes, %d BspLeafs, %d HEdges, %d Vertexes\n"
" Balance %+ld (l%ld - r%ld).\n", map->numBspNodes, map->numBspLeafs,
map->numHEdges, map->numVertexes, lHeight - rHeight, lHeight, rHeight) );
}

// We are finished with the BSP build data.
if(rootNode)
{
BinaryTree_Delete(rootNode);
}
rootNode = NULL;

// How much time did we spend?
VERBOSE2( Con_Message(" Done in %.2f seconds.\n", (Sys_GetRealTime() - startTime) / 1000.0f) );

return builtOK;
}

boolean BspBuilder_Build(BspBuilder_c* builder, GameMap* map, Vertex*** vertexes, uint* numVertexes)
BinaryTree* BspBuilder::root() const
{
assert(builder);
return builder->inst->build(map, vertexes, numVertexes);
return rootNode;
}

const HPlaneIntercept* BspBuilder::hplaneInterceptByVertex(HPlane* hplane, Vertex* vertex)
Expand Down Expand Up @@ -675,3 +633,36 @@ void BspBuilder::addEdgeTip(Vertex* vert, double dx, double dy, HEdge* back,
vert->buildData.tipSet = tip;
}
}

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

void BspBuilder_Delete(BspBuilder_c* builder)
{
assert(builder);
delete builder->inst;
free(builder);
}

BspBuilder_c* BspBuilder_SetSplitCostFactor(BspBuilder_c* builder, int factor)
{
assert(builder);
builder->inst->setSplitCostFactor(factor);
return builder;
}

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

BinaryTree* BspBuilder_Root(BspBuilder_c* builder)
{
assert(builder);
return builder->inst->root();
}
38 changes: 23 additions & 15 deletions doomsday/engine/portable/src/edit_bsp.c
Expand Up @@ -159,9 +159,6 @@ static void finishHEdges(GameMap* map)

if(hedge->length == 0)
hedge->length = 0.01f; // Hmm...

// We're done with the build info.
Z_Free(HEdge_DetachBspBuildInfo(hedge));
}
}

Expand Down Expand Up @@ -250,8 +247,6 @@ static void hardenBSP(GameMap* dest, BinaryTree* rootNode)
BinaryTree_PostOrder(rootNode, countLeaf, &dest->numBspLeafs);
dest->bspLeafs = (BspLeaf**)Z_Calloc(dest->numBspLeafs * sizeof(BspLeaf*), PU_MAPSTATIC, 0);

if(!rootNode) return;

if(BinaryTree_IsLeaf(rootNode))
{
BspLeaf* leaf = (BspLeaf*) BinaryTree_UserData(rootNode);
Expand Down Expand Up @@ -311,18 +306,31 @@ static void updateVertexLinks(GameMap* map)
}
}

void BspBuilder_Save(GameMap* dest, void* rootNode, Vertex*** vertexes, uint* numVertexes)
void MPE_SaveBsp(BspBuilder_c* builder, GameMap* map, Vertex*** vertexes, uint* numVertexes)
{
uint startTime = Sys_GetRealTime();
BinaryTree* rn = (BinaryTree*) rootNode;
BinaryTree* rootNode = BspBuilder_Root(builder);
long rHeight, lHeight;

buildHEdgeLut(map, rootNode);
hardenVertexes(map, vertexes, numVertexes);
updateVertexLinks(map);

buildHEdgeLut(dest, rn);
hardenVertexes(dest, vertexes, numVertexes);
updateVertexLinks(dest);
finishHEdges(map);
hardenBSP(map, rootNode);

if(rootNode && !BinaryTree_IsLeaf(rootNode))
{
rHeight = (long) BinaryTree_Height(BinaryTree_Right(rootNode));
lHeight = (long) BinaryTree_Height(BinaryTree_Left(rootNode));
}
else
{
rHeight = lHeight = 0;
}

finishHEdges(dest);
hardenBSP(dest, rn);
VERBOSE(
Con_Message("BSP built: %d Nodes, %d BspLeafs, %d HEdges, %d Vertexes\n"
" Balance %+ld (l%ld - r%ld).\n", map->numBspNodes, map->numBspLeafs,
map->numHEdges, map->numVertexes, lHeight - rHeight, lHeight, rHeight) );

// How much time did we spend?
VERBOSE( Con_Message("BspBuilder_Save: Done in %.2f seconds.\n", (Sys_GetRealTime() - startTime) / 1000.0f) );
}
36 changes: 30 additions & 6 deletions doomsday/engine/portable/src/edit_map.c
Expand Up @@ -52,8 +52,6 @@ static editmap_t* map = &editMap;

static GameMap *lastBuiltMap = NULL;

static BspBuilder_c* bspBuilder = NULL;

static uint numUnclosedSectors;
static usecrecord_t *unclosedSectors;

Expand Down Expand Up @@ -1654,6 +1652,35 @@ static void findBounds(Vertex const** vertexes, uint numVertexes, vec2f_t min, v
}
}

static boolean buildBsp(GameMap* gamemap)
{
BspBuilder_c* bspBuilder = NULL;
uint startTime;
boolean builtOK;

if(!map) return false;

VERBOSE( Con_Message("Building BSP using tunable split factor of %d...\n", bspFactor) )

// It begins...
startTime = Sys_GetRealTime();

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

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

BspBuilder_Delete(bspBuilder);

// How much time did we spend?
VERBOSE2( Con_Message(" Done in %.2f seconds.\n", (Sys_GetRealTime() - startTime) / 1000.0f) );
return builtOK;
}

/**
* Called to complete the map building process.
*/
Expand Down Expand Up @@ -1722,10 +1749,7 @@ boolean MPE_End(void)
/**
* Build a BSP for this map.
*/
bspBuilder = BspBuilder_New();
BspBuilder_SetSplitCostFactor(bspBuilder, bspFactor);
builtOK = BspBuilder_Build(bspBuilder, gamemap, &map->vertexes, &map->numVertexes);
BspBuilder_Delete(bspBuilder);
builtOK = buildBsp(gamemap);

// Finish the polyobjs (after the vertexes are hardened).
for(i = 0; i < gamemap->numPolyObjs; ++i)
Expand Down

0 comments on commit 6664235

Please sign in to comment.