- if (clue_mistake != ds->clue_error[i]
- || clue_satisfied != ds->clue_satisfied[i]) {
- int x, y;
- face_text_pos(ds, g, f, &x, &y);
- /* There seems to be a certain amount of trial-and-error
- * involved in working out the correct bounding-box for
- * the text. */
- draw_rect(dr, x - ds->tilesize/4 - 1, y - ds->tilesize/4 - 3,
- ds->tilesize/2 + 2, ds->tilesize/2 + 5,
- COL_BACKGROUND);
- draw_text(dr, x, y,
- FONT_VARIABLE, ds->tilesize/2,
- ALIGN_VCENTRE | ALIGN_HCENTRE,
- clue_mistake ? COL_MISTAKE :
- clue_satisfied ? COL_SATISFIED : COL_FOREGROUND, c);
- draw_update(dr, x - ds->tilesize/4 - 1, y - ds->tilesize/4 - 3,
- ds->tilesize/2 + 2, ds->tilesize/2 + 5);
+ /* Redrawing is somewhat involved.
+ *
+ * An update can theoretically affect an arbitrary number of edges
+ * (consider, for example, completing or breaking a cycle which doesn't
+ * satisfy all the clues -- we'll switch many edges between error and
+ * normal states). On the other hand, redrawing the whole grid takes a
+ * while, making the game feel sluggish, and many updates are actually
+ * quite well localized.
+ *
+ * This redraw algorithm attempts to cope with both situations gracefully
+ * and correctly. For localized changes, we set a clip rectangle, fill
+ * it with background, and then redraw (a plausible but conservative
+ * guess at) the objects which intersect the rectangle; if several
+ * objects need redrawing, we'll do them individually. However, if lots
+ * of objects are affected, we'll just redraw everything.
+ *
+ * The reason for all of this is that it's just not safe to do the redraw
+ * piecemeal. If you try to draw an antialiased diagonal line over
+ * itself, you get a slightly thicker antialiased diagonal line, which
+ * looks rather ugly after a while.
+ *
+ * So, we take two passes over the grid. The first attempts to work out
+ * what needs doing, and the second actually does it.
+ */
+
+ if (!ds->started)
+ redraw_everything = TRUE;
+ else {
+
+ /* First, trundle through the faces. */
+ for (i = 0; i < g->num_faces; i++) {
+ grid_face *f = g->faces + i;
+ int sides = f->order;
+ int clue_mistake;
+ int clue_satisfied;
+ int n = state->clues[i];
+ if (n < 0)
+ continue;
+
+ clue_mistake = (face_order(state, i, LINE_YES) > n ||
+ face_order(state, i, LINE_NO ) > (sides-n));
+ clue_satisfied = (face_order(state, i, LINE_YES) == n &&
+ face_order(state, i, LINE_NO ) == (sides-n));
+
+ if (clue_mistake != ds->clue_error[i] ||
+ clue_satisfied != ds->clue_satisfied[i]) {
+ ds->clue_error[i] = clue_mistake;
+ ds->clue_satisfied[i] = clue_satisfied;
+ if (nfaces == REDRAW_OBJECTS_LIMIT)
+ redraw_everything = TRUE;
+ else
+ faces[nfaces++] = i;
+ }
+ }