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