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