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