rnd-20100623-1-src
[rocksndiamonds.git] / src / libgame / system.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * system.c                                                 *
12 ***********************************************************/
13
14 #include <string.h>
15 #include <signal.h>
16
17 #include "platform.h"
18
19 #if defined(PLATFORM_MSDOS)
20 #include <fcntl.h>
21 #endif
22
23 #include "system.h"
24 #include "image.h"
25 #include "sound.h"
26 #include "setup.h"
27 #include "joystick.h"
28 #include "misc.h"
29
30
31 /* ========================================================================= */
32 /* exported variables                                                        */
33 /* ========================================================================= */
34
35 struct ProgramInfo      program;
36 struct OptionInfo       options;
37 struct VideoSystemInfo  video;
38 struct AudioSystemInfo  audio;
39 struct GfxInfo          gfx;
40 struct ArtworkInfo      artwork;
41 struct JoystickInfo     joystick;
42 struct SetupInfo        setup;
43
44 LevelDirTree           *leveldir_first_all = NULL;
45 LevelDirTree           *leveldir_first = NULL;
46 LevelDirTree           *leveldir_current = NULL;
47 int                     level_nr;
48
49 Display                *display = NULL;
50 Visual                 *visual = NULL;
51 int                     screen = 0;
52 Colormap                cmap = None;
53
54 DrawWindow             *window = NULL;
55 DrawBuffer             *backbuffer = NULL;
56 DrawBuffer             *drawto = NULL;
57
58 int                     button_status = MB_NOT_PRESSED;
59 boolean                 motion_status = FALSE;
60
61 int                     redraw_mask = REDRAW_NONE;
62 int                     redraw_tiles = 0;
63
64 int                     FrameCounter = 0;
65
66
67 /* ========================================================================= */
68 /* init/close functions                                                      */
69 /* ========================================================================= */
70
71 void InitProgramInfo(char *argv0,
72                      char *userdata_subdir, char *userdata_subdir_unix,
73                      char *program_title, char *window_title, char *icon_title,
74                      char *x11_icon_filename, char *x11_iconmask_filename,
75                      char *sdl_icon_filename, char *msdos_cursor_filename,
76                      char *cookie_prefix, char *filename_prefix,
77                      int program_version)
78 {
79   program.command_basepath = getBasePath(argv0);
80   program.command_basename = getBaseName(argv0);
81
82   program.userdata_subdir = userdata_subdir;
83   program.userdata_subdir_unix = userdata_subdir_unix;
84   program.userdata_path = getUserGameDataDir();
85
86   program.program_title = program_title;
87   program.window_title = window_title;
88   program.icon_title = icon_title;
89
90   program.x11_icon_filename = x11_icon_filename;
91   program.x11_iconmask_filename = x11_iconmask_filename;
92   program.sdl_icon_filename = sdl_icon_filename;
93   program.msdos_cursor_filename = msdos_cursor_filename;
94
95   program.cookie_prefix = cookie_prefix;
96   program.filename_prefix = filename_prefix;
97
98   program.version_major = VERSION_MAJOR(program_version);
99   program.version_minor = VERSION_MINOR(program_version);
100   program.version_patch = VERSION_PATCH(program_version);
101
102   program.error_filename = getErrorFilename(ERROR_BASENAME);
103   program.error_file = stderr;
104 }
105
106 void InitExitFunction(void (*exit_function)(int))
107 {
108   program.exit_function = exit_function;
109
110   /* set signal handlers to custom exit function */
111   signal(SIGINT, exit_function);
112   signal(SIGTERM, exit_function);
113
114 #if defined(TARGET_SDL)
115   /* set exit function to automatically cleanup SDL stuff after exit() */
116   atexit(SDL_Quit);
117 #endif
118 }
119
120 void InitPlatformDependentStuff(void)
121 {
122 #if defined(PLATFORM_MSDOS)
123   _fmode = O_BINARY;
124 #endif
125
126 #if defined(PLATFORM_MACOSX)
127   updateUserGameDataDir();
128 #endif
129
130 #if !defined(PLATFORM_UNIX) || defined(PLATFORM_MACOSX)
131   openErrorFile();
132 #endif
133
134 #if defined(TARGET_SDL)
135   if (SDL_Init(SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE) < 0)
136     Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
137
138   SDLNet_Init();
139 #endif
140 }
141
142 void ClosePlatformDependentStuff(void)
143 {
144 #if defined(PLATFORM_WIN32) || defined(PLATFORM_MSDOS)
145   closeErrorFile();
146 #endif
147
148 #if defined(PLATFORM_MSDOS)
149   dumpErrorFile();
150 #endif
151 }
152
153 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
154                       int real_sx, int real_sy,
155                       int full_sxsize, int full_sysize,
156                       Bitmap *field_save_buffer)
157 {
158   gfx.sx = sx;
159   gfx.sy = sy;
160   gfx.sxsize = sxsize;
161   gfx.sysize = sysize;
162   gfx.real_sx = real_sx;
163   gfx.real_sy = real_sy;
164   gfx.full_sxsize = full_sxsize;
165   gfx.full_sysize = full_sysize;
166
167   gfx.field_save_buffer = field_save_buffer;
168
169 #if 0
170   gfx.background_bitmap = NULL;
171   gfx.background_bitmap_mask = REDRAW_NONE;
172 #endif
173
174   SetDrawDeactivationMask(REDRAW_NONE);         /* do not deactivate drawing */
175   SetDrawBackgroundMask(REDRAW_NONE);           /* deactivate masked drawing */
176 }
177
178 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
179 {
180   gfx.dx = dx;
181   gfx.dy = dy;
182   gfx.dxsize = dxsize;
183   gfx.dysize = dysize;
184 }
185
186 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
187 {
188   gfx.vx = vx;
189   gfx.vy = vy;
190   gfx.vxsize = vxsize;
191   gfx.vysize = vysize;
192 }
193
194 void InitGfxWindowInfo(int win_xsize, int win_ysize)
195 {
196   gfx.win_xsize = win_xsize;
197   gfx.win_ysize = win_ysize;
198
199 #if 1
200   gfx.background_bitmap_mask = REDRAW_NONE;
201
202   ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize, DEFAULT_DEPTH);
203 #endif
204 }
205
206 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
207 {
208   /* currently only used by MSDOS code to alloc VRAM buffer, if available */
209   /* 2009-03-24: also (temporarily?) used for overlapping blit workaround */
210   gfx.scrollbuffer_width = scrollbuffer_width;
211   gfx.scrollbuffer_height = scrollbuffer_height;
212 }
213
214 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
215 {
216   gfx.clipping_enabled = enabled;
217   gfx.clip_x = x;
218   gfx.clip_y = y;
219   gfx.clip_width = width;
220   gfx.clip_height = height;
221 }
222
223 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
224 {
225   gfx.draw_busy_anim_function = draw_busy_anim_function;
226 }
227
228 void InitGfxCustomArtworkInfo()
229 {
230   gfx.override_level_graphics = FALSE;
231   gfx.override_level_sounds = FALSE;
232   gfx.override_level_music = FALSE;
233
234   gfx.draw_init_text = TRUE;
235 }
236
237 void SetDrawDeactivationMask(int draw_deactivation_mask)
238 {
239   gfx.draw_deactivation_mask = draw_deactivation_mask;
240 }
241
242 void SetDrawBackgroundMask(int draw_background_mask)
243 {
244   gfx.draw_background_mask = draw_background_mask;
245 }
246
247 #if 0
248
249 static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile,
250                                int dest_x, int dest_y, int width, int height)
251 {
252   int bitmap_xsize = width;
253   int bitmap_ysize = height;
254   int tile_xsize = tile->width;
255   int tile_ysize = tile->height;
256   int tile_xsteps = (bitmap_xsize + tile_xsize - 1) / tile_xsize;
257   int tile_ysteps = (bitmap_ysize + tile_ysize - 1) / tile_ysize;
258   int x, y;
259
260   for (y = 0; y < tile_ysteps; y++)
261   {
262     for (x = 0; x < tile_xsteps; x++)
263     {
264       int draw_x = dest_x + x * tile_xsize;
265       int draw_y = dest_y + y * tile_ysize;
266       int draw_xsize = MIN(tile_xsize, bitmap_xsize - x * tile_xsize);
267       int draw_ysize = MIN(tile_ysize, bitmap_ysize - y * tile_ysize);
268
269       BlitBitmap(tile, bitmap, 0, 0, draw_xsize, draw_ysize, draw_x, draw_y);
270     }
271   }
272 }
273
274 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
275 {
276   if (background_bitmap_tile != NULL)
277     gfx.background_bitmap_mask |= mask;
278   else
279     gfx.background_bitmap_mask &= ~mask;
280
281 #if 0
282   if (gfx.background_bitmap == NULL)
283     gfx.background_bitmap = CreateBitmap(video.width, video.height,
284                                          DEFAULT_DEPTH);
285 #endif
286
287   if (background_bitmap_tile == NULL)   /* empty background requested */
288     return;
289
290   if (mask == REDRAW_ALL)
291     DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
292                        0, 0, video.width, video.height);
293   else if (mask == REDRAW_FIELD)
294     DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
295                        gfx.real_sx, gfx.real_sy,
296                        gfx.full_sxsize, gfx.full_sysize);
297   else if (mask == REDRAW_DOOR_1)
298   {
299     DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
300                        gfx.dx, gfx.dy,
301                        gfx.dxsize, gfx.dysize);
302   }
303 }
304
305 #else
306
307 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
308 {
309   if (background_bitmap_tile != NULL)
310     gfx.background_bitmap_mask |= mask;
311   else
312     gfx.background_bitmap_mask &= ~mask;
313
314 #if 0
315   if (gfx.background_bitmap == NULL)
316     gfx.background_bitmap = CreateBitmap(video.width, video.height,
317                                          DEFAULT_DEPTH);
318 #endif
319
320   if (background_bitmap_tile == NULL)   /* empty background requested */
321     return;
322
323   if (mask == REDRAW_ALL)
324     BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
325                     0, 0, video.width, video.height);
326   else if (mask == REDRAW_FIELD)
327     BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
328                     gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
329   else if (mask == REDRAW_DOOR_1)
330   {
331     BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
332                     gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
333   }
334 }
335
336 #endif
337
338 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
339 {
340   /* remove every mask before setting mask for window */
341   /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
342   SetBackgroundBitmap(NULL, 0xffff);            /* !!! FIX THIS !!! */
343   SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
344 }
345
346 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
347 {
348   /* remove window area mask before setting mask for main area */
349   /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
350   SetBackgroundBitmap(NULL, REDRAW_ALL);        /* !!! FIX THIS !!! */
351   SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
352 }
353
354 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
355 {
356   /* remove window area mask before setting mask for door area */
357   /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
358   SetBackgroundBitmap(NULL, REDRAW_ALL);        /* !!! FIX THIS !!! */
359   SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
360 }
361
362
363 /* ========================================================================= */
364 /* video functions                                                           */
365 /* ========================================================================= */
366
367 inline static int GetRealDepth(int depth)
368 {
369   return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
370 }
371
372 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
373                                int width, int height, Pixel color)
374 {
375 #if defined(TARGET_SDL)
376   SDLFillRectangle(bitmap, x, y, width, height, color);
377 #else
378   X11FillRectangle(bitmap, x, y, width, height, color);
379 #endif
380 }
381
382 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
383                                int src_x, int src_y, int width, int height,
384                                int dst_x, int dst_y, int mask_mode)
385 {
386 #if defined(TARGET_SDL)
387   SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
388               dst_x, dst_y, mask_mode);
389 #else
390   X11CopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
391               dst_x, dst_y, mask_mode);
392 #endif
393 }
394
395 void InitVideoDisplay(void)
396 {
397 #if defined(TARGET_SDL)
398   SDLInitVideoDisplay();
399 #else
400   X11InitVideoDisplay();
401 #endif
402 }
403
404 void CloseVideoDisplay(void)
405 {
406   KeyboardAutoRepeatOn();
407
408 #if defined(TARGET_SDL)
409   SDL_QuitSubSystem(SDL_INIT_VIDEO);
410 #else
411   if (display)
412     XCloseDisplay(display);
413 #endif
414 }
415
416 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
417 {
418   video.width = width;
419   video.height = height;
420   video.depth = GetRealDepth(depth);
421
422   video.fullscreen_available = FULLSCREEN_STATUS;
423   video.fullscreen_enabled = FALSE;
424 #if 0
425   video.fullscreen_mode_current = NULL;
426   video.fullscreen_modes = NULL;
427 #endif
428
429 #if defined(TARGET_SDL)
430   SDLInitVideoBuffer(&backbuffer, &window, fullscreen);
431 #else
432   X11InitVideoBuffer(&backbuffer, &window);
433 #endif
434
435   drawto = backbuffer;
436 }
437
438 inline static void FreeBitmapPointers(Bitmap *bitmap)
439 {
440   if (bitmap == NULL)
441     return;
442
443 #if defined(TARGET_SDL)
444   SDLFreeBitmapPointers(bitmap);
445 #else
446   X11FreeBitmapPointers(bitmap);
447 #endif
448
449   checked_free(bitmap->source_filename);
450   bitmap->source_filename = NULL;
451 }
452
453 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
454                                           Bitmap *dst_bitmap)
455 {
456   if (src_bitmap == NULL || dst_bitmap == NULL)
457     return;
458
459   FreeBitmapPointers(dst_bitmap);
460
461   *dst_bitmap = *src_bitmap;
462 }
463
464 void FreeBitmap(Bitmap *bitmap)
465 {
466   if (bitmap == NULL)
467     return;
468
469   FreeBitmapPointers(bitmap);
470
471   free(bitmap);
472 }
473
474 Bitmap *CreateBitmapStruct(void)
475 {
476 #if defined(TARGET_SDL)
477   return checked_calloc(sizeof(struct SDLSurfaceInfo));
478 #else
479   return checked_calloc(sizeof(struct X11DrawableInfo));
480 #endif
481 }
482
483 Bitmap *CreateBitmap(int width, int height, int depth)
484 {
485   Bitmap *new_bitmap = CreateBitmapStruct();
486   int real_width  = MAX(1, width);      /* prevent zero bitmap width */
487   int real_height = MAX(1, height);     /* prevent zero bitmap height */
488   int real_depth  = GetRealDepth(depth);
489
490 #if defined(TARGET_SDL)
491   SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
492 #else
493   X11CreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
494 #endif
495
496   new_bitmap->width  = real_width;
497   new_bitmap->height = real_height;
498
499   return new_bitmap;
500 }
501
502 void ReCreateBitmap(Bitmap **bitmap, int width, int height, int depth)
503 {
504   Bitmap *new_bitmap = CreateBitmap(width, height, depth);
505
506   if (*bitmap == NULL)
507   {
508     *bitmap = new_bitmap;
509   }
510   else
511   {
512     TransferBitmapPointers(new_bitmap, *bitmap);
513     free(new_bitmap);
514   }
515 }
516
517 void CloseWindow(DrawWindow *window)
518 {
519 #if defined(TARGET_X11)
520   X11CloseWindow(window);
521 #endif
522 }
523
524 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
525                                        int draw_mask)
526 {
527   if (draw_mask == REDRAW_NONE)
528     return FALSE;
529
530   if (draw_mask & REDRAW_ALL)
531     return TRUE;
532
533   if ((draw_mask & REDRAW_FIELD) &&
534       x >= gfx.real_sx && x < gfx.real_sx + gfx.full_sxsize)
535     return TRUE;
536
537   if ((draw_mask & REDRAW_DOOR_1) &&
538       x >= gfx.dx && y < gfx.dy + gfx.dysize)
539     return TRUE;
540
541   if ((draw_mask & REDRAW_DOOR_2) &&
542       x >= gfx.dx && y >= gfx.vy)
543     return TRUE;
544
545   return FALSE;
546 }
547
548 boolean DrawingDeactivated(int x, int y, int width, int height)
549 {
550   return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
551 }
552
553 boolean DrawingOnBackground(int x, int y)
554 {
555   return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
556           CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
557 }
558
559 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
560                                   int *width, int *height, boolean is_dest)
561 {
562 #if 1
563   int clip_x, clip_y, clip_width, clip_height;
564
565   if (gfx.clipping_enabled && is_dest)  /* only clip destination bitmap */
566   {
567     clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
568     clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
569     clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
570     clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
571   }
572   else
573   {
574     clip_x = 0;
575     clip_y = 0;
576     clip_width = bitmap->width;
577     clip_height = bitmap->height;
578   }
579
580   /* skip if rectangle completely outside bitmap */
581
582   if (*x + *width  <= clip_x ||
583       *y + *height <= clip_y ||
584       *x >= clip_x + clip_width ||
585       *y >= clip_y + clip_height)
586     return FALSE;
587
588   /* clip if rectangle overlaps bitmap */
589
590   if (*x < clip_x)
591   {
592     *width -= clip_x - *x;
593     *x = clip_x;
594   }
595   else if (*x + *width > clip_x + clip_width)
596   {
597     *width = clip_x + clip_width - *x;
598   }
599
600   if (*y < clip_y)
601   {
602     *height -= clip_y - *y;
603     *y = clip_y;
604   }
605   else if (*y + *height > clip_y + clip_height)
606   {
607     *height = clip_y + clip_height - *y;
608   }
609
610   return TRUE;
611
612 #else
613
614   /* skip if rectangle completely outside bitmap */
615
616   if (*x + *width <= 0 ||
617       *y + *height <= 0 ||
618       *x >= bitmap->width ||
619       *y >= bitmap->height)
620     return FALSE;
621
622   /* clip if rectangle overlaps bitmap */
623
624   if (*x < 0)
625   {
626     *width += *x;
627     *x = 0;
628   }
629   else if (*x + *width > bitmap->width)
630   {
631     *width = bitmap->width - *x;
632   }
633
634   if (*y < 0)
635   {
636     *height += *y;
637     *y = 0;
638   }
639   else if (*y + *height > bitmap->height)
640   {
641     *height = bitmap->height - *y;
642   }
643
644   return TRUE;
645 #endif
646 }
647
648 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
649                 int src_x, int src_y, int width, int height,
650                 int dst_x, int dst_y)
651 {
652   int dst_x_unclipped = dst_x;
653   int dst_y_unclipped = dst_y;
654
655   if (DrawingDeactivated(dst_x, dst_y, width, height))
656     return;
657
658 #if 1
659   if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
660       !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
661     return;
662
663   /* source x/y might need adjustment if destination x/y was clipped top/left */
664   src_x += dst_x - dst_x_unclipped;
665   src_y += dst_y - dst_y_unclipped;
666
667 #else
668   /* skip if rectangle starts outside bitmap */
669   if (src_x >= src_bitmap->width ||
670       src_y >= src_bitmap->height ||
671       dst_x >= dst_bitmap->width ||
672       dst_y >= dst_bitmap->height)
673     return;
674
675   /* clip if rectangle overlaps bitmap */
676   if (src_x + width > src_bitmap->width)
677     width = src_bitmap->width - src_x;
678   if (src_y + height > src_bitmap->height)
679     height = src_bitmap->height - src_y;
680   if (dst_x + width > dst_bitmap->width)
681     width = dst_bitmap->width - dst_x;
682   if (dst_y + height > dst_bitmap->height)
683     height = dst_bitmap->height - dst_y;
684 #endif
685
686 #if 0
687   /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
688   /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
689      but is already fixed in SVN and should therefore finally be fixed with
690      the next official SDL release, which is probably version 1.2.14.) */
691 #if 1
692   /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
693 #if defined(TARGET_SDL) && defined(PLATFORM_WIN32)
694   if (src_bitmap == dst_bitmap)
695   {
696     /* !!! THIS IS A BUG (IN THE SDL LIBRARY?) AND SHOULD BE FIXED !!! */
697
698     /* needed when blitting directly to same bitmap -- should not be needed with
699        recent SDL libraries, but apparently does not work in 1.2.11 directly */
700
701     static Bitmap *tmp_bitmap = NULL;
702     static int tmp_bitmap_xsize = 0;
703     static int tmp_bitmap_ysize = 0;
704
705     /* start with largest static bitmaps for initial bitmap size ... */
706     if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
707     {
708       tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
709       tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
710     }
711
712     /* ... and allow for later re-adjustments due to custom artwork bitmaps */
713     if (src_bitmap->width > tmp_bitmap_xsize ||
714         src_bitmap->height > tmp_bitmap_ysize)
715     {
716       tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
717       tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
718
719       FreeBitmap(tmp_bitmap);
720
721       tmp_bitmap = NULL;
722     }
723
724     if (tmp_bitmap == NULL)
725       tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
726                                 DEFAULT_DEPTH);
727
728     sysCopyArea(src_bitmap, tmp_bitmap,
729                 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
730     sysCopyArea(tmp_bitmap, dst_bitmap,
731                 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
732
733     return;
734   }
735 #endif
736 #endif
737 #endif
738
739 #if 0
740   if (dst_x < gfx.sx + gfx.sxsize)
741     printf("::: %d: BlitBitmap(%d, %d, %d, %d)\n",
742            FrameCounter, dst_x, dst_y, width, height);
743 #endif
744
745   sysCopyArea(src_bitmap, dst_bitmap,
746               src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
747 }
748
749 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
750                      int src_x, int src_y, int src_width, int src_height,
751                      int dst_x, int dst_y, int dst_width, int dst_height)
752 {
753   int src_xsize = (src_width  == 0 ? src_bitmap->width  : src_width);
754   int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
755   int dst_xsize = dst_width;
756   int dst_ysize = dst_height;
757   int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
758   int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
759   int x, y;
760
761   for (y = 0; y < src_ysteps; y++)
762   {
763     for (x = 0; x < src_xsteps; x++)
764     {
765       int draw_x = dst_x + x * src_xsize;
766       int draw_y = dst_y + y * src_ysize;
767       int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
768       int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
769
770       BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
771                  draw_x, draw_y);
772     }
773   }
774 }
775
776 void FadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
777                    int fade_mode, int fade_delay, int post_delay,
778                    void (*draw_border_function)(void))
779 {
780 #if 1
781   /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
782   if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
783     return;
784 #endif
785
786 #if defined(TARGET_SDL)
787   SDLFadeRectangle(bitmap_cross, x, y, width, height,
788                    fade_mode, fade_delay, post_delay, draw_border_function);
789 #else
790   X11FadeRectangle(bitmap_cross, x, y, width, height,
791                    fade_mode, fade_delay, post_delay, draw_border_function);
792 #endif
793 }
794
795 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
796                    Pixel color)
797 {
798   if (DrawingDeactivated(x, y, width, height))
799     return;
800
801 #if 1
802   if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
803     return;
804 #else
805   /* skip if rectangle starts outside bitmap */
806   if (x >= bitmap->width ||
807       y >= bitmap->height)
808     return;
809
810   /* clip if rectangle overlaps bitmap */
811   if (x + width > bitmap->width)
812     width = bitmap->width - x;
813   if (y + height > bitmap->height)
814     height = bitmap->height - y;
815 #endif
816
817   sysFillRectangle(bitmap, x, y, width, height, color);
818 }
819
820 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
821 {
822   FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
823 }
824
825 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
826                                 int width, int height)
827 {
828   if (DrawingOnBackground(x, y))
829     BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
830   else
831     ClearRectangle(bitmap, x, y, width, height);
832 }
833
834 void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
835 {
836 #if defined(TARGET_X11)
837   if (clip_gc)
838   {
839     bitmap->clip_gc = clip_gc;
840     XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
841   }
842 #endif
843 }
844
845 void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
846 {
847 #if defined(TARGET_X11)
848   if (clip_gc)
849   {
850     bitmap->clip_gc = clip_gc;
851     XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
852   }
853 #endif
854 }
855
856 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
857                       int src_x, int src_y, int width, int height,
858                       int dst_x, int dst_y)
859 {
860   if (DrawingDeactivated(dst_x, dst_y, width, height))
861     return;
862
863   sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
864               dst_x, dst_y, BLIT_MASKED);
865 }
866
867 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
868                             int src_x, int src_y, int width, int height,
869                             int dst_x, int dst_y)
870 {
871   if (DrawingOnBackground(dst_x, dst_y))
872   {
873     /* draw background */
874     BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
875                dst_x, dst_y);
876
877     /* draw foreground */
878     SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
879                   dst_x - src_x, dst_y - src_y);
880     BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
881                      dst_x, dst_y);
882   }
883   else
884     BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
885                dst_x, dst_y);
886 }
887
888 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
889                          int to_x, int to_y)
890 {
891 #if defined(TARGET_SDL)
892   SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
893 #else
894   X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
895 #endif
896 }
897
898 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
899                          int to_x, int to_y)
900 {
901 #if defined(TARGET_SDL)
902   SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
903 #else
904   X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
905 #endif
906 }
907
908 #if !defined(TARGET_X11_NATIVE)
909 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
910               int to_x, int to_y, Pixel pixel, int line_width)
911 {
912   int x, y;
913
914   for (x = 0; x < line_width; x++)
915   {
916     for (y = 0; y < line_width; y++)
917     {
918       int dx = x - line_width / 2;
919       int dy = y - line_width / 2;
920
921       if ((x == 0 && y == 0) ||
922           (x == 0 && y == line_width - 1) ||
923           (x == line_width - 1 && y == 0) ||
924           (x == line_width - 1 && y == line_width - 1))
925         continue;
926
927 #if defined(TARGET_SDL)
928       SDLDrawLine(bitmap,
929                   from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
930 #elif defined(TARGET_ALLEGRO)
931       AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy,
932                       to_x + dx, to_y + dy, pixel);
933 #endif
934     }
935   }
936 }
937 #endif
938
939 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
940 {
941 #if !defined(TARGET_X11_NATIVE)
942   int line_width = 4;
943   int i;
944
945   for (i = 0; i < num_points - 1; i++)
946     DrawLine(bitmap, points[i].x, points[i].y,
947              points[i + 1].x, points[i + 1].y, pixel, line_width);
948
949   /*
950   SDLDrawLines(bitmap->surface, points, num_points, pixel);
951   */
952 #else
953   XSetForeground(display, bitmap->line_gc[1], pixel);
954   XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
955              (XPoint *)points, num_points, CoordModeOrigin);
956 #endif
957 }
958
959 Pixel GetPixel(Bitmap *bitmap, int x, int y)
960 {
961   if (x < 0 || x >= bitmap->width ||
962       y < 0 || y >= bitmap->height)
963     return BLACK_PIXEL;
964
965 #if defined(TARGET_SDL)
966   return SDLGetPixel(bitmap, x, y);
967 #elif defined(TARGET_ALLEGRO)
968   return AllegroGetPixel(bitmap->drawable, x, y);
969 #else
970   return X11GetPixel(bitmap, x, y);
971 #endif
972 }
973
974 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
975                       unsigned int color_g, unsigned int color_b)
976 {
977 #if defined(TARGET_SDL)
978   return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
979 #elif defined(TARGET_ALLEGRO)
980   return AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
981 #else
982   return X11GetPixelFromRGB(color_r, color_g, color_b);
983 #endif
984 }
985
986 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
987 {
988   unsigned int color_r = (color >> 16) & 0xff;
989   unsigned int color_g = (color >>  8) & 0xff;
990   unsigned int color_b = (color >>  0) & 0xff;
991
992   return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
993 }
994
995 /* execute all pending screen drawing operations */
996 void FlushDisplay(void)
997 {
998 #ifndef TARGET_SDL
999   XFlush(display);
1000 #endif
1001 }
1002
1003 /* execute and wait for all pending screen drawing operations */
1004 void SyncDisplay(void)
1005 {
1006 #ifndef TARGET_SDL
1007   XSync(display, FALSE);
1008 #endif
1009 }
1010
1011 void KeyboardAutoRepeatOn(void)
1012 {
1013 #if defined(TARGET_SDL)
1014   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
1015                       SDL_DEFAULT_REPEAT_INTERVAL / 2);
1016   SDL_EnableUNICODE(1);
1017 #else
1018   if (display)
1019     XAutoRepeatOn(display);
1020 #endif
1021 }
1022
1023 void KeyboardAutoRepeatOff(void)
1024 {
1025 #if defined(TARGET_SDL)
1026   SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1027   SDL_EnableUNICODE(0);
1028 #else
1029   if (display)
1030     XAutoRepeatOff(display);
1031 #endif
1032 }
1033
1034 boolean PointerInWindow(DrawWindow *window)
1035 {
1036 #if defined(TARGET_SDL)
1037   return TRUE;
1038 #else
1039   Window root, child;
1040   int root_x, root_y;
1041   unsigned int mask;
1042   int win_x, win_y;
1043
1044   /* if XQueryPointer() returns False, the pointer
1045      is not on the same screen as the specified window */
1046   return XQueryPointer(display, window->drawable, &root, &child,
1047                        &root_x, &root_y, &win_x, &win_y, &mask);
1048 #endif
1049 }
1050
1051 boolean SetVideoMode(boolean fullscreen)
1052 {
1053 #if defined(TARGET_SDL)
1054   return SDLSetVideoMode(&backbuffer, fullscreen);
1055 #else
1056   boolean success = TRUE;
1057
1058   if (fullscreen && video.fullscreen_available)
1059   {
1060     Error(ERR_WARN, "fullscreen not available in X11 version");
1061
1062     /* display error message only once */
1063     video.fullscreen_available = FALSE;
1064
1065     success = FALSE;
1066   }
1067
1068   return success;
1069 #endif
1070 }
1071
1072 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1073 {
1074 #if defined(TARGET_SDL)
1075   if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1076       (!fullscreen && video.fullscreen_enabled))
1077     fullscreen = SetVideoMode(fullscreen);
1078 #endif
1079
1080   return fullscreen;
1081 }
1082
1083 Bitmap *LoadImage(char *filename)
1084 {
1085   Bitmap *new_bitmap;
1086
1087 #if defined(TARGET_SDL)
1088   new_bitmap = SDLLoadImage(filename);
1089 #else
1090   new_bitmap = X11LoadImage(filename);
1091 #endif
1092
1093   if (new_bitmap)
1094     new_bitmap->source_filename = getStringCopy(filename);
1095
1096   return new_bitmap;
1097 }
1098
1099 Bitmap *LoadCustomImage(char *basename)
1100 {
1101   char *filename = getCustomImageFilename(basename);
1102   Bitmap *new_bitmap;
1103
1104   if (filename == NULL)
1105     Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1106
1107   if ((new_bitmap = LoadImage(filename)) == NULL)
1108     Error(ERR_EXIT, "LoadImage() failed: %s", GetError());
1109
1110   return new_bitmap;
1111 }
1112
1113 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1114 {
1115   char *filename = getCustomImageFilename(basename);
1116   Bitmap *new_bitmap;
1117
1118   if (filename == NULL)         /* (should never happen) */
1119   {
1120     Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1121     return;
1122   }
1123
1124   if (strEqual(filename, bitmap->source_filename))
1125   {
1126     /* The old and new image are the same (have the same filename and path).
1127        This usually means that this image does not exist in this graphic set
1128        and a fallback to the existing image is done. */
1129
1130     return;
1131   }
1132
1133   if ((new_bitmap = LoadImage(filename)) == NULL)
1134   {
1135     Error(ERR_WARN, "LoadImage() failed: %s", GetError());
1136     return;
1137   }
1138
1139   if (bitmap->width != new_bitmap->width ||
1140       bitmap->height != new_bitmap->height)
1141   {
1142     Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1143           filename);
1144     FreeBitmap(new_bitmap);
1145     return;
1146   }
1147
1148   TransferBitmapPointers(new_bitmap, bitmap);
1149   free(new_bitmap);
1150 }
1151
1152 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1153 {
1154   Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
1155
1156 #if defined(TARGET_SDL)
1157   SDLZoomBitmap(src_bitmap, dst_bitmap);
1158 #else
1159   X11ZoomBitmap(src_bitmap, dst_bitmap);
1160 #endif
1161
1162   return dst_bitmap;
1163 }
1164
1165 static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor,
1166                                 boolean create_small_bitmaps)
1167 {
1168   Bitmap swap_bitmap;
1169   Bitmap *new_bitmap;
1170   Bitmap *tmp_bitmap_1;
1171   Bitmap *tmp_bitmap_2;
1172   Bitmap *tmp_bitmap_4;
1173   Bitmap *tmp_bitmap_8;
1174   Bitmap *tmp_bitmap_16;
1175   Bitmap *tmp_bitmap_32;
1176   int width_1, height_1;
1177   int width_2, height_2;
1178   int width_4, height_4;
1179   int width_8, height_8;
1180   int width_16, height_16;
1181   int width_32, height_32;
1182   int new_width, new_height;
1183
1184   /* calculate new image dimensions for normal sized image */
1185   width_1  = old_bitmap->width  * zoom_factor;
1186   height_1 = old_bitmap->height * zoom_factor;
1187
1188   /* get image with normal size (this might require scaling up) */
1189   if (zoom_factor != 1)
1190     tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1191   else
1192     tmp_bitmap_1 = old_bitmap;
1193
1194   /* this is only needed to make compilers happy */
1195   tmp_bitmap_2 = NULL;
1196   tmp_bitmap_4 = NULL;
1197   tmp_bitmap_8 = NULL;
1198   tmp_bitmap_16 = NULL;
1199   tmp_bitmap_32 = NULL;
1200
1201   if (create_small_bitmaps)
1202   {
1203     /* calculate new image dimensions for small images */
1204     width_2  = width_1  / 2;
1205     height_2 = height_1 / 2;
1206     width_4  = width_1  / 4;
1207     height_4 = height_1 / 4;
1208     width_8  = width_1  / 8;
1209     height_8 = height_1 / 8;
1210     width_16  = width_1  / 16;
1211     height_16 = height_1 / 16;
1212     width_32  = width_1  / 32;
1213     height_32 = height_1 / 32;
1214
1215     UPDATE_BUSY_STATE();
1216
1217     /* get image with 1/2 of normal size (for use in the level editor) */
1218     if (zoom_factor != 2)
1219       tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2);
1220     else
1221       tmp_bitmap_2 = old_bitmap;
1222
1223     UPDATE_BUSY_STATE();
1224
1225     /* get image with 1/4 of normal size (for use in the level editor) */
1226     if (zoom_factor != 4)
1227       tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_2 / 2, height_2 / 2);
1228     else
1229       tmp_bitmap_4 = old_bitmap;
1230
1231     UPDATE_BUSY_STATE();
1232
1233     /* get image with 1/8 of normal size (for use on the preview screen) */
1234     if (zoom_factor != 8)
1235       tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_4 / 2, height_4 / 2);
1236     else
1237       tmp_bitmap_8 = old_bitmap;
1238
1239     UPDATE_BUSY_STATE();
1240
1241     /* get image with 1/16 of normal size (for use on the preview screen) */
1242     if (zoom_factor != 16)
1243       tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_8 / 2, height_8 / 2);
1244     else
1245       tmp_bitmap_16 = old_bitmap;
1246
1247     UPDATE_BUSY_STATE();
1248
1249     /* get image with 1/32 of normal size (for use on the preview screen) */
1250     if (zoom_factor != 32)
1251       tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_16 / 2, height_16 / 2);
1252     else
1253       tmp_bitmap_32 = old_bitmap;
1254
1255     UPDATE_BUSY_STATE();
1256   }
1257
1258 #if 0
1259   /* if image was scaled up, create new clipmask for normal size image */
1260   if (zoom_factor != 1)
1261   {
1262 #if defined(TARGET_X11)
1263     if (old_bitmap->clip_mask)
1264       XFreePixmap(display, old_bitmap->clip_mask);
1265
1266     old_bitmap->clip_mask =
1267       Pixmap_to_Mask(tmp_bitmap_1->drawable, width_1, height_1);
1268
1269     XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1270 #else
1271     SDL_Surface *tmp_surface_1 = tmp_bitmap_1->surface;
1272
1273     if (old_bitmap->surface_masked)
1274       SDL_FreeSurface(old_bitmap->surface_masked);
1275
1276     SDL_SetColorKey(tmp_surface_1, SDL_SRCCOLORKEY,
1277                     SDL_MapRGB(tmp_surface_1->format, 0x00, 0x00, 0x00));
1278     if ((old_bitmap->surface_masked = SDL_DisplayFormat(tmp_surface_1)) ==NULL)
1279       Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1280     SDL_SetColorKey(tmp_surface_1, 0, 0);       /* reset transparent pixel */
1281 #endif
1282   }
1283 #endif
1284
1285   if (create_small_bitmaps)
1286   {
1287     new_width  = width_1;
1288     new_height = height_1 + (height_1 + 1) / 2;     /* prevent odd height */
1289
1290     new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH);
1291
1292     BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0);
1293     BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2,
1294                0, height_1);
1295     BlitBitmap(tmp_bitmap_4, new_bitmap, 0, 0, width_1 / 4, height_1 / 4,
1296                width_1 / 2, height_1);
1297     BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8,
1298                3 * width_1 / 4, height_1);
1299     BlitBitmap(tmp_bitmap_16, new_bitmap, 0, 0, width_1 / 16, height_1 / 16,
1300                7 * width_1 / 8, height_1);
1301     BlitBitmap(tmp_bitmap_32, new_bitmap, 0, 0, width_1 / 32, height_1 / 32,
1302                15 * width_1 / 16, height_1);
1303
1304     UPDATE_BUSY_STATE();
1305   }
1306   else
1307   {
1308     new_width  = width_1;
1309     new_height = height_1;
1310
1311     new_bitmap = tmp_bitmap_1;  /* directly use tmp_bitmap_1 as new bitmap */
1312   }
1313
1314   if (create_small_bitmaps)
1315   {
1316     /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */
1317     if (zoom_factor != 1)
1318       FreeBitmap(tmp_bitmap_1);
1319
1320     if (zoom_factor != 2)
1321       FreeBitmap(tmp_bitmap_2);
1322
1323     if (zoom_factor != 4)
1324       FreeBitmap(tmp_bitmap_4);
1325
1326     if (zoom_factor != 8)
1327       FreeBitmap(tmp_bitmap_8);
1328
1329     if (zoom_factor != 16)
1330       FreeBitmap(tmp_bitmap_16);
1331
1332     if (zoom_factor != 32)
1333       FreeBitmap(tmp_bitmap_32);
1334   }
1335
1336   /* replace image with extended image (containing 1/1, 1/2, 1/4, 1/8 size) */
1337 #if defined(TARGET_SDL)
1338   swap_bitmap.surface = old_bitmap->surface;
1339   old_bitmap->surface = new_bitmap->surface;
1340   new_bitmap->surface = swap_bitmap.surface;
1341 #else
1342   swap_bitmap.drawable = old_bitmap->drawable;
1343   old_bitmap->drawable = new_bitmap->drawable;
1344   new_bitmap->drawable = swap_bitmap.drawable;
1345 #endif
1346
1347   old_bitmap->width  = new_bitmap->width;
1348   old_bitmap->height = new_bitmap->height;
1349
1350 #if 1
1351   /* this replaces all blit masks created when loading -- maybe optimize this */
1352   {
1353 #if defined(TARGET_X11)
1354     if (old_bitmap->clip_mask)
1355       XFreePixmap(display, old_bitmap->clip_mask);
1356
1357     old_bitmap->clip_mask =
1358       Pixmap_to_Mask(old_bitmap->drawable, new_width, new_height);
1359
1360     XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1361 #else
1362     SDL_Surface *old_surface = old_bitmap->surface;
1363
1364     if (old_bitmap->surface_masked)
1365       SDL_FreeSurface(old_bitmap->surface_masked);
1366
1367     SDL_SetColorKey(old_surface, SDL_SRCCOLORKEY,
1368                     SDL_MapRGB(old_surface->format, 0x00, 0x00, 0x00));
1369     if ((old_bitmap->surface_masked = SDL_DisplayFormat(old_surface)) ==NULL)
1370       Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1371     SDL_SetColorKey(old_surface, 0, 0);         /* reset transparent pixel */
1372 #endif
1373   }
1374 #endif
1375
1376   UPDATE_BUSY_STATE();
1377
1378   FreeBitmap(new_bitmap);       /* this actually frees the _old_ bitmap now */
1379 }
1380
1381 void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
1382 {
1383   CreateScaledBitmaps(old_bitmap, zoom_factor, TRUE);
1384 }
1385
1386 void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor)
1387 {
1388   CreateScaledBitmaps(old_bitmap, zoom_factor, FALSE);
1389 }
1390
1391
1392 /* ------------------------------------------------------------------------- */
1393 /* mouse pointer functions                                                   */
1394 /* ------------------------------------------------------------------------- */
1395
1396 #if !defined(PLATFORM_MSDOS)
1397 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER            0
1398 /* XPM image definitions */
1399 static const char *cursor_image_none[] =
1400 {
1401   /* width height num_colors chars_per_pixel */
1402   "    16    16        3            1",
1403
1404   /* colors */
1405   "X c #000000",
1406   ". c #ffffff",
1407   "  c None",
1408
1409   /* pixels */
1410   "                ",
1411   "                ",
1412   "                ",
1413   "                ",
1414   "                ",
1415   "                ",
1416   "                ",
1417   "                ",
1418   "                ",
1419   "                ",
1420   "                ",
1421   "                ",
1422   "                ",
1423   "                ",
1424   "                ",
1425   "                ",
1426
1427   /* hot spot */
1428   "0,0"
1429 };
1430 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1431 static const char *cursor_image_dot[] =
1432 {
1433   /* width height num_colors chars_per_pixel */
1434   "    16    16        3            1",
1435
1436   /* colors */
1437   "X c #000000",
1438   ". c #ffffff",
1439   "  c None",
1440
1441   /* pixels */
1442   " X              ",
1443   "X.X             ",
1444   " X              ",
1445   "                ",
1446   "                ",
1447   "                ",
1448   "                ",
1449   "                ",
1450   "                ",
1451   "                ",
1452   "                ",
1453   "                ",
1454   "                ",
1455   "                ",
1456   "                ",
1457   "                ",
1458
1459   /* hot spot */
1460   "1,1"
1461 };
1462 static const char **cursor_image_playfield = cursor_image_dot;
1463 #else
1464 /* some people complained about a "white dot" on the screen and thought it
1465    was a graphical error... OK, let's just remove the whole pointer :-) */
1466 static const char **cursor_image_playfield = cursor_image_none;
1467 #endif
1468
1469 #if defined(TARGET_SDL)
1470 static const int cursor_bit_order = BIT_ORDER_MSB;
1471 #elif defined(TARGET_X11_NATIVE)
1472 static const int cursor_bit_order = BIT_ORDER_LSB;
1473 #endif
1474
1475 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1476 {
1477   struct MouseCursorInfo *cursor;
1478   boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1479   int header_lines = 4;
1480   int x, y, i;
1481
1482   cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1483
1484   sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1485
1486   i = -1;
1487   for (y = 0; y < cursor->width; y++)
1488   {
1489     for (x = 0; x < cursor->height; x++)
1490     {
1491       int bit_nr = x % 8;
1492       int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1493
1494       if (bit_nr == 0)
1495       {
1496         i++;
1497         cursor->data[i] = cursor->mask[i] = 0;
1498       }
1499
1500       switch (image[header_lines + y][x])
1501       {
1502         case 'X':
1503           cursor->data[i] |= bit_mask;
1504           cursor->mask[i] |= bit_mask;
1505           break;
1506
1507         case '.':
1508           cursor->mask[i] |= bit_mask;
1509           break;
1510
1511         case ' ':
1512           break;
1513       }
1514     }
1515   }
1516
1517   sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1518
1519   return cursor;
1520 }
1521 #endif  /* !PLATFORM_MSDOS */
1522
1523 void SetMouseCursor(int mode)
1524 {
1525 #if !defined(PLATFORM_MSDOS)
1526   static struct MouseCursorInfo *cursor_none = NULL;
1527   static struct MouseCursorInfo *cursor_playfield = NULL;
1528   struct MouseCursorInfo *cursor_new;
1529
1530   if (cursor_none == NULL)
1531     cursor_none = get_cursor_from_image(cursor_image_none);
1532
1533   if (cursor_playfield == NULL)
1534     cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1535
1536   cursor_new = (mode == CURSOR_DEFAULT   ? NULL :
1537                 mode == CURSOR_NONE      ? cursor_none :
1538                 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1539
1540 #if defined(TARGET_SDL)
1541   SDLSetMouseCursor(cursor_new);
1542 #elif defined(TARGET_X11_NATIVE)
1543   X11SetMouseCursor(cursor_new);
1544 #endif
1545 #endif
1546 }
1547
1548
1549 /* ========================================================================= */
1550 /* audio functions                                                           */
1551 /* ========================================================================= */
1552
1553 void OpenAudio(void)
1554 {
1555   /* always start with reliable default values */
1556   audio.sound_available = FALSE;
1557   audio.music_available = FALSE;
1558   audio.loops_available = FALSE;
1559
1560   audio.sound_enabled = FALSE;
1561   audio.sound_deactivated = FALSE;
1562
1563   audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1564   audio.mixer_pid = 0;
1565   audio.device_name = NULL;
1566   audio.device_fd = -1;
1567
1568   audio.num_channels = 0;
1569   audio.music_channel = 0;
1570   audio.first_sound_channel = 0;
1571
1572 #if defined(TARGET_SDL)
1573   SDLOpenAudio();
1574 #elif defined(PLATFORM_UNIX)
1575   UnixOpenAudio();
1576 #elif defined(PLATFORM_MSDOS)
1577   MSDOSOpenAudio();
1578 #endif
1579 }
1580
1581 void CloseAudio(void)
1582 {
1583 #if defined(TARGET_SDL)
1584   SDLCloseAudio();
1585 #elif defined(PLATFORM_UNIX)
1586   UnixCloseAudio();
1587 #elif defined(PLATFORM_MSDOS)
1588   MSDOSCloseAudio();
1589 #endif
1590
1591   audio.sound_enabled = FALSE;
1592 }
1593
1594 void SetAudioMode(boolean enabled)
1595 {
1596   if (!audio.sound_available)
1597     return;
1598
1599   audio.sound_enabled = enabled;
1600 }
1601
1602
1603 /* ========================================================================= */
1604 /* event functions                                                           */
1605 /* ========================================================================= */
1606
1607 void InitEventFilter(EventFilter filter_function)
1608 {
1609 #if defined(TARGET_SDL)
1610   /* set event filter to filter out certain events */
1611   SDL_SetEventFilter(filter_function);
1612 #endif
1613 }
1614
1615 boolean PendingEvent(void)
1616 {
1617 #if defined(TARGET_SDL)
1618   return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1619 #else
1620   return (XPending(display) ? TRUE : FALSE);
1621 #endif
1622 }
1623
1624 void NextEvent(Event *event)
1625 {
1626 #if defined(TARGET_SDL)
1627   SDLNextEvent(event);
1628 #else
1629   XNextEvent(display, event);
1630 #endif
1631 }
1632
1633 void PeekEvent(Event *event)
1634 {
1635 #if defined(TARGET_SDL)
1636   SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1637 #else
1638   XPeekEvent(display, event);
1639 #endif
1640 }
1641
1642 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1643 {
1644 #if defined(TARGET_SDL)
1645
1646 #if 0
1647   printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1648          (int)event->keysym.unicode,
1649          (int)event->keysym.sym,
1650          (int)SDL_GetModState());
1651 #endif
1652
1653   if (with_modifiers &&
1654       event->keysym.unicode > 0x0000 &&
1655       event->keysym.unicode < 0x2000)
1656     return event->keysym.unicode;
1657   else
1658     return event->keysym.sym;
1659
1660 #else
1661
1662 #if 0
1663   printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
1664          (int)XLookupKeysym(event, event->state),
1665          (int)XLookupKeysym(event, 0));
1666 #endif
1667
1668   if (with_modifiers)
1669     return XLookupKeysym(event, event->state);
1670   else
1671     return XLookupKeysym(event, 0);
1672 #endif
1673 }
1674
1675 KeyMod HandleKeyModState(Key key, int key_status)
1676 {
1677   static KeyMod current_modifiers = KMOD_None;
1678
1679   if (key != KSYM_UNDEFINED)    /* new key => check for modifier key change */
1680   {
1681     KeyMod new_modifier = KMOD_None;
1682
1683     switch(key)
1684     {
1685       case KSYM_Shift_L:
1686         new_modifier = KMOD_Shift_L;
1687         break;
1688       case KSYM_Shift_R:
1689         new_modifier = KMOD_Shift_R;
1690         break;
1691       case KSYM_Control_L:
1692         new_modifier = KMOD_Control_L;
1693         break;
1694       case KSYM_Control_R:
1695         new_modifier = KMOD_Control_R;
1696         break;
1697       case KSYM_Meta_L:
1698         new_modifier = KMOD_Meta_L;
1699         break;
1700       case KSYM_Meta_R:
1701         new_modifier = KMOD_Meta_R;
1702         break;
1703       case KSYM_Alt_L:
1704         new_modifier = KMOD_Alt_L;
1705         break;
1706       case KSYM_Alt_R:
1707         new_modifier = KMOD_Alt_R;
1708         break;
1709       default:
1710         break;
1711     }
1712
1713     if (key_status == KEY_PRESSED)
1714       current_modifiers |= new_modifier;
1715     else
1716       current_modifiers &= ~new_modifier;
1717   }
1718
1719   return current_modifiers;
1720 }
1721
1722 KeyMod GetKeyModState()
1723 {
1724 #if defined(TARGET_SDL)
1725   return (KeyMod)SDL_GetModState();
1726 #else
1727   return HandleKeyModState(KSYM_UNDEFINED, 0);
1728 #endif
1729 }
1730
1731 KeyMod GetKeyModStateFromEvents()
1732 {
1733   /* always use key modifier state as tracked from key events (this is needed
1734      if the modifier key event was injected into the event queue, but the key
1735      was not really pressed on keyboard -- SDL_GetModState() seems to directly
1736      query the keys as held pressed on the keyboard) -- this case is currently
1737      only used to filter out clipboard insert events from "True X-Mouse" tool */
1738
1739   return HandleKeyModState(KSYM_UNDEFINED, 0);
1740 }
1741
1742 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1743 {
1744   if (event->type != EVENT_CLIENTMESSAGE)
1745     return FALSE;
1746
1747 #if defined(TARGET_SDL)
1748   return TRUE;          /* the only possible message here is SDL_QUIT */
1749 #elif defined(PLATFORM_UNIX)
1750   if ((event->window == window->drawable) &&
1751       (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
1752     return TRUE;
1753 #endif
1754
1755   return FALSE;
1756 }
1757
1758
1759 /* ========================================================================= */
1760 /* joystick functions                                                        */
1761 /* ========================================================================= */
1762
1763 void InitJoysticks()
1764 {
1765   int i;
1766
1767 #if defined(NO_JOYSTICK)
1768   return;       /* joysticks generally deactivated by compile-time directive */
1769 #endif
1770
1771   /* always start with reliable default values */
1772   joystick.status = JOYSTICK_NOT_AVAILABLE;
1773   for (i = 0; i < MAX_PLAYERS; i++)
1774     joystick.fd[i] = -1;                /* joystick device closed */
1775
1776 #if defined(TARGET_SDL)
1777   SDLInitJoysticks();
1778 #elif defined(PLATFORM_UNIX)
1779   UnixInitJoysticks();
1780 #elif defined(PLATFORM_MSDOS)
1781   MSDOSInitJoysticks();
1782 #endif
1783
1784 #if 0
1785   for (i = 0; i < MAX_PLAYERS; i++)
1786     printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]);
1787 #endif
1788 }
1789
1790 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1791 {
1792 #if defined(TARGET_SDL)
1793   return SDLReadJoystick(nr, x, y, b1, b2);
1794 #elif defined(PLATFORM_UNIX)
1795   return UnixReadJoystick(nr, x, y, b1, b2);
1796 #elif defined(PLATFORM_MSDOS)
1797   return MSDOSReadJoystick(nr, x, y, b1, b2);
1798 #endif
1799 }