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