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 #define USE_TARGET_TEXTURE TRUE
28 #define USE_TARGET_TEXTURE_ONLY FALSE
30 static SDL_Window *sdl_window = NULL;
31 static SDL_Renderer *sdl_renderer = NULL;
32 #if USE_TARGET_TEXTURE
33 static SDL_Texture *sdl_texture_stream = NULL;
34 static SDL_Texture *sdl_texture_target = NULL;
36 static SDL_Texture *sdl_texture = NULL;
38 static boolean fullscreen_enabled = FALSE;
40 #define USE_RENDERER TRUE
43 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
44 static int fullscreen_width;
45 static int fullscreen_height;
46 static int fullscreen_xoffset;
47 static int fullscreen_yoffset;
48 static int video_xoffset;
49 static int video_yoffset;
50 static boolean limit_screen_updates = FALSE;
53 /* functions from SGE library */
54 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
56 void SDLLimitScreenUpdates(boolean enable)
58 limit_screen_updates = enable;
61 static void UpdateScreen(SDL_Rect *rect)
63 static unsigned int update_screen_delay = 0;
64 unsigned int update_screen_delay_value = 50; /* (milliseconds) */
65 SDL_Surface *screen = backbuffer->surface;
67 if (limit_screen_updates &&
68 !DelayReached(&update_screen_delay, update_screen_delay_value))
71 LimitScreenUpdates(FALSE);
75 static int LastFrameCounter = 0;
76 boolean changed = (FrameCounter != LastFrameCounter);
78 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
79 (changed ? "-" : "SAME FRAME UPDATED"));
81 LastFrameCounter = FrameCounter;
90 #if USE_FINAL_SCREEN_BITMAP
91 if (gfx.final_screen_bitmap != NULL) // may not be initialized yet
94 // draw global animations using bitmaps instead of using textures
95 // to prevent texture scaling artefacts (this is potentially slower)
97 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
98 gfx.win_xsize, gfx.win_ysize, 0, 0);
100 // copy global animations to render target buffer, if defined (below border)
101 if (gfx.draw_global_anim_function != NULL)
102 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
104 // copy global masked border to render target buffer, if defined
105 if (gfx.draw_global_border_function != NULL)
106 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
108 // copy global animations to render target buffer, if defined (above border)
109 if (gfx.draw_global_anim_function != NULL)
110 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
112 screen = gfx.final_screen_bitmap->surface;
114 // force full window redraw
119 #if USE_TARGET_TEXTURE
120 #if USE_TARGET_TEXTURE_ONLY
121 SDL_Texture *sdl_texture = sdl_texture_target;
123 SDL_Texture *sdl_texture = sdl_texture_stream;
127 #if defined(TARGET_SDL2)
131 int bytes_x = screen->pitch / video.width;
132 int bytes_y = screen->pitch;
134 if (video.fullscreen_enabled)
135 bytes_x = screen->pitch / fullscreen_width;
137 SDL_UpdateTexture(sdl_texture, rect,
138 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
143 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
146 // clear render target buffer
147 SDL_RenderClear(sdl_renderer);
149 #if USE_TARGET_TEXTURE
150 SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
152 // copy backbuffer to render target buffer
153 if (sdl_texture != sdl_texture_target)
154 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
156 // copy backbuffer to render target buffer
157 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
160 #if !USE_FINAL_SCREEN_BITMAP
161 // copy global animations to render target buffer, if defined (below border)
162 if (gfx.draw_global_anim_function != NULL)
163 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
165 // copy global masked border to render target buffer, if defined
166 if (gfx.draw_global_border_function != NULL)
167 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
169 // copy global animations to render target buffer, if defined (above border)
170 if (gfx.draw_global_anim_function != NULL)
171 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
174 #if USE_TARGET_TEXTURE
175 SDL_SetRenderTarget(sdl_renderer, NULL);
176 SDL_RenderCopy(sdl_renderer, sdl_texture_target, NULL, NULL);
179 // show render target buffer on screen
180 SDL_RenderPresent(sdl_renderer);
185 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
187 SDL_UpdateWindowSurface(sdl_window);
192 SDL_UpdateRects(screen, 1, rect);
194 SDL_UpdateRect(screen, 0, 0, 0, 0);
198 static void setFullscreenParameters(char *fullscreen_mode_string)
200 #if defined(TARGET_SDL2)
201 fullscreen_width = video.width;
202 fullscreen_height = video.height;
203 fullscreen_xoffset = 0;
204 fullscreen_yoffset = 0;
208 struct ScreenModeInfo *fullscreen_mode;
211 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
213 if (fullscreen_mode == NULL)
216 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
218 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
219 fullscreen_mode->height == video.fullscreen_modes[i].height)
221 fullscreen_width = fullscreen_mode->width;
222 fullscreen_height = fullscreen_mode->height;
224 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
225 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
233 static void SDLSetWindowIcon(char *basename)
235 /* (setting the window icon on Mac OS X would replace the high-quality
236 dock icon with the currently smaller (and uglier) icon from file) */
238 #if !defined(PLATFORM_MACOSX)
239 char *filename = getCustomImageFilename(basename);
240 SDL_Surface *surface;
242 if (filename == NULL)
244 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
249 if ((surface = IMG_Load(filename)) == NULL)
251 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
256 /* set transparent color */
257 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
258 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
260 #if defined(TARGET_SDL2)
261 SDL_SetWindowIcon(sdl_window, surface);
263 SDL_WM_SetIcon(surface, NULL);
268 #if defined(TARGET_SDL2)
270 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
271 SDL_PixelFormat *format2)
273 return (format1->format == format2->format &&
274 format1->BitsPerPixel == format2->BitsPerPixel &&
275 format1->BytesPerPixel == format2->BytesPerPixel &&
276 format1->Rmask == format2->Rmask &&
277 format1->Gmask == format2->Gmask &&
278 format1->Bmask == format2->Bmask &&
279 format1->Amask == format2->Amask);
282 boolean SDLSetNativeSurface(SDL_Surface **surface)
284 SDL_Surface *new_surface;
286 if (surface == NULL ||
288 backbuffer == NULL ||
289 backbuffer->surface == NULL)
292 // if pixel format already optimized for destination surface, do nothing
293 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
296 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
298 if (new_surface == NULL)
299 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
301 SDL_FreeSurface(*surface);
303 *surface = new_surface;
308 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
310 SDL_PixelFormat format;
311 SDL_Surface *new_surface;
316 if (backbuffer && backbuffer->surface)
318 format = *backbuffer->surface->format;
319 format.Amask = surface->format->Amask; // keep alpha channel
323 format = *surface->format;
326 new_surface = SDL_ConvertSurface(surface, &format, 0);
328 if (new_surface == NULL)
329 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
336 boolean SDLSetNativeSurface(SDL_Surface **surface)
338 SDL_Surface *new_surface;
340 if (surface == NULL ||
345 new_surface = SDL_DisplayFormat(*surface);
347 if (new_surface == NULL)
348 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
350 SDL_FreeSurface(*surface);
352 *surface = new_surface;
357 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
359 SDL_Surface *new_surface;
361 if (video.initialized)
362 new_surface = SDL_DisplayFormat(surface);
364 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
366 if (new_surface == NULL)
367 Error(ERR_EXIT, "%s() failed: %s",
368 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
376 #if defined(TARGET_SDL2)
377 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
379 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
382 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
389 void SDLCreateBitmapTextures(Bitmap *bitmap)
391 #if defined(TARGET_SDL2)
396 SDL_DestroyTexture(bitmap->texture);
397 if (bitmap->texture_masked)
398 SDL_DestroyTexture(bitmap->texture_masked);
400 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
401 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
405 void SDLFreeBitmapTextures(Bitmap *bitmap)
407 #if defined(TARGET_SDL2)
412 SDL_DestroyTexture(bitmap->texture);
413 if (bitmap->texture_masked)
414 SDL_DestroyTexture(bitmap->texture_masked);
416 bitmap->texture = NULL;
417 bitmap->texture_masked = NULL;
421 void SDLInitVideoDisplay(void)
423 #if !defined(TARGET_SDL2)
424 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
425 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
427 SDL_putenv("SDL_VIDEO_CENTERED=1");
430 /* initialize SDL video */
431 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
432 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
434 /* set default SDL depth */
435 #if !defined(TARGET_SDL2)
436 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
438 video.default_depth = 32; // (how to determine video depth in SDL2?)
442 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
445 #if !defined(TARGET_SDL2)
446 static int screen_xy[][2] =
454 SDL_Rect **modes = NULL;
455 boolean hardware_fullscreen_available = TRUE;
458 /* default: normal game window size */
459 fullscreen_width = video.width;
460 fullscreen_height = video.height;
461 fullscreen_xoffset = 0;
462 fullscreen_yoffset = 0;
464 #if !defined(TARGET_SDL2)
465 /* determine required standard fullscreen mode for game screen size */
466 for (i = 0; screen_xy[i][0] != -1; i++)
468 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
470 fullscreen_width = screen_xy[i][0];
471 fullscreen_height = screen_xy[i][1];
477 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
478 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
481 checked_free(video.fullscreen_modes);
483 video.fullscreen_modes = NULL;
484 video.fullscreen_mode_current = NULL;
486 video.window_scaling_percent = setup.window_scaling_percent;
487 video.window_scaling_quality = setup.window_scaling_quality;
489 #if defined(TARGET_SDL2)
490 int num_displays = SDL_GetNumVideoDisplays();
492 if (num_displays > 0)
494 // currently only display modes of first display supported
495 int num_modes = SDL_GetNumDisplayModes(0);
499 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
501 for (i = 0; i < num_modes; i++)
503 SDL_DisplayMode mode;
505 if (SDL_GetDisplayMode(0, i, &mode) < 0)
508 modes[i] = checked_calloc(sizeof(SDL_Rect));
510 modes[i]->w = mode.w;
511 modes[i]->h = mode.h;
516 /* get available hardware supported fullscreen modes */
517 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
522 /* no hardware screen modes available => no fullscreen mode support */
523 // video.fullscreen_available = FALSE;
524 hardware_fullscreen_available = FALSE;
526 else if (modes == (SDL_Rect **)-1)
528 /* fullscreen resolution is not restricted -- all resolutions available */
529 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
531 /* use native video buffer size for fullscreen mode */
532 video.fullscreen_modes[0].width = video.width;
533 video.fullscreen_modes[0].height = video.height;
535 video.fullscreen_modes[1].width = -1;
536 video.fullscreen_modes[1].height = -1;
540 /* in this case, a certain number of screen modes is available */
543 for (i = 0; modes[i] != NULL; i++)
545 boolean found_mode = FALSE;
547 /* screen mode is smaller than video buffer size -- skip it */
548 if (modes[i]->w < video.width || modes[i]->h < video.height)
551 if (video.fullscreen_modes != NULL)
552 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
553 if (modes[i]->w == video.fullscreen_modes[j].width &&
554 modes[i]->h == video.fullscreen_modes[j].height)
557 if (found_mode) /* screen mode already stored -- skip it */
560 /* new mode found; add it to list of available fullscreen modes */
564 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
566 sizeof(struct ScreenModeInfo));
568 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
569 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
571 video.fullscreen_modes[num_modes].width = -1;
572 video.fullscreen_modes[num_modes].height = -1;
577 /* no appropriate screen modes available => no fullscreen mode support */
578 // video.fullscreen_available = FALSE;
579 hardware_fullscreen_available = FALSE;
583 video.fullscreen_available = hardware_fullscreen_available;
585 #if USE_DESKTOP_FULLSCREEN
586 // in SDL 2.0, there is always support for desktop fullscreen mode
587 // (in SDL 1.2, there is only support for "real" fullscreen mode)
588 video.fullscreen_available = TRUE;
591 #if defined(TARGET_SDL2)
594 for (i = 0; modes[i] != NULL; i++)
595 checked_free(modes[i]);
601 /* open SDL video output device (window or fullscreen mode) */
602 if (!SDLSetVideoMode(backbuffer, fullscreen))
603 Error(ERR_EXIT, "setting video mode failed");
605 /* !!! SDL2 can only set the window icon if the window already exists !!! */
606 /* set window icon */
607 SDLSetWindowIcon(program.icon_filename);
609 /* set window and icon title */
610 #if defined(TARGET_SDL2)
611 SDL_SetWindowTitle(sdl_window, program.window_title);
613 SDL_WM_SetCaption(program.window_title, program.window_title);
616 /* SDL cannot directly draw to the visible video framebuffer like X11,
617 but always uses a backbuffer, which is then blitted to the visible
618 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
619 visible video framebuffer with 'SDL_Flip', if the hardware supports
620 this). Therefore do not use an additional backbuffer for drawing, but
621 use a symbolic buffer (distinguishable from the SDL backbuffer) called
622 'window', which indicates that the SDL backbuffer should be updated to
623 the visible video framebuffer when attempting to blit to it.
625 For convenience, it seems to be a good idea to create this symbolic
626 buffer 'window' at the same size as the SDL backbuffer. Although it
627 should never be drawn to directly, it would do no harm nevertheless. */
629 /* create additional (symbolic) buffer for double-buffering */
630 ReCreateBitmap(window, video.width, video.height, video.depth);
633 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
636 SDL_Surface *new_surface = NULL;
638 #if defined(TARGET_SDL2)
639 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
640 #if USE_DESKTOP_FULLSCREEN
641 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
643 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
647 int surface_flags_window = SURFACE_FLAGS;
648 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
651 int width = (fullscreen ? fullscreen_width : video.width);
652 int height = (fullscreen ? fullscreen_height : video.height);
653 int surface_flags = (fullscreen ? surface_flags_fullscreen :
654 surface_flags_window);
656 // default window size is unscaled
657 video.window_width = video.width;
658 video.window_height = video.height;
660 #if defined(TARGET_SDL2)
662 // store if initial screen mode is fullscreen mode when changing screen size
663 video.fullscreen_initial = fullscreen;
666 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
667 #if !USE_DESKTOP_FULLSCREEN
668 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
671 video.window_width = window_scaling_factor * width;
672 video.window_height = window_scaling_factor * height;
674 if ((*backbuffer)->surface)
676 SDL_FreeSurface((*backbuffer)->surface);
677 (*backbuffer)->surface = NULL;
680 #if USE_TARGET_TEXTURE
681 if (sdl_texture_stream)
683 SDL_DestroyTexture(sdl_texture_stream);
684 sdl_texture_stream = NULL;
687 if (sdl_texture_target)
689 SDL_DestroyTexture(sdl_texture_target);
690 sdl_texture_target = NULL;
695 SDL_DestroyTexture(sdl_texture);
700 if (!(fullscreen && fullscreen_enabled))
704 SDL_DestroyRenderer(sdl_renderer);
710 SDL_DestroyWindow(sdl_window);
715 if (sdl_window == NULL)
716 sdl_window = SDL_CreateWindow(program.window_title,
717 SDL_WINDOWPOS_CENTERED,
718 SDL_WINDOWPOS_CENTERED,
719 #if USE_DESKTOP_FULLSCREEN
723 (int)(screen_scaling_factor * width),
724 (int)(screen_scaling_factor * height),
728 if (sdl_window != NULL)
731 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
732 *without* enabling 2D/3D acceleration and/or guest additions installed,
733 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
734 it will try to use accelerated graphics and apparently fails miserably) */
735 if (sdl_renderer == NULL)
736 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
738 if (sdl_renderer == NULL)
739 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
742 if (sdl_renderer != NULL)
744 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
745 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
746 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
748 #if USE_TARGET_TEXTURE
749 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
750 SDL_PIXELFORMAT_ARGB8888,
751 SDL_TEXTUREACCESS_STREAMING,
754 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
755 SDL_PIXELFORMAT_ARGB8888,
756 SDL_TEXTUREACCESS_TARGET,
759 sdl_texture = SDL_CreateTexture(sdl_renderer,
760 SDL_PIXELFORMAT_ARGB8888,
761 SDL_TEXTUREACCESS_STREAMING,
765 #if USE_TARGET_TEXTURE
766 if (sdl_texture_stream != NULL &&
767 sdl_texture_target != NULL)
769 if (sdl_texture != NULL)
772 // use SDL default values for RGB masks and no alpha channel
773 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
775 if (new_surface == NULL)
776 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
781 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
786 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
791 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
797 SDL_DestroyWindow(sdl_window);
799 sdl_window = SDL_CreateWindow(program.window_title,
800 SDL_WINDOWPOS_CENTERED,
801 SDL_WINDOWPOS_CENTERED,
805 if (sdl_window != NULL)
806 new_surface = SDL_GetWindowSurface(sdl_window);
810 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
813 #if defined(TARGET_SDL2)
814 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
815 if (new_surface != NULL)
816 fullscreen_enabled = fullscreen;
822 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
824 boolean success = TRUE;
825 SDL_Surface *new_surface = NULL;
829 if (*backbuffer == NULL)
830 *backbuffer = CreateBitmapStruct();
832 /* (real bitmap might be larger in fullscreen mode with video offsets) */
833 (*backbuffer)->width = video.width;
834 (*backbuffer)->height = video.height;
836 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
838 setFullscreenParameters(setup.fullscreen_mode);
840 video_xoffset = fullscreen_xoffset;
841 video_yoffset = fullscreen_yoffset;
843 /* switch display to fullscreen mode, if available */
844 new_surface = SDLCreateScreen(backbuffer, TRUE);
846 if (new_surface == NULL)
848 /* switching display to fullscreen mode failed */
849 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
851 /* do not try it again */
852 video.fullscreen_available = FALSE;
858 (*backbuffer)->surface = new_surface;
860 video.fullscreen_enabled = TRUE;
861 video.fullscreen_mode_current = setup.fullscreen_mode;
867 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
872 /* switch display to window mode */
873 new_surface = SDLCreateScreen(backbuffer, FALSE);
875 if (new_surface == NULL)
877 /* switching display to window mode failed -- should not happen */
878 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
884 (*backbuffer)->surface = new_surface;
886 video.fullscreen_enabled = FALSE;
887 video.window_scaling_percent = setup.window_scaling_percent;
888 video.window_scaling_quality = setup.window_scaling_quality;
894 #if defined(TARGET_SDL2)
895 SDLRedrawWindow(); // map window
899 #if defined(PLATFORM_WIN32)
900 // experimental drag and drop code
902 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
905 SDL_SysWMinfo wminfo;
907 boolean wminfo_success = FALSE;
909 SDL_VERSION(&wminfo.version);
910 #if defined(TARGET_SDL2)
912 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
914 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
919 #if defined(TARGET_SDL2)
920 hwnd = wminfo.info.win.window;
922 hwnd = wminfo.window;
925 DragAcceptFiles(hwnd, TRUE);
934 void SDLSetWindowTitle()
936 #if defined(TARGET_SDL2)
937 SDL_SetWindowTitle(sdl_window, program.window_title);
939 SDL_WM_SetCaption(program.window_title, program.window_title);
943 #if defined(TARGET_SDL2)
944 void SDLSetWindowScaling(int window_scaling_percent)
946 if (sdl_window == NULL)
949 float window_scaling_factor = (float)window_scaling_percent / 100;
950 int new_window_width = (int)(window_scaling_factor * video.width);
951 int new_window_height = (int)(window_scaling_factor * video.height);
953 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
955 video.window_scaling_percent = window_scaling_percent;
956 video.window_width = new_window_width;
957 video.window_height = new_window_height;
962 void SDLSetWindowScalingQuality(char *window_scaling_quality)
964 #if USE_TARGET_TEXTURE
965 SDL_Texture *new_texture;
967 if (sdl_texture_stream == NULL ||
968 sdl_texture_target == NULL)
971 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
973 new_texture = SDL_CreateTexture(sdl_renderer,
974 SDL_PIXELFORMAT_ARGB8888,
975 SDL_TEXTUREACCESS_STREAMING,
976 video.width, video.height);
978 if (new_texture != NULL)
980 SDL_DestroyTexture(sdl_texture_stream);
982 sdl_texture_stream = new_texture;
985 new_texture = SDL_CreateTexture(sdl_renderer,
986 SDL_PIXELFORMAT_ARGB8888,
987 SDL_TEXTUREACCESS_TARGET,
988 video.width, video.height);
990 if (new_texture != NULL)
992 SDL_DestroyTexture(sdl_texture_target);
994 sdl_texture_target = new_texture;
1000 if (sdl_texture == NULL)
1003 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
1005 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
1006 SDL_PIXELFORMAT_ARGB8888,
1007 SDL_TEXTUREACCESS_STREAMING,
1008 video.width, video.height);
1010 if (new_texture != NULL)
1012 SDL_DestroyTexture(sdl_texture);
1014 sdl_texture = new_texture;
1020 video.window_scaling_quality = window_scaling_quality;
1023 void SDLSetWindowFullscreen(boolean fullscreen)
1025 if (sdl_window == NULL)
1028 #if USE_DESKTOP_FULLSCREEN
1029 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
1031 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
1034 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
1035 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
1037 // if screen size was changed in fullscreen mode, correct desktop window size
1038 if (!fullscreen && video.fullscreen_initial)
1040 SDLSetWindowScaling(setup.window_scaling_percent);
1041 SDL_SetWindowPosition(sdl_window,
1042 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
1044 video.fullscreen_initial = FALSE;
1048 void SDLRedrawWindow()
1054 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
1057 SDL_Surface *surface =
1058 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
1060 if (surface == NULL)
1061 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1063 SDLSetNativeSurface(&surface);
1065 bitmap->surface = surface;
1068 void SDLFreeBitmapPointers(Bitmap *bitmap)
1070 if (bitmap->surface)
1071 SDL_FreeSurface(bitmap->surface);
1072 if (bitmap->surface_masked)
1073 SDL_FreeSurface(bitmap->surface_masked);
1075 bitmap->surface = NULL;
1076 bitmap->surface_masked = NULL;
1078 #if defined(TARGET_SDL2)
1079 if (bitmap->texture)
1080 SDL_DestroyTexture(bitmap->texture);
1081 if (bitmap->texture_masked)
1082 SDL_DestroyTexture(bitmap->texture_masked);
1084 bitmap->texture = NULL;
1085 bitmap->texture_masked = NULL;
1089 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1090 int src_x, int src_y, int width, int height,
1091 int dst_x, int dst_y, int mask_mode)
1093 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1094 SDL_Rect src_rect, dst_rect;
1096 if (src_bitmap == backbuffer)
1098 src_x += video_xoffset;
1099 src_y += video_yoffset;
1105 src_rect.h = height;
1107 if (dst_bitmap == backbuffer || dst_bitmap == window)
1109 dst_x += video_xoffset;
1110 dst_y += video_yoffset;
1116 dst_rect.h = height;
1118 // if (src_bitmap != backbuffer || dst_bitmap != window)
1119 if (!(src_bitmap == backbuffer && dst_bitmap == window))
1120 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
1121 src_bitmap->surface_masked : src_bitmap->surface),
1122 &src_rect, real_dst_bitmap->surface, &dst_rect);
1124 #if defined(TARGET_SDL2)
1125 if (dst_bitmap == window)
1127 // SDL_UpdateWindowSurface(sdl_window);
1128 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1129 UpdateScreen(&dst_rect);
1132 if (dst_bitmap == window)
1134 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
1135 UpdateScreen(&dst_rect);
1140 void SDLBlitTexture(Bitmap *bitmap,
1141 int src_x, int src_y, int width, int height,
1142 int dst_x, int dst_y, int mask_mode)
1144 #if defined(TARGET_SDL2)
1146 SDL_Texture *texture;
1151 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
1153 if (texture == NULL)
1159 src_rect.h = height;
1164 dst_rect.h = height;
1166 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
1171 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
1174 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1177 if (dst_bitmap == backbuffer || dst_bitmap == window)
1188 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1190 #if defined(TARGET_SDL2)
1191 if (dst_bitmap == window)
1193 // SDL_UpdateWindowSurface(sdl_window);
1194 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
1195 UpdateScreen(&rect);
1198 if (dst_bitmap == window)
1200 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
1201 UpdateScreen(&rect);
1206 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
1207 int fade_mode, int fade_delay, int post_delay,
1208 void (*draw_border_function)(void))
1210 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
1211 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
1212 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
1213 SDL_Surface *surface_screen = backbuffer->surface;
1214 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
1215 SDL_Rect src_rect, dst_rect;
1217 int src_x = x, src_y = y;
1218 int dst_x = x, dst_y = y;
1219 unsigned int time_last, time_current;
1221 // store function for drawing global masked border
1222 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
1224 // deactivate drawing of global border while fading, if needed
1225 if (draw_border_function == NULL)
1226 gfx.draw_global_border_function = NULL;
1231 src_rect.h = height;
1233 dst_x += video_xoffset;
1234 dst_y += video_yoffset;
1238 dst_rect.w = width; /* (ignored) */
1239 dst_rect.h = height; /* (ignored) */
1241 dst_rect2 = dst_rect;
1243 /* copy source and target surfaces to temporary surfaces for fading */
1244 if (fade_mode & FADE_TYPE_TRANSFORM)
1246 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1247 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1249 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
1250 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
1252 else if (fade_mode & FADE_TYPE_FADE_IN)
1254 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1255 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1257 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
1259 else /* FADE_TYPE_FADE_OUT */
1261 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1262 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1264 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
1267 time_current = SDL_GetTicks();
1269 if (fade_mode == FADE_MODE_MELT)
1271 boolean done = FALSE;
1272 int melt_pixels = 2;
1273 int melt_columns = width / melt_pixels;
1274 int ypos[melt_columns];
1275 int max_steps = height / 8 + 32;
1280 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1281 #if defined(TARGET_SDL2)
1282 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1284 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1287 ypos[0] = -GetSimpleRandom(16);
1289 for (i = 1 ; i < melt_columns; i++)
1291 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1293 ypos[i] = ypos[i - 1] + r;
1306 time_last = time_current;
1307 time_current = SDL_GetTicks();
1308 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1309 steps_final = MIN(MAX(0, steps), max_steps);
1313 done = (steps_done >= steps_final);
1315 for (i = 0 ; i < melt_columns; i++)
1323 else if (ypos[i] < height)
1328 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1330 if (ypos[i] + dy >= height)
1331 dy = height - ypos[i];
1333 /* copy part of (appearing) target surface to upper area */
1334 src_rect.x = src_x + i * melt_pixels;
1335 // src_rect.y = src_y + ypos[i];
1337 src_rect.w = melt_pixels;
1339 src_rect.h = ypos[i] + dy;
1341 dst_rect.x = dst_x + i * melt_pixels;
1342 // dst_rect.y = dst_y + ypos[i];
1345 if (steps_done >= steps_final)
1346 SDL_BlitSurface(surface_target, &src_rect,
1347 surface_screen, &dst_rect);
1351 /* copy part of (disappearing) source surface to lower area */
1352 src_rect.x = src_x + i * melt_pixels;
1354 src_rect.w = melt_pixels;
1355 src_rect.h = height - ypos[i];
1357 dst_rect.x = dst_x + i * melt_pixels;
1358 dst_rect.y = dst_y + ypos[i];
1360 if (steps_done >= steps_final)
1361 SDL_BlitSurface(surface_source, &src_rect,
1362 surface_screen, &dst_rect);
1368 src_rect.x = src_x + i * melt_pixels;
1370 src_rect.w = melt_pixels;
1371 src_rect.h = height;
1373 dst_rect.x = dst_x + i * melt_pixels;
1376 if (steps_done >= steps_final)
1377 SDL_BlitSurface(surface_target, &src_rect,
1378 surface_screen, &dst_rect);
1382 if (steps_done >= steps_final)
1384 if (draw_border_function != NULL)
1385 draw_border_function();
1387 UpdateScreen(&dst_rect2);
1391 else if (fade_mode == FADE_MODE_CURTAIN)
1395 int xx_size = width / 2;
1397 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1398 #if defined(TARGET_SDL2)
1399 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1401 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1404 for (xx = 0; xx < xx_size;)
1406 time_last = time_current;
1407 time_current = SDL_GetTicks();
1408 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1409 xx_final = MIN(MAX(0, xx), xx_size);
1414 src_rect.h = height;
1419 /* draw new (target) image to screen buffer */
1420 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1422 if (xx_final < xx_size)
1424 src_rect.w = xx_size - xx_final;
1425 src_rect.h = height;
1427 /* draw old (source) image to screen buffer (left side) */
1429 src_rect.x = src_x + xx_final;
1432 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1434 /* draw old (source) image to screen buffer (right side) */
1436 src_rect.x = src_x + xx_size;
1437 dst_rect.x = dst_x + xx_size + xx_final;
1439 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1442 if (draw_border_function != NULL)
1443 draw_border_function();
1445 /* only update the region of the screen that is affected from fading */
1446 UpdateScreen(&dst_rect2);
1449 else /* fading in, fading out or cross-fading */
1454 for (alpha = 0.0; alpha < 255.0;)
1456 time_last = time_current;
1457 time_current = SDL_GetTicks();
1458 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1459 alpha_final = MIN(MAX(0, alpha), 255);
1461 /* draw existing (source) image to screen buffer */
1462 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1464 /* draw new (target) image to screen buffer using alpha blending */
1465 #if defined(TARGET_SDL2)
1466 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1467 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1469 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1471 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1473 if (draw_border_function != NULL)
1474 draw_border_function();
1476 /* only update the region of the screen that is affected from fading */
1477 UpdateScreen(&dst_rect);
1483 unsigned int time_post_delay;
1485 time_current = SDL_GetTicks();
1486 time_post_delay = time_current + post_delay;
1488 while (time_current < time_post_delay)
1490 // do not wait longer than 10 ms at a time to be able to ...
1491 Delay(MIN(10, time_post_delay - time_current));
1493 // ... continue drawing global animations during post delay
1496 time_current = SDL_GetTicks();
1500 // restore function for drawing global masked border
1501 gfx.draw_global_border_function = draw_global_border_function;
1504 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1505 int to_x, int to_y, Uint32 color)
1507 SDL_Surface *surface = dst_bitmap->surface;
1511 swap_numbers(&from_x, &to_x);
1514 swap_numbers(&from_y, &to_y);
1518 rect.w = (to_x - from_x + 1);
1519 rect.h = (to_y - from_y + 1);
1521 if (dst_bitmap == backbuffer || dst_bitmap == window)
1523 rect.x += video_xoffset;
1524 rect.y += video_yoffset;
1527 SDL_FillRect(surface, &rect, color);
1530 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1531 int to_x, int to_y, Uint32 color)
1533 if (dst_bitmap == backbuffer || dst_bitmap == window)
1535 from_x += video_xoffset;
1536 from_y += video_yoffset;
1537 to_x += video_xoffset;
1538 to_y += video_yoffset;
1541 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1544 #if ENABLE_UNUSED_CODE
1545 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1546 int num_points, Uint32 color)
1551 for (i = 0; i < num_points - 1; i++)
1553 for (x = 0; x < line_width; x++)
1555 for (y = 0; y < line_width; y++)
1557 int dx = x - line_width / 2;
1558 int dy = y - line_width / 2;
1560 if ((x == 0 && y == 0) ||
1561 (x == 0 && y == line_width - 1) ||
1562 (x == line_width - 1 && y == 0) ||
1563 (x == line_width - 1 && y == line_width - 1))
1566 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1567 points[i+1].x + dx, points[i+1].y + dy, color);
1574 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1576 SDL_Surface *surface = src_bitmap->surface;
1578 if (src_bitmap == backbuffer || src_bitmap == window)
1584 switch (surface->format->BytesPerPixel)
1586 case 1: /* assuming 8-bpp */
1588 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1592 case 2: /* probably 15-bpp or 16-bpp */
1594 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1598 case 3: /* slow 24-bpp mode; usually not used */
1600 /* does this work? */
1601 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1605 shift = surface->format->Rshift;
1606 color |= *(pix + shift / 8) >> shift;
1607 shift = surface->format->Gshift;
1608 color |= *(pix + shift / 8) >> shift;
1609 shift = surface->format->Bshift;
1610 color |= *(pix + shift / 8) >> shift;
1616 case 4: /* probably 32-bpp */
1618 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1627 /* ========================================================================= */
1628 /* The following functions were taken from the SGE library */
1629 /* (SDL Graphics Extension Library) by Anders Lindström */
1630 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1631 /* ========================================================================= */
1633 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1635 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1637 switch (surface->format->BytesPerPixel)
1641 /* Assuming 8-bpp */
1642 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1648 /* Probably 15-bpp or 16-bpp */
1649 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1655 /* Slow 24-bpp mode, usually not used */
1659 /* Gack - slow, but endian correct */
1660 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1661 shift = surface->format->Rshift;
1662 *(pix+shift/8) = color>>shift;
1663 shift = surface->format->Gshift;
1664 *(pix+shift/8) = color>>shift;
1665 shift = surface->format->Bshift;
1666 *(pix+shift/8) = color>>shift;
1672 /* Probably 32-bpp */
1673 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1680 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1681 Uint8 R, Uint8 G, Uint8 B)
1683 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1686 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1688 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1691 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1693 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1696 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1701 /* Gack - slow, but endian correct */
1702 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1703 shift = surface->format->Rshift;
1704 *(pix+shift/8) = color>>shift;
1705 shift = surface->format->Gshift;
1706 *(pix+shift/8) = color>>shift;
1707 shift = surface->format->Bshift;
1708 *(pix+shift/8) = color>>shift;
1711 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1713 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1716 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1718 switch (dest->format->BytesPerPixel)
1721 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1725 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1729 _PutPixel24(dest,x,y,color);
1733 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1738 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1740 if (SDL_MUSTLOCK(surface))
1742 if (SDL_LockSurface(surface) < 0)
1748 _PutPixel(surface, x, y, color);
1750 if (SDL_MUSTLOCK(surface))
1752 SDL_UnlockSurface(surface);
1756 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1757 Uint8 r, Uint8 g, Uint8 b)
1759 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1762 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1764 if (y >= 0 && y <= dest->h - 1)
1766 switch (dest->format->BytesPerPixel)
1769 return y*dest->pitch;
1773 return y*dest->pitch/2;
1777 return y*dest->pitch;
1781 return y*dest->pitch/4;
1789 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1791 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1793 switch (surface->format->BytesPerPixel)
1797 /* Assuming 8-bpp */
1798 *((Uint8 *)surface->pixels + ypitch + x) = color;
1804 /* Probably 15-bpp or 16-bpp */
1805 *((Uint16 *)surface->pixels + ypitch + x) = color;
1811 /* Slow 24-bpp mode, usually not used */
1815 /* Gack - slow, but endian correct */
1816 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1817 shift = surface->format->Rshift;
1818 *(pix+shift/8) = color>>shift;
1819 shift = surface->format->Gshift;
1820 *(pix+shift/8) = color>>shift;
1821 shift = surface->format->Bshift;
1822 *(pix+shift/8) = color>>shift;
1828 /* Probably 32-bpp */
1829 *((Uint32 *)surface->pixels + ypitch + x) = color;
1836 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1841 if (SDL_MUSTLOCK(Surface))
1843 if (SDL_LockSurface(Surface) < 0)
1856 /* Do the clipping */
1857 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1861 if (x2 > Surface->w - 1)
1862 x2 = Surface->w - 1;
1869 SDL_FillRect(Surface, &l, Color);
1871 if (SDL_MUSTLOCK(Surface))
1873 SDL_UnlockSurface(Surface);
1877 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1878 Uint8 R, Uint8 G, Uint8 B)
1880 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1883 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1894 /* Do the clipping */
1895 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1899 if (x2 > Surface->w - 1)
1900 x2 = Surface->w - 1;
1907 SDL_FillRect(Surface, &l, Color);
1910 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1915 if (SDL_MUSTLOCK(Surface))
1917 if (SDL_LockSurface(Surface) < 0)
1930 /* Do the clipping */
1931 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1935 if (y2 > Surface->h - 1)
1936 y2 = Surface->h - 1;
1943 SDL_FillRect(Surface, &l, Color);
1945 if (SDL_MUSTLOCK(Surface))
1947 SDL_UnlockSurface(Surface);
1951 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1952 Uint8 R, Uint8 G, Uint8 B)
1954 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1957 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1968 /* Do the clipping */
1969 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1973 if (y2 > Surface->h - 1)
1974 y2 = Surface->h - 1;
1981 SDL_FillRect(Surface, &l, Color);
1984 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1985 Sint16 x2, Sint16 y2, Uint32 Color,
1986 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1989 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1994 sdx = (dx < 0) ? -1 : 1;
1995 sdy = (dy < 0) ? -1 : 1;
2007 for (x = 0; x < dx; x++)
2009 Callback(Surface, px, py, Color);
2023 for (y = 0; y < dy; y++)
2025 Callback(Surface, px, py, Color);
2039 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
2040 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
2041 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
2044 sge_DoLine(Surface, X1, Y1, X2, Y2,
2045 SDL_MapRGB(Surface->format, R, G, B), Callback);
2048 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
2051 if (SDL_MUSTLOCK(Surface))
2053 if (SDL_LockSurface(Surface) < 0)
2058 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
2060 /* unlock the display */
2061 if (SDL_MUSTLOCK(Surface))
2063 SDL_UnlockSurface(Surface);
2067 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
2068 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
2070 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
2073 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
2075 if (dst_bitmap == backbuffer || dst_bitmap == window)
2081 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
2086 -----------------------------------------------------------------------------
2087 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
2088 -----------------------------------------------------------------------------
2091 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
2092 int width, int height, Uint32 color)
2096 for (y = src_y; y < src_y + height; y++)
2098 for (x = src_x; x < src_x + width; x++)
2100 Uint32 pixel = SDLGetPixel(bitmap, x, y);
2102 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
2107 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
2108 int src_x, int src_y, int width, int height,
2109 int dst_x, int dst_y)
2113 for (y = 0; y < height; y++)
2115 for (x = 0; x < width; x++)
2117 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
2119 if (pixel != BLACK_PIXEL)
2120 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
2126 /* ========================================================================= */
2127 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
2128 /* (Rotozoomer) by Andreas Schiffler */
2129 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
2130 /* ========================================================================= */
2133 -----------------------------------------------------------------------------
2136 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
2137 -----------------------------------------------------------------------------
2148 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
2151 tColorRGBA *sp, *csp, *dp;
2155 sp = csp = (tColorRGBA *) src->pixels;
2156 dp = (tColorRGBA *) dst->pixels;
2157 dgap = dst->pitch - dst->w * 4;
2159 for (y = 0; y < dst->h; y++)
2163 for (x = 0; x < dst->w; x++)
2165 tColorRGBA *sp0 = sp;
2166 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2167 tColorRGBA *sp00 = &sp0[0];
2168 tColorRGBA *sp01 = &sp0[1];
2169 tColorRGBA *sp10 = &sp1[0];
2170 tColorRGBA *sp11 = &sp1[1];
2173 /* create new color pixel from all four source color pixels */
2174 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2175 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2176 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2177 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2182 /* advance source pointers */
2185 /* advance destination pointer */
2189 /* advance source pointer */
2190 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2192 /* advance destination pointers */
2193 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2199 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2201 int x, y, *sax, *say, *csax, *csay;
2203 tColorRGBA *sp, *csp, *csp0, *dp;
2206 /* use specialized zoom function when scaling down to exactly half size */
2207 if (src->w == 2 * dst->w &&
2208 src->h == 2 * dst->h)
2209 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2211 /* variable setup */
2212 sx = (float) src->w / (float) dst->w;
2213 sy = (float) src->h / (float) dst->h;
2215 /* allocate memory for row increments */
2216 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2217 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2219 /* precalculate row increments */
2220 for (x = 0; x <= dst->w; x++)
2221 *csax++ = (int)(sx * x);
2223 for (y = 0; y <= dst->h; y++)
2224 *csay++ = (int)(sy * y);
2227 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2228 dp = (tColorRGBA *) dst->pixels;
2229 dgap = dst->pitch - dst->w * 4;
2232 for (y = 0; y < dst->h; y++)
2237 for (x = 0; x < dst->w; x++)
2242 /* advance source pointers */
2246 /* advance destination pointer */
2250 /* advance source pointer */
2252 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2254 /* advance destination pointers */
2255 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2265 -----------------------------------------------------------------------------
2268 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2269 -----------------------------------------------------------------------------
2272 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2274 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2275 Uint8 *sp, *dp, *csp;
2278 /* variable setup */
2279 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2280 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2282 /* allocate memory for row increments */
2283 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2284 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2286 /* precalculate row increments */
2289 for (x = 0; x < dst->w; x++)
2292 *csax = (csx >> 16);
2299 for (y = 0; y < dst->h; y++)
2302 *csay = (csy >> 16);
2309 for (x = 0; x < dst->w; x++)
2317 for (y = 0; y < dst->h; y++)
2324 sp = csp = (Uint8 *) src->pixels;
2325 dp = (Uint8 *) dst->pixels;
2326 dgap = dst->pitch - dst->w;
2330 for (y = 0; y < dst->h; y++)
2334 for (x = 0; x < dst->w; x++)
2339 /* advance source pointers */
2343 /* advance destination pointer */
2347 /* advance source pointer (for row) */
2348 csp += ((*csay) * src->pitch);
2351 /* advance destination pointers */
2362 -----------------------------------------------------------------------------
2365 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2366 'zoomx' and 'zoomy' are scaling factors for width and height.
2367 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2368 into a 32bit RGBA format on the fly.
2369 -----------------------------------------------------------------------------
2372 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2374 SDL_Surface *zoom_src = NULL;
2375 SDL_Surface *zoom_dst = NULL;
2376 boolean is_converted = FALSE;
2383 /* determine if source surface is 32 bit or 8 bit */
2384 is_32bit = (src->format->BitsPerPixel == 32);
2386 if (is_32bit || src->format->BitsPerPixel == 8)
2388 /* use source surface 'as is' */
2393 /* new source surface is 32 bit with a defined RGB ordering */
2394 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2395 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2396 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2398 is_converted = TRUE;
2401 /* allocate surface to completely contain the zoomed surface */
2404 /* target surface is 32 bit with source RGBA/ABGR ordering */
2405 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2406 zoom_src->format->Rmask,
2407 zoom_src->format->Gmask,
2408 zoom_src->format->Bmask, 0);
2412 /* target surface is 8 bit */
2413 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2417 /* lock source surface */
2418 SDL_LockSurface(zoom_src);
2420 /* check which kind of surface we have */
2423 /* call the 32 bit transformation routine to do the zooming */
2424 zoomSurfaceRGBA(zoom_src, zoom_dst);
2429 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2430 zoom_dst->format->palette->colors[i] =
2431 zoom_src->format->palette->colors[i];
2432 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2434 /* call the 8 bit transformation routine to do the zooming */
2435 zoomSurfaceY(zoom_src, zoom_dst);
2438 /* unlock source surface */
2439 SDL_UnlockSurface(zoom_src);
2441 /* free temporary surface */
2443 SDL_FreeSurface(zoom_src);
2445 /* return destination surface */
2449 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2451 Bitmap *dst_bitmap = CreateBitmapStruct();
2452 SDL_Surface **dst_surface = &dst_bitmap->surface;
2454 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2455 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2457 dst_bitmap->width = dst_width;
2458 dst_bitmap->height = dst_height;
2460 /* create zoomed temporary surface from source surface */
2461 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2463 /* create native format destination surface from zoomed temporary surface */
2464 SDLSetNativeSurface(dst_surface);
2470 /* ========================================================================= */
2471 /* load image to bitmap */
2472 /* ========================================================================= */
2474 Bitmap *SDLLoadImage(char *filename)
2476 Bitmap *new_bitmap = CreateBitmapStruct();
2477 SDL_Surface *sdl_image_tmp;
2479 print_timestamp_init("SDLLoadImage");
2481 print_timestamp_time(getBaseNamePtr(filename));
2483 /* load image to temporary surface */
2484 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2486 SetError("IMG_Load(): %s", SDL_GetError());
2491 print_timestamp_time("IMG_Load");
2493 UPDATE_BUSY_STATE();
2495 /* create native non-transparent surface for current image */
2496 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2498 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2503 print_timestamp_time("SDL_DisplayFormat (opaque)");
2505 UPDATE_BUSY_STATE();
2507 /* create native transparent surface for current image */
2508 if (sdl_image_tmp->format->Amask == 0)
2509 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2510 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2512 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2514 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2519 print_timestamp_time("SDL_DisplayFormat (masked)");
2521 UPDATE_BUSY_STATE();
2523 /* free temporary surface */
2524 SDL_FreeSurface(sdl_image_tmp);
2526 new_bitmap->width = new_bitmap->surface->w;
2527 new_bitmap->height = new_bitmap->surface->h;
2529 print_timestamp_done("SDLLoadImage");
2535 /* ------------------------------------------------------------------------- */
2536 /* custom cursor fuctions */
2537 /* ------------------------------------------------------------------------- */
2539 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2541 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2542 cursor_info->width, cursor_info->height,
2543 cursor_info->hot_x, cursor_info->hot_y);
2546 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2548 static struct MouseCursorInfo *last_cursor_info = NULL;
2549 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2550 static SDL_Cursor *cursor_default = NULL;
2551 static SDL_Cursor *cursor_current = NULL;
2553 /* if invoked for the first time, store the SDL default cursor */
2554 if (cursor_default == NULL)
2555 cursor_default = SDL_GetCursor();
2557 /* only create new cursor if cursor info (custom only) has changed */
2558 if (cursor_info != NULL && cursor_info != last_cursor_info)
2560 cursor_current = create_cursor(cursor_info);
2561 last_cursor_info = cursor_info;
2564 /* only set new cursor if cursor info (custom or NULL) has changed */
2565 if (cursor_info != last_cursor_info2)
2566 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2568 last_cursor_info2 = cursor_info;
2572 /* ========================================================================= */
2573 /* audio functions */
2574 /* ========================================================================= */
2576 void SDLOpenAudio(void)
2578 #if !defined(TARGET_SDL2)
2579 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2580 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2583 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2585 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2589 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2590 AUDIO_NUM_CHANNELS_STEREO,
2591 setup.system.audio_fragment_size) < 0)
2593 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2597 audio.sound_available = TRUE;
2598 audio.music_available = TRUE;
2599 audio.loops_available = TRUE;
2600 audio.sound_enabled = TRUE;
2602 /* set number of available mixer channels */
2603 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2604 audio.music_channel = MUSIC_CHANNEL;
2605 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2607 Mixer_InitChannels();
2610 void SDLCloseAudio(void)
2613 Mix_HaltChannel(-1);
2616 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2620 /* ========================================================================= */
2621 /* event functions */
2622 /* ========================================================================= */
2624 void SDLNextEvent(Event *event)
2626 SDL_WaitEvent(event);
2628 if (event->type == EVENT_BUTTONPRESS ||
2629 event->type == EVENT_BUTTONRELEASE)
2631 if (((ButtonEvent *)event)->x > video_xoffset)
2632 ((ButtonEvent *)event)->x -= video_xoffset;
2634 ((ButtonEvent *)event)->x = 0;
2635 if (((ButtonEvent *)event)->y > video_yoffset)
2636 ((ButtonEvent *)event)->y -= video_yoffset;
2638 ((ButtonEvent *)event)->y = 0;
2640 else if (event->type == EVENT_MOTIONNOTIFY)
2642 if (((MotionEvent *)event)->x > video_xoffset)
2643 ((MotionEvent *)event)->x -= video_xoffset;
2645 ((MotionEvent *)event)->x = 0;
2646 if (((MotionEvent *)event)->y > video_yoffset)
2647 ((MotionEvent *)event)->y -= video_yoffset;
2649 ((MotionEvent *)event)->y = 0;
2653 void SDLHandleWindowManagerEvent(Event *event)
2656 #if defined(PLATFORM_WIN32)
2657 // experimental drag and drop code
2659 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2660 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2662 #if defined(TARGET_SDL2)
2663 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2665 if (syswmmsg->msg == WM_DROPFILES)
2668 #if defined(TARGET_SDL2)
2669 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2671 HDROP hdrop = (HDROP)syswmmsg->wParam;
2675 printf("::: SDL_SYSWMEVENT:\n");
2677 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2679 for (i = 0; i < num_files; i++)
2681 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2682 char buffer[buffer_len + 1];
2684 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2686 printf("::: - '%s'\n", buffer);
2689 #if defined(TARGET_SDL2)
2690 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2692 DragFinish((HDROP)syswmmsg->wParam);
2700 /* ========================================================================= */
2701 /* joystick functions */
2702 /* ========================================================================= */
2704 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2705 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2706 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2708 static boolean SDLOpenJoystick(int nr)
2710 if (nr < 0 || nr > MAX_PLAYERS)
2713 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2716 static void SDLCloseJoystick(int nr)
2718 if (nr < 0 || nr > MAX_PLAYERS)
2721 SDL_JoystickClose(sdl_joystick[nr]);
2723 sdl_joystick[nr] = NULL;
2726 static boolean SDLCheckJoystickOpened(int nr)
2728 if (nr < 0 || nr > MAX_PLAYERS)
2731 #if defined(TARGET_SDL2)
2732 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2734 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2738 void HandleJoystickEvent(Event *event)
2742 case SDL_JOYAXISMOTION:
2743 if (event->jaxis.axis < 2)
2744 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2747 case SDL_JOYBUTTONDOWN:
2748 if (event->jbutton.button < 2)
2749 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2752 case SDL_JOYBUTTONUP:
2753 if (event->jbutton.button < 2)
2754 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2762 void SDLInitJoysticks()
2764 static boolean sdl_joystick_subsystem_initialized = FALSE;
2765 boolean print_warning = !sdl_joystick_subsystem_initialized;
2768 if (!sdl_joystick_subsystem_initialized)
2770 sdl_joystick_subsystem_initialized = TRUE;
2772 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2774 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2779 for (i = 0; i < MAX_PLAYERS; i++)
2781 /* get configured joystick for this player */
2782 char *device_name = setup.input[i].joy.device_name;
2783 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2785 if (joystick_nr >= SDL_NumJoysticks())
2787 if (setup.input[i].use_joystick && print_warning)
2788 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2793 /* misuse joystick file descriptor variable to store joystick number */
2794 joystick.fd[i] = joystick_nr;
2796 if (joystick_nr == -1)
2799 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2800 if (SDLCheckJoystickOpened(joystick_nr))
2801 SDLCloseJoystick(joystick_nr);
2803 if (!setup.input[i].use_joystick)
2806 if (!SDLOpenJoystick(joystick_nr))
2809 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2814 joystick.status = JOYSTICK_ACTIVATED;
2818 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2820 if (nr < 0 || nr >= MAX_PLAYERS)
2824 *x = sdl_js_axis[nr][0];
2826 *y = sdl_js_axis[nr][1];
2829 *b1 = sdl_js_button[nr][0];
2831 *b2 = sdl_js_button[nr][1];