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