2 * Copyright (c) 2007, 2008 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.
24 #include "c64_gfx.h" /* char c64_gfx[] with (almost) original graphics */
29 #include "c64_png_colors.h"
31 #define GD_NUM_OF_CHARS 128
33 /* these can't be larger than 127, or they mess up with utf8 coding */
34 #define UNKNOWN_CHAR_INDEX 31
35 #define BACKSLASH_CHAR_INDEX 64
36 #define TILDE_CHAR_INDEX 95
37 #define UNDERSCORE_CHAR_INDEX 100
38 #define OPEN_BRACKET_CHAR_INDEX 27
39 #define CLOSE_BRACKET_CHAR_INDEX 29
40 #define CHECKED_BOX_CHAR_INDEX 121
41 #define CHECK_MARK_INDEX 122
42 #define BALL_CHAR_INDEX 104
44 int gd_scale
=1; /* a graphics scale things which sets EVERYTHING. it is set with gd_sdl_init, and cannot be modified later. */
45 int gd_scale_type
=GD_SCALING_ORIGINAL
;
47 static SDL_Surface
*cells
[2*NUM_OF_CELLS
];
48 static const guchar
*font
;
49 static GHashTable
*font_w
, *font_n
;
50 static GdColor color0
, color1
, color2
, color3
, color4
, color5
; /* currently used cell colors */
51 static guint8
*c64_custom_gfx
=NULL
;
52 static gboolean using_png_gfx
;
54 /* these masks are always for RGB and RGBA ordering in memory.
55 that is what gdk-pixbuf uses, and also what sdl uses.
58 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
59 static guint32 rmask
= 0xff000000;
60 static guint32 gmask
= 0x00ff0000;
61 static guint32 bmask
= 0x0000ff00;
62 static guint32 amask
= 0x000000ff;
64 /* for non-alpha channel gdk pixbuf includes */
65 static guint32 rmask_24
= 0xff0000;
66 static guint32 gmask_24
= 0x00ff00;
67 static guint32 bmask_24
= 0x0000ff;
69 static guint32 rmask
= 0x000000ff;
70 static guint32 gmask
= 0x0000ff00;
71 static guint32 bmask
= 0x00ff0000;
72 static guint32 amask
= 0xff000000;
74 /* for non-alpha channel gdk pixbuf includes */
75 static guint32 rmask_24
= 0x0000ff;
76 static guint32 gmask_24
= 0x00ff00;
77 static guint32 bmask_24
= 0xff0000;
82 SDL_Surface
*gd_screen
=NULL
;
83 static SDL_Surface
*dark_background
=NULL
;
84 static GList
*backup_screens
=NULL
, *dark_screens
=NULL
;
87 int statusbar_height
=20;
90 int statusbar_mid
=(20-8)/2;
91 static int scroll_x
, scroll_y
;
94 /* quit, global variable which is set to true if the application should quit */
95 gboolean gd_quit
=FALSE
;
100 static int cell_size
=16;
108 /* return name of key. names taken from sdl documentation */
110 w3m -dump file:///usr/share/doc/libsdl1.2-dev/docs/html/sdlkey.html |grep -v "──" |
111 cut -c 1-19,38- |sed "s/│$//;s/ *$//g;s/│/case /;s/ *│/: return \"/;s/$/\";/"|tee ~/keys.txt
114 gd_key_name(guint keysym
)
116 static char keyname
[30];
118 case SDLK_BACKSPACE
: return "BACKSPACE";
119 case SDLK_TAB
: return "TAB";
120 case SDLK_CLEAR
: return "CLEAR";
121 case SDLK_RETURN
: return "RETURN";
122 case SDLK_PAUSE
: return "PAUSE";
123 case SDLK_ESCAPE
: return "ESCAPE";
124 case SDLK_SPACE
: return "SPACE";
125 case SDLK_EXCLAIM
: return "EXCLAIM";
126 case SDLK_QUOTEDBL
: return "QUOTEDBL";
127 case SDLK_HASH
: return "HASH";
128 case SDLK_DOLLAR
: return "DOLLAR";
129 case SDLK_AMPERSAND
: return "AMPERSAND";
130 case SDLK_QUOTE
: return "QUOTE";
131 case SDLK_LEFTPAREN
: return "LEFT PARENTHESIS";
132 case SDLK_RIGHTPAREN
: return "RIGHT PARENTHESIS";
133 case SDLK_ASTERISK
: return "ASTERISK";
134 case SDLK_PLUS
: return "PLUS SIGN";
135 case SDLK_COMMA
: return "COMMA";
136 case SDLK_MINUS
: return "MINUS SIGN";
137 case SDLK_PERIOD
: return "PERIOD";
138 case SDLK_SLASH
: return "FORWARD SLASH";
139 case SDLK_0
: return "0";
140 case SDLK_1
: return "1";
141 case SDLK_2
: return "2";
142 case SDLK_3
: return "3";
143 case SDLK_4
: return "4";
144 case SDLK_5
: return "5";
145 case SDLK_6
: return "6";
146 case SDLK_7
: return "7";
147 case SDLK_8
: return "8";
148 case SDLK_9
: return "9";
149 case SDLK_COLON
: return "COLON";
150 case SDLK_SEMICOLON
: return "SEMICOLON";
151 case SDLK_LESS
: return "LESS-THAN SIGN";
152 case SDLK_EQUALS
: return "EQUALS SIGN";
153 case SDLK_GREATER
: return "GREATER-THAN SIGN";
154 case SDLK_QUESTION
: return "QUESTION MARK";
155 case SDLK_AT
: return "AT";
156 case SDLK_LEFTBRACKET
: return "LEFT BRACKET";
157 case SDLK_BACKSLASH
: return "BACKSLASH";
158 case SDLK_RIGHTBRACKET
: return "RIGHT BRACKET";
159 case SDLK_CARET
: return "CARET";
160 case SDLK_UNDERSCORE
: return "UNDERSCORE";
161 case SDLK_BACKQUOTE
: return "GRAVE";
162 case SDLK_a
: return "A";
163 case SDLK_b
: return "B";
164 case SDLK_c
: return "C";
165 case SDLK_d
: return "D";
166 case SDLK_e
: return "E";
167 case SDLK_f
: return "F";
168 case SDLK_g
: return "G";
169 case SDLK_h
: return "H";
170 case SDLK_i
: return "I";
171 case SDLK_j
: return "J";
172 case SDLK_k
: return "K";
173 case SDLK_l
: return "L";
174 case SDLK_m
: return "M";
175 case SDLK_n
: return "N";
176 case SDLK_o
: return "O";
177 case SDLK_p
: return "P";
178 case SDLK_q
: return "Q";
179 case SDLK_r
: return "R";
180 case SDLK_s
: return "S";
181 case SDLK_t
: return "T";
182 case SDLK_u
: return "U";
183 case SDLK_v
: return "V";
184 case SDLK_w
: return "W";
185 case SDLK_x
: return "X";
186 case SDLK_y
: return "Y";
187 case SDLK_z
: return "Z";
188 case SDLK_DELETE
: return "DELETE";
189 case SDLK_KP0
: return "KEYPAD 0";
190 case SDLK_KP1
: return "KEYPAD 1";
191 case SDLK_KP2
: return "KEYPAD 2";
192 case SDLK_KP3
: return "KEYPAD 3";
193 case SDLK_KP4
: return "KEYPAD 4";
194 case SDLK_KP5
: return "KEYPAD 5";
195 case SDLK_KP6
: return "KEYPAD 6";
196 case SDLK_KP7
: return "KEYPAD 7";
197 case SDLK_KP8
: return "KEYPAD 8";
198 case SDLK_KP9
: return "KEYPAD 9";
199 case SDLK_KP_PERIOD
: return "KEYPAD PERIOD";
200 case SDLK_KP_DIVIDE
: return "KEYPAD DIVIDE";
201 case SDLK_KP_MULTIPLY
: return "KEYPAD MULTIPLY";
202 case SDLK_KP_MINUS
: return "KEYPAD MINUS";
203 case SDLK_KP_PLUS
: return "KEYPAD PLUS";
204 case SDLK_KP_ENTER
: return "KEYPAD ENTER";
205 case SDLK_KP_EQUALS
: return "KEYPAD EQUALS";
206 case SDLK_UP
: return "UP ARROW";
207 case SDLK_DOWN
: return "DOWN ARROW";
208 case SDLK_RIGHT
: return "RIGHT ARROW";
209 case SDLK_LEFT
: return "LEFT ARROW";
210 case SDLK_INSERT
: return "INSERT";
211 case SDLK_HOME
: return "HOME";
212 case SDLK_END
: return "END";
213 case SDLK_PAGEUP
: return "PAGE UP";
214 case SDLK_PAGEDOWN
: return "PAGE DOWN";
215 case SDLK_F1
: return "F1";
216 case SDLK_F2
: return "F2";
217 case SDLK_F3
: return "F3";
218 case SDLK_F4
: return "F4";
219 case SDLK_F5
: return "F5";
220 case SDLK_F6
: return "F6";
221 case SDLK_F7
: return "F7";
222 case SDLK_F8
: return "F8";
223 case SDLK_F9
: return "F9";
224 case SDLK_F10
: return "F10";
225 case SDLK_F11
: return "F11";
226 case SDLK_F12
: return "F12";
227 case SDLK_F13
: return "F13";
228 case SDLK_F14
: return "F14";
229 case SDLK_F15
: return "F15";
230 case SDLK_NUMLOCK
: return "NUMLOCK";
231 case SDLK_CAPSLOCK
: return "CAPSLOCK";
232 case SDLK_SCROLLOCK
: return "SCROLLOCK";
233 case SDLK_RSHIFT
: return "RIGHT SHIFT";
234 case SDLK_LSHIFT
: return "LEFT SHIFT";
235 case SDLK_RCTRL
: return "RIGHT CTRL";
236 case SDLK_LCTRL
: return "LEFT CTRL";
237 case SDLK_RALT
: return "RIGHT ALT";
238 case SDLK_LALT
: return "LEFT ALT";
239 case SDLK_RMETA
: return "RIGHT META";
240 case SDLK_LMETA
: return "LEFT META";
241 case SDLK_LSUPER
: return "LEFT WINDOWS KEY";
242 case SDLK_RSUPER
: return "RIGHT WINDOWS KEY";
243 case SDLK_MODE
: return "MODE SHIFT";
244 case SDLK_HELP
: return "HELP";
245 case SDLK_PRINT
: return "PRINT-SCREEN";
246 case SDLK_SYSREQ
: return "SYSRQ";
247 case SDLK_BREAK
: return "BREAK";
248 case SDLK_MENU
: return "MENU";
249 case SDLK_POWER
: return "POWER";
250 case SDLK_EURO
: return "EURO";
252 sprintf(keyname
, "KEY %04X", keysym
);
253 return g_intern_string(keyname
); /* abuse? :) */
259 /* read a gdk-pixbuf source, and return an sdl surface. */
261 surface_from_gdk_pixbuf_data(guint32
*data
)
263 SDL_Surface
*surface
;
265 g_assert(GUINT32_FROM_BE(data
[0])==0x47646b50); /* gdk-pixbuf magic number */
266 if (GUINT32_FROM_BE(data
[2])==0x1010002) /* 32-bit rgba */
267 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
);
269 if (GUINT32_FROM_BE(data
[2])==0x1010001) /* 24-bit rgb */
270 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);
272 /* unknown pixel format */
273 g_assert_not_reached();
274 g_assert(surface
!=NULL
);
281 /* This is taken from the SDL_gfx project. */
283 SDL_rotozoom.c - rotozoomer for 32bit or 8bit surfaces
284 LGPL (c) A. Schiffler
285 32bit Zoomer with optional anti-aliasing by bilinear interpolation.
286 Zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
289 typedef struct tColorRGBA
{
296 static void zoomSurfaceRGBA(SDL_Surface
*src
, SDL_Surface
*dst
, gboolean smooth
)
298 int x
, y
, sx
, sy
, *sax
, *say
, *csax
, *csay
, csx
, csy
, ex
, ey
, t1
, t2
, sstep
;
299 tColorRGBA
*c00
, *c01
, *c10
, *c11
;
300 tColorRGBA
*sp
, *csp
, *dp
;
303 g_assert(src
->format
->BytesPerPixel
==4);
304 g_assert(dst
->format
->BytesPerPixel
==4);
308 /* For interpolation: assume source dimension is one pixel */
309 /* smaller to avoid overflow on right and bottom edge. */
310 sx
= (int) (65536.0 * (float) (src
->w
- 1) / (float) dst
->w
);
311 sy
= (int) (65536.0 * (float) (src
->h
- 1) / (float) dst
->h
);
313 sx
= (int) (65536.0 * (float) src
->w
/ (float) dst
->w
);
314 sy
= (int) (65536.0 * (float) src
->h
/ (float) dst
->h
);
317 /* Allocate memory for row increments */
318 sax
=g_new(gint32
, dst
->w
+1);
319 say
=g_new(gint32
, dst
->h
+1);
321 /* Precalculate row increments */
322 SDL_LockSurface(src
);
323 SDL_LockSurface(dst
);
324 sp
= csp
= (tColorRGBA
*) src
->pixels
;
325 dp
= (tColorRGBA
*) dst
->pixels
;
329 for (x
= 0; x
<= dst
->w
; x
++) {
337 for (y
= 0; y
<= dst
->h
; y
++) {
344 dgap
= dst
->pitch
- dst
->w
* 4;
347 * Switch between interpolating and non-interpolating code
350 /* Interpolating Zoom */
352 /* Scan destination */
354 for (y
= 0; y
< dst
->h
; y
++) {
355 /* Setup color source pointers */
359 c10
= (tColorRGBA
*) ((guint8
*) csp
+ src
->pitch
);
363 for (x
= 0; x
< dst
->w
; x
++) {
364 /* Interpolate colors */
365 ex
= (*csax
& 0xffff);
366 ey
= (*csay
& 0xffff);
367 t1
= ((((c01
->r
- c00
->r
) * ex
) >> 16) + c00
->r
) & 0xff;
368 t2
= ((((c11
->r
- c10
->r
) * ex
) >> 16) + c10
->r
) & 0xff;
369 dp
->r
= (((t2
- t1
) * ey
) >> 16) + t1
;
370 t1
= ((((c01
->g
- c00
->g
) * ex
) >> 16) + c00
->g
) & 0xff;
371 t2
= ((((c11
->g
- c10
->g
) * ex
) >> 16) + c10
->g
) & 0xff;
372 dp
->g
= (((t2
- t1
) * ey
) >> 16) + t1
;
373 t1
= ((((c01
->b
- c00
->b
) * ex
) >> 16) + c00
->b
) & 0xff;
374 t2
= ((((c11
->b
- c10
->b
) * ex
) >> 16) + c10
->b
) & 0xff;
375 dp
->b
= (((t2
- t1
) * ey
) >> 16) + t1
;
376 t1
= ((((c01
->a
- c00
->a
) * ex
) >> 16) + c00
->a
) & 0xff;
377 t2
= ((((c11
->a
- c10
->a
) * ex
) >> 16) + c10
->a
) & 0xff;
378 dp
->a
= (((t2
- t1
) * ey
) >> 16) + t1
;
380 /* Advance source pointers */
382 sstep
= (*csax
>> 16);
387 /* Advance destination pointer */
390 /* Advance source pointer */
392 csp
= (tColorRGBA
*) ((guint8
*) csp
+ (*csay
>> 16) * src
->pitch
);
393 /* Advance destination pointers */
394 dp
= (tColorRGBA
*) ((guint8
*) dp
+ dgap
);
397 /* Non-Interpolating Zoom */
399 for (y
= 0; y
< dst
->h
; y
++) {
402 for (x
= 0; x
< dst
->w
; x
++) {
405 /* Advance source pointers */
407 sstep
= (*csax
>> 16);
409 /* Advance destination pointer */
412 /* Advance source pointer */
414 sstep
= (*csay
>> 16) * src
->pitch
;
415 csp
= (tColorRGBA
*) ((guint8
*) csp
+ sstep
);
417 /* Advance destination pointers */
418 dp
= (tColorRGBA
*) ((guint8
*) dp
+ dgap
);
423 SDL_UnlockSurface(src
);
424 SDL_UnlockSurface(dst
);
426 /* Remove temp arrays */
434 scale2x(SDL_Surface
*src
, SDL_Surface
*dst
)
436 g_assert(dst
->w
== src
->w
*2);
437 g_assert(dst
->h
== src
->h
*2);
438 g_assert(src
->format
->BytesPerPixel
==4);
439 g_assert(dst
->format
->BytesPerPixel
==4);
441 SDL_LockSurface(src
);
442 SDL_LockSurface(dst
);
443 gd_scale2x(src
->pixels
, src
->w
, src
->h
, src
->pitch
, dst
->pixels
, dst
->pitch
);
444 SDL_UnlockSurface(src
);
445 SDL_UnlockSurface(dst
);
449 scale3x(SDL_Surface
*src
, SDL_Surface
*dst
)
451 g_assert(dst
->w
== src
->w
*3);
452 g_assert(dst
->h
== src
->h
*3);
453 g_assert(src
->format
->BytesPerPixel
==4);
454 g_assert(dst
->format
->BytesPerPixel
==4);
456 SDL_LockSurface(src
);
457 SDL_LockSurface(dst
);
458 gd_scale3x(src
->pixels
, src
->w
, src
->h
, src
->pitch
, dst
->pixels
, dst
->pitch
);
459 SDL_UnlockSurface(src
);
460 SDL_UnlockSurface(dst
);
467 /* nearest neighbor scaling for 2x and 3x. */
468 /* nearest pixel 2x scaling. */
470 scale_2x_nearest(SDL_Surface
*src
, SDL_Surface
*dst
)
474 guint8
*srcpix
=src
->pixels
;
475 guint8
*dstpix
=dst
->pixels
;
478 int srcpitch
=src
->pitch
;
479 int dstpitch
=dst
->pitch
;
481 g_assert(dst
->w
== src
->w
*2);
482 g_assert(dst
->h
== src
->h
*2);
483 g_assert(src
->format
->BytesPerPixel
==4);
484 g_assert(dst
->format
->BytesPerPixel
==4);
486 SDL_LockSurface(src
);
487 SDL_LockSurface(dst
);
488 for (y
=0; y
<height
; ++y
) {
489 for (x
=0; x
<width
; ++x
) {
490 E
= *(guint32
*)(srcpix
+ (y
*srcpitch
) + (4*x
));
492 *(guint32
*)(dstpix
+ y
*2*dstpitch
+ x
*2*4) = E
;
493 *(guint32
*)(dstpix
+ y
*2*dstpitch
+ (x
*2+1)*4) = E
;
494 *(guint32
*)(dstpix
+ (y
*2+1)*dstpitch
+ x
*2*4) = E
;
495 *(guint32
*)(dstpix
+ (y
*2+1)*dstpitch
+ (x
*2+1)*4) = E
;
498 SDL_UnlockSurface(src
);
499 SDL_UnlockSurface(dst
);
503 /* nearest pixel 3x scaling. the rotozoomer is not correct at the bottom of the image. */
505 scale_3x_nearest(SDL_Surface
*src
, SDL_Surface
*dst
)
509 guint8
*srcpix
=src
->pixels
;
510 guint8
*dstpix
=dst
->pixels
;
513 int srcpitch
=src
->pitch
;
514 int dstpitch
=dst
->pitch
;
516 g_assert(dst
->w
== src
->w
*3);
517 g_assert(dst
->h
== src
->h
*3);
518 g_assert(src
->format
->BytesPerPixel
==4);
519 g_assert(dst
->format
->BytesPerPixel
==4);
521 SDL_LockSurface(src
);
522 SDL_LockSurface(dst
);
523 for (y
=0; y
<height
; ++y
) {
524 int ny
=y
*3; /* new coordinate */
526 for (x
=0; x
<width
; ++ x
) {
527 int nx
=x
*3; /* new coordinate */
529 E
= *(guint32
*)(srcpix
+ (y
*srcpitch
+ 4*x
));
531 *(guint32
*)(dstpix
+ ny
*dstpitch
+ nx
*4) = E
;
532 *(guint32
*)(dstpix
+ ny
*dstpitch
+ (nx
+1)*4) = E
;
533 *(guint32
*)(dstpix
+ ny
*dstpitch
+ (nx
+2)*4) = E
;
534 *(guint32
*)(dstpix
+ (ny
+1)*dstpitch
+ nx
*4) = E
;
535 *(guint32
*)(dstpix
+ (ny
+1)*dstpitch
+ (nx
+1)*4) = E
;
536 *(guint32
*)(dstpix
+ (ny
+1)*dstpitch
+ (nx
+2)*4) = E
;
537 *(guint32
*)(dstpix
+ (ny
+2)*dstpitch
+ nx
*4) = E
;
538 *(guint32
*)(dstpix
+ (ny
+2)*dstpitch
+ (nx
+1)*4) = E
;
539 *(guint32
*)(dstpix
+ (ny
+2)*dstpitch
+ (nx
+2)*4) = E
;
542 SDL_UnlockSurface(src
);
543 SDL_UnlockSurface(dst
);
548 /* scales a pixbuf with the appropriate scaling type. */
550 surface_scale(SDL_Surface
*orig
)
552 SDL_Surface
*dest
, *dest2x
;
554 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
);
556 switch (gd_scale_type
) {
557 case GD_SCALING_ORIGINAL
:
558 SDL_BlitSurface(orig
, NULL
, dest
, NULL
);
562 scale_2x_nearest(orig
, dest
);
565 case GD_SCALING_2X_BILINEAR
:
566 zoomSurfaceRGBA(orig
, dest
, TRUE
);
569 case GD_SCALING_2X_SCALE2X
:
574 scale_3x_nearest(orig
, dest
);
577 case GD_SCALING_3X_BILINEAR
:
578 zoomSurfaceRGBA(orig
, dest
, TRUE
);
581 case GD_SCALING_3X_SCALE3X
:
586 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
);
587 scale_2x_nearest(orig
, dest2x
);
588 scale_2x_nearest(dest2x
, dest
);
589 SDL_FreeSurface(dest2x
);
592 case GD_SCALING_4X_BILINEAR
:
593 zoomSurfaceRGBA(orig
, dest
, TRUE
);
596 case GD_SCALING_4X_SCALE4X
:
597 /* scale2x applied twice. */
598 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
);
599 scale2x(orig
, dest2x
);
600 scale2x(dest2x
, dest
);
601 SDL_FreeSurface(dest2x
);
604 /* not a valid case, but to avoid compiler warning */
606 g_assert_not_reached();
616 pal_emu_surface(SDL_Surface
*image
)
618 SDL_LockSurface(image
);
619 gd_pal_emu(image
->pixels
, image
->w
, image
->h
, image
->pitch
, image
->format
->Rshift
, image
->format
->Gshift
, image
->format
->Bshift
, image
->format
->Ashift
);
620 SDL_UnlockSurface(image
);
624 /* create new surface, which is SDL_DisplayFormatted. */
625 /* it is also scaled by gd_scale. */
627 displayformat(SDL_Surface
*orig
)
629 SDL_Surface
*scaled
, *displayformat
;
631 /* at this point we must already be working with 32bit surfaces */
632 g_assert(orig
->format
->BytesPerPixel
==4);
635 scaled
=surface_scale(orig
);
636 if (gd_sdl_pal_emulation
)
637 pal_emu_surface(scaled
);
638 displayformat
=SDL_DisplayFormat(scaled
);
639 SDL_FreeSurface(scaled
);
641 return displayformat
;
644 /* needed to alpha-copy an src image over dst.
645 the resulting image of sdl_blitsurface is not exact?!
646 can't explain why. */
648 copy_alpha(SDL_Surface
*src
, SDL_Surface
*dst
)
652 g_assert(src
->format
->BytesPerPixel
==4);
653 g_assert(dst
->format
->BytesPerPixel
==4);
654 g_assert(src
->w
== dst
->w
);
655 g_assert(src
->h
== dst
->h
);
657 SDL_LockSurface(src
);
658 SDL_LockSurface(dst
);
659 for (y
=0; y
<src
->h
; y
++) {
660 guint32
*srcpix
=(guint32
*)((guint8
*)src
->pixels
+ src
->pitch
*y
);
661 guint32
*dstpix
=(guint32
*)((guint8
*)dst
->pixels
+ dst
->pitch
*y
);
662 for (x
=0; x
<src
->w
; x
++) {
663 if ((srcpix
[x
]&src
->format
->Amask
)>>src
->format
->Ashift
) /* if alpha is nonzero */
664 dstpix
[x
]=srcpix
[x
]; /* copy pixel as it is */
667 SDL_UnlockSurface(src
);
668 SDL_UnlockSurface(dst
);
671 /* create and return an array of surfaces, which contain the title animation.
672 the array is one pointer larger than all frames; the last pointer is a null.
673 up to the caller to free.
676 gd_get_title_animation()
682 SDL_Surface
**animation
;
685 screen
=surface_from_gdk_pixbuf_data((guint32
*) gdash_screen
);
686 tile
=surface_from_gdk_pixbuf_data((guint32
*) gdash_tile
);
688 /* do not allow more than 40 frames of animation */
689 g_assert(tile
->h
<40);
690 animation
=g_new0(SDL_Surface
*, tile
->h
+1);
692 /* create a big image, which is one tile larger than the title image size */
693 bigone
=SDL_CreateRGBSurface(0, screen
->w
, screen
->h
+tile
->h
, 32, 0, 0, 0, 0);
694 /* and fill it with the tile. */
695 for (y
=0; y
<screen
->h
+tile
->h
; y
+=tile
->h
)
696 for (x
=0; x
<screen
->w
; x
+=tile
->h
) {
701 SDL_BlitSurface(tile
, 0, bigone
, &dest
);
704 frame
=SDL_CreateRGBSurface(0, screen
->w
, screen
->h
, 32, rmask
, gmask
, bmask
, amask
); /* must be same *mask so copy_alpha works correctly */
705 for (i
=0; i
<tile
->h
; i
++) {
708 /* copy part of the big tiled image */
713 SDL_BlitSurface(bigone
, &src
, frame
, 0);
714 /* and composite it with the title image */
715 copy_alpha(screen
, frame
);
717 animation
[i
]=displayformat(frame
);
719 SDL_FreeSurface(frame
);
720 SDL_FreeSurface(bigone
);
721 SDL_FreeSurface(screen
);
722 SDL_FreeSurface(tile
);
728 rendered_font_free(gpointer font
)
732 /* null-terminated list of pointers to sdl_surfaces */
733 for(p
=font
; p
!=NULL
; p
++)
740 gd_sdl_init(GdScalingType scaling_type
)
744 /* set the cell scale option. */
745 gd_scale_type
=scaling_type
;
746 gd_scale
=gd_scaling_scale
[gd_scale_type
];
747 play_area_w
*=gd_scale
;
748 play_area_h
*=gd_scale
;
749 statusbar_y1
*=gd_scale
;
750 statusbar_y2
*=gd_scale
;
751 statusbar_height
*=gd_scale
;
752 statusbar_mid
*=gd_scale
;
754 SDL_Init(SDL_INIT_TIMER
|SDL_INIT_VIDEO
|SDL_INIT_JOYSTICK
);
755 SDL_EnableKeyRepeat(250, 100);
756 gd_screen
=SDL_SetVideoMode(play_area_w
, play_area_h
+statusbar_height
, 32, SDL_ANYFORMAT
| (gd_sdl_fullscreen
?SDL_FULLSCREEN
:0));
757 SDL_ShowCursor(SDL_DISABLE
);
761 /* keyboard, joystick */
762 gd_keystate
=SDL_GetKeyState(NULL
);
763 if (SDL_NumJoysticks()>0)
764 gd_joy
=SDL_JoystickOpen(0);
767 icon
=surface_from_gdk_pixbuf_data((guint32
*) gdash_32
);
768 SDL_WM_SetIcon(icon
, NULL
);
769 SDL_WM_SetCaption("GDash", NULL
);
770 SDL_FreeSurface(icon
);
772 font_n
=g_hash_table_new_full(g_direct_hash
, g_direct_equal
, NULL
, rendered_font_free
);
773 font_w
=g_hash_table_new_full(g_direct_hash
, g_direct_equal
, NULL
, rendered_font_free
);
781 static inline gboolean
784 return gd_joy
!=NULL
&& SDL_JoystickGetAxis(gd_joy
, 1)<-3200;
787 static inline gboolean
790 return gd_joy
!=NULL
&& SDL_JoystickGetAxis(gd_joy
, 1)>3200;
793 static inline gboolean
796 return gd_joy
!=NULL
&& SDL_JoystickGetAxis(gd_joy
, 0)<-3200;
799 static inline gboolean
802 return gd_joy
!=NULL
&& SDL_JoystickGetAxis(gd_joy
, 0)>3200;
805 static inline gboolean
808 return gd_joy
!=NULL
&& (SDL_JoystickGetButton(gd_joy
, 0) || SDL_JoystickGetButton(gd_joy
, 1));
817 return gd_keystate
[gd_sdl_key_up
] || gd_joy_up();
823 return gd_keystate
[gd_sdl_key_down
] || gd_joy_down();
829 return gd_keystate
[gd_sdl_key_left
] || gd_joy_left();
835 return gd_keystate
[gd_sdl_key_right
] || gd_joy_right();
841 return gd_keystate
[gd_sdl_key_fire_1
] || gd_keystate
[gd_sdl_key_fire_2
] || gd_joy_fire();
847 /* like the above one, but used in the main menu */
849 gd_space_or_enter_or_fire()
851 /* set these to zero, so each keypress is reported only once */
852 return gd_joy_fire() || gd_keystate
[SDLK_SPACE
] || gd_keystate
[SDLK_RETURN
];
861 width: width of playfield.
862 visible: visible part. (remember: player_x-x1!)
864 center: the coordinates to scroll to.
865 exact: scroll exactly
866 start: start scrolling
867 to: scroll to, if started
870 desired: the function stores its data here
871 speed: the function stores its data here
874 cave_scroll(int width
, int visible
, int center
, gboolean exact
, int start
, int to
, int *current
, int *desired
, int *speed
, int divisor
)
882 /* hystheresis function.
883 * when scrolling left, always go a bit less left than player being at the middle.
884 * when scrolling right, always go a bit less to the right. */
899 if (*current
+start
<center
)
901 if (*current
-start
>center
)
904 *desired
=CLAMP(*desired
, 0, width
-visible
);
906 /* adaptive scrolling speed.
907 * gets faster with distance.
908 * minimum speed is 1, to allow scrolling precisely to the desired positions (important at borders).
910 if (*speed
<ABS(*desired
-*current
)/divisor
+1)
912 if (*speed
>ABS(*desired
-*current
)/divisor
+1)
914 if (*current
< *desired
) {
915 for (i
=0; i
< *speed
; i
++)
916 if (*current
< *desired
)
920 if (*current
> *desired
) {
921 for (i
=0; i
< *speed
; i
++)
922 if (*current
> *desired
)
936 /* remove pixmaps from x server */
942 /* if cells already loaded, unref them */
943 for (i
=0; i
<G_N_ELEMENTS(cells
); i
++)
945 SDL_FreeSurface(cells
[i
]);
952 loadcells(SDL_Surface
*image
)
955 int pixbuf_cell_size
;
959 /* if we have display-formatted pixmaps, remove them */
962 /* 8 (NUM_OF_CELLS_X) cells in a row, so divide by it and we get the size of a cell in pixels */
963 pixbuf_cell_size
=image
->w
/NUM_OF_CELLS_X
;
964 cell_size
=pixbuf_cell_size
*gd_scale
;
966 rect
=SDL_CreateRGBSurface(0, pixbuf_cell_size
, pixbuf_cell_size
, 32, 0, 0, 0, 0); /* no amask, as we set overall alpha! */
967 SDL_FillRect(rect
, NULL
, SDL_MapRGB(rect
->format
, (gd_flash_color
>>16)&0xff, (gd_flash_color
>>8)&0xff, gd_flash_color
&0xff));
968 SDL_SetAlpha(rect
, SDL_SRCALPHA
, 128); /* 50% alpha; nice choice. also sdl is rendering faster for the special value alpha=128 */
970 cut
=SDL_CreateRGBSurface(0, pixbuf_cell_size
, pixbuf_cell_size
, 32, rmask
, gmask
, bmask
, amask
);
972 /* make individual cells */
973 for (i
=0; i
<NUM_OF_CELLS_X
*NUM_OF_CELLS_Y
; i
++) {
976 from
.x
=(i
%NUM_OF_CELLS_X
)*pixbuf_cell_size
;
977 from
.y
=(i
/NUM_OF_CELLS_X
)*pixbuf_cell_size
;
978 from
.w
=pixbuf_cell_size
;
979 from
.h
=pixbuf_cell_size
;
981 SDL_BlitSurface(image
, &from
, cut
, NULL
);
983 cells
[i
]=displayformat(cut
);
984 SDL_BlitSurface(rect
, NULL
, cut
, NULL
); /* create yellowish image */
985 cells
[NUM_OF_CELLS
+i
]=displayformat(cut
);
987 SDL_FreeSurface(cut
);
988 SDL_FreeSurface(rect
);
991 /* sets one of the colors in the indexed palette of an sdl surface to a GdColor. */
993 setpalette(SDL_Surface
*image
, int index
, GdColor col
)
996 c
.r
=gd_color_get_r(col
);
997 c
.g
=gd_color_get_g(col
);
998 c
.b
=gd_color_get_b(col
);
1000 SDL_SetPalette(image
, SDL_LOGPAL
|SDL_PHYSPAL
, &c
, index
, 1);
1004 loadcells_c64(GdColor c0
, GdColor c1
, GdColor c2
, GdColor c3
, GdColor c4
, GdColor c5
)
1006 const guint8
*gfx
; /* currently used graphics, will point to c64_gfx or c64_custom_gfx */
1009 gfx
=c64_custom_gfx
?c64_custom_gfx
:c64_gfx
;
1011 /* create a 8-bit palette and set its colors */
1012 /* gfx[0] is the pixel width and height of one cell. */
1013 /* from gfx[1], we have the color data, one byte/pixel. so this is an indexed color image: 8bit/pixel. */
1014 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);
1015 /* sdl supports paletted images, so this is very easy: */
1016 setpalette(image
, 0, 0);
1017 setpalette(image
, 1, c0
);
1018 setpalette(image
, 2, c1
);
1019 setpalette(image
, 3, c2
);
1020 setpalette(image
, 4, c3
);
1021 setpalette(image
, 5, c4
);
1022 setpalette(image
, 6, c5
);
1023 setpalette(image
, 7, 0);
1024 setpalette(image
, 8, 0);
1026 /* from here, same as any other image */
1028 SDL_FreeSurface(image
);
1031 /* takes a c64_gfx.png-coded 32-bit pixbuf, and creates a paletted pixbuf in our internal format. */
1033 c64_gfx_data_from_pixbuf(SDL_Surface
*image
)
1039 g_assert(image
->format
->BytesPerPixel
==4);
1041 data
=g_new(guint8
, image
->w
*image
->h
+1);
1043 data
[out
++]=image
->w
/NUM_OF_CELLS_X
;
1045 SDL_LockSurface(image
);
1046 for (y
=0; y
<image
->h
; y
++) {
1047 guint32
*p
=(guint32
*)((char *)image
->pixels
+y
*image
->pitch
);
1049 for (x
=0; x
<image
->w
; x
++) {
1052 r
=(p
[x
]&image
->format
->Rmask
) >> image
->format
->Rshift
<< image
->format
->Rloss
;
1053 g
=(p
[x
]&image
->format
->Gmask
) >> image
->format
->Gshift
<< image
->format
->Gloss
;
1054 b
=(p
[x
]&image
->format
->Bmask
) >> image
->format
->Bshift
<< image
->format
->Bloss
;
1055 a
=(p
[x
]&image
->format
->Amask
) >> image
->format
->Ashift
<< image
->format
->Aloss
;
1057 data
[out
++]=c64_png_colors(r
, g
, b
, a
);
1060 SDL_UnlockSurface(image
);
1066 /* returns true, if the given pixbuf seems to be a c64 imported image. */
1068 check_if_pixbuf_c64_png(SDL_Surface
*image
)
1074 g_assert(image
->format
->BytesPerPixel
==4);
1076 SDL_LockSurface(image
);
1078 for (y
=0; y
<image
->h
; y
++) {
1079 p
=((guchar
*)image
->pixels
) + y
* image
->pitch
;
1080 for (x
=0; x
<image
->w
*image
->format
->BytesPerPixel
; x
++)
1081 if (p
[x
]!=0 && p
[x
]!=255)
1084 SDL_UnlockSurface(image
);
1089 /* check if given surface is ok to be a gdash theme. */
1091 gd_is_surface_ok_for_theme (SDL_Surface
*surface
)
1093 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
)) {
1094 g_warning("image should contain %d cells in a row and %d in a column!", NUM_OF_CELLS_X
, NUM_OF_CELLS_Y
);
1095 return FALSE
; /* Image should contain 16 cells in a row and 32 in a column! */
1097 /* we do not check for an alpha channel, as in the gtk version. we do not need it here. */
1098 /* the gtk version needs it because of the editor. */
1100 return TRUE
; /* passed checks */
1104 /* load theme from bmp file. */
1105 /* return true if successful. */
1107 gd_loadcells_file(const char *filename
)
1109 SDL_Surface
*surface
, *converted
;
1111 /* load cell graphics */
1112 /* load from file */
1113 surface
=SDL_LoadBMP(filename
);
1116 g_warning("%s: unable to load image", filename
);
1120 /* do some checks. if those fail, the error is already reported by the function */
1121 if (!gd_is_surface_ok_for_theme(surface
)) {
1122 SDL_FreeSurface(surface
);
1126 /* convert to 32bit rgba */
1127 converted
=SDL_CreateRGBSurface(0, surface
->w
, surface
->h
, 32, rmask
, bmask
, gmask
, amask
);
1128 SDL_BlitSurface(surface
, NULL
, converted
, NULL
);
1129 SDL_FreeSurface(surface
);
1131 if (check_if_pixbuf_c64_png(converted
)) {
1132 /* c64 pixbuf with a small number of colors which can be changed */
1133 g_free(c64_custom_gfx
);
1134 c64_custom_gfx
=c64_gfx_data_from_pixbuf(converted
);
1135 using_png_gfx
=FALSE
;
1137 /* normal, "truecolor" pixbuf */
1138 g_free(c64_custom_gfx
);
1139 c64_custom_gfx
=NULL
;
1141 loadcells(converted
);
1143 SDL_FreeSurface(converted
);
1144 color0
=GD_COLOR_INVALID
; /* this is an invalid gdash color; so redraw is forced */
1151 /* load the theme specified in gd_sdl_theme. */
1152 /* if successful, ok. */
1153 /* if fails, or no theme specified, load the builtin, and forget gd_sdl_theme */
1158 if (!gd_loadcells_file(gd_sdl_theme
)) {
1159 /* if failing to load the bmp file specified in the config file: forget the setting now, and load the builtin. */
1160 g_free(gd_sdl_theme
);
1165 gd_loadcells_default(); /* if no theme specified, or loading the file failed, simply load the builtin. */
1170 /* C64 FONT HANDLING */
1172 /* creates a guint32 value, which can be raw-written to a sdl_surface memory area. */
1173 /* takes the pixel format of the surface into consideration. */
1175 rgba_pixel_from_gdcolor(SDL_PixelFormat
*format
, GdColor col
, guint8 a
)
1177 return SDL_MapRGBA(format
, gd_color_get_r(col
), gd_color_get_g(col
), gd_color_get_b(col
), a
);
1181 /* FIXME fixed font size: 8x8 */
1182 /* renders the fonts for a specific color. */
1183 /* the wide font draws black pixels, the narrow (normal) font does not! */
1185 renderfont_color(GdColor color
)
1189 SDL_Surface
*image
, *image_n
;
1190 SDL_Surface
**fn
, **fw
;
1192 /* check that we already got an rgb color */
1193 g_assert(gd_color_is_rgb(color
));
1195 /* if already rendered, return now */
1196 if (g_hash_table_lookup(font_w
, GUINT_TO_POINTER(color
)))
1199 fn
=g_new0(SDL_Surface
*, GD_NUM_OF_CHARS
+1);
1200 fw
=g_new0(SDL_Surface
*, GD_NUM_OF_CHARS
+1);
1202 /* colors data into memory */
1203 image
=SDL_CreateRGBSurface(0, 16, 8, 32, rmask
, gmask
, bmask
, amask
);
1204 image_n
=SDL_CreateRGBSurface(0, 8, 8, 32, rmask
, gmask
, bmask
, amask
);
1206 col
=rgba_pixel_from_gdcolor(image
->format
, color
, 0xff);
1207 black
=rgba_pixel_from_gdcolor(image
->format
, 0, 0xff);
1209 /* for all characters */
1210 /* render character in "image", then do a displayformat(image) to generate the resulting one */
1211 for (j
=0; j
<GD_NUM_OF_CHARS
; j
++) {
1214 y1
=(j
/16)*8; /* 16 characters in a row */
1217 SDL_LockSurface(image
);
1218 SDL_LockSurface(image_n
);
1219 for (y
=0; y
<8; y
++) {
1220 guint32
*p
=(guint32
*) ((char *)image
->pixels
+ y
*image
->pitch
);
1221 guint32
*p_n
=(guint32
*) ((char *)image_n
->pixels
+ y
*image_n
->pitch
);
1223 for (x
=0; x
<8; x
++) {
1224 /* the font array is encoded the same way as a c64-colored pixbuf. see c64_gfx_data...() */
1225 if (font
[(y1
+y
)*128+x1
+x
]!=1) {
1226 p
[0]=col
; /* wide */
1228 p_n
[0]=col
; /* normal */
1230 p
[0]=black
; /* wide */
1232 p_n
[0]=black
; /* normal */
1238 SDL_UnlockSurface(image
);
1239 SDL_UnlockSurface(image_n
);
1240 fw
[j
]=displayformat(image
);
1241 fn
[j
]=displayformat(image_n
);
1242 /* small font does not draw black background */
1243 SDL_SetColorKey(fn
[j
], SDL_SRCCOLORKEY
, SDL_MapRGB(fn
[j
]->format
, 0, 0, 0));
1245 SDL_FreeSurface(image
);
1246 SDL_FreeSurface(image_n
);
1248 g_hash_table_insert(font_w
, GINT_TO_POINTER(color
), fw
);
1249 g_hash_table_insert(font_n
, GINT_TO_POINTER(color
), fn
);
1252 /* XXX these functions are not really implemented */
1256 /* forget all previously rendered chars */
1257 g_hash_table_remove_all(font_w
);
1258 g_hash_table_remove_all(font_n
);
1262 /* loads a font from a file */
1264 gd_loadfont_file(const char *filename
)
1266 g_assert_not_reached();
1269 /* loads inlined c64 font */
1271 gd_loadfont_default()
1273 font
=c64_font
+1; /* first byte in c64_gfx[] is the "cell size", we ignore that */
1280 int gd_font_height()
1290 int gd_line_height()
1292 return gd_font_height()+2;
1295 /* clears one line on the screen. takes dark screen or totally black screen into consideration. */
1297 gd_clear_line(SDL_Surface
*screen
, int y
)
1304 rect
.h
=gd_font_height();
1305 if (dark_screens
!=NULL
&& dark_screens
->data
!=NULL
)
1306 SDL_BlitSurface(dark_screens
->data
, &rect
, screen
, &rect
);
1308 SDL_FillRect(screen
, &rect
, SDL_MapRGB(screen
->format
, 0, 0, 0)); /* fill rectangle with black */
1313 /* function which draws characters on the screen. used internally. */
1314 /* x=-1 -> center horizontally */
1316 gd_blittext_font(SDL_Surface
*screen
, SDL_Surface
**font
, int x1
, int y
, const char *text
)
1325 x1
=screen
->w
/2 - (font
[0]->w
*g_utf8_strlen(text
, -1))/2;
1328 c
=g_utf8_get_char(p
);
1331 /* if it is an enter */
1338 /* it is a normal character */
1339 if (c
==GD_CHECKED_BOX_CHAR
)
1340 i
=CHECKED_BOX_CHAR_INDEX
;
1342 if (c
==GD_BALL_CHAR
)
1345 if (c
==GD_CHECK_MARK_CHAR
)
1348 if (c
==GD_PLAYER_CHAR
|| c
==GD_DIAMOND_CHAR
|| c
==GD_UNCHECKED_BOX_CHAR
) /* special, by gdash */
1357 if (c
>=' ' && c
<='Z') /* from space to Z, petscii=ascii */
1360 if (c
>='a' && c
<='z')
1364 i
=BACKSLASH_CHAR_INDEX
;
1367 i
=UNDERSCORE_CHAR_INDEX
;
1373 i
=OPEN_BRACKET_CHAR_INDEX
;
1376 i
=CLOSE_BRACKET_CHAR_INDEX
;
1378 i
=UNKNOWN_CHAR_INDEX
;
1382 SDL_BlitSurface(font
[i
], NULL
, screen
, &destrect
);
1387 p
=g_utf8_next_char(p
); /* next character */
1388 c
=g_utf8_get_char(p
);
1394 /* write something to the screen, with wide characters. */
1395 /* x=-1 -> center horizontally */
1397 gd_blittext(SDL_Surface
*screen
, int x
, int y
, GdColor color
, const char *text
)
1399 color
=gd_color_get_rgb(color
); /* convert to rgb, so they are stored that way in the hash table */
1400 renderfont_color(color
);
1401 return gd_blittext_font(screen
, g_hash_table_lookup(font_w
, GUINT_TO_POINTER(color
)), x
, y
, text
);
1404 /* write something to the screen, with normal characters. */
1405 /* x=-1 -> center horizontally */
1407 gd_blittext_n(SDL_Surface
*screen
, int x
, int y
, GdColor color
, const char *text
)
1409 color
=gd_color_get_rgb(color
); /* convert to rgb, so they are stored that way in the hash table */
1410 renderfont_color(color
);
1411 return gd_blittext_font(screen
, g_hash_table_lookup(font_n
, GUINT_TO_POINTER(color
)), x
, y
, text
);
1414 /* write something to the screen, with wide characters. */
1415 /* x=-1 -> center horizontally */
1417 gd_blittext_printf(SDL_Surface
*screen
, int x
, int y
, GdColor color
, const char *format
, ...)
1422 va_start(args
, format
);
1423 text
=g_strdup_vprintf(format
, args
);
1424 x
=gd_blittext(screen
, x
, y
, color
, text
);
1431 /* write something to the screen, with normal characters. */
1432 /* x=-1 -> center horizontally */
1434 gd_blittext_printf_n(SDL_Surface
*screen
, int x
, int y
, GdColor color
, const char *format
, ...)
1439 va_start(args
, format
);
1440 text
=g_strdup_vprintf(format
, args
);
1441 x
=gd_blittext_n(screen
, x
, y
, color
, text
);
1451 gd_select_pixbuf_colors(GdColor c0
, GdColor c1
, GdColor c2
, GdColor c3
, GdColor c4
, GdColor c5
)
1453 /* if non-c64 gfx, nothing to do */
1457 /* convert to rgb value */
1458 c0
=gd_color_get_rgb(c0
);
1459 c1
=gd_color_get_rgb(c1
);
1460 c2
=gd_color_get_rgb(c2
);
1461 c3
=gd_color_get_rgb(c3
);
1462 c4
=gd_color_get_rgb(c4
);
1463 c5
=gd_color_get_rgb(c5
);
1465 /* and compare rgb values! */
1466 if (c0
!=color0
|| c1
!=color1
|| c2
!=color2
|| c3
!=color3
|| c4
!=color4
|| c5
!=color5
) {
1467 /* if not the same colors as requested before */
1475 loadcells_c64(c0
, c1
, c2
, c3
, c4
, c5
);
1479 /* selects built-in graphics */
1481 gd_loadcells_default()
1483 g_free(c64_custom_gfx
);
1484 c64_custom_gfx
=NULL
;
1485 using_png_gfx
=FALSE
;
1486 /* just to set some default */
1487 color0
=GD_COLOR_INVALID
; /* this is an invalid gdash color; so redraw is forced */
1490 /* the dark gray background */
1492 gd_create_dark_background()
1494 SDL_Surface
*tile
, *dark_tile
, *dark_screen_tiled
;
1497 g_assert(gd_screen
!=NULL
);
1499 if (dark_background
)
1500 SDL_FreeSurface(dark_background
);
1502 tile
=surface_from_gdk_pixbuf_data((guint32
*) gdash_tile
);
1503 /* 24bpp, as it has no alpha channel */
1504 dark_tile
=SDL_CreateRGBSurface(0, tile
->w
, tile
->h
, 24, 0, 0, 0, 0);
1505 SDL_BlitSurface(tile
, NULL
, dark_tile
, NULL
);
1506 SDL_FreeSurface(tile
);
1507 SDL_SetAlpha(dark_tile
, SDL_SRCALPHA
, 256/6); /* 1/6 opacity */
1509 /* create the image, and fill it with the tile. */
1510 /* the image is screen size / gd_scale, so we prefer the original screen size here */
1511 /* and only do the scaling later! */
1512 dark_screen_tiled
=SDL_CreateRGBSurface(0, gd_screen
->w
/gd_scale
, gd_screen
->h
/gd_scale
, 32, rmask
, gmask
, bmask
, amask
);
1513 for (y
=0; y
<dark_screen_tiled
->h
; y
+=dark_tile
->h
)
1514 for (x
=0; x
<dark_screen_tiled
->w
; x
+=dark_tile
->w
) {
1520 SDL_BlitSurface(dark_tile
, NULL
, dark_screen_tiled
, &rect
);
1522 SDL_FreeSurface(dark_tile
);
1523 dark_background
=displayformat(dark_screen_tiled
);
1524 SDL_FreeSurface(dark_screen_tiled
);
1530 * screen backup and restore functions. these are used by menus, help screens
1531 * and the like. backups and restores can be nested.
1534 /* backups the current screen contents, and darkens it. */
1535 /* later, gd_restore_screen can be called. */
1537 gd_backup_and_dark_screen()
1539 SDL_Surface
*backup_screen
, *dark_screen
;
1541 backup_screen
=SDL_CreateRGBSurface(0, gd_screen
->w
, gd_screen
->h
, 32, 0, 0, 0, 0);
1542 SDL_BlitSurface(gd_screen
, 0, backup_screen
, 0);
1544 dark_screen
=SDL_DisplayFormat(dark_background
);
1546 SDL_BlitSurface(dark_screen
, NULL
, gd_screen
, NULL
);
1548 backup_screens
=g_list_prepend(backup_screens
, backup_screen
);
1549 dark_screens
=g_list_prepend(dark_screens
, dark_screen
);
1552 /* backups the current screen contents, and clears it. */
1553 /* later, gd_restore_screen can be called. */
1555 gd_backup_and_black_screen()
1557 SDL_Surface
*backup_screen
;
1559 backup_screen
=SDL_CreateRGBSurface(0, gd_screen
->w
, gd_screen
->h
, 32, 0, 0, 0, 0);
1560 SDL_BlitSurface(gd_screen
, 0, backup_screen
, 0);
1562 backup_screens
=g_list_prepend(backup_screens
, backup_screen
);
1563 dark_screens
=g_list_prepend(dark_screens
, NULL
);
1566 /* restores a backed up screen. */
1570 SDL_Surface
*backup_screen
, *dark_screen
;
1572 /* check if lists are non-empty */
1573 g_assert(backup_screens
!=NULL
);
1574 g_assert(dark_screens
!=NULL
);
1576 backup_screen
=backup_screens
->data
;
1577 backup_screens
=g_list_delete_link(backup_screens
, backup_screens
); /* remove first */
1578 dark_screen
=dark_screens
->data
;
1579 dark_screens
=g_list_delete_link(dark_screens
, dark_screens
); /* remove first */
1581 SDL_BlitSurface(backup_screen
, 0, gd_screen
, 0);
1582 SDL_Flip(gd_screen
);
1583 SDL_FreeSurface(backup_screen
);
1585 SDL_FreeSurface(dark_screen
);
1590 /* process pending events, so presses and releases are applied */
1591 /* also check for quit event */
1593 gd_process_pending_events()
1597 /* process pending events, so presses and releases are applied */
1598 while (SDL_PollEvent(&event
)) {
1599 /* meanwhile, if we receive a quit event, we set the global variable. */
1600 if (event
.type
==SDL_QUIT
)
1607 /* this function waits until SPACE, ENTER and ESCAPE are released */
1609 gd_wait_for_key_releases()
1611 /* wait until the user releases return and escape */
1612 while (gd_keystate
[SDLK_RETURN
]!=0 || gd_keystate
[SDLK_ESCAPE
]!=0 || gd_keystate
[SDLK_SPACE
]!=0 || gd_keystate
[SDLK_n
]!=0 || gd_fire()) {
1615 /* process pending events, so presses and releases are applied */
1616 while (SDL_PollEvent(&event
)) {
1617 /* meanwhile, if we receive a quit event, we set the global variable. */
1618 if (event
.type
==SDL_QUIT
)
1622 SDL_Delay(50); /* do not eat cpu */
1634 /* just set current viewport to upper left. */
1636 gd_scroll_to_origin()
1645 * scrolls to the player during game play.
1646 * called by drawcave
1647 * returns true, if player is not visible-ie it is out of the visible size in the drawing area.
1650 gd_scroll(const Cave
*cave
, gboolean exact_scroll
)
1652 static int scroll_desired_x
=0, scroll_desired_y
=0;
1653 static int scroll_speed_x
=0, scroll_speed_y
=0;
1654 gboolean out_of_window
;
1655 int player_x
, player_y
, visible_x
, visible_y
;
1659 player_x
=cave
->player_x
-cave
->x1
; /* cell coordinates of player */
1660 player_y
=cave
->player_y
-cave
->y1
;
1661 visible_x
=(cave
->x2
-cave
->x1
+1)*cell_size
; /* pixel size of visible part of the cave (may be smaller in intermissions) */
1662 visible_y
=(cave
->y2
-cave
->y1
+1)*cell_size
;
1665 scroll_divisor
=12; /* some sort of scrolling speed */
1667 scroll_divisor
*=2; /* as fine scrolling is 50hz, whereas normal is 25hz only */
1668 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_x
, scroll_divisor
))
1670 if (cave_scroll(visible_y
, play_area_h
, player_y
*cell_size
+cell_size
/2-play_area_h
/2, exact_scroll
, play_area_h
/4, play_area_h
/8, &scroll_y
, &scroll_desired_y
, &scroll_speed_y
, scroll_divisor
))
1673 /* if scrolling, we should update entire gd_screen. */
1677 for (y
=0; y
<gd_gameplay
.cave
->h
; y
++)
1678 for (x
=0; x
<gd_gameplay
.cave
->w
; x
++)
1679 gd_gameplay
.gfx_buffer
[y
][x
] |= GD_REDRAW
;
1682 /* check if active player is visible at the moment. */
1683 out_of_window
=FALSE
;
1684 /* check if active player is outside drawing area. if yes, we should wait for scrolling */
1685 if ((player_x
*cell_size
)<scroll_x
|| (player_x
*cell_size
+cell_size
-1)>scroll_x
+play_area_w
)
1686 /* but only do the wait, if the player SHOULD BE visible, ie. he is inside the defined visible area of the cave */
1687 if (cave
->player_x
>=cave
->x1
&& cave
->player_x
<=cave
->x2
)
1689 if ((player_y
*cell_size
)<scroll_y
|| (player_y
*cell_size
+cell_size
-1)>scroll_y
+play_area_h
)
1690 /* but only do the wait, if the player SHOULD BE visible, ie. he is inside the defined visible area of the cave */
1691 if (cave
->player_y
>=cave
->y1
&& cave
->player_y
<=cave
->y2
)
1694 /* 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. */
1695 if (cave
->player_state
==GD_PL_NOT_YET
)
1697 return out_of_window
;
1704 gd_drawcave(SDL_Surface
*dest
, const Cave
*cave
, int **gfx_buffer
)
1708 int scroll_y_aligned
;
1710 /* on-screen clipping rectangle */
1712 cliprect
.y
=statusbar_height
;
1713 cliprect
.w
=play_area_w
;
1714 cliprect
.h
=play_area_h
;
1715 SDL_SetClipRect(dest
, &cliprect
);
1717 /* for the paused parameter, we set FALSE here, as the sdl version does not color the playfield when paused */
1718 if (gd_sdl_pal_emulation
&& gd_even_line_pal_emu_vertical_scroll
)
1719 /* make it even (dividable by two) */
1720 scroll_y_aligned
=scroll_y
/2*2;
1722 scroll_y_aligned
=scroll_y
;
1723 /* here we draw all cells to be redrawn. we do not take scrolling area into consideration - sdl will do the clipping. */
1724 for (y
=cave
->y1
, yd
=0; y
<=cave
->y2
; y
++, yd
++) {
1725 for (x
=cave
->x1
, xd
=0; x
<=cave
->x2
; x
++, xd
++) {
1726 if (gd_gameplay
.gfx_buffer
[y
][x
] & GD_REDRAW
) { /* if it needs to be redrawn */
1729 offset
.y
=y
*cell_size
+statusbar_height
-scroll_y_aligned
; /* sdl_blitsurface destroys offset, so we have to set y here, too. (ie. in every iteration) */
1730 offset
.x
=x
*cell_size
-scroll_x
;
1732 gd_gameplay
.gfx_buffer
[y
][x
]=gd_gameplay
.gfx_buffer
[y
][x
] & ~GD_REDRAW
; /* now we have drawn it */
1734 SDL_BlitSurface(cells
[gfx_buffer
[y
][x
]], NULL
, dest
, &offset
);
1739 /* restore clipping to whole screen */
1740 SDL_SetClipRect(dest
, NULL
);