rnd-20030403-2-src
[rocksndiamonds.git] / src / libgame / system.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2002 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 "sound.h"
25 #include "setup.h"
26 #include "joystick.h"
27 #include "misc.h"
28
29
30 /* ========================================================================= */
31 /* exported variables                                                        */
32 /* ========================================================================= */
33
34 struct ProgramInfo      program;
35 struct OptionInfo       options;
36 struct VideoSystemInfo  video;
37 struct AudioSystemInfo  audio;
38 struct GfxInfo          gfx;
39 struct ArtworkInfo      artwork;
40 struct JoystickInfo     joystick;
41 struct SetupInfo        setup;
42
43 LevelDirTree           *leveldir_first = NULL;
44 LevelDirTree           *leveldir_current = NULL;
45 int                     level_nr;
46
47 Display                *display = NULL;
48 Visual                 *visual = NULL;
49 int                     screen = 0;
50 Colormap                cmap = None;
51
52 DrawWindow             *window = NULL;
53 DrawBuffer             *backbuffer = NULL;
54 DrawBuffer             *drawto = NULL;
55
56 int                     button_status = MB_NOT_PRESSED;
57 boolean                 motion_status = FALSE;
58
59 int                     redraw_mask = REDRAW_NONE;
60 int                     redraw_tiles = 0;
61
62 int                     FrameCounter = 0;
63
64
65 /* ========================================================================= */
66 /* init/close functions                                                      */
67 /* ========================================================================= */
68
69 void InitProgramInfo(char *argv0,
70                      char *userdata_directory, char *program_title,
71                      char *window_title, char *icon_title,
72                      char *x11_icon_filename, char *x11_iconmask_filename,
73                      char *msdos_pointer_filename,
74                      char *cookie_prefix, char *filename_prefix,
75                      int program_version)
76 {
77   program.command_basename =
78     (strrchr(argv0, '/') ? strrchr(argv0, '/') + 1 : argv0);
79
80   program.userdata_directory = userdata_directory;
81   program.program_title = program_title;
82   program.window_title = window_title;
83   program.icon_title = icon_title;
84   program.x11_icon_filename = x11_icon_filename;
85   program.x11_iconmask_filename = x11_iconmask_filename;
86   program.msdos_pointer_filename = msdos_pointer_filename;
87
88   program.cookie_prefix = cookie_prefix;
89   program.filename_prefix = filename_prefix;
90
91   program.version_major = VERSION_MAJOR(program_version);
92   program.version_minor = VERSION_MINOR(program_version);
93   program.version_patch = VERSION_PATCH(program_version);
94 }
95
96 void InitExitFunction(void (*exit_function)(int))
97 {
98   program.exit_function = exit_function;
99
100   /* set signal handlers to custom exit function */
101   signal(SIGINT, exit_function);
102   signal(SIGTERM, exit_function);
103
104 #if defined(TARGET_SDL)
105   /* set exit function to automatically cleanup SDL stuff after exit() */
106   atexit(SDL_Quit);
107 #endif
108 }
109
110 void InitPlatformDependantStuff(void)
111 {
112 #if defined(PLATFORM_MSDOS)
113   _fmode = O_BINARY;
114   initErrorFile();
115 #endif
116
117 #if defined(TARGET_SDL)
118   if (SDL_Init(SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE) < 0)
119     Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
120 #endif
121 }
122
123 void ClosePlatformDependantStuff(void)
124 {
125 #if defined(PLATFORM_MSDOS)
126   dumpErrorFile();
127 #endif
128 }
129
130 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
131                       int real_sx, int real_sy,
132                       int full_sxsize, int full_sysize,
133                       Bitmap *field_save_buffer)
134 {
135   gfx.sx = sx;
136   gfx.sy = sy;
137   gfx.sxsize = sxsize;
138   gfx.sysize = sysize;
139   gfx.real_sx = real_sx;
140   gfx.real_sy = real_sy;
141   gfx.full_sxsize = full_sxsize;
142   gfx.full_sysize = full_sysize;
143
144   gfx.field_save_buffer = field_save_buffer;
145
146   gfx.background_bitmap = NULL;
147   gfx.background_bitmap_mask = REDRAW_NONE;
148
149   SetDrawDeactivationMask(REDRAW_NONE);         /* do not deactivate drawing */
150   SetDrawBackgroundMask(REDRAW_NONE);           /* deactivate masked drawing */
151 }
152
153 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
154 {
155   gfx.dx = dx;
156   gfx.dy = dy;
157   gfx.dxsize = dxsize;
158   gfx.dysize = dysize;
159 }
160
161 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
162 {
163   gfx.vx = vx;
164   gfx.vy = vy;
165   gfx.vxsize = vxsize;
166   gfx.vysize = vysize;
167 }
168
169 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
170 {
171   /* currently only used by MSDOS code to alloc VRAM buffer, if available */
172   gfx.scrollbuffer_width = scrollbuffer_width;
173   gfx.scrollbuffer_height = scrollbuffer_height;
174 }
175
176 void SetDrawDeactivationMask(int draw_deactivation_mask)
177 {
178   gfx.draw_deactivation_mask = draw_deactivation_mask;
179 }
180
181 void SetDrawBackgroundMask(int draw_background_mask)
182 {
183   gfx.draw_background_mask = draw_background_mask;
184 }
185
186 static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile,
187                                int dest_x, int dest_y, int width, int height)
188 {
189   int bitmap_xsize = width;
190   int bitmap_ysize = height;
191   int tile_xsize = tile->width;
192   int tile_ysize = tile->height;
193   int tile_xsteps = (bitmap_xsize + tile_xsize - 1) / tile_xsize;
194   int tile_ysteps = (bitmap_ysize + tile_ysize - 1) / tile_ysize;
195   int x, y;
196
197   for (y=0; y < tile_ysteps; y++)
198   {
199     for (x=0; x < tile_xsteps; x++)
200     {
201       int draw_x = dest_x + x * tile_xsize;
202       int draw_y = dest_y + y * tile_ysize;
203       int draw_xsize = MIN(tile_xsize, bitmap_xsize - x * tile_xsize);
204       int draw_ysize = MIN(tile_ysize, bitmap_ysize - y * tile_ysize);
205
206       BlitBitmap(tile, bitmap, 0, 0, draw_xsize, draw_ysize, draw_x, draw_y);
207     }
208   }
209 }
210
211 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
212 {
213   static Bitmap *main_bitmap_tile = NULL;
214   static Bitmap *door_bitmap_tile = NULL;
215
216   if (mask == REDRAW_FIELD)
217   {
218     if (background_bitmap_tile == main_bitmap_tile)
219       return;           /* main background tile has not changed */
220
221     main_bitmap_tile = background_bitmap_tile;
222   }
223   else if (mask == REDRAW_DOOR_1)
224   {
225     if (background_bitmap_tile == door_bitmap_tile)
226       return;   /* main background tile has not changed */
227
228     door_bitmap_tile = background_bitmap_tile;
229   }
230   else          /* should not happen */
231     return;
232
233   if (background_bitmap_tile)
234     gfx.background_bitmap_mask |= mask;
235   else
236     gfx.background_bitmap_mask &= ~mask;
237
238   if (gfx.background_bitmap == NULL)
239     gfx.background_bitmap = CreateBitmap(video.width, video.height,
240                                          DEFAULT_DEPTH);
241
242   if (background_bitmap_tile == NULL)   /* empty background requested */
243     return;
244
245   if (mask == REDRAW_FIELD)
246     DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
247                        gfx.real_sx, gfx.real_sy,
248                        gfx.full_sxsize, gfx.full_sysize);
249   else
250     DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
251                        gfx.dx, gfx.dy,
252                        gfx.dxsize, gfx.dysize);
253 }
254
255 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
256 {
257   SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
258 }
259
260 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
261 {
262   SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
263 }
264
265
266 /* ========================================================================= */
267 /* video functions                                                           */
268 /* ========================================================================= */
269
270 inline static int GetRealDepth(int depth)
271 {
272   return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
273 }
274
275 inline void InitVideoDisplay(void)
276 {
277 #if defined(TARGET_SDL)
278   SDLInitVideoDisplay();
279 #else
280   X11InitVideoDisplay();
281 #endif
282 }
283
284 inline void CloseVideoDisplay(void)
285 {
286   KeyboardAutoRepeatOn();
287
288 #if defined(TARGET_SDL)
289   SDL_QuitSubSystem(SDL_INIT_VIDEO);
290 #else
291
292   if (display)
293     XCloseDisplay(display);
294 #endif
295 }
296
297 inline void InitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
298                             int width, int height, int depth,
299                             boolean fullscreen)
300 {
301   video.width = width;
302   video.height = height;
303   video.depth = GetRealDepth(depth);
304   video.fullscreen_available = FULLSCREEN_STATUS;
305   video.fullscreen_enabled = FALSE;
306
307 #ifdef TARGET_SDL
308   SDLInitVideoBuffer(backbuffer, window, fullscreen);
309 #else
310   X11InitVideoBuffer(backbuffer, window);
311 #endif
312 }
313
314 inline Bitmap *CreateBitmapStruct(void)
315 {
316 #ifdef TARGET_SDL
317   return checked_calloc(sizeof(struct SDLSurfaceInfo));
318 #else
319   return checked_calloc(sizeof(struct X11DrawableInfo));
320 #endif
321 }
322
323 inline Bitmap *CreateBitmap(int width, int height, int depth)
324 {
325   Bitmap *new_bitmap = CreateBitmapStruct();
326   int real_depth = GetRealDepth(depth);
327
328 #ifdef TARGET_SDL
329   SDL_Surface *surface_tmp, *surface_native;
330
331   if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height,
332                                           real_depth, 0, 0, 0, 0))
333       == NULL)
334     Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
335
336   if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
337     Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
338
339   SDL_FreeSurface(surface_tmp);
340
341   new_bitmap->surface = surface_native;
342 #else
343   Pixmap pixmap;
344
345   if ((pixmap = XCreatePixmap(display, window->drawable,
346                               width, height, real_depth))
347       == None)
348     Error(ERR_EXIT, "cannot create pixmap");
349
350   new_bitmap->drawable = pixmap;
351
352   if (window == NULL)
353     Error(ERR_EXIT, "Window GC needed for Bitmap -- create Window first");
354
355   new_bitmap->gc = window->gc;
356
357   new_bitmap->line_gc[0] = window->line_gc[0];
358   new_bitmap->line_gc[1] = window->line_gc[1];
359 #endif
360
361   new_bitmap->width = width;
362   new_bitmap->height = height;
363
364   return new_bitmap;
365 }
366
367 inline static void FreeBitmapPointers(Bitmap *bitmap)
368 {
369   if (bitmap == NULL)
370     return;
371
372 #ifdef TARGET_SDL
373   if (bitmap->surface)
374     SDL_FreeSurface(bitmap->surface);
375   if (bitmap->surface_masked)
376     SDL_FreeSurface(bitmap->surface_masked);
377   bitmap->surface = NULL;
378   bitmap->surface_masked = NULL;
379 #else
380   /* The X11 version seems to have a memory leak here -- although
381      "XFreePixmap()" is called, the corresponding memory seems not
382      to be freed (according to "ps"). The SDL version apparently
383      does not have this problem. */
384
385   if (bitmap->drawable)
386     XFreePixmap(display, bitmap->drawable);
387   if (bitmap->clip_mask)
388     XFreePixmap(display, bitmap->clip_mask);
389   if (bitmap->stored_clip_gc)
390     XFreeGC(display, bitmap->stored_clip_gc);
391   /* the other GCs are only pointers to GCs used elsewhere */
392   bitmap->drawable = None;
393   bitmap->clip_mask = None;
394   bitmap->stored_clip_gc = None;
395 #endif
396
397   if (bitmap->source_filename)
398     free(bitmap->source_filename);
399   bitmap->source_filename = NULL;
400 }
401
402 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
403                                           Bitmap *dst_bitmap)
404 {
405   if (src_bitmap == NULL || dst_bitmap == NULL)
406     return;
407
408   FreeBitmapPointers(dst_bitmap);
409
410   *dst_bitmap = *src_bitmap;
411 }
412
413 inline void FreeBitmap(Bitmap *bitmap)
414 {
415   if (bitmap == NULL)
416     return;
417
418   FreeBitmapPointers(bitmap);
419
420   free(bitmap);
421 }
422
423 inline void CloseWindow(DrawWindow *window)
424 {
425 #ifdef TARGET_X11
426   if (window->drawable)
427   {
428     XUnmapWindow(display, window->drawable);
429     XDestroyWindow(display, window->drawable);
430   }
431   if (window->gc)
432     XFreeGC(display, window->gc);
433 #endif
434 }
435
436 static inline boolean CheckDrawingArea(int x, int y, int width, int height,
437                                        int draw_mask)
438 {
439   if (draw_mask == REDRAW_NONE)
440     return FALSE;
441
442   if (draw_mask & REDRAW_ALL)
443     return TRUE;
444
445   if ((draw_mask & REDRAW_FIELD) && x < gfx.real_sx + gfx.full_sxsize)
446     return TRUE;
447
448   if ((draw_mask & REDRAW_DOOR_1) && x >= gfx.dx && y < gfx.dy + gfx.dysize)
449     return TRUE;
450
451   if ((draw_mask & REDRAW_DOOR_2) && x >= gfx.dx && y >= gfx.vy)
452     return TRUE;
453
454   return FALSE;
455 }
456
457 inline boolean DrawingDeactivated(int x, int y, int width, int height)
458 {
459   return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
460 }
461
462 inline boolean DrawingOnBackground(int x, int y)
463 {
464   return ((gfx.draw_background_mask & gfx.background_bitmap_mask) &&
465           CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
466 }
467
468 inline void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
469                        int src_x, int src_y,
470                        int width, int height,
471                        int dst_x, int dst_y)
472 {
473   if (DrawingDeactivated(dst_x, dst_y, width, height))
474     return;
475
476 #ifdef TARGET_SDL
477   SDLCopyArea(src_bitmap, dst_bitmap,
478               src_x, src_y, width, height, dst_x, dst_y, SDLCOPYAREA_OPAQUE);
479 #else
480   XCopyArea(display, src_bitmap->drawable, dst_bitmap->drawable,
481             dst_bitmap->gc, src_x, src_y, width, height, dst_x, dst_y);
482 #endif
483 }
484
485 inline void DrawRectangle(Bitmap *bitmap, int x, int y, int width, int height,
486                           Pixel color)
487 {
488   if (DrawingDeactivated(x, y, width, height))
489     return;
490
491 #ifdef TARGET_SDL
492   SDLFillRectangle(bitmap, x, y, width, height, color);
493 #else
494   XSetForeground(display, bitmap->gc, color);
495   XFillRectangle(display, bitmap->drawable, bitmap->gc, x, y, width, height);
496   XSetForeground(display, bitmap->gc, BlackPixel(display, screen));
497 #endif
498 }
499
500 #if 1
501 inline void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
502 {
503 #ifdef TARGET_SDL
504   DrawRectangle(bitmap, x, y, width, height, 0x000000);
505 #else
506   DrawRectangle(bitmap, x, y, width, height, 0x000000);
507 #endif
508 }
509 #else
510 inline void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
511 {
512   if (DrawingDeactivated(x, y, width, height))
513     return;
514
515 #ifdef TARGET_SDL
516   SDLFillRectangle(bitmap, x, y, width, height, 0x000000);
517 #else
518   XFillRectangle(display, bitmap->drawable, bitmap->gc, x, y, width, height);
519 #endif
520 }
521 #endif
522
523 inline void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
524                                        int width, int height)
525 {
526   if (DrawingOnBackground(x, y))
527     BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
528   else
529     ClearRectangle(bitmap, x, y, width, height);
530 }
531
532 #if 0
533 #ifndef TARGET_SDL
534 static GC last_clip_gc = 0;     /* needed for XCopyArea() through clip mask */
535 #endif
536 #endif
537
538 inline void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
539 {
540 #ifdef TARGET_X11
541   if (clip_gc)
542   {
543     bitmap->clip_gc = clip_gc;
544     XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
545   }
546 #if 0
547   last_clip_gc = clip_gc;
548 #endif
549 #endif
550 }
551
552 inline void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
553 {
554 #ifdef TARGET_X11
555   if (clip_gc)
556   {
557     bitmap->clip_gc = clip_gc;
558     XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
559   }
560 #if 0
561   last_clip_gc = clip_gc;
562 #endif
563 #endif
564 }
565
566 inline void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
567                              int src_x, int src_y,
568                              int width, int height,
569                              int dst_x, int dst_y)
570 {
571   if (DrawingDeactivated(dst_x, dst_y, width, height))
572     return;
573
574 #ifdef TARGET_SDL
575   SDLCopyArea(src_bitmap, dst_bitmap,
576               src_x, src_y, width, height, dst_x, dst_y, SDLCOPYAREA_MASKED);
577 #else
578   XCopyArea(display, src_bitmap->drawable, dst_bitmap->drawable,
579             src_bitmap->clip_gc, src_x, src_y, width, height, dst_x, dst_y);
580 #endif
581 }
582
583 inline void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
584                                    int src_x, int src_y,
585                                    int width, int height,
586                                    int dst_x, int dst_y)
587 {
588   if (DrawingOnBackground(dst_x, dst_y))
589   {
590     /* draw background */
591     BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
592                dst_x, dst_y);
593
594     /* draw foreground */
595     SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
596                   dst_x - src_x, dst_y - src_y);
597     BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
598                      dst_x, dst_y);
599   }
600   else
601     BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
602                dst_x, dst_y);
603 }
604
605 inline void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
606                                 int to_x, int to_y)
607 {
608 #ifdef TARGET_SDL
609   SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, 0xffffff);
610 #else
611   XSetForeground(display, bitmap->gc, WhitePixel(display, screen));
612   XDrawLine(display, bitmap->drawable, bitmap->gc, from_x, from_y, to_x, to_y);
613   XSetForeground(display, bitmap->gc, BlackPixel(display, screen));
614 #endif
615 }
616
617 #if !defined(TARGET_X11_NATIVE)
618 inline void DrawLine(Bitmap *bitmap, int from_x, int from_y,
619                      int to_x, int to_y, Pixel pixel, int line_width)
620 {
621   int x, y;
622
623   for (x=0; x<line_width; x++)
624   {
625     for (y=0; y<line_width; y++)
626     {
627       int dx = x - line_width / 2;
628       int dy = y - line_width / 2;
629
630       if ((x == 0 && y == 0) ||
631           (x == 0 && y == line_width - 1) ||
632           (x == line_width - 1 && y == 0) ||
633           (x == line_width - 1 && y == line_width - 1))
634         continue;
635
636 #if defined(TARGET_SDL)
637       SDLDrawLine(bitmap,
638                   from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
639 #elif defined(TARGET_ALLEGRO)
640       AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy,
641                       to_x + dx, to_y + dy, pixel);
642 #endif
643     }
644   }
645 }
646 #endif
647
648 inline void DrawLines(Bitmap *bitmap, struct XY *points, int num_points,
649                       Pixel pixel)
650 {
651 #if !defined(TARGET_X11_NATIVE)
652   int line_width = 4;
653   int i;
654
655   for (i=0; i<num_points - 1; i++)
656     DrawLine(bitmap, points[i].x, points[i].y,
657              points[i + 1].x, points[i + 1].y, pixel, line_width);
658
659   /*
660   SDLDrawLines(bitmap->surface, points, num_points, pixel);
661   */
662 #else
663   XSetForeground(display, bitmap->line_gc[1], pixel);
664   XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
665              (XPoint *)points, num_points, CoordModeOrigin);
666   /*
667   XSetForeground(display, gc, BlackPixel(display, screen));
668   */
669 #endif
670 }
671
672 inline Pixel GetPixel(Bitmap *bitmap, int x, int y)
673 {
674 #if defined(TARGET_SDL)
675   return SDLGetPixel(bitmap, x, y);
676 #elif defined(TARGET_ALLEGRO)
677   return AllegroGetPixel(bitmap->drawable, x, y);
678 #else
679   unsigned long pixel_value;
680   XImage *pixel_image;
681
682   pixel_image = XGetImage(display, bitmap->drawable, x, y, 1, 1,
683                           AllPlanes, ZPixmap);
684   pixel_value = XGetPixel(pixel_image, 0, 0);
685
686   XDestroyImage(pixel_image);
687
688   return pixel_value;
689 #endif
690 }
691
692 inline Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
693                              unsigned int color_g, unsigned int color_b)
694 {
695   Pixel pixel;
696
697 #if defined(TARGET_SDL)
698   pixel = SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
699 #elif defined(TARGET_ALLEGRO)
700   pixel = AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
701 #elif defined(TARGET_X11_NATIVE)
702   XColor xcolor;
703
704   xcolor.flags = DoRed | DoGreen | DoBlue;
705   xcolor.red = (color_r << 8);
706   xcolor.green = (color_g << 8);
707   xcolor.blue = (color_b << 8);
708   XAllocColor(display, cmap, &xcolor);
709   pixel = xcolor.pixel;
710 #endif
711
712   return pixel;
713 }
714
715 inline Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
716 {
717   unsigned int color_r = (color >> 16) & 0xff;
718   unsigned int color_g = (color >>  8) & 0xff;
719   unsigned int color_b = (color >>  0) & 0xff;
720
721   return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
722 }
723
724 /* execute all pending screen drawing operations */
725 inline void FlushDisplay(void)
726 {
727 #ifndef TARGET_SDL
728   XFlush(display);
729 #endif
730 }
731
732 /* execute and wait for all pending screen drawing operations */
733 inline void SyncDisplay(void)
734 {
735 #ifndef TARGET_SDL
736   XSync(display, FALSE);
737 #endif
738 }
739
740 inline void KeyboardAutoRepeatOn(void)
741 {
742 #ifdef TARGET_SDL
743   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
744                       SDL_DEFAULT_REPEAT_INTERVAL / 2);
745   SDL_EnableUNICODE(1);
746 #else
747   if (display)
748     XAutoRepeatOn(display);
749 #endif
750 }
751
752 inline void KeyboardAutoRepeatOff(void)
753 {
754 #ifdef TARGET_SDL
755   SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
756   SDL_EnableUNICODE(0);
757 #else
758   if (display)
759     XAutoRepeatOff(display);
760 #endif
761 }
762
763 inline boolean PointerInWindow(DrawWindow *window)
764 {
765 #ifdef TARGET_SDL
766   return TRUE;
767 #else
768   Window root, child;
769   int root_x, root_y;
770   unsigned int mask;
771   int win_x, win_y;
772
773   /* if XQueryPointer() returns False, the pointer
774      is not on the same screen as the specified window */
775   return XQueryPointer(display, window->drawable, &root, &child,
776                        &root_x, &root_y, &win_x, &win_y, &mask);
777 #endif
778 }
779
780 inline boolean SetVideoMode(boolean fullscreen)
781 {
782 #ifdef TARGET_SDL
783   return SDLSetVideoMode(&backbuffer, fullscreen);
784 #else
785   boolean success = TRUE;
786
787   if (fullscreen && video.fullscreen_available)
788   {
789     Error(ERR_WARN, "fullscreen not available in X11 version");
790
791     /* display error message only once */
792     video.fullscreen_available = FALSE;
793
794     success = FALSE;
795   }
796
797   return success;
798 #endif
799 }
800
801 inline boolean ChangeVideoModeIfNeeded(boolean fullscreen)
802 {
803 #ifdef TARGET_SDL
804   if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
805       (!fullscreen && video.fullscreen_enabled))
806     fullscreen = SetVideoMode(fullscreen);
807 #endif
808
809   return fullscreen;
810 }
811
812 Bitmap *LoadImage(char *filename)
813 {
814   Bitmap *new_bitmap;
815
816 #if defined(TARGET_SDL)
817   new_bitmap = SDLLoadImage(filename);
818 #else
819   new_bitmap = X11LoadImage(filename);
820 #endif
821
822   if (new_bitmap)
823     new_bitmap->source_filename = getStringCopy(filename);
824
825   return new_bitmap;
826 }
827
828 Bitmap *LoadCustomImage(char *basename)
829 {
830   char *filename = getCustomImageFilename(basename);
831   Bitmap *new_bitmap;
832
833   if (filename == NULL)
834     Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
835
836   if ((new_bitmap = LoadImage(filename)) == NULL)
837     Error(ERR_EXIT, "LoadImage() failed: %s", GetError());
838
839   return new_bitmap;
840 }
841
842 void ReloadCustomImage(Bitmap *bitmap, char *basename)
843 {
844   char *filename = getCustomImageFilename(basename);
845   Bitmap *new_bitmap;
846
847   if (filename == NULL)         /* (should never happen) */
848   {
849     Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
850     return;
851   }
852
853   if (strcmp(filename, bitmap->source_filename) == 0)
854   {
855     /* The old and new image are the same (have the same filename and path).
856        This usually means that this image does not exist in this graphic set
857        and a fallback to the existing image is done. */
858
859     return;
860   }
861
862   if ((new_bitmap = LoadImage(filename)) == NULL)
863   {
864     Error(ERR_WARN, "LoadImage() failed: %s", GetError());
865     return;
866   }
867
868   if (bitmap->width != new_bitmap->width ||
869       bitmap->height != new_bitmap->height)
870   {
871     Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
872           filename);
873     FreeBitmap(new_bitmap);
874     return;
875   }
876
877   TransferBitmapPointers(new_bitmap, bitmap);
878   free(new_bitmap);
879 }
880
881 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
882 {
883   Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
884
885 #if defined(TARGET_SDL)
886   SDLZoomBitmap(src_bitmap, dst_bitmap);
887 #else
888   X11ZoomBitmap(src_bitmap, dst_bitmap);
889 #endif
890
891   return dst_bitmap;
892 }
893
894 void CreateBitmapWithSmallBitmaps(Bitmap *src_bitmap)
895 {
896   Bitmap *tmp_bitmap, *tmp_bitmap_2, *tmp_bitmap_8;
897   int src_width, src_height;
898   int tmp_width, tmp_height;
899
900   src_width  = src_bitmap->width;
901   src_height = src_bitmap->height;
902
903   tmp_width  = src_width;
904   tmp_height = src_height + src_height / 2;
905
906   tmp_bitmap = CreateBitmap(tmp_width, tmp_height, DEFAULT_DEPTH);
907
908   tmp_bitmap_2 = ZoomBitmap(src_bitmap, src_width / 2, src_height / 2);
909   tmp_bitmap_8 = ZoomBitmap(src_bitmap, src_width / 8, src_height / 8);
910
911   BlitBitmap(src_bitmap, tmp_bitmap, 0, 0, src_width, src_height, 0, 0);
912   BlitBitmap(tmp_bitmap_2, tmp_bitmap, 0, 0, src_width / 2, src_height / 2,
913              0, src_height);
914   BlitBitmap(tmp_bitmap_8, tmp_bitmap, 0, 0, src_width / 8, src_height / 8,
915              3 * src_width / 4, src_height);
916
917   FreeBitmap(tmp_bitmap_2);
918   FreeBitmap(tmp_bitmap_8);
919
920 #ifdef TARGET_SDL
921   src_bitmap->surface = tmp_bitmap->surface;
922   tmp_bitmap->surface = NULL;
923 #else
924   src_bitmap->drawable = tmp_bitmap->drawable;
925   tmp_bitmap->drawable = None;
926 #endif
927
928   src_bitmap->height = tmp_bitmap->height;
929
930   FreeBitmap(tmp_bitmap);
931 }
932
933
934 /* ========================================================================= */
935 /* audio functions                                                           */
936 /* ========================================================================= */
937
938 inline void OpenAudio(void)
939 {
940   /* always start with reliable default values */
941   audio.sound_available = FALSE;
942   audio.music_available = FALSE;
943   audio.loops_available = FALSE;
944
945   audio.sound_enabled = FALSE;
946   audio.sound_deactivated = FALSE;
947
948   audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
949   audio.mixer_pid = 0;
950   audio.device_name = NULL;
951   audio.device_fd = -1;
952
953   audio.num_channels = 0;
954   audio.music_channel = 0;
955   audio.first_sound_channel = 0;
956
957 #if defined(TARGET_SDL)
958   SDLOpenAudio();
959 #elif defined(PLATFORM_UNIX)
960   UnixOpenAudio();
961 #elif defined(PLATFORM_MSDOS)
962   MSDOSOpenAudio();
963 #endif
964 }
965
966 inline void CloseAudio(void)
967 {
968 #if defined(TARGET_SDL)
969   SDLCloseAudio();
970 #elif defined(PLATFORM_UNIX)
971   UnixCloseAudio();
972 #elif defined(PLATFORM_MSDOS)
973   MSDOSCloseAudio();
974 #endif
975
976   audio.sound_enabled = FALSE;
977 }
978
979 inline void SetAudioMode(boolean enabled)
980 {
981   if (!audio.sound_available)
982     return;
983
984   audio.sound_enabled = enabled;
985 }
986
987
988 /* ========================================================================= */
989 /* event functions                                                           */
990 /* ========================================================================= */
991
992 inline void InitEventFilter(EventFilter filter_function)
993 {
994 #ifdef TARGET_SDL
995   /* set event filter to filter out certain events */
996   SDL_SetEventFilter(filter_function);
997 #endif
998 }
999
1000 inline boolean PendingEvent(void)
1001 {
1002 #ifdef TARGET_SDL
1003   return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1004 #else
1005   return (XPending(display) ? TRUE : FALSE);
1006 #endif
1007 }
1008
1009 inline void NextEvent(Event *event)
1010 {
1011 #ifdef TARGET_SDL
1012   SDLNextEvent(event);
1013 #else
1014   XNextEvent(display, event);
1015 #endif
1016 }
1017
1018 inline Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1019 {
1020 #ifdef TARGET_SDL
1021 #if 0
1022   printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1023          (int)event->keysym.unicode,
1024          (int)event->keysym.sym,
1025          (int)SDL_GetModState());
1026 #endif
1027
1028   if (with_modifiers &&
1029       event->keysym.unicode > 0x0000 &&
1030       event->keysym.unicode < 0x2000)
1031     return event->keysym.unicode;
1032   else
1033     return event->keysym.sym;
1034 #else
1035 #if 0
1036   printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
1037          (int)XLookupKeysym(event, event->state),
1038          (int)XLookupKeysym(event, 0));
1039 #endif
1040
1041   if (with_modifiers)
1042     return XLookupKeysym(event, event->state);
1043   else
1044     return XLookupKeysym(event, 0);
1045 #endif
1046 }
1047
1048 inline boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1049 {
1050   if (event->type != EVENT_CLIENTMESSAGE)
1051     return FALSE;
1052
1053 #if defined(TARGET_SDL)
1054   return TRUE;          /* the only possible message here is SDL_QUIT */
1055 #elif defined(PLATFORM_UNIX)
1056   if ((event->window == window->drawable) &&
1057       (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
1058     return TRUE;
1059 #endif
1060
1061   return FALSE;
1062 }
1063
1064
1065 /* ========================================================================= */
1066 /* joystick functions                                                        */
1067 /* ========================================================================= */
1068
1069 inline void InitJoysticks()
1070 {
1071   int i;
1072
1073 #ifdef NO_JOYSTICK
1074   return;       /* joysticks generally deactivated by compile-time directive */
1075 #endif
1076
1077   /* always start with reliable default values */
1078   joystick.status = JOYSTICK_NOT_AVAILABLE;
1079   for (i=0; i<MAX_PLAYERS; i++)
1080     joystick.fd[i] = -1;                /* joystick device closed */
1081
1082 #if defined(TARGET_SDL)
1083   SDLInitJoysticks();
1084 #elif defined(PLATFORM_UNIX)
1085   UnixInitJoysticks();
1086 #elif defined(PLATFORM_MSDOS)
1087   MSDOSInitJoysticks();
1088 #endif
1089 }
1090
1091 inline boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1092 {
1093 #if defined(TARGET_SDL)
1094   return SDLReadJoystick(nr, x, y, b1, b2);
1095 #elif defined(PLATFORM_UNIX)
1096   return UnixReadJoystick(nr, x, y, b1, b2);
1097 #elif defined(PLATFORM_MSDOS)
1098   return MSDOSReadJoystick(nr, x, y, b1, b2);
1099 #endif
1100 }