- /* Horizontal lines */
- FORALL_HL(state, i, j) {
- switch (RIGHTOF_DOT(state, i, j)) {
- case LINE_UNKNOWN:
- if (ds->hl[HL_INDEX(state, i, j)] != RIGHTOF_DOT(state, i, j)) {
- CLEAR_HL(i, j);
- }
- break;
- case LINE_YES:
- if (ds->hl[HL_INDEX(state, i, j)] != RIGHTOF_DOT(state, i, j) ||
- flash_changed) {
- CLEAR_HL(i, j);
- draw_rect(dr,
- BORDER + i * TILE_SIZE + LINEWIDTH - LINEWIDTH/2,
- BORDER + j * TILE_SIZE - LINEWIDTH/2,
- TILE_SIZE - LINEWIDTH, LINEWIDTH,
- line_colour);
- }
- break;
- case LINE_NO:
- if (ds->hl[HL_INDEX(state, i, j)] != RIGHTOF_DOT(state, i, j)) {
- CLEAR_HL(i, j);
- draw_line(dr,
- BORDER + i * TILE_SIZE + TILE_SIZE/2 - CROSS_SIZE,
- BORDER + j * TILE_SIZE + CROSS_SIZE - 1,
- BORDER + i * TILE_SIZE + TILE_SIZE/2 + CROSS_SIZE - 1,
- BORDER + j * TILE_SIZE - CROSS_SIZE,
- COL_FOREGROUND);
- draw_line(dr,
- BORDER + i * TILE_SIZE + TILE_SIZE/2 - CROSS_SIZE,
- BORDER + j * TILE_SIZE - CROSS_SIZE,
- BORDER + i * TILE_SIZE + TILE_SIZE/2 + CROSS_SIZE - 1,
- BORDER + j * TILE_SIZE + CROSS_SIZE - 1,
- COL_FOREGROUND);
- break;
- }
- }
- ds->hl[HL_INDEX(state, i, j)] = RIGHTOF_DOT(state, i, j);
- }
+ 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;
+ }
+ }
+
+ /* Work out what the flash state needs to be. */
+ if (flashtime > 0 &&
+ (flashtime <= FLASH_TIME/3 ||
+ flashtime >= FLASH_TIME*2/3)) {
+ flash_changed = !ds->flashing;
+ ds->flashing = TRUE;
+ } else {
+ flash_changed = ds->flashing;
+ ds->flashing = FALSE;
+ }
+
+ /* Now, trundle through the edges. */
+ for (i = 0; i < g->num_edges; i++) {
+ char new_ds =
+ state->line_errors[i] ? DS_LINE_ERROR : state->lines[i];
+ if (new_ds != ds->lines[i] ||
+ (flash_changed && state->lines[i] == LINE_YES)) {
+ ds->lines[i] = new_ds;
+ if (nedges == REDRAW_OBJECTS_LIMIT)
+ redraw_everything = TRUE;
+ else
+ edges[nedges++] = i;
+ }
+ }
+ }
+
+ /* Pass one is now done. Now we do the actual drawing. */
+ if (redraw_everything) {
+
+ /* This is the unsubtle version. */
+
+ int grid_width = g->highest_x - g->lowest_x;
+ int grid_height = g->highest_y - g->lowest_y;
+ int w = grid_width * ds->tilesize / g->tilesize;
+ int h = grid_height * ds->tilesize / g->tilesize;
+
+ draw_rect(dr, 0, 0, w + 2*border + 1, h + 2*border + 1,
+ COL_BACKGROUND);
+
+ for (i = 0; i < g->num_faces; i++)
+ game_redraw_clue(dr, ds, state, i);
+ for (i = 0; i < g->num_edges; i++)
+ game_redraw_line(dr, ds, state, i);
+ for (i = 0; i < g->num_dots; i++)
+ game_redraw_dot(dr, ds, state, i);
+
+ draw_update(dr, 0, 0, w + 2*border + 1, h + 2*border + 1);
+ } else {
+
+ /* Right. Now we roll up our sleeves. */
+
+ for (i = 0; i < nfaces; i++) {
+ grid_face *f = g->faces + faces[i];
+ int xx, yy;
+ int x, y, w, h;
+ int j;
+
+ /* There seems to be a certain amount of trial-and-error
+ * involved in working out the correct bounding-box for
+ * the text. */
+ face_text_pos(ds, g, f, &xx, &yy);
+
+ x = xx - ds->tilesize/4 - 1; w = ds->tilesize/2 + 2;
+ y = yy - ds->tilesize/4 - 3; h = ds->tilesize/2 + 5;
+ clip(dr, x, y, w, h);
+ draw_rect(dr, x, y, w, h, COL_BACKGROUND);
+
+ game_redraw_clue(dr, ds, state, faces[i]);
+ for (j = 0; j < f->order; j++)
+ game_redraw_line(dr, ds, state, f->edges[j] - g->edges);
+ for (j = 0; j < f->order; j++)
+ game_redraw_dot(dr, ds, state, f->dots[j] - g->dots);
+ unclip(dr);
+ draw_update(dr, x, y, w, h);
+ }
+
+ for (i = 0; i < nedges; i++) {
+ grid_edge *e = g->edges + edges[i], *ee;
+ int x1 = e->dot1->x;
+ int y1 = e->dot1->y;
+ int x2 = e->dot2->x;
+ int y2 = e->dot2->y;
+ int xmin, xmax, ymin, ymax;
+ int j;
+
+ grid_to_screen(ds, g, x1, y1, &x1, &y1);
+ grid_to_screen(ds, g, x2, y2, &x2, &y2);
+ /* Allow extra margin for dots, and thickness of lines */
+ xmin = min(x1, x2) - 2;
+ xmax = max(x1, x2) + 2;
+ ymin = min(y1, y2) - 2;
+ ymax = max(y1, y2) + 2;
+ /* For testing, I find it helpful to change COL_BACKGROUND
+ * to COL_SATISFIED here. */
+ clip(dr, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
+ draw_rect(dr, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1,
+ COL_BACKGROUND);
+
+ if (e->face1)
+ game_redraw_clue(dr, ds, state, e->face1 - g->faces);
+ if (e->face2)
+ game_redraw_clue(dr, ds, state, e->face2 - g->faces);
+
+ game_redraw_line(dr, ds, state, edges[i]);
+ for (j = 0; j < e->dot1->order; j++) {
+ ee = e->dot1->edges[j];
+ if (ee != e)
+ game_redraw_line(dr, ds, state, ee - g->edges);
+ }
+ for (j = 0; j < e->dot2->order; j++) {
+ ee = e->dot2->edges[j];
+ if (ee != e)
+ game_redraw_line(dr, ds, state, ee - g->edges);
+ }
+ game_redraw_dot(dr, ds, state, e->dot1 - g->dots);
+ game_redraw_dot(dr, ds, state, e->dot2 - g->dots);
+
+ unclip(dr);
+ draw_update(dr, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
+ }
+ }
+
+ ds->started = TRUE;