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