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