1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
18 #define ENABLE_UNUSED_CODE 0 /* currently unused functions */
21 /* ========================================================================= */
23 /* ========================================================================= */
25 /* SDL internal variables */
26 #if defined(TARGET_SDL2)
27 static SDL_Window *sdl_window = NULL;
28 static SDL_Renderer *sdl_renderer = NULL;
29 static SDL_Texture *sdl_texture = NULL;
30 static boolean fullscreen_enabled = FALSE;
32 #define USE_RENDERER TRUE
35 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
36 static int fullscreen_width;
37 static int fullscreen_height;
38 static int fullscreen_xoffset;
39 static int fullscreen_yoffset;
40 static int video_xoffset;
41 static int video_yoffset;
42 static boolean limit_screen_updates = FALSE;
45 /* functions from SGE library */
46 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
48 void SDLLimitScreenUpdates(boolean enable)
50 limit_screen_updates = enable;
53 static void UpdateScreen(SDL_Rect *rect)
55 static unsigned int update_screen_delay = 0;
56 unsigned int update_screen_delay_value = 20; /* (milliseconds) */
57 SDL_Surface *screen = backbuffer->surface;
59 if (limit_screen_updates &&
60 !DelayReached(&update_screen_delay, update_screen_delay_value))
63 LimitScreenUpdates(FALSE);
67 static int LastFrameCounter = 0;
68 boolean changed = (FrameCounter != LastFrameCounter);
70 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
71 (changed ? "-" : "SAME FRAME UPDATED"));
73 LastFrameCounter = FrameCounter;
82 #if USE_FINAL_SCREEN_BITMAP
83 if (gfx.final_screen_bitmap != NULL) // may not be initialized yet
86 // draw global animations using bitmaps instead of using textures
87 // to prevent texture scaling artefacts (this is potentially slower)
89 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
90 gfx.win_xsize, gfx.win_ysize, 0, 0);
92 // copy global animations to render target buffer, if defined (below border)
93 if (gfx.draw_global_anim_function != NULL)
94 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
96 // copy global masked border to render target buffer, if defined
97 if (gfx.draw_global_border_function != NULL)
98 gfx.draw_global_border_function(REDRAW_ALL);
100 // copy global animations to render target buffer, if defined (above border)
101 if (gfx.draw_global_anim_function != NULL)
102 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
104 screen = gfx.final_screen_bitmap->surface;
106 // force full window redraw
111 #if defined(TARGET_SDL2)
115 int bytes_x = screen->pitch / video.width;
116 int bytes_y = screen->pitch;
118 if (video.fullscreen_enabled)
119 bytes_x = screen->pitch / fullscreen_width;
121 SDL_UpdateTexture(sdl_texture, rect,
122 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
127 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
130 // clear render target buffer
131 SDL_RenderClear(sdl_renderer);
133 // copy backbuffer to render target buffer
134 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
136 #if !USE_FINAL_SCREEN_BITMAP
137 // copy global animations to render target buffer, if defined (below border)
138 if (gfx.draw_global_anim_function != NULL)
139 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
141 // copy global masked border to render target buffer, if defined
142 if (gfx.draw_global_border_function != NULL)
143 gfx.draw_global_border_function(REDRAW_ALL);
145 // copy global animations to render target buffer, if defined (above border)
146 if (gfx.draw_global_anim_function != NULL)
147 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
150 // show render target buffer on screen
151 SDL_RenderPresent(sdl_renderer);
156 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
158 SDL_UpdateWindowSurface(sdl_window);
163 SDL_UpdateRects(screen, 1, rect);
165 SDL_UpdateRect(screen, 0, 0, 0, 0);
169 static void setFullscreenParameters(char *fullscreen_mode_string)
171 #if defined(TARGET_SDL2)
172 fullscreen_width = video.width;
173 fullscreen_height = video.height;
174 fullscreen_xoffset = 0;
175 fullscreen_yoffset = 0;
179 struct ScreenModeInfo *fullscreen_mode;
182 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
184 if (fullscreen_mode == NULL)
187 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
189 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
190 fullscreen_mode->height == video.fullscreen_modes[i].height)
192 fullscreen_width = fullscreen_mode->width;
193 fullscreen_height = fullscreen_mode->height;
195 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
196 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
204 static void SDLSetWindowIcon(char *basename)
206 /* (setting the window icon on Mac OS X would replace the high-quality
207 dock icon with the currently smaller (and uglier) icon from file) */
209 #if !defined(PLATFORM_MACOSX)
210 char *filename = getCustomImageFilename(basename);
211 SDL_Surface *surface;
213 if (filename == NULL)
215 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
220 if ((surface = IMG_Load(filename)) == NULL)
222 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
227 /* set transparent color */
228 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
229 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
231 #if defined(TARGET_SDL2)
232 SDL_SetWindowIcon(sdl_window, surface);
234 SDL_WM_SetIcon(surface, NULL);
239 #if defined(TARGET_SDL2)
241 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
242 SDL_PixelFormat *format2)
244 return (format1->format == format2->format &&
245 format1->BitsPerPixel == format2->BitsPerPixel &&
246 format1->BytesPerPixel == format2->BytesPerPixel &&
247 format1->Rmask == format2->Rmask &&
248 format1->Gmask == format2->Gmask &&
249 format1->Bmask == format2->Bmask &&
250 format1->Amask == format2->Amask);
253 boolean SDLSetNativeSurface(SDL_Surface **surface)
255 SDL_Surface *new_surface;
257 if (surface == NULL ||
259 backbuffer == NULL ||
260 backbuffer->surface == NULL)
263 // if pixel format already optimized for destination surface, do nothing
264 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
267 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
269 if (new_surface == NULL)
270 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
272 SDL_FreeSurface(*surface);
274 *surface = new_surface;
279 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
281 SDL_Surface *new_surface;
286 if (backbuffer && backbuffer->surface)
287 new_surface = SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
289 new_surface = SDL_ConvertSurface(surface, surface->format, 0);
291 if (new_surface == NULL)
292 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
299 boolean SDLSetNativeSurface(SDL_Surface **surface)
301 SDL_Surface *new_surface;
303 if (surface == NULL ||
308 new_surface = SDL_DisplayFormat(*surface);
310 if (new_surface == NULL)
311 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
313 SDL_FreeSurface(*surface);
315 *surface = new_surface;
320 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
322 SDL_Surface *new_surface;
324 if (video.initialized)
325 new_surface = SDL_DisplayFormat(surface);
327 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
329 if (new_surface == NULL)
330 Error(ERR_EXIT, "%s() failed: %s",
331 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
339 #if defined(TARGET_SDL2)
340 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
342 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
345 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
352 void SDLCreateBitmapTextures(Bitmap *bitmap)
354 #if defined(TARGET_SDL2)
359 SDL_DestroyTexture(bitmap->texture);
360 if (bitmap->texture_masked)
361 SDL_DestroyTexture(bitmap->texture_masked);
363 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
364 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
368 void SDLFreeBitmapTextures(Bitmap *bitmap)
370 #if defined(TARGET_SDL2)
375 SDL_DestroyTexture(bitmap->texture);
376 if (bitmap->texture_masked)
377 SDL_DestroyTexture(bitmap->texture_masked);
379 bitmap->texture = NULL;
380 bitmap->texture_masked = NULL;
384 void SDLInitVideoDisplay(void)
386 #if !defined(TARGET_SDL2)
387 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
388 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
390 SDL_putenv("SDL_VIDEO_CENTERED=1");
393 /* initialize SDL video */
394 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
395 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
397 /* set default SDL depth */
398 #if !defined(TARGET_SDL2)
399 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
401 video.default_depth = 32; // (how to determine video depth in SDL2?)
405 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
408 #if !defined(TARGET_SDL2)
409 static int screen_xy[][2] =
417 SDL_Rect **modes = NULL;
418 boolean hardware_fullscreen_available = TRUE;
421 /* default: normal game window size */
422 fullscreen_width = video.width;
423 fullscreen_height = video.height;
424 fullscreen_xoffset = 0;
425 fullscreen_yoffset = 0;
427 #if !defined(TARGET_SDL2)
428 /* determine required standard fullscreen mode for game screen size */
429 for (i = 0; screen_xy[i][0] != -1; i++)
431 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
433 fullscreen_width = screen_xy[i][0];
434 fullscreen_height = screen_xy[i][1];
440 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
441 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
444 checked_free(video.fullscreen_modes);
446 video.fullscreen_modes = NULL;
447 video.fullscreen_mode_current = NULL;
449 video.window_scaling_percent = setup.window_scaling_percent;
450 video.window_scaling_quality = setup.window_scaling_quality;
452 #if defined(TARGET_SDL2)
453 int num_displays = SDL_GetNumVideoDisplays();
455 if (num_displays > 0)
457 // currently only display modes of first display supported
458 int num_modes = SDL_GetNumDisplayModes(0);
462 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
464 for (i = 0; i < num_modes; i++)
466 SDL_DisplayMode mode;
468 if (SDL_GetDisplayMode(0, i, &mode) < 0)
471 modes[i] = checked_calloc(sizeof(SDL_Rect));
473 modes[i]->w = mode.w;
474 modes[i]->h = mode.h;
479 /* get available hardware supported fullscreen modes */
480 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
485 /* no hardware screen modes available => no fullscreen mode support */
486 // video.fullscreen_available = FALSE;
487 hardware_fullscreen_available = FALSE;
489 else if (modes == (SDL_Rect **)-1)
491 /* fullscreen resolution is not restricted -- all resolutions available */
492 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
494 /* use native video buffer size for fullscreen mode */
495 video.fullscreen_modes[0].width = video.width;
496 video.fullscreen_modes[0].height = video.height;
498 video.fullscreen_modes[1].width = -1;
499 video.fullscreen_modes[1].height = -1;
503 /* in this case, a certain number of screen modes is available */
506 for (i = 0; modes[i] != NULL; i++)
508 boolean found_mode = FALSE;
510 /* screen mode is smaller than video buffer size -- skip it */
511 if (modes[i]->w < video.width || modes[i]->h < video.height)
514 if (video.fullscreen_modes != NULL)
515 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
516 if (modes[i]->w == video.fullscreen_modes[j].width &&
517 modes[i]->h == video.fullscreen_modes[j].height)
520 if (found_mode) /* screen mode already stored -- skip it */
523 /* new mode found; add it to list of available fullscreen modes */
527 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
529 sizeof(struct ScreenModeInfo));
531 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
532 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
534 video.fullscreen_modes[num_modes].width = -1;
535 video.fullscreen_modes[num_modes].height = -1;
540 /* no appropriate screen modes available => no fullscreen mode support */
541 // video.fullscreen_available = FALSE;
542 hardware_fullscreen_available = FALSE;
546 video.fullscreen_available = hardware_fullscreen_available;
548 #if USE_DESKTOP_FULLSCREEN
549 // in SDL 2.0, there is always support for desktop fullscreen mode
550 // (in SDL 1.2, there is only support for "real" fullscreen mode)
551 video.fullscreen_available = TRUE;
554 #if defined(TARGET_SDL2)
557 for (i = 0; modes[i] != NULL; i++)
558 checked_free(modes[i]);
564 /* open SDL video output device (window or fullscreen mode) */
565 if (!SDLSetVideoMode(backbuffer, fullscreen))
566 Error(ERR_EXIT, "setting video mode failed");
568 /* !!! SDL2 can only set the window icon if the window already exists !!! */
569 /* set window icon */
570 SDLSetWindowIcon(program.icon_filename);
572 /* set window and icon title */
573 #if defined(TARGET_SDL2)
574 SDL_SetWindowTitle(sdl_window, program.window_title);
576 SDL_WM_SetCaption(program.window_title, program.window_title);
579 /* SDL cannot directly draw to the visible video framebuffer like X11,
580 but always uses a backbuffer, which is then blitted to the visible
581 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
582 visible video framebuffer with 'SDL_Flip', if the hardware supports
583 this). Therefore do not use an additional backbuffer for drawing, but
584 use a symbolic buffer (distinguishable from the SDL backbuffer) called
585 'window', which indicates that the SDL backbuffer should be updated to
586 the visible video framebuffer when attempting to blit to it.
588 For convenience, it seems to be a good idea to create this symbolic
589 buffer 'window' at the same size as the SDL backbuffer. Although it
590 should never be drawn to directly, it would do no harm nevertheless. */
592 /* create additional (symbolic) buffer for double-buffering */
593 ReCreateBitmap(window, video.width, video.height, video.depth);
596 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
599 SDL_Surface *new_surface = NULL;
601 #if defined(TARGET_SDL2)
602 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
603 #if USE_DESKTOP_FULLSCREEN
604 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
606 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
610 int surface_flags_window = SURFACE_FLAGS;
611 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
614 int width = (fullscreen ? fullscreen_width : video.width);
615 int height = (fullscreen ? fullscreen_height : video.height);
616 int surface_flags = (fullscreen ? surface_flags_fullscreen :
617 surface_flags_window);
619 // default window size is unscaled
620 video.window_width = video.width;
621 video.window_height = video.height;
623 #if defined(TARGET_SDL2)
625 // store if initial screen mode is fullscreen mode when changing screen size
626 video.fullscreen_initial = fullscreen;
629 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
630 #if !USE_DESKTOP_FULLSCREEN
631 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
634 video.window_width = window_scaling_factor * width;
635 video.window_height = window_scaling_factor * height;
637 if ((*backbuffer)->surface)
639 SDL_FreeSurface((*backbuffer)->surface);
640 (*backbuffer)->surface = NULL;
645 SDL_DestroyTexture(sdl_texture);
649 if (!(fullscreen && fullscreen_enabled))
653 SDL_DestroyRenderer(sdl_renderer);
659 SDL_DestroyWindow(sdl_window);
664 if (sdl_window == NULL)
665 sdl_window = SDL_CreateWindow(program.window_title,
666 SDL_WINDOWPOS_CENTERED,
667 SDL_WINDOWPOS_CENTERED,
668 #if USE_DESKTOP_FULLSCREEN
672 (int)(screen_scaling_factor * width),
673 (int)(screen_scaling_factor * height),
677 if (sdl_window != NULL)
680 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
681 *without* enabling 2D/3D acceleration and/or guest additions installed,
682 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
683 it will try to use accelerated graphics and apparently fails miserably) */
684 if (sdl_renderer == NULL)
685 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
687 if (sdl_renderer == NULL)
688 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
691 if (sdl_renderer != NULL)
693 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
694 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
695 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
697 sdl_texture = SDL_CreateTexture(sdl_renderer,
698 SDL_PIXELFORMAT_ARGB8888,
699 SDL_TEXTUREACCESS_STREAMING,
702 if (sdl_texture != NULL)
704 // use SDL default values for RGB masks and no alpha channel
705 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
707 if (new_surface == NULL)
708 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
713 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
718 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
723 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
729 SDL_DestroyWindow(sdl_window);
731 sdl_window = SDL_CreateWindow(program.window_title,
732 SDL_WINDOWPOS_CENTERED,
733 SDL_WINDOWPOS_CENTERED,
737 if (sdl_window != NULL)
738 new_surface = SDL_GetWindowSurface(sdl_window);
742 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
745 #if defined(TARGET_SDL2)
746 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
747 if (new_surface != NULL)
748 fullscreen_enabled = fullscreen;
754 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
756 boolean success = TRUE;
757 SDL_Surface *new_surface = NULL;
761 if (*backbuffer == NULL)
762 *backbuffer = CreateBitmapStruct();
764 /* (real bitmap might be larger in fullscreen mode with video offsets) */
765 (*backbuffer)->width = video.width;
766 (*backbuffer)->height = video.height;
768 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
770 setFullscreenParameters(setup.fullscreen_mode);
772 video_xoffset = fullscreen_xoffset;
773 video_yoffset = fullscreen_yoffset;
775 /* switch display to fullscreen mode, if available */
776 new_surface = SDLCreateScreen(backbuffer, TRUE);
778 if (new_surface == NULL)
780 /* switching display to fullscreen mode failed */
781 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
783 /* do not try it again */
784 video.fullscreen_available = FALSE;
790 (*backbuffer)->surface = new_surface;
792 video.fullscreen_enabled = TRUE;
793 video.fullscreen_mode_current = setup.fullscreen_mode;
799 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
804 /* switch display to window mode */
805 new_surface = SDLCreateScreen(backbuffer, FALSE);
807 if (new_surface == NULL)
809 /* switching display to window mode failed -- should not happen */
810 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
816 (*backbuffer)->surface = new_surface;
818 video.fullscreen_enabled = FALSE;
819 video.window_scaling_percent = setup.window_scaling_percent;
820 video.window_scaling_quality = setup.window_scaling_quality;
826 #if defined(TARGET_SDL2)
827 SDLRedrawWindow(); // map window
831 #if defined(PLATFORM_WIN32)
832 // experimental drag and drop code
834 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
837 SDL_SysWMinfo wminfo;
839 boolean wminfo_success = FALSE;
841 SDL_VERSION(&wminfo.version);
842 #if defined(TARGET_SDL2)
844 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
846 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
851 #if defined(TARGET_SDL2)
852 hwnd = wminfo.info.win.window;
854 hwnd = wminfo.window;
857 DragAcceptFiles(hwnd, TRUE);
866 void SDLSetWindowTitle()
868 #if defined(TARGET_SDL2)
869 SDL_SetWindowTitle(sdl_window, program.window_title);
871 SDL_WM_SetCaption(program.window_title, program.window_title);
875 #if defined(TARGET_SDL2)
876 void SDLSetWindowScaling(int window_scaling_percent)
878 if (sdl_window == NULL)
881 float window_scaling_factor = (float)window_scaling_percent / 100;
882 int new_window_width = (int)(window_scaling_factor * video.width);
883 int new_window_height = (int)(window_scaling_factor * video.height);
885 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
887 video.window_scaling_percent = window_scaling_percent;
888 video.window_width = new_window_width;
889 video.window_height = new_window_height;
894 void SDLSetWindowScalingQuality(char *window_scaling_quality)
896 if (sdl_texture == NULL)
899 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
901 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
902 SDL_PIXELFORMAT_ARGB8888,
903 SDL_TEXTUREACCESS_STREAMING,
904 video.width, video.height);
906 if (new_texture != NULL)
908 SDL_DestroyTexture(sdl_texture);
910 sdl_texture = new_texture;
915 video.window_scaling_quality = window_scaling_quality;
918 void SDLSetWindowFullscreen(boolean fullscreen)
920 if (sdl_window == NULL)
923 #if USE_DESKTOP_FULLSCREEN
924 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
926 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
929 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
930 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
932 // if screen size was changed in fullscreen mode, correct desktop window size
933 if (!fullscreen && video.fullscreen_initial)
935 SDLSetWindowScaling(setup.window_scaling_percent);
936 SDL_SetWindowPosition(sdl_window,
937 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
939 video.fullscreen_initial = FALSE;
943 void SDLRedrawWindow()
949 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
952 SDL_Surface *surface =
953 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
956 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
958 SDLSetNativeSurface(&surface);
960 bitmap->surface = surface;
963 void SDLFreeBitmapPointers(Bitmap *bitmap)
966 SDL_FreeSurface(bitmap->surface);
967 if (bitmap->surface_masked)
968 SDL_FreeSurface(bitmap->surface_masked);
970 bitmap->surface = NULL;
971 bitmap->surface_masked = NULL;
973 #if defined(TARGET_SDL2)
975 SDL_DestroyTexture(bitmap->texture);
976 if (bitmap->texture_masked)
977 SDL_DestroyTexture(bitmap->texture_masked);
979 bitmap->texture = NULL;
980 bitmap->texture_masked = NULL;
984 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
985 int src_x, int src_y, int width, int height,
986 int dst_x, int dst_y, int mask_mode)
988 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
989 SDL_Rect src_rect, dst_rect;
991 if (src_bitmap == backbuffer)
993 src_x += video_xoffset;
994 src_y += video_yoffset;
1000 src_rect.h = height;
1002 if (dst_bitmap == backbuffer || dst_bitmap == window)
1004 dst_x += video_xoffset;
1005 dst_y += video_yoffset;
1011 dst_rect.h = height;
1013 // if (src_bitmap != backbuffer || dst_bitmap != window)
1014 if (!(src_bitmap == backbuffer && dst_bitmap == window))
1015 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
1016 src_bitmap->surface_masked : src_bitmap->surface),
1017 &src_rect, real_dst_bitmap->surface, &dst_rect);
1019 #if defined(TARGET_SDL2)
1020 if (dst_bitmap == window)
1022 // SDL_UpdateWindowSurface(sdl_window);
1023 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1024 UpdateScreen(&dst_rect);
1027 if (dst_bitmap == window)
1029 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
1030 UpdateScreen(&dst_rect);
1035 void SDLBlitTexture(Bitmap *bitmap,
1036 int src_x, int src_y, int width, int height,
1037 int dst_x, int dst_y, int mask_mode)
1039 #if defined(TARGET_SDL2)
1041 SDL_Texture *texture;
1046 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
1048 if (texture == NULL)
1054 src_rect.h = height;
1059 dst_rect.h = height;
1061 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
1066 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
1069 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1072 if (dst_bitmap == backbuffer || dst_bitmap == window)
1083 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1085 #if defined(TARGET_SDL2)
1086 if (dst_bitmap == window)
1088 // SDL_UpdateWindowSurface(sdl_window);
1089 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
1090 UpdateScreen(&rect);
1093 if (dst_bitmap == window)
1095 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
1096 UpdateScreen(&rect);
1101 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
1102 int fade_mode, int fade_delay, int post_delay,
1103 void (*draw_border_function)(void))
1105 static boolean initialization_needed = TRUE;
1106 static SDL_Surface *surface_source = NULL;
1107 static SDL_Surface *surface_target = NULL;
1108 static SDL_Surface *surface_black = NULL;
1109 SDL_Surface *surface_screen = backbuffer->surface;
1110 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
1111 SDL_Rect src_rect, dst_rect;
1113 int src_x = x, src_y = y;
1114 int dst_x = x, dst_y = y;
1115 unsigned int time_last, time_current;
1117 // store function for drawing global masked border
1118 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
1120 // deactivate drawing of global border while fading, if needed
1121 if (draw_border_function == NULL)
1122 gfx.draw_global_border_function = NULL;
1124 /* check if screen size has changed */
1125 if (surface_source != NULL && (video.width != surface_source->w ||
1126 video.height != surface_source->h))
1128 SDL_FreeSurface(surface_source);
1129 SDL_FreeSurface(surface_target);
1130 SDL_FreeSurface(surface_black);
1132 initialization_needed = TRUE;
1138 src_rect.h = height;
1140 dst_x += video_xoffset;
1141 dst_y += video_yoffset;
1145 dst_rect.w = width; /* (ignored) */
1146 dst_rect.h = height; /* (ignored) */
1148 dst_rect2 = dst_rect;
1150 if (initialization_needed)
1152 #if defined(TARGET_SDL2)
1153 unsigned int flags = 0;
1155 unsigned int flags = SDL_SRCALPHA;
1157 /* use same surface type as screen surface */
1158 if ((surface_screen->flags & SDL_HWSURFACE))
1159 flags |= SDL_HWSURFACE;
1161 flags |= SDL_SWSURFACE;
1164 /* create surface for temporary copy of screen buffer (source) */
1165 if ((surface_source =
1166 SDL_CreateRGBSurface(flags,
1169 surface_screen->format->BitsPerPixel,
1170 surface_screen->format->Rmask,
1171 surface_screen->format->Gmask,
1172 surface_screen->format->Bmask,
1173 surface_screen->format->Amask)) == NULL)
1174 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1176 /* create surface for cross-fading screen buffer (target) */
1177 if ((surface_target =
1178 SDL_CreateRGBSurface(flags,
1181 surface_screen->format->BitsPerPixel,
1182 surface_screen->format->Rmask,
1183 surface_screen->format->Gmask,
1184 surface_screen->format->Bmask,
1185 surface_screen->format->Amask)) == NULL)
1186 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1188 /* create black surface for fading from/to black */
1189 if ((surface_black =
1190 SDL_CreateRGBSurface(flags,
1193 surface_screen->format->BitsPerPixel,
1194 surface_screen->format->Rmask,
1195 surface_screen->format->Gmask,
1196 surface_screen->format->Bmask,
1197 surface_screen->format->Amask)) == NULL)
1198 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1200 /* completely fill the surface with black color pixels */
1201 SDL_FillRect(surface_black, NULL,
1202 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1204 initialization_needed = FALSE;
1207 /* copy source and target surfaces to temporary surfaces for fading */
1208 if (fade_mode & FADE_TYPE_TRANSFORM)
1210 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1211 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1213 else if (fade_mode & FADE_TYPE_FADE_IN)
1215 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1216 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1218 else /* FADE_TYPE_FADE_OUT */
1220 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1221 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1224 time_current = SDL_GetTicks();
1226 if (fade_mode == FADE_MODE_MELT)
1228 boolean done = FALSE;
1229 int melt_pixels = 2;
1230 int melt_columns = width / melt_pixels;
1231 int ypos[melt_columns];
1232 int max_steps = height / 8 + 32;
1237 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1238 #if defined(TARGET_SDL2)
1239 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1241 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1244 ypos[0] = -GetSimpleRandom(16);
1246 for (i = 1 ; i < melt_columns; i++)
1248 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1250 ypos[i] = ypos[i - 1] + r;
1263 time_last = time_current;
1264 time_current = SDL_GetTicks();
1265 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1266 steps_final = MIN(MAX(0, steps), max_steps);
1270 done = (steps_done >= steps_final);
1272 for (i = 0 ; i < melt_columns; i++)
1280 else if (ypos[i] < height)
1285 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1287 if (ypos[i] + dy >= height)
1288 dy = height - ypos[i];
1290 /* copy part of (appearing) target surface to upper area */
1291 src_rect.x = src_x + i * melt_pixels;
1292 // src_rect.y = src_y + ypos[i];
1294 src_rect.w = melt_pixels;
1296 src_rect.h = ypos[i] + dy;
1298 dst_rect.x = dst_x + i * melt_pixels;
1299 // dst_rect.y = dst_y + ypos[i];
1302 if (steps_done >= steps_final)
1303 SDL_BlitSurface(surface_target, &src_rect,
1304 surface_screen, &dst_rect);
1308 /* copy part of (disappearing) source surface to lower area */
1309 src_rect.x = src_x + i * melt_pixels;
1311 src_rect.w = melt_pixels;
1312 src_rect.h = height - ypos[i];
1314 dst_rect.x = dst_x + i * melt_pixels;
1315 dst_rect.y = dst_y + ypos[i];
1317 if (steps_done >= steps_final)
1318 SDL_BlitSurface(surface_source, &src_rect,
1319 surface_screen, &dst_rect);
1325 src_rect.x = src_x + i * melt_pixels;
1327 src_rect.w = melt_pixels;
1328 src_rect.h = height;
1330 dst_rect.x = dst_x + i * melt_pixels;
1333 if (steps_done >= steps_final)
1334 SDL_BlitSurface(surface_target, &src_rect,
1335 surface_screen, &dst_rect);
1339 if (steps_done >= steps_final)
1341 if (draw_border_function != NULL)
1342 draw_border_function();
1344 UpdateScreen(&dst_rect2);
1348 else if (fade_mode == FADE_MODE_CURTAIN)
1352 int xx_size = width / 2;
1354 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1355 #if defined(TARGET_SDL2)
1356 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1358 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1361 for (xx = 0; xx < xx_size;)
1363 time_last = time_current;
1364 time_current = SDL_GetTicks();
1365 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1366 xx_final = MIN(MAX(0, xx), xx_size);
1371 src_rect.h = height;
1376 /* draw new (target) image to screen buffer */
1377 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1379 if (xx_final < xx_size)
1381 src_rect.w = xx_size - xx_final;
1382 src_rect.h = height;
1384 /* draw old (source) image to screen buffer (left side) */
1386 src_rect.x = src_x + xx_final;
1389 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1391 /* draw old (source) image to screen buffer (right side) */
1393 src_rect.x = src_x + xx_size;
1394 dst_rect.x = dst_x + xx_size + xx_final;
1396 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1399 if (draw_border_function != NULL)
1400 draw_border_function();
1402 /* only update the region of the screen that is affected from fading */
1403 UpdateScreen(&dst_rect2);
1406 else /* fading in, fading out or cross-fading */
1411 for (alpha = 0.0; alpha < 255.0;)
1413 time_last = time_current;
1414 time_current = SDL_GetTicks();
1415 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1416 alpha_final = MIN(MAX(0, alpha), 255);
1418 /* draw existing (source) image to screen buffer */
1419 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1421 /* draw new (target) image to screen buffer using alpha blending */
1422 #if defined(TARGET_SDL2)
1423 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1424 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1426 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1428 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1430 if (draw_border_function != NULL)
1431 draw_border_function();
1433 /* only update the region of the screen that is affected from fading */
1434 UpdateScreen(&dst_rect);
1440 unsigned int time_post_delay;
1442 time_current = SDL_GetTicks();
1443 time_post_delay = time_current + post_delay;
1445 while (time_current < time_post_delay)
1447 // do not wait longer than 10 ms at a time to be able to ...
1448 Delay(MIN(10, time_post_delay - time_current));
1450 // ... continue drawing global animations during post delay
1453 time_current = SDL_GetTicks();
1457 // restore function for drawing global masked border
1458 gfx.draw_global_border_function = draw_global_border_function;
1461 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1462 int to_x, int to_y, Uint32 color)
1464 SDL_Surface *surface = dst_bitmap->surface;
1468 swap_numbers(&from_x, &to_x);
1471 swap_numbers(&from_y, &to_y);
1475 rect.w = (to_x - from_x + 1);
1476 rect.h = (to_y - from_y + 1);
1478 if (dst_bitmap == backbuffer || dst_bitmap == window)
1480 rect.x += video_xoffset;
1481 rect.y += video_yoffset;
1484 SDL_FillRect(surface, &rect, color);
1487 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1488 int to_x, int to_y, Uint32 color)
1490 if (dst_bitmap == backbuffer || dst_bitmap == window)
1492 from_x += video_xoffset;
1493 from_y += video_yoffset;
1494 to_x += video_xoffset;
1495 to_y += video_yoffset;
1498 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1501 #if ENABLE_UNUSED_CODE
1502 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1503 int num_points, Uint32 color)
1508 for (i = 0; i < num_points - 1; i++)
1510 for (x = 0; x < line_width; x++)
1512 for (y = 0; y < line_width; y++)
1514 int dx = x - line_width / 2;
1515 int dy = y - line_width / 2;
1517 if ((x == 0 && y == 0) ||
1518 (x == 0 && y == line_width - 1) ||
1519 (x == line_width - 1 && y == 0) ||
1520 (x == line_width - 1 && y == line_width - 1))
1523 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1524 points[i+1].x + dx, points[i+1].y + dy, color);
1531 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1533 SDL_Surface *surface = src_bitmap->surface;
1535 if (src_bitmap == backbuffer || src_bitmap == window)
1541 switch (surface->format->BytesPerPixel)
1543 case 1: /* assuming 8-bpp */
1545 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1549 case 2: /* probably 15-bpp or 16-bpp */
1551 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1555 case 3: /* slow 24-bpp mode; usually not used */
1557 /* does this work? */
1558 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1562 shift = surface->format->Rshift;
1563 color |= *(pix + shift / 8) >> shift;
1564 shift = surface->format->Gshift;
1565 color |= *(pix + shift / 8) >> shift;
1566 shift = surface->format->Bshift;
1567 color |= *(pix + shift / 8) >> shift;
1573 case 4: /* probably 32-bpp */
1575 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1584 /* ========================================================================= */
1585 /* The following functions were taken from the SGE library */
1586 /* (SDL Graphics Extension Library) by Anders Lindström */
1587 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1588 /* ========================================================================= */
1590 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1592 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1594 switch (surface->format->BytesPerPixel)
1598 /* Assuming 8-bpp */
1599 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1605 /* Probably 15-bpp or 16-bpp */
1606 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1612 /* Slow 24-bpp mode, usually not used */
1616 /* Gack - slow, but endian correct */
1617 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1618 shift = surface->format->Rshift;
1619 *(pix+shift/8) = color>>shift;
1620 shift = surface->format->Gshift;
1621 *(pix+shift/8) = color>>shift;
1622 shift = surface->format->Bshift;
1623 *(pix+shift/8) = color>>shift;
1629 /* Probably 32-bpp */
1630 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1637 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1638 Uint8 R, Uint8 G, Uint8 B)
1640 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1643 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1645 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1648 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1650 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1653 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1658 /* Gack - slow, but endian correct */
1659 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1660 shift = surface->format->Rshift;
1661 *(pix+shift/8) = color>>shift;
1662 shift = surface->format->Gshift;
1663 *(pix+shift/8) = color>>shift;
1664 shift = surface->format->Bshift;
1665 *(pix+shift/8) = color>>shift;
1668 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1670 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1673 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1675 switch (dest->format->BytesPerPixel)
1678 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1682 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1686 _PutPixel24(dest,x,y,color);
1690 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1695 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1697 if (SDL_MUSTLOCK(surface))
1699 if (SDL_LockSurface(surface) < 0)
1705 _PutPixel(surface, x, y, color);
1707 if (SDL_MUSTLOCK(surface))
1709 SDL_UnlockSurface(surface);
1713 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1714 Uint8 r, Uint8 g, Uint8 b)
1716 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1719 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1721 if (y >= 0 && y <= dest->h - 1)
1723 switch (dest->format->BytesPerPixel)
1726 return y*dest->pitch;
1730 return y*dest->pitch/2;
1734 return y*dest->pitch;
1738 return y*dest->pitch/4;
1746 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1748 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1750 switch (surface->format->BytesPerPixel)
1754 /* Assuming 8-bpp */
1755 *((Uint8 *)surface->pixels + ypitch + x) = color;
1761 /* Probably 15-bpp or 16-bpp */
1762 *((Uint16 *)surface->pixels + ypitch + x) = color;
1768 /* Slow 24-bpp mode, usually not used */
1772 /* Gack - slow, but endian correct */
1773 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1774 shift = surface->format->Rshift;
1775 *(pix+shift/8) = color>>shift;
1776 shift = surface->format->Gshift;
1777 *(pix+shift/8) = color>>shift;
1778 shift = surface->format->Bshift;
1779 *(pix+shift/8) = color>>shift;
1785 /* Probably 32-bpp */
1786 *((Uint32 *)surface->pixels + ypitch + x) = color;
1793 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1798 if (SDL_MUSTLOCK(Surface))
1800 if (SDL_LockSurface(Surface) < 0)
1813 /* Do the clipping */
1814 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1818 if (x2 > Surface->w - 1)
1819 x2 = Surface->w - 1;
1826 SDL_FillRect(Surface, &l, Color);
1828 if (SDL_MUSTLOCK(Surface))
1830 SDL_UnlockSurface(Surface);
1834 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1835 Uint8 R, Uint8 G, Uint8 B)
1837 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1840 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1851 /* Do the clipping */
1852 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1856 if (x2 > Surface->w - 1)
1857 x2 = Surface->w - 1;
1864 SDL_FillRect(Surface, &l, Color);
1867 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1872 if (SDL_MUSTLOCK(Surface))
1874 if (SDL_LockSurface(Surface) < 0)
1887 /* Do the clipping */
1888 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1892 if (y2 > Surface->h - 1)
1893 y2 = Surface->h - 1;
1900 SDL_FillRect(Surface, &l, Color);
1902 if (SDL_MUSTLOCK(Surface))
1904 SDL_UnlockSurface(Surface);
1908 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1909 Uint8 R, Uint8 G, Uint8 B)
1911 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1914 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1925 /* Do the clipping */
1926 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1930 if (y2 > Surface->h - 1)
1931 y2 = Surface->h - 1;
1938 SDL_FillRect(Surface, &l, Color);
1941 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1942 Sint16 x2, Sint16 y2, Uint32 Color,
1943 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1946 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1951 sdx = (dx < 0) ? -1 : 1;
1952 sdy = (dy < 0) ? -1 : 1;
1964 for (x = 0; x < dx; x++)
1966 Callback(Surface, px, py, Color);
1980 for (y = 0; y < dy; y++)
1982 Callback(Surface, px, py, Color);
1996 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1997 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1998 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
2001 sge_DoLine(Surface, X1, Y1, X2, Y2,
2002 SDL_MapRGB(Surface->format, R, G, B), Callback);
2005 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
2008 if (SDL_MUSTLOCK(Surface))
2010 if (SDL_LockSurface(Surface) < 0)
2015 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
2017 /* unlock the display */
2018 if (SDL_MUSTLOCK(Surface))
2020 SDL_UnlockSurface(Surface);
2024 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
2025 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
2027 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
2030 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
2032 if (dst_bitmap == backbuffer || dst_bitmap == window)
2038 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
2043 -----------------------------------------------------------------------------
2044 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
2045 -----------------------------------------------------------------------------
2048 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
2049 int width, int height, Uint32 color)
2053 for (y = src_y; y < src_y + height; y++)
2055 for (x = src_x; x < src_x + width; x++)
2057 Uint32 pixel = SDLGetPixel(bitmap, x, y);
2059 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
2064 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
2065 int src_x, int src_y, int width, int height,
2066 int dst_x, int dst_y)
2070 for (y = 0; y < height; y++)
2072 for (x = 0; x < width; x++)
2074 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
2076 if (pixel != BLACK_PIXEL)
2077 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
2083 /* ========================================================================= */
2084 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
2085 /* (Rotozoomer) by Andreas Schiffler */
2086 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
2087 /* ========================================================================= */
2090 -----------------------------------------------------------------------------
2093 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
2094 -----------------------------------------------------------------------------
2105 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
2108 tColorRGBA *sp, *csp, *dp;
2112 sp = csp = (tColorRGBA *) src->pixels;
2113 dp = (tColorRGBA *) dst->pixels;
2114 dgap = dst->pitch - dst->w * 4;
2116 for (y = 0; y < dst->h; y++)
2120 for (x = 0; x < dst->w; x++)
2122 tColorRGBA *sp0 = sp;
2123 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2124 tColorRGBA *sp00 = &sp0[0];
2125 tColorRGBA *sp01 = &sp0[1];
2126 tColorRGBA *sp10 = &sp1[0];
2127 tColorRGBA *sp11 = &sp1[1];
2130 /* create new color pixel from all four source color pixels */
2131 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2132 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2133 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2134 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2139 /* advance source pointers */
2142 /* advance destination pointer */
2146 /* advance source pointer */
2147 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2149 /* advance destination pointers */
2150 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2156 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2158 int x, y, *sax, *say, *csax, *csay;
2160 tColorRGBA *sp, *csp, *csp0, *dp;
2163 /* use specialized zoom function when scaling down to exactly half size */
2164 if (src->w == 2 * dst->w &&
2165 src->h == 2 * dst->h)
2166 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2168 /* variable setup */
2169 sx = (float) src->w / (float) dst->w;
2170 sy = (float) src->h / (float) dst->h;
2172 /* allocate memory for row increments */
2173 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2174 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2176 /* precalculate row increments */
2177 for (x = 0; x <= dst->w; x++)
2178 *csax++ = (int)(sx * x);
2180 for (y = 0; y <= dst->h; y++)
2181 *csay++ = (int)(sy * y);
2184 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2185 dp = (tColorRGBA *) dst->pixels;
2186 dgap = dst->pitch - dst->w * 4;
2189 for (y = 0; y < dst->h; y++)
2194 for (x = 0; x < dst->w; x++)
2199 /* advance source pointers */
2203 /* advance destination pointer */
2207 /* advance source pointer */
2209 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2211 /* advance destination pointers */
2212 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2222 -----------------------------------------------------------------------------
2225 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2226 -----------------------------------------------------------------------------
2229 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2231 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2232 Uint8 *sp, *dp, *csp;
2235 /* variable setup */
2236 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2237 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2239 /* allocate memory for row increments */
2240 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2241 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2243 /* precalculate row increments */
2246 for (x = 0; x < dst->w; x++)
2249 *csax = (csx >> 16);
2256 for (y = 0; y < dst->h; y++)
2259 *csay = (csy >> 16);
2266 for (x = 0; x < dst->w; x++)
2274 for (y = 0; y < dst->h; y++)
2281 sp = csp = (Uint8 *) src->pixels;
2282 dp = (Uint8 *) dst->pixels;
2283 dgap = dst->pitch - dst->w;
2287 for (y = 0; y < dst->h; y++)
2291 for (x = 0; x < dst->w; x++)
2296 /* advance source pointers */
2300 /* advance destination pointer */
2304 /* advance source pointer (for row) */
2305 csp += ((*csay) * src->pitch);
2308 /* advance destination pointers */
2319 -----------------------------------------------------------------------------
2322 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2323 'zoomx' and 'zoomy' are scaling factors for width and height.
2324 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2325 into a 32bit RGBA format on the fly.
2326 -----------------------------------------------------------------------------
2329 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2331 SDL_Surface *zoom_src = NULL;
2332 SDL_Surface *zoom_dst = NULL;
2333 boolean is_converted = FALSE;
2340 /* determine if source surface is 32 bit or 8 bit */
2341 is_32bit = (src->format->BitsPerPixel == 32);
2343 if (is_32bit || src->format->BitsPerPixel == 8)
2345 /* use source surface 'as is' */
2350 /* new source surface is 32 bit with a defined RGB ordering */
2351 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2352 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2353 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2355 is_converted = TRUE;
2358 /* allocate surface to completely contain the zoomed surface */
2361 /* target surface is 32 bit with source RGBA/ABGR ordering */
2362 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2363 zoom_src->format->Rmask,
2364 zoom_src->format->Gmask,
2365 zoom_src->format->Bmask, 0);
2369 /* target surface is 8 bit */
2370 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2374 /* lock source surface */
2375 SDL_LockSurface(zoom_src);
2377 /* check which kind of surface we have */
2380 /* call the 32 bit transformation routine to do the zooming */
2381 zoomSurfaceRGBA(zoom_src, zoom_dst);
2386 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2387 zoom_dst->format->palette->colors[i] =
2388 zoom_src->format->palette->colors[i];
2389 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2391 /* call the 8 bit transformation routine to do the zooming */
2392 zoomSurfaceY(zoom_src, zoom_dst);
2395 /* unlock source surface */
2396 SDL_UnlockSurface(zoom_src);
2398 /* free temporary surface */
2400 SDL_FreeSurface(zoom_src);
2402 /* return destination surface */
2406 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2408 Bitmap *dst_bitmap = CreateBitmapStruct();
2409 SDL_Surface **dst_surface = &dst_bitmap->surface;
2411 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2412 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2414 dst_bitmap->width = dst_width;
2415 dst_bitmap->height = dst_height;
2417 /* create zoomed temporary surface from source surface */
2418 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2420 /* create native format destination surface from zoomed temporary surface */
2421 SDLSetNativeSurface(dst_surface);
2427 /* ========================================================================= */
2428 /* load image to bitmap */
2429 /* ========================================================================= */
2431 Bitmap *SDLLoadImage(char *filename)
2433 Bitmap *new_bitmap = CreateBitmapStruct();
2434 SDL_Surface *sdl_image_tmp;
2436 print_timestamp_init("SDLLoadImage");
2438 print_timestamp_time(getBaseNamePtr(filename));
2440 /* load image to temporary surface */
2441 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2443 SetError("IMG_Load(): %s", SDL_GetError());
2448 print_timestamp_time("IMG_Load");
2450 UPDATE_BUSY_STATE();
2452 /* create native non-transparent surface for current image */
2453 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2455 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2460 print_timestamp_time("SDL_DisplayFormat (opaque)");
2462 UPDATE_BUSY_STATE();
2464 /* create native transparent surface for current image */
2465 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2466 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2468 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2470 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2475 print_timestamp_time("SDL_DisplayFormat (masked)");
2477 UPDATE_BUSY_STATE();
2479 /* free temporary surface */
2480 SDL_FreeSurface(sdl_image_tmp);
2482 new_bitmap->width = new_bitmap->surface->w;
2483 new_bitmap->height = new_bitmap->surface->h;
2485 print_timestamp_done("SDLLoadImage");
2491 /* ------------------------------------------------------------------------- */
2492 /* custom cursor fuctions */
2493 /* ------------------------------------------------------------------------- */
2495 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2497 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2498 cursor_info->width, cursor_info->height,
2499 cursor_info->hot_x, cursor_info->hot_y);
2502 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2504 static struct MouseCursorInfo *last_cursor_info = NULL;
2505 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2506 static SDL_Cursor *cursor_default = NULL;
2507 static SDL_Cursor *cursor_current = NULL;
2509 /* if invoked for the first time, store the SDL default cursor */
2510 if (cursor_default == NULL)
2511 cursor_default = SDL_GetCursor();
2513 /* only create new cursor if cursor info (custom only) has changed */
2514 if (cursor_info != NULL && cursor_info != last_cursor_info)
2516 cursor_current = create_cursor(cursor_info);
2517 last_cursor_info = cursor_info;
2520 /* only set new cursor if cursor info (custom or NULL) has changed */
2521 if (cursor_info != last_cursor_info2)
2522 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2524 last_cursor_info2 = cursor_info;
2528 /* ========================================================================= */
2529 /* audio functions */
2530 /* ========================================================================= */
2532 void SDLOpenAudio(void)
2534 #if !defined(TARGET_SDL2)
2535 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2536 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2539 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2541 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2545 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2546 AUDIO_NUM_CHANNELS_STEREO,
2547 setup.system.audio_fragment_size) < 0)
2549 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2553 audio.sound_available = TRUE;
2554 audio.music_available = TRUE;
2555 audio.loops_available = TRUE;
2556 audio.sound_enabled = TRUE;
2558 /* set number of available mixer channels */
2559 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2560 audio.music_channel = MUSIC_CHANNEL;
2561 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2563 Mixer_InitChannels();
2566 void SDLCloseAudio(void)
2569 Mix_HaltChannel(-1);
2572 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2576 /* ========================================================================= */
2577 /* event functions */
2578 /* ========================================================================= */
2580 void SDLNextEvent(Event *event)
2582 SDL_WaitEvent(event);
2584 if (event->type == EVENT_BUTTONPRESS ||
2585 event->type == EVENT_BUTTONRELEASE)
2587 if (((ButtonEvent *)event)->x > video_xoffset)
2588 ((ButtonEvent *)event)->x -= video_xoffset;
2590 ((ButtonEvent *)event)->x = 0;
2591 if (((ButtonEvent *)event)->y > video_yoffset)
2592 ((ButtonEvent *)event)->y -= video_yoffset;
2594 ((ButtonEvent *)event)->y = 0;
2596 else if (event->type == EVENT_MOTIONNOTIFY)
2598 if (((MotionEvent *)event)->x > video_xoffset)
2599 ((MotionEvent *)event)->x -= video_xoffset;
2601 ((MotionEvent *)event)->x = 0;
2602 if (((MotionEvent *)event)->y > video_yoffset)
2603 ((MotionEvent *)event)->y -= video_yoffset;
2605 ((MotionEvent *)event)->y = 0;
2609 void SDLHandleWindowManagerEvent(Event *event)
2612 #if defined(PLATFORM_WIN32)
2613 // experimental drag and drop code
2615 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2616 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2618 #if defined(TARGET_SDL2)
2619 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2621 if (syswmmsg->msg == WM_DROPFILES)
2624 #if defined(TARGET_SDL2)
2625 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2627 HDROP hdrop = (HDROP)syswmmsg->wParam;
2631 printf("::: SDL_SYSWMEVENT:\n");
2633 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2635 for (i = 0; i < num_files; i++)
2637 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2638 char buffer[buffer_len + 1];
2640 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2642 printf("::: - '%s'\n", buffer);
2645 #if defined(TARGET_SDL2)
2646 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2648 DragFinish((HDROP)syswmmsg->wParam);
2656 /* ========================================================================= */
2657 /* joystick functions */
2658 /* ========================================================================= */
2660 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2661 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2662 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2664 static boolean SDLOpenJoystick(int nr)
2666 if (nr < 0 || nr > MAX_PLAYERS)
2669 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2672 static void SDLCloseJoystick(int nr)
2674 if (nr < 0 || nr > MAX_PLAYERS)
2677 SDL_JoystickClose(sdl_joystick[nr]);
2679 sdl_joystick[nr] = NULL;
2682 static boolean SDLCheckJoystickOpened(int nr)
2684 if (nr < 0 || nr > MAX_PLAYERS)
2687 #if defined(TARGET_SDL2)
2688 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2690 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2694 void HandleJoystickEvent(Event *event)
2698 case SDL_JOYAXISMOTION:
2699 if (event->jaxis.axis < 2)
2700 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2703 case SDL_JOYBUTTONDOWN:
2704 if (event->jbutton.button < 2)
2705 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2708 case SDL_JOYBUTTONUP:
2709 if (event->jbutton.button < 2)
2710 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2718 void SDLInitJoysticks()
2720 static boolean sdl_joystick_subsystem_initialized = FALSE;
2721 boolean print_warning = !sdl_joystick_subsystem_initialized;
2724 if (!sdl_joystick_subsystem_initialized)
2726 sdl_joystick_subsystem_initialized = TRUE;
2728 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2730 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2735 for (i = 0; i < MAX_PLAYERS; i++)
2737 /* get configured joystick for this player */
2738 char *device_name = setup.input[i].joy.device_name;
2739 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2741 if (joystick_nr >= SDL_NumJoysticks())
2743 if (setup.input[i].use_joystick && print_warning)
2744 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2749 /* misuse joystick file descriptor variable to store joystick number */
2750 joystick.fd[i] = joystick_nr;
2752 if (joystick_nr == -1)
2755 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2756 if (SDLCheckJoystickOpened(joystick_nr))
2757 SDLCloseJoystick(joystick_nr);
2759 if (!setup.input[i].use_joystick)
2762 if (!SDLOpenJoystick(joystick_nr))
2765 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2770 joystick.status = JOYSTICK_ACTIVATED;
2774 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2776 if (nr < 0 || nr >= MAX_PLAYERS)
2780 *x = sdl_js_axis[nr][0];
2782 *y = sdl_js_axis[nr][1];
2785 *b1 = sdl_js_button[nr][0];
2787 *b2 = sdl_js_button[nr][1];