diff --git a/doomsday/engine/portable/include/bsp_superblock.h b/doomsday/engine/portable/include/bsp_superblock.h index 5b9a84832f..54b6537118 100644 --- a/doomsday/engine/portable/include/bsp_superblock.h +++ b/doomsday/engine/portable/include/bsp_superblock.h @@ -30,6 +30,7 @@ #ifndef LIBDENG_MAP_BSP_SUPERBLOCK #define LIBDENG_MAP_BSP_SUPERBLOCK +#include "de_platform.h" #include "bsp_intersection.h" typedef struct superblock_s { @@ -38,8 +39,8 @@ typedef struct superblock_s { // Coordinates on map for this block, from lower-left corner to // upper-right corner. Pseudo-inclusive, i.e (x,y) is inside block - // if and only if BOXLEFT <= x < BOXRIGHT and BOXBOTTOM <= y < BOXTOP. - int bbox[4]; + // if and only if minX <= x < maxX and minY <= y < maxY. + AABox aaBox; // Sub-blocks. NULL when empty. [0] has the lower coordinates, and // [1] has the higher coordinates. Division of a square always diff --git a/doomsday/engine/portable/include/p_maputil.h b/doomsday/engine/portable/include/p_maputil.h index 2b086d840e..830ffae7cf 100644 --- a/doomsday/engine/portable/include/p_maputil.h +++ b/doomsday/engine/portable/include/p_maputil.h @@ -62,10 +62,25 @@ int P_PointOnLinedefSide2(double pointX, double pointY, int P_BoxOnLineSide(const AABoxf* box, const LineDef* ld); int P_BoxOnLineSide2(float xl, float xh, float yl, float yh, const LineDef *ld); -int P_BoxOnLineSide3(const int bbox[4], double lineSX, - double lineSY, double lineDX, double lineDY, - double linePerp, double lineLength, - double epsilon); + +/** + * Check the spatial relationship between the given box and a partitioning line. + * + * @param bbox Ptr to the box being tested. + * @param lineSX X coordinate of the start of the line. + * @param lineSY Y coordinate of the end of the line. + * @param lineDX X delta of the line (slope). + * @param lineDY Y delta of the line (slope). + * @param linePerp Perpendicular d of the line. + * @param lineLength Length of the line. + * @param epsilon Points within this distance will be considered equal. + * + * @return @c <0= bbox is wholly on the left side. + * @c 0= line intersects bbox. + * @c >0= bbox wholly on the right side. + */ +int P_BoxOnLineSide3(const AABox* aaBox, double lineSX, double lineSY, double lineDX, + double lineDY, double linePerp, double lineLength, double epsilon); void P_MakeDivline(const LineDef* lineDef, divline_t* divline); diff --git a/doomsday/engine/portable/src/bsp_main.c b/doomsday/engine/portable/src/bsp_main.c index 57490db9ba..91b7a25df5 100644 --- a/doomsday/engine/portable/src/bsp_main.c +++ b/doomsday/engine/portable/src/bsp_main.c @@ -43,31 +43,63 @@ void BSP_Register(void) C_VAR_INT("bsp-factor", &bspFactor, CVF_NO_MAX, 0, 0); } -static void findMapLimits(GameMap* src, int* bbox) +static void initAABoxFromEditableLineDefVertexes(AABoxf* aaBox, const LineDef* line) { - uint i; + const double* from = line->L_v1->buildData.pos; + const double* to = line->L_v2->buildData.pos; + aaBox->minX = MIN_OF(from[VX], to[VX]); + aaBox->minY = MIN_OF(from[VY], to[VY]); + aaBox->maxX = MAX_OF(from[VX], to[VX]); + aaBox->maxY = MAX_OF(from[VY], to[VY]); +} + +typedef struct { + AABoxf bounds; + boolean initialized; +} findmapboundsparams_t; + +static int findMapBoundsIterator(LineDef* line, void* parameters) +{ + findmapboundsparams_t* p = (findmapboundsparams_t*) parameters; + AABoxf lineAABox; + assert(p); - M_ClearBox(bbox); + // Do not consider zero-length LineDefs. + if(line->buildData.mlFlags & MLF_ZEROLENGTH) return false; // Continue iteration. - for(i = 0; i < src->numLineDefs; ++i) + initAABoxFromEditableLineDefVertexes(&lineAABox, line); + if(p->initialized) { - LineDef* l = &src->lineDefs[i]; + V2_AddToBox(p->bounds.arvec2, lineAABox.min); + } + else + { + V2_InitBox(p->bounds.arvec2, lineAABox.min); + p->initialized = true; + } + V2_AddToBox(p->bounds.arvec2, lineAABox.max); + return false; // Continue iteration. +} - if(!(l->buildData.mlFlags & MLF_ZEROLENGTH)) +static void findMapBounds(GameMap* map, AABoxf* aaBox) +{ + assert(map && aaBox); + + if(GameMap_LineDefCount(map)) + { + findmapboundsparams_t parm; + parm.initialized = false; + GameMap_LineDefIterator(map, findMapBoundsIterator, (void*)&parm); + if(parm.initialized) { - double x1 = l->v[0]->buildData.pos[VX]; - double y1 = l->v[0]->buildData.pos[VY]; - double x2 = l->v[1]->buildData.pos[VX]; - double y2 = l->v[1]->buildData.pos[VY]; - int lX = (int) floor(MIN_OF(x1, x2)); - int lY = (int) floor(MIN_OF(y1, y2)); - int hX = (int) ceil(MAX_OF(x1, x2)); - int hY = (int) ceil(MAX_OF(y1, y2)); - - M_AddToBox(bbox, lX, lY); - M_AddToBox(bbox, hX, hY); + V2_CopyBox(aaBox->arvec2, parm.bounds.arvec2); + return; } } + + // Clear. + V2_Set(aaBox->min, DDMAXFLOAT, DDMAXFLOAT); + V2_Set(aaBox->max, DDMINFLOAT, DDMINFLOAT); } /** @@ -79,29 +111,33 @@ static superblock_t* createInitialHEdges(GameMap* map) { uint startTime = Sys_GetRealTime(); - uint i; - int bw, bh; bsp_hedge_t* back, *front; superblock_t* block; - int mapBounds[4]; + AABoxf mapBoundsf; + AABox mapBounds; + int bw, bh; + uint i; // Find maximal vertexes. - findMapLimits(map, mapBounds); + findMapBounds(map, &mapBoundsf); + + mapBounds.minX = (int) floor(mapBoundsf.minX); + mapBounds.minY = (int) floor(mapBoundsf.minY); + mapBounds.maxX = (int) ceil(mapBoundsf.maxX); + mapBounds.maxY = (int) ceil(mapBoundsf.maxY); VERBOSE2( - Con_Message("Map goes from (%d,%d) to (%d,%d)\n", - mapBounds[BOXLEFT], mapBounds[BOXBOTTOM], - mapBounds[BOXRIGHT], mapBounds[BOXTOP]) ); + Con_Message("Map goes from [x:%f, y:%f] -> [x:%f, y:%f]\n", + mapBoundsf.minX, mapBoundsf.minY, mapBoundsf.maxX, mapBoundsf.maxY) ); block = BSP_SuperBlockCreate(); + block->aaBox.minX = mapBounds.minX - (mapBounds.minX & 0x7); + block->aaBox.minY = mapBounds.minY - (mapBounds.minY & 0x7); + bw = ((mapBounds.maxX - block->aaBox.minX) / 128) + 1; + bh = ((mapBounds.maxY - block->aaBox.minY) / 128) + 1; - block->bbox[BOXLEFT] = mapBounds[BOXLEFT] - (mapBounds[BOXLEFT] & 0x7); - block->bbox[BOXBOTTOM] = mapBounds[BOXBOTTOM] - (mapBounds[BOXBOTTOM] & 0x7); - bw = ((mapBounds[BOXRIGHT] - block->bbox[BOXLEFT]) / 128) + 1; - bh = ((mapBounds[BOXTOP] - block->bbox[BOXBOTTOM]) / 128) + 1; - - block->bbox[BOXRIGHT] = block->bbox[BOXLEFT] + 128 * M_CeilPow2(bw); - block->bbox[BOXTOP] = block->bbox[BOXBOTTOM] + 128 * M_CeilPow2(bh); + block->aaBox.maxX = block->aaBox.minX + 128 * M_CeilPow2(bw); + block->aaBox.maxY = block->aaBox.minY + 128 * M_CeilPow2(bh); for(i = 0; i < map->numLineDefs; ++i) { diff --git a/doomsday/engine/portable/src/bsp_node.c b/doomsday/engine/portable/src/bsp_node.c index ab5c1de2e9..a0d31edc2f 100644 --- a/doomsday/engine/portable/src/bsp_node.c +++ b/doomsday/engine/portable/src/bsp_node.c @@ -51,18 +51,16 @@ static __inline int pointOnHEdgeSide(double x, double y, const bsp_hedge_t* part void BSP_AddHEdgeToSuperBlock(superblock_t* block, bsp_hedge_t* hEdge) { #define SUPER_IS_LEAF(s) \ - ((s)->bbox[BOXRIGHT] - (s)->bbox[BOXLEFT] <= 256 && \ - (s)->bbox[BOXTOP] - (s)->bbox[BOXBOTTOM] <= 256) + ((s)->aaBox.maxX - (s)->aaBox.minX <= 256 && \ + (s)->aaBox.maxY - (s)->aaBox.minY <= 256) for(;;) { - int p1, p2; - int child; - int midPoint[2]; + int p1, p2, child, midPoint[2]; superblock_t* sub; - midPoint[VX] = (block->bbox[BOXLEFT] + block->bbox[BOXRIGHT]) / 2; - midPoint[VY] = (block->bbox[BOXBOTTOM] + block->bbox[BOXTOP]) / 2; + midPoint[VX] = (block->aaBox.minX + block->aaBox.maxX) / 2; + midPoint[VY] = (block->aaBox.minY + block->aaBox.maxY) / 2; // Update half-edge counts. if(hEdge->lineDef) @@ -77,8 +75,8 @@ void BSP_AddHEdgeToSuperBlock(superblock_t* block, bsp_hedge_t* hEdge) return; } - if(block->bbox[BOXRIGHT] - block->bbox[BOXLEFT] >= - block->bbox[BOXTOP] - block->bbox[BOXBOTTOM]) + if(block->aaBox.maxX - block->aaBox.minX >= + block->aaBox.maxY - block->aaBox.minY) { // Block is wider than it is high, or square. p1 = hEdge->v[0]->buildData.pos[VX] >= midPoint[VX]; @@ -113,22 +111,22 @@ void BSP_AddHEdgeToSuperBlock(superblock_t* block, bsp_hedge_t* hEdge) block->subs[child] = sub = BSP_SuperBlockCreate(); sub->parent = block; - if(block->bbox[BOXRIGHT] - block->bbox[BOXLEFT] >= - block->bbox[BOXTOP] - block->bbox[BOXBOTTOM]) + if(block->aaBox.maxX - block->aaBox.minX >= + block->aaBox.maxY - block->aaBox.minY) { - sub->bbox[BOXLEFT] = (child? midPoint[VX] : block->bbox[BOXLEFT]); - sub->bbox[BOXBOTTOM] = block->bbox[BOXBOTTOM]; + sub->aaBox.minX = (child? midPoint[VX] : block->aaBox.minX); + sub->aaBox.minY = block->aaBox.minY; - sub->bbox[BOXRIGHT] = (child? block->bbox[BOXRIGHT] : midPoint[VX]); - sub->bbox[BOXTOP] = block->bbox[BOXTOP]; + sub->aaBox.maxX = (child? block->aaBox.maxX : midPoint[VX]); + sub->aaBox.maxY = block->aaBox.maxY; } else { - sub->bbox[BOXLEFT] = block->bbox[BOXLEFT]; - sub->bbox[BOXBOTTOM] = (child? midPoint[VY] : block->bbox[BOXBOTTOM]); + sub->aaBox.minX = block->aaBox.minX; + sub->aaBox.minY = (child? midPoint[VY] : block->aaBox.minY); - sub->bbox[BOXRIGHT] = block->bbox[BOXRIGHT]; - sub->bbox[BOXTOP] = (child? block->bbox[BOXTOP] : midPoint[VY]); + sub->aaBox.maxX = block->aaBox.maxX; + sub->aaBox.maxY = (child? block->aaBox.maxY : midPoint[VY]); } } @@ -546,8 +544,8 @@ boolean BuildNodes(superblock_t* hEdgeList, binarytree_t** parent, size_t depth, hEdgeSet[LEFT] = (superblock_t *) BSP_SuperBlockCreate(); // Copy the bounding box of the edge list to the superblocks. - M_CopyBox(hEdgeSet[LEFT]->bbox, hEdgeList->bbox); - M_CopyBox(hEdgeSet[RIGHT]->bbox, hEdgeList->bbox); + memcpy(&hEdgeSet[LEFT]->aaBox, &hEdgeList->aaBox, sizeof(hEdgeSet[LEFT]->aaBox)); + memcpy(&hEdgeSet[RIGHT]->aaBox, &hEdgeList->aaBox, sizeof(hEdgeSet[RIGHT]->aaBox)); // Divide the half-edges into two lists: left & right. BSP_PartitionHEdges(hEdgeList, &partition, hEdgeSet[RIGHT], hEdgeSet[LEFT], cutList); diff --git a/doomsday/engine/portable/src/bsp_superblock.c b/doomsday/engine/portable/src/bsp_superblock.c index 56318eb331..587e6c95a0 100644 --- a/doomsday/engine/portable/src/bsp_superblock.c +++ b/doomsday/engine/portable/src/bsp_superblock.c @@ -315,8 +315,8 @@ static int evalPartitionWorker(const superblock_t* hEdgeList, bsp_hedge_t* part, * half-edges within it at once. Only when the partition line intercepts the * box do we need to go deeper into it. */ - num = P_BoxOnLineSide3(hEdgeList->bbox, part->pSX, part->pSY, part->pDX, part->pDY, - part->pPerp, part->pLength, DIST_EPSILON); + num = P_BoxOnLineSide3(&hEdgeList->aaBox, part->pSX, part->pSY, part->pDX, + part->pDY, part->pPerp, part->pLength, DIST_EPSILON); if(num < 0) { diff --git a/doomsday/engine/portable/src/p_maputil.c b/doomsday/engine/portable/src/p_maputil.c index 5d6413df1e..d762093bf8 100644 --- a/doomsday/engine/portable/src/p_maputil.c +++ b/doomsday/engine/portable/src/p_maputil.c @@ -245,37 +245,20 @@ int P_PointOnLinedefSide2(double pointX, double pointY, double lineDX, return (perp < 0? -1 : +1); } -/** - * Check the spatial relationship between the given box and a partitioning - * line. - * - * @param bbox Ptr to the box being tested. - * @param lineSX X coordinate of the start of the line. - * @param lineSY Y coordinate of the end of the line. - * @param lineDX X delta of the line (slope). - * @param lineDY Y delta of the line (slope). - * @param linePerp Perpendicular d of the line. - * @param lineLength Length of the line. - * @param epsilon Points within this distance will be considered equal. - * - * @return @c <0= bbox is wholly on the left side. - * @c 0= line intersects bbox. - * @c >0= bbox wholly on the right side. - */ -int P_BoxOnLineSide3(const int bbox[4], double lineSX, double lineSY, - double lineDX, double lineDY, double linePerp, - double lineLength, double epsilon) +int P_BoxOnLineSide3(const AABox* aaBox, double lineSX, double lineSY, + double lineDX, double lineDY, double linePerp, double lineLength, double epsilon) { -#define IFFY_LEN 4.0 +#define IFFY_LEN 4.0 - int p1, p2; - double x1 = (double)bbox[BOXLEFT] - IFFY_LEN * 1.5; - double y1 = (double)bbox[BOXBOTTOM] - IFFY_LEN * 1.5; - double x2 = (double)bbox[BOXRIGHT] + IFFY_LEN * 1.5; - double y2 = (double)bbox[BOXTOP] + IFFY_LEN * 1.5; + double x1 = (double)aaBox->minX - IFFY_LEN * 1.5; + double y1 = (double)aaBox->minY - IFFY_LEN * 1.5; + double x2 = (double)aaBox->maxX + IFFY_LEN * 1.5; + double y2 = (double)aaBox->maxY + IFFY_LEN * 1.5; + int p1, p2; if(FEQUAL(lineDX, 0)) - { // Horizontal. + { + // Horizontal. p1 = (x1 > lineSX? +1 : -1); p2 = (x2 > lineSX? +1 : -1); @@ -286,7 +269,8 @@ int P_BoxOnLineSide3(const int bbox[4], double lineSX, double lineSY, } } else if(FEQUAL(lineDY, 0)) - { // Vertical. + { + // Vertical. p1 = (y1 < lineSY? +1 : -1); p2 = (y2 < lineSY? +1 : -1); @@ -297,19 +281,19 @@ int P_BoxOnLineSide3(const int bbox[4], double lineSX, double lineSY, } } else if(lineDX * lineDY > 0) - { // Positive slope. + { + // Positive slope. p1 = P_PointOnLinedefSide2(x1, y2, lineDX, lineDY, linePerp, lineLength, epsilon); p2 = P_PointOnLinedefSide2(x2, y1, lineDX, lineDY, linePerp, lineLength, epsilon); } else - { // Negative slope. + { + // Negative slope. p1 = P_PointOnLinedefSide2(x1, y1, lineDX, lineDY, linePerp, lineLength, epsilon); p2 = P_PointOnLinedefSide2(x2, y2, lineDX, lineDY, linePerp, lineLength, epsilon); } - if(p1 == p2) - return p1; - + if(p1 == p2) return p1; return 0; #undef IFFY_LEN