first maemo release
[mancala] / src / graphics.c
1 /*  
2  *  Graphics Routines -- graphics.c
3  *  $Id: graphics.c,v 1.1.2.20 2004/01/14 05:18:19 sparrow_hawk Exp $
4  *
5  *  Copyright (C) 2003 Kevin Riggle 
6  *  http://cmancala.sourcefoge.net
7  *  Copyright (C) 2009 Reto Zingg
8  *
9  *  This program is free software; you can redistribute it and/or modify it
10  *  under the terms of the GNU General Public License as published by the
11  *  Free Software Foundation; either version 2, or (at your option) any
12  *  later version.
13  *
14  *  This program is distributed in the hope that it will be useful, but
15  *  WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  General Public License for more details, a copy of which may be found in
18  *  the file COPYING provided in the main directory of this release.
19  *
20  */
21
22 #include <stdio.h>
23
24 #include "SDL.h"
25 #include "SDL_endian.h" /* Used for the endian-dependent 24 bpp mode */
26
27 #include "SDL_image.h"
28 #include "SDL_ttf.h"
29
30 #include "graphics.h"
31 #include "main.h"
32 #include "mancala.h"
33 #include "play.h"
34
35 static SDL_Surface *ShiftColors(SDL_Surface *old, Uint8 red, Uint8 blue, Uint8 green, Uint8 alpha);
36
37 SDL_Surface *LoadRes(char *filename) {
38
39         return IMG_LoadPNG_RW(SDL_RWFromFile(filename, "r"));
40
41 }
42
43
44 SDL_Rect SurfaceToRect(SDL_Surface *src) {
45
46         SDL_Rect dest;
47
48         dest.x = 0;
49         dest.y = 0;
50         dest.w = src->w;
51         dest.h = src->h;
52
53         return dest;
54
55 }
56
57 /* create a new, blank surface with another's properties */
58 static SDL_Surface *NewSurfaceFrom(SDL_Surface *old, Uint32 flags) {
59
60         return SDL_CreateRGBSurface(
61                         flags, old->w, old->h, old->format->BitsPerPixel,
62                         old->format->Rmask, old->format->Gmask, 
63                         old->format->Bmask, old->format->Amask
64         );
65
66 }
67
68 static SDL_Surface *FillHole(int stones, TTF_Font *font, 
69                                 SDL_Surface **stone_gfx) {
70
71         SDL_Surface *text;
72         SDL_Color font_color;
73         char stone_string[STRING_MAX];
74         int w, h;
75
76         /* do we have a graphic for this number of stones? */
77         if (stones <= STONE_MAX) {
78
79                 return *(stone_gfx + stones);
80         }
81         else {
82                 font_color.r = 128;
83                 font_color.g = 128;
84                 font_color.b = 128;
85                 /* convert the integer to text */
86                 if (sprintf(stone_string, "%d", stones)<=0)
87                         fprintf(stderr, "String conversion problem.\n");
88                 /* get the size of the rendered text */
89                 if (TTF_SizeText(font, stone_string, &w, &h)<0) 
90                         fprintf(stderr, "SDL_ttf: %s\n", TTF_GetError());
91                 /* if the text is too large, render a '?' */
92                 if ((w > (*stone_gfx)->w) || (h > (*stone_gfx)->h))
93                         sprintf(stone_string, "?");
94                 if (!(text = TTF_RenderText_Blended(font, stone_string, 
95                         font_color))) {
96                         fprintf(stderr, "SDL_ttf: %s\n", TTF_GetError());
97                         return NULL;
98                 }
99                 return text;
100         }
101
102         /* NEVER REACHED */
103         return NULL;
104 }
105
106
107 SDL_Surface *DrawBoard(int *aiBoard, int *humanBoard,
108                         TTF_Font *board_font, TTF_Font *home_font,
109                         SDL_Surface *tile, SDL_Surface **stone_gfx,
110                         int active, int highlight) {
111
112         SDL_Surface *board, *stones;
113         SDL_Rect tile_rect, blit_rect;
114         SDL_Color home_color;
115         char home_string[STRING_MAX];
116         int i;
117
118         /* initialize the board surface */
119         board = SDL_CreateRGBSurface(SDL_SWSURFACE, tile->w*(BOARD_MAX+2),
120                 tile->h*2, tile->format->BitsPerPixel, 0, 0, 0, 0);
121         if (!board) {
122                 fprintf(stderr, "DrawBoard: %s\n", SDL_GetError());
123                 return NULL;
124         }
125
126         tile_rect = SurfaceToRect(tile);
127         /*printf("tile is %dx%d\n", tile_rect.w, tile_rect.h);*/
128
129         /* set the color of text in the home */
130         home_color.r = 0;
131         home_color.g = 0;
132         home_color.b = 0;
133
134         for (i=0; i<=BOARD_MAX+1; i++)
135         {
136                 /* update current tile location */
137                 tile_rect.x = i * tile_rect.w;
138                 tile_rect.y = 0;
139                 /*printf("Currently a %dx%d rectangle at %d,%d.\n", tile_rect.w,
140                         tile_rect.h, tile_rect.x, tile_rect.y);*/
141                 blit_rect = tile_rect;
142                 /* is this is the first or last tile? */
143                 if ((i==0) || (i==BOARD_MAX+1)) {
144                         /* make it blank */
145                         if (SDL_BlitSurface(tile, NULL, board, &blit_rect)<0)
146                                 fprintf(stderr,"DrawBoard: %s\n", 
147                                         SDL_GetError());
148                         blit_rect = tile_rect;
149                         blit_rect.y = blit_rect.h;
150                         SDL_BlitSurface(tile, NULL, board, &blit_rect);
151                         /* render the number of stones in each home */
152                         if (i==0) {
153                                 if (sprintf(home_string,"%d",humanBoard[0])<=0)
154                                         printf("Human string problems.\n");
155                         }
156                         else {
157                                 if (sprintf(home_string, "%d", aiBoard[0])<=0)
158                                         printf("AI string problems.\n");
159                         }
160                         if (!(stones = TTF_RenderText_Blended(home_font, 
161                                 home_string, home_color)))
162                                 fprintf(stderr, "DrawBoard: %s\n", 
163                                         TTF_GetError());
164                         blit_rect.w = stones->w;
165                         blit_rect.h = stones->h;
166                         blit_rect.x += ((tile_rect.w - blit_rect.w)/2);
167                         blit_rect.y = ((tile_rect.h*2 - blit_rect.h)/2);
168                         SDL_BlitSurface(stones, NULL, board, &blit_rect);
169                 }
170                 /* otherwise, draw a hole and fill it */
171                 else {
172                         SDL_BlitSurface(stone_gfx[0], NULL, board, &blit_rect);
173                         if (humanBoard[i] > 0) {
174                                 if (!(stones = FillHole(humanBoard[i], 
175                                         board_font, stone_gfx)))
176                                         fprintf(stderr,"FillHole() problems\n");
177                                 if (i == highlight)
178                                         stones = ShiftColors(stones,128,128,128,255);
179                                 if (active == 1)
180                                         stones = ShiftColors(stones,0,0,0,160);
181                                 blit_rect.w = stones->w;
182                                 blit_rect.h = stones->h;
183                                 blit_rect.x += ((tile_rect.w - blit_rect.w)/2);
184                                 blit_rect.y += ((tile_rect.h - blit_rect.h)/2);
185                                 SDL_BlitSurface(stones,NULL,board,&blit_rect);
186                         }
187
188                         blit_rect = tile_rect;
189                         blit_rect.y = blit_rect.h;
190                         SDL_BlitSurface(stone_gfx[0], NULL, board, &blit_rect);
191                         if (aiBoard[BOARD_MAX-i+1] > 0) {
192                                 if (!(stones = FillHole(aiBoard[BOARD_MAX-i+1], 
193                                         board_font, stone_gfx)))
194                                         fprintf(stderr,"FillHole() problems\n");
195                                 if (active == 0)
196                                         stones = ShiftColors(stones,0,0,0,160);
197                                 blit_rect.w = stones->w;
198                                 blit_rect.h = stones->h;
199                                 blit_rect.x += ((tile_rect.w - blit_rect.w)/2);
200                                 blit_rect.y += ((tile_rect.h - blit_rect.h)/2);
201                                 SDL_BlitSurface(stones,NULL,board,&blit_rect);
202                         }
203                 }
204         }
205
206         SDL_FreeSurface(stones);
207
208         return board;
209 }
210
211
212 /* flagrantly stol^H^H^Hborrowed from SDL Introduction */
213 /* passing 0 for red, green, or blue leaves them alone */
214 /* passing 0 for alpha makes the image transparent     */
215
216 SDL_Surface *ShiftColors(SDL_Surface *old, Uint8 red, Uint8 green, Uint8 blue, Uint8 alpha)
217 {
218     SDL_Surface *new;
219     Uint8 r, g, b, a;
220     int x, y;
221
222     new = NewSurfaceFrom(old, (SDL_SWSURFACE|SDL_SRCALPHA));
223
224     if ( SDL_MUSTLOCK(old) ) {
225         if (SDL_LockSurface(old) < 0 ) {
226             return NULL;
227         }
228     }
229
230     if ( SDL_MUSTLOCK(new) ) {
231         if ( SDL_LockSurface(new) < 0 ) {
232             return NULL;
233         }
234     }
235
236     for (x=0; x<old->w; x++)
237     for (y=0; y<old->h; y++) {
238  
239     r = g = b = a = 0;
240
241     switch (old->format->BytesPerPixel) {
242         case 1: { /* Assuming 8-bpp */
243             Uint8 *bufp, *bufq;
244
245             bufp = (Uint8 *)old->pixels + y*old->pitch + x;
246             bufq = (Uint8 *)new->pixels + y*new->pitch + x;
247             SDL_GetRGBA((Uint32)*bufp, old->format, &r, &g, &b, &a);
248             a *= alpha/SDL_ALPHA_OPAQUE;
249             *bufq = (Uint8)SDL_MapRGBA(new->format, r, g, b, a);
250         }
251         break;
252
253         case 2: { /* Probably 15-bpp or 16-bpp */
254             Uint16 *bufp, *bufq;
255
256             bufp = (Uint16 *)old->pixels + y*old->pitch/2 + x;
257             bufq = (Uint16 *)new->pixels + y*new->pitch + x;
258             SDL_GetRGBA((Uint32)*bufp, new->format, &r, &g, &b, &a);
259             a *= alpha/SDL_ALPHA_OPAQUE;
260             *bufq = (Uint8)SDL_MapRGBA(new->format, r, g, b, a);
261         }
262         break;
263
264         case 3: { /* Slow 24-bpp mode, usually not used */
265             Uint8 *bufp, *bufq;
266             Uint32 color;
267
268             bufp = (Uint8 *)old->pixels + y*old->pitch + x * 3;
269             bufq = (Uint8 *)new->pixels + y*new->pitch + x * 3;
270             SDL_GetRGBA((Uint32)*bufp, old->format, &r, &g, &b, &a);
271             a *= alpha/SDL_ALPHA_OPAQUE;
272             color = SDL_MapRGBA(new->format, r, g, b, a);
273             if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {
274                 bufq[0] = color;
275                 bufq[1] = color >> 8;
276                 bufq[2] = color >> 16;
277             } else {
278                 bufq[2] = color;
279                 bufq[1] = color >> 8;
280                 bufq[0] = color >> 16;
281             }
282         }
283         break;
284
285         case 4: { /* Probably 32-bpp */
286             Uint32 *bufp, *bufq;
287
288             bufp = (Uint32 *)old->pixels + y*old->pitch/4 + x;
289             bufq = (Uint32 *)new->pixels + y*new->pitch/4 + x;
290             SDL_GetRGBA(*bufp, old->format, &r, &g, &b, &a);
291             a = (int)((long)a * (long)alpha/SDL_ALPHA_OPAQUE);
292             r += (int)((long)(SDL_ALPHA_OPAQUE - r) * (long)red/SDL_ALPHA_OPAQUE);
293             g += (int)((long)(SDL_ALPHA_OPAQUE - g) * (long)green/SDL_ALPHA_OPAQUE);
294             b += (int)((long)(SDL_ALPHA_OPAQUE - b) * (long)blue/SDL_ALPHA_OPAQUE);
295           *bufq = SDL_MapRGBA(new->format, r, g, b, a);
296         }
297         break;
298     }
299     }
300
301     if ( SDL_MUSTLOCK(new) ) {
302         SDL_UnlockSurface(new);
303     }
304   
305     if ( SDL_MUSTLOCK(old) ) {
306         SDL_UnlockSurface(old);
307     }
308     
309     return new;
310 }
311
312
313 /*  End graphics.c  */