shithub: puzzles

Download patch

ref: 20a85890d713d9a6b701eee08a76538f0a4334e4
parent: 985b538e5346b1aad6d5e09d534fb9ccacfe9235
author: Simon Tatham <anakin@pobox.com>
date: Fri May 21 10:07:13 EDT 2021

Galaxies: clean up draw/undraw code for dragged arrows.

The previous code had multiple bugs. We had completely left out the
draw_update after drawing each arrow; we omitted the usual
precautionary clip() that constrains each arrow draw to the same
rectangle we just saved in the blitter; we re-computed the coordinates
of the opposite arrow at undraw time, instead of saving the
coordinates we _actually_ used after computing them the first time.
And we restored from the two blitters in the same order we saved them,
instead of reverse order, which was harmless at the time (the drawing
happened after both saves), but is generally bad practice, and needed
to be fixed when the code was rearranged to fix the rest of these
issues.

I noticed these issues in passing, while hunting the diagonal-line bug
fixed in the previous commit. These fixes by themselves would have
prevented any persistent drawing artefact as a result of that bug (the
clip() would have constrained the spurious diagonal line to the region
saved by the blitter, so it would have been undrawn again afterwards);
but it's better to have fixed the root cause as well!

--- a/galaxies.c
+++ b/galaxies.c
@@ -2383,7 +2383,7 @@
     blitter *blmirror;
 
     bool dragging;
-    int dragx, dragy;
+    int dragx, dragy, oppx, oppy;
 
     int *colour_scratch;
 
@@ -3112,7 +3112,7 @@
     ds->bl = NULL;
     ds->blmirror = NULL;
     ds->dragging = false;
-    ds->dragx = ds->dragy = 0;
+    ds->dragx = ds->dragy = ds->oppx = ds->oppy = 0;
 
     ds->colour_scratch = snewn(ds->w * ds->h, int);
 
@@ -3274,7 +3274,6 @@
     int w = ds->w, h = ds->h;
     int x, y;
     bool flashing = false;
-    int oppx, oppy;
 
     if (flashtime > 0) {
         int frame = (int)(flashtime / FLASH_TIME);
@@ -3284,14 +3283,10 @@
     if (ds->dragging) {
         assert(ds->bl);
         assert(ds->blmirror);
-        calculate_opposite_point(ui, ds, ds->dragx + TILE_SIZE/2,
-                                 ds->dragy + TILE_SIZE/2, &oppx, &oppy);
-        oppx -= TILE_SIZE/2;
-        oppy -= TILE_SIZE/2;
+        blitter_load(dr, ds->blmirror, ds->oppx, ds->oppy);
+        draw_update(dr, ds->oppx, ds->oppy, TILE_SIZE, TILE_SIZE);
         blitter_load(dr, ds->bl, ds->dragx, ds->dragy);
         draw_update(dr, ds->dragx, ds->dragy, TILE_SIZE, TILE_SIZE);
-        blitter_load(dr, ds->blmirror, oppx, oppy);
-        draw_update(dr, oppx, oppy, TILE_SIZE, TILE_SIZE);
         ds->dragging = false;
     }
     if (ds->cur_visible) {
@@ -3449,16 +3444,28 @@
     }
 
     if (ui->dragging) {
+        int oppx, oppy;
+
         ds->dragging = true;
         ds->dragx = ui->dx - TILE_SIZE/2;
         ds->dragy = ui->dy - TILE_SIZE/2;
         calculate_opposite_point(ui, ds, ui->dx, ui->dy, &oppx, &oppy);
+        ds->oppx = oppx - TILE_SIZE/2;
+        ds->oppy = oppy - TILE_SIZE/2;
+
         blitter_save(dr, ds->bl, ds->dragx, ds->dragy);
-        blitter_save(dr, ds->blmirror, oppx - TILE_SIZE/2, oppy - TILE_SIZE/2);
+        clip(dr, ds->dragx, ds->dragy, TILE_SIZE, TILE_SIZE);
         draw_arrow(dr, ds, ui->dx, ui->dy, SCOORD(ui->dotx) - ui->dx,
                    SCOORD(ui->doty) - ui->dy, COL_ARROW);
+        unclip(dr);
+        draw_update(dr, ds->dragx, ds->dragy, TILE_SIZE, TILE_SIZE);
+
+        blitter_save(dr, ds->blmirror, ds->oppx, ds->oppy);
+        clip(dr, ds->oppx, ds->oppy, TILE_SIZE, TILE_SIZE);
         draw_arrow(dr, ds, oppx, oppy, SCOORD(ui->dotx) - oppx,
                    SCOORD(ui->doty) - oppy, COL_ARROW);
+        unclip(dr);
+        draw_update(dr, ds->oppx, ds->oppy, TILE_SIZE, TILE_SIZE);
     }
 #ifdef EDITOR
     {