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