rnd-20001204-3-src
[rocksndiamonds.git] / src / libgame / system.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2000 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
16 #include "platform.h"
17
18 #if defined(PLATFORM_MSDOS)
19 #include <fcntl.h>
20 #endif
21
22 #include "system.h"
23 #include "sound.h"
24 #include "misc.h"
25
26
27 /* ========================================================================= */
28 /* exported variables                                                        */
29 /* ========================================================================= */
30
31 struct ProgramInfo      program;
32 struct OptionInfo       options;
33 struct VideoSystemInfo  video;
34 struct AudioSystemInfo  audio;
35 struct GfxInfo          gfx;
36
37 struct LevelDirInfo    *leveldir_first = NULL;
38 struct LevelDirInfo    *leveldir_current = NULL;
39
40 Display        *display = NULL;
41 Visual         *visual = NULL;
42 int             screen = 0;
43 Colormap        cmap = None;
44
45 DrawWindow      window = NULL;
46 DrawBuffer      backbuffer = NULL;
47 DrawBuffer      drawto = NULL;
48
49 int             button_status = MB_NOT_PRESSED;
50 boolean         motion_status = FALSE;
51
52 int             redraw_mask = REDRAW_NONE;
53 int             redraw_tiles = 0;
54
55 int             FrameCounter = 0;
56
57
58 /* ========================================================================= */
59 /* init functions                                                            */
60 /* ========================================================================= */
61
62 void InitCommandName(char *argv0)
63 {
64   program.command_basename =
65     (strrchr(argv0, '/') ? strrchr(argv0, '/') + 1 : argv0);
66 }
67
68 void InitExitFunction(void (*exit_function)(int))
69 {
70   program.exit_function = exit_function;
71 }
72
73 void InitPlatformDependantStuff(void)
74 {
75 #if defined(PLATFORM_MSDOS)
76   _fmode = O_BINARY;
77 #endif
78 }
79
80 void InitProgramInfo(char *unix_userdata_directory, char *program_title,
81                      char *window_title, char *icon_title,
82                      char *x11_icon_basename, char *x11_iconmask_basename,
83                      char *msdos_pointer_basename)
84 {
85   char *gfx_dir = getPath2(options.ro_base_directory, GRAPHICS_DIRECTORY);
86   char *x11_icon_filename = getPath2(gfx_dir, x11_icon_basename);
87   char *x11_iconmask_filename = getPath2(gfx_dir, x11_iconmask_basename);
88   char *msdos_pointer_filename = getPath2(gfx_dir, msdos_pointer_basename);
89
90   free(gfx_dir);
91
92 #if defined(PLATFORM_UNIX)
93   program.userdata_directory = unix_userdata_directory;
94 #else
95   program.userdata_directory = "userdata";
96 #endif
97
98   program.program_title = program_title;
99   program.window_title = window_title;
100   program.icon_title = icon_title;
101   program.x11_icon_filename = x11_icon_filename;
102   program.x11_iconmask_filename = x11_iconmask_filename;
103   program.msdos_pointer_filename = msdos_pointer_filename;
104 }
105
106 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
107                       int real_sx, int real_sy,
108                       int full_sxsize, int full_sysize)
109 {
110   gfx.sx = sx;
111   gfx.sy = sy;
112   gfx.sxsize = sxsize;
113   gfx.sysize = sysize;
114   gfx.real_sx = real_sx;
115   gfx.real_sy = real_sy;
116   gfx.full_sxsize = full_sxsize;
117   gfx.full_sysize = full_sysize;
118 }
119
120 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
121 {
122   gfx.dx = dx;
123   gfx.dy = dy;
124   gfx.dxsize = dxsize;
125   gfx.dysize = dysize;
126 }
127
128 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
129 {
130   gfx.vx = vx;
131   gfx.vy = vy;
132   gfx.vxsize = vxsize;
133   gfx.vysize = vysize;
134 }
135
136 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
137 {
138   /* currently only used by MSDOS code to alloc VRAM buffer, if available */
139   gfx.scrollbuffer_width = scrollbuffer_width;
140   gfx.scrollbuffer_height = scrollbuffer_height;
141 }
142
143
144 /* ========================================================================= */
145 /* video functions                                                           */
146 /* ========================================================================= */
147
148 inline static int GetRealDepth(int depth)
149 {
150   return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
151 }
152
153 inline void InitVideoDisplay(void)
154 {
155 #ifdef TARGET_SDL
156   SDLInitVideoDisplay();
157 #else
158   X11InitVideoDisplay();
159 #endif
160 }
161
162 inline void InitVideoBuffer(DrawBuffer *backbuffer, DrawWindow *window,
163                             int width, int height, int depth,
164                             boolean fullscreen)
165 {
166   video.width = width;
167   video.height = height;
168   video.depth = GetRealDepth(depth);
169   video.fullscreen_available = FULLSCREEN_STATUS;
170   video.fullscreen_enabled = FALSE;
171
172 #ifdef TARGET_SDL
173   SDLInitVideoBuffer(backbuffer, window, fullscreen);
174 #else
175   X11InitVideoBuffer(backbuffer, window);
176 #endif
177 }
178
179 inline Bitmap CreateBitmapStruct(void)
180 {
181 #ifdef TARGET_SDL
182   return checked_calloc(sizeof(struct SDLSurfaceInfo));
183 #else
184   return checked_calloc(sizeof(struct X11DrawableInfo));
185 #endif
186 }
187
188 inline Bitmap CreateBitmap(int width, int height, int depth)
189 {
190   Bitmap new_bitmap = CreateBitmapStruct();
191   int real_depth = GetRealDepth(depth);
192
193 #ifdef TARGET_SDL
194   SDL_Surface *surface_tmp, *surface_native;
195
196   if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height,
197                                           real_depth, 0, 0, 0, 0))
198       == NULL)
199     Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
200
201   if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
202     Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
203
204   SDL_FreeSurface(surface_tmp);
205
206   new_bitmap->surface = surface_native;
207 #else
208   Pixmap pixmap;
209
210   if ((pixmap = XCreatePixmap(display, window->drawable,
211                               width, height, real_depth))
212       == None)
213     Error(ERR_EXIT, "cannot create pixmap");
214
215   new_bitmap->drawable = pixmap;
216
217   if (window == NULL)
218     Error(ERR_EXIT, "Window GC needed for Bitmap -- create Window first");
219
220   new_bitmap->gc = window->gc;
221
222   new_bitmap->line_gc[0] = window->line_gc[0];
223   new_bitmap->line_gc[1] = window->line_gc[1];
224 #endif
225
226   return new_bitmap;
227 }
228
229 inline void FreeBitmap(Bitmap bitmap)
230 {
231   if (bitmap == NULL)
232     return;
233
234 #ifdef TARGET_SDL
235   if (bitmap->surface)
236     SDL_FreeSurface(bitmap->surface);
237   if (bitmap->surface_masked)
238     SDL_FreeSurface(bitmap->surface_masked);
239 #else
240   if (bitmap->drawable)
241     XFreePixmap(display, bitmap->drawable);
242   if (bitmap->clip_mask)
243     XFreePixmap(display, bitmap->clip_mask);
244   if (bitmap->stored_clip_gc)
245     XFreeGC(display, bitmap->stored_clip_gc);
246 #endif
247
248   free(bitmap);
249 }
250
251 inline void CloseWindow(DrawWindow window)
252 {
253 #ifdef TARGET_X11
254   if (window->drawable)
255   {
256     XUnmapWindow(display, window->drawable);
257     XDestroyWindow(display, window->drawable);
258   }
259   if (window->gc)
260     XFreeGC(display, window->gc);
261 #endif
262 }
263
264 inline void BlitBitmap(Bitmap src_bitmap, Bitmap dst_bitmap,
265                        int src_x, int src_y,
266                        int width, int height,
267                        int dst_x, int dst_y)
268 {
269 #ifdef TARGET_SDL
270   SDLCopyArea(src_bitmap, dst_bitmap,
271               src_x, src_y, width, height, dst_x, dst_y, SDLCOPYAREA_OPAQUE);
272 #else
273   XCopyArea(display, src_bitmap->drawable, dst_bitmap->drawable,
274             dst_bitmap->gc, src_x, src_y, width, height, dst_x, dst_y);
275 #endif
276 }
277
278 inline void ClearRectangle(Bitmap bitmap, int x, int y, int width, int height)
279 {
280 #ifdef TARGET_SDL
281   SDLFillRectangle(bitmap, x, y, width, height, 0x000000);
282 #else
283   XFillRectangle(display, bitmap->drawable, bitmap->gc, x, y, width, height);
284 #endif
285 }
286
287 #if 0
288 #ifndef TARGET_SDL
289 static GC last_clip_gc = 0;     /* needed for XCopyArea() through clip mask */
290 #endif
291 #endif
292
293 inline void SetClipMask(Bitmap bitmap, GC clip_gc, Pixmap clip_pixmap)
294 {
295 #ifdef TARGET_X11
296   if (clip_gc)
297   {
298     bitmap->clip_gc = clip_gc;
299     XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
300   }
301 #if 0
302   last_clip_gc = clip_gc;
303 #endif
304 #endif
305 }
306
307 inline void SetClipOrigin(Bitmap bitmap, GC clip_gc, int clip_x, int clip_y)
308 {
309 #ifdef TARGET_X11
310   if (clip_gc)
311   {
312     bitmap->clip_gc = clip_gc;
313     XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
314   }
315 #if 0
316   last_clip_gc = clip_gc;
317 #endif
318 #endif
319 }
320
321 inline void BlitBitmapMasked(Bitmap src_bitmap, Bitmap dst_bitmap,
322                              int src_x, int src_y,
323                              int width, int height,
324                              int dst_x, int dst_y)
325 {
326 #ifdef TARGET_SDL
327   SDLCopyArea(src_bitmap, dst_bitmap,
328               src_x, src_y, width, height, dst_x, dst_y, SDLCOPYAREA_MASKED);
329 #else
330   XCopyArea(display, src_bitmap->drawable, dst_bitmap->drawable,
331             src_bitmap->clip_gc, src_x, src_y, width, height, dst_x, dst_y);
332 #endif
333 }
334
335 inline void DrawSimpleWhiteLine(Bitmap bitmap, int from_x, int from_y,
336                                 int to_x, int to_y)
337 {
338 #ifdef TARGET_SDL
339   SDLDrawSimpleLine(bitmap->surface, from_x, from_y, to_x, to_y, 0xffffff);
340 #else
341   XSetForeground(display, bitmap->gc, WhitePixel(display, screen));
342   XDrawLine(display, bitmap->drawable, bitmap->gc, from_x, from_y, to_x, to_y);
343   XSetForeground(display, bitmap->gc, BlackPixel(display, screen));
344 #endif
345 }
346
347 #if !defined(TARGET_X11_NATIVE)
348 inline void DrawLine(Bitmap bitmap, int from_x, int from_y,
349                      int to_x, int to_y, Pixel pixel, int line_width)
350 {
351   int x, y;
352
353   for (x=0; x<line_width; x++)
354   {
355     for (y=0; y<line_width; y++)
356     {
357       int dx = x - line_width / 2;
358       int dy = y - line_width / 2;
359
360       if ((x == 0 && y == 0) ||
361           (x == 0 && y == line_width - 1) ||
362           (x == line_width - 1 && y == 0) ||
363           (x == line_width - 1 && y == line_width - 1))
364         continue;
365
366 #if defined(TARGET_SDL)
367       sge_Line(bitmap->surface,
368                from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
369 #elif defined(TARGET_ALLEGRO)
370       AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy,
371                       to_x + dx, to_y + dy, pixel);
372 #endif
373     }
374   }
375 }
376 #endif
377
378 inline void DrawLines(Bitmap bitmap, struct XY *points, int num_points,
379                       Pixel pixel)
380 {
381 #if !defined(TARGET_X11_NATIVE)
382   int line_width = 4;
383   int i;
384
385   for (i=0; i<num_points - 1; i++)
386     DrawLine(bitmap, points[i].x, points[i].y,
387              points[i + 1].x, points[i + 1].y, pixel, line_width);
388
389   /*
390   SDLDrawLines(bitmap->surface, points, num_points, pixel);
391   */
392 #else
393   XSetForeground(display, bitmap->line_gc[1], pixel);
394   XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
395              (XPoint *)points, num_points, CoordModeOrigin);
396   /*
397   XSetForeground(display, gc, BlackPixel(display, screen));
398   */
399 #endif
400 }
401
402 inline Pixel GetPixelFromRGB(Bitmap bitmap, unsigned int color_r,
403                              unsigned int color_g, unsigned int color_b)
404 {
405   Pixel pixel;
406
407 #if defined(TARGET_SDL)
408   pixel = SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
409 #elif defined(TARGET_X11_NATIVE)
410   XColor xcolor;
411
412   xcolor.flags = DoRed | DoGreen | DoBlue;
413   xcolor.red = (color_r << 8);
414   xcolor.green = (color_g << 8);
415   xcolor.blue = (color_b << 8);
416   XAllocColor(display, cmap, &xcolor);
417   pixel = xcolor.pixel;
418 #endif
419
420   return pixel;
421 }
422
423 inline Pixel GetPixelFromRGBcompact(Bitmap bitmap, unsigned int color)
424 {
425   unsigned int color_r = (color >> 16) & 0xff;
426   unsigned int color_g = (color >>  8) & 0xff;
427   unsigned int color_b = (color >>  0) & 0xff;
428
429   return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
430 }
431
432 /* execute all pending screen drawing operations */
433 inline void FlushDisplay(void)
434 {
435 #ifndef TARGET_SDL
436   XFlush(display);
437 #endif
438 }
439
440 /* execute and wait for all pending screen drawing operations */
441 inline void SyncDisplay(void)
442 {
443 #ifndef TARGET_SDL
444   XSync(display, FALSE);
445 #endif
446 }
447
448 inline void KeyboardAutoRepeatOn(void)
449 {
450 #ifdef TARGET_SDL
451   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
452                       SDL_DEFAULT_REPEAT_INTERVAL / 2);
453   SDL_EnableUNICODE(1);
454 #else
455   XAutoRepeatOn(display);
456 #endif
457 }
458
459 inline void KeyboardAutoRepeatOff(void)
460 {
461 #ifdef TARGET_SDL
462   SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
463   SDL_EnableUNICODE(0);
464 #else
465   XAutoRepeatOff(display);
466 #endif
467 }
468
469 inline boolean PointerInWindow(DrawWindow window)
470 {
471 #ifdef TARGET_SDL
472   return TRUE;
473 #else
474   Window root, child;
475   int root_x, root_y;
476   unsigned int mask;
477   int win_x, win_y;
478
479   /* if XQueryPointer() returns False, the pointer
480      is not on the same screen as the specified window */
481   return XQueryPointer(display, window->drawable, &root, &child,
482                        &root_x, &root_y, &win_x, &win_y, &mask);
483 #endif
484 }
485
486 inline boolean SetVideoMode(boolean fullscreen)
487 {
488 #ifdef TARGET_SDL
489   return SDLSetVideoMode(&backbuffer, fullscreen);
490 #else
491   boolean success = TRUE;
492
493   if (fullscreen && video.fullscreen_available)
494   {
495     Error(ERR_WARN, "fullscreen not available in X11 version");
496
497     /* display error message only once */
498     video.fullscreen_available = FALSE;
499
500     success = FALSE;
501   }
502
503   return success;
504 #endif
505 }
506
507 inline boolean ChangeVideoModeIfNeeded(boolean fullscreen)
508 {
509 #ifdef TARGET_SDL
510   if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
511       (!fullscreen && video.fullscreen_enabled))
512     fullscreen = SetVideoMode(fullscreen);
513 #endif
514
515   return fullscreen;
516 }
517
518
519 /* ========================================================================= */
520 /* audio functions                                                           */
521 /* ========================================================================= */
522
523 inline boolean OpenAudio(struct AudioSystemInfo *audio)
524 {
525   audio->sound_available = FALSE;
526   audio->loops_available = FALSE;
527   audio->sound_enabled = FALSE;
528   audio->soundserver_pipe[0] = audio->soundserver_pipe[1] = 0;
529   audio->soundserver_pid = 0;
530   audio->device_name = NULL;
531   audio->device_fd = 0;
532
533 #if defined(TARGET_SDL)
534   if (SDLOpenAudio())
535   {
536     audio->sound_available = TRUE;
537     audio->loops_available = TRUE;
538     audio->sound_enabled = TRUE;
539   }
540 #elif defined(PLATFORM_MSDOS)
541   if (MSDOSOpenAudio())
542   {
543     audio->sound_available = TRUE;
544     audio->loops_available = TRUE;
545     audio->sound_enabled = TRUE;
546   }
547 #elif defined(PLATFORM_UNIX)
548   UnixOpenAudio(audio);
549 #endif
550
551   return audio->sound_available;
552 }
553
554 inline void CloseAudio(struct AudioSystemInfo *audio)
555 {
556 #if defined(TARGET_SDL)
557   SDLCloseAudio();
558 #elif defined(PLATFORM_MSDOS)
559   MSDOSCloseAudio();
560 #elif defined(PLATFORM_UNIX)
561   UnixCloseAudio(audio);
562 #endif
563
564   audio->sound_available = FALSE;
565   audio->loops_available = FALSE;
566   audio->sound_enabled = FALSE;
567 }
568
569 inline void SetAudioMode(boolean enabled)
570 {
571   if (!audio.sound_available)
572     return;
573
574   audio.sound_enabled = enabled;
575 }
576
577
578 /* ========================================================================= */
579 /* event functions                                                           */
580 /* ========================================================================= */
581
582 inline void InitEventFilter(EventFilter filter_function)
583 {
584 #ifdef TARGET_SDL
585   /* set event filter to filter out certain events */
586   SDL_SetEventFilter(filter_function);
587 #endif
588 }
589
590 inline boolean PendingEvent(void)
591 {
592 #ifdef TARGET_SDL
593   return (SDL_PollEvent(NULL) ? TRUE : FALSE);
594 #else
595   return (XPending(display) ? TRUE : FALSE);
596 #endif
597 }
598
599 inline void NextEvent(Event *event)
600 {
601 #ifdef TARGET_SDL
602   SDL_WaitEvent(event);
603 #else
604   XNextEvent(display, event);
605 #endif
606 }
607
608 inline Key GetEventKey(KeyEvent *event, boolean with_modifiers)
609 {
610 #ifdef TARGET_SDL
611 #if 0
612   printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
613          (int)event->keysym.unicode,
614          (int)event->keysym.sym,
615          (int)SDL_GetModState());
616 #endif
617
618   if (with_modifiers && event->keysym.unicode != 0)
619     return event->keysym.unicode;
620   else
621     return event->keysym.sym;
622 #else
623 #if 0
624   printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
625          (int)XLookupKeysym(event, event->state),
626          (int)XLookupKeysym(event, 0));
627 #endif
628
629   if (with_modifiers)
630     return XLookupKeysym(event, event->state);
631   else
632     return XLookupKeysym(event, 0);
633 #endif
634 }
635
636 inline boolean CheckCloseWindowEvent(ClientMessageEvent *event)
637 {
638   if (event->type != EVENT_CLIENTMESSAGE)
639     return FALSE;
640
641 #if defined(TARGET_SDL)
642   return TRUE;          /* the only possible message here is SDL_QUIT */
643 #elif defined(PLATFORM_UNIX)
644   if ((event->window == window->drawable) &&
645       (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
646     return TRUE;
647 #endif
648
649   return FALSE;
650 }
651
652
653 inline void dummy(void)
654 {
655 #ifdef TARGET_SDL
656 #else
657 #endif
658 }