Upgrade the graphics in Towers to include a thematically appropriate

3D effect. (I only committed it without so that I could preserve a
record of how the code looked before I added it.) The 3D effect can
be disabled by setting TOWERS_2D in the environment, should anybody
seriously dislike it.

[originally from svn r8817]
This commit is contained in:
Simon Tatham
2010-01-07 18:42:01 +00:00
parent ceb12cb080
commit 7cd075870e

164
towers.c
View File

@ -1160,8 +1160,10 @@ static void game_changed_state(game_ui *ui, game_state *oldstate,
struct game_drawstate {
int tilesize;
int three_d; /* default 3D graphics are user-disableable */
int started;
long *tiles;
long *tiles; /* (w+2)*(w+2) temp space */
long *drawn; /* (w+2)*(w+2)*4: current drawn data */
int *errtmp;
};
@ -1465,10 +1467,12 @@ static game_drawstate *game_new_drawstate(drawing *dr, game_state *state)
int i;
ds->tilesize = 0;
ds->three_d = !getenv("TOWERS_2D");
ds->started = FALSE;
ds->tiles = snewn((w+2)*(w+2), long);
for (i = 0; i < (w+2)*(w+2); i++)
ds->tiles[i] = -1;
ds->drawn = snewn((w+2)*(w+2)*4, long);
for (i = 0; i < (w+2)*(w+2)*4; i++)
ds->drawn[i] = -1;
ds->errtmp = snewn((w+2)*(w+2), int);
return ds;
@ -1478,6 +1482,7 @@ static void game_free_drawstate(drawing *dr, game_drawstate *ds)
{
sfree(ds->errtmp);
sfree(ds->tiles);
sfree(ds->drawn);
sfree(ds);
}
@ -1485,36 +1490,75 @@ static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues,
int x, int y, long tile)
{
int w = clues->w /* , a = w*w */;
int tx, ty, tw, th;
int cx, cy, cw, ch;
int tx, ty;
char str[64];
tx = BORDER + x * TILESIZE + 1;
ty = BORDER + y * TILESIZE + 1;
tx = COORD(x);
ty = COORD(y);
cx = tx;
cy = ty;
cw = tw = TILESIZE-1;
ch = th = TILESIZE-1;
/* draw tower */
if (ds->three_d && (tile & DF_PLAYAREA) && (tile & DF_DIGIT_MASK)) {
int coords[8];
int xoff = (tile & DF_DIGIT_MASK) * TILESIZE / (8 * w);
int yoff = (tile & DF_DIGIT_MASK) * TILESIZE / (4 * w);
clip(dr, cx, cy, cw, ch);
/* left face of tower */
coords[0] = tx;
coords[1] = ty - 1;
coords[2] = tx;
coords[3] = ty + TILESIZE - 1;
coords[4] = coords[2] + xoff;
coords[5] = coords[3] - yoff;
coords[6] = coords[0] + xoff;
coords[7] = coords[1] - yoff;
draw_polygon(dr, coords, 4, COL_BACKGROUND, COL_GRID);
/* background needs erasing */
draw_rect(dr, cx, cy, cw, ch,
/* bottom face of tower */
coords[0] = tx + TILESIZE;
coords[1] = ty + TILESIZE - 1;
coords[2] = tx;
coords[3] = ty + TILESIZE - 1;
coords[4] = coords[2] + xoff;
coords[5] = coords[3] - yoff;
coords[6] = coords[0] + xoff;
coords[7] = coords[1] - yoff;
draw_polygon(dr, coords, 4, COL_BACKGROUND, COL_GRID);
/* now offset all subsequent drawing to the top of the tower */
tx += xoff;
ty -= yoff;
}
/* erase background */
draw_rect(dr, tx, ty, TILESIZE, TILESIZE,
(tile & DF_HIGHLIGHT) ? COL_HIGHLIGHT : COL_BACKGROUND);
/* pencil-mode highlight */
if (tile & DF_HIGHLIGHT_PENCIL) {
int coords[6];
coords[0] = cx;
coords[1] = cy;
coords[2] = cx+cw/2;
coords[3] = cy;
coords[4] = cx;
coords[5] = cy+ch/2;
coords[0] = tx;
coords[1] = ty;
coords[2] = tx+TILESIZE/2;
coords[3] = ty;
coords[4] = tx;
coords[5] = ty+TILESIZE/2;
draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT);
}
/* draw box outline */
if (tile & DF_PLAYAREA) {
int coords[8];
coords[0] = tx;
coords[1] = ty - 1;
coords[2] = tx + TILESIZE;
coords[3] = ty - 1;
coords[4] = tx + TILESIZE;
coords[5] = ty + TILESIZE - 1;
coords[6] = tx;
coords[7] = ty + TILESIZE - 1;
draw_polygon(dr, coords, 4, -1, COL_GRID);
}
/* new number needs drawing? */
if (tile & DF_DIGIT_MASK) {
str[1] = '\0';
@ -1543,11 +1587,11 @@ static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues,
* Determine the bounding rectangle within which we're going
* to put the pencil marks.
*/
/* Start with the whole square */
pl = tx;
pr = pl + TILESIZE;
/* Start with the whole square, minus space for impinging towers */
pl = tx + TILESIZE/8;
pr = tx + TILESIZE;
pt = ty;
pb = pt + TILESIZE;
pb = ty + TILESIZE - TILESIZE/4;
/*
* We arrange our pencil marks in a grid layout, with
@ -1588,8 +1632,8 @@ static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues,
/*
* Centre the resulting figure in the square.
*/
pl = tx + (TILESIZE - fontsize * pw) / 2;
pt = ty + (TILESIZE - fontsize * ph) / 2;
pl = pl + (pr - pl - fontsize * pw) / 2;
pt = pt + (pb - pt - fontsize * ph) / 2;
/*
* Now actually draw the pencil marks.
@ -1608,10 +1652,6 @@ static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues,
}
}
}
unclip(dr);
draw_update(dr, cx, cy, cw, ch);
}
static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
@ -1630,13 +1670,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
*/
draw_rect(dr, 0, 0, SIZE(w), SIZE(w), COL_BACKGROUND);
/*
* Big containing rectangle.
*/
draw_rect(dr, COORD(0), COORD(0),
w*TILESIZE+1, w*TILESIZE+1,
COL_GRID);
draw_update(dr, 0, 0, SIZE(w), SIZE(w));
ds->started = TRUE;
@ -1645,28 +1678,22 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
check_errors(state, ds->errtmp);
/*
* Draw the clues.
* Work out what data each tile should contain.
*/
for (i = 0; i < (w+2)*(w+2); i++)
ds->tiles[i] = 0; /* completely blank square */
/* The clue squares... */
for (i = 0; i < 4*w; i++) {
long tile = state->clues->clues[i];
if (!tile)
continue;
CLUEPOS(x, y, i, w);
if (ds->errtmp[(y+1)*(w+2)+(x+1)])
tile |= DF_ERROR;
if (ds->tiles[(y+1)*(w+2)+(x+1)] != tile) {
ds->tiles[(y+1)*(w+2)+(x+1)] = tile;
draw_tile(dr, ds, state->clues, x, y, tile);
}
ds->tiles[(y+1)*(w+2)+(x+1)] = tile;
}
/*
* Draw the main grid.
*/
/* ... and the main grid. */
for (y = 0; y < w; y++) {
for (x = 0; x < w; x++) {
long tile = DF_PLAYAREA;
@ -1690,9 +1717,42 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
if (ds->errtmp[(y+1)*(w+2)+(x+1)])
tile |= DF_ERROR;
if (ds->tiles[(y+1)*(w+2)+(x+1)] != tile) {
ds->tiles[(y+1)*(w+2)+(x+1)] = tile;
draw_tile(dr, ds, state->clues, x, y, tile);
ds->tiles[(y+1)*(w+2)+(x+1)] = tile;
}
}
/*
* Now actually draw anything that needs to be changed.
*/
for (y = 0; y < w+2; y++) {
for (x = 0; x < w+2; x++) {
long tl, tr, bl, br;
int i = y*(w+2)+x;
tr = ds->tiles[y*(w+2)+x];
tl = (x == 0 ? 0 : ds->tiles[y*(w+2)+(x-1)]);
br = (y == w+1 ? 0 : ds->tiles[(y+1)*(w+2)+x]);
bl = (x == 0 || y == w+1 ? 0 : ds->tiles[(y+1)*(w+2)+(x-1)]);
if (ds->drawn[i*4] != tl || ds->drawn[i*4+1] != tr ||
ds->drawn[i*4+2] != bl || ds->drawn[i*4+3] != br) {
clip(dr, COORD(x-1), COORD(y-1), TILESIZE, TILESIZE);
draw_tile(dr, ds, state->clues, x-1, y-1, tr);
if (x > 0)
draw_tile(dr, ds, state->clues, x-2, y-1, tl);
if (y <= w)
draw_tile(dr, ds, state->clues, x-1, y, br);
if (x > 0 && y <= w)
draw_tile(dr, ds, state->clues, x-2, y, bl);
unclip(dr);
draw_update(dr, COORD(x-1), COORD(y-1), TILESIZE, TILESIZE);
ds->drawn[i*4] = tl;
ds->drawn[i*4+1] = tr;
ds->drawn[i*4+2] = bl;
ds->drawn[i*4+3] = br;
}
}
}