1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
24 #define ENABLE_UNUSED_CODE 0 // currently unused functions
27 // ============================================================================
29 // ============================================================================
31 struct ProgramInfo program;
32 struct NetworkInfo network;
33 struct RuntimeInfo runtime;
34 struct OptionInfo options;
35 struct VideoSystemInfo video;
36 struct AudioSystemInfo audio;
38 struct TileCursorInfo tile_cursor;
39 struct OverlayInfo overlay;
40 struct ArtworkInfo artwork;
41 struct JoystickInfo joystick;
42 struct SetupInfo setup;
45 LevelDirTree *leveldir_first_all = NULL;
46 LevelDirTree *leveldir_first = NULL;
47 LevelDirTree *leveldir_current = NULL;
50 struct LevelSetInfo levelset;
51 struct LevelStats level_stats[MAX_LEVELS];
53 DrawWindow *window = NULL;
54 DrawBuffer *backbuffer = NULL;
55 DrawBuffer *drawto = NULL;
57 int button_status = MB_NOT_PRESSED;
58 boolean motion_status = FALSE;
59 int wheel_steps = DEFAULT_WHEEL_STEPS;
60 boolean keyrepeat_status = TRUE;
61 boolean textinput_status = FALSE;
63 int redraw_mask = REDRAW_NONE;
68 // ============================================================================
69 // init/close functions
70 // ============================================================================
72 void InitProgramInfo(char *argv0, char *config_filename, char *userdata_subdir,
73 char *program_title, char *icon_title,
74 char *icon_filename, char *cookie_prefix,
75 char *program_version_string, int program_version)
77 program.command_basepath = getBasePath(argv0);
78 program.command_basename = getBaseName(argv0);
80 program.config_filename = config_filename;
82 program.userdata_subdir = userdata_subdir;
83 program.userdata_path = getMainUserGameDataDir();
85 program.program_title = program_title;
86 program.window_title = "(undefined)";
87 program.icon_title = icon_title;
89 program.icon_filename = icon_filename;
91 program.cookie_prefix = cookie_prefix;
93 program.version_super = VERSION_SUPER(program_version);
94 program.version_major = VERSION_MAJOR(program_version);
95 program.version_minor = VERSION_MINOR(program_version);
96 program.version_patch = VERSION_PATCH(program_version);
97 program.version_ident = program_version;
99 program.version_string = program_version_string;
101 program.log_filename[LOG_OUT_ID] = getLogFilename(LOG_OUT_BASENAME);
102 program.log_filename[LOG_ERR_ID] = getLogFilename(LOG_ERR_BASENAME);
103 program.log_file[LOG_OUT_ID] = program.log_file_default[LOG_OUT_ID] = stdout;
104 program.log_file[LOG_ERR_ID] = program.log_file_default[LOG_ERR_ID] = stderr;
106 program.headless = FALSE;
108 #if defined(PLATFORM_EMSCRIPTEN)
111 Module.sync_done = 0;
113 FS.mkdir('/persistent'); // create persistent data directory
114 FS.mount(IDBFS, {}, '/persistent'); // mount with IDBFS filesystem type
115 FS.syncfs(true, function(err) // sync persistent data into memory
118 Module.sync_done = 1;
122 // wait for persistent data to be synchronized to memory
123 while (emscripten_run_script_int("Module.sync_done") == 0)
128 void InitNetworkInfo(boolean enabled, boolean connected, boolean serveronly,
129 char *server_host, int server_port)
131 network.enabled = enabled;
132 network.connected = connected;
133 network.serveronly = serveronly;
135 network.server_host = server_host;
136 network.server_port = server_port;
138 network.server_thread = NULL;
139 network.is_server_thread = FALSE;
142 void InitRuntimeInfo()
144 #if defined(HAS_TOUCH_DEVICE)
145 runtime.uses_touch_device = TRUE;
147 runtime.uses_touch_device = FALSE;
151 void InitScoresInfo(void)
153 char *global_scores_dir = getPath2(getCommonDataDir(), SCORES_DIRECTORY);
155 program.global_scores = directoryExists(global_scores_dir);
156 program.many_scores_per_name = !program.global_scores;
161 if (program.global_scores)
163 Debug("internal:path", "Using global, multi-user scores directory '%s'.",
165 Debug("internal:path", "Remove to enable single-user scores directory.");
166 Debug("internal:path", "(This enables multipe score entries per user.)");
170 Debug("internal:path", "Using private, single-user scores directory.");
175 free(global_scores_dir);
178 void SetWindowTitle(void)
180 program.window_title = program.window_title_function();
185 void InitWindowTitleFunction(char *(*window_title_function)(void))
187 program.window_title_function = window_title_function;
190 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
192 program.exit_message_function = exit_message_function;
195 void InitExitFunction(void (*exit_function)(int))
197 program.exit_function = exit_function;
199 // set signal handlers to custom exit function
200 // signal(SIGINT, exit_function);
201 signal(SIGTERM, exit_function);
203 // set exit function to automatically cleanup SDL stuff after exit()
207 void InitPlatformDependentStuff(void)
209 // this is initialized in GetOptions(), but may already be used before
210 options.verbose = TRUE;
214 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
216 if (SDL_Init(sdl_init_flags) < 0)
217 Fail("SDL_Init() failed: %s", SDL_GetError());
222 void ClosePlatformDependentStuff(void)
227 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
228 int real_sx, int real_sy,
229 int full_sxsize, int full_sysize,
230 Bitmap *field_save_buffer)
236 gfx.real_sx = real_sx;
237 gfx.real_sy = real_sy;
238 gfx.full_sxsize = full_sxsize;
239 gfx.full_sysize = full_sysize;
241 gfx.field_save_buffer = field_save_buffer;
243 SetDrawDeactivationMask(REDRAW_NONE); // do not deactivate drawing
244 SetDrawBackgroundMask(REDRAW_NONE); // deactivate masked drawing
247 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
249 gfx.game_tile_size = game_tile_size;
250 gfx.standard_tile_size = standard_tile_size;
253 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
261 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
269 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
277 void InitGfxWindowInfo(int win_xsize, int win_ysize)
279 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
281 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
283 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
285 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
286 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
287 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
288 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
290 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
293 gfx.win_xsize = win_xsize;
294 gfx.win_ysize = win_ysize;
296 gfx.background_bitmap_mask = REDRAW_NONE;
299 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
301 // currently only used by MSDOS code to alloc VRAM buffer, if available
302 // 2009-03-24: also (temporarily?) used for overlapping blit workaround
303 gfx.scrollbuffer_width = scrollbuffer_width;
304 gfx.scrollbuffer_height = scrollbuffer_height;
307 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
309 gfx.clipping_enabled = enabled;
312 gfx.clip_width = width;
313 gfx.clip_height = height;
316 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
318 gfx.draw_busy_anim_function = draw_busy_anim_function;
321 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
323 gfx.draw_global_anim_function = draw_global_anim_function;
326 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
328 gfx.draw_global_border_function = draw_global_border_function;
331 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
333 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
336 void InitGfxCustomArtworkInfo(void)
338 gfx.override_level_graphics = FALSE;
339 gfx.override_level_sounds = FALSE;
340 gfx.override_level_music = FALSE;
342 gfx.draw_init_text = TRUE;
345 void InitGfxOtherSettings(void)
347 gfx.cursor_mode = CURSOR_DEFAULT;
348 gfx.cursor_mode_override = CURSOR_UNDEFINED;
349 gfx.cursor_mode_final = gfx.cursor_mode;
351 // prevent initially displaying custom mouse cursor in upper left corner
352 gfx.mouse_x = POS_OFFSCREEN;
353 gfx.mouse_y = POS_OFFSCREEN;
356 void InitTileCursorInfo(void)
358 tile_cursor.enabled = FALSE;
359 tile_cursor.active = FALSE;
360 tile_cursor.moving = FALSE;
362 tile_cursor.xpos = 0;
363 tile_cursor.ypos = 0;
366 tile_cursor.target_x = 0;
367 tile_cursor.target_y = 0;
372 tile_cursor.xsn_debug = FALSE;
375 void InitOverlayInfo(void)
377 overlay.enabled = FALSE;
378 overlay.active = FALSE;
380 overlay.show_grid = FALSE;
382 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
383 overlay.grid_button_action = JOY_NO_ACTION;
385 SetOverlayGridSizeAndButtons();
387 #if defined(USE_TOUCH_INPUT_OVERLAY)
388 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
389 overlay.enabled = TRUE;
393 void SetOverlayGridSizeAndButtons(void)
395 int nr = GRID_ACTIVE_NR();
398 overlay.grid_xsize = setup.touch.grid_xsize[nr];
399 overlay.grid_ysize = setup.touch.grid_ysize[nr];
401 for (x = 0; x < MAX_GRID_XSIZE; x++)
402 for (y = 0; y < MAX_GRID_YSIZE; y++)
403 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
406 void SetTileCursorEnabled(boolean enabled)
408 tile_cursor.enabled = enabled;
411 void SetTileCursorActive(boolean active)
413 tile_cursor.active = active;
416 void SetTileCursorTargetXY(int x, int y)
418 // delayed placement of tile selection cursor at target position
419 // (tile cursor will be moved to target position step by step)
421 tile_cursor.xpos = x;
422 tile_cursor.ypos = y;
423 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
424 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
426 tile_cursor.moving = TRUE;
429 void SetTileCursorXY(int x, int y)
431 // immediate placement of tile selection cursor at target position
433 SetTileCursorTargetXY(x, y);
435 tile_cursor.x = tile_cursor.target_x;
436 tile_cursor.y = tile_cursor.target_y;
438 tile_cursor.moving = FALSE;
441 void SetTileCursorSXSY(int sx, int sy)
447 void SetOverlayEnabled(boolean enabled)
449 overlay.enabled = enabled;
452 void SetOverlayActive(boolean active)
454 overlay.active = active;
457 void SetOverlayShowGrid(boolean show_grid)
459 overlay.show_grid = show_grid;
461 SetOverlayActive(show_grid);
464 SetOverlayEnabled(TRUE);
467 boolean GetOverlayEnabled(void)
469 return overlay.enabled;
472 boolean GetOverlayActive(void)
474 return overlay.active;
477 void SetDrawDeactivationMask(int draw_deactivation_mask)
479 gfx.draw_deactivation_mask = draw_deactivation_mask;
482 int GetDrawDeactivationMask(void)
484 return gfx.draw_deactivation_mask;
487 void SetDrawBackgroundMask(int draw_background_mask)
489 gfx.draw_background_mask = draw_background_mask;
492 static void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
494 if (background_bitmap_tile != NULL)
495 gfx.background_bitmap_mask |= mask;
497 gfx.background_bitmap_mask &= ~mask;
499 if (background_bitmap_tile == NULL) // empty background requested
502 if (mask == REDRAW_ALL)
503 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
504 0, 0, video.width, video.height);
505 else if (mask == REDRAW_FIELD)
506 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
507 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
508 else if (mask == REDRAW_DOOR_1)
509 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
510 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
513 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
515 // remove every mask before setting mask for window
516 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
517 SetBackgroundBitmap(NULL, 0xffff); // !!! FIX THIS !!!
518 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
521 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
523 // remove window area mask before setting mask for main area
524 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
525 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
526 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
529 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
531 // remove window area mask before setting mask for door area
532 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
533 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
534 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
538 // ============================================================================
540 // ============================================================================
542 static int GetRealDepth(int depth)
544 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
547 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
548 int width, int height, Pixel color)
550 SDLFillRectangle(bitmap, x, y, width, height, color);
552 if (bitmap == backbuffer)
553 SetRedrawMaskFromArea(x, y, width, height);
556 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
557 int src_x, int src_y, int width, int height,
558 int dst_x, int dst_y, int mask_mode)
560 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
561 dst_x, dst_y, mask_mode);
563 if (dst_bitmap == backbuffer)
564 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
567 void LimitScreenUpdates(boolean enable)
569 SDLLimitScreenUpdates(enable);
572 void InitVideoDefaults(void)
574 video.default_depth = 32;
577 void InitVideoDisplay(void)
579 if (program.headless)
582 SDLInitVideoDisplay();
586 void CloseVideoDisplay(void)
588 KeyboardAutoRepeatOn();
590 SDL_QuitSubSystem(SDL_INIT_VIDEO);
593 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
596 video.height = height;
597 video.depth = GetRealDepth(depth);
599 video.screen_width = width;
600 video.screen_height = height;
601 video.screen_xoffset = 0;
602 video.screen_yoffset = 0;
604 video.fullscreen_available = FULLSCREEN_STATUS;
605 video.fullscreen_enabled = FALSE;
607 video.window_scaling_available = WINDOW_SCALING_STATUS;
609 video.frame_counter = 0;
610 video.frame_delay = 0;
611 video.frame_delay_value = GAME_FRAME_DELAY;
613 video.shifted_up = FALSE;
614 video.shifted_up_pos = 0;
615 video.shifted_up_pos_last = 0;
616 video.shifted_up_delay = 0;
617 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
619 SDLInitVideoBuffer(fullscreen);
621 video.initialized = !program.headless;
626 static void FreeBitmapPointers(Bitmap *bitmap)
631 SDLFreeBitmapPointers(bitmap);
633 checked_free(bitmap->source_filename);
634 bitmap->source_filename = NULL;
637 static void TransferBitmapPointers(Bitmap *src_bitmap,
640 if (src_bitmap == NULL || dst_bitmap == NULL)
643 FreeBitmapPointers(dst_bitmap);
645 *dst_bitmap = *src_bitmap;
648 void FreeBitmap(Bitmap *bitmap)
653 FreeBitmapPointers(bitmap);
658 Bitmap *CreateBitmapStruct(void)
660 return checked_calloc(sizeof(Bitmap));
663 Bitmap *CreateBitmap(int width, int height, int depth)
665 Bitmap *new_bitmap = CreateBitmapStruct();
666 int real_width = MAX(1, width); // prevent zero bitmap width
667 int real_height = MAX(1, height); // prevent zero bitmap height
668 int real_depth = GetRealDepth(depth);
670 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
672 new_bitmap->width = real_width;
673 new_bitmap->height = real_height;
678 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
682 // if new bitmap size fits into old one, no need to re-create it
683 if (width <= (*bitmap)->width &&
684 height <= (*bitmap)->height)
687 // else adjust size so that old and new bitmap size fit into it
688 width = MAX(width, (*bitmap)->width);
689 height = MAX(height, (*bitmap)->height);
692 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
696 *bitmap = new_bitmap;
700 TransferBitmapPointers(new_bitmap, *bitmap);
706 static void CloseWindow(DrawWindow *window)
711 void SetRedrawMaskFromArea(int x, int y, int width, int height)
715 int x2 = x + width - 1;
716 int y2 = y + height - 1;
718 if (width == 0 || height == 0)
721 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
722 redraw_mask |= REDRAW_FIELD;
723 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
724 redraw_mask |= REDRAW_DOOR_1;
725 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
726 redraw_mask |= REDRAW_DOOR_2;
727 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
728 redraw_mask |= REDRAW_DOOR_3;
730 redraw_mask = REDRAW_ALL;
733 static boolean CheckDrawingArea(int x, int y, int width, int height,
736 if (draw_mask == REDRAW_NONE)
739 if (draw_mask & REDRAW_ALL)
742 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
745 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
748 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
751 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
757 boolean DrawingDeactivatedField(void)
759 if (program.headless)
762 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
768 boolean DrawingDeactivated(int x, int y, int width, int height)
770 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
773 boolean DrawingOnBackground(int x, int y)
775 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
776 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
779 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
780 int *width, int *height, boolean is_dest)
782 int clip_x, clip_y, clip_width, clip_height;
784 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
786 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
787 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
788 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
789 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
795 clip_width = bitmap->width;
796 clip_height = bitmap->height;
799 // skip if rectangle completely outside bitmap
801 if (*x + *width <= clip_x ||
802 *y + *height <= clip_y ||
803 *x >= clip_x + clip_width ||
804 *y >= clip_y + clip_height)
807 // clip if rectangle overlaps bitmap
811 *width -= clip_x - *x;
814 else if (*x + *width > clip_x + clip_width)
816 *width = clip_x + clip_width - *x;
821 *height -= clip_y - *y;
824 else if (*y + *height > clip_y + clip_height)
826 *height = clip_y + clip_height - *y;
832 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
833 int src_x, int src_y, int width, int height,
834 int dst_x, int dst_y)
836 int dst_x_unclipped = dst_x;
837 int dst_y_unclipped = dst_y;
839 if (program.headless)
842 if (src_bitmap == NULL || dst_bitmap == NULL)
845 if (DrawingDeactivated(dst_x, dst_y, width, height))
848 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
849 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
852 // source x/y might need adjustment if destination x/y was clipped top/left
853 src_x += dst_x - dst_x_unclipped;
854 src_y += dst_y - dst_y_unclipped;
856 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
857 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
858 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
859 but is already fixed in SVN and should therefore finally be fixed with
860 the next official SDL release, which is probably version 1.2.14.) */
861 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
863 if (src_bitmap == dst_bitmap)
865 // needed when blitting directly to same bitmap -- should not be needed with
866 // recent SDL libraries, but apparently does not work in 1.2.11 directly
868 static Bitmap *tmp_bitmap = NULL;
869 static int tmp_bitmap_xsize = 0;
870 static int tmp_bitmap_ysize = 0;
872 // start with largest static bitmaps for initial bitmap size ...
873 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
875 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
876 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
879 // ... and allow for later re-adjustments due to custom artwork bitmaps
880 if (src_bitmap->width > tmp_bitmap_xsize ||
881 src_bitmap->height > tmp_bitmap_ysize)
883 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
884 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
886 FreeBitmap(tmp_bitmap);
891 if (tmp_bitmap == NULL)
892 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
895 sysCopyArea(src_bitmap, tmp_bitmap,
896 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
897 sysCopyArea(tmp_bitmap, dst_bitmap,
898 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
903 sysCopyArea(src_bitmap, dst_bitmap,
904 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
907 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
908 int src_x, int src_y, int src_width, int src_height,
909 int dst_x, int dst_y, int dst_width, int dst_height)
911 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
912 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
913 int dst_xsize = dst_width;
914 int dst_ysize = dst_height;
915 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
916 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
919 for (y = 0; y < src_ysteps; y++)
921 for (x = 0; x < src_xsteps; x++)
923 int draw_x = dst_x + x * src_xsize;
924 int draw_y = dst_y + y * src_ysize;
925 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
926 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
928 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
934 void FadeRectangle(int x, int y, int width, int height,
935 int fade_mode, int fade_delay, int post_delay,
936 void (*draw_border_function)(void))
938 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
939 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
942 SDLFadeRectangle(x, y, width, height,
943 fade_mode, fade_delay, post_delay, draw_border_function);
946 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
949 if (DrawingDeactivated(x, y, width, height))
952 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
955 sysFillRectangle(bitmap, x, y, width, height, color);
958 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
960 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
963 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
964 int width, int height)
966 if (DrawingOnBackground(x, y))
967 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
969 ClearRectangle(bitmap, x, y, width, height);
972 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
973 int src_x, int src_y, int width, int height,
974 int dst_x, int dst_y)
976 if (DrawingDeactivated(dst_x, dst_y, width, height))
979 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
980 dst_x, dst_y, BLIT_MASKED);
983 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
984 int src_x, int src_y, int width, int height,
985 int dst_x, int dst_y)
987 if (DrawingOnBackground(dst_x, dst_y))
990 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
994 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
998 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
1002 void BlitTexture(Bitmap *bitmap,
1003 int src_x, int src_y, int width, int height,
1004 int dst_x, int dst_y)
1009 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
1013 void BlitTextureMasked(Bitmap *bitmap,
1014 int src_x, int src_y, int width, int height,
1015 int dst_x, int dst_y)
1020 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
1024 void BlitToScreen(Bitmap *bitmap,
1025 int src_x, int src_y, int width, int height,
1026 int dst_x, int dst_y)
1031 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1032 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1033 width, height, dst_x, dst_y);
1035 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1038 void BlitToScreenMasked(Bitmap *bitmap,
1039 int src_x, int src_y, int width, int height,
1040 int dst_x, int dst_y)
1045 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1046 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1047 width, height, dst_x, dst_y);
1049 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1052 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1055 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1058 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1061 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1064 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1065 int to_x, int to_y, Pixel pixel, int line_width)
1069 if (program.headless)
1072 for (x = 0; x < line_width; x++)
1074 for (y = 0; y < line_width; y++)
1076 int dx = x - line_width / 2;
1077 int dy = y - line_width / 2;
1079 if ((x == 0 && y == 0) ||
1080 (x == 0 && y == line_width - 1) ||
1081 (x == line_width - 1 && y == 0) ||
1082 (x == line_width - 1 && y == line_width - 1))
1086 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1091 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1096 for (i = 0; i < num_points - 1; i++)
1097 DrawLine(bitmap, points[i].x, points[i].y,
1098 points[i + 1].x, points[i + 1].y, pixel, line_width);
1101 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1105 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1107 if (program.headless)
1110 if (x < 0 || x >= bitmap->width ||
1111 y < 0 || y >= bitmap->height)
1114 return SDLGetPixel(bitmap, x, y);
1117 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1118 unsigned int color_g, unsigned int color_b)
1120 if (program.headless)
1123 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1126 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1128 unsigned int color_r = (color >> 16) & 0xff;
1129 unsigned int color_g = (color >> 8) & 0xff;
1130 unsigned int color_b = (color >> 0) & 0xff;
1132 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1135 void KeyboardAutoRepeatOn(void)
1137 keyrepeat_status = TRUE;
1140 void KeyboardAutoRepeatOff(void)
1142 keyrepeat_status = FALSE;
1145 boolean SetVideoMode(boolean fullscreen)
1147 return SDLSetVideoMode(fullscreen);
1150 void SetVideoFrameDelay(unsigned int frame_delay_value)
1152 video.frame_delay_value = frame_delay_value;
1155 unsigned int GetVideoFrameDelay(void)
1157 return video.frame_delay_value;
1160 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1162 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1163 (!fullscreen && video.fullscreen_enabled))
1164 fullscreen = SetVideoMode(fullscreen);
1169 Bitmap *LoadImage(char *filename)
1173 new_bitmap = SDLLoadImage(filename);
1176 new_bitmap->source_filename = getStringCopy(filename);
1181 Bitmap *LoadCustomImage(char *basename)
1183 char *filename = getCustomImageFilename(basename);
1186 if (filename == NULL)
1187 Fail("LoadCustomImage(): cannot find file '%s'", basename);
1189 if ((new_bitmap = LoadImage(filename)) == NULL)
1190 Fail("LoadImage('%s') failed", basename);
1195 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1197 char *filename = getCustomImageFilename(basename);
1200 if (filename == NULL) // (should never happen)
1202 Warn("ReloadCustomImage(): cannot find file '%s'", basename);
1207 if (strEqual(filename, bitmap->source_filename))
1209 // The old and new image are the same (have the same filename and path).
1210 // This usually means that this image does not exist in this graphic set
1211 // and a fallback to the existing image is done.
1216 if ((new_bitmap = LoadImage(filename)) == NULL)
1218 Warn("LoadImage('%s') failed", basename);
1223 if (bitmap->width != new_bitmap->width ||
1224 bitmap->height != new_bitmap->height)
1226 Warn("ReloadCustomImage: new image '%s' has wrong dimensions",
1229 FreeBitmap(new_bitmap);
1234 TransferBitmapPointers(new_bitmap, bitmap);
1238 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1240 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1243 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1245 if (bitmaps[IMG_BITMAP_CUSTOM])
1247 // check if original sized bitmap points to custom sized bitmap
1248 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] == bitmaps[IMG_BITMAP_CUSTOM])
1250 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1252 // keep pointer of previous custom size bitmap
1253 bitmaps[IMG_BITMAP_OTHER] = bitmaps[IMG_BITMAP_CUSTOM];
1255 // set original bitmap pointer to scaled original bitmap of other size
1256 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1258 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1262 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1265 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1268 if (gfx.game_tile_size == gfx.standard_tile_size)
1270 // set game bitmap pointer to standard sized bitmap (already existing)
1271 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1276 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1277 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1278 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1280 bitmaps[IMG_BITMAP_CUSTOM] = ZoomBitmap(bitmap, width, height);
1282 // set game bitmap pointer to custom sized bitmap (newly created)
1283 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1286 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1287 int tile_size, boolean create_small_bitmaps)
1289 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1290 Bitmap *tmp_bitmap_final = NULL;
1291 Bitmap *tmp_bitmap_0 = NULL;
1292 Bitmap *tmp_bitmap_1 = NULL;
1293 Bitmap *tmp_bitmap_2 = NULL;
1294 Bitmap *tmp_bitmap_4 = NULL;
1295 Bitmap *tmp_bitmap_8 = NULL;
1296 Bitmap *tmp_bitmap_16 = NULL;
1297 Bitmap *tmp_bitmap_32 = NULL;
1298 int width_final, height_final;
1299 int width_0, height_0;
1300 int width_1, height_1;
1301 int width_2, height_2;
1302 int width_4, height_4;
1303 int width_8, height_8;
1304 int width_16, height_16;
1305 int width_32, height_32;
1306 int old_width, old_height;
1309 print_timestamp_init("CreateScaledBitmaps");
1311 old_width = old_bitmap->width;
1312 old_height = old_bitmap->height;
1314 // calculate new image dimensions for final image size
1315 width_final = old_width * zoom_factor;
1316 height_final = old_height * zoom_factor;
1318 // get image with final size (this might require scaling up)
1319 // ("final" size may result in non-standard tile size image)
1320 if (zoom_factor != 1)
1321 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1323 tmp_bitmap_final = old_bitmap;
1325 UPDATE_BUSY_STATE();
1327 width_0 = width_1 = width_final;
1328 height_0 = height_1 = height_final;
1330 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1332 if (create_small_bitmaps)
1334 // check if we have a non-gameplay tile size image
1335 if (tile_size != gfx.game_tile_size)
1337 // get image with gameplay tile size
1338 width_0 = width_final * gfx.game_tile_size / tile_size;
1339 height_0 = height_final * gfx.game_tile_size / tile_size;
1341 if (width_0 == old_width)
1342 tmp_bitmap_0 = old_bitmap;
1343 else if (width_0 == width_final)
1344 tmp_bitmap_0 = tmp_bitmap_final;
1346 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1348 UPDATE_BUSY_STATE();
1351 // check if we have a non-standard tile size image
1352 if (tile_size != gfx.standard_tile_size)
1354 // get image with standard tile size
1355 width_1 = width_final * gfx.standard_tile_size / tile_size;
1356 height_1 = height_final * gfx.standard_tile_size / tile_size;
1358 if (width_1 == old_width)
1359 tmp_bitmap_1 = old_bitmap;
1360 else if (width_1 == width_final)
1361 tmp_bitmap_1 = tmp_bitmap_final;
1362 else if (width_1 == width_0)
1363 tmp_bitmap_1 = tmp_bitmap_0;
1365 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1367 UPDATE_BUSY_STATE();
1370 // calculate new image dimensions for small images
1371 width_2 = width_1 / 2;
1372 height_2 = height_1 / 2;
1373 width_4 = width_1 / 4;
1374 height_4 = height_1 / 4;
1375 width_8 = width_1 / 8;
1376 height_8 = height_1 / 8;
1377 width_16 = width_1 / 16;
1378 height_16 = height_1 / 16;
1379 width_32 = width_1 / 32;
1380 height_32 = height_1 / 32;
1382 // get image with 1/2 of normal size (for use in the level editor)
1383 if (width_2 == old_width)
1384 tmp_bitmap_2 = old_bitmap;
1386 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1388 UPDATE_BUSY_STATE();
1390 // get image with 1/4 of normal size (for use in the level editor)
1391 if (width_4 == old_width)
1392 tmp_bitmap_4 = old_bitmap;
1394 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1396 UPDATE_BUSY_STATE();
1398 // get image with 1/8 of normal size (for use on the preview screen)
1399 if (width_8 == old_width)
1400 tmp_bitmap_8 = old_bitmap;
1402 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1404 UPDATE_BUSY_STATE();
1406 // get image with 1/16 of normal size (for use on the preview screen)
1407 if (width_16 == old_width)
1408 tmp_bitmap_16 = old_bitmap;
1410 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1412 UPDATE_BUSY_STATE();
1414 // get image with 1/32 of normal size (for use on the preview screen)
1415 if (width_32 == old_width)
1416 tmp_bitmap_32 = old_bitmap;
1418 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1420 UPDATE_BUSY_STATE();
1422 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1423 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1424 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1425 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1426 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1427 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1429 if (width_0 != width_1)
1430 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1432 if (bitmaps[IMG_BITMAP_CUSTOM])
1433 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1435 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1437 // store the "final" (up-scaled) original bitmap, if not already stored
1439 int tmp_bitmap_final_nr = -1;
1441 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1442 if (bitmaps[i] == tmp_bitmap_final)
1443 tmp_bitmap_final_nr = i;
1445 if (tmp_bitmap_final_nr == -1) // scaled original bitmap not stored
1447 // store pointer of scaled original bitmap (not used for any other size)
1448 bitmaps[IMG_BITMAP_OTHER] = tmp_bitmap_final;
1450 // set original bitmap pointer to scaled original bitmap of other size
1451 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1455 // set original bitmap pointer to corresponding sized bitmap
1456 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[tmp_bitmap_final_nr];
1459 // free the "old" (unscaled) original bitmap, if not already stored
1461 boolean free_old_bitmap = TRUE;
1463 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1464 if (bitmaps[i] == old_bitmap)
1465 free_old_bitmap = FALSE;
1467 if (free_old_bitmap)
1469 // copy image filename from old to new standard sized bitmap
1470 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1471 getStringCopy(old_bitmap->source_filename);
1473 FreeBitmap(old_bitmap);
1478 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1480 // set original bitmap pointer to corresponding sized bitmap
1481 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_32x32];
1483 if (old_bitmap != tmp_bitmap_1)
1484 FreeBitmap(old_bitmap);
1487 UPDATE_BUSY_STATE();
1489 print_timestamp_done("CreateScaledBitmaps");
1492 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1495 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1498 void CreateBitmapTextures(Bitmap **bitmaps)
1500 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1501 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1503 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1506 void FreeBitmapTextures(Bitmap **bitmaps)
1508 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1509 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1511 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1514 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1516 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1520 // ----------------------------------------------------------------------------
1521 // mouse pointer functions
1522 // ----------------------------------------------------------------------------
1524 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1526 // XPM image definitions
1527 static const char *cursor_image_none[] =
1529 // width height num_colors chars_per_pixel
1559 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1560 static const char *cursor_image_dot[] =
1562 // width height num_colors chars_per_pixel
1591 static const char **cursor_image_playfield = cursor_image_dot;
1593 // some people complained about a "white dot" on the screen and thought it
1594 // was a graphical error... OK, let's just remove the whole pointer :-)
1595 static const char **cursor_image_playfield = cursor_image_none;
1598 static const int cursor_bit_order = BIT_ORDER_MSB;
1600 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1602 struct MouseCursorInfo *cursor;
1603 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1604 int header_lines = 4;
1607 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1609 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1612 for (y = 0; y < cursor->width; y++)
1614 for (x = 0; x < cursor->height; x++)
1617 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1622 cursor->data[i] = cursor->mask[i] = 0;
1625 switch (image[header_lines + y][x])
1628 cursor->data[i] |= bit_mask;
1629 cursor->mask[i] |= bit_mask;
1633 cursor->mask[i] |= bit_mask;
1642 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1647 void SetMouseCursor(int mode)
1649 static struct MouseCursorInfo *cursor_none = NULL;
1650 static struct MouseCursorInfo *cursor_playfield = NULL;
1651 struct MouseCursorInfo *cursor_new;
1652 int mode_final = mode;
1654 if (cursor_none == NULL)
1655 cursor_none = get_cursor_from_image(cursor_image_none);
1657 if (cursor_playfield == NULL)
1658 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1660 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1661 mode_final = gfx.cursor_mode_override;
1663 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1664 mode_final == CURSOR_NONE ? cursor_none :
1665 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1667 SDLSetMouseCursor(cursor_new);
1669 gfx.cursor_mode = mode;
1670 gfx.cursor_mode_final = mode_final;
1673 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1675 // mouse events do not contain logical screen size corrections yet
1676 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1678 mouse_x -= video.screen_xoffset;
1679 mouse_y -= video.screen_yoffset;
1681 gfx.mouse_x = mouse_x;
1682 gfx.mouse_y = mouse_y;
1685 void UpdateMousePosition(void)
1687 int mouse_x, mouse_y;
1690 SDL_GetMouseState(&mouse_x, &mouse_y);
1692 UpdateRawMousePosition(mouse_x, mouse_y);
1696 // ============================================================================
1698 // ============================================================================
1700 void OpenAudio(void)
1702 // always start with reliable default values
1703 audio.sound_available = FALSE;
1704 audio.music_available = FALSE;
1705 audio.loops_available = FALSE;
1707 audio.sound_enabled = FALSE;
1708 audio.sound_deactivated = FALSE;
1710 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1711 audio.mixer_pid = 0;
1712 audio.device_name = NULL;
1713 audio.device_fd = -1;
1715 audio.num_channels = 0;
1716 audio.music_channel = 0;
1717 audio.first_sound_channel = 0;
1722 void CloseAudio(void)
1726 audio.sound_enabled = FALSE;
1729 void SetAudioMode(boolean enabled)
1731 if (!audio.sound_available)
1734 audio.sound_enabled = enabled;
1738 // ============================================================================
1740 // ============================================================================
1742 void InitEventFilter(EventFilter filter_function)
1744 SDL_SetEventFilter(filter_function, NULL);
1747 boolean PendingEvent(void)
1749 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1752 void WaitEvent(Event *event)
1754 SDLWaitEvent(event);
1757 void PeekEvent(Event *event)
1759 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1762 void PumpEvents(void)
1767 void CheckQuitEvent(void)
1769 if (SDL_QuitRequested())
1770 program.exit_function(0);
1773 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1775 // key up/down events in SDL2 do not return text characters anymore
1776 return event->keysym.sym;
1779 KeyMod HandleKeyModState(Key key, int key_status)
1781 static KeyMod current_modifiers = KMOD_None;
1783 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1785 KeyMod new_modifier = KMOD_None;
1790 new_modifier = KMOD_Shift_L;
1793 new_modifier = KMOD_Shift_R;
1795 case KSYM_Control_L:
1796 new_modifier = KMOD_Control_L;
1798 case KSYM_Control_R:
1799 new_modifier = KMOD_Control_R;
1802 new_modifier = KMOD_Meta_L;
1805 new_modifier = KMOD_Meta_R;
1808 new_modifier = KMOD_Alt_L;
1811 new_modifier = KMOD_Alt_R;
1817 if (key_status == KEY_PRESSED)
1818 current_modifiers |= new_modifier;
1820 current_modifiers &= ~new_modifier;
1823 return current_modifiers;
1826 KeyMod GetKeyModState(void)
1828 return (KeyMod)SDL_GetModState();
1831 KeyMod GetKeyModStateFromEvents(void)
1833 /* always use key modifier state as tracked from key events (this is needed
1834 if the modifier key event was injected into the event queue, but the key
1835 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1836 query the keys as held pressed on the keyboard) -- this case is currently
1837 only used to filter out clipboard insert events from "True X-Mouse" tool */
1839 return HandleKeyModState(KSYM_UNDEFINED, 0);
1842 void StartTextInput(int x, int y, int width, int height)
1844 textinput_status = TRUE;
1846 #if defined(HAS_SCREEN_KEYBOARD)
1847 SDL_StartTextInput();
1849 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1851 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1852 video.shifted_up_delay = SDL_GetTicks();
1853 video.shifted_up = TRUE;
1858 void StopTextInput(void)
1860 textinput_status = FALSE;
1862 #if defined(HAS_SCREEN_KEYBOARD)
1863 SDL_StopTextInput();
1865 if (video.shifted_up)
1867 video.shifted_up_pos = 0;
1868 video.shifted_up_delay = SDL_GetTicks();
1869 video.shifted_up = FALSE;
1874 void PushUserEvent(int code, int value1, int value2)
1878 SDL_memset(&event, 0, sizeof(event));
1880 event.type = EVENT_USER;
1882 event.value1 = value1;
1883 event.value2 = value2;
1885 SDL_PushEvent((SDL_Event *)&event);
1889 // ============================================================================
1890 // joystick functions
1891 // ============================================================================
1893 void InitJoysticks(void)
1897 #if defined(NO_JOYSTICK)
1898 return; // joysticks generally deactivated by compile-time directive
1901 // always start with reliable default values
1902 joystick.status = JOYSTICK_NOT_AVAILABLE;
1903 for (i = 0; i < MAX_PLAYERS; i++)
1904 joystick.nr[i] = -1; // no joystick configured
1909 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1911 return SDLReadJoystick(nr, x, y, b1, b2);
1914 boolean CheckJoystickOpened(int nr)
1916 return SDLCheckJoystickOpened(nr);
1919 void ClearJoystickState(void)
1921 SDLClearJoystickState();