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