X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=draw.c;h=79518a04c98e340ac2c0014320892d687e09a97f;hb=v4.9.x;hp=4ad6887c967171130df3bbb2bcc68ff84fdeb100;hpb=c972af9ffaac85819f9f0466c2b814553bd82be9;p=xboard.git diff --git a/draw.c b/draw.c index 4ad6887..f51c771 100644 --- a/draw.c +++ b/draw.c @@ -106,10 +106,10 @@ extern char *getenv(); Boolean cairoAnimate; Option *currBoard; cairo_surface_t *csBoardWindow; -static cairo_surface_t *pngPieceImages[2][(int)BlackPawn]; // png 256 x 256 images -static cairo_surface_t *pngPieceBitmaps[2][(int)BlackPawn]; // scaled pieces as used -static cairo_surface_t *pngPieceBitmaps2[2][(int)BlackPawn]; // scaled pieces in store -static RsvgHandle *svgPieces[2][(int)BlackPawn]; // vector pieces in store +static cairo_surface_t *pngPieceImages[2][(int)BlackPawn+1]; // png 256 x 256 images +static cairo_surface_t *pngPieceBitmaps[2][(int)BlackPawn+1]; // scaled pieces as used +static cairo_surface_t *pngPieceBitmaps2[2][(int)BlackPawn+1]; // scaled pieces in store +static RsvgHandle *svgPieces[2][(int)BlackPawn+1]; // vector pieces in store static cairo_surface_t *pngBoardBitmap[2], *pngOriginalBoardBitmap[2]; int useTexture, textureW[2], textureH[2]; @@ -165,7 +165,7 @@ SelectPieces(VariantClass v) int i; for(i=0; i<2; i++) { int p; - for(p=0; p<=(int)WhiteKing; p++) + for(p=0; p<=(int)WhiteKing+1; p++) pngPieceBitmaps[i][p] = pngPieceBitmaps2[i][p]; // defaults if(v == VariantShogi && BOARD_HEIGHT != 7) { // no exceptions in Tori Shogi pngPieceBitmaps[i][(int)WhiteCannon] = pngPieceBitmaps2[i][(int)WhiteTokin]; @@ -187,20 +187,6 @@ SelectPieces(VariantClass v) if(v == VariantChuChess) { pngPieceBitmaps[i][(int)WhiteNightrider] = pngPieceBitmaps2[i][(int)WhiteLion]; } - if(v == VariantChu) { - pngPieceBitmaps[i][(int)WhiteNightrider] = pngPieceBitmaps2[i][(int)WhiteClaw]; - pngPieceBitmaps[i][(int)WhiteClaw] = pngPieceBitmaps2[i][(int)WhiteNightrider]; - pngPieceBitmaps[i][(int)WhiteUnicorn] = pngPieceBitmaps2[i][(int)WhiteCat]; - pngPieceBitmaps[i][(int)WhiteSilver] = pngPieceBitmaps2[i][(int)WhiteSword]; - pngPieceBitmaps[i][(int)WhiteFalcon] = pngPieceBitmaps2[i][(int)WhiteDagger]; - pngPieceBitmaps[i][(int)WhiteCat] = pngPieceBitmaps2[i][(int)WhiteUnicorn]; - pngPieceBitmaps[i][(int)WhiteSword] = pngPieceBitmaps2[i][(int)WhiteSilver]; - pngPieceBitmaps[i][(int)WhiteDagger] = pngPieceBitmaps2[i][(int)WhiteFalcon]; - pngPieceBitmaps[i][(int)WhiteMan] = pngPieceBitmaps2[i][(int)WhiteCopper]; - pngPieceBitmaps[i][(int)WhiteCopper] = pngPieceBitmaps2[i][(int)WhiteMan]; - pngPieceBitmaps[i][(int)WhiteAxe] = pngPieceBitmaps2[i][(int)WhiteCannon]; - pngPieceBitmaps[i][(int)WhiteCannon] = pngPieceBitmaps2[i][(int)WhiteAxe]; - } } } @@ -220,7 +206,7 @@ InitDrawingSizes (BoardSize boardSize, int flags) squareSize = ((squareSize + lineGap) * oldNrOfFiles + 0.5*BOARD_WIDTH) / BOARD_WIDTH; // keep total width fixed if(appData.overrideLineGap < 0) lineGap = squareSize < 37 ? 1 : squareSize < 59 ? 2 : squareSize < 116 ? 3 : 4; squareSize -= lineGap; - CreatePNGPieces(); + CreatePNGPieces(appData.pieceDirectory); CreateGrid(); } oldNrOfFiles = BOARD_WIDTH; @@ -288,13 +274,14 @@ CreatePNGBoard (char *s, int kind) useTexture |= kind + 1; pngOriginalBoardBitmap[kind] = img; w = textureW[kind] = cairo_image_surface_get_width (img); h = textureH[kind] = cairo_image_surface_get_height (img); + transparency[kind] = cairo_image_surface_get_format (img) == CAIRO_FORMAT_ARGB32; n[kind] = 1.; modV[kind] = modH[kind] = -1; while((q = strchr(p+1, '-'))) p = q; // find last '-' if(strlen(p) < 11 && sscanf(p, "-%dx%d.pn%c", &f, &r, &c) == 3 && c == 'g') { if(f == 0 || r == 0) f = BOARD_WIDTH, r = BOARD_HEIGHT; // 0x0 means 'fits any', so make it fit textureW[kind] = (w*BOARD_WIDTH)/f; // sync cutting locations with square pattern textureH[kind] = (h*BOARD_HEIGHT)/r; - n[kind] = r*squareSize/h; // scale to make it fit exactly vertically + n[kind] = (r*squareSize + 0.99)/h; // scale to make it fit exactly vertically modV[kind] = r; modH[kind] = f; } else if((p = strstr(s, "xq")) && (p == s || p[-1] == '/')) { // assume full-board image for Xiangqi @@ -324,7 +311,7 @@ char *pngPieceNames[] = // must be in same order as internal piece encoding "LShield", "Pegasus", "Wizard", "Copper", "Iron", "Viking", "Flag", "Axe", "Dolphin", "Leopard", "Claw", "Left", "Butterfly", "PromoBishop", "PromoRook", "HCrown", "RShield", "Prince", "Phoenix", "Kylin", "Drunk", "Right", "GoldPawn", "GoldKnight", "PromoHorse", "PromoDragon", "GoldLance", "GoldSilver", "HSword", "PromoSword", "PromoHSword", "Princess", "King", - NULL + "Ducky", NULL }; char *backupPiece[] = { // pieces that map on other in default theme ("Crown" - "Drunk") @@ -351,6 +338,15 @@ LoadSVG (char *dir, int color, int piece, int retry) if(!svg && *dir) { svg = rsvg_handle_new_from_file(buf, &svgerror); + if(!svg) { // failed! If -pid name starts with "sub_" we try to load the piece from the parent directory + char *p = buf, *q; + safeStrCpy(buf, dir, MSG_SIZ); + while((q = strchr(p, '/'))) p = q + 1; + if(!strncmp(p, "sub_", 4)) { + if(p == buf) safeStrCpy(buf, ".", MSG_SIZ); else p[-1] = NULLCHAR; // strip last directory off path + return LoadSVG(buf, color, piece, retry); + } + } if(!svg && *appData.inscriptions) { // if there is no piece-specific SVG, but we make inscriptions, try general background snprintf(buf, MSG_SIZ, "%s/%sTile.svg", dir, color ? "Black" : "White"); svg = rsvg_handle_new_from_file(buf, &svgerror); @@ -379,8 +375,42 @@ LoadSVG (char *dir, int color, int piece, int retry) return NULL; } +static void Wint(FILE *f, int n) +{ // write 32-bit int, lsb first + fprintf(f, "%c%c%c%c", n&255, n>>8&255, n>>16&255, n>>24&255); +} + static void -ScaleOnePiece (int color, int piece) +SaveWindowsBitmap(ChessSquare piece, int color, int *data, int stride, int w, int h, int bpp) +{ + int i, v, line = (w*bpp + 3)>>2, size = line*4*h; + char buf[100]; + FILE *f; + snprintf(buf, 100, "bmaps/piece%d_%d%c.bmp", piece, w, color ? 's': 'o'); + if(piece >= appData.bmpSave && piece != WhiteKing) return; + f = fopen(buf, "wb"); + if(!f) return; + fprintf(f, "BM"); + Wint(f, size+54); Wint(f, 0); Wint(f, 54); Wint(f, 40); // file size, reserved, image offset, header size + Wint(f, w); Wint(f, h); Wint(f, 8*bpp << 16 | 1); // width, height, planes & bits/pix + Wint(f, 0); // compression + Wint(f, size); Wint(f, 3780); Wint(f, 3780); Wint(f, 0); Wint(f, 0); // image size, pix/m (H and V), color-table size (2x) + for(v=h-1; v>=0; v--) { + for(i=0; i>16&255, g=pix>>8&255, b=pix&255, a=pix>>24&255; + r = r*a/255; b = b*a/255; g = g*a/255; + if(bpp == 4) fprintf(f, "%c%c%c%c", b, g, r, a); else fprintf(f, "%c%c%c", b, g, r); + } + i *= bpp; while(i++ < line*4) fprintf(f, "%c", 0); // padding + } + fclose(f); + if(appData.bmpSave && piece == WhiteKing && color) exit(0); +} + +void InscribeKanji (cairo_surface_t *canvas, ChessSquare piece, int x, int y); + +static void +ScaleOnePiece (int color, int piece, char *pieceDir) { float w, h; char buf[MSG_SIZ]; @@ -392,11 +422,11 @@ ScaleOnePiece (int color, int piece) svgPieces[color][piece] = LoadSVG("", color, piece, 0); // this fills pngPieceImages if we had cached svg with bitmap of wanted size if(!pngPieceImages[color][piece]) { // we don't have cached bitmap (implying we did not have cached svg) - if(*appData.pieceDirectory) { // user specified piece directory - snprintf(buf, MSG_SIZ, "%s/%s%s.png", appData.pieceDirectory, color ? "Black" : "White", pngPieceNames[piece]); + if(*pieceDir) { // user specified piece directory + snprintf(buf, MSG_SIZ, "%s/%s%s.png", pieceDir, color ? "Black" : "White", pngPieceNames[piece]); img = cairo_image_surface_create_from_png (buf); // try if there are png pieces there if(cairo_surface_status(img) != CAIRO_STATUS_SUCCESS) { // there were not - svgPieces[color][piece] = LoadSVG(appData.pieceDirectory, color, piece, 0); // so try if he has svg there + svgPieces[color][piece] = LoadSVG(pieceDir, color, piece, 0); // so try if he has svg there } else pngPieceImages[color][piece] = img; } } @@ -428,13 +458,17 @@ ScaleOnePiece (int color, int piece) cairo_set_source_surface (cr, img, 0, 0); cairo_paint (cr); cairo_destroy (cr); +if(appData.inscriptions[0]) InscribeKanji(cs, piece+BlackPawn*color, 0, 0); +//sprintf(buf, "%c2%d.png", color ? 'b' : 'w', piece); +//if(piece < 66) cairo_surface_write_to_png(cs, buf); - if(!appData.trueColors || !*appData.pieceDirectory) { // operate on bitmap to color it (king-size hack...) + if(!appData.trueColors || !*pieceDir) { // operate on bitmap to color it (king-size hack...) int stride = cairo_image_surface_get_stride(cs)/4; int *buf = (int *) cairo_image_surface_get_data(cs); int i, j, p; sscanf(color ? appData.blackPieceColor+1 : appData.whitePieceColor+1, "%x", &p); // replacement color cairo_surface_flush(cs); + SaveWindowsBitmap(piece, color, buf, stride, squareSize, squareSize, 4); for(i=0; i= BlackPawn) piece = BLACK_TO_WHITE piece; p = appData.inscriptions; - n = piece; + if(*p > '0' && *p < '3') nr = *p++ - '0'; // nr of kanji per piece + n = piece; i = 0; while(piece > WhitePawn) { + if(*p == '/') p++, piece = n - WhitePBishop; // secondary series if(*p++ == NULLCHAR) { if(n != WhiteKing) return; - p = q; + p = oldq; break; } - q = p - 1; + oldq = q; q = p - 1; while((*p & 0xC0) == 0x80) p++; // skip UTF-8 continuation bytes - piece--; + if(*q != '.' && ++i < nr) continue; // yet more kanji for the current piece + piece--; i = 0; } - strncpy(buf, p, 10); - for(q=buf; (*++q & 0xC0) == 0x80;); + strncpy(buf, p, 20); + for(q=buf; (*++q & 0xC0) == 0x80;); // skip first unicode + if(nr > 1) { + p = q; + while((*++p & 0xC0) == 0x80) {} // skip second unicode + *p = NULLCHAR; size = 30; i = -12; + DrawUnicode(canvas, q, x, y, PieceToChar(n), flip, size, 16); + } else i = 4; *q = NULLCHAR; - DrawUnicode(canvas, buf, x, y, PieceToChar(n), flip); + DrawUnicode(canvas, buf, x, y, PieceToChar(n), flip, size, i); } void @@ -890,7 +965,7 @@ DrawOneSquare (int x, int y, ChessSquare piece, int square_color, int marker, ch BlankSquare(CsBoardWindow(currBoard), x, y, square_color, piece, 1); } else { pngDrawPiece(CsBoardWindow(currBoard), piece, square_color, x, y); - if(appData.inscriptions[0]) InscribeKanji(CsBoardWindow(currBoard), piece, x, y); +// if(appData.inscriptions[0]) InscribeKanji(CsBoardWindow(currBoard), piece, x, y); } if(align) { // square carries inscription (coord or piece count)