Stop the analysis pass in Loopy's redraw routine from being
[sgt/puzzles] / devel.but
index c5a2c43..970a73a 100644 (file)
--- a/devel.but
+++ b/devel.but
@@ -856,7 +856,7 @@ producing new \c{game_state}s.
 \S{backend-interpret-move} \cw{interpret_move()}
 
 \c char *(*interpret_move)(game_state *state, game_ui *ui,
 \S{backend-interpret-move} \cw{interpret_move()}
 
 \c char *(*interpret_move)(game_state *state, game_ui *ui,
-\c                         game_drawstate *ds,
+\c                         const game_drawstate *ds,
 \c                         int x, int y, int button);
 
 This function receives user input and processes it. Its input
 \c                         int x, int y, int button);
 
 This function receives user input and processes it. Its input
@@ -868,6 +868,11 @@ indicating an arrow or function key or a mouse event; when
 coordinates of the mouse pointer relative to the top left of the
 puzzle's drawing area.
 
 coordinates of the mouse pointer relative to the top left of the
 puzzle's drawing area.
 
+(The pointer to the \c{game_drawstate} is marked \c{const}, because
+\c{interpret_move} should not write to it. The normal use of that
+pointer will be to read the game's tile size parameter in order to
+divide mouse coordinates by it.)
+
 \cw{interpret_move()} may return in three different ways:
 
 \b Returning \cw{NULL} indicates that no action whatsoever occurred
 \cw{interpret_move()} may return in three different ways:
 
 \b Returning \cw{NULL} indicates that no action whatsoever occurred
@@ -1224,6 +1229,34 @@ a mine from the colour it uses when you complete the game. In order
 to achieve this, its \cw{flash_length()} function has to store a
 flag in the \c{game_ui} to indicate which flash type is required.)
 
 to achieve this, its \cw{flash_length()} function has to store a
 flag in the \c{game_ui} to indicate which flash type is required.)
 
+\S{backend-status} \cw{status()}
+
+\c int (*status)(game_state *state);
+
+This function returns a status value indicating whether the current
+game is still in play, or has been won, or has been conclusively lost.
+The mid-end uses this to implement \cw{midend_status()}
+(\k{midend-status}).
+
+The return value should be +1 if the game has been successfully
+solved. If the game has been lost in a situation where further play is
+unlikely, the return value should be -1. If neither is true (so play
+is still ongoing), return zero.
+
+Front ends may wish to use a non-zero status as a cue to proactively
+offer the option of starting a new game. Therefore, back ends should
+not return -1 if the game has been \e{technically} lost but undoing
+and continuing is still a realistic possibility.
+
+(For instance, games with hidden information such as Guess or Mines
+might well return a non-zero status whenever they reveal the solution,
+whether or not the player guessed it correctly, on the grounds that a
+player would be unlikely to hide the solution and continue playing
+after the answer was spoiled. On the other hand, games where you can
+merely get into a dead end such as Same Game or Inertia might choose
+to return 0 in that situation, on the grounds that the player would
+quite likely press Undo and carry on playing.)
+
 \S{backend-redraw} \cw{redraw()}
 
 \c void (*redraw)(drawing *dr, game_drawstate *ds,
 \S{backend-redraw} \cw{redraw()}
 
 \c void (*redraw)(drawing *dr, game_drawstate *ds,
@@ -1433,7 +1466,7 @@ them internally. (There are currently no puzzles which have a
 one-line ASCII representation, so there's no precedent yet for
 whether that should come with a newline or not.)
 
 one-line ASCII representation, so there's no precedent yet for
 whether that should come with a newline or not.)
 
-\S{backend-wants-statusbar} \cw{wants_statusbar()}
+\S{backend-wants-statusbar} \cw{wants_statusbar}
 
 \c int wants_statusbar;
 
 
 \c int wants_statusbar;
 
@@ -1641,6 +1674,43 @@ end does any drawing it informs the front end of which parts of the
 window it has accessed, and hence which parts need repainting. This
 is done by calling \cw{draw_update()} (\k{drawing-draw-update}).
 
 window it has accessed, and hence which parts need repainting. This
 is done by calling \cw{draw_update()} (\k{drawing-draw-update}).
 
+Persistence of old drawing is convenient. However, a puzzle should
+be very careful about how it updates its drawing area. The problem
+is that some front ends do anti-aliased drawing: rather than simply
+choosing between leaving each pixel untouched or painting it a
+specified colour, an antialiased drawing function will \e{blend} the
+original and new colours in pixels at a figure's boundary according
+to the proportion of the pixel occupied by the figure (probably
+modified by some heuristic fudge factors). All of this produces a
+smoother appearance for curves and diagonal lines.
+
+An unfortunate effect of drawing an anti-aliased figure repeatedly
+is that the pixels around the figure's boundary come steadily more
+saturated with \q{ink} and the boundary appears to \q{spread out}.
+Worse, redrawing a figure in a different colour won't fully paint
+over the old boundary pixels, so the end result is a rather ugly
+smudge.
+
+A good strategy to avoid unpleasant anti-aliasing artifacts is to
+identify a number of rectangular areas which need to be redrawn,
+clear them to the background colour, and then redraw their contents
+from scratch, being careful all the while not to stray beyond the
+boundaries of the original rectangles. The \cw{clip()} function
+(\k{drawing-clip}) comes in very handy here. Games based on a square
+grid can often do this fairly easily. Other games may need to be
+somewhat more careful. For example, Loopy's redraw function first
+identifies portions of the display which need to be updated. Then,
+if the changes are fairly well localised, it clears and redraws a
+rectangle containing each changed area. Otherwise, it gives up and
+redraws the entire grid from scratch.
+
+It is possible to avoid clearing to background and redrawing from
+scratch if one is very careful about which drawing functions one
+uses: if a function is documented as not anti-aliasing under some
+circumstances, you can rely on each pixel in a drawing either being
+left entirely alone or being set to the requested colour, with no
+blending being performed.
+
 In the following sections I first discuss the drawing API as seen by
 the back end, and then the \e{almost} identical function-pointer
 form seen by the front end.
 In the following sections I first discuss the drawing API as seen by
 the back end, and then the \e{almost} identical function-pointer
 form seen by the front end.
@@ -1715,8 +1785,9 @@ the back end function \cw{colours()} (\k{backend-colours}).
 
 Some platforms may perform anti-aliasing on this function.
 Therefore, do not assume that you can erase a line by drawing the
 
 Some platforms may perform anti-aliasing on this function.
 Therefore, do not assume that you can erase a line by drawing the
-same line over it in the background colour; anti-aliasing might
-lead to perceptible ghost artefacts around the vanished line.
+same line over it in the background colour; anti-aliasing might lead
+to perceptible ghost artefacts around the vanished line. Horizontal
+and vertical lines, however, are pixel-perfect and not anti-aliased.
 
 This function may be used for both drawing and printing.
 
 
 This function may be used for both drawing and printing.
 
@@ -1753,7 +1824,8 @@ same polygon over it in the background colour. Also, be prepared for
 the polygon to extend a pixel beyond its obvious bounding box as a
 result of this; if you really need it not to do this to avoid
 interfering with other delicate graphics, you should probably use
 the polygon to extend a pixel beyond its obvious bounding box as a
 result of this; if you really need it not to do this to avoid
 interfering with other delicate graphics, you should probably use
-\cw{clip()} (\k{drawing-clip}).
+\cw{clip()} (\k{drawing-clip}). You can rely on horizontal and
+vertical lines not being anti-aliased.
 
 This function may be used for both drawing and printing.
 
 
 This function may be used for both drawing and printing.
 
@@ -1795,6 +1867,32 @@ interfering with other delicate graphics, you should probably use
 
 This function may be used for both drawing and printing.
 
 
 This function may be used for both drawing and printing.
 
+\S{drawing-draw-thick-line} \cw{draw_thick_line()}
+
+\c void draw_thick_line(drawing *dr, float thickness,
+\c                      float x1, float y1, float x2, float y2,
+\c                      int colour)
+
+Draws a line in the puzzle window, giving control over the line's
+thickness.
+
+\c{x1} and \c{y1} give the coordinates of one end of the line.
+\c{x2} and \c{y2} give the coordinates of the other end.
+\c{thickness} gives the thickness of the line, in pixels.
+
+Note that the coordinates and thickness are floating-point: the
+continuous coordinate system is in effect here. It's important to
+be able to address points with better-than-pixel precision in this
+case, because one can't otherwise properly express the endpoints of
+lines with both odd and even thicknesses.
+
+Some platforms may perform anti-aliasing on this function. The
+precise pixels affected by a thick-line drawing operation may vary
+between platforms, and no particular guarantees are provided.
+Indeed, even horizontal or vertical lines may be anti-aliased.
+
+This function may be used for both drawing and printing.
+
 \S{drawing-draw-text} \cw{draw_text()}
 
 \c void draw_text(drawing *dr, int x, int y, int fonttype,
 \S{drawing-draw-text} \cw{draw_text()}
 
 \c void draw_text(drawing *dr, int x, int y, int fonttype,
@@ -1911,7 +2009,9 @@ inclusive. (These are exactly the same semantics as
 
 After this call, no drawing operation will affect anything outside
 the specified rectangle. The effect can be reversed by calling
 
 After this call, no drawing operation will affect anything outside
 the specified rectangle. The effect can be reversed by calling
-\cw{unclip()} (\k{drawing-unclip}).
+\cw{unclip()} (\k{drawing-unclip}). The clipping rectangle is
+pixel-perfect: pixels within the rectangle are affected as usual by
+drawing functions; pixels outside are completely untouched.
 
 Back ends should not assume that a clipping rectangle will be
 automatically cleared up by the front end if it's left lying around;
 
 Back ends should not assume that a clipping rectangle will be
 automatically cleared up by the front end if it's left lying around;
@@ -2265,6 +2365,20 @@ function; see \k{drawing-draw-polygon}.
 This function behaves exactly like the back end \cw{draw_circle()}
 function; see \k{drawing-draw-circle}.
 
 This function behaves exactly like the back end \cw{draw_circle()}
 function; see \k{drawing-draw-circle}.
 
+\S{drawingapi-draw-thick-line} \cw{draw_thick_line()}
+
+\c void draw_thick_line(drawing *dr, float thickness,
+\c                      float x1, float y1, float x2, float y2,
+\c                      int colour)
+
+This function behaves exactly like the back end
+\cw{draw_thick_line()} function; see \k{drawing-draw-thick-line}.
+
+An implementation of this API which doesn't provide high-quality
+rendering of thick lines is permitted to define this function
+pointer to be \cw{NULL}. The middleware in \cw{drawing.c} will notice
+and provide a low-quality alternative using \cw{draw_polygon()}.
+
 \S{drawingapi-draw-update} \cw{draw_update()}
 
 \c void (*draw_update)(void *handle, int x, int y, int w, int h);
 \S{drawingapi-draw-update} \cw{draw_update()}
 
 \c void (*draw_update)(void *handle, int x, int y, int w, int h);
@@ -2605,14 +2719,12 @@ without closing the window...)
 
 Frees a mid-end structure and all its associated data.
 
 
 Frees a mid-end structure and all its associated data.
 
-\H{midend-tilesize} 
+\H{midend-tilesize} \cw{midend_tilesize()}
 
 \c int midend_tilesize(midend *me);
 
 Returns the \cq{tilesize} parameter being used to display the
 
 \c int midend_tilesize(midend *me);
 
 Returns the \cq{tilesize} parameter being used to display the
-current puzzle.
-
-\k{backend-preferred-tilesize}
+current puzzle (\k{backend-preferred-tilesize}).
 
 \H{midend-set-params} \cw{midend_set_params()}
 
 
 \H{midend-set-params} \cw{midend_set_params()}
 
@@ -2697,6 +2809,9 @@ to use scroll bars for large puzzles), you can pass dimensions of
 \cw{INT_MAX} as input to this function. You should probably not do
 that \e{and} set the \c{user_size} flag, though!
 
 \cw{INT_MAX} as input to this function. You should probably not do
 that \e{and} set the \c{user_size} flag, though!
 
+The midend relies on the frontend calling \cw{midend_new_game()}
+(\k{midend-new-game}) before calling \cw{midend_size()}.
+
 \H{midend-new-game} \cw{midend_new_game()}
 
 \c void midend_new_game(midend *me);
 \H{midend-new-game} \cw{midend_new_game()}
 
 \c void midend_new_game(midend *me);
@@ -2733,7 +2848,8 @@ undo list (so that an accidental restart can be undone).
 
 This function automatically causes a redraw, i.e. the front end can
 expect its drawing API to be called from \e{within} a call to this
 
 This function automatically causes a redraw, i.e. the front end can
 expect its drawing API to be called from \e{within} a call to this
-function.
+function. Some back ends require that \cw{midend_size()}
+(\k{midend-size}) is called before \cw{midend_restart_game()}.
 
 \H{midend-force-redraw} \cw{midend_force_redraw()}
 
 
 \H{midend-force-redraw} \cw{midend_force_redraw()}
 
@@ -2744,7 +2860,8 @@ discarding the current \c{game_drawstate} and creating a new one
 from scratch before calling the game's \cw{redraw()} function.
 
 The front end can expect its drawing API to be called from within a
 from scratch before calling the game's \cw{redraw()} function.
 
 The front end can expect its drawing API to be called from within a
-call to this function.
+call to this function. Some back ends require that \cw{midend_size()}
+(\k{midend-size}) is called before \cw{midend_force_redraw()}.
 
 \H{midend-redraw} \cw{midend_redraw()}
 
 
 \H{midend-redraw} \cw{midend_redraw()}
 
@@ -2755,7 +2872,8 @@ calling the game's \cw{redraw()} function. (That is, the only things
 redrawn will be things that have changed since the last redraw.)
 
 The front end can expect its drawing API to be called from within a
 redrawn will be things that have changed since the last redraw.)
 
 The front end can expect its drawing API to be called from within a
-call to this function.
+call to this function. Some back ends require that \cw{midend_size()}
+(\k{midend-size}) is called before \cw{midend_redraw()}.
 
 \H{midend-process-key} \cw{midend_process_key()}
 
 
 \H{midend-process-key} \cw{midend_process_key()}
 
@@ -3013,7 +3131,40 @@ user.
 
 The front end can expect its drawing API and/or
 \cw{activate_timer()} to be called from within a call to this
 
 The front end can expect its drawing API and/or
 \cw{activate_timer()} to be called from within a call to this
-function.
+function.  Some back ends require that \cw{midend_size()}
+(\k{midend-size}) is called before \cw{midend_solve()}.
+
+\H{midend-status} \cw{midend_status()}
+
+\c int midend_status(midend *me);
+
+This function returns +1 if the midend is currently displaying a game
+in a solved state, -1 if the game is in a permanently lost state, or 0
+otherwise. This function just calls the back end's \cw{status()}
+function. Front ends may wish to use this as a cue to proactively
+offer the option of starting a new game.
+
+(See \k{backend-status} for more detail about the back end's
+\cw{status()} function and discussion of what should count as which
+status code.)
+
+\H{midend-can-undo} \cw{midend_can_undo()}
+
+\c int midend_can_undo(midend *me);
+
+Returns \cw{TRUE} if the midend is currently in a state where the undo
+operation is meaningful (i.e. at least one position exists on the undo
+chain before the present one). Front ends may wish to use this to
+visually activate and deactivate an undo button.
+
+\H{midend-can-redo} \cw{midend_can_redo()}
+
+\c int midend_can_redo(midend *me);
+
+Returns \cw{TRUE} if the midend is currently in a state where the redo
+operation is meaningful (i.e. at least one position exists on the redo
+chain after the present one). Front ends may wish to use this to
+visually activate and deactivate a redo button.
 
 \H{midend-serialise} \cw{midend_serialise()}
 
 
 \H{midend-serialise} \cw{midend_serialise()}