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 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 LevelSetInfo levelset;
49 struct LevelStats level_stats[MAX_LEVELS];
51 DrawWindow *window = NULL;
52 DrawBuffer *backbuffer = NULL;
53 DrawBuffer *drawto = NULL;
55 int button_status = MB_NOT_PRESSED;
56 boolean motion_status = FALSE;
57 int wheel_steps = DEFAULT_WHEEL_STEPS;
58 boolean keyrepeat_status = TRUE;
60 int redraw_mask = REDRAW_NONE;
65 // ============================================================================
66 // init/close functions
67 // ============================================================================
69 void InitProgramInfo(char *argv0, char *config_filename, char *userdata_subdir,
70 char *program_title, char *icon_title,
71 char *icon_filename, char *cookie_prefix,
72 char *program_version_string, int program_version)
74 program.command_basepath = getBasePath(argv0);
75 program.command_basename = getBaseName(argv0);
77 program.config_filename = config_filename;
79 program.userdata_subdir = userdata_subdir;
80 program.userdata_path = getUserGameDataDir();
82 program.program_title = program_title;
83 program.window_title = "(undefined)";
84 program.icon_title = icon_title;
86 program.icon_filename = icon_filename;
88 program.cookie_prefix = cookie_prefix;
90 program.version_super = VERSION_SUPER(program_version);
91 program.version_major = VERSION_MAJOR(program_version);
92 program.version_minor = VERSION_MINOR(program_version);
93 program.version_patch = VERSION_PATCH(program_version);
94 program.version_ident = program_version;
96 program.version_string = program_version_string;
98 program.log_filename[LOG_OUT_ID] = getLogFilename(LOG_OUT_BASENAME);
99 program.log_filename[LOG_ERR_ID] = getLogFilename(LOG_ERR_BASENAME);
100 program.log_file[LOG_OUT_ID] = program.log_file_default[LOG_OUT_ID] = stdout;
101 program.log_file[LOG_ERR_ID] = program.log_file_default[LOG_ERR_ID] = stderr;
103 program.headless = FALSE;
106 void InitNetworkInfo(boolean enabled, boolean connected, boolean serveronly,
107 char *server_host, int server_port)
109 network.enabled = enabled;
110 network.connected = connected;
111 network.serveronly = serveronly;
113 network.server_host = server_host;
114 network.server_port = server_port;
117 void InitScoresInfo(void)
119 char *global_scores_dir = getPath2(getCommonDataDir(), SCORES_DIRECTORY);
121 program.global_scores = directoryExists(global_scores_dir);
122 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.");
141 free(global_scores_dir);
144 void SetWindowTitle(void)
146 program.window_title = program.window_title_function();
151 void InitWindowTitleFunction(char *(*window_title_function)(void))
153 program.window_title_function = window_title_function;
156 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
158 program.exit_message_function = exit_message_function;
161 void InitExitFunction(void (*exit_function)(int))
163 program.exit_function = exit_function;
165 // set signal handlers to custom exit function
166 // signal(SIGINT, exit_function);
167 signal(SIGTERM, exit_function);
169 // set exit function to automatically cleanup SDL stuff after exit()
173 void InitPlatformDependentStuff(void)
175 // this is initialized in GetOptions(), but may already be used before
176 options.verbose = TRUE;
180 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
182 if (SDL_Init(sdl_init_flags) < 0)
183 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
188 void ClosePlatformDependentStuff(void)
193 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
194 int real_sx, int real_sy,
195 int full_sxsize, int full_sysize,
196 Bitmap *field_save_buffer)
202 gfx.real_sx = real_sx;
203 gfx.real_sy = real_sy;
204 gfx.full_sxsize = full_sxsize;
205 gfx.full_sysize = full_sysize;
207 gfx.field_save_buffer = field_save_buffer;
209 SetDrawDeactivationMask(REDRAW_NONE); // do not deactivate drawing
210 SetDrawBackgroundMask(REDRAW_NONE); // deactivate masked drawing
213 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
215 gfx.game_tile_size = game_tile_size;
216 gfx.standard_tile_size = standard_tile_size;
219 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
227 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
235 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
243 void InitGfxWindowInfo(int win_xsize, int win_ysize)
245 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
247 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
249 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
251 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
252 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
253 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
254 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
256 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
259 gfx.win_xsize = win_xsize;
260 gfx.win_ysize = win_ysize;
262 gfx.background_bitmap_mask = REDRAW_NONE;
265 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
267 // currently only used by MSDOS code to alloc VRAM buffer, if available
268 // 2009-03-24: also (temporarily?) used for overlapping blit workaround
269 gfx.scrollbuffer_width = scrollbuffer_width;
270 gfx.scrollbuffer_height = scrollbuffer_height;
273 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
275 gfx.clipping_enabled = enabled;
278 gfx.clip_width = width;
279 gfx.clip_height = height;
282 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
284 gfx.draw_busy_anim_function = draw_busy_anim_function;
287 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
289 gfx.draw_global_anim_function = draw_global_anim_function;
292 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
294 gfx.draw_global_border_function = draw_global_border_function;
297 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
299 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
302 void InitGfxCustomArtworkInfo(void)
304 gfx.override_level_graphics = FALSE;
305 gfx.override_level_sounds = FALSE;
306 gfx.override_level_music = FALSE;
308 gfx.draw_init_text = TRUE;
311 void InitGfxOtherSettings(void)
313 gfx.cursor_mode = CURSOR_DEFAULT;
316 void InitTileCursorInfo(void)
318 tile_cursor.enabled = FALSE;
319 tile_cursor.active = FALSE;
320 tile_cursor.moving = FALSE;
322 tile_cursor.xpos = 0;
323 tile_cursor.ypos = 0;
326 tile_cursor.target_x = 0;
327 tile_cursor.target_y = 0;
333 void InitOverlayInfo(void)
335 int nr = GRID_ACTIVE_NR();
338 overlay.enabled = FALSE;
339 overlay.active = FALSE;
341 overlay.show_grid = FALSE;
343 overlay.grid_xsize = setup.touch.grid_xsize[nr];
344 overlay.grid_ysize = setup.touch.grid_ysize[nr];
346 for (x = 0; x < MAX_GRID_XSIZE; x++)
347 for (y = 0; y < MAX_GRID_YSIZE; y++)
348 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
350 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
351 overlay.grid_button_action = JOY_NO_ACTION;
353 #if defined(USE_TOUCH_INPUT_OVERLAY)
354 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
355 overlay.enabled = TRUE;
359 void SetTileCursorEnabled(boolean enabled)
361 tile_cursor.enabled = enabled;
364 void SetTileCursorActive(boolean active)
366 tile_cursor.active = active;
369 void SetTileCursorTargetXY(int x, int y)
371 // delayed placement of tile selection cursor at target position
372 // (tile cursor will be moved to target position step by step)
374 tile_cursor.xpos = x;
375 tile_cursor.ypos = y;
376 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
377 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
379 tile_cursor.moving = TRUE;
382 void SetTileCursorXY(int x, int y)
384 // immediate placement of tile selection cursor at target position
386 SetTileCursorTargetXY(x, y);
388 tile_cursor.x = tile_cursor.target_x;
389 tile_cursor.y = tile_cursor.target_y;
391 tile_cursor.moving = FALSE;
394 void SetTileCursorSXSY(int sx, int sy)
400 void SetOverlayEnabled(boolean enabled)
402 overlay.enabled = enabled;
405 void SetOverlayActive(boolean active)
407 overlay.active = active;
410 void SetOverlayShowGrid(boolean show_grid)
412 overlay.show_grid = show_grid;
414 SetOverlayActive(show_grid);
417 SetOverlayEnabled(TRUE);
420 boolean GetOverlayActive(void)
422 return overlay.active;
425 void SetDrawDeactivationMask(int draw_deactivation_mask)
427 gfx.draw_deactivation_mask = draw_deactivation_mask;
430 int GetDrawDeactivationMask(void)
432 return gfx.draw_deactivation_mask;
435 void SetDrawBackgroundMask(int draw_background_mask)
437 gfx.draw_background_mask = draw_background_mask;
440 static void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
442 if (background_bitmap_tile != NULL)
443 gfx.background_bitmap_mask |= mask;
445 gfx.background_bitmap_mask &= ~mask;
447 if (background_bitmap_tile == NULL) // empty background requested
450 if (mask == REDRAW_ALL)
451 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
452 0, 0, video.width, video.height);
453 else if (mask == REDRAW_FIELD)
454 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
455 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
456 else if (mask == REDRAW_DOOR_1)
457 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
458 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
461 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
463 // remove every mask before setting mask for window
464 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
465 SetBackgroundBitmap(NULL, 0xffff); // !!! FIX THIS !!!
466 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
469 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
471 // remove window area mask before setting mask for main area
472 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
473 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
474 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
477 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
479 // remove window area mask before setting mask for door area
480 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
481 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
482 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
486 // ============================================================================
488 // ============================================================================
490 static int GetRealDepth(int depth)
492 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
495 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
496 int width, int height, Pixel color)
498 SDLFillRectangle(bitmap, x, y, width, height, color);
500 if (bitmap == backbuffer)
501 SetRedrawMaskFromArea(x, y, width, height);
504 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
505 int src_x, int src_y, int width, int height,
506 int dst_x, int dst_y, int mask_mode)
508 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
509 dst_x, dst_y, mask_mode);
511 if (dst_bitmap == backbuffer)
512 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
515 void LimitScreenUpdates(boolean enable)
517 SDLLimitScreenUpdates(enable);
520 void InitVideoDefaults(void)
522 video.default_depth = 32;
525 void InitVideoDisplay(void)
527 if (program.headless)
530 SDLInitVideoDisplay();
534 void CloseVideoDisplay(void)
536 KeyboardAutoRepeatOn();
538 SDL_QuitSubSystem(SDL_INIT_VIDEO);
541 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
544 video.height = height;
545 video.depth = GetRealDepth(depth);
547 video.screen_width = width;
548 video.screen_height = height;
549 video.screen_xoffset = 0;
550 video.screen_yoffset = 0;
552 video.fullscreen_available = FULLSCREEN_STATUS;
553 video.fullscreen_enabled = FALSE;
555 video.window_scaling_available = WINDOW_SCALING_STATUS;
557 video.frame_delay = 0;
558 video.frame_delay_value = GAME_FRAME_DELAY;
560 video.shifted_up = FALSE;
561 video.shifted_up_pos = 0;
562 video.shifted_up_pos_last = 0;
563 video.shifted_up_delay = 0;
564 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
566 SDLInitVideoBuffer(fullscreen);
568 video.initialized = !program.headless;
573 static void FreeBitmapPointers(Bitmap *bitmap)
578 SDLFreeBitmapPointers(bitmap);
580 checked_free(bitmap->source_filename);
581 bitmap->source_filename = NULL;
584 static void TransferBitmapPointers(Bitmap *src_bitmap,
587 if (src_bitmap == NULL || dst_bitmap == NULL)
590 FreeBitmapPointers(dst_bitmap);
592 *dst_bitmap = *src_bitmap;
595 void FreeBitmap(Bitmap *bitmap)
600 FreeBitmapPointers(bitmap);
605 Bitmap *CreateBitmapStruct(void)
607 return checked_calloc(sizeof(Bitmap));
610 Bitmap *CreateBitmap(int width, int height, int depth)
612 Bitmap *new_bitmap = CreateBitmapStruct();
613 int real_width = MAX(1, width); // prevent zero bitmap width
614 int real_height = MAX(1, height); // prevent zero bitmap height
615 int real_depth = GetRealDepth(depth);
617 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
619 new_bitmap->width = real_width;
620 new_bitmap->height = real_height;
625 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
629 // if new bitmap size fits into old one, no need to re-create it
630 if (width <= (*bitmap)->width &&
631 height <= (*bitmap)->height)
634 // else adjust size so that old and new bitmap size fit into it
635 width = MAX(width, (*bitmap)->width);
636 height = MAX(height, (*bitmap)->height);
639 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
643 *bitmap = new_bitmap;
647 TransferBitmapPointers(new_bitmap, *bitmap);
653 static void CloseWindow(DrawWindow *window)
658 void SetRedrawMaskFromArea(int x, int y, int width, int height)
662 int x2 = x + width - 1;
663 int y2 = y + height - 1;
665 if (width == 0 || height == 0)
668 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
669 redraw_mask |= REDRAW_FIELD;
670 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
671 redraw_mask |= REDRAW_DOOR_1;
672 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
673 redraw_mask |= REDRAW_DOOR_2;
674 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
675 redraw_mask |= REDRAW_DOOR_3;
677 redraw_mask = REDRAW_ALL;
680 static boolean CheckDrawingArea(int x, int y, int width, int height,
683 if (draw_mask == REDRAW_NONE)
686 if (draw_mask & REDRAW_ALL)
689 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
692 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
695 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
698 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
704 boolean DrawingDeactivatedField(void)
706 if (program.headless)
709 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
715 boolean DrawingDeactivated(int x, int y, int width, int height)
717 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
720 boolean DrawingOnBackground(int x, int y)
722 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
723 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
726 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
727 int *width, int *height, boolean is_dest)
729 int clip_x, clip_y, clip_width, clip_height;
731 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
733 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
734 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
735 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
736 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
742 clip_width = bitmap->width;
743 clip_height = bitmap->height;
746 // skip if rectangle completely outside bitmap
748 if (*x + *width <= clip_x ||
749 *y + *height <= clip_y ||
750 *x >= clip_x + clip_width ||
751 *y >= clip_y + clip_height)
754 // clip if rectangle overlaps bitmap
758 *width -= clip_x - *x;
761 else if (*x + *width > clip_x + clip_width)
763 *width = clip_x + clip_width - *x;
768 *height -= clip_y - *y;
771 else if (*y + *height > clip_y + clip_height)
773 *height = clip_y + clip_height - *y;
779 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
780 int src_x, int src_y, int width, int height,
781 int dst_x, int dst_y)
783 int dst_x_unclipped = dst_x;
784 int dst_y_unclipped = dst_y;
786 if (program.headless)
789 if (src_bitmap == NULL || dst_bitmap == NULL)
792 if (DrawingDeactivated(dst_x, dst_y, width, height))
795 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
796 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
799 // source x/y might need adjustment if destination x/y was clipped top/left
800 src_x += dst_x - dst_x_unclipped;
801 src_y += dst_y - dst_y_unclipped;
803 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
804 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
805 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
806 but is already fixed in SVN and should therefore finally be fixed with
807 the next official SDL release, which is probably version 1.2.14.) */
808 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
810 if (src_bitmap == dst_bitmap)
812 // needed when blitting directly to same bitmap -- should not be needed with
813 // recent SDL libraries, but apparently does not work in 1.2.11 directly
815 static Bitmap *tmp_bitmap = NULL;
816 static int tmp_bitmap_xsize = 0;
817 static int tmp_bitmap_ysize = 0;
819 // start with largest static bitmaps for initial bitmap size ...
820 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
822 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
823 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
826 // ... and allow for later re-adjustments due to custom artwork bitmaps
827 if (src_bitmap->width > tmp_bitmap_xsize ||
828 src_bitmap->height > tmp_bitmap_ysize)
830 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
831 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
833 FreeBitmap(tmp_bitmap);
838 if (tmp_bitmap == NULL)
839 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
842 sysCopyArea(src_bitmap, tmp_bitmap,
843 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
844 sysCopyArea(tmp_bitmap, dst_bitmap,
845 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
850 sysCopyArea(src_bitmap, dst_bitmap,
851 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
854 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
855 int src_x, int src_y, int src_width, int src_height,
856 int dst_x, int dst_y, int dst_width, int dst_height)
858 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
859 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
860 int dst_xsize = dst_width;
861 int dst_ysize = dst_height;
862 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
863 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
866 for (y = 0; y < src_ysteps; y++)
868 for (x = 0; x < src_xsteps; x++)
870 int draw_x = dst_x + x * src_xsize;
871 int draw_y = dst_y + y * src_ysize;
872 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
873 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
875 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
881 void FadeRectangle(int x, int y, int width, int height,
882 int fade_mode, int fade_delay, int post_delay,
883 void (*draw_border_function)(void))
885 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
886 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
889 SDLFadeRectangle(x, y, width, height,
890 fade_mode, fade_delay, post_delay, draw_border_function);
893 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
896 if (DrawingDeactivated(x, y, width, height))
899 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
902 sysFillRectangle(bitmap, x, y, width, height, color);
905 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
907 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
910 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
911 int width, int height)
913 if (DrawingOnBackground(x, y))
914 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
916 ClearRectangle(bitmap, x, y, width, height);
919 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
920 int src_x, int src_y, int width, int height,
921 int dst_x, int dst_y)
923 if (DrawingDeactivated(dst_x, dst_y, width, height))
926 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
927 dst_x, dst_y, BLIT_MASKED);
930 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
931 int src_x, int src_y, int width, int height,
932 int dst_x, int dst_y)
934 if (DrawingOnBackground(dst_x, dst_y))
937 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
941 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
945 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
949 void BlitTexture(Bitmap *bitmap,
950 int src_x, int src_y, int width, int height,
951 int dst_x, int dst_y)
956 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
960 void BlitTextureMasked(Bitmap *bitmap,
961 int src_x, int src_y, int width, int height,
962 int dst_x, int dst_y)
967 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
971 void BlitToScreen(Bitmap *bitmap,
972 int src_x, int src_y, int width, int height,
973 int dst_x, int dst_y)
978 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
979 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
980 width, height, dst_x, dst_y);
982 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
985 void BlitToScreenMasked(Bitmap *bitmap,
986 int src_x, int src_y, int width, int height,
987 int dst_x, int dst_y)
992 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
993 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
994 width, height, dst_x, dst_y);
996 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
999 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1002 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1005 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1008 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1011 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1012 int to_x, int to_y, Pixel pixel, int line_width)
1016 if (program.headless)
1019 for (x = 0; x < line_width; x++)
1021 for (y = 0; y < line_width; y++)
1023 int dx = x - line_width / 2;
1024 int dy = y - line_width / 2;
1026 if ((x == 0 && y == 0) ||
1027 (x == 0 && y == line_width - 1) ||
1028 (x == line_width - 1 && y == 0) ||
1029 (x == line_width - 1 && y == line_width - 1))
1033 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1038 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1043 for (i = 0; i < num_points - 1; i++)
1044 DrawLine(bitmap, points[i].x, points[i].y,
1045 points[i + 1].x, points[i + 1].y, pixel, line_width);
1048 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1052 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1054 if (program.headless)
1057 if (x < 0 || x >= bitmap->width ||
1058 y < 0 || y >= bitmap->height)
1061 return SDLGetPixel(bitmap, x, y);
1064 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1065 unsigned int color_g, unsigned int color_b)
1067 if (program.headless)
1070 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1073 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1075 unsigned int color_r = (color >> 16) & 0xff;
1076 unsigned int color_g = (color >> 8) & 0xff;
1077 unsigned int color_b = (color >> 0) & 0xff;
1079 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1082 void KeyboardAutoRepeatOn(void)
1084 keyrepeat_status = TRUE;
1087 void KeyboardAutoRepeatOff(void)
1089 keyrepeat_status = FALSE;
1092 boolean SetVideoMode(boolean fullscreen)
1094 return SDLSetVideoMode(fullscreen);
1097 void SetVideoFrameDelay(unsigned int frame_delay_value)
1099 video.frame_delay_value = frame_delay_value;
1102 unsigned int GetVideoFrameDelay(void)
1104 return video.frame_delay_value;
1107 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1109 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1110 (!fullscreen && video.fullscreen_enabled))
1111 fullscreen = SetVideoMode(fullscreen);
1116 Bitmap *LoadImage(char *filename)
1120 new_bitmap = SDLLoadImage(filename);
1123 new_bitmap->source_filename = getStringCopy(filename);
1128 Bitmap *LoadCustomImage(char *basename)
1130 char *filename = getCustomImageFilename(basename);
1133 if (filename == NULL)
1134 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1136 if ((new_bitmap = LoadImage(filename)) == NULL)
1137 Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError());
1142 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1144 char *filename = getCustomImageFilename(basename);
1147 if (filename == NULL) // (should never happen)
1149 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1153 if (strEqual(filename, bitmap->source_filename))
1155 // The old and new image are the same (have the same filename and path).
1156 // This usually means that this image does not exist in this graphic set
1157 // and a fallback to the existing image is done.
1162 if ((new_bitmap = LoadImage(filename)) == NULL)
1164 Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError());
1168 if (bitmap->width != new_bitmap->width ||
1169 bitmap->height != new_bitmap->height)
1171 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1173 FreeBitmap(new_bitmap);
1177 TransferBitmapPointers(new_bitmap, bitmap);
1181 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1183 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1186 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1188 if (bitmaps[IMG_BITMAP_CUSTOM])
1190 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1192 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1195 if (gfx.game_tile_size == gfx.standard_tile_size)
1197 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1202 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1203 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1204 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1206 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1208 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1209 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1212 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1213 int tile_size, boolean create_small_bitmaps)
1215 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1216 Bitmap *tmp_bitmap_final = NULL;
1217 Bitmap *tmp_bitmap_0 = NULL;
1218 Bitmap *tmp_bitmap_1 = NULL;
1219 Bitmap *tmp_bitmap_2 = NULL;
1220 Bitmap *tmp_bitmap_4 = NULL;
1221 Bitmap *tmp_bitmap_8 = NULL;
1222 Bitmap *tmp_bitmap_16 = NULL;
1223 Bitmap *tmp_bitmap_32 = NULL;
1224 int width_final, height_final;
1225 int width_0, height_0;
1226 int width_1, height_1;
1227 int width_2, height_2;
1228 int width_4, height_4;
1229 int width_8, height_8;
1230 int width_16, height_16;
1231 int width_32, height_32;
1232 int old_width, old_height;
1235 print_timestamp_init("CreateScaledBitmaps");
1237 old_width = old_bitmap->width;
1238 old_height = old_bitmap->height;
1240 // calculate new image dimensions for final image size
1241 width_final = old_width * zoom_factor;
1242 height_final = old_height * zoom_factor;
1244 // get image with final size (this might require scaling up)
1245 // ("final" size may result in non-standard tile size image)
1246 if (zoom_factor != 1)
1247 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1249 tmp_bitmap_final = old_bitmap;
1251 UPDATE_BUSY_STATE();
1253 width_0 = width_1 = width_final;
1254 height_0 = height_1 = height_final;
1256 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1258 if (create_small_bitmaps)
1260 // check if we have a non-gameplay tile size image
1261 if (tile_size != gfx.game_tile_size)
1263 // get image with gameplay tile size
1264 width_0 = width_final * gfx.game_tile_size / tile_size;
1265 height_0 = height_final * gfx.game_tile_size / tile_size;
1267 if (width_0 == old_width)
1268 tmp_bitmap_0 = old_bitmap;
1269 else if (width_0 == width_final)
1270 tmp_bitmap_0 = tmp_bitmap_final;
1272 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1274 UPDATE_BUSY_STATE();
1277 // check if we have a non-standard tile size image
1278 if (tile_size != gfx.standard_tile_size)
1280 // get image with standard tile size
1281 width_1 = width_final * gfx.standard_tile_size / tile_size;
1282 height_1 = height_final * gfx.standard_tile_size / tile_size;
1284 if (width_1 == old_width)
1285 tmp_bitmap_1 = old_bitmap;
1286 else if (width_1 == width_final)
1287 tmp_bitmap_1 = tmp_bitmap_final;
1288 else if (width_1 == width_0)
1289 tmp_bitmap_1 = tmp_bitmap_0;
1291 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1293 UPDATE_BUSY_STATE();
1296 // calculate new image dimensions for small images
1297 width_2 = width_1 / 2;
1298 height_2 = height_1 / 2;
1299 width_4 = width_1 / 4;
1300 height_4 = height_1 / 4;
1301 width_8 = width_1 / 8;
1302 height_8 = height_1 / 8;
1303 width_16 = width_1 / 16;
1304 height_16 = height_1 / 16;
1305 width_32 = width_1 / 32;
1306 height_32 = height_1 / 32;
1308 // get image with 1/2 of normal size (for use in the level editor)
1309 if (width_2 == old_width)
1310 tmp_bitmap_2 = old_bitmap;
1312 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1314 UPDATE_BUSY_STATE();
1316 // get image with 1/4 of normal size (for use in the level editor)
1317 if (width_4 == old_width)
1318 tmp_bitmap_4 = old_bitmap;
1320 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1322 UPDATE_BUSY_STATE();
1324 // get image with 1/8 of normal size (for use on the preview screen)
1325 if (width_8 == old_width)
1326 tmp_bitmap_8 = old_bitmap;
1328 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1330 UPDATE_BUSY_STATE();
1332 // get image with 1/16 of normal size (for use on the preview screen)
1333 if (width_16 == old_width)
1334 tmp_bitmap_16 = old_bitmap;
1336 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1338 UPDATE_BUSY_STATE();
1340 // get image with 1/32 of normal size (for use on the preview screen)
1341 if (width_32 == old_width)
1342 tmp_bitmap_32 = old_bitmap;
1344 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1346 UPDATE_BUSY_STATE();
1348 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1349 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1350 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1351 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1352 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1353 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1355 if (width_0 != width_1)
1356 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1358 if (bitmaps[IMG_BITMAP_CUSTOM])
1359 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1361 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1363 boolean free_old_bitmap = TRUE;
1365 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1366 if (bitmaps[i] == old_bitmap)
1367 free_old_bitmap = FALSE;
1369 if (free_old_bitmap)
1371 // copy image filename from old to new standard sized bitmap
1372 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1373 getStringCopy(old_bitmap->source_filename);
1375 FreeBitmap(old_bitmap);
1380 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1383 UPDATE_BUSY_STATE();
1385 print_timestamp_done("CreateScaledBitmaps");
1388 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1391 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1394 void CreateBitmapTextures(Bitmap **bitmaps)
1396 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1399 void FreeBitmapTextures(Bitmap **bitmaps)
1401 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1404 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1406 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1410 // ----------------------------------------------------------------------------
1411 // mouse pointer functions
1412 // ----------------------------------------------------------------------------
1414 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1416 // XPM image definitions
1417 static const char *cursor_image_none[] =
1419 // width height num_colors chars_per_pixel
1449 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1450 static const char *cursor_image_dot[] =
1452 // width height num_colors chars_per_pixel
1481 static const char **cursor_image_playfield = cursor_image_dot;
1483 // some people complained about a "white dot" on the screen and thought it
1484 // was a graphical error... OK, let's just remove the whole pointer :-)
1485 static const char **cursor_image_playfield = cursor_image_none;
1488 static const int cursor_bit_order = BIT_ORDER_MSB;
1490 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1492 struct MouseCursorInfo *cursor;
1493 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1494 int header_lines = 4;
1497 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1499 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1502 for (y = 0; y < cursor->width; y++)
1504 for (x = 0; x < cursor->height; x++)
1507 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1512 cursor->data[i] = cursor->mask[i] = 0;
1515 switch (image[header_lines + y][x])
1518 cursor->data[i] |= bit_mask;
1519 cursor->mask[i] |= bit_mask;
1523 cursor->mask[i] |= bit_mask;
1532 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1537 void SetMouseCursor(int mode)
1539 static struct MouseCursorInfo *cursor_none = NULL;
1540 static struct MouseCursorInfo *cursor_playfield = NULL;
1541 struct MouseCursorInfo *cursor_new;
1543 if (cursor_none == NULL)
1544 cursor_none = get_cursor_from_image(cursor_image_none);
1546 if (cursor_playfield == NULL)
1547 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1549 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1550 mode == CURSOR_NONE ? cursor_none :
1551 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1553 SDLSetMouseCursor(cursor_new);
1555 gfx.cursor_mode = mode;
1559 // ============================================================================
1561 // ============================================================================
1563 void OpenAudio(void)
1565 // always start with reliable default values
1566 audio.sound_available = FALSE;
1567 audio.music_available = FALSE;
1568 audio.loops_available = FALSE;
1570 audio.sound_enabled = FALSE;
1571 audio.sound_deactivated = FALSE;
1573 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1574 audio.mixer_pid = 0;
1575 audio.device_name = NULL;
1576 audio.device_fd = -1;
1578 audio.num_channels = 0;
1579 audio.music_channel = 0;
1580 audio.first_sound_channel = 0;
1585 void CloseAudio(void)
1589 audio.sound_enabled = FALSE;
1592 void SetAudioMode(boolean enabled)
1594 if (!audio.sound_available)
1597 audio.sound_enabled = enabled;
1601 // ============================================================================
1603 // ============================================================================
1605 boolean PendingEvent(void)
1607 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1610 void WaitEvent(Event *event)
1612 SDLWaitEvent(event);
1615 void PeekEvent(Event *event)
1617 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1620 void CheckQuitEvent(void)
1622 if (SDL_QuitRequested())
1623 program.exit_function(0);
1626 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1628 // key up/down events in SDL2 do not return text characters anymore
1629 return event->keysym.sym;
1632 KeyMod HandleKeyModState(Key key, int key_status)
1634 static KeyMod current_modifiers = KMOD_None;
1636 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1638 KeyMod new_modifier = KMOD_None;
1643 new_modifier = KMOD_Shift_L;
1646 new_modifier = KMOD_Shift_R;
1648 case KSYM_Control_L:
1649 new_modifier = KMOD_Control_L;
1651 case KSYM_Control_R:
1652 new_modifier = KMOD_Control_R;
1655 new_modifier = KMOD_Meta_L;
1658 new_modifier = KMOD_Meta_R;
1661 new_modifier = KMOD_Alt_L;
1664 new_modifier = KMOD_Alt_R;
1670 if (key_status == KEY_PRESSED)
1671 current_modifiers |= new_modifier;
1673 current_modifiers &= ~new_modifier;
1676 return current_modifiers;
1679 KeyMod GetKeyModState(void)
1681 return (KeyMod)SDL_GetModState();
1684 KeyMod GetKeyModStateFromEvents(void)
1686 /* always use key modifier state as tracked from key events (this is needed
1687 if the modifier key event was injected into the event queue, but the key
1688 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1689 query the keys as held pressed on the keyboard) -- this case is currently
1690 only used to filter out clipboard insert events from "True X-Mouse" tool */
1692 return HandleKeyModState(KSYM_UNDEFINED, 0);
1695 void StartTextInput(int x, int y, int width, int height)
1697 #if defined(HAS_SCREEN_KEYBOARD)
1698 SDL_StartTextInput();
1700 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1702 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1703 video.shifted_up_delay = SDL_GetTicks();
1704 video.shifted_up = TRUE;
1709 void StopTextInput(void)
1711 #if defined(HAS_SCREEN_KEYBOARD)
1712 SDL_StopTextInput();
1714 if (video.shifted_up)
1716 video.shifted_up_pos = 0;
1717 video.shifted_up_delay = SDL_GetTicks();
1718 video.shifted_up = FALSE;
1723 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1725 if (event->type != EVENT_CLIENTMESSAGE)
1728 return TRUE; // the only possible message here is SDL_QUIT
1732 // ============================================================================
1733 // joystick functions
1734 // ============================================================================
1736 void InitJoysticks(void)
1740 #if defined(NO_JOYSTICK)
1741 return; // joysticks generally deactivated by compile-time directive
1744 // always start with reliable default values
1745 joystick.status = JOYSTICK_NOT_AVAILABLE;
1746 for (i = 0; i < MAX_PLAYERS; i++)
1747 joystick.nr[i] = -1; // no joystick configured
1752 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1754 return SDLReadJoystick(nr, x, y, b1, b2);
1757 boolean CheckJoystickOpened(int nr)
1759 return SDLCheckJoystickOpened(nr);
1762 void ClearJoystickState(void)
1764 SDLClearJoystickState();