Skip to content

Commit

Permalink
Centralise initial clearing of the puzzle window.
Browse files Browse the repository at this point in the history
I don't know how I've never thought of this before! Pretty much every
game in this collection has to have a mechanism for noticing when
game_redraw is called for the first time on a new drawstate, and if
so, start by covering the whole window with a filled rectangle of the
background colour. This is a pain for implementers, and also awkward
because the drawstate often has to _work out_ its own pixel size (or
else remember it from when its size method was called).

The backends all do that so that the frontends don't have to guarantee
anything about the initial window contents. But that's a silly
tradeoff to begin with (there are way more backends than frontends, so
this _adds_ work rather than saving it), and also, in this code base
there's a standard way to handle things you don't want to have to do
in every backend _or_ every frontend: do them just once in the midend!

So now that rectangle-drawing operation happens in midend_redraw, and
I've been able to remove it from almost every puzzle. (A couple of
puzzles have other approaches: Slant didn't have a rectangle-draw
because it handles even the game borders using its per-tile redraw
function, and Untangle clears the whole window on every redraw
_anyway_ because it would just be too confusing not to.)

In some cases I've also been able to remove the 'started' flag from
the drawstate. But in many cases that has to stay because it also
triggers drawing of static display furniture other than the
background.
  • Loading branch information
sgtatham committed Apr 25, 2021
1 parent c6a48bf commit c0da615
Show file tree
Hide file tree
Showing 41 changed files with 36 additions and 293 deletions.
4 changes: 0 additions & 4 deletions blackbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -1377,10 +1377,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
int x0 = TODRAW(0)-1, y0 = TODRAW(0)-1;
int x1 = TODRAW(state->w+2), y1 = TODRAW(state->h+2);

draw_rect(dr, 0, 0,
TILE_SIZE * (state->w+3), TILE_SIZE * (state->h+3),
COL_BACKGROUND);

/* clockwise around the outline starting at pt behind (1,1). */
draw_line(dr, x0+ts, y0+ts, x0+ts, y0, COL_HIGHLIGHT);
draw_line(dr, x0+ts, y0, x1-ts, y0, COL_HIGHLIGHT);
Expand Down
3 changes: 0 additions & 3 deletions bridges.c
Original file line number Diff line number Diff line change
Expand Up @@ -2987,9 +2987,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,

/* Clear screen, if required. */
if (!ds->started) {
draw_rect(dr, 0, 0,
TILE_SIZE * ds->w + 2 * BORDER,
TILE_SIZE * ds->h + 2 * BORDER, COL_BACKGROUND);
#ifdef DRAW_GRID
draw_rect_outline(dr,
COORD(0)-1, COORD(0)-1,
Expand Down
10 changes: 0 additions & 10 deletions dominosa.c
Original file line number Diff line number Diff line change
Expand Up @@ -2746,7 +2746,6 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
#define FROMCOORD(x) ( ((x) - BORDER + TILESIZE) / TILESIZE - 1 )

struct game_drawstate {
bool started;
int w, h, tilesize;
unsigned long *visible;
};
Expand Down Expand Up @@ -3059,7 +3058,6 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
struct game_drawstate *ds = snew(struct game_drawstate);
int i;

ds->started = false;
ds->w = state->w;
ds->h = state->h;
ds->visible = snewn(ds->w * ds->h, unsigned long);
Expand Down Expand Up @@ -3225,14 +3223,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
int x, y, i;
unsigned char *used;

if (!ds->started) {
int pw, ph;
game_compute_size(&state->params, TILESIZE, &pw, &ph);
draw_rect(dr, 0, 0, pw, ph, COL_BACKGROUND);
draw_update(dr, 0, 0, pw, ph);
ds->started = true;
}

/*
* See how many dominoes of each type there are, so we can
* highlight clashes in red.
Expand Down
7 changes: 0 additions & 7 deletions fifteen.c
Original file line number Diff line number Diff line change
Expand Up @@ -904,13 +904,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
if (!ds->started) {
int coords[10];

draw_rect(dr, 0, 0,
TILE_SIZE * state->w + 2 * BORDER,
TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND);
draw_update(dr, 0, 0,
TILE_SIZE * state->w + 2 * BORDER,
TILE_SIZE * state->h + 2 * BORDER);

/*
* Recessed area containing the whole puzzle.
*/
Expand Down
11 changes: 1 addition & 10 deletions filling.c
Original file line number Diff line number Diff line change
Expand Up @@ -2021,17 +2021,8 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
(flashtime <= FLASH_TIME/3 || flashtime >= FLASH_TIME*2/3);

if (!ds->started) {
/*
* The initial contents of the window are not guaranteed and
* can vary with front ends. To be on the safe side, all games
* should start by drawing a big background-colour rectangle
* covering the whole window.
*/
draw_rect(dr, 0, 0, w*TILE_SIZE + 2*BORDER, h*TILE_SIZE + 2*BORDER,
COL_BACKGROUND);

/*
* Smaller black rectangle which is the main grid.
* Black rectangle which is the main grid.
*/
draw_rect(dr, BORDER - BORDER_WIDTH, BORDER - BORDER_WIDTH,
w*TILE_SIZE + 2*BORDER_WIDTH + 1,
Expand Down
3 changes: 0 additions & 3 deletions flip.c
Original file line number Diff line number Diff line change
Expand Up @@ -1202,9 +1202,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
int i, flashframe;

if (!ds->started) {
draw_rect(dr, 0, 0, TILE_SIZE * w + 2 * BORDER,
TILE_SIZE * h + 2 * BORDER, COL_BACKGROUND);

/*
* Draw the grid lines.
*/
Expand Down
7 changes: 0 additions & 7 deletions flood.c
Original file line number Diff line number Diff line change
Expand Up @@ -1128,13 +1128,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
if (!ds->started) {
int coords[10];

draw_rect(dr, 0, 0,
TILESIZE * w + 2 * BORDER,
TILESIZE * h + 2 * BORDER, COL_BACKGROUND);
draw_update(dr, 0, 0,
TILESIZE * w + 2 * BORDER,
TILESIZE * h + 2 * BORDER);

/*
* Recessed area containing the whole puzzle.
*/
Expand Down
1 change: 0 additions & 1 deletion galaxies.c
Original file line number Diff line number Diff line change
Expand Up @@ -3285,7 +3285,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
}

if (!ds->started) {
draw_rect(dr, 0, 0, DRAW_WIDTH, DRAW_HEIGHT, COL_BACKGROUND);
draw_rect(dr, BORDER - EDGE_THICKNESS + 1, BORDER - EDGE_THICKNESS + 1,
w*TILE_SIZE + EDGE_THICKNESS*2 - 1,
h*TILE_SIZE + EDGE_THICKNESS*2 - 1, COL_EDGE);
Expand Down
1 change: 0 additions & 1 deletion guess.c
Original file line number Diff line number Diff line change
Expand Up @@ -1349,7 +1349,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
new_move = (state->next_go != ds->next_go) || !ds->started;

if (!ds->started) {
draw_rect(dr, 0, 0, ds->w, ds->h, COL_BACKGROUND);
draw_rect(dr, SOLN_OX, SOLN_OY - ds->gapsz - 1, SOLN_W, 2, COL_FRAME);
draw_update(dr, 0, 0, ds->w, ds->h);
}
Expand Down
9 changes: 0 additions & 9 deletions inertia.c
Original file line number Diff line number Diff line change
Expand Up @@ -2008,15 +2008,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
* Initialise a fresh drawstate.
*/
if (!ds->started) {
int wid, ht;

/*
* Blank out the window initially.
*/
game_compute_size(&ds->p, TILESIZE, &wid, &ht);
draw_rect(dr, 0, 0, wid, ht, COL_BACKGROUND);
draw_update(dr, 0, 0, wid, ht);

/*
* Draw the grid lines.
*/
Expand Down
8 changes: 0 additions & 8 deletions keen.c
Original file line number Diff line number Diff line change
Expand Up @@ -2133,14 +2133,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
int x, y;

if (!ds->started) {
/*
* The initial contents of the window are not guaranteed and
* can vary with front ends. To be on the safe side, all
* games should start by drawing a big background-colour
* rectangle covering the whole window.
*/
draw_rect(dr, 0, 0, SIZE(w), SIZE(w), COL_BACKGROUND);

/*
* Big containing rectangle.
*/
Expand Down
4 changes: 0 additions & 4 deletions lightup.c
Original file line number Diff line number Diff line change
Expand Up @@ -2176,10 +2176,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
if (flashtime) flashing = (int)(flashtime * 3 / FLASH_TIME) != 1;

if (!ds->started) {
draw_rect(dr, 0, 0,
TILE_SIZE * ds->w + 2 * BORDER,
TILE_SIZE * ds->h + 2 * BORDER, COL_BACKGROUND);

draw_rect_outline(dr, COORD(0)-1, COORD(0)-1,
TILE_SIZE * ds->w + 2,
TILE_SIZE * ds->h + 2,
Expand Down
7 changes: 1 addition & 6 deletions magnets.c
Original file line number Diff line number Diff line change
Expand Up @@ -2205,12 +2205,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
flash = (int)(flashtime * 5 / FLASH_TIME) % 2;

if (!ds->started) {
/* draw background, corner +-. */
draw_rect(dr, 0, 0,
TILE_SIZE * (w+2) + 2 * BORDER,
TILE_SIZE * (h+2) + 2 * BORDER,
COL_BACKGROUND);

/* draw corner +-. */
draw_sym(dr, ds, -1, -1, POSITIVE, COL_TEXT);
draw_sym(dr, ds, state->w, state->h, NEGATIVE, COL_TEXT);

Expand Down
13 changes: 1 addition & 12 deletions map.c
Original file line number Diff line number Diff line change
Expand Up @@ -2872,21 +2872,10 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
ds->drag_visible = false;
}

/*
* The initial contents of the window are not guaranteed and
* can vary with front ends. To be on the safe side, all games
* should start by drawing a big background-colour rectangle
* covering the whole window.
*/
if (!ds->started) {
int ww, wh;

game_compute_size(&state->p, TILESIZE, &ww, &wh);
draw_rect(dr, 0, 0, ww, wh, COL_BACKGROUND);
draw_rect(dr, COORD(0), COORD(0), w*TILESIZE+1, h*TILESIZE+1,
COL_GRID);

draw_update(dr, 0, 0, ww, wh);
draw_update(dr, COORD(0), COORD(0), w*TILESIZE+1, h*TILESIZE+1);
ds->started = true;
}

Expand Down
29 changes: 29 additions & 0 deletions midend.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ struct midend {

game_params *params, *curparams;
game_drawstate *drawstate;
bool first_draw;
game_ui *ui;

game_state *oldstate;
Expand Down Expand Up @@ -196,6 +197,7 @@ midend *midend_new(frontend *fe, const game *ourgame,
me->aux_info = NULL;
me->genmode = GOT_NOTHING;
me->drawstate = NULL;
me->first_draw = true;
me->oldstate = NULL;
me->preset_menu = NULL;
me->anim_time = me->anim_pos = 0.0F;
Expand Down Expand Up @@ -318,6 +320,7 @@ void midend_size(midend *me, int *x, int *y, bool user_size)
me->ourgame->free_drawstate(me->drawing, me->drawstate);
me->drawstate = me->ourgame->new_drawstate(me->drawing,
me->states[0].state);
me->first_draw = true;
}

/*
Expand Down Expand Up @@ -1140,7 +1143,24 @@ void midend_redraw(midend *me)
assert(me->drawing);

if (me->statepos > 0 && me->drawstate) {
bool first_draw = me->first_draw;
me->first_draw = false;

start_draw(me->drawing);

if (first_draw) {
/*
* The initial contents of the window are not guaranteed
* by the front end. But we also don't want to require
* every single game to go to the effort of clearing the
* window on setup. So we centralise here the operation of
* covering the whole window with colour 0 (assumed to be
* the puzzle's background colour) the first time we do a
* redraw operation with a new drawstate.
*/
draw_rect(me->drawing, 0, 0, me->winwidth, me->winheight, 0);
}

if (me->oldstate && me->anim_time > 0 &&
me->anim_pos < me->anim_time) {
assert(me->dir != 0);
Expand All @@ -1152,6 +1172,15 @@ void midend_redraw(midend *me)
me->states[me->statepos-1].state, +1 /*shrug*/,
me->ui, 0.0, me->flash_pos);
}

if (first_draw) {
/*
* Call a big draw_update on the whole window, in case the
* game backend didn't.
*/
draw_update(me->drawing, 0, 0, me->winwidth, me->winheight);
}

end_draw(me->drawing);
}
}
Expand Down
7 changes: 0 additions & 7 deletions mines.c
Original file line number Diff line number Diff line change
Expand Up @@ -2978,13 +2978,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
if (!ds->started) {
int coords[10];

draw_rect(dr, 0, 0,
TILE_SIZE * state->w + 2 * BORDER,
TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND);
draw_update(dr, 0, 0,
TILE_SIZE * state->w + 2 * BORDER,
TILE_SIZE * state->h + 2 * BORDER);

/*
* Recessed area containing the whole puzzle.
*/
Expand Down
15 changes: 0 additions & 15 deletions mosaic.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ struct game_ui {

struct game_drawstate {
int tilesize;
bool started;
int *state;
int cur_x, cur_y; /* -1, -1 for no cursor displayed. */
int prev_cur_x, prev_cur_y;
Expand Down Expand Up @@ -1413,7 +1412,6 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
int i;

ds->tilesize = 0;
ds->started = false;
ds->state = NULL;
ds->state = snewn(state->width * state->height, int);
for (i = 0; i < state->width * state->height; i++)
Expand Down Expand Up @@ -1474,19 +1472,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
bool flashing = (flashtime > 0 && (flashtime <= FLASH_TIME / 3 ||
flashtime > 2*FLASH_TIME / 3));

if (!ds->started) {
/*
* The initial contents of the window are not guaranteed and
* can vary with front ends. To be on the safe side, all games
* should start by drawing a big background-colour rectangle
* covering the whole window.
*/
draw_rect(dr, 0, 0, (state->width + 1) * ds->tilesize,
(state->height + 1) * ds->tilesize, COL_BACKGROUND);
draw_update(dr, 0, 0, (state->width + 1) * ds->tilesize,
(state->height + 1) * ds->tilesize);
ds->started = true;
}
for (y = 0; y < state->height; y++) {
for (x = 0; x < state->width; x++) {
int cell = state->cells_contents[(y * state->width) + x];
Expand Down
19 changes: 0 additions & 19 deletions net.c
Original file line number Diff line number Diff line change
Expand Up @@ -2054,7 +2054,6 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
}

struct game_drawstate {
bool started;
int width, height;
int tilesize;
unsigned long *visible, *to_draw;
Expand Down Expand Up @@ -2441,7 +2440,6 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
game_drawstate *ds = snew(game_drawstate);
int i, ncells;

ds->started = false;
ds->width = state->width;
ds->height = state->height;
ncells = (state->width+2) * (state->height+2);
Expand Down Expand Up @@ -2838,23 +2836,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
int *loops;
float angle = 0.0;

/*
* Clear the screen on our first call.
*/
if (!ds->started) {
int w, h;
game_params params;

ds->started = true;

params.width = ds->width;
params.height = ds->height;
game_compute_size(&params, TILE_SIZE, &w, &h);

draw_rect(dr, 0, 0, w, h, COL_BACKGROUND);
draw_update(dr, 0, 0, w, h);
}

tx = ty = -1;
last_rotate_dir = dir==-1 ? oldstate->last_rotate_dir :
state->last_rotate_dir;
Expand Down
11 changes: 1 addition & 10 deletions netslide.c
Original file line number Diff line number Diff line change
Expand Up @@ -1589,22 +1589,13 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
int cur_x = -1, cur_y = -1;

/*
* Clear the screen and draw the exterior barrier lines if this
* is our first call.
* Draw the exterior barrier lines if this is our first call.
*/
if (!ds->started) {
int phase;

ds->started = true;

draw_rect(dr, 0, 0,
BORDER * 2 + WINDOW_OFFSET * 2 + TILE_SIZE * state->width + TILE_BORDER,
BORDER * 2 + WINDOW_OFFSET * 2 + TILE_SIZE * state->height + TILE_BORDER,
COL_BACKGROUND);
draw_update(dr, 0, 0,
BORDER * 2 + WINDOW_OFFSET*2 + TILE_SIZE*state->width + TILE_BORDER,
BORDER * 2 + WINDOW_OFFSET*2 + TILE_SIZE*state->height + TILE_BORDER);

for (phase = 0; phase < 2; phase++) {

for (x = 0; x < ds->width; x++) {
Expand Down
1 change: 0 additions & 1 deletion palisade.c
Original file line number Diff line number Diff line change
Expand Up @@ -1174,7 +1174,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
if (!ds->grid) {
char buf[40];
int bgw = (w+1) * ds->tilesize, bgh = (h+1) * ds->tilesize;
draw_rect(dr, 0, 0, bgw, bgh, COL_BACKGROUND);

for (r = 0; r <= h; ++r)
for (c = 0; c <= w; ++c)
Expand Down
Loading

0 comments on commit c0da615

Please sign in to comment.