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"
87 #include "xevalgraph.h"
99 #define usleep(t) _sleep2(((t)+500)/1000)
103 # define _(s) gettext (s)
104 # define N_(s) gettext_noop (s)
112 Boolean cairoAnimate;
113 static cairo_surface_t *csBoardWindow, *csBoardBackup, *csDualBoard;
114 static cairo_surface_t *pngPieceBitmaps[2][(int)BlackPawn]; // scaled pieces as used
115 static cairo_surface_t *pngPieceBitmaps2[2][(int)BlackPawn+4]; // scaled pieces in store
116 static cairo_surface_t *pngBoardBitmap[2];
117 int useTexture, textureW[2], textureH[2];
119 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
120 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
122 #define White(piece) ((int)(piece) < (int)BlackPawn)
126 } gridSegments[BOARD_RANKS + BOARD_FILES + 2];
133 cairo_surface_t *cstmp = csBoardWindow;
134 csBoardWindow = csDualBoard;
137 csBoardWindow = GetOutputSurface(&dualOptions[3], 0, 0);
146 // delete surfaces after size becomes invalid, so they will be recreated
147 if(csBoardWindow) cairo_surface_destroy(csBoardWindow);
148 if(csBoardBackup) cairo_surface_destroy(csBoardBackup);
149 if(csDualBoard) cairo_surface_destroy(csDualBoard);
150 csBoardWindow = csBoardBackup = csDualBoard = NULL;
153 #define BoardSize int
155 InitDrawingSizes (BoardSize boardSize, int flags)
156 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
157 int boardWidth, boardHeight;
159 static int oldWidth, oldHeight;
160 static VariantClass oldVariant;
161 static int oldMono = -1, oldTwoBoards = 0;
162 extern Widget formWidget;
164 if(!formWidget) return;
166 if(oldTwoBoards && !twoBoards) PopDown(DummyDlg);
167 oldTwoBoards = twoBoards;
169 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
170 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
171 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
173 if(boardWidth != oldWidth || boardHeight != oldHeight) { // do resizing stuff only if size actually changed
175 oldWidth = boardWidth; oldHeight = boardHeight;
180 * Inhibit shell resizing.
182 ResizeBoardWindow(boardWidth, boardHeight, 0);
187 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
190 if(gameInfo.variant != oldVariant) { // and only if variant changed
194 for(p=0; p<=(int)WhiteKing; p++)
195 pngPieceBitmaps[i][p] = pngPieceBitmaps2[i][p]; // defaults
196 if(gameInfo.variant == VariantShogi) {
197 pngPieceBitmaps[i][(int)WhiteCannon] = pngPieceBitmaps2[i][(int)WhiteKing+1];
198 pngPieceBitmaps[i][(int)WhiteNightrider] = pngPieceBitmaps2[i][(int)WhiteKing+2];
199 pngPieceBitmaps[i][(int)WhiteSilver] = pngPieceBitmaps2[i][(int)WhiteKing+3];
200 pngPieceBitmaps[i][(int)WhiteGrasshopper] = pngPieceBitmaps2[i][(int)WhiteKing+4];
201 pngPieceBitmaps[i][(int)WhiteQueen] = pngPieceBitmaps2[i][(int)WhiteLance];
204 if(gameInfo.variant == VariantGothic) {
205 pngPieceBitmaps[i][(int)WhiteMarshall] = pngPieceBitmaps2[i][(int)WhiteSilver];
208 if(gameInfo.variant == VariantSChess) {
209 pngPieceBitmaps[i][(int)WhiteAngel] = pngPieceBitmaps2[i][(int)WhiteFalcon];
210 pngPieceBitmaps[i][(int)WhiteMarshall] = pngPieceBitmaps2[i][(int)WhiteAlfil];
213 oldMono = -10; // kludge to force recreation of animation masks
214 oldVariant = gameInfo.variant;
217 oldMono = appData.monoMode;
221 CreatePNGBoard (char *s, int kind)
223 if(!appData.useBitmaps || s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
224 if(strstr(s, ".png")) {
225 cairo_surface_t *img = cairo_image_surface_create_from_png (s);
227 useTexture |= kind + 1; pngBoardBitmap[kind] = img;
228 textureW[kind] = cairo_image_surface_get_width (img);
229 textureH[kind] = cairo_image_surface_get_height (img);
234 char *pngPieceNames[] = // must be in same order as internal piece encoding
235 { "Pawn", "Knight", "Bishop", "Rook", "Queen", "Advisor", "Elephant", "Archbishop", "Marshall", "Gold", "Commoner",
236 "Canon", "Nightrider", "CrownedBishop", "CrownedRook", "Princess", "Chancellor", "Hawk", "Lance", "Cobra", "Unicorn", "King",
237 "GoldKnight", "GoldLance", "GoldPawn", "GoldSilver", NULL
241 ConvertPixmap (int color, int piece)
243 int i, j, stride, f, colcode[10], w, b;
245 cairo_surface_t *res;
246 XpmPieces *p = builtInXpms + 10;
247 char **pixels = p->xpm[piece % BlackPawn][2*color];
249 sscanf(pixels[0], "%*d %*d %d", &f);
250 sscanf(appData.whitePieceColor+1, "%x", &w);
251 sscanf(appData.blackPieceColor+1, "%x", &b);
252 res = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, p->size, p->size);
253 stride = cairo_image_surface_get_stride(res);
254 buf = (int *) cairo_image_surface_get_data(res);
256 ch[i] = pixels[i+1][0];
258 if(strstr(pixels[i+1], "black")) colcode[i] = 0xFF000000; // 0xFF000000 + (color ? b : 0);
259 if(strstr(pixels[i+1], "white")) colcode[i] = 0xFFFFFFCC; // 0xFF000000 + w;
261 for(i=0; i<p->size; i++) {
262 for(j=0; j<p->size; j++) {
263 char c = pixels[i+f+1][j];
265 for(k=0; ch[k] != c && k < f; k++);
266 buf[i*p->size + j] = colcode[k];
269 cairo_surface_mark_dirty(res);
274 ScaleOnePiece (char *name, int color, int piece)
278 cairo_surface_t *img, *cs;
280 static cairo_surface_t *pngPieceImages[2][(int)BlackPawn+4]; // png 256 x 256 images
282 if((img = pngPieceImages[color][piece]) == NULL) { // if PNG file for this piece was not yet read, read it now and store it
283 if(!*appData.pngDirectory) img = ConvertPixmap(color, piece); else {
284 snprintf(buf, MSG_SIZ, "%s/%s%s.png", appData.pngDirectory, color ? "Black" : "White", pngPieceNames[piece]);
285 img = cairo_image_surface_create_from_png (buf);
286 if(cairo_surface_status(img) != CAIRO_STATUS_SUCCESS) img = ConvertPixmap(color, piece);
289 pngPieceImages[color][piece] = img;
290 // create new bitmap to hold scaled piece image (and remove any old)
291 if(pngPieceBitmaps2[color][piece]) cairo_surface_destroy (pngPieceBitmaps2[color][piece]);
292 pngPieceBitmaps2[color][piece] = cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, squareSize, squareSize);
293 if(piece <= WhiteKing) pngPieceBitmaps[color][piece] = cs;
294 // scaled copying of the raw png image
295 cr = cairo_create(cs);
296 w = cairo_image_surface_get_width (img);
297 h = cairo_image_surface_get_height (img);
298 cairo_scale(cr, squareSize/w, squareSize/h);
299 cairo_set_source_surface (cr, img, 0, 0);
302 { // operate on bitmap to color it (king-size hack...)
303 int stride = cairo_image_surface_get_stride(cs)/4;
304 int *buf = (int *) cairo_image_surface_get_data(cs);
306 sscanf(color ? appData.blackPieceColor+1 : appData.whitePieceColor+1, "%x", &p); // replacement color
307 cairo_surface_flush(cs);
308 for(i=0; i<squareSize; i++) for(j=0; j<squareSize; j++) {
311 unsigned int c = buf[i*stride + j];
312 a = c >> 24; r = c >> 16 & 255; // alpha and red, where red is the 'white' weight, since white is #FFFFCC in the source images
313 f = (color ? a - r : r)/255.; // fraction of black or white in the mix that has to be replaced
314 buf[i*stride + j] = c & 0xFF000000; // alpha channel is kept at same opacity
315 buf[i*stride + j] += ((int)(f*(p&0xFF0000)) & 0xFF0000) + ((int)(f*(p&0xFF00)) & 0xFF00) + (int)(f*(p&0xFF)); // add desired fraction of new color
316 if(color) buf[i*stride + j] += r | r << 8 | r << 16; // details on black pieces get their weight added in pure white
318 cairo_surface_mark_dirty(cs);
327 for(p=0; pngPieceNames[p]; p++) {
328 ScaleOnePiece(pngPieceNames[p], 0, p);
329 ScaleOnePiece(pngPieceNames[p], 1, p);
335 { // [HGM] taken out of main
337 CreatePNGBoard(appData.liteBackTextureFile, 1);
338 CreatePNGBoard(appData.darkBackTextureFile, 0);
348 // [HGM] seekgraph: some low-level drawing routines (by JC, mostly)
351 Color (char *col, int n)
354 sscanf(col, "#%x", &c);
360 SetPen (cairo_t *cr, float w, char *col, int dash)
362 static const double dotted[] = {4.0, 4.0};
363 static int len = sizeof(dotted) / sizeof(dotted[0]);
364 cairo_set_line_width (cr, w);
365 cairo_set_source_rgba (cr, Color(col, 4), Color(col, 2), Color(col, 0), 1.0);
366 if(dash) cairo_set_dash (cr, dotted, len, 0.0);
369 void DrawSeekAxis( int x, int y, int xTo, int yTo )
374 cr = cairo_create (csBoardWindow);
376 cairo_move_to (cr, x, y);
377 cairo_line_to(cr, xTo, yTo );
379 SetPen(cr, 2, "#000000", 0);
386 void DrawSeekBackground( int left, int top, int right, int bottom )
388 cairo_t *cr = cairo_create (csBoardWindow);
390 cairo_rectangle (cr, left, top, right-left, bottom-top);
392 cairo_set_source_rgba(cr, 0.8, 0.8, 0.4,1.0);
399 void DrawSeekText(char *buf, int x, int y)
401 cairo_t *cr = cairo_create (csBoardWindow);
403 cairo_select_font_face (cr, "Sans",
404 CAIRO_FONT_SLANT_NORMAL,
405 CAIRO_FONT_WEIGHT_NORMAL);
407 cairo_set_font_size (cr, 12.0);
409 cairo_move_to (cr, x, y+4);
410 cairo_set_source_rgba(cr, 0, 0, 0,1.0);
411 cairo_show_text( cr, buf);
417 void DrawSeekDot(int x, int y, int colorNr)
419 cairo_t *cr = cairo_create (csBoardWindow);
420 int square = colorNr & 0x80;
424 cairo_rectangle (cr, x-squareSize/9, y-squareSize/9, 2*(squareSize/9), 2*(squareSize/9));
426 cairo_arc(cr, x, y, squareSize/9, 0.0, 2*M_PI);
428 SetPen(cr, 2, "#000000", 0);
429 cairo_stroke_preserve(cr);
431 case 0: cairo_set_source_rgba(cr, 1.0, 0, 0,1.0); break;
432 case 1: cairo_set_source_rgba (cr, 0.0, 0.7, 0.2, 1.0); break;
433 default: cairo_set_source_rgba (cr, 1.0, 1.0, 0.0, 1.0); break;
444 int boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
445 int boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
447 csBoardWindow = GetOutputSurface(&mainOptions[W_BOARD], 0, 0);
448 csBoardBackup = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, boardWidth, boardHeight);
462 if (lineGap == 0) return;
464 /* [HR] Split this into 2 loops for non-square boards. */
466 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
467 gridSegments[i].x1 = 0;
469 lineGap + BOARD_WIDTH * (squareSize + lineGap);
470 gridSegments[i].y1 = gridSegments[i].y2
471 = lineGap / 2 + (i * (squareSize + lineGap));
474 for (j = 0; j < BOARD_WIDTH + 1; j++) {
475 gridSegments[j + i].y1 = 0;
476 gridSegments[j + i].y2 =
477 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
478 gridSegments[j + i].x1 = gridSegments[j + i].x2
479 = lineGap / 2 + (j * (squareSize + lineGap));
484 DoDrawGrid(cairo_surface_t *cs)
486 /* draws a grid starting around Nx, Ny squares starting at x,y */
492 cr = cairo_create (cs);
494 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
495 SetPen(cr, lineGap, "#000000", 0);
498 for (i = 0; i < BOARD_WIDTH + BOARD_HEIGHT + 2; i++)
500 cairo_move_to (cr, gridSegments[i].x1, gridSegments[i].y1);
501 cairo_line_to (cr, gridSegments[i].x2, gridSegments[i].y2);
514 DoDrawGrid(csBoardWindow);
515 if(!dual) DoDrawGrid(csBoardBackup);
519 DoDrawBorder (cairo_surface_t *cs, int x, int y, int type)
526 case 0: col = "#000000"; break;
527 case 1: col = appData.highlightSquareColor; break;
528 case 2: col = appData.premoveHighlightColor; break;
530 cr = cairo_create(cs);
531 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
532 cairo_rectangle(cr, x, y, squareSize+lineGap, squareSize+lineGap);
533 SetPen(cr, lineGap, col, 0);
538 DrawBorder (int x, int y, int type)
540 DoDrawBorder(csBoardWindow, x, y, type);
541 if(!dual) DoDrawBorder(csBoardBackup, x, y, type);
545 CutOutSquare (int x, int y, int *x0, int *y0, int kind)
547 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
548 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
550 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
551 if(textureW[kind] < W*squareSize)
552 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
554 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
555 if(textureH[kind] < H*squareSize)
556 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
558 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
563 DrawLogo (void *handle, void *logo)
565 cairo_surface_t *img, *cs;
569 if(!logo || !handle) return;
570 cs = GetOutputSurface(handle, appData.logoSize, appData.logoSize/2);
571 img = cairo_image_surface_create_from_png (logo);
572 w = cairo_image_surface_get_width (img);
573 h = cairo_image_surface_get_height (img);
574 cr = cairo_create(cs);
575 cairo_scale(cr, (float)appData.logoSize/w, appData.logoSize/(2.*h));
576 cairo_set_source_surface (cr, img, 0, 0);
579 cairo_surface_destroy (img);
580 cairo_surface_destroy (cs);
584 BlankSquare (cairo_surface_t *dest, int x, int y, int color, ChessSquare piece, int fac)
585 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
589 cr = cairo_create (dest);
591 if ((useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
592 cairo_set_source_surface (cr, pngBoardBitmap[color], x*fac - x0, y*fac - y0);
593 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
594 cairo_rectangle (cr, x*fac, y*fac, squareSize, squareSize);
597 } else { // evenly colored squares
600 case 0: col = appData.darkSquareColor; break;
601 case 1: col = appData.lightSquareColor; break;
602 case 2: col = "#000000"; break;
604 SetPen(cr, 2.0, col, 0);
605 cairo_rectangle (cr, x, y, squareSize, squareSize);
612 pngDrawPiece (cairo_surface_t *dest, ChessSquare piece, int square_color, int x, int y)
617 if ((int)piece < (int) BlackPawn) {
623 if(appData.upsideDown && flipView) { p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
624 BlankSquare(dest, x, y, square_color, piece, 1); // erase previous contents with background
625 cr = cairo_create (dest);
626 cairo_set_source_surface (cr, pngPieceBitmaps[kind][piece], x, y);
632 DoDrawDot (cairo_surface_t *cs, int marker, int x, int y, int r)
636 cr = cairo_create(cs);
637 cairo_arc(cr, x+r/2, y+r/2, r/2, 0.0, 2*M_PI);
638 if(appData.monoMode) {
639 SetPen(cr, 2, marker == 2 ? "#000000" : "#FFFFFF", 0);
640 cairo_stroke_preserve(cr);
641 SetPen(cr, 2, marker == 2 ? "#FFFFFF" : "#000000", 0);
643 SetPen(cr, 2, marker == 2 ? "#FF0000" : "#FFFF00", 0);
651 DrawDot (int marker, int x, int y, int r)
652 { // used for atomic captures; no need to draw on backup
654 DoDrawDot(csBoardWindow, marker, x, y, r);
658 DoDrawOneSquare (cairo_surface_t *dest, int x, int y, ChessSquare piece, int square_color, int marker, char *string, int align)
659 { // basic front-end board-draw function: takes care of everything that can be in square:
660 // piece, background, coordinate/count, marker dot
663 if (piece == EmptySquare) {
664 BlankSquare(dest, x, y, square_color, piece, 1);
666 pngDrawPiece(dest, piece, square_color, x, y);
669 if(align) { // square carries inscription (coord or piece count)
671 cairo_text_extents_t te;
673 cr = cairo_create (dest);
674 cairo_select_font_face (cr, "Sans",
675 CAIRO_FONT_SLANT_NORMAL,
676 CAIRO_FONT_WEIGHT_BOLD);
678 cairo_set_font_size (cr, squareSize/4);
679 // calculate where it goes
680 cairo_text_extents (cr, string, &te);
683 xx += squareSize - te.width - te.x_bearing - 1;
684 yy += squareSize - te.height - te.y_bearing - 1;
685 } else if (align == 2) {
686 xx += te.x_bearing + 1, yy += -te.y_bearing + 1;
687 } else if (align == 3) {
688 xx += squareSize - te.width -te.x_bearing - 1;
689 yy += -te.y_bearing + 3;
690 } else if (align == 4) {
691 xx += te.x_bearing + 1, yy += -te.y_bearing + 3;
694 cairo_move_to (cr, xx-1, yy);
695 if(align < 3) cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
696 else cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
697 cairo_show_text (cr, string);
701 if(marker) { // print fat marker dot, if requested
702 DoDrawDot(dest, marker, x + squareSize/4, y+squareSize/4, squareSize/2);
707 DrawOneSquare (int x, int y, ChessSquare piece, int square_color, int marker, char *string, int align)
710 DoDrawOneSquare (csBoardWindow, x, y, piece, square_color, marker, string, align);
712 DoDrawOneSquare (csBoardBackup, x, y, piece, square_color, marker, string, align);
715 /**** Animation code by Hugh Fisher, DCS, ANU. ****/
717 /* Masks for XPM pieces. Black and white pieces can have
718 different shapes, but in the interest of retaining my
719 sanity pieces must have the same outline on both light
720 and dark squares, and all pieces must use the same
721 background square colors/images. */
723 static cairo_surface_t *c_animBufs[3*NrOfAnims]; // newBuf, saveBuf
726 InitAnimState (AnimNr anr)
728 DrawSeekOpen(); // set cs to board widget
729 if(c_animBufs[anr]) cairo_surface_destroy (c_animBufs[anr]);
730 if(c_animBufs[anr+2]) cairo_surface_destroy (c_animBufs[anr+2]);
731 c_animBufs[anr+4] = csBoardWindow;
732 c_animBufs[anr+2] = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, squareSize, squareSize);
733 c_animBufs[anr] = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, squareSize, squareSize);
740 InitAnimState(Player);
744 CairoOverlayPiece (ChessSquare piece, cairo_surface_t *dest)
746 static cairo_t *pieceSource;
747 pieceSource = cairo_create (dest);
748 cairo_set_source_surface (pieceSource, pngPieceBitmaps[!White(piece)][piece % BlackPawn], 0, 0);
749 if(doubleClick) cairo_paint_with_alpha (pieceSource, 0.6);
750 else cairo_paint(pieceSource);
751 cairo_destroy (pieceSource);
755 InsertPiece (AnimNr anr, ChessSquare piece)
757 CairoOverlayPiece(piece, c_animBufs[anr]);
761 DrawBlank (AnimNr anr, int x, int y, int startColor)
763 BlankSquare(c_animBufs[anr+2], x, y, startColor, EmptySquare, 0);
766 void CopyRectangle (AnimNr anr, int srcBuf, int destBuf,
767 int srcX, int srcY, int width, int height, int destX, int destY)
769 cairo_t *cr;// = cairo_create (c_animBufs[anr+destBuf]);
770 cr = cairo_create (c_animBufs[anr+destBuf]);
771 if(c_animBufs[anr+srcBuf] == csBoardWindow)
772 cairo_set_source_surface (cr, csBoardBackup, destX - srcX, destY - srcY);
774 cairo_set_source_surface (cr, c_animBufs[anr+srcBuf], destX - srcX, destY - srcY);
775 cairo_rectangle (cr, destX, destY, width, height);
778 if(c_animBufs[anr+destBuf] == csBoardWindow) {
779 cr = cairo_create (csBoardBackup); // also draw to backup
780 cairo_set_source_surface (cr, c_animBufs[anr+srcBuf], destX - srcX, destY - srcY);
781 cairo_rectangle (cr, destX, destY, width, height);
788 SetDragPiece (AnimNr anr, ChessSquare piece)
792 /* [AS] Arrow highlighting support */
795 DoDrawPolygon (cairo_surface_t *cs, Pnt arrow[], int nr)
799 cr = cairo_create (cs);
800 cairo_move_to (cr, arrow[nr-1].x, arrow[nr-1].y);
802 cairo_line_to(cr, arrow[i].x, arrow[i].y);
804 if(appData.monoMode) { // should we always outline arrow?
805 cairo_line_to(cr, arrow[0].x, arrow[0].y);
806 SetPen(cr, 2, "#000000", 0);
807 cairo_stroke_preserve(cr);
809 SetPen(cr, 2, appData.highlightSquareColor, 0);
817 DrawPolygon (Pnt arrow[], int nr)
819 DoDrawPolygon(csBoardWindow, arrow, nr);
820 if(!dual) DoDrawPolygon(csBoardBackup, arrow, nr);