1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2006 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 "image.h"
25 #include "sound.h"
26 #include "setup.h"
27 #include "joystick.h"
28 #include "misc.h"
29 
30 
31 /* ========================================================================= */
32 /* exported variables                                                        */
33 /* ========================================================================= */
34 
35 struct ProgramInfo	program;
36 struct OptionInfo	options;
37 struct VideoSystemInfo	video;
38 struct AudioSystemInfo	audio;
39 struct GfxInfo		gfx;
40 struct ArtworkInfo	artwork;
41 struct JoystickInfo	joystick;
42 struct SetupInfo	setup;
43 
44 LevelDirTree	       *leveldir_first_all = NULL;
45 LevelDirTree	       *leveldir_first = NULL;
46 LevelDirTree	       *leveldir_current = NULL;
47 int			level_nr;
48 
49 Display		       *display = NULL;
50 Visual		       *visual = NULL;
51 int			screen = 0;
52 Colormap		cmap = None;
53 
54 DrawWindow	       *window = NULL;
55 DrawBuffer	       *backbuffer = NULL;
56 DrawBuffer	       *drawto = NULL;
57 
58 int			button_status = MB_NOT_PRESSED;
59 boolean			motion_status = FALSE;
60 
61 int			redraw_mask = REDRAW_NONE;
62 int			redraw_tiles = 0;
63 
64 int			FrameCounter = 0;
65 
66 
67 /* ========================================================================= */
68 /* init/close functions                                                      */
69 /* ========================================================================= */
70 
InitProgramInfo(char * argv0,char * userdata_subdir,char * userdata_subdir_unix,char * program_title,char * window_title,char * icon_title,char * x11_icon_filename,char * x11_iconmask_filename,char * sdl_icon_filename,char * msdos_cursor_filename,char * cookie_prefix,char * filename_prefix,int program_version)71 void InitProgramInfo(char *argv0,
72 		     char *userdata_subdir, char *userdata_subdir_unix,
73 		     char *program_title, char *window_title, char *icon_title,
74 		     char *x11_icon_filename, char *x11_iconmask_filename,
75 		     char *sdl_icon_filename, char *msdos_cursor_filename,
76 		     char *cookie_prefix, char *filename_prefix,
77 		     int program_version)
78 {
79   program.command_basepath = getBasePath(argv0);
80   program.command_basename = getBaseName(argv0);
81 
82   program.userdata_subdir = userdata_subdir;
83   program.userdata_subdir_unix = userdata_subdir_unix;
84   program.userdata_path = getUserGameDataDir();
85 
86   program.program_title = program_title;
87   program.window_title = window_title;
88   program.icon_title = icon_title;
89 
90   program.x11_icon_filename = x11_icon_filename;
91   program.x11_iconmask_filename = x11_iconmask_filename;
92   program.sdl_icon_filename = sdl_icon_filename;
93   program.msdos_cursor_filename = msdos_cursor_filename;
94 
95   program.cookie_prefix = cookie_prefix;
96   program.filename_prefix = filename_prefix;
97 
98   program.version_major = VERSION_MAJOR(program_version);
99   program.version_minor = VERSION_MINOR(program_version);
100   program.version_patch = VERSION_PATCH(program_version);
101 
102   program.error_filename = getErrorFilename(ERROR_BASENAME);
103   program.error_file = stderr;
104 }
105 
InitExitFunction(void (* exit_function)(int))106 void InitExitFunction(void (*exit_function)(int))
107 {
108   program.exit_function = exit_function;
109 
110   /* set signal handlers to custom exit function */
111   signal(SIGINT, exit_function);
112   signal(SIGTERM, exit_function);
113 
114 #if defined(TARGET_SDL)
115   /* set exit function to automatically cleanup SDL stuff after exit() */
116   atexit(SDL_Quit);
117 #endif
118 }
119 
InitPlatformDependentStuff(void)120 void InitPlatformDependentStuff(void)
121 {
122 #if defined(PLATFORM_MSDOS)
123   _fmode = O_BINARY;
124 #endif
125 
126 #if defined(PLATFORM_MACOSX)
127   updateUserGameDataDir();
128 #endif
129 
130 #if !defined(PLATFORM_UNIX) || defined(PLATFORM_MACOSX)
131   openErrorFile();
132 #endif
133 
134 #if defined(TARGET_SDL)
135   if (SDL_Init(SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE) < 0)
136     Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
137 
138   SDLNet_Init();
139 #endif
140 }
141 
ClosePlatformDependentStuff(void)142 void ClosePlatformDependentStuff(void)
143 {
144 #if defined(PLATFORM_WIN32) || defined(PLATFORM_MSDOS)
145   closeErrorFile();
146 #endif
147 
148 #if defined(PLATFORM_MSDOS)
149   dumpErrorFile();
150 #endif
151 }
152 
InitGfxFieldInfo(int sx,int sy,int sxsize,int sysize,int real_sx,int real_sy,int full_sxsize,int full_sysize,Bitmap * field_save_buffer)153 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
154 		      int real_sx, int real_sy,
155 		      int full_sxsize, int full_sysize,
156 		      Bitmap *field_save_buffer)
157 {
158   gfx.sx = sx;
159   gfx.sy = sy;
160   gfx.sxsize = sxsize;
161   gfx.sysize = sysize;
162   gfx.real_sx = real_sx;
163   gfx.real_sy = real_sy;
164   gfx.full_sxsize = full_sxsize;
165   gfx.full_sysize = full_sysize;
166 
167   gfx.field_save_buffer = field_save_buffer;
168 
169 #if 0
170   gfx.background_bitmap = NULL;
171   gfx.background_bitmap_mask = REDRAW_NONE;
172 #endif
173 
174   SetDrawDeactivationMask(REDRAW_NONE);		/* do not deactivate drawing */
175   SetDrawBackgroundMask(REDRAW_NONE);		/* deactivate masked drawing */
176 }
177 
InitGfxDoor1Info(int dx,int dy,int dxsize,int dysize)178 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
179 {
180   gfx.dx = dx;
181   gfx.dy = dy;
182   gfx.dxsize = dxsize;
183   gfx.dysize = dysize;
184 }
185 
InitGfxDoor2Info(int vx,int vy,int vxsize,int vysize)186 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
187 {
188   gfx.vx = vx;
189   gfx.vy = vy;
190   gfx.vxsize = vxsize;
191   gfx.vysize = vysize;
192 }
193 
InitGfxWindowInfo(int win_xsize,int win_ysize)194 void InitGfxWindowInfo(int win_xsize, int win_ysize)
195 {
196   gfx.win_xsize = win_xsize;
197   gfx.win_ysize = win_ysize;
198 
199 #if 1
200   gfx.background_bitmap_mask = REDRAW_NONE;
201 
202   ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize, DEFAULT_DEPTH);
203 #endif
204 }
205 
InitGfxScrollbufferInfo(int scrollbuffer_width,int scrollbuffer_height)206 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
207 {
208   /* currently only used by MSDOS code to alloc VRAM buffer, if available */
209   /* 2009-03-24: also (temporarily?) used for overlapping blit workaround */
210   gfx.scrollbuffer_width = scrollbuffer_width;
211   gfx.scrollbuffer_height = scrollbuffer_height;
212 }
213 
InitGfxClipRegion(boolean enabled,int x,int y,int width,int height)214 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
215 {
216   gfx.clipping_enabled = enabled;
217   gfx.clip_x = x;
218   gfx.clip_y = y;
219   gfx.clip_width = width;
220   gfx.clip_height = height;
221 }
222 
InitGfxDrawBusyAnimFunction(void (* draw_busy_anim_function)(void))223 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
224 {
225   gfx.draw_busy_anim_function = draw_busy_anim_function;
226 }
227 
InitGfxCustomArtworkInfo()228 void InitGfxCustomArtworkInfo()
229 {
230   gfx.override_level_graphics = FALSE;
231   gfx.override_level_sounds = FALSE;
232   gfx.override_level_music = FALSE;
233 
234   gfx.draw_init_text = TRUE;
235 }
236 
SetDrawDeactivationMask(int draw_deactivation_mask)237 void SetDrawDeactivationMask(int draw_deactivation_mask)
238 {
239   gfx.draw_deactivation_mask = draw_deactivation_mask;
240 }
241 
SetDrawBackgroundMask(int draw_background_mask)242 void SetDrawBackgroundMask(int draw_background_mask)
243 {
244   gfx.draw_background_mask = draw_background_mask;
245 }
246 
DrawBitmapFromTile(Bitmap * bitmap,Bitmap * tile,int dest_x,int dest_y,int width,int height)247 static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile,
248 			       int dest_x, int dest_y, int width, int height)
249 {
250   int bitmap_xsize = width;
251   int bitmap_ysize = height;
252   int tile_xsize = tile->width;
253   int tile_ysize = tile->height;
254   int tile_xsteps = (bitmap_xsize + tile_xsize - 1) / tile_xsize;
255   int tile_ysteps = (bitmap_ysize + tile_ysize - 1) / tile_ysize;
256   int x, y;
257 
258   for (y = 0; y < tile_ysteps; y++)
259   {
260     for (x = 0; x < tile_xsteps; x++)
261     {
262       int draw_x = dest_x + x * tile_xsize;
263       int draw_y = dest_y + y * tile_ysize;
264       int draw_xsize = MIN(tile_xsize, bitmap_xsize - x * tile_xsize);
265       int draw_ysize = MIN(tile_ysize, bitmap_ysize - y * tile_ysize);
266 
267       BlitBitmap(tile, bitmap, 0, 0, draw_xsize, draw_ysize, draw_x, draw_y);
268     }
269   }
270 }
271 
SetBackgroundBitmap(Bitmap * background_bitmap_tile,int mask)272 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
273 {
274   if (background_bitmap_tile != NULL)
275     gfx.background_bitmap_mask |= mask;
276   else
277     gfx.background_bitmap_mask &= ~mask;
278 
279 #if 0
280   if (gfx.background_bitmap == NULL)
281     gfx.background_bitmap = CreateBitmap(video.width, video.height,
282 					 DEFAULT_DEPTH);
283 #endif
284 
285   if (background_bitmap_tile == NULL)	/* empty background requested */
286     return;
287 
288   if (mask == REDRAW_ALL)
289     DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
290 		       0, 0, video.width, video.height);
291   else if (mask == REDRAW_FIELD)
292     DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
293 		       gfx.real_sx, gfx.real_sy,
294 		       gfx.full_sxsize, gfx.full_sysize);
295   else if (mask == REDRAW_DOOR_1)
296   {
297     DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
298 		       gfx.dx, gfx.dy,
299 		       gfx.dxsize, gfx.dysize);
300   }
301 }
302 
SetWindowBackgroundBitmap(Bitmap * background_bitmap_tile)303 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
304 {
305   /* remove every mask before setting mask for window */
306   /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
307   SetBackgroundBitmap(NULL, 0xffff);		/* !!! FIX THIS !!! */
308   SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
309 }
310 
SetMainBackgroundBitmap(Bitmap * background_bitmap_tile)311 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
312 {
313   /* remove window area mask before setting mask for main area */
314   /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
315   SetBackgroundBitmap(NULL, REDRAW_ALL);	/* !!! FIX THIS !!! */
316   SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
317 }
318 
SetDoorBackgroundBitmap(Bitmap * background_bitmap_tile)319 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
320 {
321   /* remove window area mask before setting mask for door area */
322   /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
323   SetBackgroundBitmap(NULL, REDRAW_ALL);	/* !!! FIX THIS !!! */
324   SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
325 }
326 
327 
328 /* ========================================================================= */
329 /* video functions                                                           */
330 /* ========================================================================= */
331 
GetRealDepth(int depth)332 inline static int GetRealDepth(int depth)
333 {
334   return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
335 }
336 
sysFillRectangle(Bitmap * bitmap,int x,int y,int width,int height,Pixel color)337 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
338 			       int width, int height, Pixel color)
339 {
340 #if defined(TARGET_SDL)
341   SDLFillRectangle(bitmap, x, y, width, height, color);
342 #else
343   X11FillRectangle(bitmap, x, y, width, height, color);
344 #endif
345 }
346 
sysCopyArea(Bitmap * src_bitmap,Bitmap * dst_bitmap,int src_x,int src_y,int width,int height,int dst_x,int dst_y,int mask_mode)347 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
348 			       int src_x, int src_y, int width, int height,
349 			       int dst_x, int dst_y, int mask_mode)
350 {
351 #if defined(TARGET_SDL)
352   SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
353 	      dst_x, dst_y, mask_mode);
354 #else
355   X11CopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
356 	      dst_x, dst_y, mask_mode);
357 #endif
358 }
359 
InitVideoDisplay(void)360 void InitVideoDisplay(void)
361 {
362 #if defined(TARGET_SDL)
363   SDLInitVideoDisplay();
364 #else
365   X11InitVideoDisplay();
366 #endif
367 }
368 
CloseVideoDisplay(void)369 void CloseVideoDisplay(void)
370 {
371   KeyboardAutoRepeatOn();
372 
373 #if defined(TARGET_SDL)
374   SDL_QuitSubSystem(SDL_INIT_VIDEO);
375 #else
376   if (display)
377     XCloseDisplay(display);
378 #endif
379 }
380 
InitVideoBuffer(int width,int height,int depth,boolean fullscreen)381 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
382 {
383   video.width = width;
384   video.height = height;
385   video.depth = GetRealDepth(depth);
386 
387   video.fullscreen_available = FULLSCREEN_STATUS;
388   video.fullscreen_enabled = FALSE;
389 #if 0
390   video.fullscreen_mode_current = NULL;
391   video.fullscreen_modes = NULL;
392 #endif
393 
394 #if defined(TARGET_SDL)
395   SDLInitVideoBuffer(&backbuffer, &window, fullscreen);
396 #else
397   X11InitVideoBuffer(&backbuffer, &window);
398 #endif
399 
400   drawto = backbuffer;
401 }
402 
FreeBitmapPointers(Bitmap * bitmap)403 inline static void FreeBitmapPointers(Bitmap *bitmap)
404 {
405   if (bitmap == NULL)
406     return;
407 
408 #if defined(TARGET_SDL)
409   SDLFreeBitmapPointers(bitmap);
410 #else
411   X11FreeBitmapPointers(bitmap);
412 #endif
413 
414   checked_free(bitmap->source_filename);
415   bitmap->source_filename = NULL;
416 }
417 
TransferBitmapPointers(Bitmap * src_bitmap,Bitmap * dst_bitmap)418 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
419 					  Bitmap *dst_bitmap)
420 {
421   if (src_bitmap == NULL || dst_bitmap == NULL)
422     return;
423 
424   FreeBitmapPointers(dst_bitmap);
425 
426   *dst_bitmap = *src_bitmap;
427 }
428 
FreeBitmap(Bitmap * bitmap)429 void FreeBitmap(Bitmap *bitmap)
430 {
431   if (bitmap == NULL)
432     return;
433 
434   FreeBitmapPointers(bitmap);
435 
436   free(bitmap);
437 }
438 
CreateBitmapStruct(void)439 Bitmap *CreateBitmapStruct(void)
440 {
441 #if defined(TARGET_SDL)
442   return checked_calloc(sizeof(struct SDLSurfaceInfo));
443 #else
444   return checked_calloc(sizeof(struct X11DrawableInfo));
445 #endif
446 }
447 
CreateBitmap(int width,int height,int depth)448 Bitmap *CreateBitmap(int width, int height, int depth)
449 {
450   Bitmap *new_bitmap = CreateBitmapStruct();
451   int real_width  = MAX(1, width);	/* prevent zero bitmap width */
452   int real_height = MAX(1, height);	/* prevent zero bitmap height */
453   int real_depth  = GetRealDepth(depth);
454 
455 #if defined(TARGET_SDL)
456   SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
457 #else
458   X11CreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
459 #endif
460 
461   new_bitmap->width  = real_width;
462   new_bitmap->height = real_height;
463 
464   return new_bitmap;
465 }
466 
ReCreateBitmap(Bitmap ** bitmap,int width,int height,int depth)467 void ReCreateBitmap(Bitmap **bitmap, int width, int height, int depth)
468 {
469   Bitmap *new_bitmap = CreateBitmap(width, height, depth);
470 
471   if (*bitmap == NULL)
472   {
473     *bitmap = new_bitmap;
474   }
475   else
476   {
477     TransferBitmapPointers(new_bitmap, *bitmap);
478     free(new_bitmap);
479   }
480 }
481 
CloseWindow(DrawWindow * window)482 void CloseWindow(DrawWindow *window)
483 {
484 #if defined(TARGET_X11)
485   X11CloseWindow(window);
486 #endif
487 }
488 
CheckDrawingArea(int x,int y,int width,int height,int draw_mask)489 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
490 				       int draw_mask)
491 {
492   if (draw_mask == REDRAW_NONE)
493     return FALSE;
494 
495   if (draw_mask & REDRAW_ALL)
496     return TRUE;
497 
498   if ((draw_mask & REDRAW_FIELD) &&
499       x >= gfx.real_sx && x < gfx.real_sx + gfx.full_sxsize)
500     return TRUE;
501 
502   if ((draw_mask & REDRAW_DOOR_1) &&
503       x >= gfx.dx && y < gfx.dy + gfx.dysize)
504     return TRUE;
505 
506   if ((draw_mask & REDRAW_DOOR_2) &&
507       x >= gfx.dx && y >= gfx.vy)
508     return TRUE;
509 
510   return FALSE;
511 }
512 
DrawingDeactivated(int x,int y,int width,int height)513 boolean DrawingDeactivated(int x, int y, int width, int height)
514 {
515   return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
516 }
517 
DrawingOnBackground(int x,int y)518 boolean DrawingOnBackground(int x, int y)
519 {
520   return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
521 	  CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
522 }
523 
InClippedRectangle(Bitmap * bitmap,int * x,int * y,int * width,int * height,boolean is_dest)524 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
525 				  int *width, int *height, boolean is_dest)
526 {
527 #if 1
528   int clip_x, clip_y, clip_width, clip_height;
529 
530   if (gfx.clipping_enabled && is_dest)	/* only clip destination bitmap */
531   {
532     clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
533     clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
534     clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
535     clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
536   }
537   else
538   {
539     clip_x = 0;
540     clip_y = 0;
541     clip_width = bitmap->width;
542     clip_height = bitmap->height;
543   }
544 
545   /* skip if rectangle completely outside bitmap */
546 
547   if (*x + *width  <= clip_x ||
548       *y + *height <= clip_y ||
549       *x >= clip_x + clip_width ||
550       *y >= clip_y + clip_height)
551     return FALSE;
552 
553   /* clip if rectangle overlaps bitmap */
554 
555   if (*x < clip_x)
556   {
557     *width -= clip_x - *x;
558     *x = clip_x;
559   }
560   else if (*x + *width > clip_x + clip_width)
561   {
562     *width = clip_x + clip_width - *x;
563   }
564 
565   if (*y < clip_y)
566   {
567     *height -= clip_y - *y;
568     *y = clip_y;
569   }
570   else if (*y + *height > clip_y + clip_height)
571   {
572     *height = clip_y + clip_height - *y;
573   }
574 
575   return TRUE;
576 
577 #else
578 
579   /* skip if rectangle completely outside bitmap */
580 
581   if (*x + *width <= 0 ||
582       *y + *height <= 0 ||
583       *x >= bitmap->width ||
584       *y >= bitmap->height)
585     return FALSE;
586 
587   /* clip if rectangle overlaps bitmap */
588 
589   if (*x < 0)
590   {
591     *width += *x;
592     *x = 0;
593   }
594   else if (*x + *width > bitmap->width)
595   {
596     *width = bitmap->width - *x;
597   }
598 
599   if (*y < 0)
600   {
601     *height += *y;
602     *y = 0;
603   }
604   else if (*y + *height > bitmap->height)
605   {
606     *height = bitmap->height - *y;
607   }
608 
609   return TRUE;
610 #endif
611 }
612 
BlitBitmap(Bitmap * src_bitmap,Bitmap * dst_bitmap,int src_x,int src_y,int width,int height,int dst_x,int dst_y)613 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
614 		int src_x, int src_y, int width, int height,
615 		int dst_x, int dst_y)
616 {
617   int dst_x_unclipped = dst_x;
618   int dst_y_unclipped = dst_y;
619 
620   if (DrawingDeactivated(dst_x, dst_y, width, height))
621     return;
622 
623 #if 1
624   if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
625       !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
626     return;
627 
628   /* source x/y might need adjustment if destination x/y was clipped top/left */
629   src_x += dst_x - dst_x_unclipped;
630   src_y += dst_y - dst_y_unclipped;
631 
632 #else
633   /* skip if rectangle starts outside bitmap */
634   if (src_x >= src_bitmap->width ||
635       src_y >= src_bitmap->height ||
636       dst_x >= dst_bitmap->width ||
637       dst_y >= dst_bitmap->height)
638     return;
639 
640   /* clip if rectangle overlaps bitmap */
641   if (src_x + width > src_bitmap->width)
642     width = src_bitmap->width - src_x;
643   if (src_y + height > src_bitmap->height)
644     height = src_bitmap->height - src_y;
645   if (dst_x + width > dst_bitmap->width)
646     width = dst_bitmap->width - dst_x;
647   if (dst_y + height > dst_bitmap->height)
648     height = dst_bitmap->height - dst_y;
649 #endif
650 
651 #if 0
652   /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
653   /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
654      but is already fixed in SVN and should therefore finally be fixed with
655      the next official SDL release, which is probably version 1.2.14.) */
656 #if 1
657   /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
658 #if defined(TARGET_SDL) && defined(PLATFORM_WIN32)
659   if (src_bitmap == dst_bitmap)
660   {
661     /* !!! THIS IS A BUG (IN THE SDL LIBRARY?) AND SHOULD BE FIXED !!! */
662 
663     /* needed when blitting directly to same bitmap -- should not be needed with
664        recent SDL libraries, but apparently does not work in 1.2.11 directly */
665 
666     static Bitmap *tmp_bitmap = NULL;
667     static int tmp_bitmap_xsize = 0;
668     static int tmp_bitmap_ysize = 0;
669 
670     /* start with largest static bitmaps for initial bitmap size ... */
671     if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
672     {
673       tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
674       tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
675     }
676 
677     /* ... and allow for later re-adjustments due to custom artwork bitmaps */
678     if (src_bitmap->width > tmp_bitmap_xsize ||
679 	src_bitmap->height > tmp_bitmap_ysize)
680     {
681       tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
682       tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
683 
684       FreeBitmap(tmp_bitmap);
685 
686       tmp_bitmap = NULL;
687     }
688 
689     if (tmp_bitmap == NULL)
690       tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
691 				DEFAULT_DEPTH);
692 
693     sysCopyArea(src_bitmap, tmp_bitmap,
694 		src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
695     sysCopyArea(tmp_bitmap, dst_bitmap,
696 		dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
697 
698     return;
699   }
700 #endif
701 #endif
702 #endif
703 
704   sysCopyArea(src_bitmap, dst_bitmap,
705 	      src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
706 }
707 
FadeRectangle(Bitmap * bitmap_cross,int x,int y,int width,int height,int fade_mode,int fade_delay,int post_delay,void (* draw_border_function)(void))708 void FadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
709 		   int fade_mode, int fade_delay, int post_delay,
710 		   void (*draw_border_function)(void))
711 {
712 #if 1
713   /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
714   if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
715     return;
716 #endif
717 
718 #if defined(TARGET_SDL)
719   SDLFadeRectangle(bitmap_cross, x, y, width, height,
720 		   fade_mode, fade_delay, post_delay, draw_border_function);
721 #else
722   X11FadeRectangle(bitmap_cross, x, y, width, height,
723 		   fade_mode, fade_delay, post_delay, draw_border_function);
724 #endif
725 }
726 
FillRectangle(Bitmap * bitmap,int x,int y,int width,int height,Pixel color)727 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
728 		   Pixel color)
729 {
730   if (DrawingDeactivated(x, y, width, height))
731     return;
732 
733 #if 1
734   if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
735     return;
736 #else
737   /* skip if rectangle starts outside bitmap */
738   if (x >= bitmap->width ||
739       y >= bitmap->height)
740     return;
741 
742   /* clip if rectangle overlaps bitmap */
743   if (x + width > bitmap->width)
744     width = bitmap->width - x;
745   if (y + height > bitmap->height)
746     height = bitmap->height - y;
747 #endif
748 
749   sysFillRectangle(bitmap, x, y, width, height, color);
750 }
751 
ClearRectangle(Bitmap * bitmap,int x,int y,int width,int height)752 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
753 {
754   FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
755 }
756 
ClearRectangleOnBackground(Bitmap * bitmap,int x,int y,int width,int height)757 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
758 				int width, int height)
759 {
760   if (DrawingOnBackground(x, y))
761     BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
762   else
763     ClearRectangle(bitmap, x, y, width, height);
764 }
765 
SetClipMask(Bitmap * bitmap,GC clip_gc,Pixmap clip_pixmap)766 void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
767 {
768 #if defined(TARGET_X11)
769   if (clip_gc)
770   {
771     bitmap->clip_gc = clip_gc;
772     XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
773   }
774 #endif
775 }
776 
SetClipOrigin(Bitmap * bitmap,GC clip_gc,int clip_x,int clip_y)777 void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
778 {
779 #if defined(TARGET_X11)
780   if (clip_gc)
781   {
782     bitmap->clip_gc = clip_gc;
783     XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
784   }
785 #endif
786 }
787 
BlitBitmapMasked(Bitmap * src_bitmap,Bitmap * dst_bitmap,int src_x,int src_y,int width,int height,int dst_x,int dst_y)788 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
789 		      int src_x, int src_y, int width, int height,
790 		      int dst_x, int dst_y)
791 {
792   if (DrawingDeactivated(dst_x, dst_y, width, height))
793     return;
794 
795   sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
796 	      dst_x, dst_y, BLIT_MASKED);
797 }
798 
BlitBitmapOnBackground(Bitmap * src_bitmap,Bitmap * dst_bitmap,int src_x,int src_y,int width,int height,int dst_x,int dst_y)799 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
800 			    int src_x, int src_y, int width, int height,
801 			    int dst_x, int dst_y)
802 {
803   if (DrawingOnBackground(dst_x, dst_y))
804   {
805     /* draw background */
806     BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
807 	       dst_x, dst_y);
808 
809     /* draw foreground */
810     SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
811 		  dst_x - src_x, dst_y - src_y);
812     BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
813 		     dst_x, dst_y);
814   }
815   else
816     BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
817 	       dst_x, dst_y);
818 }
819 
DrawSimpleBlackLine(Bitmap * bitmap,int from_x,int from_y,int to_x,int to_y)820 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
821 			 int to_x, int to_y)
822 {
823 #if defined(TARGET_SDL)
824   SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
825 #else
826   X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
827 #endif
828 }
829 
DrawSimpleWhiteLine(Bitmap * bitmap,int from_x,int from_y,int to_x,int to_y)830 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
831 			 int to_x, int to_y)
832 {
833 #if defined(TARGET_SDL)
834   SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
835 #else
836   X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
837 #endif
838 }
839 
840 #if !defined(TARGET_X11_NATIVE)
DrawLine(Bitmap * bitmap,int from_x,int from_y,int to_x,int to_y,Pixel pixel,int line_width)841 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
842 	      int to_x, int to_y, Pixel pixel, int line_width)
843 {
844   int x, y;
845 
846   for (x = 0; x < line_width; x++)
847   {
848     for (y = 0; y < line_width; y++)
849     {
850       int dx = x - line_width / 2;
851       int dy = y - line_width / 2;
852 
853       if ((x == 0 && y == 0) ||
854 	  (x == 0 && y == line_width - 1) ||
855 	  (x == line_width - 1 && y == 0) ||
856 	  (x == line_width - 1 && y == line_width - 1))
857 	continue;
858 
859 #if defined(TARGET_SDL)
860       SDLDrawLine(bitmap,
861 		  from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
862 #elif defined(TARGET_ALLEGRO)
863       AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy,
864 		      to_x + dx, to_y + dy, pixel);
865 #endif
866     }
867   }
868 }
869 #endif
870 
DrawLines(Bitmap * bitmap,struct XY * points,int num_points,Pixel pixel)871 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
872 {
873 #if !defined(TARGET_X11_NATIVE)
874   int line_width = 4;
875   int i;
876 
877   for (i = 0; i < num_points - 1; i++)
878     DrawLine(bitmap, points[i].x, points[i].y,
879 	     points[i + 1].x, points[i + 1].y, pixel, line_width);
880 
881   /*
882   SDLDrawLines(bitmap->surface, points, num_points, pixel);
883   */
884 #else
885   XSetForeground(display, bitmap->line_gc[1], pixel);
886   XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
887 	     (XPoint *)points, num_points, CoordModeOrigin);
888 #endif
889 }
890 
GetPixel(Bitmap * bitmap,int x,int y)891 Pixel GetPixel(Bitmap *bitmap, int x, int y)
892 {
893   if (x < 0 || x >= bitmap->width ||
894       y < 0 || y >= bitmap->height)
895     return BLACK_PIXEL;
896 
897 #if defined(TARGET_SDL)
898   return SDLGetPixel(bitmap, x, y);
899 #elif defined(TARGET_ALLEGRO)
900   return AllegroGetPixel(bitmap->drawable, x, y);
901 #else
902   return X11GetPixel(bitmap, x, y);
903 #endif
904 }
905 
GetPixelFromRGB(Bitmap * bitmap,unsigned int color_r,unsigned int color_g,unsigned int color_b)906 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
907 		      unsigned int color_g, unsigned int color_b)
908 {
909 #if defined(TARGET_SDL)
910   return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
911 #elif defined(TARGET_ALLEGRO)
912   return AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
913 #else
914   return X11GetPixelFromRGB(color_r, color_g, color_b);
915 #endif
916 }
917 
GetPixelFromRGBcompact(Bitmap * bitmap,unsigned int color)918 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
919 {
920   unsigned int color_r = (color >> 16) & 0xff;
921   unsigned int color_g = (color >>  8) & 0xff;
922   unsigned int color_b = (color >>  0) & 0xff;
923 
924   return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
925 }
926 
927 /* execute all pending screen drawing operations */
FlushDisplay(void)928 void FlushDisplay(void)
929 {
930 #ifndef TARGET_SDL
931   XFlush(display);
932 #endif
933 }
934 
935 /* execute and wait for all pending screen drawing operations */
SyncDisplay(void)936 void SyncDisplay(void)
937 {
938 #ifndef TARGET_SDL
939   XSync(display, FALSE);
940 #endif
941 }
942 
KeyboardAutoRepeatOn(void)943 void KeyboardAutoRepeatOn(void)
944 {
945 #if defined(TARGET_SDL)
946   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
947 		      SDL_DEFAULT_REPEAT_INTERVAL / 2);
948   SDL_EnableUNICODE(1);
949 #else
950   if (display)
951     XAutoRepeatOn(display);
952 #endif
953 }
954 
KeyboardAutoRepeatOff(void)955 void KeyboardAutoRepeatOff(void)
956 {
957 #if defined(TARGET_SDL)
958   SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
959   SDL_EnableUNICODE(0);
960 #else
961   if (display)
962     XAutoRepeatOff(display);
963 #endif
964 }
965 
PointerInWindow(DrawWindow * window)966 boolean PointerInWindow(DrawWindow *window)
967 {
968 #if defined(TARGET_SDL)
969   return TRUE;
970 #else
971   Window root, child;
972   int root_x, root_y;
973   unsigned int mask;
974   int win_x, win_y;
975 
976   /* if XQueryPointer() returns False, the pointer
977      is not on the same screen as the specified window */
978   return XQueryPointer(display, window->drawable, &root, &child,
979 		       &root_x, &root_y, &win_x, &win_y, &mask);
980 #endif
981 }
982 
SetVideoMode(boolean fullscreen)983 boolean SetVideoMode(boolean fullscreen)
984 {
985 #if defined(TARGET_SDL)
986   return SDLSetVideoMode(&backbuffer, fullscreen);
987 #else
988   boolean success = TRUE;
989 
990   if (fullscreen && video.fullscreen_available)
991   {
992     Error(ERR_WARN, "fullscreen not available in X11 version");
993 
994     /* display error message only once */
995     video.fullscreen_available = FALSE;
996 
997     success = FALSE;
998   }
999 
1000   return success;
1001 #endif
1002 }
1003 
ChangeVideoModeIfNeeded(boolean fullscreen)1004 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1005 {
1006 #if defined(TARGET_SDL)
1007   if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1008       (!fullscreen && video.fullscreen_enabled))
1009     fullscreen = SetVideoMode(fullscreen);
1010 #endif
1011 
1012   return fullscreen;
1013 }
1014 
LoadImage(char * filename)1015 Bitmap *LoadImage(char *filename)
1016 {
1017   Bitmap *new_bitmap;
1018 
1019 #if defined(TARGET_SDL)
1020   new_bitmap = SDLLoadImage(filename);
1021 #else
1022   new_bitmap = X11LoadImage(filename);
1023 #endif
1024 
1025   if (new_bitmap)
1026     new_bitmap->source_filename = getStringCopy(filename);
1027 
1028   return new_bitmap;
1029 }
1030 
LoadCustomImage(char * basename)1031 Bitmap *LoadCustomImage(char *basename)
1032 {
1033   char *filename = getCustomImageFilename(basename);
1034   Bitmap *new_bitmap;
1035 
1036   if (filename == NULL)
1037     Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1038 
1039   if ((new_bitmap = LoadImage(filename)) == NULL)
1040     Error(ERR_EXIT, "LoadImage() failed: %s", GetError());
1041 
1042   return new_bitmap;
1043 }
1044 
ReloadCustomImage(Bitmap * bitmap,char * basename)1045 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1046 {
1047   char *filename = getCustomImageFilename(basename);
1048   Bitmap *new_bitmap;
1049 
1050   if (filename == NULL)		/* (should never happen) */
1051   {
1052     Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1053     return;
1054   }
1055 
1056   if (strEqual(filename, bitmap->source_filename))
1057   {
1058     /* The old and new image are the same (have the same filename and path).
1059        This usually means that this image does not exist in this graphic set
1060        and a fallback to the existing image is done. */
1061 
1062     return;
1063   }
1064 
1065   if ((new_bitmap = LoadImage(filename)) == NULL)
1066   {
1067     Error(ERR_WARN, "LoadImage() failed: %s", GetError());
1068     return;
1069   }
1070 
1071   if (bitmap->width != new_bitmap->width ||
1072       bitmap->height != new_bitmap->height)
1073   {
1074     Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1075 	  filename);
1076     FreeBitmap(new_bitmap);
1077     return;
1078   }
1079 
1080   TransferBitmapPointers(new_bitmap, bitmap);
1081   free(new_bitmap);
1082 }
1083 
ZoomBitmap(Bitmap * src_bitmap,int zoom_width,int zoom_height)1084 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1085 {
1086   Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
1087 
1088 #if defined(TARGET_SDL)
1089   SDLZoomBitmap(src_bitmap, dst_bitmap);
1090 #else
1091   X11ZoomBitmap(src_bitmap, dst_bitmap);
1092 #endif
1093 
1094   return dst_bitmap;
1095 }
1096 
CreateScaledBitmaps(Bitmap * old_bitmap,int zoom_factor,boolean create_small_bitmaps)1097 static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor,
1098 				boolean create_small_bitmaps)
1099 {
1100   Bitmap swap_bitmap;
1101   Bitmap *new_bitmap;
1102   Bitmap *tmp_bitmap_1;
1103   Bitmap *tmp_bitmap_2;
1104   Bitmap *tmp_bitmap_4;
1105   Bitmap *tmp_bitmap_8;
1106   Bitmap *tmp_bitmap_16;
1107   Bitmap *tmp_bitmap_32;
1108   int width_1, height_1;
1109   int width_2, height_2;
1110   int width_4, height_4;
1111   int width_8, height_8;
1112   int width_16, height_16;
1113   int width_32, height_32;
1114   int new_width, new_height;
1115 
1116   /* calculate new image dimensions for normal sized image */
1117   width_1  = old_bitmap->width  * zoom_factor;
1118   height_1 = old_bitmap->height * zoom_factor;
1119 
1120   /* get image with normal size (this might require scaling up) */
1121   if (zoom_factor != 1)
1122     tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1123   else
1124     tmp_bitmap_1 = old_bitmap;
1125 
1126   /* this is only needed to make compilers happy */
1127   tmp_bitmap_2 = NULL;
1128   tmp_bitmap_4 = NULL;
1129   tmp_bitmap_8 = NULL;
1130   tmp_bitmap_16 = NULL;
1131   tmp_bitmap_32 = NULL;
1132 
1133   if (create_small_bitmaps)
1134   {
1135     /* calculate new image dimensions for small images */
1136     width_2  = width_1  / 2;
1137     height_2 = height_1 / 2;
1138     width_4  = width_1  / 4;
1139     height_4 = height_1 / 4;
1140     width_8  = width_1  / 8;
1141     height_8 = height_1 / 8;
1142     width_16  = width_1  / 16;
1143     height_16 = height_1 / 16;
1144     width_32  = width_1  / 32;
1145     height_32 = height_1 / 32;
1146 
1147     UPDATE_BUSY_STATE();
1148 
1149     /* get image with 1/2 of normal size (for use in the level editor) */
1150     if (zoom_factor != 2)
1151       tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2);
1152     else
1153       tmp_bitmap_2 = old_bitmap;
1154 
1155     UPDATE_BUSY_STATE();
1156 
1157     /* get image with 1/4 of normal size (for use in the level editor) */
1158     if (zoom_factor != 4)
1159       tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_2 / 2, height_2 / 2);
1160     else
1161       tmp_bitmap_4 = old_bitmap;
1162 
1163     UPDATE_BUSY_STATE();
1164 
1165     /* get image with 1/8 of normal size (for use on the preview screen) */
1166     if (zoom_factor != 8)
1167       tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_4 / 2, height_4 / 2);
1168     else
1169       tmp_bitmap_8 = old_bitmap;
1170 
1171     UPDATE_BUSY_STATE();
1172 
1173     /* get image with 1/16 of normal size (for use on the preview screen) */
1174     if (zoom_factor != 16)
1175       tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_8 / 2, height_8 / 2);
1176     else
1177       tmp_bitmap_16 = old_bitmap;
1178 
1179     UPDATE_BUSY_STATE();
1180 
1181     /* get image with 1/32 of normal size (for use on the preview screen) */
1182     if (zoom_factor != 32)
1183       tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_16 / 2, height_16 / 2);
1184     else
1185       tmp_bitmap_32 = old_bitmap;
1186 
1187     UPDATE_BUSY_STATE();
1188   }
1189 
1190 #if 0
1191   /* if image was scaled up, create new clipmask for normal size image */
1192   if (zoom_factor != 1)
1193   {
1194 #if defined(TARGET_X11)
1195     if (old_bitmap->clip_mask)
1196       XFreePixmap(display, old_bitmap->clip_mask);
1197 
1198     old_bitmap->clip_mask =
1199       Pixmap_to_Mask(tmp_bitmap_1->drawable, width_1, height_1);
1200 
1201     XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1202 #else
1203     SDL_Surface *tmp_surface_1 = tmp_bitmap_1->surface;
1204 
1205     if (old_bitmap->surface_masked)
1206       SDL_FreeSurface(old_bitmap->surface_masked);
1207 
1208     SDL_SetColorKey(tmp_surface_1, SDL_SRCCOLORKEY,
1209 		    SDL_MapRGB(tmp_surface_1->format, 0x00, 0x00, 0x00));
1210     if ((old_bitmap->surface_masked = SDL_DisplayFormat(tmp_surface_1)) ==NULL)
1211       Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1212     SDL_SetColorKey(tmp_surface_1, 0, 0);	/* reset transparent pixel */
1213 #endif
1214   }
1215 #endif
1216 
1217   if (create_small_bitmaps)
1218   {
1219     new_width  = width_1;
1220     new_height = height_1 + (height_1 + 1) / 2;     /* prevent odd height */
1221 
1222     new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH);
1223 
1224     BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0);
1225     BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2,
1226 	       0, height_1);
1227     BlitBitmap(tmp_bitmap_4, new_bitmap, 0, 0, width_1 / 4, height_1 / 4,
1228 	       width_1 / 2, height_1);
1229     BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8,
1230 	       3 * width_1 / 4, height_1);
1231     BlitBitmap(tmp_bitmap_16, new_bitmap, 0, 0, width_1 / 16, height_1 / 16,
1232 	       7 * width_1 / 8, height_1);
1233     BlitBitmap(tmp_bitmap_32, new_bitmap, 0, 0, width_1 / 32, height_1 / 32,
1234 	       15 * width_1 / 16, height_1);
1235 
1236     UPDATE_BUSY_STATE();
1237   }
1238   else
1239   {
1240     new_width  = width_1;
1241     new_height = height_1;
1242 
1243     new_bitmap = tmp_bitmap_1;	/* directly use tmp_bitmap_1 as new bitmap */
1244   }
1245 
1246   if (create_small_bitmaps)
1247   {
1248     /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */
1249     if (zoom_factor != 1)
1250       FreeBitmap(tmp_bitmap_1);
1251 
1252     if (zoom_factor != 2)
1253       FreeBitmap(tmp_bitmap_2);
1254 
1255     if (zoom_factor != 4)
1256       FreeBitmap(tmp_bitmap_4);
1257 
1258     if (zoom_factor != 8)
1259       FreeBitmap(tmp_bitmap_8);
1260 
1261     if (zoom_factor != 16)
1262       FreeBitmap(tmp_bitmap_16);
1263 
1264     if (zoom_factor != 32)
1265       FreeBitmap(tmp_bitmap_32);
1266   }
1267 
1268   /* replace image with extended image (containing 1/1, 1/2, 1/4, 1/8 size) */
1269 #if defined(TARGET_SDL)
1270   swap_bitmap.surface = old_bitmap->surface;
1271   old_bitmap->surface = new_bitmap->surface;
1272   new_bitmap->surface = swap_bitmap.surface;
1273 #else
1274   swap_bitmap.drawable = old_bitmap->drawable;
1275   old_bitmap->drawable = new_bitmap->drawable;
1276   new_bitmap->drawable = swap_bitmap.drawable;
1277 #endif
1278 
1279   old_bitmap->width  = new_bitmap->width;
1280   old_bitmap->height = new_bitmap->height;
1281 
1282 #if 1
1283   /* this replaces all blit masks created when loading -- maybe optimize this */
1284   {
1285 #if defined(TARGET_X11)
1286     if (old_bitmap->clip_mask)
1287       XFreePixmap(display, old_bitmap->clip_mask);
1288 
1289     old_bitmap->clip_mask =
1290       Pixmap_to_Mask(old_bitmap->drawable, new_width, new_height);
1291 
1292     XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1293 #else
1294     SDL_Surface *old_surface = old_bitmap->surface;
1295 
1296     if (old_bitmap->surface_masked)
1297       SDL_FreeSurface(old_bitmap->surface_masked);
1298 
1299     SDL_SetColorKey(old_surface, SDL_SRCCOLORKEY,
1300 		    SDL_MapRGB(old_surface->format, 0x00, 0x00, 0x00));
1301     if ((old_bitmap->surface_masked = SDL_DisplayFormat(old_surface)) ==NULL)
1302       Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1303     SDL_SetColorKey(old_surface, 0, 0);		/* reset transparent pixel */
1304 #endif
1305   }
1306 #endif
1307 
1308   UPDATE_BUSY_STATE();
1309 
1310   FreeBitmap(new_bitmap);	/* this actually frees the _old_ bitmap now */
1311 }
1312 
CreateBitmapWithSmallBitmaps(Bitmap * old_bitmap,int zoom_factor)1313 void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
1314 {
1315   CreateScaledBitmaps(old_bitmap, zoom_factor, TRUE);
1316 }
1317 
ScaleBitmap(Bitmap * old_bitmap,int zoom_factor)1318 void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor)
1319 {
1320   CreateScaledBitmaps(old_bitmap, zoom_factor, FALSE);
1321 }
1322 
1323 
1324 /* ------------------------------------------------------------------------- */
1325 /* mouse pointer functions                                                   */
1326 /* ------------------------------------------------------------------------- */
1327 
1328 #if !defined(PLATFORM_MSDOS)
1329 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER		0
1330 /* XPM image definitions */
1331 static const char *cursor_image_none[] =
1332 {
1333   /* width height num_colors chars_per_pixel */
1334   "    16    16        3            1",
1335 
1336   /* colors */
1337   "X c #000000",
1338   ". c #ffffff",
1339   "  c None",
1340 
1341   /* pixels */
1342   "                ",
1343   "                ",
1344   "                ",
1345   "                ",
1346   "                ",
1347   "                ",
1348   "                ",
1349   "                ",
1350   "                ",
1351   "                ",
1352   "                ",
1353   "                ",
1354   "                ",
1355   "                ",
1356   "                ",
1357   "                ",
1358 
1359   /* hot spot */
1360   "0,0"
1361 };
1362 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1363 static const char *cursor_image_dot[] =
1364 {
1365   /* width height num_colors chars_per_pixel */
1366   "    16    16        3            1",
1367 
1368   /* colors */
1369   "X c #000000",
1370   ". c #ffffff",
1371   "  c None",
1372 
1373   /* pixels */
1374   " X              ",
1375   "X.X             ",
1376   " X              ",
1377   "                ",
1378   "                ",
1379   "                ",
1380   "                ",
1381   "                ",
1382   "                ",
1383   "                ",
1384   "                ",
1385   "                ",
1386   "                ",
1387   "                ",
1388   "                ",
1389   "                ",
1390 
1391   /* hot spot */
1392   "1,1"
1393 };
1394 static const char **cursor_image_playfield = cursor_image_dot;
1395 #else
1396 /* some people complained about a "white dot" on the screen and thought it
1397    was a graphical error... OK, let's just remove the whole pointer :-) */
1398 static const char **cursor_image_playfield = cursor_image_none;
1399 #endif
1400 
1401 #if defined(TARGET_SDL)
1402 static const int cursor_bit_order = BIT_ORDER_MSB;
1403 #elif defined(TARGET_X11_NATIVE)
1404 static const int cursor_bit_order = BIT_ORDER_LSB;
1405 #endif
1406 
get_cursor_from_image(const char ** image)1407 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1408 {
1409   struct MouseCursorInfo *cursor;
1410   boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1411   int header_lines = 4;
1412   int x, y, i;
1413 
1414   cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1415 
1416   sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1417 
1418   i = -1;
1419   for (y = 0; y < cursor->width; y++)
1420   {
1421     for (x = 0; x < cursor->height; x++)
1422     {
1423       int bit_nr = x % 8;
1424       int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1425 
1426       if (bit_nr == 0)
1427       {
1428         i++;
1429         cursor->data[i] = cursor->mask[i] = 0;
1430       }
1431 
1432       switch (image[header_lines + y][x])
1433       {
1434         case 'X':
1435 	  cursor->data[i] |= bit_mask;
1436 	  cursor->mask[i] |= bit_mask;
1437 	  break;
1438 
1439         case '.':
1440 	  cursor->mask[i] |= bit_mask;
1441 	  break;
1442 
1443         case ' ':
1444 	  break;
1445       }
1446     }
1447   }
1448 
1449   sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1450 
1451   return cursor;
1452 }
1453 #endif	/* !PLATFORM_MSDOS */
1454 
SetMouseCursor(int mode)1455 void SetMouseCursor(int mode)
1456 {
1457 #if !defined(PLATFORM_MSDOS)
1458   static struct MouseCursorInfo *cursor_none = NULL;
1459   static struct MouseCursorInfo *cursor_playfield = NULL;
1460   struct MouseCursorInfo *cursor_new;
1461 
1462   if (cursor_none == NULL)
1463     cursor_none = get_cursor_from_image(cursor_image_none);
1464 
1465   if (cursor_playfield == NULL)
1466     cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1467 
1468   cursor_new = (mode == CURSOR_DEFAULT   ? NULL :
1469 		mode == CURSOR_NONE      ? cursor_none :
1470 		mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1471 
1472 #if defined(TARGET_SDL)
1473   SDLSetMouseCursor(cursor_new);
1474 #elif defined(TARGET_X11_NATIVE)
1475   X11SetMouseCursor(cursor_new);
1476 #endif
1477 #endif
1478 }
1479 
1480 
1481 /* ========================================================================= */
1482 /* audio functions                                                           */
1483 /* ========================================================================= */
1484 
OpenAudio(void)1485 void OpenAudio(void)
1486 {
1487   /* always start with reliable default values */
1488   audio.sound_available = FALSE;
1489   audio.music_available = FALSE;
1490   audio.loops_available = FALSE;
1491 
1492   audio.sound_enabled = FALSE;
1493   audio.sound_deactivated = FALSE;
1494 
1495   audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1496   audio.mixer_pid = 0;
1497   audio.device_name = NULL;
1498   audio.device_fd = -1;
1499 
1500   audio.num_channels = 0;
1501   audio.music_channel = 0;
1502   audio.first_sound_channel = 0;
1503 
1504 #if defined(TARGET_SDL)
1505   SDLOpenAudio();
1506 #elif defined(PLATFORM_UNIX)
1507   UnixOpenAudio();
1508 #elif defined(PLATFORM_MSDOS)
1509   MSDOSOpenAudio();
1510 #endif
1511 }
1512 
CloseAudio(void)1513 void CloseAudio(void)
1514 {
1515 #if defined(TARGET_SDL)
1516   SDLCloseAudio();
1517 #elif defined(PLATFORM_UNIX)
1518   UnixCloseAudio();
1519 #elif defined(PLATFORM_MSDOS)
1520   MSDOSCloseAudio();
1521 #endif
1522 
1523   audio.sound_enabled = FALSE;
1524 }
1525 
SetAudioMode(boolean enabled)1526 void SetAudioMode(boolean enabled)
1527 {
1528   if (!audio.sound_available)
1529     return;
1530 
1531   audio.sound_enabled = enabled;
1532 }
1533 
1534 
1535 /* ========================================================================= */
1536 /* event functions                                                           */
1537 /* ========================================================================= */
1538 
InitEventFilter(EventFilter filter_function)1539 void InitEventFilter(EventFilter filter_function)
1540 {
1541 #if defined(TARGET_SDL)
1542   /* set event filter to filter out certain events */
1543   SDL_SetEventFilter(filter_function);
1544 #endif
1545 }
1546 
PendingEvent(void)1547 boolean PendingEvent(void)
1548 {
1549 #if defined(TARGET_SDL)
1550   return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1551 #else
1552   return (XPending(display) ? TRUE : FALSE);
1553 #endif
1554 }
1555 
NextEvent(Event * event)1556 void NextEvent(Event *event)
1557 {
1558 #if defined(TARGET_SDL)
1559   SDLNextEvent(event);
1560 #else
1561   XNextEvent(display, event);
1562 #endif
1563 }
1564 
PeekEvent(Event * event)1565 void PeekEvent(Event *event)
1566 {
1567 #if defined(TARGET_SDL)
1568   SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1569 #else
1570   XPeekEvent(display, event);
1571 #endif
1572 }
1573 
GetEventKey(KeyEvent * event,boolean with_modifiers)1574 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1575 {
1576 #if defined(TARGET_SDL)
1577 
1578 #if 0
1579   printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1580 	 (int)event->keysym.unicode,
1581 	 (int)event->keysym.sym,
1582 	 (int)SDL_GetModState());
1583 #endif
1584 
1585   if (with_modifiers &&
1586       event->keysym.unicode > 0x0000 &&
1587       event->keysym.unicode < 0x2000)
1588     return event->keysym.unicode;
1589   else
1590     return event->keysym.sym;
1591 
1592 #else
1593 
1594 #if 0
1595   printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
1596 	 (int)XLookupKeysym(event, event->state),
1597 	 (int)XLookupKeysym(event, 0));
1598 #endif
1599 
1600   if (with_modifiers)
1601     return XLookupKeysym(event, event->state);
1602   else
1603     return XLookupKeysym(event, 0);
1604 #endif
1605 }
1606 
HandleKeyModState(Key key,int key_status)1607 KeyMod HandleKeyModState(Key key, int key_status)
1608 {
1609   static KeyMod current_modifiers = KMOD_None;
1610 
1611   if (key != KSYM_UNDEFINED)	/* new key => check for modifier key change */
1612   {
1613     KeyMod new_modifier = KMOD_None;
1614 
1615     switch(key)
1616     {
1617       case KSYM_Shift_L:
1618 	new_modifier = KMOD_Shift_L;
1619 	break;
1620       case KSYM_Shift_R:
1621 	new_modifier = KMOD_Shift_R;
1622 	break;
1623       case KSYM_Control_L:
1624 	new_modifier = KMOD_Control_L;
1625 	break;
1626       case KSYM_Control_R:
1627 	new_modifier = KMOD_Control_R;
1628 	break;
1629       case KSYM_Meta_L:
1630 	new_modifier = KMOD_Meta_L;
1631 	break;
1632       case KSYM_Meta_R:
1633 	new_modifier = KMOD_Meta_R;
1634 	break;
1635       case KSYM_Alt_L:
1636 	new_modifier = KMOD_Alt_L;
1637 	break;
1638       case KSYM_Alt_R:
1639 	new_modifier = KMOD_Alt_R;
1640 	break;
1641       default:
1642 	break;
1643     }
1644 
1645     if (key_status == KEY_PRESSED)
1646       current_modifiers |= new_modifier;
1647     else
1648       current_modifiers &= ~new_modifier;
1649   }
1650 
1651   return current_modifiers;
1652 }
1653 
GetKeyModState()1654 KeyMod GetKeyModState()
1655 {
1656 #if defined(TARGET_SDL)
1657   return (KeyMod)SDL_GetModState();
1658 #else
1659   return HandleKeyModState(KSYM_UNDEFINED, 0);
1660 #endif
1661 }
1662 
GetKeyModStateFromEvents()1663 KeyMod GetKeyModStateFromEvents()
1664 {
1665   /* always use key modifier state as tracked from key events (this is needed
1666      if the modifier key event was injected into the event queue, but the key
1667      was not really pressed on keyboard -- SDL_GetModState() seems to directly
1668      query the keys as held pressed on the keyboard) -- this case is currently
1669      only used to filter out clipboard insert events from "True X-Mouse" tool */
1670 
1671   return HandleKeyModState(KSYM_UNDEFINED, 0);
1672 }
1673 
CheckCloseWindowEvent(ClientMessageEvent * event)1674 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1675 {
1676   if (event->type != EVENT_CLIENTMESSAGE)
1677     return FALSE;
1678 
1679 #if defined(TARGET_SDL)
1680   return TRUE;		/* the only possible message here is SDL_QUIT */
1681 #elif defined(PLATFORM_UNIX)
1682   if ((event->window == window->drawable) &&
1683       (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
1684     return TRUE;
1685 #endif
1686 
1687   return FALSE;
1688 }
1689 
1690 
1691 /* ========================================================================= */
1692 /* joystick functions                                                        */
1693 /* ========================================================================= */
1694 
InitJoysticks()1695 void InitJoysticks()
1696 {
1697   int i;
1698 
1699 #if defined(NO_JOYSTICK)
1700   return;	/* joysticks generally deactivated by compile-time directive */
1701 #endif
1702 
1703   /* always start with reliable default values */
1704   joystick.status = JOYSTICK_NOT_AVAILABLE;
1705   for (i = 0; i < MAX_PLAYERS; i++)
1706     joystick.fd[i] = -1;		/* joystick device closed */
1707 
1708 #if defined(TARGET_SDL)
1709   SDLInitJoysticks();
1710 #elif defined(PLATFORM_UNIX)
1711   UnixInitJoysticks();
1712 #elif defined(PLATFORM_MSDOS)
1713   MSDOSInitJoysticks();
1714 #endif
1715 
1716 #if 0
1717   for (i = 0; i < MAX_PLAYERS; i++)
1718     printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]);
1719 #endif
1720 }
1721 
ReadJoystick(int nr,int * x,int * y,boolean * b1,boolean * b2)1722 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1723 {
1724 #if defined(TARGET_SDL)
1725   return SDLReadJoystick(nr, x, y, b1, b2);
1726 #elif defined(PLATFORM_UNIX)
1727   return UnixReadJoystick(nr, x, y, b1, b2);
1728 #elif defined(PLATFORM_MSDOS)
1729   return MSDOSReadJoystick(nr, x, y, b1, b2);
1730 #endif
1731 }
1732