2 * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <SDL_image.h>
25 #include "c64_gfx.h" /* char c64_gfx[] with (almost) original graphics */
29 #include "caveset.h" /* UGLY */
31 #include "c64_png_colors.h"
33 #define NUM_OF_CHARS 128
35 int gd_scale
=1; /* a graphics scale things which sets EVERYTHING. it is set with gd_sdl_init, and cannot be modified later. */
36 int gd_scale_type
=GD_SCALING_ORIGINAL
;
38 static SDL_Surface
*cells
[2*NUM_OF_CELLS
]; /* CANNOT BE NUM_OF_CELLS_X*NUM_OF_CELLS_Y, as the cave rendering routine in cave.c uses this. */
39 static const guchar
*font
;
40 static GHashTable
*font_w
, *font_n
;
41 static GList
*font_color_recently_used
;
42 static GdColor color0
, color1
, color2
, color3
, color4
, color5
; /* currently used cell colors */
43 static guint8
*c64_custom_gfx
=NULL
;
44 static gboolean using_png_gfx
;
46 /* these masks are always for RGB and RGBA ordering in memory.
47 that is what gdk-pixbuf uses, and also what sdl uses.
50 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
51 static guint32 rmask
= 0xff000000;
52 static guint32 gmask
= 0x00ff0000;
53 static guint32 bmask
= 0x0000ff00;
54 static guint32 amask
= 0x000000ff;
56 static guint32 rmask
= 0x000000ff;
57 static guint32 gmask
= 0x0000ff00;
58 static guint32 bmask
= 0x00ff0000;
59 static guint32 amask
= 0xff000000;
64 SDL_Surface
*gd_screen
=NULL
;
65 static SDL_Surface
*dark_background
=NULL
;
66 static GList
*backup_screens
=NULL
, *dark_screens
=NULL
;
67 static int play_area_w
=320;
68 static int play_area_h
=180;
69 int gd_statusbar_height
=20;
70 int gd_statusbar_y1
=1;
71 int gd_statusbar_y2
=10;
72 int gd_statusbar_mid
=(20-8)/2; /* (height-fontheight)/2 */
73 static int scroll_x
, scroll_y
;
76 /* quit, global variable which is set to true if the application should quit */
77 gboolean gd_quit
=FALSE
;
80 static SDL_Joystick
*joystick_1
;
82 static int cell_size
=16;
90 /* return name of key. names taken from sdl documentation */
92 w3m -dump file:///usr/share/doc/libsdl1.2-dev/docs/html/sdlkey.html |grep -v "──" |
93 cut -c 1-19,38- |sed "s/│$//;s/ *$//g;s/│/case /;s/ *│/: return \"/;s/$/\";/"|tee ~/keys.txt
96 gd_key_name(guint keysym
)
98 static char keyname
[30];
100 case SDLK_BACKSPACE
: return "BACKSPACE";
101 case SDLK_TAB
: return "TAB";
102 case SDLK_CLEAR
: return "CLEAR";
103 case SDLK_RETURN
: return "RETURN";
104 case SDLK_PAUSE
: return "PAUSE";
105 case SDLK_ESCAPE
: return "ESCAPE";
106 case SDLK_SPACE
: return "SPACE";
107 case SDLK_EXCLAIM
: return "EXCLAIM";
108 case SDLK_QUOTEDBL
: return "QUOTEDBL";
109 case SDLK_HASH
: return "HASH";
110 case SDLK_DOLLAR
: return "DOLLAR";
111 case SDLK_AMPERSAND
: return "AMPERSAND";
112 case SDLK_QUOTE
: return "QUOTE";
113 case SDLK_LEFTPAREN
: return "LEFT PARENTHESIS";
114 case SDLK_RIGHTPAREN
: return "RIGHT PARENTHESIS";
115 case SDLK_ASTERISK
: return "ASTERISK";
116 case SDLK_PLUS
: return "PLUS SIGN";
117 case SDLK_COMMA
: return "COMMA";
118 case SDLK_MINUS
: return "MINUS SIGN";
119 case SDLK_PERIOD
: return "PERIOD";
120 case SDLK_SLASH
: return "FORWARD SLASH";
121 case SDLK_0
: return "0";
122 case SDLK_1
: return "1";
123 case SDLK_2
: return "2";
124 case SDLK_3
: return "3";
125 case SDLK_4
: return "4";
126 case SDLK_5
: return "5";
127 case SDLK_6
: return "6";
128 case SDLK_7
: return "7";
129 case SDLK_8
: return "8";
130 case SDLK_9
: return "9";
131 case SDLK_COLON
: return "COLON";
132 case SDLK_SEMICOLON
: return "SEMICOLON";
133 case SDLK_LESS
: return "LESS-THAN SIGN";
134 case SDLK_EQUALS
: return "EQUALS SIGN";
135 case SDLK_GREATER
: return "GREATER-THAN SIGN";
136 case SDLK_QUESTION
: return "QUESTION MARK";
137 case SDLK_AT
: return "AT";
138 case SDLK_LEFTBRACKET
: return "LEFT BRACKET";
139 case SDLK_BACKSLASH
: return "BACKSLASH";
140 case SDLK_RIGHTBRACKET
: return "RIGHT BRACKET";
141 case SDLK_CARET
: return "CARET";
142 case SDLK_UNDERSCORE
: return "UNDERSCORE";
143 case SDLK_BACKQUOTE
: return "GRAVE";
144 case SDLK_a
: return "A";
145 case SDLK_b
: return "B";
146 case SDLK_c
: return "C";
147 case SDLK_d
: return "D";
148 case SDLK_e
: return "E";
149 case SDLK_f
: return "F";
150 case SDLK_g
: return "G";
151 case SDLK_h
: return "H";
152 case SDLK_i
: return "I";
153 case SDLK_j
: return "J";
154 case SDLK_k
: return "K";
155 case SDLK_l
: return "L";
156 case SDLK_m
: return "M";
157 case SDLK_n
: return "N";
158 case SDLK_o
: return "O";
159 case SDLK_p
: return "P";
160 case SDLK_q
: return "Q";
161 case SDLK_r
: return "R";
162 case SDLK_s
: return "S";
163 case SDLK_t
: return "T";
164 case SDLK_u
: return "U";
165 case SDLK_v
: return "V";
166 case SDLK_w
: return "W";
167 case SDLK_x
: return "X";
168 case SDLK_y
: return "Y";
169 case SDLK_z
: return "Z";
170 case SDLK_DELETE
: return "DELETE";
171 case SDLK_KP0
: return "KEYPAD 0";
172 case SDLK_KP1
: return "KEYPAD 1";
173 case SDLK_KP2
: return "KEYPAD 2";
174 case SDLK_KP3
: return "KEYPAD 3";
175 case SDLK_KP4
: return "KEYPAD 4";
176 case SDLK_KP5
: return "KEYPAD 5";
177 case SDLK_KP6
: return "KEYPAD 6";
178 case SDLK_KP7
: return "KEYPAD 7";
179 case SDLK_KP8
: return "KEYPAD 8";
180 case SDLK_KP9
: return "KEYPAD 9";
181 case SDLK_KP_PERIOD
: return "KEYPAD PERIOD";
182 case SDLK_KP_DIVIDE
: return "KEYPAD DIVIDE";
183 case SDLK_KP_MULTIPLY
: return "KEYPAD MULTIPLY";
184 case SDLK_KP_MINUS
: return "KEYPAD MINUS";
185 case SDLK_KP_PLUS
: return "KEYPAD PLUS";
186 case SDLK_KP_ENTER
: return "KEYPAD ENTER";
187 case SDLK_KP_EQUALS
: return "KEYPAD EQUALS";
188 case SDLK_UP
: return "UP ARROW";
189 case SDLK_DOWN
: return "DOWN ARROW";
190 case SDLK_RIGHT
: return "RIGHT ARROW";
191 case SDLK_LEFT
: return "LEFT ARROW";
192 case SDLK_INSERT
: return "INSERT";
193 case SDLK_HOME
: return "HOME";
194 case SDLK_END
: return "END";
195 case SDLK_PAGEUP
: return "PAGE UP";
196 case SDLK_PAGEDOWN
: return "PAGE DOWN";
197 case SDLK_F1
: return "F1";
198 case SDLK_F2
: return "F2";
199 case SDLK_F3
: return "F3";
200 case SDLK_F4
: return "F4";
201 case SDLK_F5
: return "F5";
202 case SDLK_F6
: return "F6";
203 case SDLK_F7
: return "F7";
204 case SDLK_F8
: return "F8";
205 case SDLK_F9
: return "F9";
206 case SDLK_F10
: return "F10";
207 case SDLK_F11
: return "F11";
208 case SDLK_F12
: return "F12";
209 case SDLK_F13
: return "F13";
210 case SDLK_F14
: return "F14";
211 case SDLK_F15
: return "F15";
212 case SDLK_NUMLOCK
: return "NUMLOCK";
213 case SDLK_CAPSLOCK
: return "CAPSLOCK";
214 case SDLK_SCROLLOCK
: return "SCROLLOCK";
215 case SDLK_RSHIFT
: return "RIGHT SHIFT";
216 case SDLK_LSHIFT
: return "LEFT SHIFT";
217 case SDLK_RCTRL
: return "RIGHT CTRL";
218 case SDLK_LCTRL
: return "LEFT CTRL";
219 case SDLK_RALT
: return "RIGHT ALT";
220 case SDLK_LALT
: return "LEFT ALT";
221 case SDLK_RMETA
: return "RIGHT META";
222 case SDLK_LMETA
: return "LEFT META";
223 case SDLK_LSUPER
: return "LEFT WINDOWS KEY";
224 case SDLK_RSUPER
: return "RIGHT WINDOWS KEY";
225 case SDLK_MODE
: return "MODE SHIFT";
226 case SDLK_HELP
: return "HELP";
227 case SDLK_PRINT
: return "PRINT-SCREEN";
228 case SDLK_SYSREQ
: return "SYSRQ";
229 case SDLK_BREAK
: return "BREAK";
230 case SDLK_MENU
: return "MENU";
231 case SDLK_POWER
: return "POWER";
232 case SDLK_EURO
: return "EURO";
234 sprintf(keyname
, "KEY %04X", keysym
);
235 return g_intern_string(keyname
); /* abuse? :) */
242 /* read a gdk-pixbuf source, and return an sdl surface. */
243 /* these masks are always for RGB and RGBA ordering in memory.
244 that is what gdk-pixbuf uses, and also what sdl uses.
247 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
248 static guint32 rmask
= 0xff000000;
249 static guint32 gmask
= 0x00ff0000;
250 static guint32 bmask
= 0x0000ff00;
251 static guint32 amask
= 0x000000ff;
253 /* for non-alpha channel gdk pixbuf includes */
254 static guint32 rmask_24
= 0xff0000;
255 static guint32 gmask_24
= 0x00ff00;
256 static guint32 bmask_24
= 0x0000ff;
258 static guint32 rmask
= 0x000000ff;
259 static guint32 gmask
= 0x0000ff00;
260 static guint32 bmask
= 0x00ff0000;
261 static guint32 amask
= 0xff000000;
263 /* for non-alpha channel gdk pixbuf includes */
264 static guint32 rmask_24
= 0x0000ff;
265 static guint32 gmask_24
= 0x00ff00;
266 static guint32 bmask_24
= 0xff0000;
269 surface_from_gdk_pixbuf_data(guint32
*data
)
271 SDL_Surface
*surface
;
273 g_assert(GUINT32_FROM_BE(data
[0])==0x47646b50); /* gdk-pixbuf magic number */
274 if (GUINT32_FROM_BE(data
[2])==0x1010002) /* 32-bit rgba */
275 surface
=SDL_CreateRGBSurfaceFrom(data
+6, GUINT32_FROM_BE(data
[4]), GUINT32_FROM_BE(data
[5]), 32, GUINT32_FROM_BE(data
[3]), rmask
, gmask
, bmask
, amask
);
277 if (GUINT32_FROM_BE(data
[2])==0x1010001) /* 24-bit rgb */
278 surface
=SDL_CreateRGBSurfaceFrom(data
+6, GUINT32_FROM_BE(data
[4]), GUINT32_FROM_BE(data
[5]), 24, GUINT32_FROM_BE(data
[3]), rmask_24
, gmask_24
, bmask_24
, 0);
280 /* unknown pixel format */
281 g_assert_not_reached();
282 g_assert(surface
!=NULL
);
289 surface_from_raw_data(const guint8
*data
, int length
)
292 SDL_Surface
*surface
;
294 rwop
=SDL_RWFromConstMem(data
, length
);
295 surface
=IMG_Load_RW(rwop
, 1); /* 1 = automatically closes rwop */
300 surface_from_base64(const char *base64
)
304 SDL_Surface
*surface
;
306 data
=g_base64_decode(base64
, &length
);
307 surface
=surface_from_raw_data(data
, length
);
313 /* This is taken from the SDL_gfx project. */
315 SDL_rotozoom.c - rotozoomer for 32bit or 8bit surfaces
316 LGPL (c) A. Schiffler
317 32bit Zoomer with optional anti-aliasing by bilinear interpolation.
318 Zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
322 zoomSurfaceRGBA(SDL_Surface
*src
, SDL_Surface
*dst
, gboolean smooth
)
324 typedef struct tColorRGBA
{
331 int x
, y
, sx
, sy
, *sax
, *say
, *csax
, *csay
, csx
, csy
, ex
, ey
, t1
, t2
, sstep
;
332 tColorRGBA
*c00
, *c01
, *c10
, *c11
;
333 tColorRGBA
*sp
, *csp
, *dp
;
336 g_assert(src
->format
->BytesPerPixel
==4);
337 g_assert(dst
->format
->BytesPerPixel
==4);
341 /* For interpolation: assume source dimension is one pixel */
342 /* smaller to avoid overflow on right and bottom edge. */
343 sx
= (int) (65536.0 * (float) (src
->w
- 1) / (float) dst
->w
);
344 sy
= (int) (65536.0 * (float) (src
->h
- 1) / (float) dst
->h
);
346 sx
= (int) (65536.0 * (float) src
->w
/ (float) dst
->w
);
347 sy
= (int) (65536.0 * (float) src
->h
/ (float) dst
->h
);
350 /* Allocate memory for row increments */
351 sax
=g_new(gint32
, dst
->w
+1);
352 say
=g_new(gint32
, dst
->h
+1);
354 /* Precalculate row increments */
355 if (SDL_MUSTLOCK(src
))
356 SDL_LockSurface(src
);
357 if (SDL_MUSTLOCK(dst
))
358 SDL_LockSurface(dst
);
359 sp
= csp
= (tColorRGBA
*) src
->pixels
;
360 dp
= (tColorRGBA
*) dst
->pixels
;
364 for (x
= 0; x
<= dst
->w
; x
++) {
372 for (y
= 0; y
<= dst
->h
; y
++) {
379 dgap
= dst
->pitch
- dst
->w
* 4;
382 * Switch between interpolating and non-interpolating code
385 /* Interpolating Zoom */
387 /* Scan destination */
389 for (y
= 0; y
< dst
->h
; y
++) {
390 /* Setup color source pointers */
394 c10
= (tColorRGBA
*) ((guint8
*) csp
+ src
->pitch
);
398 for (x
= 0; x
< dst
->w
; x
++) {
399 /* Interpolate colors */
400 ex
= (*csax
& 0xffff);
401 ey
= (*csay
& 0xffff);
402 t1
= ((((c01
->r
- c00
->r
) * ex
) >> 16) + c00
->r
) & 0xff;
403 t2
= ((((c11
->r
- c10
->r
) * ex
) >> 16) + c10
->r
) & 0xff;
404 dp
->r
= (((t2
- t1
) * ey
) >> 16) + t1
;
405 t1
= ((((c01
->g
- c00
->g
) * ex
) >> 16) + c00
->g
) & 0xff;
406 t2
= ((((c11
->g
- c10
->g
) * ex
) >> 16) + c10
->g
) & 0xff;
407 dp
->g
= (((t2
- t1
) * ey
) >> 16) + t1
;
408 t1
= ((((c01
->b
- c00
->b
) * ex
) >> 16) + c00
->b
) & 0xff;
409 t2
= ((((c11
->b
- c10
->b
) * ex
) >> 16) + c10
->b
) & 0xff;
410 dp
->b
= (((t2
- t1
) * ey
) >> 16) + t1
;
411 t1
= ((((c01
->a
- c00
->a
) * ex
) >> 16) + c00
->a
) & 0xff;
412 t2
= ((((c11
->a
- c10
->a
) * ex
) >> 16) + c10
->a
) & 0xff;
413 dp
->a
= (((t2
- t1
) * ey
) >> 16) + t1
;
415 /* Advance source pointers */
417 sstep
= (*csax
>> 16);
422 /* Advance destination pointer */
425 /* Advance source pointer */
427 csp
= (tColorRGBA
*) ((guint8
*) csp
+ (*csay
>> 16) * src
->pitch
);
428 /* Advance destination pointers */
429 dp
= (tColorRGBA
*) ((guint8
*) dp
+ dgap
);
432 /* Non-Interpolating Zoom */
434 for (y
= 0; y
< dst
->h
; y
++) {
437 for (x
= 0; x
< dst
->w
; x
++) {
440 /* Advance source pointers */
442 sstep
= (*csax
>> 16);
444 /* Advance destination pointer */
447 /* Advance source pointer */
449 sstep
= (*csay
>> 16) * src
->pitch
;
450 csp
= (tColorRGBA
*) ((guint8
*) csp
+ sstep
);
452 /* Advance destination pointers */
453 dp
= (tColorRGBA
*) ((guint8
*) dp
+ dgap
);
458 if (SDL_MUSTLOCK(src
))
459 SDL_UnlockSurface(src
);
460 if (SDL_MUSTLOCK(dst
))
461 SDL_UnlockSurface(dst
);
463 /* Remove temp arrays */
471 scale2x(SDL_Surface
*src
, SDL_Surface
*dst
)
473 g_assert(dst
->w
== src
->w
*2);
474 g_assert(dst
->h
== src
->h
*2);
475 g_assert(src
->format
->BytesPerPixel
==4);
476 g_assert(dst
->format
->BytesPerPixel
==4);
478 if (SDL_MUSTLOCK(src
))
479 SDL_LockSurface(src
);
480 if (SDL_MUSTLOCK(dst
))
481 SDL_LockSurface(dst
);
482 gd_scale2x_raw(src
->pixels
, src
->w
, src
->h
, src
->pitch
, dst
->pixels
, dst
->pitch
);
483 if (SDL_MUSTLOCK(src
))
484 SDL_UnlockSurface(src
);
485 if (SDL_MUSTLOCK(dst
))
486 SDL_UnlockSurface(dst
);
490 scale3x(SDL_Surface
*src
, SDL_Surface
*dst
)
492 g_assert(dst
->w
== src
->w
*3);
493 g_assert(dst
->h
== src
->h
*3);
494 g_assert(src
->format
->BytesPerPixel
==4);
495 g_assert(dst
->format
->BytesPerPixel
==4);
497 if (SDL_MUSTLOCK(src
))
498 SDL_LockSurface(src
);
499 if (SDL_MUSTLOCK(dst
))
500 SDL_LockSurface(dst
);
501 gd_scale3x_raw(src
->pixels
, src
->w
, src
->h
, src
->pitch
, dst
->pixels
, dst
->pitch
);
502 if (SDL_MUSTLOCK(src
))
503 SDL_UnlockSurface(src
);
504 if (SDL_MUSTLOCK(dst
))
505 SDL_UnlockSurface(dst
);
512 /* nearest neighbor scaling for 2x and 3x. */
513 /* nearest pixel 2x scaling. */
515 scale_2x_nearest(SDL_Surface
*src
, SDL_Surface
*dst
)
519 guint8
*srcpix
=src
->pixels
;
520 guint8
*dstpix
=dst
->pixels
;
523 int srcpitch
=src
->pitch
;
524 int dstpitch
=dst
->pitch
;
526 g_assert(dst
->w
== src
->w
*2);
527 g_assert(dst
->h
== src
->h
*2);
528 g_assert(src
->format
->BytesPerPixel
==4);
529 g_assert(dst
->format
->BytesPerPixel
==4);
531 if (SDL_MUSTLOCK(src
))
532 SDL_LockSurface(src
);
533 if (SDL_MUSTLOCK(dst
))
534 SDL_LockSurface(dst
);
535 for (y
=0; y
<height
; ++y
) {
536 for (x
=0; x
<width
; ++x
) {
537 E
= *(guint32
*)(srcpix
+ (y
*srcpitch
) + (4*x
));
539 *(guint32
*)(dstpix
+ y
*2*dstpitch
+ x
*2*4) = E
;
540 *(guint32
*)(dstpix
+ y
*2*dstpitch
+ (x
*2+1)*4) = E
;
541 *(guint32
*)(dstpix
+ (y
*2+1)*dstpitch
+ x
*2*4) = E
;
542 *(guint32
*)(dstpix
+ (y
*2+1)*dstpitch
+ (x
*2+1)*4) = E
;
545 if (SDL_MUSTLOCK(src
))
546 SDL_UnlockSurface(src
);
547 if (SDL_MUSTLOCK(dst
))
548 SDL_UnlockSurface(dst
);
552 /* nearest pixel 3x scaling. the rotozoomer is not correct at the bottom of the image. */
554 scale_3x_nearest(SDL_Surface
*src
, SDL_Surface
*dst
)
558 guint8
*srcpix
=src
->pixels
;
559 guint8
*dstpix
=dst
->pixels
;
562 int srcpitch
=src
->pitch
;
563 int dstpitch
=dst
->pitch
;
565 g_assert(dst
->w
== src
->w
*3);
566 g_assert(dst
->h
== src
->h
*3);
567 g_assert(src
->format
->BytesPerPixel
==4);
568 g_assert(dst
->format
->BytesPerPixel
==4);
570 if (SDL_MUSTLOCK(src
))
571 SDL_LockSurface(src
);
572 if (SDL_MUSTLOCK(dst
))
573 SDL_LockSurface(dst
);
574 for (y
=0; y
<height
; ++y
) {
575 int ny
=y
*3; /* new coordinate */
577 for (x
=0; x
<width
; ++ x
) {
578 int nx
=x
*3; /* new coordinate */
580 E
= *(guint32
*)(srcpix
+ (y
*srcpitch
+ 4*x
));
582 *(guint32
*)(dstpix
+ ny
*dstpitch
+ nx
*4) = E
;
583 *(guint32
*)(dstpix
+ ny
*dstpitch
+ (nx
+1)*4) = E
;
584 *(guint32
*)(dstpix
+ ny
*dstpitch
+ (nx
+2)*4) = E
;
585 *(guint32
*)(dstpix
+ (ny
+1)*dstpitch
+ nx
*4) = E
;
586 *(guint32
*)(dstpix
+ (ny
+1)*dstpitch
+ (nx
+1)*4) = E
;
587 *(guint32
*)(dstpix
+ (ny
+1)*dstpitch
+ (nx
+2)*4) = E
;
588 *(guint32
*)(dstpix
+ (ny
+2)*dstpitch
+ nx
*4) = E
;
589 *(guint32
*)(dstpix
+ (ny
+2)*dstpitch
+ (nx
+1)*4) = E
;
590 *(guint32
*)(dstpix
+ (ny
+2)*dstpitch
+ (nx
+2)*4) = E
;
593 if (SDL_MUSTLOCK(src
))
594 SDL_UnlockSurface(src
);
595 if (SDL_MUSTLOCK(dst
))
596 SDL_UnlockSurface(dst
);
601 /* scales a pixbuf with the appropriate scaling type. */
603 surface_scale(SDL_Surface
*orig
)
605 SDL_Surface
*dest
, *dest2x
;
607 /* special case: no scaling. */
608 /* return a new pixbuf, but its pixels are at the same place as the original. (so the pixbuf struct can be freed on its own) */
609 if (gd_scale_type
==GD_SCALING_ORIGINAL
) {
610 g_assert(gd_scale
==1); /* just to be sure */
612 return SDL_CreateRGBSurfaceFrom(orig
->pixels
, orig
->w
, orig
->h
, orig
->format
->BitsPerPixel
, orig
->pitch
, orig
->format
->Rmask
, orig
->format
->Gmask
, orig
->format
->Bmask
, orig
->format
->Amask
);
615 dest
=SDL_CreateRGBSurface(orig
->flags
, orig
->w
*gd_scale
, orig
->h
*gd_scale
, orig
->format
->BitsPerPixel
, orig
->format
->Rmask
, orig
->format
->Gmask
, orig
->format
->Bmask
, orig
->format
->Amask
);
617 switch (gd_scale_type
) {
618 case GD_SCALING_ORIGINAL
:
620 g_assert_not_reached();
624 scale_2x_nearest(orig
, dest
);
627 case GD_SCALING_2X_BILINEAR
:
628 zoomSurfaceRGBA(orig
, dest
, TRUE
);
631 case GD_SCALING_2X_SCALE2X
:
636 scale_3x_nearest(orig
, dest
);
639 case GD_SCALING_3X_BILINEAR
:
640 zoomSurfaceRGBA(orig
, dest
, TRUE
);
643 case GD_SCALING_3X_SCALE3X
:
648 dest2x
=SDL_CreateRGBSurface(orig
->flags
, orig
->w
*2, orig
->h
*2, orig
->format
->BitsPerPixel
, orig
->format
->Rmask
, orig
->format
->Gmask
, orig
->format
->Bmask
, orig
->format
->Amask
);
649 scale_2x_nearest(orig
, dest2x
);
650 scale_2x_nearest(dest2x
, dest
);
651 SDL_FreeSurface(dest2x
);
654 case GD_SCALING_4X_BILINEAR
:
655 zoomSurfaceRGBA(orig
, dest
, TRUE
);
658 case GD_SCALING_4X_SCALE4X
:
659 /* scale2x applied twice. */
660 dest2x
=SDL_CreateRGBSurface(orig
->flags
, orig
->w
*2, orig
->h
*2, orig
->format
->BitsPerPixel
, orig
->format
->Rmask
, orig
->format
->Gmask
, orig
->format
->Bmask
, orig
->format
->Amask
);
661 scale2x(orig
, dest2x
);
662 scale2x(dest2x
, dest
);
663 SDL_FreeSurface(dest2x
);
666 /* not a valid case, but to avoid compiler warning */
668 g_assert_not_reached();
678 pal_emu_surface(SDL_Surface
*image
)
680 if (SDL_MUSTLOCK(image
))
681 SDL_LockSurface(image
);
682 gd_pal_emulate_raw(image
->pixels
, image
->w
, image
->h
, image
->pitch
, image
->format
->Rshift
, image
->format
->Gshift
, image
->format
->Bshift
, image
->format
->Ashift
);
683 if (SDL_MUSTLOCK(image
))
684 SDL_UnlockSurface(image
);
688 /* create new surface, which is SDL_DisplayFormatted. */
689 /* it is also scaled by gd_scale. */
691 displayformat(SDL_Surface
*orig
)
693 SDL_Surface
*scaled
, *displayformat
;
695 /* at this point we must already be working with 32bit surfaces */
696 g_assert(orig
->format
->BytesPerPixel
==4);
698 scaled
=surface_scale(orig
);
699 if (gd_sdl_pal_emulation
)
700 pal_emu_surface(scaled
);
701 displayformat
=SDL_DisplayFormat(scaled
);
702 SDL_FreeSurface(scaled
);
704 return displayformat
;
708 displayformatalpha(SDL_Surface
*orig
)
710 SDL_Surface
*scaled
, *displayformat
;
712 /* at this point we must already be working with 32bit surfaces */
713 g_assert(orig
->format
->BytesPerPixel
==4);
715 scaled
=surface_scale(orig
);
716 if (gd_sdl_pal_emulation
)
717 pal_emu_surface(scaled
);
718 displayformat
=SDL_DisplayFormatAlpha(scaled
);
719 SDL_FreeSurface(scaled
);
721 return displayformat
;
725 /* needed to alpha-copy an src image over dst.
726 the resulting image of sdl_blitsurface is not exact?!
727 can't explain why. XXX. */
729 copy_alpha(SDL_Surface
*src
, SDL_Surface
*dst
)
733 g_assert(src
->format
->BytesPerPixel
==4);
734 g_assert(dst
->format
->BytesPerPixel
==4);
735 g_assert(src
->w
== dst
->w
);
736 g_assert(src
->h
== dst
->h
);
738 SDL_LockSurface(src
);
739 SDL_LockSurface(dst
);
740 for (y
=0; y
<src
->h
; y
++) {
741 guint32
*srcpix
=(guint32
*)((guint8
*)src
->pixels
+ src
->pitch
*y
);
742 guint32
*dstpix
=(guint32
*)((guint8
*)dst
->pixels
+ dst
->pitch
*y
);
743 for (x
=0; x
<src
->w
; x
++) {
744 if ((srcpix
[x
]&src
->format
->Amask
)>>src
->format
->Ashift
) /* if alpha is nonzero */
745 dstpix
[x
]=srcpix
[x
]; /* copy pixel as it is */
748 SDL_UnlockSurface(src
);
749 SDL_UnlockSurface(dst
);
753 /* create and return an array of surfaces, which contain the title animation.
754 the array is one pointer larger than all frames; the last pointer is a null.
755 up to the caller to free.
758 gd_get_title_animation(gboolean one_frame_only
)
764 SDL_Surface
**animation
;
770 if (gd_caveset_data
->title_screen
->len
!=0) {
771 /* user defined title screen */
772 screen
=surface_from_base64(gd_caveset_data
->title_screen
->str
);
774 g_warning("Caveset is storing an invalid title screen image.");
775 g_string_assign(gd_caveset_data
->title_screen
, "");
777 /* if we loaded the screen, now try to load the tile. */
778 /* only if the screen has an alpha channel. otherwise it would not make any sense */
779 if (screen
->format
->Amask
!=0 && gd_caveset_data
->title_screen_scroll
->len
!=0) {
780 tile
=surface_from_base64(gd_caveset_data
->title_screen_scroll
->str
);
783 g_warning("Caveset is storing an invalid title screen background image.");
784 g_string_assign(gd_caveset_data
->title_screen_scroll
, "");
791 /* if no special title image or unable to load that one, load the built-in */
794 screen
=surface_from_raw_data(gdash_screen
, sizeof(gdash_screen
));
795 /* the tile to be put under the screen */
796 tile
=surface_from_raw_data(gdash_tile
, sizeof(gdash_tile
));
797 g_assert(screen
!=NULL
);
798 g_assert(tile
!=NULL
);
801 /* if no tile, let it be black. */
802 /* the sdl version does the same. */
804 /* one-row pixbuf, so no animation. */
805 tile
=SDL_CreateRGBSurface(0, screen
->w
, 1, 32, 0, 0, 0, 0);
806 SDL_FillRect(tile
, NULL
, SDL_MapRGB(tile
->format
, 0, 0, 0));
809 /* do not allow more than 40 frames of animation */
810 g_assert(tile
->h
<40);
815 animation
=g_new0(SDL_Surface
*, framenum
+1);
817 /* create a big image, which is one tile larger than the title image size */
818 bigone
=SDL_CreateRGBSurface(0, screen
->w
, screen
->h
+tile
->h
, 32, 0, 0, 0, 0);
819 /* and fill it with the tile. */
820 for (y
=0; y
<screen
->h
+tile
->h
; y
+=tile
->h
)
821 for (x
=0; x
<screen
->w
; x
+=tile
->h
) {
826 SDL_BlitSurface(tile
, 0, bigone
, &dest
);
829 frame
=SDL_CreateRGBSurface(0, screen
->w
, screen
->h
, 32, rmask
, gmask
, bmask
, amask
); /* must be same *mask so copy_alpha works correctly */
830 for (i
=0; i
<framenum
; i
++) {
833 /* copy part of the big tiled image */
838 SDL_BlitSurface(bigone
, &src
, frame
, 0);
839 /* and composite it with the title image */
840 // copy_alpha(screen, frame);
841 SDL_BlitSurface(screen
, NULL
, frame
, NULL
);
842 animation
[i
]=displayformat(frame
);
844 SDL_FreeSurface(frame
);
845 SDL_FreeSurface(bigone
);
846 SDL_FreeSurface(screen
);
847 SDL_FreeSurface(tile
);
853 rendered_font_free(gpointer font
)
857 /* null-terminated list of pointers to sdl_surfaces */
858 for(p
=font
; p
!=NULL
; p
++)
865 gd_sdl_init(GdScalingType scaling_type
)
869 /* set the cell scale option. */
870 gd_scale_type
=scaling_type
;
871 gd_scale
=gd_scaling_scale
[gd_scale_type
];
872 play_area_w
*=gd_scale
;
873 play_area_h
*=gd_scale
;
874 gd_statusbar_y1
*=gd_scale
;
875 gd_statusbar_y2
*=gd_scale
;
876 gd_statusbar_height
*=gd_scale
;
877 gd_statusbar_mid
*=gd_scale
;
879 SDL_Init(SDL_INIT_TIMER
|SDL_INIT_VIDEO
|SDL_INIT_JOYSTICK
);
880 SDL_EnableKeyRepeat(250, 100);
881 gd_screen
=SDL_SetVideoMode(play_area_w
, play_area_h
+gd_statusbar_height
, 32, SDL_ANYFORMAT
| (gd_sdl_fullscreen
?SDL_FULLSCREEN
:0));
882 /* do not show mouse cursor */
883 SDL_ShowCursor(SDL_DISABLE
);
884 /* warp mouse pointer so cursor cannot be seen, if the above call did nothing for some reason */
885 SDL_WarpMouse(gd_screen
->w
-1, gd_screen
->h
-1);
889 /* keyboard, joystick */
890 gd_keystate
=SDL_GetKeyState(NULL
);
891 if (SDL_NumJoysticks()>0)
892 joystick_1
=SDL_JoystickOpen(0);
895 icon
=surface_from_raw_data(gdash_32
, sizeof(gdash_32
));
896 SDL_WM_SetIcon(icon
, NULL
);
897 SDL_WM_SetCaption("GDash", NULL
);
898 SDL_FreeSurface(icon
);
900 font_n
=g_hash_table_new_full(g_direct_hash
, g_direct_equal
, NULL
, rendered_font_free
);
901 font_w
=g_hash_table_new_full(g_direct_hash
, g_direct_equal
, NULL
, rendered_font_free
);
902 font_color_recently_used
=NULL
;
910 static inline gboolean
913 return joystick_1
!=NULL
&& SDL_JoystickGetAxis(joystick_1
, 1)<-3200;
916 static inline gboolean
919 return joystick_1
!=NULL
&& SDL_JoystickGetAxis(joystick_1
, 1)>3200;
922 static inline gboolean
925 return joystick_1
!=NULL
&& SDL_JoystickGetAxis(joystick_1
, 0)<-3200;
928 static inline gboolean
931 return joystick_1
!=NULL
&& SDL_JoystickGetAxis(joystick_1
, 0)>3200;
934 static inline gboolean
937 return joystick_1
!=NULL
&& (SDL_JoystickGetButton(joystick_1
, 0) || SDL_JoystickGetButton(joystick_1
, 1));
946 return gd_keystate
[gd_sdl_key_up
] || get_joy_up();
952 return gd_keystate
[gd_sdl_key_down
] || get_joy_down();
958 return gd_keystate
[gd_sdl_key_left
] || get_joy_left();
964 return gd_keystate
[gd_sdl_key_right
] || get_joy_right();
970 return gd_keystate
[gd_sdl_key_fire_1
] || gd_keystate
[gd_sdl_key_fire_2
] || get_joy_fire();
976 /* like the above one, but used in the main menu */
978 gd_space_or_enter_or_fire()
980 /* set these to zero, so each keypress is reported only once */
981 return get_joy_fire() || gd_keystate
[SDLK_SPACE
] || gd_keystate
[SDLK_RETURN
];
985 /* process pending events, so presses and releases are applied */
986 /* also check for quit event */
988 gd_process_pending_events()
992 /* process pending events, so presses and releases are applied */
993 while (SDL_PollEvent(&event
)) {
994 /* meanwhile, if we receive a quit event, we set the global variable. */
995 if (event
.type
==SDL_QUIT
)
1002 /* this function waits until SPACE, ENTER and ESCAPE are released */
1004 gd_wait_for_key_releases()
1006 /* wait until the user releases return and escape */
1007 while (gd_keystate
[SDLK_RETURN
]!=0 || gd_keystate
[SDLK_ESCAPE
]!=0 || gd_keystate
[SDLK_SPACE
]!=0 || gd_keystate
[SDLK_n
]!=0 || gd_fire()) {
1010 /* process pending events, so presses and releases are applied */
1011 while (SDL_PollEvent(&event
)) {
1012 /* meanwhile, if we receive a quit event, we set the global variable. */
1013 if (event
.type
==SDL_QUIT
)
1017 SDL_Delay(50); /* do not eat cpu */
1031 /* remove pixmaps from x server */
1037 /* if cells already loaded, unref them */
1038 for (i
=0; i
<G_N_ELEMENTS(cells
); i
++)
1040 SDL_FreeSurface(cells
[i
]);
1047 loadcells_from_surface(SDL_Surface
*image
)
1050 int pixbuf_cell_size
;
1054 /* if we have display-formatted pixmaps, remove them */
1057 /* 8 (NUM_OF_CELLS_X) cells in a row, so divide by it and we get the size of a cell in pixels */
1058 pixbuf_cell_size
=image
->w
/NUM_OF_CELLS_X
;
1059 cell_size
=pixbuf_cell_size
*gd_scale
;
1061 rect
=SDL_CreateRGBSurface(0, pixbuf_cell_size
, pixbuf_cell_size
, 32, 0, 0, 0, 0); /* no amask, as we set overall alpha! */
1062 SDL_FillRect(rect
, NULL
, SDL_MapRGB(rect
->format
, (gd_flash_color
>>16)&0xff, (gd_flash_color
>>8)&0xff, gd_flash_color
&0xff));
1063 SDL_SetAlpha(rect
, SDL_SRCALPHA
, 128); /* 50% alpha; nice choice. also sdl is rendering faster for the special value alpha=128 */
1065 cut
=SDL_CreateRGBSurface(0, pixbuf_cell_size
, pixbuf_cell_size
, 32, rmask
, gmask
, bmask
, amask
);
1067 /* make individual cells */
1068 for (i
=0; i
<NUM_OF_CELLS_X
*NUM_OF_CELLS_Y
; i
++) {
1071 from
.x
=(i
%NUM_OF_CELLS_X
)*pixbuf_cell_size
;
1072 from
.y
=(i
/NUM_OF_CELLS_X
)*pixbuf_cell_size
;
1073 from
.w
=pixbuf_cell_size
;
1074 from
.h
=pixbuf_cell_size
;
1076 SDL_BlitSurface(image
, &from
, cut
, NULL
);
1078 cells
[i
]=displayformat(cut
);
1079 SDL_BlitSurface(rect
, NULL
, cut
, NULL
); /* create yellowish image */
1080 cells
[NUM_OF_CELLS
+i
]=displayformat(cut
);
1082 SDL_FreeSurface(cut
);
1083 SDL_FreeSurface(rect
);
1086 /* sets one of the colors in the indexed palette of an sdl surface to a GdColor. */
1088 surface_setpalette(SDL_Surface
*image
, int index
, GdColor col
)
1091 c
.r
=gd_color_get_r(col
);
1092 c
.g
=gd_color_get_g(col
);
1093 c
.b
=gd_color_get_b(col
);
1095 SDL_SetPalette(image
, SDL_LOGPAL
|SDL_PHYSPAL
, &c
, index
, 1);
1099 loadcells_from_c64_data(GdColor c0
, GdColor c1
, GdColor c2
, GdColor c3
, GdColor c4
, GdColor c5
)
1101 const guint8
*gfx
; /* currently used graphics, will point to c64_gfx or c64_custom_gfx */
1104 gfx
=c64_custom_gfx
?c64_custom_gfx
:c64_gfx
;
1106 /* create a 8-bit palette and set its colors */
1107 /* gfx[0] is the pixel width and height of one cell. */
1108 /* from gfx[1], we have the color data, one byte/pixel. so this is an indexed color image: 8bit/pixel. */
1109 image
=SDL_CreateRGBSurfaceFrom((void *)(gfx
+1), NUM_OF_CELLS_X
*(int)gfx
[0], NUM_OF_CELLS_Y
*(int)gfx
[0], 8, NUM_OF_CELLS_X
*(int)gfx
[0], 0, 0, 0, 0);
1110 /* sdl supports paletted images, so this is very easy: */
1111 surface_setpalette(image
, 0, 0);
1112 surface_setpalette(image
, 1, c0
);
1113 surface_setpalette(image
, 2, c1
);
1114 surface_setpalette(image
, 3, c2
);
1115 surface_setpalette(image
, 4, c3
);
1116 surface_setpalette(image
, 5, c4
);
1117 surface_setpalette(image
, 6, c5
);
1118 surface_setpalette(image
, 7, 0);
1119 surface_setpalette(image
, 8, 0);
1121 /* from here, same as any other image */
1122 loadcells_from_surface(image
);
1123 SDL_FreeSurface(image
);
1126 /* takes a c64_gfx.png-coded 32-bit pixbuf, and creates a paletted pixbuf in our internal format. */
1128 c64_gfx_data_from_pixbuf(SDL_Surface
*image
)
1134 g_assert(image
->format
->BytesPerPixel
==4);
1136 data
=g_new(guint8
, image
->w
*image
->h
+1);
1138 data
[out
++]=image
->w
/NUM_OF_CELLS_X
;
1140 SDL_LockSurface(image
);
1141 for (y
=0; y
<image
->h
; y
++) {
1142 guint32
*p
=(guint32
*)((char *)image
->pixels
+y
*image
->pitch
);
1144 for (x
=0; x
<image
->w
; x
++) {
1147 r
=(p
[x
]&image
->format
->Rmask
) >> image
->format
->Rshift
<< image
->format
->Rloss
;
1148 g
=(p
[x
]&image
->format
->Gmask
) >> image
->format
->Gshift
<< image
->format
->Gloss
;
1149 b
=(p
[x
]&image
->format
->Bmask
) >> image
->format
->Bshift
<< image
->format
->Bloss
;
1151 a=(p[x]&image->format->Amask) >> image->format->Ashift << image->format->Aloss;
1152 but we do not use the alpha channel in sdash, so we just use 255 (max alpha)
1154 data
[out
++]=c64_png_colors(r
, g
, b
, 255);
1157 SDL_UnlockSurface(image
);
1163 /* returns true, if the given pixbuf seems to be a c64 imported image. */
1165 check_if_pixbuf_c64_png(SDL_Surface
*image
)
1171 g_assert(image
->format
->BytesPerPixel
==4);
1173 SDL_LockSurface(image
);
1175 for (y
=0; y
<image
->h
; y
++) {
1176 p
=((guchar
*)image
->pixels
) + y
* image
->pitch
;
1177 for (x
=0; x
<image
->w
*image
->format
->BytesPerPixel
; x
++)
1178 if (p
[x
]!=0 && p
[x
]!=255)
1181 SDL_UnlockSurface(image
);
1186 /* check if given surface is ok to be a gdash theme. */
1188 gd_is_surface_ok_for_theme(SDL_Surface
*surface
)
1190 if ((surface
->w
% NUM_OF_CELLS_X
!= 0) || (surface
->h
% NUM_OF_CELLS_Y
!= 0) || (surface
->w
/ NUM_OF_CELLS_X
!= surface
->h
/ NUM_OF_CELLS_Y
)) {
1191 g_warning("image should contain %d cells in a row and %d in a column!", NUM_OF_CELLS_X
, NUM_OF_CELLS_Y
);
1192 return FALSE
; /* Image should contain 16 cells in a row and 32 in a column! */
1194 /* we do not check for an alpha channel, as in the gtk version. we do not need it here. */
1195 /* the gtk version needs it because of the editor. */
1197 return TRUE
; /* passed checks */
1201 /* load theme from image file. */
1202 /* return true if successful. */
1204 gd_loadcells_file(const char *filename
)
1206 SDL_Surface
*surface
, *converted
;
1208 /* load cell graphics */
1209 /* load from file */
1210 surface
=IMG_Load(filename
);
1213 g_warning("%s: unable to load image", filename
);
1217 /* do some checks. if those fail, the error is already reported by the function */
1218 if (!gd_is_surface_ok_for_theme(surface
)) {
1219 SDL_FreeSurface(surface
);
1223 /* convert to 32bit rgba */
1224 converted
=SDL_CreateRGBSurface(0, surface
->w
, surface
->h
, 32, rmask
, gmask
, bmask
, amask
); /* 32bits per pixel, but we dont need an alpha channel */
1225 SDL_SetAlpha(surface
, 0, 0); /* do not use the alpha blending for the copy */
1226 SDL_BlitSurface(surface
, NULL
, converted
, NULL
);
1227 SDL_FreeSurface(surface
);
1229 if (check_if_pixbuf_c64_png(converted
)) {
1230 /* c64 pixbuf with a small number of colors which can be changed */
1231 g_free(c64_custom_gfx
);
1232 c64_custom_gfx
=c64_gfx_data_from_pixbuf(converted
);
1233 using_png_gfx
=FALSE
;
1235 /* normal, "truecolor" pixbuf */
1236 g_free(c64_custom_gfx
);
1237 c64_custom_gfx
=NULL
;
1239 loadcells_from_surface(converted
);
1241 SDL_FreeSurface(converted
);
1242 color0
=GD_COLOR_INVALID
; /* this is an invalid gdash color; so redraw is forced */
1249 /* load the theme specified in gd_sdl_theme. */
1250 /* if successful, ok. */
1251 /* if fails, or no theme specified, load the builtin, and forget gd_sdl_theme */
1256 if (!gd_loadcells_file(gd_sdl_theme
)) {
1257 /* if failing to load the bmp file specified in the config file: forget the setting now, and load the builtin. */
1258 g_free(gd_sdl_theme
);
1263 gd_loadcells_default(); /* if no theme specified, or loading the file failed, simply load the builtin. */
1267 /* selects built-in graphics */
1269 gd_loadcells_default()
1271 g_free(c64_custom_gfx
);
1272 c64_custom_gfx
=NULL
;
1273 using_png_gfx
=FALSE
;
1274 /* just to set some default */
1275 color0
=GD_COLOR_INVALID
; /* this is an invalid gdash color; so redraw is forced */
1277 /* size of array (in bytes), -1 which is the cell size */
1278 g_assert(sizeof(c64_gfx
)-1 == NUM_OF_CELLS_X
*NUM_OF_CELLS_Y
*c64_gfx
[0]*c64_gfx
[0]);
1284 /* C64 FONT HANDLING */
1286 /* creates a guint32 value, which can be raw-written to a sdl_surface memory area. */
1287 /* takes the pixel format of the surface into consideration. */
1289 rgba_pixel_from_gdcolor(SDL_PixelFormat
*format
, GdColor col
, guint8 a
)
1291 return SDL_MapRGBA(format
, gd_color_get_r(col
), gd_color_get_g(col
), gd_color_get_b(col
), a
);
1295 /* FIXME fixed font size: 8x8 */
1296 /* renders the fonts for a specific color. */
1297 /* the wide font draws black pixels, the narrow (normal) font does not! */
1299 renderfont_color(GdColor color
)
1302 guint32 col
, transparent
;
1303 SDL_Surface
*image
, *image_n
;
1304 SDL_Surface
**fn
, **fw
;
1306 /* check that we already got an rgb color */
1307 g_assert(gd_color_is_rgb(color
));
1309 /* remove from list and add to the front */
1310 font_color_recently_used
=g_list_remove(font_color_recently_used
, GUINT_TO_POINTER(color
));
1311 font_color_recently_used
=g_list_prepend(font_color_recently_used
, GUINT_TO_POINTER(color
));
1313 /* if already rendered, return now */
1314 if (g_hash_table_lookup(font_w
, GUINT_TO_POINTER(color
)))
1317 /* -------- RENDERING A NEW FONT -------- */
1318 /* if storing too many fonts, free the oldest one. */
1319 if (g_list_length(font_color_recently_used
)>32) {
1322 /* if list too big, remove least recently used */
1323 last
=g_list_last(font_color_recently_used
);
1324 g_hash_table_remove(font_w
, last
->data
);
1325 g_hash_table_remove(font_n
, last
->data
);
1326 font_color_recently_used
=g_list_delete_link(font_color_recently_used
, last
);
1329 fn
=g_new0(SDL_Surface
*, NUM_OF_CHARS
+1);
1330 fw
=g_new0(SDL_Surface
*, NUM_OF_CHARS
+1);
1332 /* colors data into memory */
1333 image
=SDL_CreateRGBSurface(SDL_SRCALPHA
, 16, 8, 32, rmask
, gmask
, bmask
, amask
);
1334 image_n
=SDL_CreateRGBSurface(SDL_SRCALPHA
, 8, 8, 32, rmask
, gmask
, bmask
, amask
);
1336 col
=rgba_pixel_from_gdcolor(image
->format
, color
, SDL_ALPHA_OPAQUE
);
1337 transparent
=rgba_pixel_from_gdcolor(image
->format
, 0, SDL_ALPHA_TRANSPARENT
); /* color does not matter as totally transparent */
1339 /* for all characters */
1340 /* render character in "image", then do a displayformat(image) to generate the resulting one */
1341 for (j
=0; j
<NUM_OF_CHARS
; j
++) {
1344 y1
=(j
/16)*8; /* 16 characters in a row */
1347 if (SDL_MUSTLOCK(image
))
1348 SDL_LockSurface(image
);
1349 if (SDL_MUSTLOCK(image_n
))
1350 SDL_LockSurface(image_n
);
1351 for (y
=0; y
<8; y
++) {
1352 guint32
*p
=(guint32
*) ((char *)image
->pixels
+ y
*image
->pitch
);
1353 guint32
*p_n
=(guint32
*) ((char *)image_n
->pixels
+ y
*image_n
->pitch
);
1355 for (x
=0; x
<8; x
++) {
1356 /* the font array is encoded the same way as a c64-colored pixbuf. see c64_gfx_data...() */
1357 if (font
[(y1
+y
)*128+x1
+x
]!=1) {
1358 p
[0]=col
; /* wide */
1360 p_n
[0]=col
; /* normal */
1362 p
[0]=transparent
; /* wide */
1364 p_n
[0]=transparent
; /* normal */
1370 if (SDL_MUSTLOCK(image
))
1371 SDL_UnlockSurface(image
);
1372 if (SDL_MUSTLOCK(image_n
))
1373 SDL_UnlockSurface(image_n
);
1374 fw
[j
]=displayformatalpha(image
); /* alpha channel is used! */
1375 fn
[j
]=displayformatalpha(image_n
);
1377 SDL_FreeSurface(image
);
1378 SDL_FreeSurface(image_n
);
1380 /* add newly rendered font to hash table. to the recently used list, it is already added. */
1381 g_hash_table_insert(font_w
, GINT_TO_POINTER(color
), fw
);
1382 g_hash_table_insert(font_n
, GINT_TO_POINTER(color
), fn
);
1385 /* XXX these functions are not really implemented */
1389 /* forget all previously rendered chars */
1390 g_hash_table_remove_all(font_w
);
1391 g_hash_table_remove_all(font_n
);
1392 g_list_free(font_color_recently_used
);
1393 font_color_recently_used
=NULL
;
1397 /* loads a font from a file */
1399 gd_loadfont_file(const char *filename
)
1401 /* not yet implemented */
1402 g_assert_not_reached();
1405 /* loads inlined c64 font */
1407 gd_loadfont_default()
1409 font
=c64_font
+1; /* first byte in c64_gfx[] is the "cell size", we ignore that */
1416 int gd_font_height()
1426 int gd_line_height()
1428 return gd_font_height()+2;
1431 /* clears one line on the screen. takes dark screen or totally black screen into consideration. */
1433 gd_clear_line(SDL_Surface
*screen
, int y
)
1440 rect
.h
=gd_font_height();
1441 if (dark_screens
!=NULL
&& dark_screens
->data
!=NULL
)
1442 SDL_BlitSurface(dark_screens
->data
, &rect
, screen
, &rect
);
1444 SDL_FillRect(screen
, &rect
, SDL_MapRGB(screen
->format
, 0, 0, 0)); /* fill rectangle with black */
1450 /* function which draws characters on the screen. used internally. */
1451 /* x=-1 -> center horizontally */
1453 blittext_font(SDL_Surface
*screen
, SDL_Surface
**font
, int x1
, int y
, const char *text
)
1462 x1
=screen
->w
/2 - (font
[0]->w
*g_utf8_strlen(text
, -1))/2;
1465 c
=g_utf8_get_char(p
);
1468 /* if it is an enter */
1478 i
=127; /* unknown char */
1482 SDL_BlitSurface(font
[i
], NULL
, screen
, &destrect
);
1487 p
=g_utf8_next_char(p
); /* next character */
1488 c
=g_utf8_get_char(p
);
1494 /* write something to the screen, with wide characters. */
1495 /* x=-1 -> center horizontally */
1497 gd_blittext(SDL_Surface
*screen
, int x
, int y
, GdColor color
, const char *text
)
1499 color
=gd_color_get_rgb(color
); /* convert to rgb, so they are stored that way in the hash table */
1500 renderfont_color(color
);
1501 return blittext_font(screen
, g_hash_table_lookup(font_w
, GUINT_TO_POINTER(color
)), x
, y
, text
);
1504 /* write something to the screen, with normal characters. */
1505 /* x=-1 -> center horizontally */
1507 gd_blittext_n(SDL_Surface
*screen
, int x
, int y
, GdColor color
, const char *text
)
1509 color
=gd_color_get_rgb(color
); /* convert to rgb, so they are stored that way in the hash table */
1510 renderfont_color(color
);
1511 return blittext_font(screen
, g_hash_table_lookup(font_n
, GUINT_TO_POINTER(color
)), x
, y
, text
);
1514 /* write something to the screen, with wide characters. */
1515 /* x=-1 -> center horizontally */
1517 gd_blittext_printf(SDL_Surface
*screen
, int x
, int y
, GdColor color
, const char *format
, ...)
1522 va_start(args
, format
);
1523 text
=g_strdup_vprintf(format
, args
);
1524 x
=gd_blittext(screen
, x
, y
, color
, text
);
1531 /* write something to the screen, with normal characters. */
1532 /* x=-1 -> center horizontally */
1534 gd_blittext_printf_n(SDL_Surface
*screen
, int x
, int y
, GdColor color
, const char *format
, ...)
1539 va_start(args
, format
);
1540 text
=g_strdup_vprintf(format
, args
);
1541 x
=gd_blittext_n(screen
, x
, y
, color
, text
);
1551 gd_select_pixbuf_colors(GdColor c0
, GdColor c1
, GdColor c2
, GdColor c3
, GdColor c4
, GdColor c5
)
1553 /* if non-c64 gfx, nothing to do */
1557 /* convert to rgb value */
1558 c0
=gd_color_get_rgb(c0
);
1559 c1
=gd_color_get_rgb(c1
);
1560 c2
=gd_color_get_rgb(c2
);
1561 c3
=gd_color_get_rgb(c3
);
1562 c4
=gd_color_get_rgb(c4
);
1563 c5
=gd_color_get_rgb(c5
);
1565 /* and compare rgb values! */
1566 if (c0
!=color0
|| c1
!=color1
|| c2
!=color2
|| c3
!=color3
|| c4
!=color4
|| c5
!=color5
) {
1567 /* if not the same colors as requested before */
1575 loadcells_from_c64_data(c0
, c1
, c2
, c3
, c4
, c5
);
1588 logical_size: logical pixel size of playfield, usually larger than the screen.
1589 physical_size: visible part. (remember: player_x-x1!)
1591 center: the coordinates to scroll to.
1592 exact: scroll exactly
1593 start: start scrolling if difference is larger than
1594 to: scroll to, if started, until difference is smaller than
1597 desired: the function stores its data here
1598 speed: the function stores its data here
1600 cell_size: size of one cell. used to determine if the play field is only a slightly larger than the screen, in that case no scrolling is desirable
1603 cave_scroll(int logical_size
, int physical_size
, int center
, gboolean exact
, int start
, int to
, int *current
, int *desired
, int speed
, int cell_size
)
1609 max
=logical_size
-physical_size
;
1615 /* if cave size smaller than the screen, no scrolling req'd */
1616 if (logical_size
<physical_size
) {
1626 /* if cave size is only a slightly larger than the screen, also no scrolling */
1627 if (logical_size
<=physical_size
+cell_size
) {
1628 *desired
=max
/2; /* scroll to the middle of the cell */
1630 /* hystheresis function.
1631 * when scrolling left, always go a bit less left than player being at the middle.
1632 * when scrolling right, always go a bit less to the right. */
1636 if (*current
+start
<center
)
1638 if (*current
-start
>center
)
1642 *desired
=gd_clamp(*desired
, 0, max
);
1644 if (*current
<*desired
) {
1645 for (i
=0; i
<speed
; i
++)
1646 if (*current
<*desired
)
1650 if (*current
> *desired
) {
1651 for (i
=0; i
<speed
; i
++)
1652 if (*current
>*desired
)
1661 /* just set current viewport to upper left. */
1663 gd_scroll_to_origin()
1672 * scrolls to the player during game play.
1673 * called by drawcave
1674 * returns true, if player is not visible-ie it is out of the visible size in the drawing area.
1677 gd_scroll(GdGame
*game
, gboolean exact_scroll
)
1679 static int scroll_desired_x
=0, scroll_desired_y
=0;
1680 gboolean out_of_window
;
1681 int player_x
, player_y
, visible_x
, visible_y
;
1684 /* max scrolling speed depends on the speed of the cave. */
1685 /* game moves cell_size_game* 1s/cave time pixels in a second. */
1686 /* scrolling moves scroll speed * 1s/scroll_time in a second. */
1687 /* these should be almost equal; scrolling speed a little slower. */
1688 /* that way, the player might reach the border with a small probability, */
1689 /* but the scrolling will not "oscillate", ie. turn on for little intervals as it has */
1690 /* caught up with the desired position. smaller is better. */
1691 int scroll_speed
=cell_size
*(gd_fine_scroll
?20:40)/game
->cave
->speed
;
1693 player_x
=game
->cave
->player_x
-game
->cave
->x1
; /* cell coordinates of player */
1694 player_y
=game
->cave
->player_y
-game
->cave
->y1
;
1695 visible_x
=(game
->cave
->x2
-game
->cave
->x1
+1)*cell_size
; /* pixel size of visible part of the cave (may be smaller in intermissions) */
1696 visible_y
=(game
->cave
->y2
-game
->cave
->y1
+1)*cell_size
;
1698 /* cell_size contains the scaled size, but we need the original. */
1700 /* some sort of scrolling speed. with larger cells, the divisor must be smaller, so the scrolling faster. */
1701 scroll_divisor
=256/cell_size
;
1703 scroll_divisor
*=2; /* as fine scrolling is 50hz, whereas normal is 25hz only */
1705 if (cave_scroll(visible_x
, play_area_w
, player_x
*cell_size
+cell_size
/2-play_area_w
/2, exact_scroll
, play_area_w
/4, play_area_w
/8, &scroll_x
, &scroll_desired_x
, scroll_speed
, cell_size
))
1707 if (cave_scroll(visible_y
, play_area_h
, player_y
*cell_size
+cell_size
/2-play_area_h
/2, exact_scroll
, play_area_h
/5, play_area_h
/10, &scroll_y
, &scroll_desired_y
, scroll_speed
, cell_size
))
1710 /* if scrolling, we should update entire gd_screen. */
1714 for (y
=0; y
<game
->cave
->h
; y
++)
1715 for (x
=0; x
<game
->cave
->w
; x
++)
1716 game
->gfx_buffer
[y
][x
] |= GD_REDRAW
;
1719 /* check if active player is visible at the moment. */
1720 out_of_window
=FALSE
;
1721 /* check if active player is outside drawing area. if yes, we should wait for scrolling */
1722 if ((player_x
*cell_size
)<scroll_x
|| (player_x
*cell_size
+cell_size
-1)>scroll_x
+play_area_w
)
1723 /* but only do the wait, if the player SHOULD BE visible, ie. he is inside the defined visible area of the cave */
1724 if (game
->cave
->player_x
>=game
->cave
->x1
&& game
->cave
->player_x
<=game
->cave
->x2
)
1726 if ((player_y
*cell_size
)<scroll_y
|| (player_y
*cell_size
+cell_size
-1)>scroll_y
+play_area_h
)
1727 /* but only do the wait, if the player SHOULD BE visible, ie. he is inside the defined visible area of the cave */
1728 if (game
->cave
->player_y
>=game
->cave
->y1
&& game
->cave
->player_y
<=game
->cave
->y2
)
1731 /* if not yet born, we treat as visible. so cave will run. the user is unable to control an unborn player, so this is the right behaviour. */
1732 if (game
->cave
->player_state
==GD_PL_NOT_YET
)
1734 return out_of_window
;
1741 gd_drawcave(SDL_Surface
*dest
, GdGame
*game
)
1745 int scroll_y_aligned
;
1747 /* on-screen clipping rectangle */
1749 cliprect
.y
=gd_statusbar_height
;
1750 cliprect
.w
=play_area_w
;
1751 cliprect
.h
=play_area_h
;
1752 SDL_SetClipRect(dest
, &cliprect
);
1754 if (gd_sdl_pal_emulation
&& gd_even_line_pal_emu_vertical_scroll
)
1755 scroll_y_aligned
=scroll_y
/2*2; /* make it even (dividable by two) */
1757 scroll_y_aligned
=scroll_y
;
1759 /* here we draw all cells to be redrawn. we do not take scrolling area into consideration - sdl will do the clipping. */
1760 for (y
=game
->cave
->y1
, yd
=0; y
<=game
->cave
->y2
; y
++, yd
++) {
1761 for (x
=game
->cave
->x1
, xd
=0; x
<=game
->cave
->x2
; x
++, xd
++) {
1762 if (game
->gfx_buffer
[y
][x
] & GD_REDRAW
) { /* if it needs to be redrawn */
1765 offset
.y
=y
*cell_size
+gd_statusbar_height
-scroll_y_aligned
; /* sdl_blitsurface destroys offset, so we have to set y here, too. (ie. in every iteration) */
1766 offset
.x
=x
*cell_size
-scroll_x
;
1768 game
->gfx_buffer
[y
][x
]=game
->gfx_buffer
[y
][x
] & ~GD_REDRAW
; /* now we have drawn it */
1770 SDL_BlitSurface(cells
[game
->gfx_buffer
[y
][x
]], NULL
, dest
, &offset
);
1775 /* restore clipping to whole screen */
1776 SDL_SetClipRect(dest
, NULL
);
1781 gd_play_game_select_status_bar_colors(GdStatusBarColors
*cols
, const GdCave
*cave
)
1783 GdColor (*color_indexer
) (int i
);
1786 /* first, count the number of c64 colors the cave uses. */
1787 /* if it uses mostly c64 colors, we will use c64 colors for the status bar. */
1788 /* otherwise we will use gdash colors. */
1789 /* note that the atari original status bar color setting only uses the game colors. */
1791 if (gd_color_is_c64(cave
->color0
)) c64_col
++;
1792 if (gd_color_is_c64(cave
->color1
)) c64_col
++;
1793 if (gd_color_is_c64(cave
->color2
)) c64_col
++;
1794 if (gd_color_is_c64(cave
->color3
)) c64_col
++;
1795 if (gd_color_is_c64(cave
->color4
)) c64_col
++;
1796 if (gd_color_is_c64(cave
->color5
)) c64_col
++;
1798 color_indexer
=gd_c64_color
;
1800 color_indexer
=gd_gdash_color
;
1802 switch (gd_status_bar_type
) {
1803 case GD_STATUS_BAR_ORIGINAL
:
1804 cols
->background
=color_indexer(GD_COLOR_INDEX_BLACK
);
1805 cols
->diamond_needed
=cols
->diamond_collected
=color_indexer(GD_COLOR_INDEX_YELLOW
);
1806 cols
->diamond_value
=cols
->score
=cols
->default_color
=color_indexer(GD_COLOR_INDEX_WHITE
);
1808 case GD_STATUS_BAR_1STB
:
1809 cols
->background
=color_indexer(GD_COLOR_INDEX_BLACK
);
1810 cols
->diamond_needed
=cols
->diamond_collected
=cols
->score
=color_indexer(GD_COLOR_INDEX_YELLOW
);
1811 cols
->diamond_value
=cols
->default_color
=color_indexer(GD_COLOR_INDEX_WHITE
);
1813 case GD_STATUS_BAR_CRLI
:
1814 cols
->background
=color_indexer(GD_COLOR_INDEX_BLACK
);
1815 cols
->diamond_needed
=color_indexer(GD_COLOR_INDEX_RED
);
1816 cols
->diamond_collected
=color_indexer(GD_COLOR_INDEX_GREEN
);
1817 cols
->diamond_value
=color_indexer(GD_COLOR_INDEX_CYAN
);
1818 cols
->score
=color_indexer(GD_COLOR_INDEX_YELLOW
);
1819 cols
->default_color
=color_indexer(GD_COLOR_INDEX_WHITE
);
1821 case GD_STATUS_BAR_FINAL
:
1822 cols
->background
=color_indexer(GD_COLOR_INDEX_BLACK
);
1823 cols
->diamond_needed
=color_indexer(GD_COLOR_INDEX_RED
);
1824 cols
->diamond_collected
=color_indexer(GD_COLOR_INDEX_GREEN
);
1825 cols
->diamond_value
=cols
->score
=cols
->default_color
=color_indexer(GD_COLOR_INDEX_WHITE
);
1827 case GD_STATUS_BAR_ATARI_ORIGINAL
:
1828 cols
->background
=cave
->color0
;
1829 cols
->diamond_needed
=cols
->diamond_collected
=cave
->color2
;
1830 cols
->diamond_value
=cols
->score
=cols
->default_color
=cave
->color3
;
1833 g_assert_not_reached();
1839 gd_clear_header(GdColor c
)
1846 r
.h
=gd_statusbar_height
;
1847 SDL_FillRect(gd_screen
, &r
, SDL_MapRGB(gd_screen
->format
, gd_color_get_r(c
), gd_color_get_g(c
), gd_color_get_b(c
)));
1851 gd_showheader_uncover(const GdGame
*game
, const GdStatusBarColors
*cols
, gboolean show_replay_sign
)
1856 gboolean first_line
;
1858 gd_clear_header(cols
->background
);
1859 first_line
=FALSE
; /* will be set to TRUE, if we draw in the next few code lines. so the y coordinate of the second status line can be decided. */
1861 /* if playing a replay, tell the user! */
1862 if (game
->type
==GD_GAMETYPE_REPLAY
&& show_replay_sign
) {
1863 gd_blittext(gd_screen
, -1, gd_statusbar_y1
, GD_GDASH_YELLOW
, "PLAYING REPLAY");
1867 /* also inform about intermission, but not if playing a replay. also the replay saver should not show it! f */
1868 if (game
->cave
->intermission
&& !game
->type
==GD_GAMETYPE_REPLAY
) {
1869 gd_blittext(gd_screen
, -1, gd_statusbar_y1
, cols
->default_color
, "ONE LIFE EXTRA");
1873 /* if not an intermission, we may show the name of the game (caveset) */
1874 if (gd_show_name_of_game
) { /* if showing the name of the cave... */
1875 len
=g_utf8_strlen(gd_caveset_data
->name
, -1);
1876 if (gd_screen
->w
/gd_font_width()/2>=len
) /* if have place for double-width font */
1877 gd_blittext(gd_screen
, -1, gd_statusbar_y1
, cols
->default_color
, gd_caveset_data
->name
);
1879 gd_blittext_n(gd_screen
, -1, gd_statusbar_y1
, cols
->default_color
, gd_caveset_data
->name
);
1884 cavename_y
=first_line
?gd_statusbar_y2
:gd_statusbar_mid
;
1885 /* "xy players, cave ab/3" */
1886 if (game
->type
==GD_GAMETYPE_NORMAL
)
1887 str
=g_strdup_printf("%d%c, %s/%d", game
->player_lives
, GD_PLAYER_CHAR
, game
->cave
->name
, game
->cave
->rendered
);
1889 /* if not a normal game, do not show number of remaining lives */
1890 str
=g_strdup_printf("%s/%d", game
->cave
->name
, game
->cave
->rendered
);
1891 len
=g_utf8_strlen(str
, -1);
1892 if (gd_screen
->w
/gd_font_width()/2>=len
) /* if have place for double-width font */
1893 gd_blittext(gd_screen
, -1, cavename_y
, cols
->default_color
, str
);
1895 gd_blittext_n(gd_screen
, -1, cavename_y
, cols
->default_color
, str
);
1900 gd_showheader_game(const GdGame
*game
, int timeout_since
, const GdStatusBarColors
*cols
, gboolean show_replay_sign
)
1903 gboolean first_line
;
1904 first_line
=FALSE
; /* will be set to TRUE, if we draw in the next few code lines. so the y coordinate of the second status line can be decided. */
1906 gd_clear_header(cols
->background
);
1908 /* if playing a replay, tell the user! */
1909 if (game
->type
==GD_GAMETYPE_REPLAY
&& show_replay_sign
) {
1910 gd_blittext(gd_screen
, -1, gd_statusbar_y1
, GD_GDASH_YELLOW
, "PLAYING REPLAY");
1914 /* y position of status bar */
1915 y
=first_line
?gd_statusbar_y2
:gd_statusbar_mid
;
1917 if (game
->cave
->player_state
==GD_PL_TIMEOUT
&& timeout_since
/50%4==0) {
1918 gd_clear_header(cols
->background
);
1919 gd_blittext(gd_screen
, -1, y
, GD_GDASH_WHITE
, "OUT OF TIME");
1922 if (game
->cave
->player_state
==GD_PL_NOT_YET
) {
1923 /* ... if the player is not yet born, we should rather show the uncover bar. */
1924 gd_showheader_uncover(game
, cols
, show_replay_sign
);
1928 if (gd_keystate
[SDLK_LSHIFT
] || gd_keystate
[SDLK_RSHIFT
]) {
1929 /* ALTERNATIVE STATUS BAR BY PRESSING SHIFT */
1932 x
=gd_blittext_printf(gd_screen
, x
, y
, cols
->default_color
, "%c%02d", GD_PLAYER_CHAR
, MIN(game
->player_lives
, 99)); /* max 99 in %2d */
1934 /* color numbers are not the same as key numbers! c3->k1, c2->k2, c1->k3 */
1935 /* this is how it was implemented in crdr7. */
1936 x
=gd_blittext_printf(gd_screen
, x
, y
, game
->cave
->color3
, "%c%1d", GD_KEY_CHAR
, MIN(game
->cave
->key1
, 9)); /* max 9 in %1d */
1938 x
=gd_blittext_printf(gd_screen
, x
, y
, game
->cave
->color2
, "%c%1d", GD_KEY_CHAR
, MIN(game
->cave
->key2
, 9));
1940 x
=gd_blittext_printf(gd_screen
, x
, y
, game
->cave
->color1
, "%c%1d", GD_KEY_CHAR
, MIN(game
->cave
->key3
, 9));
1942 if (game
->cave
->gravity_will_change
>0) {
1945 switch(game
->cave
->gravity_next_direction
) {
1946 case MV_DOWN
: gravity_char
=GD_DOWN_CHAR
; break;
1947 case MV_LEFT
: gravity_char
=GD_LEFT_CHAR
; break;
1948 case MV_RIGHT
: gravity_char
=GD_RIGHT_CHAR
; break;
1949 case MV_UP
: gravity_char
=GD_UP_CHAR
; break;
1950 default: gravity_char
='?'; break;
1952 x
=gd_blittext_printf(gd_screen
, x
, y
, cols
->default_color
, "%c%02d", gravity_char
, MIN(gd_cave_time_show(game
->cave
, game
->cave
->gravity_will_change
), 99));
1956 switch(game
->cave
->gravity
) {
1957 case MV_DOWN
: gravity_char
=GD_DOWN_CHAR
; break;
1958 case MV_LEFT
: gravity_char
=GD_LEFT_CHAR
; break;
1959 case MV_RIGHT
: gravity_char
=GD_RIGHT_CHAR
; break;
1960 case MV_UP
: gravity_char
=GD_UP_CHAR
; break;
1961 default: gravity_char
='?'; break;
1963 x
=gd_blittext_printf(gd_screen
, x
, y
, cols
->default_color
, "%c%02d", gravity_char
, 0);
1966 x
=gd_blittext_printf(gd_screen
, x
, y
, cols
->diamond_collected
, "%c%02d", GD_SKELETON_CHAR
, MIN(game
->cave
->skeletons_collected
, 99));
1968 /* NORMAL STATUS BAR */
1972 /* cave time is rounded _UP_ to seconds. so at the exact moment when it changes from
1973 2sec remaining to 1sec remaining, the player has exactly one second. when it changes
1974 to zero, it is the exact moment of timeout. */
1975 time_secs
=gd_cave_time_show(game
->cave
, game
->cave
->time
);
1977 if (gd_keystate
[SDLK_f
]) {
1978 /* fast forward mode - show "FAST" */
1979 x
=gd_blittext_printf(gd_screen
, x
, y
, cols
->default_color
, "%cFAST%c", GD_DIAMOND_CHAR
, GD_DIAMOND_CHAR
);
1981 /* normal speed mode - show diamonds NEEDED <> VALUE */
1982 /* or if collected enough diamonds, <><><> VALUE */
1983 if (game
->cave
->diamonds_needed
>game
->cave
->diamonds_collected
) {
1984 if (game
->cave
->diamonds_needed
>0)
1985 x
=gd_blittext_printf(gd_screen
, x
, y
, cols
->diamond_needed
, "%03d", game
->cave
->diamonds_needed
);
1987 /* did not already count diamonds needed */
1988 x
=gd_blittext_printf(gd_screen
, x
, y
, cols
->diamond_needed
, "%c%c%c", GD_DIAMOND_CHAR
, GD_DIAMOND_CHAR
, GD_DIAMOND_CHAR
);
1991 x
=gd_blittext_printf(gd_screen
, x
, y
, cols
->default_color
, " %c%c", GD_DIAMOND_CHAR
, GD_DIAMOND_CHAR
);
1992 x
=gd_blittext_printf(gd_screen
, x
, y
, cols
->default_color
, "%c", GD_DIAMOND_CHAR
, GD_DIAMOND_CHAR
);
1993 x
=gd_blittext_printf(gd_screen
, x
, y
, cols
->diamond_value
, "%02d", game
->cave
->diamond_value
);
1996 x
=gd_blittext_printf(gd_screen
, x
, y
, cols
->diamond_collected
, "%03d", game
->cave
->diamonds_collected
);
1998 x
=gd_blittext_printf(gd_screen
, x
, y
, cols
->default_color
, "%03d", time_secs
);
2000 x
=gd_blittext_printf(gd_screen
, x
, y
, cols
->score
, "%06d", game
->player_score
);
2018 /* the dark gray background */
2019 /* to be called at application startup */
2021 gd_create_dark_background()
2023 SDL_Surface
*tile
, *dark_tile
, *dark_screen_tiled
;
2026 g_assert(gd_screen
!=NULL
);
2028 if (dark_background
)
2029 SDL_FreeSurface(dark_background
);
2031 tile
=surface_from_raw_data(gdash_tile
, sizeof(gdash_tile
));
2032 /* 24bpp, as it has no alpha channel */
2033 dark_tile
=SDL_CreateRGBSurface(0, tile
->w
, tile
->h
, 24, 0, 0, 0, 0);
2034 SDL_BlitSurface(tile
, NULL
, dark_tile
, NULL
);
2035 SDL_FreeSurface(tile
);
2036 SDL_SetAlpha(dark_tile
, SDL_SRCALPHA
, 256/6); /* 1/6 opacity */
2038 /* create the image, and fill it with the tile. */
2039 /* the image is screen size / gd_scale, so we prefer the original screen size here */
2040 /* and only do the scaling later! */
2041 dark_screen_tiled
=SDL_CreateRGBSurface(0, gd_screen
->w
/gd_scale
, gd_screen
->h
/gd_scale
, 32, rmask
, gmask
, bmask
, amask
);
2042 for (y
=0; y
<dark_screen_tiled
->h
; y
+=dark_tile
->h
)
2043 for (x
=0; x
<dark_screen_tiled
->w
; x
+=dark_tile
->w
) {
2049 SDL_BlitSurface(dark_tile
, NULL
, dark_screen_tiled
, &rect
);
2051 SDL_FreeSurface(dark_tile
);
2052 dark_background
=displayformat(dark_screen_tiled
);
2053 SDL_FreeSurface(dark_screen_tiled
);
2059 SDL_BlitSurface(dark_background
, NULL
, gd_screen
, NULL
);
2064 * screen backup and restore functions. these are used by menus, help screens
2065 * and the like. backups and restores can be nested.
2068 /* backups the current screen contents, and darkens it. */
2069 /* later, gd_restore_screen can be called. */
2071 gd_backup_and_dark_screen()
2073 SDL_Surface
*backup_screen
, *dark_screen
;
2075 backup_screen
=SDL_CreateRGBSurface(0, gd_screen
->w
, gd_screen
->h
, 32, 0, 0, 0, 0);
2076 SDL_BlitSurface(gd_screen
, 0, backup_screen
, 0);
2078 dark_screen
=SDL_DisplayFormat(dark_background
);
2080 SDL_BlitSurface(dark_screen
, NULL
, gd_screen
, NULL
);
2082 backup_screens
=g_list_prepend(backup_screens
, backup_screen
);
2083 dark_screens
=g_list_prepend(dark_screens
, dark_screen
);
2086 /* backups the current screen contents, and clears it. */
2087 /* later, gd_restore_screen can be called. */
2089 gd_backup_and_black_screen()
2091 SDL_Surface
*backup_screen
;
2093 backup_screen
=SDL_CreateRGBSurface(0, gd_screen
->w
, gd_screen
->h
, 32, 0, 0, 0, 0);
2094 SDL_BlitSurface(gd_screen
, 0, backup_screen
, 0);
2096 backup_screens
=g_list_prepend(backup_screens
, backup_screen
);
2097 dark_screens
=g_list_prepend(dark_screens
, NULL
);
2100 /* restores a backed up screen. */
2104 SDL_Surface
*backup_screen
, *dark_screen
;
2106 /* check if lists are non-empty */
2107 g_assert(backup_screens
!=NULL
);
2108 g_assert(dark_screens
!=NULL
);
2110 backup_screen
=backup_screens
->data
;
2111 backup_screens
=g_list_delete_link(backup_screens
, backup_screens
); /* remove first */
2112 dark_screen
=dark_screens
->data
;
2113 dark_screens
=g_list_delete_link(dark_screens
, dark_screens
); /* remove first */
2115 SDL_BlitSurface(backup_screen
, 0, gd_screen
, 0);
2116 SDL_Flip(gd_screen
);
2117 SDL_FreeSurface(backup_screen
);
2119 SDL_FreeSurface(dark_screen
);