/* * Copyright (C) 1997-2003 Gary Wong * Copyright (C) 2002-2009 the AUTHORS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #if defined(HAVE_UNISTD_H) #include #endif #include #include #ifdef WIN32 #include #endif #include "backgammon.h" #include "export.h" #include #include "render.h" #include "renderprefs.h" #include "boardpos.h" #include "boarddim.h" #if defined(HAVE_LIBPNG) static char *szFile, *pchFile; static int imagesWritten; #define NUM_IMAGES 344 /* Overall board size */ static int s; /* Size of cube and dice - now same as rest of board */ #define ss s /* Helpers for 2d position in arrays */ #define boardStride (BOARD_WIDTH * s * 3) #define coord(x, y) ((x) * s * 3 + (y) * s * boardStride) #define coordStride(x, y, stride) ((x) * s * 3 + (y) * s * stride) static unsigned char *auchBoard, *auchChequer[2], *auchChequerLabels, *auchLo, *auchHi, *auchLoRev, *auchHiRev, *auchCube, *auchCubeFaces, *auchDice[2], *auchPips[2], *auchLabel, *auchOff[2], *auchMidBoard, *auchBar[2], *auchPoint[2][2][2]; static unsigned short *asRefract[2]; #if defined(USE_GTK) static unsigned char *auchArrow[2]; #endif static unsigned char *auchMidlb; static void WriteImageStride(unsigned char *img, int stride, int cx, int cy) { if (WritePNG(szFile, img, (unsigned int) stride, (unsigned int) cx, (unsigned int) cy) == -1) outputf(_("Error creating image file %s\n"), szFile); imagesWritten++; ProgressValueAdd(1); } static void WriteStride(const char *name, unsigned char *img, int stride, int cx, int cy) { strcpy(pchFile, name); WriteImageStride(img, stride, cx, cy); } static void WriteImage(unsigned char *img, int cx, int cy) { WriteImageStride(img, boardStride, cx, cy); } static void Write(const char *name, unsigned char *img, int cx, int cy) { strcpy(pchFile, name); WriteImage(img, cx, cy); } static void DrawArrow(int side, int player) { /* side 0 = left, 1 = right */ int offset_x = 0; memcpy(auchMidlb, auchBoard, BOARD_WIDTH * s * BOARD_HEIGHT * s * 3); #if defined(USE_GTK) { int x, y; ArrowPosition(side /* rd.fClockwise */ , player, s, &x, &y); AlphaBlendClip2(auchMidlb, boardStride, x, y, BOARD_WIDTH * s, BOARD_HEIGHT * s, auchMidlb, boardStride, x, y, auchArrow[player], s * ARROW_WIDTH * 4, 0, 0, s * ARROW_WIDTH, s * ARROW_HEIGHT); } #endif sprintf(pchFile, "b-mid%cb-%c.png", side ? 'r' : 'l', player ? 'o' : 'x'); if (side == 1) offset_x = BOARD_WIDTH - BEAROFF_WIDTH; WriteImage(auchMidlb + coord(offset_x, BOARD_HEIGHT / 2 - BOARD_CENTER_HEIGHT / 2), BEAROFF_WIDTH * s, BOARD_CENTER_HEIGHT * s); } static void DrawPips(unsigned char *auchDest, int nStride, unsigned char *auchPip, int n) { int ix, iy, afPip[9]; afPip[0] = afPip[8] = (n == 2) || (n == 3) || (n == 4) || (n == 5) || (n == 6); afPip[1] = afPip[7] = 0; afPip[2] = afPip[6] = (n == 4) || (n == 5) || (n == 6); afPip[3] = afPip[5] = n == 6; afPip[4] = n & 1; for (iy = 0; iy < 3; iy++) { for (ix = 0; ix < 3; ix++) { if (afPip[iy * 3 + ix]) CopyArea(auchDest + (int) (1.5 * (ix + 1) * ss) * 3 + ((int) (1.5 * (iy + 1) * ss) * nStride), nStride, auchPip, ss * 3, ss, ss); } } } static void WriteBorder(const char *file, unsigned char *auchSrc, unsigned char *auchBoardSrc) { CopyArea(auchLabel, boardStride, auchBoardSrc, boardStride, BOARD_WIDTH * s, BORDER_HEIGHT * s); AlphaBlendClip(auchLabel, boardStride, 0, 0, BOARD_WIDTH * s, BORDER_HEIGHT * s, auchLabel, boardStride, 0, 0, auchSrc, BOARD_WIDTH * s * 4, 0, 0, BOARD_WIDTH * s, BORDER_HEIGHT * s); Write(file, auchLabel, BOARD_WIDTH * s, BORDER_HEIGHT * s); } static void WriteImages(void) { int i, j, k; imagesWritten = 0; /* top border-high numbers */ WriteBorder("b-hitop.png", auchHi, auchBoard); WriteBorder("b-hitopr.png", auchHiRev, auchBoard); /* top border-low numbers */ WriteBorder("b-lotop.png", auchLo, auchBoard); WriteBorder("b-lotopr.png", auchLoRev, auchBoard); /* empty points */ Write("b-gd.png", auchBoard + coord(BEAROFF_WIDTH, BORDER_HEIGHT), POINT_WIDTH * s, POINT_HEIGHT * s); Write("b-rd.png", auchBoard + coord(BEAROFF_WIDTH + POINT_WIDTH, BORDER_HEIGHT), POINT_WIDTH * s, POINT_HEIGHT * s); Write("b-ru.png", auchBoard + coord(BEAROFF_WIDTH, BOARD_HEIGHT / 2 + BOARD_CENTER_HEIGHT / 2), POINT_WIDTH * s, POINT_HEIGHT * s); Write("b-gu.png", auchBoard + coord(BEAROFF_WIDTH + POINT_WIDTH, BOARD_HEIGHT / 2 + BOARD_CENTER_HEIGHT / 2), POINT_WIDTH * s, POINT_HEIGHT * s); /* upper left bearoff tray */ Write("b-loff-x0.png", auchBoard + coord(0, BORDER_HEIGHT), BEAROFF_WIDTH * s, BEAROFF_HEIGHT * s); /* upper right bearoff tray */ Write("b-roff-x0.png", auchBoard + coord(BOARD_WIDTH - BEAROFF_WIDTH, BORDER_HEIGHT), BEAROFF_WIDTH * s, BEAROFF_HEIGHT * s); /* lower right bearoff tray */ Write("b-roff-o0.png", auchBoard + coord(BOARD_WIDTH - BEAROFF_WIDTH, BORDER_HEIGHT + POINT_HEIGHT + BOARD_CENTER_HEIGHT), BEAROFF_WIDTH * s, BEAROFF_HEIGHT * s); /* lower left bearoff tray */ Write("b-loff-o0.png", auchBoard + coord(0, BORDER_HEIGHT + POINT_HEIGHT + BOARD_CENTER_HEIGHT), BEAROFF_WIDTH * s, BEAROFF_HEIGHT * s); /* bar top */ Write("b-ct.png", auchBoard + coord(BOARD_WIDTH / 2 - BAR_WIDTH / 2, BORDER_HEIGHT), BAR_WIDTH * s, CUBE_HEIGHT * s); /* bearoff tray dividers */ /* 4 arrows, left+right side for each player */ DrawArrow(0, 0); DrawArrow(0, 1); DrawArrow(1, 0); DrawArrow(1, 1); /* left bearoff centre */ strcpy(pchFile, "b-midlb.png"); WriteImage(auchBoard + coord(0, BOARD_HEIGHT / 2 - BOARD_CENTER_HEIGHT / 2), BEAROFF_WIDTH * s, BOARD_CENTER_HEIGHT * s); /* right bearoff centre */ strcpy(pchFile, "b-midrb.png"); WriteImage(auchBoard + coord(BOARD_WIDTH - BEAROFF_WIDTH, BOARD_HEIGHT / 2 - BOARD_CENTER_HEIGHT / 2), BEAROFF_WIDTH * s, BOARD_CENTER_HEIGHT * s); /* left board centre */ strcpy(pchFile, "b-midl.png"); WriteImage(auchBoard + coord(BEAROFF_WIDTH, BOARD_HEIGHT / 2 - BOARD_CENTER_HEIGHT / 2), BOARD_CENTER_WIDTH * s, BOARD_CENTER_HEIGHT * s); /* bar centre */ strcpy(pchFile, "b-midc.png"); WriteImage(auchBoard + coord(BOARD_WIDTH / 2 - BAR_WIDTH / 2, BOARD_HEIGHT / 2 - BOARD_CENTER_HEIGHT / 2), BAR_WIDTH * s, BOARD_CENTER_HEIGHT * s); /* right board centre */ strcpy(pchFile, "b-midr.png"); WriteImage(auchBoard + coord(BOARD_WIDTH / 2 + BAR_WIDTH / 2, BOARD_HEIGHT / 2 - BOARD_CENTER_HEIGHT / 2), BOARD_CENTER_WIDTH * s, BOARD_CENTER_HEIGHT * s); /* bar bottom */ Write("b-cb.png", auchBoard + coord(BOARD_WIDTH / 2 - BAR_WIDTH / 2, BOARD_HEIGHT - CUBE_HEIGHT - BORDER_HEIGHT), BAR_WIDTH * s, CUBE_HEIGHT * s); /* bottom border-high numbers */ WriteBorder("b-hibot.png", auchHi, auchBoard + coord(0, BOARD_HEIGHT - BORDER_HEIGHT)); WriteBorder("b-hibotr.png", auchHiRev, auchBoard + coord(0, BOARD_HEIGHT - BORDER_HEIGHT)); /* bottom border-low numbers */ WriteBorder("b-lobot.png", auchLo, auchBoard + coord(0, BOARD_HEIGHT - BORDER_HEIGHT)); WriteBorder("b-lobotr.png", auchLoRev, auchBoard + coord(0, BOARD_HEIGHT - BORDER_HEIGHT)); /* Copy 4 points (top/bottom and both colours) */ CopyArea(auchPoint[0][0][0], POINT_WIDTH * s * 3, auchBoard + coord(BEAROFF_WIDTH, BORDER_HEIGHT), boardStride, POINT_WIDTH * s, POINT_HEIGHT * s); CopyArea(auchPoint[0][0][1], POINT_WIDTH * s * 3, auchBoard + coord(BEAROFF_WIDTH, BORDER_HEIGHT), boardStride, POINT_WIDTH * s, POINT_HEIGHT * s); CopyArea(auchPoint[0][1][0], POINT_WIDTH * s * 3, auchBoard + coord(BEAROFF_WIDTH + POINT_WIDTH, BOARD_HEIGHT / 2 + BOARD_CENTER_HEIGHT / 2), boardStride, POINT_WIDTH * s, POINT_HEIGHT * s); CopyArea(auchPoint[0][1][1], POINT_WIDTH * s * 3, auchBoard + coord(BEAROFF_WIDTH + POINT_WIDTH, BOARD_HEIGHT / 2 + BOARD_CENTER_HEIGHT / 2), boardStride, POINT_WIDTH * s, POINT_HEIGHT * s); CopyArea(auchPoint[1][0][0], POINT_WIDTH * s * 3, auchBoard + coord(BEAROFF_WIDTH + POINT_WIDTH, BORDER_HEIGHT), boardStride, POINT_WIDTH * s, POINT_HEIGHT * s); CopyArea(auchPoint[1][0][1], POINT_WIDTH * s * 3, auchBoard + coord(BEAROFF_WIDTH + POINT_WIDTH, BORDER_HEIGHT), boardStride, POINT_WIDTH * s, POINT_HEIGHT * s); CopyArea(auchPoint[1][1][0], POINT_WIDTH * s * 3, auchBoard + coord(BEAROFF_WIDTH, BOARD_HEIGHT / 2 + BOARD_CENTER_HEIGHT / 2), boardStride, POINT_WIDTH * s, POINT_HEIGHT * s); CopyArea(auchPoint[1][1][1], POINT_WIDTH * s * 3, auchBoard + coord(BEAROFF_WIDTH, BOARD_HEIGHT / 2 + BOARD_CENTER_HEIGHT / 2), boardStride, POINT_WIDTH * s, POINT_HEIGHT * s); /* Bear off trays */ CopyArea(auchOff[0], BEAROFF_WIDTH * s * 3, auchBoard + coord(BOARD_WIDTH - BEAROFF_WIDTH, BORDER_HEIGHT), boardStride, BEAROFF_WIDTH * s, BEAROFF_HEIGHT * s); CopyArea(auchOff[1], BEAROFF_WIDTH * s * 3, auchBoard + coord(BOARD_WIDTH - BEAROFF_WIDTH, BOARD_HEIGHT / 2 + BOARD_CENTER_HEIGHT / 2), boardStride, BEAROFF_WIDTH * s, BEAROFF_HEIGHT * s); /* Bar areas */ CopyArea(auchBar[0], BAR_WIDTH * s * 3, auchBoard + coord(BOARD_WIDTH / 2 - BAR_WIDTH / 2, BORDER_HEIGHT + CUBE_HEIGHT), boardStride, BAR_WIDTH * s, (POINT_HEIGHT - CUBE_HEIGHT) * s); CopyArea(auchBar[1], BAR_WIDTH * s * 3, auchBoard + coord(BOARD_WIDTH / 2 - BAR_WIDTH / 2, BOARD_HEIGHT / 2 + BOARD_CENTER_HEIGHT / 2), boardStride, BAR_WIDTH * s, (POINT_HEIGHT - CUBE_HEIGHT) * s); for (i = 1; i <= 5; i++) { for (j = 0; j < 2; j++) { /* 1-5 chequers, both colours, down point */ RefractBlend(auchPoint[0][0][j] + coordStride(0, CHEQUER_HEIGHT * (i - 1), POINT_WIDTH * s * 3), POINT_WIDTH * s * 3, auchBoard + coord(BEAROFF_WIDTH, BORDER_HEIGHT + CHEQUER_HEIGHT * (i - 1)), boardStride, auchChequer[j], CHEQUER_WIDTH * s * 4, asRefract[j], CHEQUER_WIDTH * s, CHEQUER_WIDTH * s, CHEQUER_HEIGHT * s); sprintf(pchFile, "b-gd-%c%d.png", j ? 'o' : 'x', i); WriteImageStride(auchPoint[0][0][j], POINT_WIDTH * s * 3, POINT_WIDTH * s, POINT_HEIGHT * s); } for (j = 0; j < 2; j++) { /* 1-5 chequers, both colours, other down point */ RefractBlend(auchPoint[1][0][j] + coordStride(0, CHEQUER_HEIGHT * (i - 1), POINT_WIDTH * s * 3), POINT_WIDTH * s * 3, auchBoard + coord(BEAROFF_WIDTH + POINT_WIDTH, BORDER_HEIGHT + CHEQUER_HEIGHT * (i - 1)), boardStride, auchChequer[j], CHEQUER_WIDTH * s * 4, asRefract[j], CHEQUER_WIDTH * s, CHEQUER_WIDTH * s, CHEQUER_HEIGHT * s); sprintf(pchFile, "b-rd-%c%d.png", j ? 'o' : 'x', i); WriteImageStride(auchPoint[1][0][j], POINT_WIDTH * s * 3, POINT_WIDTH * s, POINT_HEIGHT * s); } for (j = 0; j < 2; j++) { /* 1-5 chequers, both colours, up point */ RefractBlend(auchPoint[0][1][j] + coordStride(0, CHEQUER_HEIGHT * (5 - i), POINT_WIDTH * s * 3), POINT_WIDTH * s * 3, auchBoard + coord(BEAROFF_WIDTH + POINT_WIDTH, BOARD_HEIGHT - BORDER_HEIGHT - CHEQUER_HEIGHT * i), boardStride, auchChequer[j], CHEQUER_WIDTH * s * 4, asRefract[j], CHEQUER_WIDTH * s, CHEQUER_WIDTH * s, CHEQUER_HEIGHT * s); sprintf(pchFile, "b-gu-%c%d.png", j ? 'o' : 'x', i); WriteImageStride(auchPoint[0][1][j], POINT_WIDTH * s * 3, POINT_WIDTH * s, POINT_HEIGHT * s); } for (j = 0; j < 2; j++) { /* 1-5 chequers, both colours, other up point */ RefractBlend(auchPoint[1][1][j] + coordStride(0, CHEQUER_HEIGHT * (5 - i), POINT_WIDTH * s * 3), POINT_WIDTH * s * 3, auchBoard + coord(BEAROFF_WIDTH, BOARD_HEIGHT - BORDER_HEIGHT - CHEQUER_HEIGHT * i), boardStride, auchChequer[j], CHEQUER_WIDTH * s * 4, asRefract[j], CHEQUER_WIDTH * s, CHEQUER_WIDTH * s, CHEQUER_HEIGHT * s); sprintf(pchFile, "b-ru-%c%d.png", j ? 'o' : 'x', i); WriteImageStride(auchPoint[1][1][j], POINT_WIDTH * s * 3, POINT_WIDTH * s, POINT_HEIGHT * s); } /* 1-5 chequers in bear-off trays */ RefractBlend(auchOff[0] + coordStride(BORDER_WIDTH, CHEQUER_HEIGHT * (i - 1), BEAROFF_WIDTH * s * 3), BEAROFF_WIDTH * s * 3, auchBoard + coord(BOARD_WIDTH - BORDER_WIDTH - CHEQUER_WIDTH, BORDER_HEIGHT + CHEQUER_HEIGHT * (i - 1)), boardStride, auchChequer[0], CHEQUER_WIDTH * s * 4, asRefract[0], CHEQUER_WIDTH * s, CHEQUER_WIDTH * s, CHEQUER_HEIGHT * s); sprintf(pchFile, "b-roff-x%d.png", i); WriteImageStride(auchOff[0], BEAROFF_WIDTH * s * 3, BEAROFF_WIDTH * s, BEAROFF_HEIGHT * s); RefractBlend(auchOff[1] + coordStride(BORDER_WIDTH, CHEQUER_HEIGHT * (5 - i), BEAROFF_WIDTH * s * 3), BEAROFF_WIDTH * s * 3, auchBoard + coord(BOARD_WIDTH - BORDER_WIDTH - CHEQUER_WIDTH, BOARD_HEIGHT - BORDER_HEIGHT - CHEQUER_HEIGHT * i), boardStride, auchChequer[1], CHEQUER_WIDTH * s * 4, asRefract[1], CHEQUER_WIDTH * s, CHEQUER_WIDTH * s, CHEQUER_HEIGHT * s); sprintf(pchFile, "b-roff-o%d.png", i); WriteImageStride(auchOff[1], BEAROFF_WIDTH * s * 3, BEAROFF_WIDTH * s, BEAROFF_HEIGHT * s); } for (i = 6; i <= 15; i++) { for (j = 0; j < 2; j++) { /* 6-15 chequers, both colours, down point */ CopyArea(auchPoint[0][0][j] + coordStride(1, CHEQUER_HEIGHT * 4 + 1, POINT_WIDTH * s * 3), POINT_WIDTH * s * 3, auchChequerLabels + coordStride(0, (i - 4) * CHEQUER_LABEL_HEIGHT, CHEQUER_LABEL_WIDTH * s * 3), CHEQUER_LABEL_WIDTH * s * 3, CHEQUER_LABEL_WIDTH * s, CHEQUER_LABEL_HEIGHT * s); sprintf(pchFile, "b-gd-%c%d.png", j ? 'o' : 'x', i); WriteImageStride(auchPoint[0][0][j], POINT_WIDTH * s * 3, POINT_WIDTH * s, POINT_HEIGHT * s); } for (j = 0; j < 2; j++) { /* 6-15 chequers, both colours, other down point */ CopyArea(auchPoint[1][0][j] + coordStride(1, CHEQUER_HEIGHT * 4 + 1, POINT_WIDTH * s * 3), POINT_WIDTH * s * 3, auchChequerLabels + coordStride(0, (i - 4) * CHEQUER_LABEL_HEIGHT, CHEQUER_LABEL_WIDTH * s * 3), CHEQUER_LABEL_WIDTH * s * 3, CHEQUER_LABEL_WIDTH * s, CHEQUER_LABEL_HEIGHT * s); sprintf(pchFile, "b-rd-%c%d.png", j ? 'o' : 'x', i); WriteImageStride(auchPoint[1][0][j], POINT_WIDTH * s * 3, POINT_WIDTH * s, POINT_HEIGHT * s); } for (j = 0; j < 2; j++) { /* 6-15 chequers, both colours, up point */ CopyArea(auchPoint[0][1][j] + coordStride(1, 1, POINT_WIDTH * s * 3), POINT_WIDTH * s * 3, auchChequerLabels + coordStride(0, (i - 4) * CHEQUER_LABEL_HEIGHT, CHEQUER_LABEL_WIDTH * s * 3), CHEQUER_LABEL_WIDTH * s * 3, CHEQUER_LABEL_WIDTH * s, CHEQUER_LABEL_HEIGHT * s); sprintf(pchFile, "b-gu-%c%d.png", j ? 'o' : 'x', i); WriteImageStride(auchPoint[0][1][j], POINT_WIDTH * s * 3, POINT_WIDTH * s, POINT_HEIGHT * s); } for (j = 0; j < 2; j++) { /* 6-15 chequers, both colours, other up point */ CopyArea(auchPoint[1][1][j] + coordStride(1, 1, POINT_WIDTH * s * 3), POINT_WIDTH * s * 3, auchChequerLabels + coordStride(0, (i - 4) * CHEQUER_LABEL_HEIGHT, CHEQUER_LABEL_WIDTH * s * 3), CHEQUER_LABEL_WIDTH * s * 3, CHEQUER_LABEL_WIDTH * s, CHEQUER_LABEL_HEIGHT * s); sprintf(pchFile, "b-ru-%c%d.png", j ? 'o' : 'x', i); WriteImageStride(auchPoint[1][1][j], POINT_WIDTH * s * 3, POINT_WIDTH * s, POINT_HEIGHT * s); } /* 6-15 chequers in bear-off trays */ CopyArea(auchOff[0] + coordStride(CHEQUER_LABEL_WIDTH, CHEQUER_HEIGHT * 4 + 1, BEAROFF_WIDTH * s * 3), BEAROFF_WIDTH * s * 3, auchChequerLabels + coordStride(0, (i - 4) * CHEQUER_LABEL_HEIGHT, CHEQUER_LABEL_WIDTH * s * 3), CHEQUER_LABEL_WIDTH * s * 3, CHEQUER_LABEL_WIDTH * s, CHEQUER_LABEL_HEIGHT * s); sprintf(pchFile, "b-roff-x%d.png", i); WriteImageStride(auchOff[0], BEAROFF_WIDTH * s * 3, BEAROFF_WIDTH * s, BEAROFF_HEIGHT * s); CopyArea(auchOff[1] + coordStride(CHEQUER_LABEL_WIDTH, 1, BEAROFF_WIDTH * s * 3), BEAROFF_WIDTH * s * 3, auchChequerLabels + coordStride(0, (i - 4) * CHEQUER_LABEL_HEIGHT, CHEQUER_LABEL_WIDTH * s * 3), CHEQUER_LABEL_WIDTH * s * 3, CHEQUER_LABEL_WIDTH * s, CHEQUER_LABEL_HEIGHT * s); sprintf(pchFile, "b-roff-o%d.png", i); WriteImageStride(auchOff[1], BEAROFF_WIDTH * s * 3, BEAROFF_WIDTH * s, BEAROFF_HEIGHT * s); } /* 0-15 chequers on bar */ WriteStride("b-bar-o0.png", auchBar[0], BAR_WIDTH * s * 3, BAR_WIDTH * s, (POINT_HEIGHT - CUBE_HEIGHT) * s); WriteStride("b-bar-x0.png", auchBar[1], BAR_WIDTH * s * 3, BAR_WIDTH * s, (POINT_HEIGHT - CUBE_HEIGHT) * s); for (i = 1; i <= 3; i++) { RefractBlend(auchBar[0] + coordStride(BAR_WIDTH / 2 - CHEQUER_WIDTH / 2, (CHEQUER_HEIGHT + 1) * (3 - i) + 1, BAR_WIDTH * s * 3), BAR_WIDTH * s * 3, auchBoard + coord(BOARD_WIDTH / 2 - CHEQUER_WIDTH / 2, (BORDER_HEIGHT + CUBE_HEIGHT) + (CHEQUER_HEIGHT + 1) * (3 - i)), boardStride, auchChequer[0], CHEQUER_WIDTH * s * 4, asRefract[0], CHEQUER_WIDTH * s, CHEQUER_WIDTH * s, CHEQUER_HEIGHT * s); sprintf(pchFile, "b-bar-o%d.png", i); WriteImageStride(auchBar[0], BAR_WIDTH * s * 3, BAR_WIDTH * s, (POINT_HEIGHT - CUBE_HEIGHT) * s); RefractBlend(auchBar[1] + coordStride(BAR_WIDTH / 2 - CHEQUER_WIDTH / 2, (CHEQUER_HEIGHT + 1) * (i - 1) + 1, BAR_WIDTH * s * 3), BAR_WIDTH * s * 3, auchBoard + coord(BOARD_WIDTH / 2 - CHEQUER_WIDTH / 2, (BOARD_HEIGHT / 2 + BOARD_CENTER_HEIGHT / 2) + (CHEQUER_HEIGHT + 1) * (i - 1)), boardStride, auchChequer[1], CHEQUER_WIDTH * s * 4, asRefract[1], CHEQUER_WIDTH * s, CHEQUER_WIDTH * s, CHEQUER_HEIGHT * s); sprintf(pchFile, "b-bar-x%d.png", i); WriteImageStride(auchBar[1], BAR_WIDTH * s * 3, BAR_WIDTH * s, (POINT_HEIGHT - CUBE_HEIGHT) * s); } for (i = 4; i <= 15; i++) { CopyArea(auchBar[0] + coordStride(CHEQUER_LABEL_WIDTH, 2, BAR_WIDTH * s * 3), BAR_WIDTH * s * 3, auchChequerLabels + coordStride(0, (i - 4) * CHEQUER_LABEL_HEIGHT, CHEQUER_LABEL_WIDTH * s * 3), CHEQUER_LABEL_WIDTH * s * 3, CHEQUER_LABEL_WIDTH * s, CHEQUER_LABEL_HEIGHT * s); sprintf(pchFile, "b-bar-o%d.png", i); WriteImageStride(auchBar[0], BAR_WIDTH * s * 3, BAR_WIDTH * s, (POINT_HEIGHT - CUBE_HEIGHT) * s); CopyArea(auchBar[1] + coordStride(CHEQUER_LABEL_WIDTH, POINT_HEIGHT - CUBE_HEIGHT - CHEQUER_HEIGHT, BAR_WIDTH * s * 3), BAR_WIDTH * s * 3, auchChequerLabels + coordStride(0, (i - 4) * CHEQUER_LABEL_HEIGHT, CHEQUER_LABEL_WIDTH * s * 3), CHEQUER_LABEL_WIDTH * s * 3, CHEQUER_LABEL_WIDTH * s, CHEQUER_LABEL_HEIGHT * s); sprintf(pchFile, "b-bar-x%d.png", i); WriteImageStride(auchBar[1], BAR_WIDTH * s * 3, BAR_WIDTH * s, (POINT_HEIGHT - CUBE_HEIGHT) * s); } /* cube - top and bottom of bar */ for (i = 0; i < 2; i++) { int offset; int cube_y = i ? ((BOARD_HEIGHT - BORDER_HEIGHT) * s - CUBE_HEIGHT * ss) : (BORDER_HEIGHT * s); AlphaBlendBase(auchBoard + (BOARD_WIDTH / 2) * s * 3 - (CUBE_WIDTH / 2) * ss * 3 + cube_y * boardStride, boardStride, auchBoard + (BOARD_WIDTH / 2) * s * 3 - (CUBE_WIDTH / 2) * ss * 3 + cube_y * boardStride, boardStride, auchCube, CUBE_WIDTH * ss * 4, CUBE_WIDTH * ss, CUBE_HEIGHT * ss); offset = i ? coord(BOARD_WIDTH / 2 - BAR_WIDTH / 2, BOARD_HEIGHT - BORDER_HEIGHT - CUBE_HEIGHT) : coord(BOARD_WIDTH / 2 - BAR_WIDTH / 2, BORDER_HEIGHT); for (j = 0; j < 12; j++) { CopyAreaRotateClip(auchBoard, boardStride, (BOARD_WIDTH / 2) * s - (CUBE_WIDTH / 2) * ss + ss, cube_y + ss, BOARD_WIDTH * s, BOARD_HEIGHT * s, auchCubeFaces, CUBE_LABEL_WIDTH * ss * 3, 0, CUBE_LABEL_HEIGHT * ss * j, ss * CUBE_LABEL_WIDTH, ss * CUBE_LABEL_HEIGHT, 2 - 2 * i); sprintf(pchFile, "b-%s-%d.png", i ? "cb" : "ct", 2 << j); WriteImage(auchBoard + offset, BAR_WIDTH * s, CUBE_HEIGHT * s); if (j == 5) { /* 64 cube is also the cube for 1 */ sprintf(pchFile, "b-%sc-1.png", i ? "cb" : "ct"); WriteImage(auchBoard + offset, BAR_WIDTH * s, CUBE_HEIGHT * s); } } } /* cube - doubles */ for (i = 0; i < 2; i++) { int offset; CopyArea(auchMidBoard, BOARD_CENTER_WIDTH * s * 3, auchBoard + coord(i ? BOARD_WIDTH / 2 + BAR_WIDTH / 2 : BEAROFF_WIDTH, BOARD_HEIGHT / 2 - BOARD_CENTER_HEIGHT / 2), boardStride, BOARD_CENTER_WIDTH * s, BOARD_CENTER_HEIGHT * s); offset = ((BOARD_CENTER_HEIGHT / 2) * s - (CUBE_HEIGHT / 2) * ss) * BOARD_CENTER_WIDTH * s * 3 + 3 * POINT_WIDTH * s * 3 - (CUBE_WIDTH / 2) * ss * 3; AlphaBlendBase(auchMidBoard + offset, BOARD_CENTER_WIDTH * s * 3, auchMidBoard + offset, BOARD_CENTER_WIDTH * s * 3, auchCube, CUBE_WIDTH * ss * 4, CUBE_WIDTH * ss, CUBE_HEIGHT * ss); for (j = 0; j < 12; j++) { CopyAreaRotateClip(auchMidBoard, BOARD_CENTER_WIDTH * s * 3, POINT_WIDTH * s * 3 - ss * CUBE_LABEL_WIDTH / 2, (BOARD_CENTER_HEIGHT / 2) * s - (CUBE_LABEL_HEIGHT / 2) * ss, BOARD_CENTER_WIDTH * s, BOARD_CENTER_HEIGHT * s, auchCubeFaces, CUBE_LABEL_WIDTH * ss * 3, 0, CUBE_LABEL_HEIGHT * ss * j, ss * CUBE_LABEL_WIDTH, ss * CUBE_LABEL_HEIGHT, i << 1); sprintf(pchFile, "b-mid%c-c%d.png", i ? 'r' : 'l', 2 << j); WriteImageStride(auchMidBoard, BOARD_CENTER_WIDTH * s * 3, BOARD_CENTER_WIDTH * s, BOARD_CENTER_HEIGHT * s); } } /* cube - centered */ AlphaBlendBase(auchBoard + ((BOARD_HEIGHT / 2) * s - (CUBE_HEIGHT / 2) * ss) * boardStride + (BOARD_WIDTH / 2) * s * 3 - (CUBE_WIDTH / 2) * ss * 3, boardStride, auchBoard + ((BOARD_HEIGHT / 2) * s - (CUBE_HEIGHT / 2) * ss) * boardStride + (BOARD_WIDTH / 2) * s * 3 - (CUBE_WIDTH / 2) * ss * 3, boardStride, auchCube, CUBE_WIDTH * ss * 4, CUBE_WIDTH * ss, CUBE_HEIGHT * ss); for (j = 0; j < 12; j++) { CopyAreaRotateClip(auchBoard, boardStride, (BOARD_WIDTH / 2) * s - (CUBE_WIDTH / 2) * ss + ss, (BOARD_HEIGHT / 2) * s - (CUBE_HEIGHT / 2) * ss + ss, BOARD_WIDTH * s, BOARD_HEIGHT * s, auchCubeFaces, CUBE_LABEL_WIDTH * ss * 3, 0, CUBE_LABEL_HEIGHT * ss * j, CUBE_LABEL_WIDTH * ss, CUBE_LABEL_HEIGHT * ss, 1); sprintf(pchFile, "b-midc-%d.png", 2 << j); WriteImage(auchBoard + coord((BOARD_WIDTH / 2) - (BAR_WIDTH / 2), ((BOARD_HEIGHT / 2) - (BOARD_CENTER_HEIGHT / 2))), BAR_WIDTH * s, BOARD_CENTER_HEIGHT * s); if (j == 5) { /* 64 cube is also the cube for 1 */ Write("b-midc-1.png", auchBoard + coord((BOARD_WIDTH / 2) - (BAR_WIDTH / 2), ((BOARD_HEIGHT / 2) - (BOARD_CENTER_HEIGHT / 2))), BAR_WIDTH * s, BOARD_CENTER_HEIGHT * s); } } /* dice rolls */ for (i = 0; i < 2; i++) { int dice_x = (BEAROFF_WIDTH + 3 * POINT_WIDTH + (6 * POINT_WIDTH + BAR_WIDTH) * i) * s * 3 - (DIE_WIDTH / 2) * ss * 3; int dice_y = ((BOARD_HEIGHT / 2) * s - (DIE_HEIGHT / 2) * ss) * boardStride; AlphaBlendBase(auchBoard + dice_x - DIE_WIDTH * ss * 3 + dice_y, boardStride, auchBoard + dice_x - DIE_WIDTH * ss * 3 + dice_y, boardStride, auchDice[i], DIE_WIDTH * ss * 4, DIE_WIDTH * ss, DIE_HEIGHT * ss); AlphaBlendBase(auchBoard + dice_x + DIE_WIDTH * ss * 3 + dice_y, boardStride, auchBoard + dice_x + DIE_WIDTH * ss * 3 + dice_y, boardStride, auchDice[i], DIE_WIDTH * ss * 4, DIE_WIDTH * ss, DIE_HEIGHT * ss); for (j = 0; j < 6; j++) { for (k = 0; k < 6; k++) { CopyArea(auchMidBoard, BOARD_CENTER_WIDTH * s * 3, auchBoard + coord(i ? BOARD_WIDTH / 2 + BAR_WIDTH / 2 : BEAROFF_WIDTH, BORDER_HEIGHT + POINT_HEIGHT), boardStride, BOARD_CENTER_WIDTH * s, BOARD_CENTER_HEIGHT * s); DrawPips(auchMidBoard + 3 * POINT_WIDTH * s * 3 - (DIE_WIDTH / 2) * ss * 3 - DIE_WIDTH * ss * 3 + ((BOARD_CENTER_HEIGHT / 2) * s - (DIE_HEIGHT / 2) * ss) * BOARD_CENTER_WIDTH * s * 3, BOARD_CENTER_WIDTH * s * 3, auchPips[i], j + 1); DrawPips(auchMidBoard + 3 * POINT_WIDTH * s * 3 - (DIE_WIDTH / 2) * ss * 3 + DIE_WIDTH * ss * 3 + ((BOARD_CENTER_HEIGHT / 2) * s - (DIE_HEIGHT / 2) * ss) * BOARD_CENTER_WIDTH * s * 3, BOARD_CENTER_WIDTH * s * 3, auchPips[i], k + 1); sprintf(pchFile, "b-mid%c-%c%d%d.png", i ? 'r' : 'l', i ? 'o' : 'x', j + 1, k + 1); WriteImageStride(auchMidBoard, BOARD_CENTER_WIDTH * s * 3, BOARD_CENTER_WIDTH * s, BOARD_CENTER_HEIGHT * s); } } } if (imagesWritten != NUM_IMAGES) g_print(_("Wrong number of images generated - %d written, expected %d\n"), imagesWritten, NUM_IMAGES); } static void RenderObjects(void) { int clockwise; renderdata rd; CopyAppearance(&rd); rd.fLabels = TRUE; rd.nSize = s; #if defined(USE_BOARD3D) /* Use 2d colours for dice */ rd.fDisplayType = DT_2D; #endif RenderBoard(&rd, auchBoard, boardStride); RenderChequers(&rd, auchChequer[0], auchChequer[1], asRefract[0], asRefract[1], CHEQUER_WIDTH * s * 4); RenderChequerLabels(&rd, auchChequerLabels, CHEQUER_LABEL_WIDTH * s * 3); #if defined(USE_GTK) && defined(HAVE_CAIRO) RenderArrows(&rd, auchArrow[0], auchArrow[1], s * ARROW_WIDTH * 4, rd.fClockwise); #endif /* Render numbers in both directions */ clockwise = rd.fClockwise; rd.fClockwise = TRUE; RenderBoardLabels(&rd, auchLo, auchHi, BOARD_WIDTH * s * 4); rd.fClockwise = FALSE; RenderBoardLabels(&rd, auchLoRev, auchHiRev, BOARD_WIDTH * s * 4); rd.fClockwise = clockwise; /* cubes and dice are rendered a bit smaller */ rd.nSize = ss; RenderCube(&rd, auchCube, CUBE_WIDTH * ss * 4); RenderCubeFaces(&rd, auchCubeFaces, CUBE_LABEL_WIDTH * ss * 3, auchCube, CUBE_WIDTH * ss * 4); RenderDice(&rd, auchDice[0], auchDice[1], DIE_WIDTH * ss * 4, TRUE); RenderPips(&rd, auchPips[0], auchPips[1], ss * 3); } static char * GetFilenameBase(char *sz) { sz = NextToken(&sz); if (!sz || !*sz) { outputf(_("You must specify a directory to export to (see `%s')\n"), "help export htmlimages"); return NULL; } if (!g_file_test(sz, G_FILE_TEST_IS_DIR) && g_mkdir(sz, 0777) < 0) { outputerr(sz); return NULL; } szFile = g_malloc(strlen(sz) + 32); strcpy(szFile, sz); if (szFile[strlen(szFile) - 1] != '/') strcat(szFile, "/"); pchFile = strchr(szFile, 0); return szFile; } static void AllocObjects(void) { int i, j, k; s = exsExport.nHtmlSize; auchMidlb = malloc((BOARD_WIDTH * s * 3 * BOARD_HEIGHT * s) * sizeof(unsigned char)); #if defined(USE_GTK) auchArrow[0] = malloc(s * ARROW_WIDTH * 4 * s * ARROW_HEIGHT); auchArrow[1] = malloc(s * ARROW_WIDTH * 4 * s * ARROW_HEIGHT); #endif /* Initialise this one else valgrind reports * use of uninitialised values in libpng */ auchBoard = calloc(BOARD_WIDTH * s * 3 * BOARD_HEIGHT * s, sizeof(unsigned char)); for (i = 0; i < 2; i++) auchChequer[i] = malloc((CHEQUER_WIDTH * s * 4 * CHEQUER_HEIGHT * s) * sizeof(unsigned char)); auchChequerLabels = malloc((12 * CHEQUER_LABEL_WIDTH * s * 3 * CHEQUER_LABEL_HEIGHT * s) * sizeof(unsigned char)); auchLo = malloc((BOARD_WIDTH * s * 4 * BORDER_HEIGHT * s) * sizeof(unsigned char)); auchHi = malloc((BOARD_WIDTH * s * 4 * BORDER_HEIGHT * s) * sizeof(unsigned char)); auchLoRev = malloc((BOARD_WIDTH * s * 4 * BORDER_HEIGHT * s) * sizeof(unsigned char)); auchHiRev = malloc((BOARD_WIDTH * s * 4 * BORDER_HEIGHT * s) * sizeof(unsigned char)); auchCube = malloc((CUBE_WIDTH * ss * 4 * CUBE_HEIGHT * ss) * sizeof(unsigned char)); auchCubeFaces = malloc((12 * CUBE_LABEL_WIDTH * ss * 3 * CUBE_LABEL_HEIGHT * ss) * sizeof(unsigned char)); for (i = 0; i < 2; i++) { auchDice[i] = malloc((DIE_WIDTH * ss * 4 * DIE_HEIGHT * ss) * sizeof(unsigned char)); auchPips[i] = malloc((ss * ss * 3) * sizeof(unsigned char)); } auchLabel = malloc((BOARD_WIDTH * s * 3 * BOARD_HEIGHT * s) * sizeof(unsigned char)); for (i = 0; i < 2; i++) auchOff[i] = malloc((BEAROFF_WIDTH * s * 3 * DISPLAY_BEAROFF_HEIGHT * s) * sizeof(unsigned char)); auchMidBoard = malloc((BOARD_CENTER_WIDTH * s * 3 * BOARD_CENTER_HEIGHT * s) * sizeof(unsigned char)); for (i = 0; i < 2; i++) auchBar[i] = malloc((BAR_WIDTH * s * 3 * (POINT_HEIGHT - CUBE_HEIGHT) * s) * sizeof(unsigned char)); for (i = 0; i < 2; i++) for (j = 0; j < 2; j++) for (k = 0; k < 2; k++) auchPoint[i][j][k] = malloc((POINT_WIDTH * s * 3 * DISPLAY_POINT_HEIGHT * s) * sizeof(unsigned char)); for (i = 0; i < 2; i++) asRefract[i] = malloc((CHEQUER_WIDTH * s * CHEQUER_HEIGHT * s) * sizeof(unsigned short)); } static void TidyObjects(void) { int i, j, k; free(auchMidlb); #if defined(USE_GTK) free(auchArrow[0]); free(auchArrow[1]); #endif g_free(szFile); free(auchBoard); for (i = 0; i < 2; i++) free(auchChequer[i]); free(auchChequerLabels); free(auchLo); free(auchHi); free(auchLoRev); free(auchHiRev); free(auchCube); free(auchCubeFaces); for (i = 0; i < 2; i++) { free(auchDice[i]); free(auchPips[i]); } free(auchLabel); for (i = 0; i < 2; i++) free(auchOff[i]); free(auchMidBoard); for (i = 0; i < 2; i++) free(auchBar[i]); for (i = 0; i < 2; i++) for (j = 0; j < 2; j++) for (k = 0; k < 2; k++) free(auchPoint[i][j][k]); for (i = 0; i < 2; i++) free(asRefract[i]); } extern void CommandExportHTMLImages(char *sz) { szFile = GetFilenameBase(sz); ProgressStartValue(_("Generating image:"), NUM_IMAGES); AllocObjects(); RenderObjects(); WriteImages(); TidyObjects(); ProgressEnd(); } #else /* not HAVE_LIBPNG */ extern void CommandExportHTMLImages(char *UNUSED(sz)) { outputl(_("This installation of GNU Backgammon was compiled without\n" "support for writing HTML images.")); } #endif /* not HAVE_LIBPNG */