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