updated copyright for 2016
[xboard.git] / board.c
diff --git a/board.c b/board.c
index 676ea0b..baf0680 100644 (file)
--- a/board.c
+++ b/board.c
@@ -5,7 +5,8 @@
  * Massachusetts.
  *
  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
- * 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+ * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Free
+ * Software Foundation, Inc.
  *
  * The following terms apply to Digital Equipment Corporation's copyright
  * interest in XBoard:
@@ -96,8 +97,10 @@ extern char *getenv();
 #include "common.h"
 #include "frontend.h"
 #include "backend.h"
+#include "xboard2.h"
 #include "moves.h"
 #include "board.h"
+#include "draw.h"
 
 
 #ifdef __EMX__
@@ -118,6 +121,9 @@ int damage[2][BOARD_RANKS][BOARD_FILES];
 AnimState anims[NrOfAnims];
 
 static void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
+static Boolean IsDrawArrowEnabled P((void));
+static void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
+static void ArrowDamage P((int s_col, int s_row, int d_col, int d_row));
 
 static void
 drawHighlight (int file, int rank, int type)
@@ -136,7 +142,7 @@ drawHighlight (int file, int rank, int type)
          (squareSize + lineGap);
     }
 
-    DrawBorder(x,y, type);
+    DrawBorder(x,y, type, lineGap & 1); // pass whether lineGap is odd
 }
 
 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
@@ -145,6 +151,8 @@ int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
 void
 SetHighlights (int fromX, int fromY, int toX, int toY)
 {
+    int arrow = hi2X >= 0 && hi1Y >= 0 && IsDrawArrowEnabled();
+
     if (hi1X != fromX || hi1Y != fromY) {
        if (hi1X >= 0 && hi1Y >= 0) {
            drawHighlight(hi1X, hi1Y, 0);
@@ -156,6 +164,10 @@ SetHighlights (int fromX, int fromY, int toX, int toY)
            drawHighlight(hi2X, hi2Y, 0);
        }
     }
+
+    if(arrow) // there currently is an arrow displayed
+       ArrowDamage(hi1X, hi1Y, hi2X, hi2Y); // mark which squares it damaged
+
     if (hi1X != fromX || hi1Y != fromY) {
        if (fromX >= 0 && fromY >= 0) {
            drawHighlight(fromX, fromY, 1);
@@ -167,13 +179,13 @@ SetHighlights (int fromX, int fromY, int toX, int toY)
        }
     }
 
-    if(toX<0) // clearing the highlights must have damaged arrow
-       DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y); // for now, redraw it (should really be cleared!)
-
     hi1X = fromX;
     hi1Y = fromY;
     hi2X = toX;
     hi2Y = toY;
+
+    if(arrow || toX >= 0 && fromY >= 0 && IsDrawArrowEnabled())
+       DrawPosition(FALSE, NULL); // repair any arrow damage, or draw a new one
 }
 
 void
@@ -468,12 +480,12 @@ AnimationFrame (AnimNr anr, Pnt *frame, ChessSquare piece)
   MyRectangle updates[4];
   MyRectangle overlap;
   Pnt     pt;
-  int       count, i;
   AnimState *anim = &anims[anr];
+  int     count, i, x, y, w, h;
 
   /* Save what we are about to draw into the new buffer */
   CopyRectangle(anr, DISP, 0,
-           frame->x, frame->y, squareSize, squareSize,
+           x = frame->x, y = frame->y, w = squareSize, h = squareSize,
            0, 0);
 
   /* Erase bits of the previous frame */
@@ -492,11 +504,17 @@ AnimationFrame (AnimNr anr, Pnt *frame, ChessSquare piece)
                updates[i].y - anim->prevFrame.y,
                updates[i].width, updates[i].height,
                updates[i].x, updates[i].y);
+    /* [HGM] correct expose rectangle to encompass both overlapping squares */
+    if(x > anim->prevFrame.x) w += x - anim->prevFrame.x, x = anim->prevFrame.x;
+    else  w += anim->prevFrame.x - x;
+    if(y > anim->prevFrame.y) h += y - anim->prevFrame.y, y = anim->prevFrame.y;
+    else  h += anim->prevFrame.y - y;
   } else {
     /* Easy when no overlap */
     CopyRectangle(anr, 2, DISP,
                  0, 0, squareSize, squareSize,
                  anim->prevFrame.x, anim->prevFrame.y);
+    GraphExpose(currBoard, anim->prevFrame.x, anim->prevFrame.y, squareSize, squareSize);
   }
 
   /* Save this frame for next time round */
@@ -511,6 +529,7 @@ AnimationFrame (AnimNr anr, Pnt *frame, ChessSquare piece)
   CopyRectangle(anr, 0, DISP,
                0, 0, squareSize, squareSize,
                frame->x, frame->y);
+  GraphExpose(currBoard, x, y, w, h);
 }
 
 static void
@@ -572,6 +591,7 @@ AnimateAtomicCapture (Board board, int fromX, int fromY, int toX, int toY)
        FrameDelay(appData.animSpeed);
     }
     board[fromY][toY] = piece;
+    DrawGrid();
 }
 
 /* Main control logic for deciding what to animate and how */
@@ -580,23 +600,31 @@ void
 AnimateMove (Board board, int fromX, int fromY, int toX, int toY)
 {
   ChessSquare piece;
-  int hop;
+  int hop, x = toX, y = toY;
   Pnt      start, finish, mid;
   Pnt      frames[kFactor * 2 + 1];
   int        nFrames, startColor, endColor;
 
+  if(killX >= 0 && IS_LION(board[fromY][fromX])) Roar();
+
   /* Are we animating? */
   if (!appData.animate || appData.blindfold)
     return;
 
   if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
-     board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
+     board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing ||
+     board[toY][toX] == WhiteKing && board[fromY][fromX] == WhiteRook || // [HGM] seirawan
+     board[toY][toX] == BlackKing && board[fromY][fromX] == BlackRook)
        return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
 
   if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
   piece = board[fromY][fromX];
   if (piece >= EmptySquare) return;
 
+  if(killX >= 0) toX = killX, toY = killY; // [HGM] lion: first to kill square
+
+again:
+
 #if DONT_HOP
   hop = FALSE;
 #else
@@ -629,11 +657,13 @@ AnimateMove (Board board, int fromX, int fromY, int toX, int toY)
   if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
     int i,j;
     for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
-      if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
+      if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] |=  1 + ((i-toX ^ j-toY) & 1);
   }
 
   /* Be sure end square is redrawn */
-  damage[0][toY][toX] = True;
+  damage[0][toY][toX] |= True;
+
+  if(toX != x || toY != y) { fromX = toX; fromY = toY; toX = x; toY = y; goto again; } // second leg
 }
 
 void
@@ -752,7 +782,7 @@ DrawDragPiece ()
      it's being dragged around the board. So we erase the square
      that the piece is on and draw it at the last known drag point. */
   DrawOneSquare(anims[Player].startSquare.x, anims[Player].startSquare.y,
-               EmptySquare, anims[Player].startColor, 0, NULL, 0);
+               EmptySquare, anims[Player].startColor, 0, NULL, NULL, 0);
   AnimationFrame(Player, &anims[Player].prevFrame, anims[Player].dragPiece);
   damage[0][anims[Player].startBoardY][anims[Player].startBoardX] = TRUE;
 }
@@ -762,7 +792,7 @@ DrawSquare (int row, int column, ChessSquare piece, int do_flash)
 {
     int square_color, x, y, align=0;
     int i;
-    char string[2];
+    char tString[3], bString[2];
     int flash_delay;
 
     /* Calculate delay in milliseconds (2-delays per complete flash) */
@@ -780,35 +810,38 @@ DrawSquare (int row, int column, ChessSquare piece, int do_flash)
 
     square_color = SquareColor(row, column);
 
-    string[1] = NULLCHAR;
+    bString[1] = bString[0] = NULLCHAR;
     if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
                && column >= BOARD_LEFT && column < BOARD_RGHT) {
-       string[0] = 'a' + column - BOARD_LEFT;
+       bString[0] = 'a' + column - BOARD_LEFT;
        align = 1; // coord in lower-right corner
     }
     if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
-       string[0] = ONE + row;
+       snprintf(tString, 3, "%d", ONE - '0' + row);
        align = 2; // coord in upper-left corner
     }
     if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
-        string[0] = '0' + piece;
+       snprintf(tString, 3, "%d", piece);
        align = 3; // holdings count in upper-right corner
     }
     if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
-       string[0] = '0' + piece;
+       snprintf(tString, 3, "%d", piece);
        align = 4; // holdings count in upper-left corner
     }
+    if(piece == DarkSquare) square_color = 2;
     if(square_color == 2 || appData.blindfold) piece = EmptySquare;
 
     if (do_flash && piece != EmptySquare && appData.flashCount > 0) {
        for (i=0; i<appData.flashCount; ++i) {
-           DrawOneSquare(x, y, piece, square_color, 0, string, 0);
+           DrawOneSquare(x, y, piece, square_color, 0, tString, bString, 0);
+           GraphExpose(currBoard, x, y, squareSize, squareSize);
            FlashDelay(flash_delay);
-           DrawOneSquare(x, y, EmptySquare, square_color, 0, string, 0);
+           DrawOneSquare(x, y, EmptySquare, square_color, 0, tString, bString, 0);
+           GraphExpose(currBoard, x, y, squareSize, squareSize);
            FlashDelay(flash_delay);
        }
     }
-    DrawOneSquare(x, y, piece, square_color, partnerUp ? 0 : marker[row][column], string, align);
+    DrawOneSquare(x, y, piece, square_color, partnerUp ? 0 : marker[row][column], tString, bString, align);
 }
 
 /* Returns 1 if there are "too many" differences between b1 and b2
@@ -879,11 +912,11 @@ check_castle_draw (Board newb, Board oldb, int *rrow, int *rcol)
 void
 DrawPosition (int repaint, Board board)
 {
-    int i, j, do_flash;
+    int i, j, do_flash, exposeAll = False;
     static int lastFlipView = 0;
     static int lastBoardValid[2] = {0, 0};
     static Board lastBoard[2];
-    Arg args[16];
+    static char lastMarker[BOARD_RANKS][BOARD_FILES];
     int rrow, rcol;
     int nr = twoBoards*partnerUp;
 
@@ -897,7 +930,7 @@ DrawPosition (int repaint, Board board)
        MarkMenuItem("View.Flip View", flipView);
     }
 
-    if(nr) { SlavePopUp(); SwitchWindow(); } // [HGM] popup board if not yet popped up, and switch drawing to it.
+    if(nr) { SlavePopUp(); SwitchWindow(0); } // [HGM] popup board if not yet popped up, and switch drawing to it.
 
     /*
      * It would be simpler to clear the window with XClearWindow()
@@ -906,8 +939,8 @@ DrawPosition (int repaint, Board board)
 
     if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
 
-       if ( lineGap && IsDrawArrowEnabled())
-           DrawGrid();
+//     if ( lineGap && IsDrawArrowEnabled())
+//         DrawGrid();
 
        /* If too much changes (begin observing new game, etc.), don't
           do flashing */
@@ -917,9 +950,8 @@ DrawPosition (int repaint, Board board)
           and the rook (just flash the king). */
        if (do_flash) {
            if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
-               /* Draw rook with NO flashing. King will be drawn flashing later */
-               DrawSquare(rrow, rcol, board[rrow][rcol], 0);
-               lastBoard[nr][rrow][rcol] = board[rrow][rcol];
+               /* Mark rook for drawing with NO flashing. */
+               damage[nr][rrow][rcol] |= 1;
            }
        }
 
@@ -928,17 +960,21 @@ DrawPosition (int repaint, Board board)
           is flashing on its new square */
        for (i = 0; i < BOARD_HEIGHT; i++)
          for (j = 0; j < BOARD_WIDTH; j++)
-           if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
+           if (((board[i][j] != lastBoard[nr][i][j] || !nr && marker[i][j] != lastMarker[i][j]) && board[i][j] == EmptySquare)
                || damage[nr][i][j]) {
                DrawSquare(i, j, board[i][j], 0);
-               damage[nr][i][j] = False;
+               if(damage[nr][i][j] & 2) {
+                   drawHighlight(j, i, 0);   // repair arrow damage
+                   if(lineGap) damage[nr][i][j] = False; // this flushed the square as well
+               } else damage[nr][i][j] = 1;  // mark for expose
            }
 
        /* Second pass -- Draw piece(s) in new position and flash them */
        for (i = 0; i < BOARD_HEIGHT; i++)
          for (j = 0; j < BOARD_WIDTH; j++)
-           if (board[i][j] != lastBoard[nr][i][j]) {
+           if (board[i][j] != lastBoard[nr][i][j] || !nr && marker[i][j] != lastMarker[i][j]) {
                DrawSquare(i, j, board[i][j], do_flash);
+               damage[nr][i][j] = 1; // mark for expose
            }
     } else {
        if (lineGap > 0)
@@ -949,25 +985,34 @@ DrawPosition (int repaint, Board board)
              DrawSquare(i, j, board[i][j], 0);
              damage[nr][i][j] = False;
          }
+
+       exposeAll = True;
     }
 
     CopyBoard(lastBoard[nr], board);
     lastBoardValid[nr] = 1;
   if(nr == 0) { // [HGM] dual: no highlights on second board yet
     lastFlipView = flipView;
+    for (i = 0; i < BOARD_HEIGHT; i++)
+       for (j = 0; j < BOARD_WIDTH; j++)
+           lastMarker[i][j] = marker[i][j];
 
     /* Draw highlights */
     if (pm1X >= 0 && pm1Y >= 0) {
       drawHighlight(pm1X, pm1Y, 2);
+      if(lineGap) damage[nr][pm1Y][pm1X] = False;
     }
     if (pm2X >= 0 && pm2Y >= 0) {
       drawHighlight(pm2X, pm2Y, 2);
+      if(lineGap) damage[nr][pm2Y][pm2X] = False;
     }
     if (hi1X >= 0 && hi1Y >= 0) {
       drawHighlight(hi1X, hi1Y, 1);
+      if(lineGap) damage[nr][hi1Y][hi1X] = False;
     }
     if (hi2X >= 0 && hi2Y >= 0) {
       drawHighlight(hi2X, hi2Y, 1);
+      if(lineGap) damage[nr][hi2Y][hi2X] = False;
     }
     DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
   }
@@ -976,8 +1021,32 @@ DrawPosition (int repaint, Board board)
     /* If piece being dragged around board, must redraw that too */
     DrawDragPiece();
 
+    if(exposeAll)
+       GraphExpose(currBoard, 0, 0, BOARD_WIDTH*(squareSize + lineGap) + lineGap, BOARD_HEIGHT*(squareSize + lineGap) + lineGap);
+    else {
+       for (i = 0; i < BOARD_HEIGHT; i++)
+           for (j = 0; j < BOARD_WIDTH; j++)
+               if(damage[nr][i][j]) {
+                   int x, y;
+                   if (flipView) {
+                       x = lineGap + ((BOARD_WIDTH-1)-j) *
+                         (squareSize + lineGap);
+                       y = lineGap + i * (squareSize + lineGap);
+                   } else {
+                       x = lineGap + j * (squareSize + lineGap);
+                       y = lineGap + ((BOARD_HEIGHT-1)-i) *
+                         (squareSize + lineGap);
+                   }
+                   if(damage[nr][i][j] & 2) // damage by old or new arrow
+                       GraphExpose(currBoard, x - lineGap, y - lineGap, squareSize + 2*lineGap, squareSize  + 2*lineGap);
+                   else
+                       GraphExpose(currBoard, x, y, squareSize, squareSize);
+                   damage[nr][i][j] &= 2; // remember damage by newly drawn error in '2' bit, to schedule it for erasure next draw
+               }
+    }
+
     FlashDelay(0); // this flushes drawing queue;
-    if(nr) SwitchWindow();
+    if(nr) SwitchWindow(1);
 }
 
 /* [AS] Arrow highlighting support */
@@ -1012,7 +1081,7 @@ SquareToPos (int rank, int file, int *x, int *y)
 }
 
 /* Draw an arrow between two points using current settings */
-void
+static void
 DrawArrowBetweenPoints (int s_x, int s_y, int d_x, int d_y)
 {
     Pnt arrow[8];
@@ -1115,22 +1184,22 @@ DrawArrowBetweenPoints (int s_x, int s_y, int d_x, int d_y)
 //    Polygon( hdc, arrow, 7 );
 }
 
-void
+static void
 ArrowDamage (int s_col, int s_row, int d_col, int d_row)
 {
     int hor, vert, i, n = partnerUp * twoBoards;
     hor = 64*s_col + 32; vert = 64*s_row + 32;
     for(i=0; i<= 64; i++) {
-            damage[n][vert+6>>6][hor+6>>6] = True;
-            damage[n][vert-6>>6][hor+6>>6] = True;
-            damage[n][vert+6>>6][hor-6>>6] = True;
-            damage[n][vert-6>>6][hor-6>>6] = True;
+            damage[n][vert+6>>6][hor+6>>6] |= 2;
+            damage[n][vert-6>>6][hor+6>>6] |= 2;
+            damage[n][vert+6>>6][hor-6>>6] |= 2;
+            damage[n][vert-6>>6][hor-6>>6] |= 2;
             hor += d_col - s_col; vert += d_row - s_row;
     }
 }
 
 /* [AS] Draw an arrow between two squares */
-void
+static void
 DrawArrowBetweenSquares (int s_col, int s_row, int d_col, int d_row)
 {
     int s_x, s_y, d_x, d_y;
@@ -1173,17 +1242,15 @@ DrawArrowBetweenSquares (int s_col, int s_row, int d_col, int d_row)
     ArrowDamage(s_col, s_row, d_col, d_row);
 }
 
-Boolean
+static Boolean
 IsDrawArrowEnabled ()
 {
     return (appData.highlightMoveWithArrow || twoBoards && partnerUp) && squareSize >= 32;
 }
 
-void
+static void
 DrawArrowHighlight (int fromX, int fromY, int toX,int toY)
 {
     if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
         DrawArrowBetweenSquares(fromX, fromY, toX, toY);
 }
-
-