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