1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
24 #define ENABLE_UNUSED_CODE 0 /* currently unused functions */
27 /* ========================================================================= */
28 /* exported variables */
29 /* ========================================================================= */
31 struct ProgramInfo program;
32 struct NetworkInfo network;
33 struct OptionInfo options;
34 struct VideoSystemInfo video;
35 struct AudioSystemInfo audio;
37 struct TileCursorInfo tile_cursor;
38 struct OverlayInfo overlay;
39 struct ArtworkInfo artwork;
40 struct JoystickInfo joystick;
41 struct SetupInfo setup;
43 LevelDirTree *leveldir_first_all = NULL;
44 LevelDirTree *leveldir_first = NULL;
45 LevelDirTree *leveldir_current = NULL;
48 struct LevelStats level_stats[MAX_LEVELS];
50 DrawWindow *window = NULL;
51 DrawBuffer *backbuffer = NULL;
52 DrawBuffer *drawto = NULL;
54 int button_status = MB_NOT_PRESSED;
55 boolean motion_status = FALSE;
56 int wheel_steps = DEFAULT_WHEEL_STEPS;
57 #if defined(TARGET_SDL2)
58 boolean keyrepeat_status = TRUE;
61 int redraw_mask = REDRAW_NONE;
66 /* ========================================================================= */
67 /* init/close functions */
68 /* ========================================================================= */
70 void InitProgramInfo(char *argv0, char *config_filename, char *userdata_subdir,
71 char *program_title, char *icon_title,
72 char *icon_filename, char *cookie_prefix,
73 char *program_version_string, int program_version)
75 program.command_basepath = getBasePath(argv0);
76 program.command_basename = getBaseName(argv0);
78 program.config_filename = config_filename;
80 program.userdata_subdir = userdata_subdir;
81 program.userdata_path = getUserGameDataDir();
83 program.program_title = program_title;
84 program.window_title = "(undefined)";
85 program.icon_title = icon_title;
87 program.icon_filename = icon_filename;
89 program.cookie_prefix = cookie_prefix;
91 program.version_super = VERSION_SUPER(program_version);
92 program.version_major = VERSION_MAJOR(program_version);
93 program.version_minor = VERSION_MINOR(program_version);
94 program.version_patch = VERSION_PATCH(program_version);
95 program.version_ident = program_version;
97 program.version_string = program_version_string;
99 program.log_filename[LOG_OUT_ID] = getLogFilename(LOG_OUT_BASENAME);
100 program.log_filename[LOG_ERR_ID] = getLogFilename(LOG_ERR_BASENAME);
101 program.log_file[LOG_OUT_ID] = program.log_file_default[LOG_OUT_ID] = stdout;
102 program.log_file[LOG_ERR_ID] = program.log_file_default[LOG_ERR_ID] = stderr;
104 program.headless = FALSE;
107 void InitNetworkInfo(boolean enabled, boolean connected, boolean serveronly,
108 char *server_host, int server_port)
110 network.enabled = enabled;
111 network.connected = connected;
112 network.serveronly = serveronly;
114 network.server_host = server_host;
115 network.server_port = server_port;
118 void InitScoresInfo()
120 char *global_scores_dir = getPath2(getCommonDataDir(), SCORES_DIRECTORY);
122 program.global_scores = directoryExists(global_scores_dir);
123 program.many_scores_per_name = !program.global_scores;
127 if (program.global_scores)
129 Error(ERR_DEBUG, "Using global, multi-user scores directory '%s'.",
131 Error(ERR_DEBUG, "Remove to enable single-user scores directory.");
132 Error(ERR_DEBUG, "(This enables multipe score entries per user.)");
136 Error(ERR_DEBUG, "Using private, single-user scores directory.");
140 free(global_scores_dir);
143 void SetWindowTitle()
145 program.window_title = program.window_title_function();
150 void InitWindowTitleFunction(char *(*window_title_function)(void))
152 program.window_title_function = window_title_function;
155 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
157 program.exit_message_function = exit_message_function;
160 void InitExitFunction(void (*exit_function)(int))
162 program.exit_function = exit_function;
164 /* set signal handlers to custom exit function */
165 // signal(SIGINT, exit_function);
166 signal(SIGTERM, exit_function);
168 /* set exit function to automatically cleanup SDL stuff after exit() */
172 void InitPlatformDependentStuff(void)
174 // this is initialized in GetOptions(), but may already be used before
175 options.verbose = TRUE;
179 #if defined(TARGET_SDL2)
180 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
182 int sdl_init_flags = SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE;
185 if (SDL_Init(sdl_init_flags) < 0)
186 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
191 void ClosePlatformDependentStuff(void)
196 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
197 int real_sx, int real_sy,
198 int full_sxsize, int full_sysize,
199 Bitmap *field_save_buffer)
205 gfx.real_sx = real_sx;
206 gfx.real_sy = real_sy;
207 gfx.full_sxsize = full_sxsize;
208 gfx.full_sysize = full_sysize;
210 gfx.field_save_buffer = field_save_buffer;
212 SetDrawDeactivationMask(REDRAW_NONE); /* do not deactivate drawing */
213 SetDrawBackgroundMask(REDRAW_NONE); /* deactivate masked drawing */
216 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
218 gfx.game_tile_size = game_tile_size;
219 gfx.standard_tile_size = standard_tile_size;
222 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
230 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
238 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
246 void InitGfxWindowInfo(int win_xsize, int win_ysize)
248 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
250 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
252 #if defined(TARGET_SDL2)
253 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
256 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
257 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
258 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
259 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
261 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
264 gfx.win_xsize = win_xsize;
265 gfx.win_ysize = win_ysize;
267 gfx.background_bitmap_mask = REDRAW_NONE;
270 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
272 /* currently only used by MSDOS code to alloc VRAM buffer, if available */
273 /* 2009-03-24: also (temporarily?) used for overlapping blit workaround */
274 gfx.scrollbuffer_width = scrollbuffer_width;
275 gfx.scrollbuffer_height = scrollbuffer_height;
278 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
280 gfx.clipping_enabled = enabled;
283 gfx.clip_width = width;
284 gfx.clip_height = height;
287 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
289 gfx.draw_busy_anim_function = draw_busy_anim_function;
292 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
294 gfx.draw_global_anim_function = draw_global_anim_function;
297 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
299 gfx.draw_global_border_function = draw_global_border_function;
302 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
304 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
307 void InitGfxCustomArtworkInfo()
309 gfx.override_level_graphics = FALSE;
310 gfx.override_level_sounds = FALSE;
311 gfx.override_level_music = FALSE;
313 gfx.draw_init_text = TRUE;
316 void InitGfxOtherSettings()
318 gfx.cursor_mode = CURSOR_DEFAULT;
321 void InitTileCursorInfo()
323 tile_cursor.enabled = FALSE;
324 tile_cursor.active = FALSE;
325 tile_cursor.moving = FALSE;
327 tile_cursor.xpos = 0;
328 tile_cursor.ypos = 0;
331 tile_cursor.target_x = 0;
332 tile_cursor.target_y = 0;
338 void InitOverlayInfo()
340 int nr = GRID_ACTIVE_NR();
343 overlay.enabled = FALSE;
344 overlay.active = FALSE;
346 overlay.show_grid = FALSE;
348 overlay.grid_xsize = setup.touch.grid_xsize[nr];
349 overlay.grid_ysize = setup.touch.grid_ysize[nr];
351 for (x = 0; x < MAX_GRID_XSIZE; x++)
352 for (y = 0; y < MAX_GRID_YSIZE; y++)
353 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
355 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
356 overlay.grid_button_action = JOY_NO_ACTION;
358 #if defined(USE_TOUCH_INPUT_OVERLAY)
359 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
360 overlay.enabled = TRUE;
364 void SetTileCursorEnabled(boolean enabled)
366 tile_cursor.enabled = enabled;
369 void SetTileCursorActive(boolean active)
371 tile_cursor.active = active;
374 void SetTileCursorTargetXY(int x, int y)
376 // delayed placement of tile selection cursor at target position
377 // (tile cursor will be moved to target position step by step)
379 tile_cursor.xpos = x;
380 tile_cursor.ypos = y;
381 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
382 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
384 tile_cursor.moving = TRUE;
387 void SetTileCursorXY(int x, int y)
389 // immediate placement of tile selection cursor at target position
391 SetTileCursorTargetXY(x, y);
393 tile_cursor.x = tile_cursor.target_x;
394 tile_cursor.y = tile_cursor.target_y;
396 tile_cursor.moving = FALSE;
399 void SetTileCursorSXSY(int sx, int sy)
405 void SetOverlayEnabled(boolean enabled)
407 overlay.enabled = enabled;
410 void SetOverlayActive(boolean active)
412 overlay.active = active;
415 void SetOverlayShowGrid(boolean show_grid)
417 overlay.show_grid = show_grid;
419 SetOverlayActive(show_grid);
422 SetOverlayEnabled(TRUE);
425 boolean GetOverlayActive()
427 return overlay.active;
430 void SetDrawDeactivationMask(int draw_deactivation_mask)
432 gfx.draw_deactivation_mask = draw_deactivation_mask;
435 int GetDrawDeactivationMask()
437 return gfx.draw_deactivation_mask;
440 void SetDrawBackgroundMask(int draw_background_mask)
442 gfx.draw_background_mask = draw_background_mask;
445 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
447 if (background_bitmap_tile != NULL)
448 gfx.background_bitmap_mask |= mask;
450 gfx.background_bitmap_mask &= ~mask;
452 if (background_bitmap_tile == NULL) /* empty background requested */
455 if (mask == REDRAW_ALL)
456 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
457 0, 0, video.width, video.height);
458 else if (mask == REDRAW_FIELD)
459 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
460 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
461 else if (mask == REDRAW_DOOR_1)
462 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
463 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
466 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
468 /* remove every mask before setting mask for window */
469 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
470 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
471 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
474 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
476 /* remove window area mask before setting mask for main area */
477 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
478 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
479 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
482 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
484 /* remove window area mask before setting mask for door area */
485 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
486 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
487 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
491 /* ========================================================================= */
492 /* video functions */
493 /* ========================================================================= */
495 inline static int GetRealDepth(int depth)
497 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
500 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
501 int width, int height, Pixel color)
503 SDLFillRectangle(bitmap, x, y, width, height, color);
505 if (bitmap == backbuffer)
506 SetRedrawMaskFromArea(x, y, width, height);
509 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
510 int src_x, int src_y, int width, int height,
511 int dst_x, int dst_y, int mask_mode)
513 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
514 dst_x, dst_y, mask_mode);
516 if (dst_bitmap == backbuffer)
517 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
520 void LimitScreenUpdates(boolean enable)
522 SDLLimitScreenUpdates(enable);
525 void InitVideoDefaults(void)
527 video.default_depth = 32;
530 void InitVideoDisplay(void)
532 if (program.headless)
535 SDLInitVideoDisplay();
536 #if defined(TARGET_SDL2)
541 void CloseVideoDisplay(void)
543 KeyboardAutoRepeatOn();
545 SDL_QuitSubSystem(SDL_INIT_VIDEO);
548 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
551 video.height = height;
552 video.depth = GetRealDepth(depth);
554 video.screen_width = width;
555 video.screen_height = height;
556 video.screen_xoffset = 0;
557 video.screen_yoffset = 0;
559 video.fullscreen_available = FULLSCREEN_STATUS;
560 video.fullscreen_enabled = FALSE;
562 video.window_scaling_available = WINDOW_SCALING_STATUS;
564 video.frame_delay = 0;
565 video.frame_delay_value = GAME_FRAME_DELAY;
567 video.shifted_up = FALSE;
568 video.shifted_up_pos = 0;
569 video.shifted_up_pos_last = 0;
570 video.shifted_up_delay = 0;
571 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
573 SDLInitVideoBuffer(fullscreen);
575 video.initialized = !program.headless;
580 inline static void FreeBitmapPointers(Bitmap *bitmap)
585 SDLFreeBitmapPointers(bitmap);
587 checked_free(bitmap->source_filename);
588 bitmap->source_filename = NULL;
591 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
594 if (src_bitmap == NULL || dst_bitmap == NULL)
597 FreeBitmapPointers(dst_bitmap);
599 *dst_bitmap = *src_bitmap;
602 void FreeBitmap(Bitmap *bitmap)
607 FreeBitmapPointers(bitmap);
612 Bitmap *CreateBitmapStruct(void)
614 return checked_calloc(sizeof(Bitmap));
617 Bitmap *CreateBitmap(int width, int height, int depth)
619 Bitmap *new_bitmap = CreateBitmapStruct();
620 int real_width = MAX(1, width); /* prevent zero bitmap width */
621 int real_height = MAX(1, height); /* prevent zero bitmap height */
622 int real_depth = GetRealDepth(depth);
624 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
626 new_bitmap->width = real_width;
627 new_bitmap->height = real_height;
632 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
636 /* if new bitmap size fits into old one, no need to re-create it */
637 if (width <= (*bitmap)->width &&
638 height <= (*bitmap)->height)
641 /* else adjust size so that old and new bitmap size fit into it */
642 width = MAX(width, (*bitmap)->width);
643 height = MAX(height, (*bitmap)->height);
646 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
650 *bitmap = new_bitmap;
654 TransferBitmapPointers(new_bitmap, *bitmap);
659 void CloseWindow(DrawWindow *window)
663 void SetRedrawMaskFromArea(int x, int y, int width, int height)
667 int x2 = x + width - 1;
668 int y2 = y + height - 1;
670 if (width == 0 || height == 0)
673 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
674 redraw_mask |= REDRAW_FIELD;
675 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
676 redraw_mask |= REDRAW_DOOR_1;
677 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
678 redraw_mask |= REDRAW_DOOR_2;
679 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
680 redraw_mask |= REDRAW_DOOR_3;
682 redraw_mask = REDRAW_ALL;
685 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
688 if (draw_mask == REDRAW_NONE)
691 if (draw_mask & REDRAW_ALL)
694 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
697 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
700 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
703 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
709 boolean DrawingDeactivatedField()
711 if (program.headless)
714 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
720 boolean DrawingDeactivated(int x, int y, int width, int height)
722 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
725 boolean DrawingOnBackground(int x, int y)
727 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
728 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
731 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
732 int *width, int *height, boolean is_dest)
734 int clip_x, clip_y, clip_width, clip_height;
736 if (gfx.clipping_enabled && is_dest) /* only clip destination bitmap */
738 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
739 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
740 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
741 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
747 clip_width = bitmap->width;
748 clip_height = bitmap->height;
751 /* skip if rectangle completely outside bitmap */
753 if (*x + *width <= clip_x ||
754 *y + *height <= clip_y ||
755 *x >= clip_x + clip_width ||
756 *y >= clip_y + clip_height)
759 /* clip if rectangle overlaps bitmap */
763 *width -= clip_x - *x;
766 else if (*x + *width > clip_x + clip_width)
768 *width = clip_x + clip_width - *x;
773 *height -= clip_y - *y;
776 else if (*y + *height > clip_y + clip_height)
778 *height = clip_y + clip_height - *y;
784 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
785 int src_x, int src_y, int width, int height,
786 int dst_x, int dst_y)
788 int dst_x_unclipped = dst_x;
789 int dst_y_unclipped = dst_y;
791 if (program.headless)
794 if (src_bitmap == NULL || dst_bitmap == NULL)
797 if (DrawingDeactivated(dst_x, dst_y, width, height))
800 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
801 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
804 /* source x/y might need adjustment if destination x/y was clipped top/left */
805 src_x += dst_x - dst_x_unclipped;
806 src_y += dst_y - dst_y_unclipped;
808 #if defined(TARGET_SDL2)
809 /* !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!! */
810 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
811 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
812 but is already fixed in SVN and should therefore finally be fixed with
813 the next official SDL release, which is probably version 1.2.14.) */
814 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
816 if (src_bitmap == dst_bitmap)
818 /* needed when blitting directly to same bitmap -- should not be needed with
819 recent SDL libraries, but apparently does not work in 1.2.11 directly */
821 static Bitmap *tmp_bitmap = NULL;
822 static int tmp_bitmap_xsize = 0;
823 static int tmp_bitmap_ysize = 0;
825 /* start with largest static bitmaps for initial bitmap size ... */
826 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
828 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
829 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
832 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
833 if (src_bitmap->width > tmp_bitmap_xsize ||
834 src_bitmap->height > tmp_bitmap_ysize)
836 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
837 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
839 FreeBitmap(tmp_bitmap);
844 if (tmp_bitmap == NULL)
845 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
848 sysCopyArea(src_bitmap, tmp_bitmap,
849 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
850 sysCopyArea(tmp_bitmap, dst_bitmap,
851 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
857 sysCopyArea(src_bitmap, dst_bitmap,
858 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
861 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
862 int src_x, int src_y, int src_width, int src_height,
863 int dst_x, int dst_y, int dst_width, int dst_height)
865 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
866 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
867 int dst_xsize = dst_width;
868 int dst_ysize = dst_height;
869 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
870 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
873 for (y = 0; y < src_ysteps; y++)
875 for (x = 0; x < src_xsteps; x++)
877 int draw_x = dst_x + x * src_xsize;
878 int draw_y = dst_y + y * src_ysize;
879 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
880 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
882 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
888 void FadeRectangle(int x, int y, int width, int height,
889 int fade_mode, int fade_delay, int post_delay,
890 void (*draw_border_function)(void))
892 /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
893 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
896 SDLFadeRectangle(x, y, width, height,
897 fade_mode, fade_delay, post_delay, draw_border_function);
900 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
903 if (DrawingDeactivated(x, y, width, height))
906 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
909 sysFillRectangle(bitmap, x, y, width, height, color);
912 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
914 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
917 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
918 int width, int height)
920 if (DrawingOnBackground(x, y))
921 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
923 ClearRectangle(bitmap, x, y, width, height);
926 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
927 int src_x, int src_y, int width, int height,
928 int dst_x, int dst_y)
930 if (DrawingDeactivated(dst_x, dst_y, width, height))
933 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
934 dst_x, dst_y, BLIT_MASKED);
937 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
938 int src_x, int src_y, int width, int height,
939 int dst_x, int dst_y)
941 if (DrawingOnBackground(dst_x, dst_y))
943 /* draw background */
944 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
947 /* draw foreground */
948 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
952 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
956 void BlitTexture(Bitmap *bitmap,
957 int src_x, int src_y, int width, int height,
958 int dst_x, int dst_y)
963 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
967 void BlitTextureMasked(Bitmap *bitmap,
968 int src_x, int src_y, int width, int height,
969 int dst_x, int dst_y)
974 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
978 void BlitToScreen(Bitmap *bitmap,
979 int src_x, int src_y, int width, int height,
980 int dst_x, int dst_y)
985 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
986 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
987 width, height, dst_x, dst_y);
989 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
992 void BlitToScreenMasked(Bitmap *bitmap,
993 int src_x, int src_y, int width, int height,
994 int dst_x, int dst_y)
999 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1000 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1001 width, height, dst_x, dst_y);
1003 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1006 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1009 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1012 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1015 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1018 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1019 int to_x, int to_y, Pixel pixel, int line_width)
1023 if (program.headless)
1026 for (x = 0; x < line_width; x++)
1028 for (y = 0; y < line_width; y++)
1030 int dx = x - line_width / 2;
1031 int dy = y - line_width / 2;
1033 if ((x == 0 && y == 0) ||
1034 (x == 0 && y == line_width - 1) ||
1035 (x == line_width - 1 && y == 0) ||
1036 (x == line_width - 1 && y == line_width - 1))
1040 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1045 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1050 for (i = 0; i < num_points - 1; i++)
1051 DrawLine(bitmap, points[i].x, points[i].y,
1052 points[i + 1].x, points[i + 1].y, pixel, line_width);
1055 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1059 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1061 if (program.headless)
1064 if (x < 0 || x >= bitmap->width ||
1065 y < 0 || y >= bitmap->height)
1068 return SDLGetPixel(bitmap, x, y);
1071 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1072 unsigned int color_g, unsigned int color_b)
1074 if (program.headless)
1077 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1080 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1082 unsigned int color_r = (color >> 16) & 0xff;
1083 unsigned int color_g = (color >> 8) & 0xff;
1084 unsigned int color_b = (color >> 0) & 0xff;
1086 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1089 void KeyboardAutoRepeatOn(void)
1091 #if defined(TARGET_SDL2)
1092 keyrepeat_status = TRUE;
1094 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
1095 SDL_DEFAULT_REPEAT_INTERVAL / 2);
1096 SDL_EnableUNICODE(1);
1100 void KeyboardAutoRepeatOff(void)
1102 #if defined(TARGET_SDL2)
1103 keyrepeat_status = FALSE;
1105 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1106 SDL_EnableUNICODE(0);
1110 boolean SetVideoMode(boolean fullscreen)
1112 return SDLSetVideoMode(fullscreen);
1115 void SetVideoFrameDelay(unsigned int frame_delay_value)
1117 video.frame_delay_value = frame_delay_value;
1120 unsigned int GetVideoFrameDelay()
1122 return video.frame_delay_value;
1125 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1127 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1128 (!fullscreen && video.fullscreen_enabled))
1129 fullscreen = SetVideoMode(fullscreen);
1134 Bitmap *LoadImage(char *filename)
1138 new_bitmap = SDLLoadImage(filename);
1141 new_bitmap->source_filename = getStringCopy(filename);
1146 Bitmap *LoadCustomImage(char *basename)
1148 char *filename = getCustomImageFilename(basename);
1151 if (filename == NULL)
1152 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1154 if ((new_bitmap = LoadImage(filename)) == NULL)
1155 Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError());
1160 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1162 char *filename = getCustomImageFilename(basename);
1165 if (filename == NULL) /* (should never happen) */
1167 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1171 if (strEqual(filename, bitmap->source_filename))
1173 /* The old and new image are the same (have the same filename and path).
1174 This usually means that this image does not exist in this graphic set
1175 and a fallback to the existing image is done. */
1180 if ((new_bitmap = LoadImage(filename)) == NULL)
1182 Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError());
1186 if (bitmap->width != new_bitmap->width ||
1187 bitmap->height != new_bitmap->height)
1189 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1191 FreeBitmap(new_bitmap);
1195 TransferBitmapPointers(new_bitmap, bitmap);
1199 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1201 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1204 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1206 if (bitmaps[IMG_BITMAP_CUSTOM])
1208 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1210 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1213 if (gfx.game_tile_size == gfx.standard_tile_size)
1215 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1220 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1221 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1222 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1224 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1226 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1227 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1230 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1231 int tile_size, boolean create_small_bitmaps)
1233 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1234 Bitmap *tmp_bitmap_final = NULL;
1235 Bitmap *tmp_bitmap_0 = NULL;
1236 Bitmap *tmp_bitmap_1 = NULL;
1237 Bitmap *tmp_bitmap_2 = NULL;
1238 Bitmap *tmp_bitmap_4 = NULL;
1239 Bitmap *tmp_bitmap_8 = NULL;
1240 Bitmap *tmp_bitmap_16 = NULL;
1241 Bitmap *tmp_bitmap_32 = NULL;
1242 int width_final, height_final;
1243 int width_0, height_0;
1244 int width_1, height_1;
1245 int width_2, height_2;
1246 int width_4, height_4;
1247 int width_8, height_8;
1248 int width_16, height_16;
1249 int width_32, height_32;
1250 int old_width, old_height;
1253 print_timestamp_init("CreateScaledBitmaps");
1255 old_width = old_bitmap->width;
1256 old_height = old_bitmap->height;
1258 /* calculate new image dimensions for final image size */
1259 width_final = old_width * zoom_factor;
1260 height_final = old_height * zoom_factor;
1262 /* get image with final size (this might require scaling up) */
1263 /* ("final" size may result in non-standard tile size image) */
1264 if (zoom_factor != 1)
1265 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1267 tmp_bitmap_final = old_bitmap;
1269 UPDATE_BUSY_STATE();
1271 width_0 = width_1 = width_final;
1272 height_0 = height_1 = height_final;
1274 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1276 if (create_small_bitmaps)
1278 /* check if we have a non-gameplay tile size image */
1279 if (tile_size != gfx.game_tile_size)
1281 /* get image with gameplay tile size */
1282 width_0 = width_final * gfx.game_tile_size / tile_size;
1283 height_0 = height_final * gfx.game_tile_size / tile_size;
1285 if (width_0 == old_width)
1286 tmp_bitmap_0 = old_bitmap;
1287 else if (width_0 == width_final)
1288 tmp_bitmap_0 = tmp_bitmap_final;
1290 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1292 UPDATE_BUSY_STATE();
1295 /* check if we have a non-standard tile size image */
1296 if (tile_size != gfx.standard_tile_size)
1298 /* get image with standard tile size */
1299 width_1 = width_final * gfx.standard_tile_size / tile_size;
1300 height_1 = height_final * gfx.standard_tile_size / tile_size;
1302 if (width_1 == old_width)
1303 tmp_bitmap_1 = old_bitmap;
1304 else if (width_1 == width_final)
1305 tmp_bitmap_1 = tmp_bitmap_final;
1306 else if (width_1 == width_0)
1307 tmp_bitmap_1 = tmp_bitmap_0;
1309 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1311 UPDATE_BUSY_STATE();
1314 /* calculate new image dimensions for small images */
1315 width_2 = width_1 / 2;
1316 height_2 = height_1 / 2;
1317 width_4 = width_1 / 4;
1318 height_4 = height_1 / 4;
1319 width_8 = width_1 / 8;
1320 height_8 = height_1 / 8;
1321 width_16 = width_1 / 16;
1322 height_16 = height_1 / 16;
1323 width_32 = width_1 / 32;
1324 height_32 = height_1 / 32;
1326 /* get image with 1/2 of normal size (for use in the level editor) */
1327 if (width_2 == old_width)
1328 tmp_bitmap_2 = old_bitmap;
1330 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1332 UPDATE_BUSY_STATE();
1334 /* get image with 1/4 of normal size (for use in the level editor) */
1335 if (width_4 == old_width)
1336 tmp_bitmap_4 = old_bitmap;
1338 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1340 UPDATE_BUSY_STATE();
1342 /* get image with 1/8 of normal size (for use on the preview screen) */
1343 if (width_8 == old_width)
1344 tmp_bitmap_8 = old_bitmap;
1346 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1348 UPDATE_BUSY_STATE();
1350 /* get image with 1/16 of normal size (for use on the preview screen) */
1351 if (width_16 == old_width)
1352 tmp_bitmap_16 = old_bitmap;
1354 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1356 UPDATE_BUSY_STATE();
1358 /* get image with 1/32 of normal size (for use on the preview screen) */
1359 if (width_32 == old_width)
1360 tmp_bitmap_32 = old_bitmap;
1362 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1364 UPDATE_BUSY_STATE();
1366 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1367 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1368 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1369 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1370 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1371 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1373 if (width_0 != width_1)
1374 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1376 if (bitmaps[IMG_BITMAP_CUSTOM])
1377 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1379 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1381 boolean free_old_bitmap = TRUE;
1383 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1384 if (bitmaps[i] == old_bitmap)
1385 free_old_bitmap = FALSE;
1387 if (free_old_bitmap)
1388 FreeBitmap(old_bitmap);
1392 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1395 UPDATE_BUSY_STATE();
1397 print_timestamp_done("CreateScaledBitmaps");
1400 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1403 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1406 void CreateBitmapTextures(Bitmap **bitmaps)
1408 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1411 void FreeBitmapTextures(Bitmap **bitmaps)
1413 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1416 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1418 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1422 /* ------------------------------------------------------------------------- */
1423 /* mouse pointer functions */
1424 /* ------------------------------------------------------------------------- */
1426 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1428 /* XPM image definitions */
1429 static const char *cursor_image_none[] =
1431 /* width height num_colors chars_per_pixel */
1461 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1462 static const char *cursor_image_dot[] =
1464 /* width height num_colors chars_per_pixel */
1493 static const char **cursor_image_playfield = cursor_image_dot;
1495 /* some people complained about a "white dot" on the screen and thought it
1496 was a graphical error... OK, let's just remove the whole pointer :-) */
1497 static const char **cursor_image_playfield = cursor_image_none;
1500 static const int cursor_bit_order = BIT_ORDER_MSB;
1502 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1504 struct MouseCursorInfo *cursor;
1505 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1506 int header_lines = 4;
1509 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1511 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1514 for (y = 0; y < cursor->width; y++)
1516 for (x = 0; x < cursor->height; x++)
1519 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1524 cursor->data[i] = cursor->mask[i] = 0;
1527 switch (image[header_lines + y][x])
1530 cursor->data[i] |= bit_mask;
1531 cursor->mask[i] |= bit_mask;
1535 cursor->mask[i] |= bit_mask;
1544 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1549 void SetMouseCursor(int mode)
1551 static struct MouseCursorInfo *cursor_none = NULL;
1552 static struct MouseCursorInfo *cursor_playfield = NULL;
1553 struct MouseCursorInfo *cursor_new;
1555 if (cursor_none == NULL)
1556 cursor_none = get_cursor_from_image(cursor_image_none);
1558 if (cursor_playfield == NULL)
1559 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1561 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1562 mode == CURSOR_NONE ? cursor_none :
1563 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1565 SDLSetMouseCursor(cursor_new);
1567 gfx.cursor_mode = mode;
1571 /* ========================================================================= */
1572 /* audio functions */
1573 /* ========================================================================= */
1575 void OpenAudio(void)
1577 /* always start with reliable default values */
1578 audio.sound_available = FALSE;
1579 audio.music_available = FALSE;
1580 audio.loops_available = FALSE;
1582 audio.sound_enabled = FALSE;
1583 audio.sound_deactivated = FALSE;
1585 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1586 audio.mixer_pid = 0;
1587 audio.device_name = NULL;
1588 audio.device_fd = -1;
1590 audio.num_channels = 0;
1591 audio.music_channel = 0;
1592 audio.first_sound_channel = 0;
1597 void CloseAudio(void)
1601 audio.sound_enabled = FALSE;
1604 void SetAudioMode(boolean enabled)
1606 if (!audio.sound_available)
1609 audio.sound_enabled = enabled;
1613 /* ========================================================================= */
1614 /* event functions */
1615 /* ========================================================================= */
1617 boolean PendingEvent(void)
1619 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1622 void WaitEvent(Event *event)
1624 SDLWaitEvent(event);
1627 void PeekEvent(Event *event)
1629 #if defined(TARGET_SDL2)
1630 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1632 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1636 void CheckQuitEvent(void)
1638 if (SDL_QuitRequested())
1639 program.exit_function(0);
1642 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1644 #if defined(TARGET_SDL2)
1645 /* key up/down events in SDL2 do not return text characters anymore */
1646 return event->keysym.sym;
1649 #if ENABLE_UNUSED_CODE
1650 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1651 (int)event->keysym.unicode,
1652 (int)event->keysym.sym,
1653 (int)SDL_GetModState());
1656 if (with_modifiers &&
1657 event->keysym.unicode > 0x0000 &&
1658 event->keysym.unicode < 0x2000)
1659 return event->keysym.unicode;
1661 return event->keysym.sym;
1666 KeyMod HandleKeyModState(Key key, int key_status)
1668 static KeyMod current_modifiers = KMOD_None;
1670 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1672 KeyMod new_modifier = KMOD_None;
1677 new_modifier = KMOD_Shift_L;
1680 new_modifier = KMOD_Shift_R;
1682 case KSYM_Control_L:
1683 new_modifier = KMOD_Control_L;
1685 case KSYM_Control_R:
1686 new_modifier = KMOD_Control_R;
1689 new_modifier = KMOD_Meta_L;
1692 new_modifier = KMOD_Meta_R;
1695 new_modifier = KMOD_Alt_L;
1698 new_modifier = KMOD_Alt_R;
1704 if (key_status == KEY_PRESSED)
1705 current_modifiers |= new_modifier;
1707 current_modifiers &= ~new_modifier;
1710 return current_modifiers;
1713 KeyMod GetKeyModState()
1715 return (KeyMod)SDL_GetModState();
1718 KeyMod GetKeyModStateFromEvents()
1720 /* always use key modifier state as tracked from key events (this is needed
1721 if the modifier key event was injected into the event queue, but the key
1722 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1723 query the keys as held pressed on the keyboard) -- this case is currently
1724 only used to filter out clipboard insert events from "True X-Mouse" tool */
1726 return HandleKeyModState(KSYM_UNDEFINED, 0);
1729 void StartTextInput(int x, int y, int width, int height)
1731 #if defined(TARGET_SDL2)
1732 #if defined(HAS_SCREEN_KEYBOARD)
1733 SDL_StartTextInput();
1735 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1737 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1738 video.shifted_up_delay = SDL_GetTicks();
1739 video.shifted_up = TRUE;
1745 void StopTextInput()
1747 #if defined(TARGET_SDL2)
1748 #if defined(HAS_SCREEN_KEYBOARD)
1749 SDL_StopTextInput();
1751 if (video.shifted_up)
1753 video.shifted_up_pos = 0;
1754 video.shifted_up_delay = SDL_GetTicks();
1755 video.shifted_up = FALSE;
1761 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1763 if (event->type != EVENT_CLIENTMESSAGE)
1766 return TRUE; /* the only possible message here is SDL_QUIT */
1770 /* ========================================================================= */
1771 /* joystick functions */
1772 /* ========================================================================= */
1774 void InitJoysticks()
1778 #if defined(NO_JOYSTICK)
1779 return; /* joysticks generally deactivated by compile-time directive */
1782 /* always start with reliable default values */
1783 joystick.status = JOYSTICK_NOT_AVAILABLE;
1784 for (i = 0; i < MAX_PLAYERS; i++)
1785 joystick.nr[i] = -1; /* no joystick configured */
1790 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1792 return SDLReadJoystick(nr, x, y, b1, b2);
1795 boolean CheckJoystickOpened(int nr)
1797 return SDLCheckJoystickOpened(nr);
1800 void ClearJoystickState()
1802 SDLClearJoystickState();