2 * draw.c -- drawing routines for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
56 #include <cairo/cairo.h>
57 #include <cairo/cairo-xlib.h>
62 #else /* not STDC_HEADERS */
63 extern char *getenv();
66 # else /* not HAVE_STRING_H */
68 # endif /* not HAVE_STRING_H */
69 #endif /* not STDC_HEADERS */
76 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
80 #include "pixmaps/pixmaps.h"
82 #include "bitmaps/bitmaps.h"
88 #include "xevalgraph.h"
100 #define usleep(t) _sleep2(((t)+500)/1000)
104 # define _(s) gettext (s)
105 # define N_(s) gettext_noop (s)
113 Boolean cairoAnimate;
114 static cairo_surface_t *csBoardWindow, *csBoardBackup, *csDualBoard;
115 static cairo_surface_t *pngPieceBitmaps[2][(int)BlackPawn]; // scaled pieces as used
116 static cairo_surface_t *pngPieceBitmaps2[2][(int)BlackPawn+4]; // scaled pieces in store
117 static cairo_surface_t *pngBoardBitmap[2];
118 int useTexture, textureW[2], textureH[2];
120 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
121 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
123 #define White(piece) ((int)(piece) < (int)BlackPawn)
127 } gridSegments[BOARD_RANKS + BOARD_FILES + 2];
132 cairo_surface_t *cstmp = csBoardWindow;
133 csBoardWindow = csDualBoard;
134 if(!csDualBoard && cstmp) {
135 int boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
136 int boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
137 csBoardWindow = cairo_xlib_surface_create(xDisplay, xBoardWindow, DefaultVisual(xDisplay, 0), boardWidth, boardHeight);
144 // delete surfaces after size becomes invalid, so they will be recreated
145 if(csBoardWindow) cairo_surface_destroy(csBoardWindow);
146 if(csBoardBackup) cairo_surface_destroy(csBoardBackup);
147 if(csDualBoard) cairo_surface_destroy(csDualBoard);
148 csBoardWindow = csBoardBackup = csDualBoard = NULL;
151 #define BoardSize int
153 InitDrawingSizes (BoardSize boardSize, int flags)
154 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
155 int boardWidth, boardHeight;
157 static Dimension oldWidth, oldHeight;
158 static VariantClass oldVariant;
159 static int oldMono = -1, oldTwoBoards = 0;
161 if(!formWidget) return;
163 if(oldTwoBoards && !twoBoards) PopDown(DummyDlg);
164 oldTwoBoards = twoBoards;
166 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
167 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
168 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
170 if(boardWidth != oldWidth || boardHeight != oldHeight) { // do resizing stuff only if size actually changed
172 oldWidth = boardWidth; oldHeight = boardHeight;
177 * Inhibit shell resizing.
179 ResizeBoardWindow(boardWidth, boardHeight, !cairoAnimate);
184 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
187 if(gameInfo.variant != oldVariant) { // and only if variant changed
191 for(p=0; p<=(int)WhiteKing; p++)
192 pngPieceBitmaps[i][p] = pngPieceBitmaps2[i][p]; // defaults
193 if(gameInfo.variant == VariantShogi) {
194 pngPieceBitmaps[i][(int)WhiteCannon] = pngPieceBitmaps2[i][(int)WhiteKing+1];
195 pngPieceBitmaps[i][(int)WhiteNightrider] = pngPieceBitmaps2[i][(int)WhiteKing+2];
196 pngPieceBitmaps[i][(int)WhiteSilver] = pngPieceBitmaps2[i][(int)WhiteKing+3];
197 pngPieceBitmaps[i][(int)WhiteGrasshopper] = pngPieceBitmaps2[i][(int)WhiteKing+4];
198 pngPieceBitmaps[i][(int)WhiteQueen] = pngPieceBitmaps2[i][(int)WhiteLance];
201 if(gameInfo.variant == VariantGothic) {
202 pngPieceBitmaps[i][(int)WhiteMarshall] = pngPieceBitmaps2[i][(int)WhiteSilver];
205 if(gameInfo.variant == VariantSChess) {
206 pngPieceBitmaps[i][(int)WhiteAngel] = pngPieceBitmaps2[i][(int)WhiteFalcon];
207 pngPieceBitmaps[i][(int)WhiteMarshall] = pngPieceBitmaps2[i][(int)WhiteAlfil];
210 oldMono = -10; // kludge to force recreation of animation masks
211 oldVariant = gameInfo.variant;
214 oldMono = appData.monoMode;
218 CreatePNGBoard (char *s, int kind)
220 if(!appData.useBitmaps || s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
221 if(strstr(s, ".png")) {
222 cairo_surface_t *img = cairo_image_surface_create_from_png (s);
224 useTexture |= kind + 1; pngBoardBitmap[kind] = img;
225 textureW[kind] = cairo_image_surface_get_width (img);
226 textureH[kind] = cairo_image_surface_get_height (img);
231 char *pngPieceNames[] = // must be in same order as internal piece encoding
232 { "Pawn", "Knight", "Bishop", "Rook", "Queen", "Advisor", "Elephant", "Archbishop", "Marshall", "Gold", "Commoner",
233 "Canon", "Nightrider", "CrownedBishop", "CrownedRook", "Princess", "Chancellor", "Hawk", "Lance", "Cobra", "Unicorn", "King",
234 "GoldKnight", "GoldLance", "GoldPawn", "GoldSilver", NULL
238 ScaleOnePiece (char *name, int color, int piece)
242 cairo_surface_t *img, *cs;
244 static cairo_surface_t *pngPieceImages[2][(int)BlackPawn+4]; // png 256 x 256 images
246 if((img = pngPieceImages[color][piece]) == NULL) { // if PNG file for this piece was not yet read, read it now and store it
247 snprintf(buf, MSG_SIZ, "%s/%s%s.png", appData.pngDirectory, color ? "Black" : "White", pngPieceNames[piece]);
248 pngPieceImages[color][piece] = img = cairo_image_surface_create_from_png (buf);
249 w = cairo_image_surface_get_width (img);
250 h = cairo_image_surface_get_height (img);
251 if(w != 64 || h != 64) { printf("Bad png size %dx%d in %s\n", w, h, buf); exit(1); }
253 // create new bitmap to hold scaled piece image (and remove any old)
254 if(pngPieceBitmaps2[color][piece]) cairo_surface_destroy (pngPieceBitmaps2[color][piece]);
255 pngPieceBitmaps2[color][piece] = cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, squareSize, squareSize);
256 if(piece <= WhiteKing) pngPieceBitmaps[color][piece] = cs;
257 // scaled copying of the raw png image
258 cr = cairo_create(cs);
259 cairo_scale(cr, squareSize/64., squareSize/64.);
260 cairo_set_source_surface (cr, img, 0, 0);
270 for(p=0; pngPieceNames[p]; p++) {
271 ScaleOnePiece(pngPieceNames[p], 0, p);
272 ScaleOnePiece(pngPieceNames[p], 1, p);
278 { // [HGM] taken out of main
279 if (appData.pngDirectory[0] != NULLCHAR) {
282 CreatePNGBoard(appData.liteBackTextureFile, 1);
283 CreatePNGBoard(appData.darkBackTextureFile, 0);
284 cairoAnimate = *appData.pngDirectory && useTexture == 3
285 && strstr(appData.liteBackTextureFile, ".png") && strstr(appData.darkBackTextureFile, ".png");
296 // [HGM] seekgraph: some low-level drawing routines (by JC, mostly)
299 Color (char *col, int n)
302 sscanf(col, "#%x", &c);
308 SetPen (cairo_t *cr, float w, char *col, int dash)
310 static const double dotted[] = {4.0, 4.0};
311 static int len = sizeof(dotted) / sizeof(dotted[0]);
312 cairo_set_line_width (cr, w);
313 cairo_set_source_rgba (cr, Color(col, 4), Color(col, 2), Color(col, 0), 1.0);
314 if(dash) cairo_set_dash (cr, dotted, len, 0.0);
317 void DrawSeekAxis( int x, int y, int xTo, int yTo )
322 cr = cairo_create (csBoardWindow);
324 cairo_move_to (cr, x, y);
325 cairo_line_to(cr, xTo, yTo );
327 SetPen(cr, 2, "#000000", 0);
334 void DrawSeekBackground( int left, int top, int right, int bottom )
336 cairo_t *cr = cairo_create (csBoardWindow);
338 cairo_rectangle (cr, left, top, right-left, bottom-top);
340 cairo_set_source_rgba(cr, 0.8, 0.8, 0.4,1.0);
347 void DrawSeekText(char *buf, int x, int y)
349 cairo_t *cr = cairo_create (csBoardWindow);
351 cairo_select_font_face (cr, "Sans",
352 CAIRO_FONT_SLANT_NORMAL,
353 CAIRO_FONT_WEIGHT_NORMAL);
355 cairo_set_font_size (cr, 12.0);
357 cairo_move_to (cr, x, y+4);
358 cairo_set_source_rgba(cr, 0, 0, 0,1.0);
359 cairo_show_text( cr, buf);
365 void DrawSeekDot(int x, int y, int colorNr)
367 cairo_t *cr = cairo_create (csBoardWindow);
368 int square = colorNr & 0x80;
372 cairo_rectangle (cr, x-squareSize/9, y-squareSize/9, 2*(squareSize/9), 2*(squareSize/9));
374 cairo_arc(cr, x, y, squareSize/9, 0.0, 2*M_PI);
376 SetPen(cr, 2, "#000000", 0);
377 cairo_stroke_preserve(cr);
379 case 0: cairo_set_source_rgba(cr, 1.0, 0, 0,1.0); break;
380 case 1: cairo_set_source_rgba (cr, 0.0, 0.7, 0.2, 1.0); break;
381 default: cairo_set_source_rgba (cr, 1.0, 1.0, 0.0, 1.0); break;
392 int boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
393 int boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
395 csBoardWindow = cairo_xlib_surface_create(xDisplay, xBoardWindow, DefaultVisual(xDisplay, 0), boardWidth, boardHeight);
396 csBoardBackup = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, boardWidth, boardHeight);
410 if (lineGap == 0) return;
412 /* [HR] Split this into 2 loops for non-square boards. */
414 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
415 gridSegments[i].x1 = 0;
417 lineGap + BOARD_WIDTH * (squareSize + lineGap);
418 gridSegments[i].y1 = gridSegments[i].y2
419 = lineGap / 2 + (i * (squareSize + lineGap));
422 for (j = 0; j < BOARD_WIDTH + 1; j++) {
423 gridSegments[j + i].y1 = 0;
424 gridSegments[j + i].y2 =
425 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
426 gridSegments[j + i].x1 = gridSegments[j + i].x2
427 = lineGap / 2 + (j * (squareSize + lineGap));
432 DoDrawGrid(cairo_surface_t *cs)
434 /* draws a grid starting around Nx, Ny squares starting at x,y */
440 cr = cairo_create (cs);
442 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
443 SetPen(cr, lineGap, "#000000", 0);
446 for (i = 0; i < BOARD_WIDTH + BOARD_HEIGHT + 2; i++)
448 cairo_move_to (cr, gridSegments[i].x1, gridSegments[i].y1);
449 cairo_line_to (cr, gridSegments[i].x2, gridSegments[i].y2);
462 DoDrawGrid(csBoardWindow);
463 DoDrawGrid(csBoardBackup);
467 DoDrawBorder (cairo_surface_t *cs, int x, int y, int type)
474 case 0: col = "#000000"; break;
475 case 1: col = appData.highlightSquareColor; break;
476 case 2: col = appData.premoveHighlightColor; break;
478 cr = cairo_create(cs);
479 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
480 cairo_rectangle(cr, x, y, squareSize+lineGap, squareSize+lineGap);
481 SetPen(cr, lineGap, col, 0);
486 DrawBorder (int x, int y, int type)
488 DoDrawBorder(csBoardWindow, x, y, type);
489 DoDrawBorder(csBoardBackup, x, y, type);
493 CutOutSquare (int x, int y, int *x0, int *y0, int kind)
495 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
496 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
498 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
499 if(textureW[kind] < W*squareSize)
500 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
502 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
503 if(textureH[kind] < H*squareSize)
504 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
506 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
511 DrawLogo (void *handle, void *logo)
513 cairo_surface_t *img, *cs;
517 if(!logo || !handle) return;
518 cs = cairo_xlib_surface_create(xDisplay, XtWindow(handle), DefaultVisual(xDisplay, 0), appData.logoSize, appData.logoSize/2);
519 img = cairo_image_surface_create_from_png (logo);
520 w = cairo_image_surface_get_width (img);
521 h = cairo_image_surface_get_height (img);
522 cr = cairo_create(cs);
523 cairo_scale(cr, (float)appData.logoSize/w, appData.logoSize/(2.*h));
524 cairo_set_source_surface (cr, img, 0, 0);
527 cairo_surface_destroy (img);
528 cairo_surface_destroy (cs);
532 BlankSquare (cairo_surface_t *dest, int x, int y, int color, ChessSquare piece, int fac)
533 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
537 cr = cairo_create (dest);
539 if ((useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
540 cairo_set_source_surface (cr, pngBoardBitmap[color], x*fac - x0, y*fac - y0);
541 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
542 cairo_rectangle (cr, x*fac, y*fac, squareSize, squareSize);
545 } else { // evenly colored squares
548 case 0: col = appData.darkSquareColor; break;
549 case 1: col = appData.lightSquareColor; break;
550 case 2: col = "#000000"; break;
552 SetPen(cr, 2.0, col, 0);
553 cairo_rectangle (cr, x, y, squareSize, squareSize);
560 pngDrawPiece (cairo_surface_t *dest, ChessSquare piece, int square_color, int x, int y)
565 if ((int)piece < (int) BlackPawn) {
571 if(appData.upsideDown && flipView) { p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
572 BlankSquare(dest, x, y, square_color, piece, 1); // erase previous contents with background
573 cr = cairo_create (dest);
574 cairo_set_source_surface (cr, pngPieceBitmaps[kind][piece], x, y);
580 DoDrawDot (cairo_surface_t *cs, int marker, int x, int y, int r)
584 cr = cairo_create(cs);
585 cairo_arc(cr, x+r/2, y+r/2, r/2, 0.0, 2*M_PI);
586 if(appData.monoMode) {
587 SetPen(cr, 2, marker == 2 ? "#000000" : "#FFFFFF", 0);
588 cairo_stroke_preserve(cr);
589 SetPen(cr, 2, marker == 2 ? "#FFFFFF" : "#000000", 0);
591 SetPen(cr, 2, marker == 2 ? "#FF0000" : "#FFFF00", 0);
599 DrawDot (int marker, int x, int y, int r)
600 { // used for atomic captures; no need to draw on backup
602 DoDrawDot(csBoardWindow, marker, x, y, r);
606 DoDrawOneSquare (cairo_surface_t *dest, int x, int y, ChessSquare piece, int square_color, int marker, char *string, int align)
607 { // basic front-end board-draw function: takes care of everything that can be in square:
608 // piece, background, coordinate/count, marker dot
609 int direction, font_ascent, font_descent;
613 if (piece == EmptySquare) {
614 BlankSquare(dest, x, y, square_color, piece, 1);
616 pngDrawPiece(dest, piece, square_color, x, y);
619 if(align) { // square carries inscription (coord or piece count)
621 // first calculate where it goes
622 XTextExtents(countFontStruct, string, 1, &direction,
623 &font_ascent, &font_descent, &overall);
625 xx += squareSize - overall.width - 2;
626 yy += squareSize - font_descent - 1;
627 } else if (align == 2) {
628 xx += 2, yy += font_ascent + 1;
629 } else if (align == 3) {
630 xx += squareSize - overall.width - 2;
631 yy += font_ascent + 1;
632 } else if (align == 4) {
633 xx += 2, yy += font_ascent + 1;
635 cr = cairo_create (dest);
636 cairo_select_font_face (cr, "Sans",
637 CAIRO_FONT_SLANT_NORMAL,
638 CAIRO_FONT_WEIGHT_BOLD);
640 cairo_set_font_size (cr, squareSize/4);
642 cairo_move_to (cr, xx-1, yy);
643 if(align < 3) cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
644 else cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
645 cairo_show_text (cr, string);
649 if(marker) { // print fat marker dot, if requested
650 DoDrawDot(dest, marker, x + squareSize/4, y+squareSize/4, squareSize/2);
655 DrawOneSquare (int x, int y, ChessSquare piece, int square_color, int marker, char *string, int align)
658 DoDrawOneSquare (csBoardWindow, x, y, piece, square_color, marker, string, align);
659 DoDrawOneSquare (csBoardBackup, x, y, piece, square_color, marker, string, align);
662 /**** Animation code by Hugh Fisher, DCS, ANU. ****/
664 /* Masks for XPM pieces. Black and white pieces can have
665 different shapes, but in the interest of retaining my
666 sanity pieces must have the same outline on both light
667 and dark squares, and all pieces must use the same
668 background square colors/images. */
670 static cairo_surface_t *c_animBufs[3*NrOfAnims]; // newBuf, saveBuf
673 InitAnimState (AnimNr anr)
675 DrawSeekOpen(); // set cs to board widget
676 if(c_animBufs[anr]) cairo_surface_destroy (c_animBufs[anr]);
677 if(c_animBufs[anr+2]) cairo_surface_destroy (c_animBufs[anr+2]);
678 c_animBufs[anr+4] = csBoardWindow;
679 c_animBufs[anr+2] = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, squareSize, squareSize);
680 c_animBufs[anr] = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, squareSize, squareSize);
687 InitAnimState(Player);
691 CairoOverlayPiece (ChessSquare piece, cairo_surface_t *dest)
693 static cairo_t *pieceSource;
694 pieceSource = cairo_create (dest);
695 cairo_set_source_surface (pieceSource, pngPieceBitmaps[!White(piece)][piece % BlackPawn], 0, 0);
696 if(doubleClick) cairo_paint_with_alpha (pieceSource, 0.6);
697 else cairo_paint(pieceSource);
698 cairo_destroy (pieceSource);
702 InsertPiece (AnimNr anr, ChessSquare piece)
704 CairoOverlayPiece(piece, c_animBufs[anr]);
708 DrawBlank (AnimNr anr, int x, int y, int startColor)
710 BlankSquare(c_animBufs[anr+2], x, y, startColor, EmptySquare, 0);
713 void CopyRectangle (AnimNr anr, int srcBuf, int destBuf,
714 int srcX, int srcY, int width, int height, int destX, int destY)
716 cairo_t *cr;// = cairo_create (c_animBufs[anr+destBuf]);
717 cr = cairo_create (c_animBufs[anr+destBuf]);
718 if(c_animBufs[anr+srcBuf] == csBoardWindow)
719 cairo_set_source_surface (cr, csBoardBackup, destX - srcX, destY - srcY);
721 cairo_set_source_surface (cr, c_animBufs[anr+srcBuf], destX - srcX, destY - srcY);
722 cairo_rectangle (cr, destX, destY, width, height);
725 if(c_animBufs[anr+destBuf] == csBoardWindow) {
726 cr = cairo_create (csBoardBackup); // also draw to backup
727 cairo_set_source_surface (cr, c_animBufs[anr+srcBuf], destX - srcX, destY - srcY);
728 cairo_rectangle (cr, destX, destY, width, height);
735 SetDragPiece (AnimNr anr, ChessSquare piece)
739 /* [AS] Arrow highlighting support */
742 DoDrawPolygon (cairo_surface_t *cs, Pnt arrow[], int nr)
746 cr = cairo_create (cs);
747 cairo_move_to (cr, arrow[nr-1].x, arrow[nr-1].y);
749 cairo_line_to(cr, arrow[i].x, arrow[i].y);
751 if(appData.monoMode) { // should we always outline arrow?
752 cairo_line_to(cr, arrow[0].x, arrow[0].y);
753 SetPen(cr, 2, "#000000", 0);
754 cairo_stroke_preserve(cr);
756 SetPen(cr, 2, appData.highlightSquareColor, 0);
764 DrawPolygon (Pnt arrow[], int nr)
766 DoDrawPolygon(csBoardWindow, arrow, nr);
767 DoDrawPolygon(csBoardBackup, arrow, nr);