From 01dc408afc43354562c2da85596b174db88db626 Mon Sep 17 00:00:00 2001 From: danij Date: Wed, 9 Oct 2013 07:00:08 +0100 Subject: [PATCH] World: Added LineBlockmap --- doomsday/client/client.pro | 2 + doomsday/client/include/world/blockmap.h | 5 +- doomsday/client/include/world/lineblockmap.h | 47 ++++++++++++ doomsday/client/src/world/lineblockmap.cpp | 77 ++++++++++++++++++++ doomsday/client/src/world/map.cpp | 65 ++--------------- doomsday/server/server.pro | 2 + 6 files changed, 140 insertions(+), 58 deletions(-) create mode 100644 doomsday/client/include/world/lineblockmap.h create mode 100644 doomsday/client/src/world/lineblockmap.cpp diff --git a/doomsday/client/client.pro b/doomsday/client/client.pro index 6000b0a3b2..44d32c9c8f 100644 --- a/doomsday/client/client.pro +++ b/doomsday/client/client.pro @@ -475,6 +475,7 @@ DENG_HEADERS += \ include/world/hand.h \ include/world/huecircle.h \ include/world/line.h \ + include/world/lineblockmap.h \ include/world/lineowner.h \ include/world/linesighttest.h \ include/world/map.h \ @@ -814,6 +815,7 @@ SOURCES += \ src/world/hand.cpp \ src/world/huecircle.cpp \ src/world/line.cpp \ + src/world/lineblockmap.cpp \ src/world/linesighttest.cpp \ src/world/map.cpp \ src/world/mapelement.cpp \ diff --git a/doomsday/client/include/world/blockmap.h b/doomsday/client/include/world/blockmap.h index 3b9cf67e5c..b2b1523ca0 100644 --- a/doomsday/client/include/world/blockmap.h +++ b/doomsday/client/include/world/blockmap.h @@ -44,7 +44,10 @@ class Blockmap typedef Vector2ui Cell; /** - * POD structure representing a rectangular range of cells. + * POD structure for representing an inclusive-exclusive rectangular range + * of cells. + * + * @todo Use Rectangleui instead -ds */ struct CellBlock { diff --git a/doomsday/client/include/world/lineblockmap.h b/doomsday/client/include/world/lineblockmap.h new file mode 100644 index 0000000000..aa975e7b6d --- /dev/null +++ b/doomsday/client/include/world/lineblockmap.h @@ -0,0 +1,47 @@ +/** @file lineblockmap.h Specialized world map line blockmap. + * + * @authors Copyright © 2003-2013 Jaakko Keränen + * @authors Copyright © 2006-2013 Daniel Swanson + * + * @par License + * GPL: http://www.gnu.org/licenses/gpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the GNU + * General Public License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef DENG_WORLD_LINEBLOCKMAP_H +#define DENG_WORLD_LINEBLOCKMAP_H + +#include + +#include "world/blockmap.h" +#include "Line" + +/** + * Specializes Blockmap for use with map Lines, implementing a linkage algorithm + * that replicates the quirky behavior of doom.exe + * + * @ingroup world + */ +class LineBlockmap : public de::Blockmap +{ +public: + LineBlockmap(AABoxd const &bounds, uint cellSize); + + /// @note Assumes @a line is not yet linked! + void link(Line &line); + + /// @note Assumes none of the specified @a lines are yet linked! + void link(QList const &lines); +}; + +#endif // DENG_WORLD_LINEBLOCKMAP_H diff --git a/doomsday/client/src/world/lineblockmap.cpp b/doomsday/client/src/world/lineblockmap.cpp new file mode 100644 index 0000000000..b351f0a032 --- /dev/null +++ b/doomsday/client/src/world/lineblockmap.cpp @@ -0,0 +1,77 @@ +/** @file lineblockmap.cpp Specialized world map line blockmap. + * + * @authors Copyright © 2003-2013 Jaakko Keränen + * @authors Copyright © 2006-2013 Daniel Swanson + * + * @par License + * GPL: http://www.gnu.org/licenses/gpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the GNU + * General Public License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include "world/lineblockmap.h" + +using namespace de; + +LineBlockmap::LineBlockmap(AABoxd const &bounds, uint cellSize) + : Blockmap(bounds, Vector2ui(cellSize, cellSize)) +{} + +void LineBlockmap::link(Line &line) +{ + // Polyobj lines are excluded (presently...). + if(line.definesPolyobj()) return; + + // Determine the block of cells we'll be working within. + BlockmapCellBlock const cellBlock = toCellBlock(line.aaBox()); + BlockmapCell cell; + for(cell.y = cellBlock.min.y; cell.y < cellBlock.max.y; ++cell.y) + for(cell.x = cellBlock.min.x; cell.x < cellBlock.max.x; ++cell.x) + { + if(line.slopeType() == ST_VERTICAL || line.slopeType() == ST_HORIZONTAL) + { + Blockmap::link(cell, &line); + continue; + } + + Vector2d const point(origin() + cellDimensions() * cell); + + // Choose a cell diagonal to test. + Vector2d from, to; + if(line.slopeType() == ST_POSITIVE) + { + // Line slope / vs \ cell diagonal. + from = Vector2d(point.x, point.y + cellDimensions().y); + to = Vector2d(point.x + cellDimensions().x, point.y); + } + else + { + // Line slope \ vs / cell diagonal. + from = Vector2d(point.x + cellDimensions().x, point.y + cellDimensions().y); + to = Vector2d(point.x, point.y); + } + + // Would Line intersect this? + if((line.pointOnSide(from) < 0) != (line.pointOnSide(to) < 0)) + { + Blockmap::link(cell, &line); + } + } +} + +void LineBlockmap::link(QList const &lines) +{ + foreach(Line *line, lines) + { + link(*line); + } +} diff --git a/doomsday/client/src/world/map.cpp b/doomsday/client/src/world/map.cpp index 1907329c1c..a3ade43aeb 100644 --- a/doomsday/client/src/world/map.cpp +++ b/doomsday/client/src/world/map.cpp @@ -46,6 +46,7 @@ #include "world/bsp/partitioner.h" #include "world/blockmap.h" +#include "world/lineblockmap.h" #include "world/entitydatabase.h" #include "world/generators.h" #include "world/lineowner.h" @@ -141,7 +142,7 @@ DENG2_OBSERVES(bsp::Partitioner, UnclosedSectorFound) /// Blockmaps: QScopedPointer mobjBlockmap; QScopedPointer polyobjBlockmap; - QScopedPointer lineBlockmap; + QScopedPointer lineBlockmap; QScopedPointer bspLeafBlockmap; #ifdef __CLIENT__ @@ -686,7 +687,6 @@ DENG2_OBSERVES(bsp::Partitioner, UnclosedSectorFound) void initLineBlockmap() { #define BLOCKMAP_MARGIN 8 // size guardband -#define CELL_SIZE MAPBLOCKUNITS // Setup the blockmap area to enclose the whole map, plus a margin // (margin is needed for a map that fits entirely inside one blockmap cell). @@ -694,67 +694,17 @@ DENG2_OBSERVES(bsp::Partitioner, UnclosedSectorFound) Vector2d max(bounds.maxX + BLOCKMAP_MARGIN, bounds.maxY + BLOCKMAP_MARGIN); AABoxd expandedBounds(min.x, min.y, max.x, max.y); - lineBlockmap.reset(new Blockmap(expandedBounds, Vector2ui(CELL_SIZE, CELL_SIZE))); + lineBlockmap.reset(new LineBlockmap(expandedBounds, MAPBLOCKUNITS)); - LOG_INFO("Line blockmap dimensions:") << lineBlockmap->dimensions().asText(); + LOG_INFO("Line blockmap dimensions:") + << lineBlockmap->dimensions().asText(); // Populate the blockmap. - foreach(Line *line, lines) - { - linkLineInBlockmap(*line); - } + lineBlockmap->link(lines); -#undef CELL_SIZE #undef BLOCKMAP_MARGIN } - void linkLineInBlockmap(Line &line) - { - // Lines of Polyobjs don't get into the blockmap (presently...). - if(line.definesPolyobj()) return; - - Vector2d const &origin = lineBlockmap->origin(); - Vector2d const &cellDimensions = lineBlockmap->cellDimensions(); - - // Determine the block of cells we'll be working within. - BlockmapCellBlock cellBlock = lineBlockmap->toCellBlock(line.aaBox()); - - BlockmapCell cell; - for(cell.y = cellBlock.min.y; cell.y < cellBlock.max.y; ++cell.y) - for(cell.x = cellBlock.min.x; cell.x < cellBlock.max.x; ++cell.x) - { - if(line.slopeType() == ST_VERTICAL || - line.slopeType() == ST_HORIZONTAL) - { - lineBlockmap->link(cell, &line); - continue; - } - - Vector2d point = origin + cellDimensions * Vector2d(cell.x, cell.y); - - // Choose a cell diagonal to test. - Vector2d from, to; - if(line.slopeType() == ST_POSITIVE) - { - // Line slope / vs \ cell diagonal. - from = Vector2d(point.x, point.y + cellDimensions.y); - to = Vector2d(point.x + cellDimensions.x, point.y); - } - else - { - // Line slope \ vs / cell diagonal. - from = Vector2d(point.x + cellDimensions.x, point.y + cellDimensions.y); - to = Vector2d(point.x, point.y); - } - - // Would Line intersect this? - if((line.pointOnSide(from) < 0) != (line.pointOnSide(to) < 0)) - { - lineBlockmap->link(cell, &line); - } - } - } - /** * Construct an initial (empty) mobj blockmap. * @@ -773,7 +723,8 @@ DENG2_OBSERVES(bsp::Partitioner, UnclosedSectorFound) mobjBlockmap.reset(new Blockmap(expandedBounds, Vector2ui(CELL_SIZE, CELL_SIZE))); - LOG_INFO("Mobj blockmap dimensions:") << mobjBlockmap->dimensions().asText(); + LOG_INFO("Mobj blockmap dimensions:") + << mobjBlockmap->dimensions().asText(); #undef CELL_SIZE #undef BLOCKMAP_MARGIN diff --git a/doomsday/server/server.pro b/doomsday/server/server.pro index 9b0b2d7e91..c5ebf14a91 100644 --- a/doomsday/server/server.pro +++ b/doomsday/server/server.pro @@ -242,6 +242,7 @@ DENG_HEADERS += \ $$SRC/include/world/entitydatabase.h \ $$SRC/include/world/entitydef.h \ $$SRC/include/world/line.h \ + $$SRC/include/world/lineblockmap.h \ $$SRC/include/world/lineowner.h \ $$SRC/include/world/linesighttest.h \ $$SRC/include/world/map.h \ @@ -410,6 +411,7 @@ SOURCES += \ $$SRC/src/world/entitydatabase.cpp \ $$SRC/src/world/entitydef.cpp \ $$SRC/src/world/line.cpp \ + $$SRC/src/world/lineblockmap.cpp \ $$SRC/src/world/linesighttest.cpp \ $$SRC/src/world/map.cpp \ $$SRC/src/world/mapelement.cpp \