Skip to content

Commit

Permalink
World: Added LineBlockmap
Browse files Browse the repository at this point in the history
  • Loading branch information
danij-deng committed Oct 9, 2013
1 parent 5e2bd63 commit 01dc408
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 58 deletions.
2 changes: 2 additions & 0 deletions doomsday/client/client.pro
Expand Up @@ -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 \
Expand Down Expand Up @@ -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 \
Expand Down
5 changes: 4 additions & 1 deletion doomsday/client/include/world/blockmap.h
Expand Up @@ -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
{
Expand Down
47 changes: 47 additions & 0 deletions 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 <jaakko.keranen@iki.fi>
* @authors Copyright © 2006-2013 Daniel Swanson <danij@dengine.net>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>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</small>
*/

#ifndef DENG_WORLD_LINEBLOCKMAP_H
#define DENG_WORLD_LINEBLOCKMAP_H

#include <QList>

#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<Line *> const &lines);
};

#endif // DENG_WORLD_LINEBLOCKMAP_H
77 changes: 77 additions & 0 deletions 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 <jaakko.keranen@iki.fi>
* @authors Copyright © 2006-2013 Daniel Swanson <danij@dengine.net>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>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</small>
*/

#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<Line *> const &lines)
{
foreach(Line *line, lines)
{
link(*line);
}
}
65 changes: 8 additions & 57 deletions doomsday/client/src/world/map.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -141,7 +142,7 @@ DENG2_OBSERVES(bsp::Partitioner, UnclosedSectorFound)
/// Blockmaps:
QScopedPointer<Blockmap> mobjBlockmap;
QScopedPointer<Blockmap> polyobjBlockmap;
QScopedPointer<Blockmap> lineBlockmap;
QScopedPointer<LineBlockmap> lineBlockmap;
QScopedPointer<Blockmap> bspLeafBlockmap;

#ifdef __CLIENT__
Expand Down Expand Up @@ -686,75 +687,24 @@ 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).
Vector2d min(bounds.minX - BLOCKMAP_MARGIN, bounds.minY - BLOCKMAP_MARGIN);
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.
*
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions doomsday/server/server.pro
Expand Up @@ -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 \
Expand Down Expand Up @@ -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 \
Expand Down

0 comments on commit 01dc408

Please sign in to comment.