eff8576cf417ccf793b11304a209ebe58cf32b80
[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     Error(ERR_EXIT, "cannot create pixmap");
213   new_bitmap->drawable = pixmap;
214
215   if (window == NULL)
216     Error(ERR_EXIT, "Window GC needed for Bitmap -- create Window first");
217   new_bitmap->gc = window->gc;
218
219 #endif
220
221   return new_bitmap;
222 }
223
224 inline void FreeBitmap(Bitmap bitmap)
225 {
226   if (bitmap == NULL)
227     return;
228
229 #ifdef TARGET_SDL
230   if (bitmap->surface)
231     SDL_FreeSurface(bitmap->surface);
232   if (bitmap->surface_masked)
233     SDL_FreeSurface(bitmap->surface_masked);
234 #else
235   if (bitmap->drawable)
236     XFreePixmap(display, bitmap->drawable);
237   if (bitmap->clip_mask)
238     XFreePixmap(display, bitmap->clip_mask);
239   if (bitmap->stored_clip_gc)
240     XFreeGC(display, bitmap->stored_clip_gc);
241 #endif
242
243   free(bitmap);
244 }
245
246 inline void CloseWindow(DrawWindow window)
247 {
248 #ifdef TARGET_X11
249   if (window->drawable)
250   {
251     XUnmapWindow(display, window->drawable);
252     XDestroyWindow(display, window->drawable);
253   }
254   if (window->gc)
255     XFreeGC(display, window->gc);
256 #endif
257 }
258
259 inline void BlitBitmap(Bitmap src_bitmap, Bitmap dst_bitmap,
260                        int src_x, int src_y,
261                        int width, int height,
262                        int dst_x, int dst_y)
263 {
264 #ifdef TARGET_SDL
265   SDLCopyArea(src_bitmap, dst_bitmap,
266               src_x, src_y, width, height, dst_x, dst_y, SDLCOPYAREA_OPAQUE);
267 #else
268   XCopyArea(display, src_bitmap->drawable, dst_bitmap->drawable,
269             dst_bitmap->gc, src_x, src_y, width, height, dst_x, dst_y);
270 #endif
271 }
272
273 inline void ClearRectangle(Bitmap bitmap, int x, int y, int width, int height)
274 {
275 #ifdef TARGET_SDL
276   SDLFillRectangle(bitmap, x, y, width, height, 0x000000);
277 #else
278   XFillRectangle(display, bitmap->drawable, bitmap->gc, x, y, width, height);
279 #endif
280 }
281
282 #if 0
283 #ifndef TARGET_SDL
284 static GC last_clip_gc = 0;     /* needed for XCopyArea() through clip mask */
285 #endif
286 #endif
287
288 inline void SetClipMask(Bitmap bitmap, GC clip_gc, Pixmap clip_pixmap)
289 {
290 #ifdef TARGET_X11
291   if (clip_gc)
292   {
293     bitmap->clip_gc = clip_gc;
294     XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
295   }
296 #if 0
297   last_clip_gc = clip_gc;
298 #endif
299 #endif
300 }
301
302 inline void SetClipOrigin(Bitmap bitmap, GC clip_gc, int clip_x, int clip_y)
303 {
304 #ifdef TARGET_X11
305   if (clip_gc)
306   {
307     bitmap->clip_gc = clip_gc;
308     XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
309   }
310 #if 0
311   last_clip_gc = clip_gc;
312 #endif
313 #endif
314 }
315
316 inline void BlitBitmapMasked(Bitmap src_bitmap, Bitmap dst_bitmap,
317                              int src_x, int src_y,
318                              int width, int height,
319                              int dst_x, int dst_y)
320 {
321 #ifdef TARGET_SDL
322   SDLCopyArea(src_bitmap, dst_bitmap,
323               src_x, src_y, width, height, dst_x, dst_y, SDLCOPYAREA_MASKED);
324 #else
325   XCopyArea(display, src_bitmap->drawable, dst_bitmap->drawable,
326             src_bitmap->clip_gc, src_x, src_y, width, height, dst_x, dst_y);
327 #endif
328 }
329
330 inline void DrawSimpleWhiteLine(Bitmap bitmap, int from_x, int from_y,
331                                 int to_x, int to_y)
332 {
333 #ifdef TARGET_SDL
334   SDLDrawSimpleLine(bitmap->surface, from_x, from_y, to_x, to_y, 0xffffff);
335 #else
336   XSetForeground(display, bitmap->gc, WhitePixel(display, screen));
337   XDrawLine(display, bitmap->drawable, bitmap->gc, from_x, from_y, to_x, to_y);
338   XSetForeground(display, bitmap->gc, BlackPixel(display, screen));
339 #endif
340 }
341
342 /* execute all pending screen drawing operations */
343 inline void FlushDisplay(void)
344 {
345 #ifndef TARGET_SDL
346   XFlush(display);
347 #endif
348 }
349
350 /* execute and wait for all pending screen drawing operations */
351 inline void SyncDisplay(void)
352 {
353 #ifndef TARGET_SDL
354   XSync(display, FALSE);
355 #endif
356 }
357
358 inline void KeyboardAutoRepeatOn(void)
359 {
360 #ifdef TARGET_SDL
361   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
362                       SDL_DEFAULT_REPEAT_INTERVAL / 2);
363   SDL_EnableUNICODE(1);
364 #else
365   XAutoRepeatOn(display);
366 #endif
367 }
368
369 inline void KeyboardAutoRepeatOff(void)
370 {
371 #ifdef TARGET_SDL
372   SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
373   SDL_EnableUNICODE(0);
374 #else
375   XAutoRepeatOff(display);
376 #endif
377 }
378
379 inline boolean PointerInWindow(DrawWindow window)
380 {
381 #ifdef TARGET_SDL
382   return TRUE;
383 #else
384   Window root, child;
385   int root_x, root_y;
386   unsigned int mask;
387   int win_x, win_y;
388
389   /* if XQueryPointer() returns False, the pointer
390      is not on the same screen as the specified window */
391   return XQueryPointer(display, window->drawable, &root, &child,
392                        &root_x, &root_y, &win_x, &win_y, &mask);
393 #endif
394 }
395
396 inline boolean SetVideoMode(boolean fullscreen)
397 {
398 #ifdef TARGET_SDL
399   return SDLSetVideoMode(&backbuffer, fullscreen);
400 #else
401   boolean success = TRUE;
402
403   if (fullscreen && video.fullscreen_available)
404   {
405     Error(ERR_WARN, "fullscreen not available in X11 version");
406
407     /* display error message only once */
408     video.fullscreen_available = FALSE;
409
410     success = FALSE;
411   }
412
413   return success;
414 #endif
415 }
416
417 inline boolean ChangeVideoModeIfNeeded(boolean fullscreen)
418 {
419 #ifdef TARGET_SDL
420   if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
421       (!fullscreen && video.fullscreen_enabled))
422     fullscreen = SetVideoMode(fullscreen);
423 #endif
424
425   return fullscreen;
426 }
427
428
429 /* ========================================================================= */
430 /* audio functions                                                           */
431 /* ========================================================================= */
432
433 inline boolean OpenAudio(struct AudioSystemInfo *audio)
434 {
435   audio->sound_available = FALSE;
436   audio->loops_available = FALSE;
437   audio->sound_enabled = FALSE;
438   audio->soundserver_pipe[0] = audio->soundserver_pipe[1] = 0;
439   audio->soundserver_pid = 0;
440   audio->device_name = NULL;
441   audio->device_fd = 0;
442
443 #if defined(TARGET_SDL)
444   if (SDLOpenAudio())
445   {
446     audio->sound_available = TRUE;
447     audio->loops_available = TRUE;
448     audio->sound_enabled = TRUE;
449   }
450 #elif defined(PLATFORM_MSDOS)
451   if (MSDOSOpenAudio())
452   {
453     audio->sound_available = TRUE;
454     audio->loops_available = TRUE;
455     audio->sound_enabled = TRUE;
456   }
457 #elif defined(PLATFORM_UNIX)
458   UnixOpenAudio(audio);
459 #endif
460
461   return audio->sound_available;
462 }
463
464 inline void CloseAudio(struct AudioSystemInfo *audio)
465 {
466 #if defined(TARGET_SDL)
467   SDLCloseAudio();
468 #elif defined(PLATFORM_MSDOS)
469   MSDOSCloseAudio();
470 #elif defined(PLATFORM_UNIX)
471   UnixCloseAudio(audio);
472 #endif
473
474   audio->sound_available = FALSE;
475   audio->loops_available = FALSE;
476   audio->sound_enabled = FALSE;
477 }
478
479 inline void SetAudioMode(boolean enabled)
480 {
481   if (!audio.sound_available)
482     return;
483
484   audio.sound_enabled = enabled;
485 }
486
487
488 /* ========================================================================= */
489 /* event functions                                                           */
490 /* ========================================================================= */
491
492 inline void InitEventFilter(EventFilter filter_function)
493 {
494 #ifdef TARGET_SDL
495   /* set event filter to filter out certain events */
496   SDL_SetEventFilter(filter_function);
497 #endif
498 }
499
500 inline boolean PendingEvent(void)
501 {
502 #ifdef TARGET_SDL
503   return (SDL_PollEvent(NULL) ? TRUE : FALSE);
504 #else
505   return (XPending(display) ? TRUE : FALSE);
506 #endif
507 }
508
509 inline void NextEvent(Event *event)
510 {
511 #ifdef TARGET_SDL
512   SDL_WaitEvent(event);
513 #else
514   XNextEvent(display, event);
515 #endif
516 }
517
518 inline Key GetEventKey(KeyEvent *event, boolean with_modifiers)
519 {
520 #ifdef TARGET_SDL
521 #if 0
522   printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
523          (int)event->keysym.unicode,
524          (int)event->keysym.sym,
525          (int)SDL_GetModState());
526 #endif
527
528   if (with_modifiers && event->keysym.unicode != 0)
529     return event->keysym.unicode;
530   else
531     return event->keysym.sym;
532 #else
533 #if 0
534   printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
535          (int)XLookupKeysym(event, event->state),
536          (int)XLookupKeysym(event, 0));
537 #endif
538
539   if (with_modifiers)
540     return XLookupKeysym(event, event->state);
541   else
542     return XLookupKeysym(event, 0);
543 #endif
544 }
545
546 inline boolean CheckCloseWindowEvent(ClientMessageEvent *event)
547 {
548   if (event->type != EVENT_CLIENTMESSAGE)
549     return FALSE;
550
551 #if defined(TARGET_SDL)
552   return TRUE;          /* the only possible message here is SDL_QUIT */
553 #elif defined(PLATFORM_UNIX)
554   if ((event->window == window->drawable) &&
555       (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
556     return TRUE;
557 #endif
558
559   return FALSE;
560 }
561
562
563 inline void dummy(void)
564 {
565 #ifdef TARGET_SDL
566 #else
567 #endif
568 }