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