217 lines
5.6 KiB
C
217 lines
5.6 KiB
C
/*
|
|
* --------------------------------------------------------------------------
|
|
* $Id: expand2x.c 11578 2009-02-23 22:02:27Z lalo $
|
|
*
|
|
* ALGORITHM
|
|
*
|
|
* ... (TBW)
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* Expands a layout by 2x in each dimension.
|
|
*
|
|
* H. S. Teoh
|
|
*/
|
|
|
|
#include <stdlib.h> /* just in case */
|
|
#include <expand2x.h> /* use compiler to do sanity check */
|
|
|
|
|
|
/* PROTOTYPES */
|
|
|
|
static void expand_misc(char **newlayout, int i, int j, char **layout);
|
|
static void expand_wall(char **newlayout, int i, int j, char **layout, int xsize, int ysize);
|
|
static void expand_door(char **newlayout, int i, int j, char **layout, int xsize, int ysize);
|
|
|
|
/* FUNCTIONS */
|
|
|
|
/**
|
|
* Expands the layout be a factor 2. Doors and walls are taken care of.
|
|
* @param layout
|
|
* layout to expand. Memory is free()d at the end, so pointer becomes invalid.
|
|
* @param xsize
|
|
* @param ysize
|
|
* layout size.
|
|
* @return
|
|
* new layout. Must be free()d by caller.
|
|
*/
|
|
char **expand2x(char **layout, int xsize, int ysize) {
|
|
int i, j;
|
|
int nxsize = xsize*2-1;
|
|
int nysize = ysize*2-1;
|
|
|
|
/* Allocate new layout */
|
|
char **newlayout = (char **)calloc(sizeof(char *), nxsize);
|
|
for (i = 0; i < nxsize; i++) {
|
|
newlayout[i] = (char *)calloc(sizeof(char), nysize);
|
|
}
|
|
|
|
for (i = 0; i < xsize; i++) {
|
|
for (j = 0; j < ysize; j++) {
|
|
switch (layout[i][j]) {
|
|
case '#':
|
|
expand_wall(newlayout, i, j, layout, xsize, ysize);
|
|
break;
|
|
|
|
case 'D':
|
|
expand_door(newlayout, i, j, layout, xsize, ysize);
|
|
break;
|
|
|
|
default:
|
|
expand_misc(newlayout, i, j, layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Dump old layout */
|
|
for (i = 0; i < xsize; i++) {
|
|
free(layout[i]);
|
|
}
|
|
free(layout);
|
|
|
|
return newlayout;
|
|
}
|
|
|
|
/**
|
|
* Copy the old tile X into the new one at location (i*2, j*2) and
|
|
* fill up the rest of the 2x2 result with 0:
|
|
* X ---> X 0
|
|
* 0 0
|
|
* @param newlayout
|
|
* map layout.
|
|
* @param i
|
|
* @param j
|
|
* spot to expand.
|
|
* @param layout
|
|
* map layout.
|
|
*/
|
|
static void expand_misc(char **newlayout, int i, int j, char **layout) {
|
|
newlayout[i*2][j*2] = layout[i][j];
|
|
/* (Note: no need to reset rest of 2x2 area to \0 because calloc does that
|
|
* for us.) */
|
|
}
|
|
|
|
/**
|
|
* Returns a bitmap that represents which squares on the right and bottom
|
|
* edges of a square (i,j) match the given character.
|
|
*
|
|
* @param ch
|
|
* character to look for.
|
|
* @param layout
|
|
* map.
|
|
* @param i
|
|
* @param j
|
|
* spot where to look.
|
|
* @param xsize
|
|
* @param ysize
|
|
* layout size.
|
|
* @return
|
|
* combination of the following values:
|
|
* - 1 means match on (i+1, j).
|
|
* - 2 means match on (i, j+1).
|
|
* - 4 means match on (i+1, j+1).
|
|
*/
|
|
static int calc_pattern(char ch, char **layout, int i, int j, int xsize, int ysize) {
|
|
int pattern = 0;
|
|
|
|
if (i+1 < xsize && layout[i+1][j] == ch)
|
|
pattern |= 1;
|
|
|
|
if (j+1 < ysize) {
|
|
if (layout[i][j+1] == ch)
|
|
pattern |= 2;
|
|
if (i+1 < xsize && layout[i+1][j+1] == ch)
|
|
pattern |= 4;
|
|
}
|
|
|
|
return pattern;
|
|
}
|
|
|
|
/**
|
|
* Expand a wall. This function will try to sensibly connect the resulting
|
|
* wall to adjacent wall squares, so that the result won't have disconnected
|
|
* walls.
|
|
* @param newlayout
|
|
* map layout.
|
|
* @param i
|
|
* @param j
|
|
* coordinates of wall to expand in non expanded layout.
|
|
* @param layout
|
|
* current (non expanded) layout.
|
|
* @param xsize
|
|
* @param ysize
|
|
* sizes of layout.
|
|
*/
|
|
static void expand_wall(char **newlayout, int i, int j, char **layout, int xsize, int ysize) {
|
|
int wall_pattern = calc_pattern('#', layout, i, j, xsize, ysize);
|
|
int door_pattern = calc_pattern('D', layout, i, j, xsize, ysize);
|
|
int both_pattern = wall_pattern|door_pattern;
|
|
|
|
newlayout[i*2][j*2] = '#';
|
|
if (i+1 < xsize) {
|
|
if (both_pattern&1) {
|
|
/* join walls/doors to the right */
|
|
newlayout[i*2+1][j*2] = layout[i+1][j];
|
|
}
|
|
}
|
|
|
|
if (j+1 < ysize) {
|
|
if (both_pattern&2) {
|
|
/* join walls/doors to the bottom */
|
|
newlayout[i*2][j*2+1] = layout[i][j+1];
|
|
}
|
|
|
|
if (wall_pattern == 7) {
|
|
/* if orig layout is a 2x2 wall block,
|
|
* we fill the result with walls. */
|
|
newlayout[i*2+1][j*2+1] = '#';
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Expand a door. This function will try to sensibly connect doors so that they meet up with
|
|
* adjacent walls. Note that it will also presumptuously delete (ignore) doors
|
|
* that it doesn't know how to correctly expand.
|
|
* @param newlayout
|
|
* expanded layout.
|
|
* @param i
|
|
* @param j
|
|
* coordinates of door to expand in non expanded layout.
|
|
* @param layout
|
|
* non expanded layout.
|
|
* @param xsize
|
|
* @param ysize
|
|
* size of non expanded layout.
|
|
*/
|
|
static void expand_door(char **newlayout, int i, int j, char **layout, int xsize, int ysize) {
|
|
int wall_pattern = calc_pattern('#', layout, i, j, xsize, ysize);
|
|
int door_pattern = calc_pattern('D', layout, i, j, xsize, ysize);
|
|
int join_pattern;
|
|
|
|
/* Doors "like" to connect to walls more than other doors. If there is
|
|
* a wall and another door, this door will connect to the wall and
|
|
* disconnect from the other door. */
|
|
if (wall_pattern&3) {
|
|
join_pattern = wall_pattern;
|
|
} else {
|
|
join_pattern = door_pattern;
|
|
}
|
|
|
|
newlayout[i*2][j*2] = 'D';
|
|
if (i+1 < xsize) {
|
|
if (join_pattern&1) {
|
|
/* there is a door/wall to the right */
|
|
newlayout[i*2+1][j*2] = 'D';
|
|
}
|
|
}
|
|
|
|
if (j+1 < ysize) {
|
|
if (join_pattern&2) {
|
|
/* there is a door/wall below */
|
|
newlayout[i*2][j*2+1] = 'D';
|
|
}
|
|
}
|
|
}
|