From 58511aa009c672cc2ade783d537a5830806fd02c Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Sun, 30 Jul 2023 11:30:19 +0100 Subject: [PATCH] Same Game: more efficient tile_redraw I've rewritten tile_redraw to reduce the number of calls to draw_rect(). Before, it would generally make five calls to draw_rect() when drawing a tile. Now it makes at most three, and usually two. That's one draw_rect() for each colour that appears in the tile, which is as good as it can get. This reduces the time to draw a large puzzle by about 35% on Firefox 102. This is of significance to me because CanvasRenderingContext2D on my test KaiOS device seems to have a limit on the number of fill() and fillRect() calls that it will tolerate in a short time. This means that if you issue more than 1024 fillRect() calls in rapid succession, the later ones are simply ignored. Same Game's largest preset called draw_rect() so much that it hit this limit. That meant that the right-hand side of the grid didn't get properly drawn when starting a new game. Now that it is less profligate with draw_rect() it fits comfortably within the limit and I get to see the entire grid. --- samegame.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/samegame.c b/samegame.c index 5638c07..33e99c2 100644 --- a/samegame.c +++ b/samegame.c @@ -1471,6 +1471,7 @@ static void tile_redraw(drawing *dr, game_drawstate *ds, int tile, int bgcolour) { int outer = bgcolour, inner = outer, col = tile & TILE_COLMASK; + int tile_w, tile_h, outer_w, outer_h; if (col) { if (tile & TILE_IMPOSSIBLE) { @@ -1483,19 +1484,25 @@ static void tile_redraw(drawing *dr, game_drawstate *ds, outer = inner = col; } } - draw_rect(dr, COORD(x), COORD(y), TILE_INNER, TILE_INNER, outer); - draw_rect(dr, COORD(x)+TILE_INNER/4, COORD(y)+TILE_INNER/4, - TILE_INNER/2, TILE_INNER/2, inner); - - if (dright) - draw_rect(dr, COORD(x)+TILE_INNER, COORD(y), TILE_GAP, TILE_INNER, - (tile & TILE_JOINRIGHT) ? outer : bgcolour); - if (dbelow) - draw_rect(dr, COORD(x), COORD(y)+TILE_INNER, TILE_INNER, TILE_GAP, - (tile & TILE_JOINDOWN) ? outer : bgcolour); - if (dright && dbelow) - draw_rect(dr, COORD(x)+TILE_INNER, COORD(y)+TILE_INNER, TILE_GAP, TILE_GAP, - (tile & TILE_JOINDIAG) ? outer : bgcolour); + tile_w = dright ? TILE_SIZE : TILE_INNER; + tile_h = dbelow ? TILE_SIZE : TILE_INNER; + outer_w = (tile & TILE_JOINRIGHT) ? tile_w : TILE_INNER; + outer_h = (tile & TILE_JOINDOWN) ? tile_h : TILE_INNER; + /* Draw the background if any of it will be visible. */ + if (outer_w != tile_w || outer_h != tile_h || outer == bgcolour) + draw_rect(dr, COORD(x), COORD(y), tile_w, tile_h, bgcolour); + /* Draw the piece. */ + if (outer != bgcolour) + draw_rect(dr, COORD(x), COORD(y), outer_w, outer_h, outer); + if (inner != outer) + draw_rect(dr, COORD(x)+TILE_INNER/4, COORD(y)+TILE_INNER/4, + TILE_INNER/2, TILE_INNER/2, inner); + /* Reset bottom-right corner if necessary. */ + if ((tile & (TILE_JOINRIGHT | TILE_JOINDOWN | TILE_JOINDIAG)) == + (TILE_JOINRIGHT | TILE_JOINDOWN) && outer != bgcolour && + TILE_GAP != 0) + draw_rect(dr, COORD(x)+TILE_INNER, COORD(y)+TILE_INNER, + TILE_GAP, TILE_GAP, bgcolour); if (tile & TILE_HASSEL) { int sx = COORD(x)+2, sy = COORD(y)+2, ssz = TILE_INNER-5;