Skip to content

Commit

Permalink
BSP Builder|Refactor: Implemented SuperBlockmap - a container for Sup…
Browse files Browse the repository at this point in the history
…erBlocks

SuperBlockmap owns the KdTree of SuperBlocks.
  • Loading branch information
danij-deng committed Mar 20, 2012
1 parent 6e684ec commit 4478438
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 46 deletions.
4 changes: 2 additions & 2 deletions doomsday/engine/portable/include/bsp_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,13 @@ void BSP_PartitionHEdges(SuperBlock* hEdgeList, SuperBlock* rightList, SuperBloc
* If the ones on the right side make a BspLeaf, then create another BspLeaf
* else put the half-edges into the right list.
*
* @param hEdgeList Ptr to the list of half edges at the current node.
* @param superblock Ptr to the list of half edges at the current node.
* @param parent Ptr to write back the address of any newly created subtree.
* @param depth Current tree depth.
* @param hPlane HPlaneIntercept list for storing any new intersections.
* @return @c true iff successfull.
*/
boolean BuildNodes(SuperBlock* hEdgeList, binarytree_t** parent, size_t depth,
boolean BuildNodes(SuperBlock* superblock, binarytree_t** parent, size_t depth,
HPlane* hPlane);

/**
Expand Down
56 changes: 45 additions & 11 deletions doomsday/engine/portable/include/bsp_superblock.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,68 @@
#include "de_platform.h"
#include "bsp_edge.h"

struct superblockmap_s; // The SuperBlockmap instance (opaque).
struct superblock_s; // The SuperBlock instance (opaque).

/**
* SuperBlockmap instance. Created with SuperBlockmap_New().
*/
typedef struct superblockmap_s SuperBlockmap;

/**
* SuperBlock instance. Created with SuperBlock_New().
*/
typedef struct superblock_s SuperBlock;

/**
* Constructs a new superblockmap. The superblockmap must be destroyed with
* SuperBlockmap_Delete() when no longer needed.
*/
SuperBlockmap* SuperBlockmap_New(const AABox* bounds);

/**
* Destroys the superblockmap.
*
* @param superblockmap SuperBlockmap instance.
*/
void SuperBlockmap_Delete(SuperBlockmap* superblockmap);

/**
* Retrieve the root SuperBlock in this SuperBlockmap.
*
* @param superblockmap SuperBlockmap instance.
* @return Root SuperBlock instance.
*/
SuperBlock* SuperBlockmap_Root(SuperBlockmap* superblockmap);

/**
* Find the axis-aligned bounding box defined by the vertices of all
* HEdges within this superblock. If no HEdges are linked then @a bounds
* will be set to the "cleared" state (i.e., min[x,y] > max[x,y]).
*
* @param superblockmap SuperBlock instance.
* @param bounds Determined bounds are written here.
*/
void SuperBlockmap_FindHEdgeBounds(SuperBlockmap* superblockmap, AABoxf* bounds);

/**
* Constructs a new superblock. The superblock must be destroyed with
* SuperBlock_Delete() when no longer needed.
*/
SuperBlock* SuperBlock_New(const AABox* bounds);
SuperBlock* SuperBlock_New(SuperBlockmap* blockmap, const AABox* bounds);

/**
* Destroys the superblock.
*/
void SuperBlock_Delete(SuperBlock* superblock);

/**
* Retrieve the SuperBlockmap which owns this block.
* @param superblock SuperBlock instance.
* @return SuperBlockmap instance which owns this.
*/
SuperBlockmap* SuperBlock_Blockmap(SuperBlock* superblock);

/**
* Retrieve the axis-aligned bounding box defined for this superblock
* during instantiation. Note that this is NOT the bounds defined by
Expand Down Expand Up @@ -126,14 +170,4 @@ int SuperBlock_Traverse(SuperBlock* superblock, int (*callback)(SuperBlock*, voi
int SuperBlock_PostTraverse2(SuperBlock* sb, int(*callback)(SuperBlock*, void*), void* parameters);
int SuperBlock_PostTraverse(SuperBlock* sb, int(*callback)(SuperBlock*, void*)/*, parameters = NULL*/);

/**
* Find the axis-aligned bounding box defined by the vertices of all
* HEdges within this superblock. If no HEdges are linked then @a bounds
* will be set to the "cleared" state (i.e., min[x,y] > max[x,y]).
*
* @param superblock SuperBlock instance.
* @param bounds Determined bounds are written here.
*/
void SuperBlock_FindHEdgeListBounds(SuperBlock* superblock, AABoxf* bounds);

#endif /// LIBDENG_MAP_BSP_SUPERBLOCK
24 changes: 12 additions & 12 deletions doomsday/engine/portable/src/bsp_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,12 @@ static void findMapBounds(GameMap* map, AABoxf* aaBox)
*
* @return The list of created half-edges.
*/
static SuperBlock* createInitialHEdges(GameMap* map)
static SuperBlockmap* createInitialHEdges(GameMap* map)
{
uint startTime = Sys_GetRealTime();

bsp_hedge_t* back, *front;
SuperBlock* block;
SuperBlockmap* sbmap;
AABoxf mapBoundsf;
AABox mapBounds, blockBounds;
int bw, bh;
Expand All @@ -138,7 +138,7 @@ static SuperBlock* createInitialHEdges(GameMap* map)
blockBounds.maxX = blockBounds.minX + 128 * M_CeilPow2(bw);
blockBounds.maxY = blockBounds.minY + 128 * M_CeilPow2(bh);

block = SuperBlock_New(&blockBounds);
sbmap = SuperBlockmap_New(&blockBounds);

for(i = 0; i < map->numLineDefs; ++i)
{
Expand Down Expand Up @@ -173,7 +173,7 @@ static SuperBlock* createInitialHEdges(GameMap* map)
Con_Message("Warning: Bad sidedef on linedef #%d\n", line->buildData.index);

front = BSP_HEdge_Create(line, line, line->v[0], line->v[1], side->sector, false);
SuperBlock_HEdgePush(block, front);
SuperBlock_HEdgePush(SuperBlockmap_Root(sbmap), front);
}
else
Con_Message("Warning: Linedef #%d has no front sidedef!\n", line->buildData.index);
Expand All @@ -186,7 +186,7 @@ static SuperBlock* createInitialHEdges(GameMap* map)
Con_Message("Warning: Bad sidedef on linedef #%d\n", line->buildData.index);

back = BSP_HEdge_Create(line, line, line->v[1], line->v[0], side->sector, true);
SuperBlock_HEdgePush(block, back);
SuperBlock_HEdgePush(SuperBlockmap_Root(sbmap), back);

if(front)
{
Expand All @@ -212,7 +212,7 @@ static SuperBlock* createInitialHEdges(GameMap* map)
other = BSP_HEdge_Create(front->lineDef, line, line->v[1], line->v[0],
line->buildData.windowEffect, true);

SuperBlock_HEdgePush(block, other);
SuperBlock_HEdgePush(SuperBlockmap_Root(sbmap), other);

// Setup the twin-ing (it's very strange to have a mini
// and a normal partnered together).
Expand All @@ -237,7 +237,7 @@ static SuperBlock* createInitialHEdges(GameMap* map)
// How much time did we spend?
VERBOSE2( Con_Message("createInitialHEdges: Done in %.2f seconds.\n", (Sys_GetRealTime() - startTime) / 1000.0f) );

return block;
return sbmap;
}

static boolean C_DECL freeBSPData(binarytree_t* tree, void* data)
Expand All @@ -259,10 +259,10 @@ static boolean C_DECL freeBSPData(binarytree_t* tree, void* data)

boolean BSP_Build(GameMap* map, Vertex*** vertexes, uint* numVertexes)
{
binarytree_t* rootNode;
SuperBlockmap* sbmap;
boolean builtOK;
uint startTime;
SuperBlock* hEdgeList;
binarytree_t* rootNode;

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

Expand All @@ -275,7 +275,7 @@ boolean BSP_Build(GameMap* map, Vertex*** vertexes, uint* numVertexes)
BSP_InitForNodeBuild(map);

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

// Build the BSP.
{
Expand All @@ -286,7 +286,7 @@ boolean BSP_Build(GameMap* map, Vertex*** vertexes, uint* numVertexes)

// Recursively create nodes.
rootNode = NULL;
builtOK = BuildNodes(hEdgeList, &rootNode, 0, hPlane);
builtOK = BuildNodes(SuperBlockmap_Root(sbmap), &rootNode, 0, hPlane);

// The intersection list is no longer needed.
HPlane_Delete(hPlane);
Expand All @@ -295,7 +295,7 @@ boolean BSP_Build(GameMap* map, Vertex*** vertexes, uint* numVertexes)
VERBOSE2( Con_Message("BuildNodes: Done in %.2f seconds.\n", (Sys_GetRealTime() - buildStartTime) / 1000.0f));
}

SuperBlock_Delete(hEdgeList);
SuperBlockmap_Delete(sbmap);

if(builtOK)
{
Expand Down
35 changes: 19 additions & 16 deletions doomsday/engine/portable/src/bsp_node.c
Original file line number Diff line number Diff line change
Expand Up @@ -956,29 +956,29 @@ static bspleafdata_t* createBSPLeaf(SuperBlock* hEdgeList)
return leaf;
}

boolean BuildNodes(SuperBlock* hEdgeList, binarytree_t** parent, size_t depth,
boolean BuildNodes(SuperBlock* superblock, binarytree_t** parent, size_t depth,
HPlane* hPlane)
{
SuperBlockmap* hEdgeSet[2];
binarytree_t* subTree;
BspNode* node;
SuperBlock* hEdgeSet[2];
bspleafdata_t* leaf;
BspNode* node;
boolean builtOK = false;

*parent = NULL;

/*DEBUG_Message(("Build: Begun @ %lu\n", (unsigned long) depth));
#if _DEBUG
BSP_PrintSuperBlockHEdges(hEdgeList);
BSP_PrintSuperBlockHEdges(superblock);
#endif*/

// Pick the next partition to use.
if(!Bsp_ChoosePartition(hEdgeList, depth, hPlane))
if(!Bsp_ChoosePartition(superblock, depth, hPlane))
{
// No partition required, already convex.
//DEBUG_Message(("BuildNodes: Convex.\n"));

leaf = createBSPLeaf(hEdgeList);
leaf = createBSPLeaf(superblock);
*parent = BinaryTree_Create(leaf);
return true;
}
Expand All @@ -987,37 +987,40 @@ boolean BuildNodes(SuperBlock* hEdgeList, binarytree_t** parent, size_t depth,
// best, best->v[0]->V_pos[VX], best->v[0]->V_pos[VY],
// best->v[1]->V_pos[VX], best->v[1]->V_pos[VY]));

// Create left and right super blocks.
// Create left and right super blockmaps.
/// @todo There should be no need to construct entirely independent
/// data structures to contain these HEdge subsets.
// Copy the bounding box of the edge list to the superblocks.
hEdgeSet[RIGHT] = SuperBlock_New(SuperBlock_Bounds(hEdgeList));
hEdgeSet[LEFT] = SuperBlock_New(SuperBlock_Bounds(hEdgeList));
hEdgeSet[RIGHT] = SuperBlockmap_New(SuperBlock_Bounds(superblock));
hEdgeSet[LEFT] = SuperBlockmap_New(SuperBlock_Bounds(superblock));

// Divide the half-edges into two lists: left & right.
BSP_PartitionHEdges(hEdgeList, hEdgeSet[RIGHT], hEdgeSet[LEFT], hPlane);
BSP_PartitionHEdges(superblock, SuperBlockmap_Root(hEdgeSet[RIGHT]),
SuperBlockmap_Root(hEdgeSet[LEFT]), hPlane);
HPlane_Clear(hPlane);

node = M_Calloc(sizeof(BspNode));
*parent = BinaryTree_Create(node);

SuperBlock_FindHEdgeListBounds(hEdgeSet[LEFT], &node->aaBox[LEFT]);
SuperBlock_FindHEdgeListBounds(hEdgeSet[RIGHT], &node->aaBox[RIGHT]);
SuperBlockmap_FindHEdgeBounds(hEdgeSet[LEFT], &node->aaBox[LEFT]);
SuperBlockmap_FindHEdgeBounds(hEdgeSet[RIGHT], &node->aaBox[RIGHT]);

node->partition.x = HPlane_X(hPlane);
node->partition.y = HPlane_Y(hPlane);
node->partition.dX = HPlane_DX(hPlane);
node->partition.dY = HPlane_DY(hPlane);

builtOK = BuildNodes(hEdgeSet[RIGHT], &subTree, depth + 1, hPlane);
builtOK = BuildNodes(SuperBlockmap_Root(hEdgeSet[RIGHT]), &subTree, depth + 1, hPlane);
BinaryTree_SetChild(*parent, RIGHT, subTree);
SuperBlock_Delete(hEdgeSet[RIGHT]);
SuperBlockmap_Delete(hEdgeSet[RIGHT]);

if(builtOK)
{
builtOK = BuildNodes(hEdgeSet[LEFT], &subTree, depth + 1, hPlane);
builtOK = BuildNodes(SuperBlockmap_Root(hEdgeSet[LEFT]), &subTree, depth + 1, hPlane);
BinaryTree_SetChild(*parent, LEFT, subTree);
}

SuperBlock_Delete(hEdgeSet[LEFT]);
SuperBlockmap_Delete(hEdgeSet[LEFT]);

return builtOK;
}
Expand Down
46 changes: 41 additions & 5 deletions doomsday/engine/portable/src/bsp_superblock.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,36 @@
* LEFT - has the higher coordinates.
* Division of a block always occurs horizontally, e.g. 512x512 -> 256x512 -> 256x256.
*/
struct superblockmap_s {
SuperBlock* root;
};

SuperBlockmap* SuperBlockmap_New(const AABox* bounds)
{
SuperBlockmap* bmap = malloc(sizeof *bmap);
if(!bmap) Con_Error("SuperBlockmap_New: Failed on allocation of %lu bytes for new SuperBlockmap.", (unsigned long) sizeof *bmap);
bmap->root = SuperBlock_New(bmap, bounds);
return bmap;
}

void SuperBlockmap_Delete(SuperBlockmap* bmap)
{
assert(bmap);
SuperBlock_Delete(bmap->root);
free(bmap);
}

SuperBlock* SuperBlockmap_Root(SuperBlockmap* bmap)
{
assert(bmap);
return bmap->root;
}

struct superblock_s {
/// SuperBlockmap which owns this block.
SuperBlockmap* blockmap;

/// KdTree node in the owning SuperBlockmap.
KdTree* tree;

/// Number of real half-edges and minihedges contained by this block
Expand Down Expand Up @@ -70,10 +99,11 @@ static void linkHEdge(SuperBlock* sb, bsp_hedge_t* hEdge)
sb->hEdges = hEdge;
}

SuperBlock* SuperBlock_New(const AABox* bounds)
SuperBlock* SuperBlock_New(SuperBlockmap* blockmap, const AABox* bounds)
{
SuperBlock* sb = malloc(sizeof *sb);
if(!sb) Con_Error("SuperBlock_New: Failed on allocation of %lu bytes for new SuperBlock.", (unsigned long) sizeof *sb);
sb->blockmap = blockmap;
sb->tree = KdTree_NewWithUserData(bounds, sb);
sb->realNum = 0;
sb->miniNum = 0;
Expand All @@ -97,6 +127,12 @@ void SuperBlock_Delete(SuperBlock* sb)
KdTree_Delete(tree);
}

SuperBlockmap* SuperBlock_Blockmap(SuperBlock* sb)
{
assert(sb);
return sb->blockmap;
}

const AABox* SuperBlock_Bounds(SuperBlock* sb)
{
assert(sb);
Expand Down Expand Up @@ -193,7 +229,7 @@ void SuperBlock_HEdgePush(SuperBlock* sb, bsp_hedge_t* hEdge)
sub.maxY = (half? bounds->maxY : midPoint[VY]);
}

child = SuperBlock_New(&sub);
child = SuperBlock_New(SuperBlock_Blockmap(sb), &sub);
child->tree = KdTree_AddChild(sb->tree, &sub, half, child);
}

Expand Down Expand Up @@ -336,13 +372,13 @@ static int findHEdgeListBoundsWorker(SuperBlock* sb, void* parameters)
return false; // Continue iteration.
}

void SuperBlock_FindHEdgeListBounds(SuperBlock* sb, AABoxf* aaBox)
void SuperBlockmap_FindHEdgeBounds(SuperBlockmap* sbmap, AABoxf* aaBox)
{
findhedgelistboundsparams_t parm;
assert(sb && aaBox);
assert(sbmap && aaBox);

parm.initialized = false;
SuperBlock_Traverse2(sb, findHEdgeListBoundsWorker, (void*)&parm);
SuperBlock_Traverse2(sbmap->root, findHEdgeListBoundsWorker, (void*)&parm);
if(parm.initialized)
{
V2_CopyBox(aaBox->arvec2, parm.bounds.arvec2);
Expand Down

0 comments on commit 4478438

Please sign in to comment.