rnd-20001203-1-src
[rocksndiamonds.git] / src / libgame / system.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  ©1995 Artsoft Development                               *
5 *        Holger Schemel                                    *
6 *        33659 Bielefeld-Senne                             *
7 *        Telefon: (0521) 493245                            *
8 *        eMail: aeglos@valinor.owl.de                      *
9 *               aeglos@uni-paderborn.de                    *
10 *               q99492@pbhrzx.uni-paderborn.de             *
11 *----------------------------------------------------------*
12 *  system.c                                                *
13 ***********************************************************/
14
15 #include "libgame.h"
16
17
18 /* ========================================================================= */
19 /* exported variables                                                        */
20 /* ========================================================================= */
21
22 struct ProgramInfo      program;
23 struct OptionInfo       options;
24 struct VideoSystemInfo  video;
25 struct AudioSystemInfo  audio;
26 struct PlayfieldInfo    playfield;
27
28 Display        *display = NULL;
29 Visual         *visual = NULL;
30 int             screen = 0;
31 Colormap        cmap = None;
32
33 DrawWindow      window = NULL;
34 DrawBuffer      backbuffer = NULL;
35 DrawBuffer      drawto = NULL;
36
37 int             redraw_mask;
38 int             redraw_tiles;
39
40 int             FrameCounter = 0;
41
42
43 /* ========================================================================= */
44 /* video functions                                                           */
45 /* ========================================================================= */
46
47 inline void InitProgramInfo(char *command_name, char *program_title,
48                             char *window_title, char *icon_title,
49                             char *x11_icon_filename,
50                             char *x11_iconmask_filename,
51                             char *msdos_pointer_filename)
52 {
53   program.command_name = command_name;
54   program.program_title = program_title;
55   program.window_title = window_title;
56   program.icon_title = icon_title;
57   program.x11_icon_filename = x11_icon_filename;
58   program.x11_iconmask_filename = x11_iconmask_filename;
59   program.msdos_pointer_filename = msdos_pointer_filename;
60 }
61
62 inline void InitPlayfieldInfo(int sx, int sy, int sxsize, int sysize,
63                               int real_sx, int real_sy,
64                               int full_sxsize, int full_sysize)
65 {
66   playfield.sx = sx;
67   playfield.sy = sy;
68   playfield.sxsize = sxsize;
69   playfield.sysize = sysize;
70   playfield.real_sx = real_sx;
71   playfield.real_sy = real_sy;
72   playfield.full_sxsize = full_sxsize;
73   playfield.full_sysize = full_sysize;
74 }
75
76 inline void InitDoor1Info(int dx, int dy, int dxsize, int dysize)
77 {
78   playfield.dx = dx;
79   playfield.dy = dy;
80   playfield.dxsize = dxsize;
81   playfield.dysize = dysize;
82 }
83
84 inline void InitDoor2Info(int vx, int vy, int vxsize, int vysize)
85 {
86   playfield.vx = vx;
87   playfield.vy = vy;
88   playfield.vxsize = vxsize;
89   playfield.vysize = vysize;
90 }
91
92 inline void InitScrollbufferInfo(int scrollbuffer_width,
93                                  int scrollbuffer_height)
94 {
95   /* currently only used by MSDOS code to alloc VRAM buffer, if available */
96   playfield.scrollbuffer_width = scrollbuffer_width;
97   playfield.scrollbuffer_height = scrollbuffer_height;
98 }
99
100 inline static int GetRealDepth(int depth)
101 {
102   return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
103 }
104
105 inline void InitVideoDisplay(void)
106 {
107 #ifdef TARGET_SDL
108   SDLInitVideoDisplay();
109 #else
110   X11InitVideoDisplay();
111 #endif
112 }
113
114 inline void InitVideoBuffer(DrawBuffer *backbuffer, DrawWindow *window,
115                             int width, int height, int depth,
116                             boolean fullscreen)
117 {
118   video.width = width;
119   video.height = height;
120   video.depth = GetRealDepth(depth);
121   video.fullscreen_available = FULLSCREEN_STATUS;
122   video.fullscreen_enabled = FALSE;
123
124 #ifdef TARGET_SDL
125   SDLInitVideoBuffer(backbuffer, window, fullscreen);
126 #else
127   X11InitVideoBuffer(backbuffer, window);
128 #endif
129 }
130
131 inline Bitmap CreateBitmapStruct(void)
132 {
133 #ifdef TARGET_SDL
134   return checked_calloc(sizeof(struct SDLSurfaceInfo));
135 #else
136   return checked_calloc(sizeof(struct X11DrawableInfo));
137 #endif
138 }
139
140 inline Bitmap CreateBitmap(int width, int height, int depth)
141 {
142   Bitmap new_bitmap = CreateBitmapStruct();
143   int real_depth = GetRealDepth(depth);
144
145 #ifdef TARGET_SDL
146   SDL_Surface *surface_tmp, *surface_native;
147
148   if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height,
149                                           real_depth, 0, 0, 0, 0))
150       == NULL)
151     Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
152
153   if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
154     Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
155
156   SDL_FreeSurface(surface_tmp);
157
158   new_bitmap->surface = surface_native;
159 #else
160   Pixmap pixmap;
161
162   if (!(pixmap = XCreatePixmap(display, window->drawable,
163                                width, height, real_depth)))
164     Error(ERR_EXIT, "cannot create pixmap");
165
166   new_bitmap->drawable = pixmap;
167 #endif
168
169   if (window == NULL)
170     Error(ERR_EXIT, "Window GC needed for Bitmap -- create Window first");
171   new_bitmap->gc = window->gc;
172
173   return new_bitmap;
174 }
175
176 inline void FreeBitmap(Bitmap bitmap)
177 {
178   if (bitmap == NULL)
179     return;
180
181 #ifdef TARGET_SDL
182   if (bitmap->surface)
183     SDL_FreeSurface(bitmap->surface);
184   if (bitmap->surface_masked)
185     SDL_FreeSurface(bitmap->surface_masked);
186 #else
187   if (bitmap->drawable)
188     XFreePixmap(display, bitmap->drawable);
189   if (bitmap->clip_mask)
190     XFreePixmap(display, bitmap->clip_mask);
191   if (bitmap->stored_clip_gc)
192     XFreeGC(display, bitmap->stored_clip_gc);
193 #endif
194
195   free(bitmap);
196 }
197
198 inline void CloseWindow(DrawWindow window)
199 {
200 #ifdef TARGET_X11
201   if (window->drawable)
202   {
203     XUnmapWindow(display, window->drawable);
204     XDestroyWindow(display, window->drawable);
205   }
206   if (window->gc)
207     XFreeGC(display, window->gc);
208 #endif
209 }
210
211 inline void BlitBitmap(Bitmap src_bitmap, Bitmap dst_bitmap,
212                        int src_x, int src_y,
213                        int width, int height,
214                        int dst_x, int dst_y)
215 {
216 #ifdef TARGET_SDL
217   SDLCopyArea(src_bitmap, dst_bitmap,
218               src_x, src_y, width, height, dst_x, dst_y, SDLCOPYAREA_OPAQUE);
219 #else
220   XCopyArea(display, src_bitmap->drawable, dst_bitmap->drawable,
221             dst_bitmap->gc, src_x, src_y, width, height, dst_x, dst_y);
222 #endif
223 }
224
225 inline void ClearRectangle(Bitmap bitmap, int x, int y, int width, int height)
226 {
227 #ifdef TARGET_SDL
228   SDLFillRectangle(bitmap, x, y, width, height, 0x000000);
229 #else
230   XFillRectangle(display, bitmap->drawable, bitmap->gc, x, y, width, height);
231 #endif
232 }
233
234 #if 0
235 #ifndef TARGET_SDL
236 static GC last_clip_gc = 0;     /* needed for XCopyArea() through clip mask */
237 #endif
238 #endif
239
240 inline void SetClipMask(Bitmap bitmap, GC clip_gc, Pixmap clip_pixmap)
241 {
242 #ifdef TARGET_X11
243   if (clip_gc)
244   {
245     bitmap->clip_gc = clip_gc;
246     XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
247   }
248 #if 0
249   last_clip_gc = clip_gc;
250 #endif
251 #endif
252 }
253
254 inline void SetClipOrigin(Bitmap bitmap, GC clip_gc, int clip_x, int clip_y)
255 {
256 #ifdef TARGET_X11
257   if (clip_gc)
258   {
259     bitmap->clip_gc = clip_gc;
260     XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
261   }
262 #if 0
263   last_clip_gc = clip_gc;
264 #endif
265 #endif
266 }
267
268 inline void BlitBitmapMasked(Bitmap src_bitmap, Bitmap dst_bitmap,
269                              int src_x, int src_y,
270                              int width, int height,
271                              int dst_x, int dst_y)
272 {
273 #ifdef TARGET_SDL
274   SDLCopyArea(src_bitmap, dst_bitmap,
275               src_x, src_y, width, height, dst_x, dst_y, SDLCOPYAREA_MASKED);
276 #else
277   XCopyArea(display, src_bitmap->drawable, dst_bitmap->drawable,
278             src_bitmap->clip_gc, src_x, src_y, width, height, dst_x, dst_y);
279 #endif
280 }
281
282 inline void DrawSimpleWhiteLine(Bitmap bitmap, int from_x, int from_y,
283                                 int to_x, int to_y)
284 {
285 #ifdef TARGET_SDL
286   SDLDrawSimpleLine(bitmap->drawable, from_x, from_y, to_x, to_y, 0xffffff);
287 #else
288   XSetForeground(display, bitmap->gc, WhitePixel(display, screen));
289   XDrawLine(display, bitmap->drawable, bitmap->gc, from_x, from_y, to_x, to_y);
290   XSetForeground(display, bitmap->gc, BlackPixel(display, screen));
291 #endif
292 }
293
294 /* execute all pending screen drawing operations */
295 inline void FlushDisplay(void)
296 {
297 #ifndef TARGET_SDL
298   XFlush(display);
299 #endif
300 }
301
302 /* execute and wait for all pending screen drawing operations */
303 inline void SyncDisplay(void)
304 {
305 #ifndef TARGET_SDL
306   XSync(display, FALSE);
307 #endif
308 }
309
310 inline void KeyboardAutoRepeatOn(void)
311 {
312 #ifdef TARGET_SDL
313   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
314                       SDL_DEFAULT_REPEAT_INTERVAL / 2);
315   SDL_EnableUNICODE(1);
316 #else
317   XAutoRepeatOn(display);
318 #endif
319 }
320
321 inline void KeyboardAutoRepeatOff(void)
322 {
323 #ifdef TARGET_SDL
324   SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
325   SDL_EnableUNICODE(0);
326 #else
327   XAutoRepeatOff(display);
328 #endif
329 }
330
331 inline boolean PointerInWindow(DrawWindow window)
332 {
333 #ifdef TARGET_SDL
334   return TRUE;
335 #else
336   Window root, child;
337   int root_x, root_y;
338   unsigned int mask;
339   int win_x, win_y;
340
341   /* if XQueryPointer() returns False, the pointer
342      is not on the same screen as the specified window */
343   return XQueryPointer(display, window->drawable, &root, &child,
344                        &root_x, &root_y, &win_x, &win_y, &mask);
345 #endif
346 }
347
348 inline boolean SetVideoMode(boolean fullscreen)
349 {
350 #ifdef TARGET_SDL
351   return SDLSetVideoMode(&backbuffer, fullscreen);
352 #else
353   boolean success = TRUE;
354
355   if (fullscreen && video.fullscreen_available)
356   {
357     Error(ERR_WARN, "fullscreen not available in X11 version");
358
359     /* display error message only once */
360     video.fullscreen_available = FALSE;
361
362     success = FALSE;
363   }
364
365   return success;
366 #endif
367 }
368
369 inline boolean ChangeVideoModeIfNeeded(boolean fullscreen)
370 {
371 #ifdef TARGET_SDL
372   if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
373       (!fullscreen && video.fullscreen_enabled))
374     fullscreen = SetVideoMode(fullscreen);
375 #endif
376
377   return fullscreen;
378 }
379
380
381 /* ========================================================================= */
382 /* audio functions                                                           */
383 /* ========================================================================= */
384
385 inline boolean OpenAudio(struct AudioSystemInfo *audio)
386 {
387   audio->sound_available = FALSE;
388   audio->loops_available = FALSE;
389   audio->soundserver_pipe[0] = audio->soundserver_pipe[1] = 0;
390   audio->soundserver_pid = 0;
391   audio->device_name = NULL;
392   audio->device_fd = 0;
393
394 #if defined(TARGET_SDL)
395   if (SDLOpenAudio())
396   {
397     audio->sound_available = TRUE;
398     audio->loops_available = TRUE;
399   }
400 #elif defined(PLATFORM_MSDOS)
401   if (MSDOSOpenAudio())
402   {
403     audio->sound_available = TRUE;
404     audio->loops_available = TRUE;
405   }
406 #elif defined(PLATFORM_UNIX)
407   UnixOpenAudio(audio);
408 #endif
409
410   return audio->sound_available;
411 }
412
413 inline void CloseAudio(struct AudioSystemInfo *audio)
414 {
415 #if defined(TARGET_SDL)
416   SDLCloseAudio();
417 #elif defined(PLATFORM_MSDOS)
418   MSDOSCloseAudio();
419 #elif defined(PLATFORM_UNIX)
420   UnixCloseAudio(audio);
421 #endif
422
423   audio->sound_available = FALSE;
424   audio->loops_available = FALSE;
425 }
426
427
428 /* ========================================================================= */
429 /* event functions                                                           */
430 /* ========================================================================= */
431
432 inline void InitEventFilter(EventFilter filter_function)
433 {
434 #ifdef TARGET_SDL
435   /* set event filter to filter out certain events */
436   SDL_SetEventFilter(filter_function);
437 #endif
438 }
439
440 inline boolean PendingEvent(void)
441 {
442 #ifdef TARGET_SDL
443   return (SDL_PollEvent(NULL) ? TRUE : FALSE);
444 #else
445   return (XPending(display) ? TRUE : FALSE);
446 #endif
447 }
448
449 inline void NextEvent(Event *event)
450 {
451 #ifdef TARGET_SDL
452   SDL_WaitEvent(event);
453 #else
454   XNextEvent(display, event);
455 #endif
456 }
457
458 inline Key GetEventKey(KeyEvent *event, boolean with_modifiers)
459 {
460 #ifdef TARGET_SDL
461 #if 0
462   printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
463          (int)event->keysym.unicode,
464          (int)event->keysym.sym,
465          (int)SDL_GetModState());
466 #endif
467
468   if (with_modifiers && event->keysym.unicode != 0)
469     return event->keysym.unicode;
470   else
471     return event->keysym.sym;
472 #else
473 #if 0
474   printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
475          (int)XLookupKeysym(event, event->state),
476          (int)XLookupKeysym(event, 0));
477 #endif
478
479   if (with_modifiers)
480     return XLookupKeysym(event, event->state);
481   else
482     return XLookupKeysym(event, 0);
483 #endif
484 }
485
486 inline boolean CheckCloseWindowEvent(ClientMessageEvent *event)
487 {
488   if (event->type != EVENT_CLIENTMESSAGE)
489     return FALSE;
490
491 #if defined(TARGET_SDL)
492   return TRUE;          /* the only possible message here is SDL_QUIT */
493 #elif defined(PLATFORM_UNIX)
494   if ((event->window == window->drawable) &&
495       (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
496     return TRUE;
497 #endif
498
499   return FALSE;
500 }
501
502
503 inline void dummy(void)
504 {
505 #ifdef TARGET_SDL
506 #else
507 #endif
508 }