Skip to content

Commit

Permalink
More aggressive tile clearing for cave corridors
Browse files Browse the repository at this point in the history
Use bresenham line drawing to ensure that even
corner corridors are big enough.

The downside is that due to the way bresenham
draws lines, it could cause a lot of tiles to be cleared
if they are on the wrong diagonal.
  • Loading branch information
cxong committed May 23, 2016
1 parent 94c8279 commit e433877
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 39 deletions.
14 changes: 7 additions & 7 deletions src/cdogs/algorithms.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ typedef struct
// and also whether to early-terminate if the line is blocked
bool CheckBlockedAndEarlyTerminate;
bool (*IsBlocked)(void *, Vec2i);
void (*Draw)(void *, Vec2i);
void (*OnPoint)(void *, Vec2i);
void *data;
} AlgoLineData;
static bool BresenhamLine(Vec2i from, Vec2i to, AlgoLineData *data)
Expand All @@ -61,7 +61,7 @@ static bool BresenhamLine(Vec2i from, Vec2i to, AlgoLineData *data)
}
else
{
data->Draw(data->data, v);
data->OnPoint(data->data, v);
}
if (e2 > -d.y)
{
Expand All @@ -84,7 +84,7 @@ static bool BresenhamLine(Vec2i from, Vec2i to, AlgoLineData *data)
}
else
{
data->Draw(data->data, v);
data->OnPoint(data->data, v);
}
return true;
}
Expand Down Expand Up @@ -235,8 +235,8 @@ static bool XiaolinWuDraw(
}
else
{
if (RFPART(aa) > AAFACTOR) data->Draw(data->data, a);
if (FPART(aa) > AAFACTOR && !isEnd) data->Draw(data->data, b);
if (RFPART(aa) > AAFACTOR) data->OnPoint(data->data, a);
if (FPART(aa) > AAFACTOR && !isEnd) data->OnPoint(data->data, b);
}
return true;
}
Expand All @@ -263,15 +263,15 @@ void BresenhamLineDraw(Vec2i from, Vec2i to, AlgoLineDrawData *data)
{
AlgoLineData bData;
bData.CheckBlockedAndEarlyTerminate = false;
bData.Draw = data->Draw;
bData.OnPoint = data->Draw;
bData.data = data->data;
BresenhamLine(from, to, &bData);
}
void XiaolinWuLineDraw(Vec2i from, Vec2i to, AlgoLineDrawData *data)
{
AlgoLineData bData;
bData.CheckBlockedAndEarlyTerminate = false;
bData.Draw = data->Draw;
bData.OnPoint = data->Draw;
bData.data = data->data;
XiaolinWuLine(from, to, &bData);
}
Expand Down
93 changes: 61 additions & 32 deletions src/cdogs/map_cave.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,7 @@
*/
#include "map_cave.h"

#include "actors.h"
#include "campaigns.h"
#include "events.h"
#include "game_events.h"
#include "gamedata.h"
#include "handle_game_events.h"
#include "log.h"
#include "map_build.h"
#include "net_util.h"
#include "algorithms.h"


static void CaveRep(Map *map, const int r1, const int r2);
Expand Down Expand Up @@ -304,16 +296,16 @@ static void AddCorridor(
IMapSet(map, end, tile);
}

static bool CheckCorridorsAroundTile(
const Map *map, const int corridorWidth, const Vec2i v);
// Make sure corridors are wide enough
static void FixValidWallTile(
Map *map, const int corridorWidth, unsigned short *tile,
const Vec2i v, const Vec2i d);
static void FixCorridors(Map *map, const int corridorWidth)
{
// Find all instances where a corridor is too narrow
// Do this by ensuring that each wall tile is, on all four sides, either
// Do this by drawing a line from each wall tile to its surrounding square
// area, and that this line of tiles that each wall tile is either
// - blocked by a neighbouring wall tile, or
// - is followed by at least corridorWidth floor tiles in that direction
// - only consists of floor tiles
// If not, then replace that wall with a floor tile
Vec2i v;
for (v.y = corridorWidth; v.y < map->Size.y - corridorWidth; v.y++)
Expand All @@ -327,32 +319,69 @@ static void FixCorridors(Map *map, const int corridorWidth)
{
continue;
}
// Top
FixValidWallTile(map, corridorWidth, tile, v, Vec2iNew(0, -1));
// Bottom
FixValidWallTile(map, corridorWidth, tile, v, Vec2iNew(0, 1));
// Left
FixValidWallTile(map, corridorWidth, tile, v, Vec2iNew(-1, 0));
// Right
FixValidWallTile(map, corridorWidth, tile, v, Vec2iNew(1, 0));
if (!CheckCorridorsAroundTile(map, corridorWidth, v))
{
// Corridor checks failed; replace with a floor tile
*tile = MAP_FLOOR;
}
}
}
}
static void FixValidWallTile(
Map *map, const int corridorWidth, unsigned short *tile,
const Vec2i v, const Vec2i d)
typedef struct
{
const Map *M;
int Counter;
bool IsFirstWall;
bool AreAllFloors;
} FixCorridorOnTileData;
static void FixCorridorOnTile(void *data, Vec2i v);
static bool CheckCorridorsAroundTile(
const Map *map, const int corridorWidth, const Vec2i v)
{
Vec2i v1 = Vec2iAdd(v, d);
if (IMapGet(map, v1) != MAP_WALL)
AlgoLineDrawData data;
data.Draw = FixCorridorOnTile;
FixCorridorOnTileData onTileData;
onTileData.M = map;
data.data = &onTileData;
Vec2i v1;
for (v1.y = v.y - corridorWidth; v1.y <= v.y + corridorWidth; v1.y++)
{
for (int i = 0; i < corridorWidth; i++, v1 = Vec2iAdd(v1, d))
for (v1.x = v.x - corridorWidth; v1.x <= v.x + corridorWidth; v1.x++)
{
if (IMapGet(map, v1) != MAP_FLOOR)
// only draw out to edges
if (v1.y != v.y - corridorWidth && v1.y != v.y + corridorWidth &&
v1.x != v.x - corridorWidth && v1.x != v.x + corridorWidth)
{
// Not enough spaces; replace with floor
*tile = MAP_FLOOR;
return;
continue;
}
onTileData.Counter = 0;
onTileData.IsFirstWall = false;
onTileData.AreAllFloors = true;
BresenhamLineDraw(v, v1, &data);
if (!onTileData.IsFirstWall && !onTileData.AreAllFloors)
{
return false;
}
}
}
return true;
}
static void FixCorridorOnTile(void *data, Vec2i v)
{
FixCorridorOnTileData *onTileData = data;
if (onTileData->Counter == 1)
{
// This is the first tile after the starting tile
// If this tile is a wall, result is good, and we don't care about
// the rest of the tiles anymore
onTileData->IsFirstWall = IMapGet(onTileData->M, v) == MAP_WALL;
}
if (onTileData->Counter > 0)
{
if (IMapGet(onTileData->M, v) != MAP_FLOOR)
{
onTileData->AreAllFloors = false;
}
}
onTileData->Counter++;
}

0 comments on commit e433877

Please sign in to comment.