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