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 // ============================================================================
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;
44 LevelDirTree *leveldir_first_all = NULL;
45 LevelDirTree *leveldir_first = NULL;
46 LevelDirTree *leveldir_current = NULL;
49 struct LevelSetInfo levelset;
50 struct LevelStats level_stats[MAX_LEVELS];
52 DrawWindow *window = NULL;
53 DrawBuffer *backbuffer = NULL;
54 DrawBuffer *drawto = NULL;
56 int button_status = MB_NOT_PRESSED;
57 boolean motion_status = FALSE;
58 int wheel_steps = DEFAULT_WHEEL_STEPS;
59 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 InitRuntimeInfo()
120 #if defined(HAS_TOUCH_DEVICE)
121 runtime.uses_touch_device = TRUE;
123 runtime.uses_touch_device = FALSE;
127 void InitScoresInfo(void)
129 char *global_scores_dir = getPath2(getCommonDataDir(), SCORES_DIRECTORY);
131 program.global_scores = directoryExists(global_scores_dir);
132 program.many_scores_per_name = !program.global_scores;
137 if (program.global_scores)
139 Error(ERR_DEBUG, "Using global, multi-user scores directory '%s'.",
141 Error(ERR_DEBUG, "Remove to enable single-user scores directory.");
142 Error(ERR_DEBUG, "(This enables multipe score entries per user.)");
146 Error(ERR_DEBUG, "Using private, single-user scores directory.");
151 free(global_scores_dir);
154 void SetWindowTitle(void)
156 program.window_title = program.window_title_function();
161 void InitWindowTitleFunction(char *(*window_title_function)(void))
163 program.window_title_function = window_title_function;
166 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
168 program.exit_message_function = exit_message_function;
171 void InitExitFunction(void (*exit_function)(int))
173 program.exit_function = exit_function;
175 // set signal handlers to custom exit function
176 // signal(SIGINT, exit_function);
177 signal(SIGTERM, exit_function);
179 // set exit function to automatically cleanup SDL stuff after exit()
183 void InitPlatformDependentStuff(void)
185 // this is initialized in GetOptions(), but may already be used before
186 options.verbose = TRUE;
190 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
192 if (SDL_Init(sdl_init_flags) < 0)
193 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
198 void ClosePlatformDependentStuff(void)
203 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
204 int real_sx, int real_sy,
205 int full_sxsize, int full_sysize,
206 Bitmap *field_save_buffer)
212 gfx.real_sx = real_sx;
213 gfx.real_sy = real_sy;
214 gfx.full_sxsize = full_sxsize;
215 gfx.full_sysize = full_sysize;
217 gfx.field_save_buffer = field_save_buffer;
219 SetDrawDeactivationMask(REDRAW_NONE); // do not deactivate drawing
220 SetDrawBackgroundMask(REDRAW_NONE); // deactivate masked drawing
223 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
225 gfx.game_tile_size = game_tile_size;
226 gfx.standard_tile_size = standard_tile_size;
229 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
237 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
245 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
253 void InitGfxWindowInfo(int win_xsize, int win_ysize)
255 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
257 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
259 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
261 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
262 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
263 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
264 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
266 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
269 gfx.win_xsize = win_xsize;
270 gfx.win_ysize = win_ysize;
272 gfx.background_bitmap_mask = REDRAW_NONE;
275 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
277 // currently only used by MSDOS code to alloc VRAM buffer, if available
278 // 2009-03-24: also (temporarily?) used for overlapping blit workaround
279 gfx.scrollbuffer_width = scrollbuffer_width;
280 gfx.scrollbuffer_height = scrollbuffer_height;
283 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
285 gfx.clipping_enabled = enabled;
288 gfx.clip_width = width;
289 gfx.clip_height = height;
292 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
294 gfx.draw_busy_anim_function = draw_busy_anim_function;
297 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
299 gfx.draw_global_anim_function = draw_global_anim_function;
302 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
304 gfx.draw_global_border_function = draw_global_border_function;
307 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
309 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
312 void InitGfxCustomArtworkInfo(void)
314 gfx.override_level_graphics = FALSE;
315 gfx.override_level_sounds = FALSE;
316 gfx.override_level_music = FALSE;
318 gfx.draw_init_text = TRUE;
321 void InitGfxOtherSettings(void)
323 gfx.cursor_mode = CURSOR_DEFAULT;
324 gfx.cursor_mode_override = CURSOR_UNDEFINED;
325 gfx.cursor_mode_final = gfx.cursor_mode;
327 // prevent initially displaying custom mouse cursor in upper left corner
328 gfx.mouse_x = POS_OFFSCREEN;
329 gfx.mouse_y = POS_OFFSCREEN;
332 void InitTileCursorInfo(void)
334 tile_cursor.enabled = FALSE;
335 tile_cursor.active = FALSE;
336 tile_cursor.moving = FALSE;
338 tile_cursor.xpos = 0;
339 tile_cursor.ypos = 0;
342 tile_cursor.target_x = 0;
343 tile_cursor.target_y = 0;
349 void InitOverlayInfo(void)
351 int nr = GRID_ACTIVE_NR();
354 overlay.enabled = FALSE;
355 overlay.active = FALSE;
357 overlay.show_grid = FALSE;
359 overlay.grid_xsize = setup.touch.grid_xsize[nr];
360 overlay.grid_ysize = setup.touch.grid_ysize[nr];
362 for (x = 0; x < MAX_GRID_XSIZE; x++)
363 for (y = 0; y < MAX_GRID_YSIZE; y++)
364 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
366 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
367 overlay.grid_button_action = JOY_NO_ACTION;
369 #if defined(USE_TOUCH_INPUT_OVERLAY)
370 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
371 overlay.enabled = TRUE;
375 void SetTileCursorEnabled(boolean enabled)
377 tile_cursor.enabled = enabled;
380 void SetTileCursorActive(boolean active)
382 tile_cursor.active = active;
385 void SetTileCursorTargetXY(int x, int y)
387 // delayed placement of tile selection cursor at target position
388 // (tile cursor will be moved to target position step by step)
390 tile_cursor.xpos = x;
391 tile_cursor.ypos = y;
392 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
393 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
395 tile_cursor.moving = TRUE;
398 void SetTileCursorXY(int x, int y)
400 // immediate placement of tile selection cursor at target position
402 SetTileCursorTargetXY(x, y);
404 tile_cursor.x = tile_cursor.target_x;
405 tile_cursor.y = tile_cursor.target_y;
407 tile_cursor.moving = FALSE;
410 void SetTileCursorSXSY(int sx, int sy)
416 void SetOverlayEnabled(boolean enabled)
418 overlay.enabled = enabled;
421 void SetOverlayActive(boolean active)
423 overlay.active = active;
426 void SetOverlayShowGrid(boolean show_grid)
428 overlay.show_grid = show_grid;
430 SetOverlayActive(show_grid);
433 SetOverlayEnabled(TRUE);
436 boolean GetOverlayEnabled(void)
438 return overlay.enabled;
441 boolean GetOverlayActive(void)
443 return overlay.active;
446 void SetDrawDeactivationMask(int draw_deactivation_mask)
448 gfx.draw_deactivation_mask = draw_deactivation_mask;
451 int GetDrawDeactivationMask(void)
453 return gfx.draw_deactivation_mask;
456 void SetDrawBackgroundMask(int draw_background_mask)
458 gfx.draw_background_mask = draw_background_mask;
461 static void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
463 if (background_bitmap_tile != NULL)
464 gfx.background_bitmap_mask |= mask;
466 gfx.background_bitmap_mask &= ~mask;
468 if (background_bitmap_tile == NULL) // empty background requested
471 if (mask == REDRAW_ALL)
472 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
473 0, 0, video.width, video.height);
474 else if (mask == REDRAW_FIELD)
475 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
476 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
477 else if (mask == REDRAW_DOOR_1)
478 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
479 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
482 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
484 // remove every mask before setting mask for window
485 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
486 SetBackgroundBitmap(NULL, 0xffff); // !!! FIX THIS !!!
487 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
490 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
492 // remove window area mask before setting mask for main area
493 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
494 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
495 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
498 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
500 // remove window area mask before setting mask for door area
501 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
502 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
503 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
507 // ============================================================================
509 // ============================================================================
511 static int GetRealDepth(int depth)
513 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
516 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
517 int width, int height, Pixel color)
519 SDLFillRectangle(bitmap, x, y, width, height, color);
521 if (bitmap == backbuffer)
522 SetRedrawMaskFromArea(x, y, width, height);
525 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
526 int src_x, int src_y, int width, int height,
527 int dst_x, int dst_y, int mask_mode)
529 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
530 dst_x, dst_y, mask_mode);
532 if (dst_bitmap == backbuffer)
533 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
536 void LimitScreenUpdates(boolean enable)
538 SDLLimitScreenUpdates(enable);
541 void InitVideoDefaults(void)
543 video.default_depth = 32;
546 void InitVideoDisplay(void)
548 if (program.headless)
551 SDLInitVideoDisplay();
555 void CloseVideoDisplay(void)
557 KeyboardAutoRepeatOn();
559 SDL_QuitSubSystem(SDL_INIT_VIDEO);
562 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
565 video.height = height;
566 video.depth = GetRealDepth(depth);
568 video.screen_width = width;
569 video.screen_height = height;
570 video.screen_xoffset = 0;
571 video.screen_yoffset = 0;
573 video.fullscreen_available = FULLSCREEN_STATUS;
574 video.fullscreen_enabled = FALSE;
576 video.window_scaling_available = WINDOW_SCALING_STATUS;
578 video.frame_counter = 0;
579 video.frame_delay = 0;
580 video.frame_delay_value = GAME_FRAME_DELAY;
582 video.shifted_up = FALSE;
583 video.shifted_up_pos = 0;
584 video.shifted_up_pos_last = 0;
585 video.shifted_up_delay = 0;
586 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
588 SDLInitVideoBuffer(fullscreen);
590 video.initialized = !program.headless;
595 static void FreeBitmapPointers(Bitmap *bitmap)
600 SDLFreeBitmapPointers(bitmap);
602 checked_free(bitmap->source_filename);
603 bitmap->source_filename = NULL;
606 static void TransferBitmapPointers(Bitmap *src_bitmap,
609 if (src_bitmap == NULL || dst_bitmap == NULL)
612 FreeBitmapPointers(dst_bitmap);
614 *dst_bitmap = *src_bitmap;
617 void FreeBitmap(Bitmap *bitmap)
622 FreeBitmapPointers(bitmap);
627 Bitmap *CreateBitmapStruct(void)
629 return checked_calloc(sizeof(Bitmap));
632 Bitmap *CreateBitmap(int width, int height, int depth)
634 Bitmap *new_bitmap = CreateBitmapStruct();
635 int real_width = MAX(1, width); // prevent zero bitmap width
636 int real_height = MAX(1, height); // prevent zero bitmap height
637 int real_depth = GetRealDepth(depth);
639 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
641 new_bitmap->width = real_width;
642 new_bitmap->height = real_height;
647 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
651 // if new bitmap size fits into old one, no need to re-create it
652 if (width <= (*bitmap)->width &&
653 height <= (*bitmap)->height)
656 // else adjust size so that old and new bitmap size fit into it
657 width = MAX(width, (*bitmap)->width);
658 height = MAX(height, (*bitmap)->height);
661 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
665 *bitmap = new_bitmap;
669 TransferBitmapPointers(new_bitmap, *bitmap);
675 static void CloseWindow(DrawWindow *window)
680 void SetRedrawMaskFromArea(int x, int y, int width, int height)
684 int x2 = x + width - 1;
685 int y2 = y + height - 1;
687 if (width == 0 || height == 0)
690 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
691 redraw_mask |= REDRAW_FIELD;
692 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
693 redraw_mask |= REDRAW_DOOR_1;
694 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
695 redraw_mask |= REDRAW_DOOR_2;
696 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
697 redraw_mask |= REDRAW_DOOR_3;
699 redraw_mask = REDRAW_ALL;
702 static boolean CheckDrawingArea(int x, int y, int width, int height,
705 if (draw_mask == REDRAW_NONE)
708 if (draw_mask & REDRAW_ALL)
711 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
714 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
717 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
720 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
726 boolean DrawingDeactivatedField(void)
728 if (program.headless)
731 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
737 boolean DrawingDeactivated(int x, int y, int width, int height)
739 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
742 boolean DrawingOnBackground(int x, int y)
744 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
745 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
748 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
749 int *width, int *height, boolean is_dest)
751 int clip_x, clip_y, clip_width, clip_height;
753 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
755 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
756 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
757 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
758 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
764 clip_width = bitmap->width;
765 clip_height = bitmap->height;
768 // skip if rectangle completely outside bitmap
770 if (*x + *width <= clip_x ||
771 *y + *height <= clip_y ||
772 *x >= clip_x + clip_width ||
773 *y >= clip_y + clip_height)
776 // clip if rectangle overlaps bitmap
780 *width -= clip_x - *x;
783 else if (*x + *width > clip_x + clip_width)
785 *width = clip_x + clip_width - *x;
790 *height -= clip_y - *y;
793 else if (*y + *height > clip_y + clip_height)
795 *height = clip_y + clip_height - *y;
801 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
802 int src_x, int src_y, int width, int height,
803 int dst_x, int dst_y)
805 int dst_x_unclipped = dst_x;
806 int dst_y_unclipped = dst_y;
808 if (program.headless)
811 if (src_bitmap == NULL || dst_bitmap == NULL)
814 if (DrawingDeactivated(dst_x, dst_y, width, height))
817 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
818 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
821 // source x/y might need adjustment if destination x/y was clipped top/left
822 src_x += dst_x - dst_x_unclipped;
823 src_y += dst_y - dst_y_unclipped;
825 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
826 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
827 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
828 but is already fixed in SVN and should therefore finally be fixed with
829 the next official SDL release, which is probably version 1.2.14.) */
830 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
832 if (src_bitmap == dst_bitmap)
834 // needed when blitting directly to same bitmap -- should not be needed with
835 // recent SDL libraries, but apparently does not work in 1.2.11 directly
837 static Bitmap *tmp_bitmap = NULL;
838 static int tmp_bitmap_xsize = 0;
839 static int tmp_bitmap_ysize = 0;
841 // start with largest static bitmaps for initial bitmap size ...
842 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
844 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
845 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
848 // ... and allow for later re-adjustments due to custom artwork bitmaps
849 if (src_bitmap->width > tmp_bitmap_xsize ||
850 src_bitmap->height > tmp_bitmap_ysize)
852 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
853 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
855 FreeBitmap(tmp_bitmap);
860 if (tmp_bitmap == NULL)
861 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
864 sysCopyArea(src_bitmap, tmp_bitmap,
865 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
866 sysCopyArea(tmp_bitmap, dst_bitmap,
867 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
872 sysCopyArea(src_bitmap, dst_bitmap,
873 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
876 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
877 int src_x, int src_y, int src_width, int src_height,
878 int dst_x, int dst_y, int dst_width, int dst_height)
880 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
881 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
882 int dst_xsize = dst_width;
883 int dst_ysize = dst_height;
884 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
885 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
888 for (y = 0; y < src_ysteps; y++)
890 for (x = 0; x < src_xsteps; x++)
892 int draw_x = dst_x + x * src_xsize;
893 int draw_y = dst_y + y * src_ysize;
894 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
895 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
897 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
903 void FadeRectangle(int x, int y, int width, int height,
904 int fade_mode, int fade_delay, int post_delay,
905 void (*draw_border_function)(void))
907 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
908 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
911 SDLFadeRectangle(x, y, width, height,
912 fade_mode, fade_delay, post_delay, draw_border_function);
915 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
918 if (DrawingDeactivated(x, y, width, height))
921 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
924 sysFillRectangle(bitmap, x, y, width, height, color);
927 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
929 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
932 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
933 int width, int height)
935 if (DrawingOnBackground(x, y))
936 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
938 ClearRectangle(bitmap, x, y, width, height);
941 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
942 int src_x, int src_y, int width, int height,
943 int dst_x, int dst_y)
945 if (DrawingDeactivated(dst_x, dst_y, width, height))
948 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
949 dst_x, dst_y, BLIT_MASKED);
952 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
953 int src_x, int src_y, int width, int height,
954 int dst_x, int dst_y)
956 if (DrawingOnBackground(dst_x, dst_y))
959 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
963 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
967 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
971 void BlitTexture(Bitmap *bitmap,
972 int src_x, int src_y, int width, int height,
973 int dst_x, int dst_y)
978 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
982 void BlitTextureMasked(Bitmap *bitmap,
983 int src_x, int src_y, int width, int height,
984 int dst_x, int dst_y)
989 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
993 void BlitToScreen(Bitmap *bitmap,
994 int src_x, int src_y, int width, int height,
995 int dst_x, int dst_y)
1000 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1001 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1002 width, height, dst_x, dst_y);
1004 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1007 void BlitToScreenMasked(Bitmap *bitmap,
1008 int src_x, int src_y, int width, int height,
1009 int dst_x, int dst_y)
1014 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1015 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1016 width, height, dst_x, dst_y);
1018 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1021 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1024 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1027 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1030 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1033 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1034 int to_x, int to_y, Pixel pixel, int line_width)
1038 if (program.headless)
1041 for (x = 0; x < line_width; x++)
1043 for (y = 0; y < line_width; y++)
1045 int dx = x - line_width / 2;
1046 int dy = y - line_width / 2;
1048 if ((x == 0 && y == 0) ||
1049 (x == 0 && y == line_width - 1) ||
1050 (x == line_width - 1 && y == 0) ||
1051 (x == line_width - 1 && y == line_width - 1))
1055 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1060 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1065 for (i = 0; i < num_points - 1; i++)
1066 DrawLine(bitmap, points[i].x, points[i].y,
1067 points[i + 1].x, points[i + 1].y, pixel, line_width);
1070 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1074 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1076 if (program.headless)
1079 if (x < 0 || x >= bitmap->width ||
1080 y < 0 || y >= bitmap->height)
1083 return SDLGetPixel(bitmap, x, y);
1086 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1087 unsigned int color_g, unsigned int color_b)
1089 if (program.headless)
1092 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1095 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1097 unsigned int color_r = (color >> 16) & 0xff;
1098 unsigned int color_g = (color >> 8) & 0xff;
1099 unsigned int color_b = (color >> 0) & 0xff;
1101 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1104 void KeyboardAutoRepeatOn(void)
1106 keyrepeat_status = TRUE;
1109 void KeyboardAutoRepeatOff(void)
1111 keyrepeat_status = FALSE;
1114 boolean SetVideoMode(boolean fullscreen)
1116 return SDLSetVideoMode(fullscreen);
1119 void SetVideoFrameDelay(unsigned int frame_delay_value)
1121 video.frame_delay_value = frame_delay_value;
1124 unsigned int GetVideoFrameDelay(void)
1126 return video.frame_delay_value;
1129 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1131 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1132 (!fullscreen && video.fullscreen_enabled))
1133 fullscreen = SetVideoMode(fullscreen);
1138 Bitmap *LoadImage(char *filename)
1142 new_bitmap = SDLLoadImage(filename);
1145 new_bitmap->source_filename = getStringCopy(filename);
1150 Bitmap *LoadCustomImage(char *basename)
1152 char *filename = getCustomImageFilename(basename);
1155 if (filename == NULL)
1156 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1158 if ((new_bitmap = LoadImage(filename)) == NULL)
1159 Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError());
1164 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1166 char *filename = getCustomImageFilename(basename);
1169 if (filename == NULL) // (should never happen)
1171 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1175 if (strEqual(filename, bitmap->source_filename))
1177 // The old and new image are the same (have the same filename and path).
1178 // This usually means that this image does not exist in this graphic set
1179 // and a fallback to the existing image is done.
1184 if ((new_bitmap = LoadImage(filename)) == NULL)
1186 Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError());
1190 if (bitmap->width != new_bitmap->width ||
1191 bitmap->height != new_bitmap->height)
1193 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1195 FreeBitmap(new_bitmap);
1199 TransferBitmapPointers(new_bitmap, bitmap);
1203 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1205 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1208 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1210 if (bitmaps[IMG_BITMAP_CUSTOM])
1212 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1214 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1217 if (gfx.game_tile_size == gfx.standard_tile_size)
1219 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1224 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1225 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1226 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1228 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1230 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1231 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1234 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1235 int tile_size, boolean create_small_bitmaps)
1237 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1238 Bitmap *tmp_bitmap_final = NULL;
1239 Bitmap *tmp_bitmap_0 = NULL;
1240 Bitmap *tmp_bitmap_1 = NULL;
1241 Bitmap *tmp_bitmap_2 = NULL;
1242 Bitmap *tmp_bitmap_4 = NULL;
1243 Bitmap *tmp_bitmap_8 = NULL;
1244 Bitmap *tmp_bitmap_16 = NULL;
1245 Bitmap *tmp_bitmap_32 = NULL;
1246 int width_final, height_final;
1247 int width_0, height_0;
1248 int width_1, height_1;
1249 int width_2, height_2;
1250 int width_4, height_4;
1251 int width_8, height_8;
1252 int width_16, height_16;
1253 int width_32, height_32;
1254 int old_width, old_height;
1257 print_timestamp_init("CreateScaledBitmaps");
1259 old_width = old_bitmap->width;
1260 old_height = old_bitmap->height;
1262 // calculate new image dimensions for final image size
1263 width_final = old_width * zoom_factor;
1264 height_final = old_height * zoom_factor;
1266 // get image with final size (this might require scaling up)
1267 // ("final" size may result in non-standard tile size image)
1268 if (zoom_factor != 1)
1269 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1271 tmp_bitmap_final = old_bitmap;
1273 UPDATE_BUSY_STATE();
1275 width_0 = width_1 = width_final;
1276 height_0 = height_1 = height_final;
1278 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1280 if (create_small_bitmaps)
1282 // check if we have a non-gameplay tile size image
1283 if (tile_size != gfx.game_tile_size)
1285 // get image with gameplay tile size
1286 width_0 = width_final * gfx.game_tile_size / tile_size;
1287 height_0 = height_final * gfx.game_tile_size / tile_size;
1289 if (width_0 == old_width)
1290 tmp_bitmap_0 = old_bitmap;
1291 else if (width_0 == width_final)
1292 tmp_bitmap_0 = tmp_bitmap_final;
1294 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1296 UPDATE_BUSY_STATE();
1299 // check if we have a non-standard tile size image
1300 if (tile_size != gfx.standard_tile_size)
1302 // get image with standard tile size
1303 width_1 = width_final * gfx.standard_tile_size / tile_size;
1304 height_1 = height_final * gfx.standard_tile_size / tile_size;
1306 if (width_1 == old_width)
1307 tmp_bitmap_1 = old_bitmap;
1308 else if (width_1 == width_final)
1309 tmp_bitmap_1 = tmp_bitmap_final;
1310 else if (width_1 == width_0)
1311 tmp_bitmap_1 = tmp_bitmap_0;
1313 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1315 UPDATE_BUSY_STATE();
1318 // calculate new image dimensions for small images
1319 width_2 = width_1 / 2;
1320 height_2 = height_1 / 2;
1321 width_4 = width_1 / 4;
1322 height_4 = height_1 / 4;
1323 width_8 = width_1 / 8;
1324 height_8 = height_1 / 8;
1325 width_16 = width_1 / 16;
1326 height_16 = height_1 / 16;
1327 width_32 = width_1 / 32;
1328 height_32 = height_1 / 32;
1330 // get image with 1/2 of normal size (for use in the level editor)
1331 if (width_2 == old_width)
1332 tmp_bitmap_2 = old_bitmap;
1334 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1336 UPDATE_BUSY_STATE();
1338 // get image with 1/4 of normal size (for use in the level editor)
1339 if (width_4 == old_width)
1340 tmp_bitmap_4 = old_bitmap;
1342 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1344 UPDATE_BUSY_STATE();
1346 // get image with 1/8 of normal size (for use on the preview screen)
1347 if (width_8 == old_width)
1348 tmp_bitmap_8 = old_bitmap;
1350 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1352 UPDATE_BUSY_STATE();
1354 // get image with 1/16 of normal size (for use on the preview screen)
1355 if (width_16 == old_width)
1356 tmp_bitmap_16 = old_bitmap;
1358 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1360 UPDATE_BUSY_STATE();
1362 // get image with 1/32 of normal size (for use on the preview screen)
1363 if (width_32 == old_width)
1364 tmp_bitmap_32 = old_bitmap;
1366 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1368 UPDATE_BUSY_STATE();
1370 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1371 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1372 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1373 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1374 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1375 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1377 if (width_0 != width_1)
1378 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1380 if (bitmaps[IMG_BITMAP_CUSTOM])
1381 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1383 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1385 boolean free_old_bitmap = TRUE;
1387 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1388 if (bitmaps[i] == old_bitmap)
1389 free_old_bitmap = FALSE;
1391 if (free_old_bitmap)
1393 // copy image filename from old to new standard sized bitmap
1394 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1395 getStringCopy(old_bitmap->source_filename);
1397 FreeBitmap(old_bitmap);
1402 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1405 UPDATE_BUSY_STATE();
1407 print_timestamp_done("CreateScaledBitmaps");
1410 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1413 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1416 void CreateBitmapTextures(Bitmap **bitmaps)
1418 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1421 void FreeBitmapTextures(Bitmap **bitmaps)
1423 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1426 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1428 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1432 // ----------------------------------------------------------------------------
1433 // mouse pointer functions
1434 // ----------------------------------------------------------------------------
1436 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1438 // XPM image definitions
1439 static const char *cursor_image_none[] =
1441 // width height num_colors chars_per_pixel
1471 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1472 static const char *cursor_image_dot[] =
1474 // width height num_colors chars_per_pixel
1503 static const char **cursor_image_playfield = cursor_image_dot;
1505 // some people complained about a "white dot" on the screen and thought it
1506 // was a graphical error... OK, let's just remove the whole pointer :-)
1507 static const char **cursor_image_playfield = cursor_image_none;
1510 static const int cursor_bit_order = BIT_ORDER_MSB;
1512 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1514 struct MouseCursorInfo *cursor;
1515 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1516 int header_lines = 4;
1519 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1521 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1524 for (y = 0; y < cursor->width; y++)
1526 for (x = 0; x < cursor->height; x++)
1529 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1534 cursor->data[i] = cursor->mask[i] = 0;
1537 switch (image[header_lines + y][x])
1540 cursor->data[i] |= bit_mask;
1541 cursor->mask[i] |= bit_mask;
1545 cursor->mask[i] |= bit_mask;
1554 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1559 void SetMouseCursor(int mode)
1561 static struct MouseCursorInfo *cursor_none = NULL;
1562 static struct MouseCursorInfo *cursor_playfield = NULL;
1563 struct MouseCursorInfo *cursor_new;
1564 int mode_final = mode;
1566 if (cursor_none == NULL)
1567 cursor_none = get_cursor_from_image(cursor_image_none);
1569 if (cursor_playfield == NULL)
1570 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1572 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1573 mode_final = gfx.cursor_mode_override;
1575 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1576 mode_final == CURSOR_NONE ? cursor_none :
1577 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1579 SDLSetMouseCursor(cursor_new);
1581 gfx.cursor_mode = mode;
1582 gfx.cursor_mode_final = mode_final;
1585 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1587 // mouse events do not contain logical screen size corrections yet
1588 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1590 mouse_x -= video.screen_xoffset;
1591 mouse_y -= video.screen_yoffset;
1593 gfx.mouse_x = mouse_x;
1594 gfx.mouse_y = mouse_y;
1597 void UpdateMousePosition(void)
1599 int mouse_x, mouse_y;
1602 SDL_GetMouseState(&mouse_x, &mouse_y);
1604 UpdateRawMousePosition(mouse_x, mouse_y);
1608 // ============================================================================
1610 // ============================================================================
1612 void OpenAudio(void)
1614 // always start with reliable default values
1615 audio.sound_available = FALSE;
1616 audio.music_available = FALSE;
1617 audio.loops_available = FALSE;
1619 audio.sound_enabled = FALSE;
1620 audio.sound_deactivated = FALSE;
1622 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1623 audio.mixer_pid = 0;
1624 audio.device_name = NULL;
1625 audio.device_fd = -1;
1627 audio.num_channels = 0;
1628 audio.music_channel = 0;
1629 audio.first_sound_channel = 0;
1634 void CloseAudio(void)
1638 audio.sound_enabled = FALSE;
1641 void SetAudioMode(boolean enabled)
1643 if (!audio.sound_available)
1646 audio.sound_enabled = enabled;
1650 // ============================================================================
1652 // ============================================================================
1654 void InitEventFilter(EventFilter filter_function)
1656 SDL_SetEventFilter(filter_function, NULL);
1659 boolean PendingEvent(void)
1661 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1664 void WaitEvent(Event *event)
1666 SDLWaitEvent(event);
1669 void PeekEvent(Event *event)
1671 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1674 void PumpEvents(void)
1679 void CheckQuitEvent(void)
1681 if (SDL_QuitRequested())
1682 program.exit_function(0);
1685 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1687 // key up/down events in SDL2 do not return text characters anymore
1688 return event->keysym.sym;
1691 KeyMod HandleKeyModState(Key key, int key_status)
1693 static KeyMod current_modifiers = KMOD_None;
1695 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1697 KeyMod new_modifier = KMOD_None;
1702 new_modifier = KMOD_Shift_L;
1705 new_modifier = KMOD_Shift_R;
1707 case KSYM_Control_L:
1708 new_modifier = KMOD_Control_L;
1710 case KSYM_Control_R:
1711 new_modifier = KMOD_Control_R;
1714 new_modifier = KMOD_Meta_L;
1717 new_modifier = KMOD_Meta_R;
1720 new_modifier = KMOD_Alt_L;
1723 new_modifier = KMOD_Alt_R;
1729 if (key_status == KEY_PRESSED)
1730 current_modifiers |= new_modifier;
1732 current_modifiers &= ~new_modifier;
1735 return current_modifiers;
1738 KeyMod GetKeyModState(void)
1740 return (KeyMod)SDL_GetModState();
1743 KeyMod GetKeyModStateFromEvents(void)
1745 /* always use key modifier state as tracked from key events (this is needed
1746 if the modifier key event was injected into the event queue, but the key
1747 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1748 query the keys as held pressed on the keyboard) -- this case is currently
1749 only used to filter out clipboard insert events from "True X-Mouse" tool */
1751 return HandleKeyModState(KSYM_UNDEFINED, 0);
1754 void StartTextInput(int x, int y, int width, int height)
1756 #if defined(HAS_SCREEN_KEYBOARD)
1757 SDL_StartTextInput();
1759 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1761 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1762 video.shifted_up_delay = SDL_GetTicks();
1763 video.shifted_up = TRUE;
1768 void StopTextInput(void)
1770 #if defined(HAS_SCREEN_KEYBOARD)
1771 SDL_StopTextInput();
1773 if (video.shifted_up)
1775 video.shifted_up_pos = 0;
1776 video.shifted_up_delay = SDL_GetTicks();
1777 video.shifted_up = FALSE;
1782 void PushUserEvent(int code, int value1, int value2)
1786 SDL_memset(&event, 0, sizeof(event));
1788 event.type = EVENT_USER;
1790 event.value1 = value1;
1791 event.value2 = value2;
1793 SDL_PushEvent((SDL_Event *)&event);
1797 // ============================================================================
1798 // joystick functions
1799 // ============================================================================
1801 void InitJoysticks(void)
1805 #if defined(NO_JOYSTICK)
1806 return; // joysticks generally deactivated by compile-time directive
1809 // always start with reliable default values
1810 joystick.status = JOYSTICK_NOT_AVAILABLE;
1811 for (i = 0; i < MAX_PLAYERS; i++)
1812 joystick.nr[i] = -1; // no joystick configured
1817 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1819 return SDLReadJoystick(nr, x, y, b1, b2);
1822 boolean CheckJoystickOpened(int nr)
1824 return SDLCheckJoystickOpened(nr);
1827 void ClearJoystickState(void)
1829 SDLClearJoystickState();