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 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1275 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1276 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1277 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1279 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1281 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1282 bitmaps[IMG_BITMAP_PTR_GAME] = bitmap_new;
1285 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1286 int tile_size, boolean create_small_bitmaps)
1288 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1289 Bitmap *tmp_bitmap_final = NULL;
1290 Bitmap *tmp_bitmap_0 = NULL;
1291 Bitmap *tmp_bitmap_1 = NULL;
1292 Bitmap *tmp_bitmap_2 = NULL;
1293 Bitmap *tmp_bitmap_4 = NULL;
1294 Bitmap *tmp_bitmap_8 = NULL;
1295 Bitmap *tmp_bitmap_16 = NULL;
1296 Bitmap *tmp_bitmap_32 = NULL;
1297 int width_final, height_final;
1298 int width_0, height_0;
1299 int width_1, height_1;
1300 int width_2, height_2;
1301 int width_4, height_4;
1302 int width_8, height_8;
1303 int width_16, height_16;
1304 int width_32, height_32;
1305 int old_width, old_height;
1308 print_timestamp_init("CreateScaledBitmaps");
1310 old_width = old_bitmap->width;
1311 old_height = old_bitmap->height;
1313 // calculate new image dimensions for final image size
1314 width_final = old_width * zoom_factor;
1315 height_final = old_height * zoom_factor;
1317 // get image with final size (this might require scaling up)
1318 // ("final" size may result in non-standard tile size image)
1319 if (zoom_factor != 1)
1320 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1322 tmp_bitmap_final = old_bitmap;
1324 UPDATE_BUSY_STATE();
1326 width_0 = width_1 = width_final;
1327 height_0 = height_1 = height_final;
1329 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1331 if (create_small_bitmaps)
1333 // check if we have a non-gameplay tile size image
1334 if (tile_size != gfx.game_tile_size)
1336 // get image with gameplay tile size
1337 width_0 = width_final * gfx.game_tile_size / tile_size;
1338 height_0 = height_final * gfx.game_tile_size / tile_size;
1340 if (width_0 == old_width)
1341 tmp_bitmap_0 = old_bitmap;
1342 else if (width_0 == width_final)
1343 tmp_bitmap_0 = tmp_bitmap_final;
1345 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1347 UPDATE_BUSY_STATE();
1350 // check if we have a non-standard tile size image
1351 if (tile_size != gfx.standard_tile_size)
1353 // get image with standard tile size
1354 width_1 = width_final * gfx.standard_tile_size / tile_size;
1355 height_1 = height_final * gfx.standard_tile_size / tile_size;
1357 if (width_1 == old_width)
1358 tmp_bitmap_1 = old_bitmap;
1359 else if (width_1 == width_final)
1360 tmp_bitmap_1 = tmp_bitmap_final;
1361 else if (width_1 == width_0)
1362 tmp_bitmap_1 = tmp_bitmap_0;
1364 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1366 UPDATE_BUSY_STATE();
1369 // calculate new image dimensions for small images
1370 width_2 = width_1 / 2;
1371 height_2 = height_1 / 2;
1372 width_4 = width_1 / 4;
1373 height_4 = height_1 / 4;
1374 width_8 = width_1 / 8;
1375 height_8 = height_1 / 8;
1376 width_16 = width_1 / 16;
1377 height_16 = height_1 / 16;
1378 width_32 = width_1 / 32;
1379 height_32 = height_1 / 32;
1381 // get image with 1/2 of normal size (for use in the level editor)
1382 if (width_2 == old_width)
1383 tmp_bitmap_2 = old_bitmap;
1385 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1387 UPDATE_BUSY_STATE();
1389 // get image with 1/4 of normal size (for use in the level editor)
1390 if (width_4 == old_width)
1391 tmp_bitmap_4 = old_bitmap;
1393 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1395 UPDATE_BUSY_STATE();
1397 // get image with 1/8 of normal size (for use on the preview screen)
1398 if (width_8 == old_width)
1399 tmp_bitmap_8 = old_bitmap;
1401 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1403 UPDATE_BUSY_STATE();
1405 // get image with 1/16 of normal size (for use on the preview screen)
1406 if (width_16 == old_width)
1407 tmp_bitmap_16 = old_bitmap;
1409 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1411 UPDATE_BUSY_STATE();
1413 // get image with 1/32 of normal size (for use on the preview screen)
1414 if (width_32 == old_width)
1415 tmp_bitmap_32 = old_bitmap;
1417 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1419 UPDATE_BUSY_STATE();
1421 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1422 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1423 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1424 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1425 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1426 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1428 if (width_0 != width_1)
1429 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1431 if (bitmaps[IMG_BITMAP_CUSTOM])
1432 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1434 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1436 // store the "final" (up-scaled) original bitmap, if not already stored
1438 int tmp_bitmap_final_nr = -1;
1440 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1441 if (bitmaps[i] == tmp_bitmap_final)
1442 tmp_bitmap_final_nr = i;
1444 if (tmp_bitmap_final_nr == -1) // scaled original bitmap not stored
1446 // store pointer of scaled original bitmap (not used for any other size)
1447 bitmaps[IMG_BITMAP_OTHER] = tmp_bitmap_final;
1449 // set original bitmap pointer to scaled original bitmap of other size
1450 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1454 // set original bitmap pointer to corresponding sized bitmap
1455 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[tmp_bitmap_final_nr];
1458 // free the "old" (unscaled) original bitmap, if not already stored
1460 boolean free_old_bitmap = TRUE;
1462 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1463 if (bitmaps[i] == old_bitmap)
1464 free_old_bitmap = FALSE;
1466 if (free_old_bitmap)
1468 // copy image filename from old to new standard sized bitmap
1469 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1470 getStringCopy(old_bitmap->source_filename);
1472 FreeBitmap(old_bitmap);
1477 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1479 // set original bitmap pointer to corresponding sized bitmap
1480 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_32x32];
1483 UPDATE_BUSY_STATE();
1485 print_timestamp_done("CreateScaledBitmaps");
1488 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1491 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1494 void CreateBitmapTextures(Bitmap **bitmaps)
1496 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1497 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1499 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1502 void FreeBitmapTextures(Bitmap **bitmaps)
1504 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1505 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1507 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1510 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1512 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1516 // ----------------------------------------------------------------------------
1517 // mouse pointer functions
1518 // ----------------------------------------------------------------------------
1520 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1522 // XPM image definitions
1523 static const char *cursor_image_none[] =
1525 // width height num_colors chars_per_pixel
1555 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1556 static const char *cursor_image_dot[] =
1558 // width height num_colors chars_per_pixel
1587 static const char **cursor_image_playfield = cursor_image_dot;
1589 // some people complained about a "white dot" on the screen and thought it
1590 // was a graphical error... OK, let's just remove the whole pointer :-)
1591 static const char **cursor_image_playfield = cursor_image_none;
1594 static const int cursor_bit_order = BIT_ORDER_MSB;
1596 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1598 struct MouseCursorInfo *cursor;
1599 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1600 int header_lines = 4;
1603 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1605 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1608 for (y = 0; y < cursor->width; y++)
1610 for (x = 0; x < cursor->height; x++)
1613 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1618 cursor->data[i] = cursor->mask[i] = 0;
1621 switch (image[header_lines + y][x])
1624 cursor->data[i] |= bit_mask;
1625 cursor->mask[i] |= bit_mask;
1629 cursor->mask[i] |= bit_mask;
1638 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1643 void SetMouseCursor(int mode)
1645 static struct MouseCursorInfo *cursor_none = NULL;
1646 static struct MouseCursorInfo *cursor_playfield = NULL;
1647 struct MouseCursorInfo *cursor_new;
1648 int mode_final = mode;
1650 if (cursor_none == NULL)
1651 cursor_none = get_cursor_from_image(cursor_image_none);
1653 if (cursor_playfield == NULL)
1654 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1656 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1657 mode_final = gfx.cursor_mode_override;
1659 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1660 mode_final == CURSOR_NONE ? cursor_none :
1661 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1663 SDLSetMouseCursor(cursor_new);
1665 gfx.cursor_mode = mode;
1666 gfx.cursor_mode_final = mode_final;
1669 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1671 // mouse events do not contain logical screen size corrections yet
1672 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1674 mouse_x -= video.screen_xoffset;
1675 mouse_y -= video.screen_yoffset;
1677 gfx.mouse_x = mouse_x;
1678 gfx.mouse_y = mouse_y;
1681 void UpdateMousePosition(void)
1683 int mouse_x, mouse_y;
1686 SDL_GetMouseState(&mouse_x, &mouse_y);
1688 UpdateRawMousePosition(mouse_x, mouse_y);
1692 // ============================================================================
1694 // ============================================================================
1696 void OpenAudio(void)
1698 // always start with reliable default values
1699 audio.sound_available = FALSE;
1700 audio.music_available = FALSE;
1701 audio.loops_available = FALSE;
1703 audio.sound_enabled = FALSE;
1704 audio.sound_deactivated = FALSE;
1706 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1707 audio.mixer_pid = 0;
1708 audio.device_name = NULL;
1709 audio.device_fd = -1;
1711 audio.num_channels = 0;
1712 audio.music_channel = 0;
1713 audio.first_sound_channel = 0;
1718 void CloseAudio(void)
1722 audio.sound_enabled = FALSE;
1725 void SetAudioMode(boolean enabled)
1727 if (!audio.sound_available)
1730 audio.sound_enabled = enabled;
1734 // ============================================================================
1736 // ============================================================================
1738 void InitEventFilter(EventFilter filter_function)
1740 SDL_SetEventFilter(filter_function, NULL);
1743 boolean PendingEvent(void)
1745 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1748 void WaitEvent(Event *event)
1750 SDLWaitEvent(event);
1753 void PeekEvent(Event *event)
1755 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1758 void PumpEvents(void)
1763 void CheckQuitEvent(void)
1765 if (SDL_QuitRequested())
1766 program.exit_function(0);
1769 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1771 // key up/down events in SDL2 do not return text characters anymore
1772 return event->keysym.sym;
1775 KeyMod HandleKeyModState(Key key, int key_status)
1777 static KeyMod current_modifiers = KMOD_None;
1779 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1781 KeyMod new_modifier = KMOD_None;
1786 new_modifier = KMOD_Shift_L;
1789 new_modifier = KMOD_Shift_R;
1791 case KSYM_Control_L:
1792 new_modifier = KMOD_Control_L;
1794 case KSYM_Control_R:
1795 new_modifier = KMOD_Control_R;
1798 new_modifier = KMOD_Meta_L;
1801 new_modifier = KMOD_Meta_R;
1804 new_modifier = KMOD_Alt_L;
1807 new_modifier = KMOD_Alt_R;
1813 if (key_status == KEY_PRESSED)
1814 current_modifiers |= new_modifier;
1816 current_modifiers &= ~new_modifier;
1819 return current_modifiers;
1822 KeyMod GetKeyModState(void)
1824 return (KeyMod)SDL_GetModState();
1827 KeyMod GetKeyModStateFromEvents(void)
1829 /* always use key modifier state as tracked from key events (this is needed
1830 if the modifier key event was injected into the event queue, but the key
1831 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1832 query the keys as held pressed on the keyboard) -- this case is currently
1833 only used to filter out clipboard insert events from "True X-Mouse" tool */
1835 return HandleKeyModState(KSYM_UNDEFINED, 0);
1838 void StartTextInput(int x, int y, int width, int height)
1840 textinput_status = TRUE;
1842 #if defined(HAS_SCREEN_KEYBOARD)
1843 SDL_StartTextInput();
1845 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1847 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1848 video.shifted_up_delay = SDL_GetTicks();
1849 video.shifted_up = TRUE;
1854 void StopTextInput(void)
1856 textinput_status = FALSE;
1858 #if defined(HAS_SCREEN_KEYBOARD)
1859 SDL_StopTextInput();
1861 if (video.shifted_up)
1863 video.shifted_up_pos = 0;
1864 video.shifted_up_delay = SDL_GetTicks();
1865 video.shifted_up = FALSE;
1870 void PushUserEvent(int code, int value1, int value2)
1874 SDL_memset(&event, 0, sizeof(event));
1876 event.type = EVENT_USER;
1878 event.value1 = value1;
1879 event.value2 = value2;
1881 SDL_PushEvent((SDL_Event *)&event);
1885 // ============================================================================
1886 // joystick functions
1887 // ============================================================================
1889 void InitJoysticks(void)
1893 #if defined(NO_JOYSTICK)
1894 return; // joysticks generally deactivated by compile-time directive
1897 // always start with reliable default values
1898 joystick.status = JOYSTICK_NOT_AVAILABLE;
1899 for (i = 0; i < MAX_PLAYERS; i++)
1900 joystick.nr[i] = -1; // no joystick configured
1905 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1907 return SDLReadJoystick(nr, x, y, b1, b2);
1910 boolean CheckJoystickOpened(int nr)
1912 return SDLCheckJoystickOpened(nr);
1915 void ClearJoystickState(void)
1917 SDLClearJoystickState();