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;
41 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
42 static int fullscreen_width;
43 static int fullscreen_height;
44 static int fullscreen_xoffset;
45 static int fullscreen_yoffset;
46 static int video_xoffset;
47 static int video_yoffset;
48 static boolean limit_screen_updates = FALSE;
51 /* functions from SGE library */
52 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
54 void SDLLimitScreenUpdates(boolean enable)
56 limit_screen_updates = enable;
59 static void UpdateScreen(SDL_Rect *rect)
61 static unsigned int update_screen_delay = 0;
62 unsigned int update_screen_delay_value = 50; /* (milliseconds) */
63 SDL_Surface *screen = backbuffer->surface;
65 if (limit_screen_updates &&
66 !DelayReached(&update_screen_delay, update_screen_delay_value))
69 LimitScreenUpdates(FALSE);
73 static int LastFrameCounter = 0;
74 boolean changed = (FrameCounter != LastFrameCounter);
76 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
77 (changed ? "-" : "SAME FRAME UPDATED"));
79 LastFrameCounter = FrameCounter;
88 #if USE_FINAL_SCREEN_BITMAP
89 if (gfx.final_screen_bitmap != NULL) // may not be initialized yet
92 // draw global animations using bitmaps instead of using textures
93 // to prevent texture scaling artefacts (this is potentially slower)
95 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
96 gfx.win_xsize, gfx.win_ysize, 0, 0);
98 // copy global animations to render target buffer, if defined (below border)
99 if (gfx.draw_global_anim_function != NULL)
100 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
102 // copy global masked border to render target buffer, if defined
103 if (gfx.draw_global_border_function != NULL)
104 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
106 // copy global animations to render target buffer, if defined (above border)
107 if (gfx.draw_global_anim_function != NULL)
108 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
110 screen = gfx.final_screen_bitmap->surface;
112 // force full window redraw
117 #if USE_TARGET_TEXTURE
118 #if USE_TARGET_TEXTURE_ONLY
119 SDL_Texture *sdl_texture = sdl_texture_target;
121 SDL_Texture *sdl_texture = sdl_texture_stream;
125 #if defined(TARGET_SDL2)
128 int bytes_x = screen->pitch / video.width;
129 int bytes_y = screen->pitch;
131 if (video.fullscreen_enabled)
132 bytes_x = screen->pitch / fullscreen_width;
134 SDL_UpdateTexture(sdl_texture, rect,
135 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
140 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
143 // clear render target buffer
144 SDL_RenderClear(sdl_renderer);
146 #if USE_TARGET_TEXTURE
147 SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
149 // copy backbuffer to render target buffer
150 if (sdl_texture != sdl_texture_target)
151 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
153 // copy backbuffer to render target buffer
154 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
157 #if !USE_FINAL_SCREEN_BITMAP
158 // copy global animations to render target buffer, if defined (below border)
159 if (gfx.draw_global_anim_function != NULL)
160 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
162 // copy global masked border to render target buffer, if defined
163 if (gfx.draw_global_border_function != NULL)
164 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
166 // copy global animations to render target buffer, if defined (above border)
167 if (gfx.draw_global_anim_function != NULL)
168 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
171 #if USE_TARGET_TEXTURE
172 SDL_SetRenderTarget(sdl_renderer, NULL);
173 SDL_RenderCopy(sdl_renderer, sdl_texture_target, NULL, NULL);
176 // show render target buffer on screen
177 SDL_RenderPresent(sdl_renderer);
181 SDL_UpdateRects(screen, 1, rect);
183 SDL_UpdateRect(screen, 0, 0, 0, 0);
187 static void setFullscreenParameters(char *fullscreen_mode_string)
189 #if defined(TARGET_SDL2)
190 fullscreen_width = video.width;
191 fullscreen_height = video.height;
192 fullscreen_xoffset = 0;
193 fullscreen_yoffset = 0;
197 struct ScreenModeInfo *fullscreen_mode;
200 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
202 if (fullscreen_mode == NULL)
205 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
207 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
208 fullscreen_mode->height == video.fullscreen_modes[i].height)
210 fullscreen_width = fullscreen_mode->width;
211 fullscreen_height = fullscreen_mode->height;
213 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
214 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
222 static void SDLSetWindowIcon(char *basename)
224 /* (setting the window icon on Mac OS X would replace the high-quality
225 dock icon with the currently smaller (and uglier) icon from file) */
227 #if !defined(PLATFORM_MACOSX)
228 char *filename = getCustomImageFilename(basename);
229 SDL_Surface *surface;
231 if (filename == NULL)
233 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
238 if ((surface = IMG_Load(filename)) == NULL)
240 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
245 /* set transparent color */
246 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
247 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
249 #if defined(TARGET_SDL2)
250 SDL_SetWindowIcon(sdl_window, surface);
252 SDL_WM_SetIcon(surface, NULL);
257 #if defined(TARGET_SDL2)
259 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
260 SDL_PixelFormat *format2)
262 return (format1->format == format2->format &&
263 format1->BitsPerPixel == format2->BitsPerPixel &&
264 format1->BytesPerPixel == format2->BytesPerPixel &&
265 format1->Rmask == format2->Rmask &&
266 format1->Gmask == format2->Gmask &&
267 format1->Bmask == format2->Bmask &&
268 format1->Amask == format2->Amask);
271 boolean SDLSetNativeSurface(SDL_Surface **surface)
273 SDL_Surface *new_surface;
275 if (surface == NULL ||
277 backbuffer == NULL ||
278 backbuffer->surface == NULL)
281 // if pixel format already optimized for destination surface, do nothing
282 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
285 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
287 if (new_surface == NULL)
288 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
290 SDL_FreeSurface(*surface);
292 *surface = new_surface;
297 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
299 SDL_PixelFormat format;
300 SDL_Surface *new_surface;
305 if (backbuffer && backbuffer->surface)
307 format = *backbuffer->surface->format;
308 format.Amask = surface->format->Amask; // keep alpha channel
312 format = *surface->format;
315 new_surface = SDL_ConvertSurface(surface, &format, 0);
317 if (new_surface == NULL)
318 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
325 boolean SDLSetNativeSurface(SDL_Surface **surface)
327 SDL_Surface *new_surface;
329 if (surface == NULL ||
334 new_surface = SDL_DisplayFormat(*surface);
336 if (new_surface == NULL)
337 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
339 SDL_FreeSurface(*surface);
341 *surface = new_surface;
346 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
348 SDL_Surface *new_surface;
350 if (video.initialized)
351 new_surface = SDL_DisplayFormat(surface);
353 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
355 if (new_surface == NULL)
356 Error(ERR_EXIT, "%s() failed: %s",
357 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
365 #if defined(TARGET_SDL2)
366 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
368 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
371 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
378 void SDLCreateBitmapTextures(Bitmap *bitmap)
380 #if defined(TARGET_SDL2)
385 SDL_DestroyTexture(bitmap->texture);
386 if (bitmap->texture_masked)
387 SDL_DestroyTexture(bitmap->texture_masked);
389 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
390 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
394 void SDLFreeBitmapTextures(Bitmap *bitmap)
396 #if defined(TARGET_SDL2)
401 SDL_DestroyTexture(bitmap->texture);
402 if (bitmap->texture_masked)
403 SDL_DestroyTexture(bitmap->texture_masked);
405 bitmap->texture = NULL;
406 bitmap->texture_masked = NULL;
410 void SDLInitVideoDisplay(void)
412 #if !defined(TARGET_SDL2)
413 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
414 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
416 SDL_putenv("SDL_VIDEO_CENTERED=1");
419 /* initialize SDL video */
420 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
421 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
423 /* set default SDL depth */
424 #if !defined(TARGET_SDL2)
425 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
427 video.default_depth = 32; // (how to determine video depth in SDL2?)
431 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
434 #if !defined(TARGET_SDL2)
435 static int screen_xy[][2] =
443 SDL_Rect **modes = NULL;
444 boolean hardware_fullscreen_available = TRUE;
447 /* default: normal game window size */
448 fullscreen_width = video.width;
449 fullscreen_height = video.height;
450 fullscreen_xoffset = 0;
451 fullscreen_yoffset = 0;
453 #if !defined(TARGET_SDL2)
454 /* determine required standard fullscreen mode for game screen size */
455 for (i = 0; screen_xy[i][0] != -1; i++)
457 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
459 fullscreen_width = screen_xy[i][0];
460 fullscreen_height = screen_xy[i][1];
466 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
467 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
470 checked_free(video.fullscreen_modes);
472 video.fullscreen_modes = NULL;
473 video.fullscreen_mode_current = NULL;
475 video.window_scaling_percent = setup.window_scaling_percent;
476 video.window_scaling_quality = setup.window_scaling_quality;
478 #if defined(TARGET_SDL2)
479 int num_displays = SDL_GetNumVideoDisplays();
481 if (num_displays > 0)
483 // currently only display modes of first display supported
484 int num_modes = SDL_GetNumDisplayModes(0);
488 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
490 for (i = 0; i < num_modes; i++)
492 SDL_DisplayMode mode;
494 if (SDL_GetDisplayMode(0, i, &mode) < 0)
497 modes[i] = checked_calloc(sizeof(SDL_Rect));
499 modes[i]->w = mode.w;
500 modes[i]->h = mode.h;
505 /* get available hardware supported fullscreen modes */
506 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
511 /* no hardware screen modes available => no fullscreen mode support */
512 // video.fullscreen_available = FALSE;
513 hardware_fullscreen_available = FALSE;
515 else if (modes == (SDL_Rect **)-1)
517 /* fullscreen resolution is not restricted -- all resolutions available */
518 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
520 /* use native video buffer size for fullscreen mode */
521 video.fullscreen_modes[0].width = video.width;
522 video.fullscreen_modes[0].height = video.height;
524 video.fullscreen_modes[1].width = -1;
525 video.fullscreen_modes[1].height = -1;
529 /* in this case, a certain number of screen modes is available */
532 for (i = 0; modes[i] != NULL; i++)
534 boolean found_mode = FALSE;
536 /* screen mode is smaller than video buffer size -- skip it */
537 if (modes[i]->w < video.width || modes[i]->h < video.height)
540 if (video.fullscreen_modes != NULL)
541 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
542 if (modes[i]->w == video.fullscreen_modes[j].width &&
543 modes[i]->h == video.fullscreen_modes[j].height)
546 if (found_mode) /* screen mode already stored -- skip it */
549 /* new mode found; add it to list of available fullscreen modes */
553 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
555 sizeof(struct ScreenModeInfo));
557 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
558 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
560 video.fullscreen_modes[num_modes].width = -1;
561 video.fullscreen_modes[num_modes].height = -1;
566 /* no appropriate screen modes available => no fullscreen mode support */
567 // video.fullscreen_available = FALSE;
568 hardware_fullscreen_available = FALSE;
572 video.fullscreen_available = hardware_fullscreen_available;
574 #if USE_DESKTOP_FULLSCREEN
575 // in SDL 2.0, there is always support for desktop fullscreen mode
576 // (in SDL 1.2, there is only support for "real" fullscreen mode)
577 video.fullscreen_available = TRUE;
580 #if defined(TARGET_SDL2)
583 for (i = 0; modes[i] != NULL; i++)
584 checked_free(modes[i]);
590 /* open SDL video output device (window or fullscreen mode) */
591 if (!SDLSetVideoMode(backbuffer, fullscreen))
592 Error(ERR_EXIT, "setting video mode failed");
594 /* !!! SDL2 can only set the window icon if the window already exists !!! */
595 /* set window icon */
596 SDLSetWindowIcon(program.icon_filename);
598 /* set window and icon title */
599 #if defined(TARGET_SDL2)
600 SDL_SetWindowTitle(sdl_window, program.window_title);
602 SDL_WM_SetCaption(program.window_title, program.window_title);
605 /* SDL cannot directly draw to the visible video framebuffer like X11,
606 but always uses a backbuffer, which is then blitted to the visible
607 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
608 visible video framebuffer with 'SDL_Flip', if the hardware supports
609 this). Therefore do not use an additional backbuffer for drawing, but
610 use a symbolic buffer (distinguishable from the SDL backbuffer) called
611 'window', which indicates that the SDL backbuffer should be updated to
612 the visible video framebuffer when attempting to blit to it.
614 For convenience, it seems to be a good idea to create this symbolic
615 buffer 'window' at the same size as the SDL backbuffer. Although it
616 should never be drawn to directly, it would do no harm nevertheless. */
618 /* create additional (symbolic) buffer for double-buffering */
619 ReCreateBitmap(window, video.width, video.height, video.depth);
622 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
625 SDL_Surface *new_surface = NULL;
627 #if defined(TARGET_SDL2)
628 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
629 #if USE_DESKTOP_FULLSCREEN
630 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
632 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
636 int surface_flags_window = SURFACE_FLAGS;
637 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
640 int width = (fullscreen ? fullscreen_width : video.width);
641 int height = (fullscreen ? fullscreen_height : video.height);
642 int surface_flags = (fullscreen ? surface_flags_fullscreen :
643 surface_flags_window);
645 // default window size is unscaled
646 video.window_width = video.width;
647 video.window_height = video.height;
649 #if defined(TARGET_SDL2)
651 // store if initial screen mode is fullscreen mode when changing screen size
652 video.fullscreen_initial = fullscreen;
654 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
655 #if !USE_DESKTOP_FULLSCREEN
656 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
659 video.window_width = window_scaling_factor * width;
660 video.window_height = window_scaling_factor * height;
662 if ((*backbuffer)->surface)
664 SDL_FreeSurface((*backbuffer)->surface);
665 (*backbuffer)->surface = NULL;
668 #if USE_TARGET_TEXTURE
669 if (sdl_texture_stream)
671 SDL_DestroyTexture(sdl_texture_stream);
672 sdl_texture_stream = NULL;
675 if (sdl_texture_target)
677 SDL_DestroyTexture(sdl_texture_target);
678 sdl_texture_target = NULL;
683 SDL_DestroyTexture(sdl_texture);
688 if (!(fullscreen && fullscreen_enabled))
692 SDL_DestroyRenderer(sdl_renderer);
698 SDL_DestroyWindow(sdl_window);
703 if (sdl_window == NULL)
704 sdl_window = SDL_CreateWindow(program.window_title,
705 SDL_WINDOWPOS_CENTERED,
706 SDL_WINDOWPOS_CENTERED,
707 #if USE_DESKTOP_FULLSCREEN
711 (int)(screen_scaling_factor * width),
712 (int)(screen_scaling_factor * height),
716 if (sdl_window != NULL)
719 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
720 *without* enabling 2D/3D acceleration and/or guest additions installed,
721 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
722 it will try to use accelerated graphics and apparently fails miserably) */
723 if (sdl_renderer == NULL)
724 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
726 if (sdl_renderer == NULL)
727 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
730 if (sdl_renderer != NULL)
732 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
733 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
734 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
736 #if USE_TARGET_TEXTURE
737 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
738 SDL_PIXELFORMAT_ARGB8888,
739 SDL_TEXTUREACCESS_STREAMING,
742 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
743 SDL_PIXELFORMAT_ARGB8888,
744 SDL_TEXTUREACCESS_TARGET,
747 sdl_texture = SDL_CreateTexture(sdl_renderer,
748 SDL_PIXELFORMAT_ARGB8888,
749 SDL_TEXTUREACCESS_STREAMING,
753 #if USE_TARGET_TEXTURE
754 if (sdl_texture_stream != NULL &&
755 sdl_texture_target != NULL)
757 if (sdl_texture != NULL)
760 // use SDL default values for RGB masks and no alpha channel
761 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
763 if (new_surface == NULL)
764 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
769 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
774 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
779 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
783 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
786 #if defined(TARGET_SDL2)
787 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
788 if (new_surface != NULL)
789 fullscreen_enabled = fullscreen;
795 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
797 boolean success = TRUE;
798 SDL_Surface *new_surface = NULL;
802 if (*backbuffer == NULL)
803 *backbuffer = CreateBitmapStruct();
805 /* (real bitmap might be larger in fullscreen mode with video offsets) */
806 (*backbuffer)->width = video.width;
807 (*backbuffer)->height = video.height;
809 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
811 setFullscreenParameters(setup.fullscreen_mode);
813 video_xoffset = fullscreen_xoffset;
814 video_yoffset = fullscreen_yoffset;
816 /* switch display to fullscreen mode, if available */
817 new_surface = SDLCreateScreen(backbuffer, TRUE);
819 if (new_surface == NULL)
821 /* switching display to fullscreen mode failed */
822 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
824 /* do not try it again */
825 video.fullscreen_available = FALSE;
831 (*backbuffer)->surface = new_surface;
833 video.fullscreen_enabled = TRUE;
834 video.fullscreen_mode_current = setup.fullscreen_mode;
840 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
845 /* switch display to window mode */
846 new_surface = SDLCreateScreen(backbuffer, FALSE);
848 if (new_surface == NULL)
850 /* switching display to window mode failed -- should not happen */
851 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
857 (*backbuffer)->surface = new_surface;
859 video.fullscreen_enabled = FALSE;
860 video.window_scaling_percent = setup.window_scaling_percent;
861 video.window_scaling_quality = setup.window_scaling_quality;
867 #if defined(TARGET_SDL2)
868 SDLRedrawWindow(); // map window
872 #if defined(PLATFORM_WIN32)
873 // experimental drag and drop code
875 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
878 SDL_SysWMinfo wminfo;
880 boolean wminfo_success = FALSE;
882 SDL_VERSION(&wminfo.version);
883 #if defined(TARGET_SDL2)
885 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
887 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
892 #if defined(TARGET_SDL2)
893 hwnd = wminfo.info.win.window;
895 hwnd = wminfo.window;
898 DragAcceptFiles(hwnd, TRUE);
907 void SDLSetWindowTitle()
909 #if defined(TARGET_SDL2)
910 SDL_SetWindowTitle(sdl_window, program.window_title);
912 SDL_WM_SetCaption(program.window_title, program.window_title);
916 #if defined(TARGET_SDL2)
917 void SDLSetWindowScaling(int window_scaling_percent)
919 if (sdl_window == NULL)
922 float window_scaling_factor = (float)window_scaling_percent / 100;
923 int new_window_width = (int)(window_scaling_factor * video.width);
924 int new_window_height = (int)(window_scaling_factor * video.height);
926 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
928 video.window_scaling_percent = window_scaling_percent;
929 video.window_width = new_window_width;
930 video.window_height = new_window_height;
935 void SDLSetWindowScalingQuality(char *window_scaling_quality)
937 #if USE_TARGET_TEXTURE
938 SDL_Texture *new_texture;
940 if (sdl_texture_stream == NULL ||
941 sdl_texture_target == NULL)
944 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
946 new_texture = SDL_CreateTexture(sdl_renderer,
947 SDL_PIXELFORMAT_ARGB8888,
948 SDL_TEXTUREACCESS_STREAMING,
949 video.width, video.height);
951 if (new_texture != NULL)
953 SDL_DestroyTexture(sdl_texture_stream);
955 sdl_texture_stream = new_texture;
958 new_texture = SDL_CreateTexture(sdl_renderer,
959 SDL_PIXELFORMAT_ARGB8888,
960 SDL_TEXTUREACCESS_TARGET,
961 video.width, video.height);
963 if (new_texture != NULL)
965 SDL_DestroyTexture(sdl_texture_target);
967 sdl_texture_target = new_texture;
973 if (sdl_texture == NULL)
976 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
978 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
979 SDL_PIXELFORMAT_ARGB8888,
980 SDL_TEXTUREACCESS_STREAMING,
981 video.width, video.height);
983 if (new_texture != NULL)
985 SDL_DestroyTexture(sdl_texture);
987 sdl_texture = new_texture;
993 video.window_scaling_quality = window_scaling_quality;
996 void SDLSetWindowFullscreen(boolean fullscreen)
998 if (sdl_window == NULL)
1001 #if USE_DESKTOP_FULLSCREEN
1002 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
1004 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
1007 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
1008 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
1010 // if screen size was changed in fullscreen mode, correct desktop window size
1011 if (!fullscreen && video.fullscreen_initial)
1013 SDLSetWindowScaling(setup.window_scaling_percent);
1014 SDL_SetWindowPosition(sdl_window,
1015 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
1017 video.fullscreen_initial = FALSE;
1021 void SDLRedrawWindow()
1027 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
1030 SDL_Surface *surface =
1031 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
1033 if (surface == NULL)
1034 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1036 SDLSetNativeSurface(&surface);
1038 bitmap->surface = surface;
1041 void SDLFreeBitmapPointers(Bitmap *bitmap)
1043 if (bitmap->surface)
1044 SDL_FreeSurface(bitmap->surface);
1045 if (bitmap->surface_masked)
1046 SDL_FreeSurface(bitmap->surface_masked);
1048 bitmap->surface = NULL;
1049 bitmap->surface_masked = NULL;
1051 #if defined(TARGET_SDL2)
1052 if (bitmap->texture)
1053 SDL_DestroyTexture(bitmap->texture);
1054 if (bitmap->texture_masked)
1055 SDL_DestroyTexture(bitmap->texture_masked);
1057 bitmap->texture = NULL;
1058 bitmap->texture_masked = NULL;
1062 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1063 int src_x, int src_y, int width, int height,
1064 int dst_x, int dst_y, int mask_mode)
1066 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1067 SDL_Rect src_rect, dst_rect;
1069 if (src_bitmap == backbuffer)
1071 src_x += video_xoffset;
1072 src_y += video_yoffset;
1078 src_rect.h = height;
1080 if (dst_bitmap == backbuffer || dst_bitmap == window)
1082 dst_x += video_xoffset;
1083 dst_y += video_yoffset;
1089 dst_rect.h = height;
1091 // if (src_bitmap != backbuffer || dst_bitmap != window)
1092 if (!(src_bitmap == backbuffer && dst_bitmap == window))
1093 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
1094 src_bitmap->surface_masked : src_bitmap->surface),
1095 &src_rect, real_dst_bitmap->surface, &dst_rect);
1097 #if defined(TARGET_SDL2)
1098 if (dst_bitmap == window)
1100 // SDL_UpdateWindowSurface(sdl_window);
1101 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1102 UpdateScreen(&dst_rect);
1105 if (dst_bitmap == window)
1107 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
1108 UpdateScreen(&dst_rect);
1113 void SDLBlitTexture(Bitmap *bitmap,
1114 int src_x, int src_y, int width, int height,
1115 int dst_x, int dst_y, int mask_mode)
1117 #if defined(TARGET_SDL2)
1118 SDL_Texture *texture;
1123 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
1125 if (texture == NULL)
1131 src_rect.h = height;
1136 dst_rect.h = height;
1138 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
1142 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
1145 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1148 if (dst_bitmap == backbuffer || dst_bitmap == window)
1159 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1161 #if defined(TARGET_SDL2)
1162 if (dst_bitmap == window)
1164 // SDL_UpdateWindowSurface(sdl_window);
1165 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
1166 UpdateScreen(&rect);
1169 if (dst_bitmap == window)
1171 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
1172 UpdateScreen(&rect);
1177 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
1178 int fade_mode, int fade_delay, int post_delay,
1179 void (*draw_border_function)(void))
1181 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
1182 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
1183 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
1184 SDL_Surface *surface_screen = backbuffer->surface;
1185 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
1186 SDL_Rect src_rect, dst_rect;
1188 int src_x = x, src_y = y;
1189 int dst_x = x, dst_y = y;
1190 unsigned int time_last, time_current;
1192 // store function for drawing global masked border
1193 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
1195 // deactivate drawing of global border while fading, if needed
1196 if (draw_border_function == NULL)
1197 gfx.draw_global_border_function = NULL;
1202 src_rect.h = height;
1204 dst_x += video_xoffset;
1205 dst_y += video_yoffset;
1209 dst_rect.w = width; /* (ignored) */
1210 dst_rect.h = height; /* (ignored) */
1212 dst_rect2 = dst_rect;
1214 /* copy source and target surfaces to temporary surfaces for fading */
1215 if (fade_mode & FADE_TYPE_TRANSFORM)
1217 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1218 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1220 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
1221 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
1223 else if (fade_mode & FADE_TYPE_FADE_IN)
1225 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1226 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1228 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
1230 else /* FADE_TYPE_FADE_OUT */
1232 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1233 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1235 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
1238 time_current = SDL_GetTicks();
1240 if (fade_mode == FADE_MODE_MELT)
1242 boolean done = FALSE;
1243 int melt_pixels = 2;
1244 int melt_columns = width / melt_pixels;
1245 int ypos[melt_columns];
1246 int max_steps = height / 8 + 32;
1251 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1252 #if defined(TARGET_SDL2)
1253 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1255 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1258 ypos[0] = -GetSimpleRandom(16);
1260 for (i = 1 ; i < melt_columns; i++)
1262 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1264 ypos[i] = ypos[i - 1] + r;
1277 time_last = time_current;
1278 time_current = SDL_GetTicks();
1279 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1280 steps_final = MIN(MAX(0, steps), max_steps);
1284 done = (steps_done >= steps_final);
1286 for (i = 0 ; i < melt_columns; i++)
1294 else if (ypos[i] < height)
1299 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1301 if (ypos[i] + dy >= height)
1302 dy = height - ypos[i];
1304 /* copy part of (appearing) target surface to upper area */
1305 src_rect.x = src_x + i * melt_pixels;
1306 // src_rect.y = src_y + ypos[i];
1308 src_rect.w = melt_pixels;
1310 src_rect.h = ypos[i] + dy;
1312 dst_rect.x = dst_x + i * melt_pixels;
1313 // dst_rect.y = dst_y + ypos[i];
1316 if (steps_done >= steps_final)
1317 SDL_BlitSurface(surface_target, &src_rect,
1318 surface_screen, &dst_rect);
1322 /* copy part of (disappearing) source surface to lower area */
1323 src_rect.x = src_x + i * melt_pixels;
1325 src_rect.w = melt_pixels;
1326 src_rect.h = height - ypos[i];
1328 dst_rect.x = dst_x + i * melt_pixels;
1329 dst_rect.y = dst_y + ypos[i];
1331 if (steps_done >= steps_final)
1332 SDL_BlitSurface(surface_source, &src_rect,
1333 surface_screen, &dst_rect);
1339 src_rect.x = src_x + i * melt_pixels;
1341 src_rect.w = melt_pixels;
1342 src_rect.h = height;
1344 dst_rect.x = dst_x + i * melt_pixels;
1347 if (steps_done >= steps_final)
1348 SDL_BlitSurface(surface_target, &src_rect,
1349 surface_screen, &dst_rect);
1353 if (steps_done >= steps_final)
1355 if (draw_border_function != NULL)
1356 draw_border_function();
1358 UpdateScreen(&dst_rect2);
1362 else if (fade_mode == FADE_MODE_CURTAIN)
1366 int xx_size = width / 2;
1368 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1369 #if defined(TARGET_SDL2)
1370 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1372 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1375 for (xx = 0; xx < xx_size;)
1377 time_last = time_current;
1378 time_current = SDL_GetTicks();
1379 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1380 xx_final = MIN(MAX(0, xx), xx_size);
1385 src_rect.h = height;
1390 /* draw new (target) image to screen buffer */
1391 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1393 if (xx_final < xx_size)
1395 src_rect.w = xx_size - xx_final;
1396 src_rect.h = height;
1398 /* draw old (source) image to screen buffer (left side) */
1400 src_rect.x = src_x + xx_final;
1403 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1405 /* draw old (source) image to screen buffer (right side) */
1407 src_rect.x = src_x + xx_size;
1408 dst_rect.x = dst_x + xx_size + xx_final;
1410 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1413 if (draw_border_function != NULL)
1414 draw_border_function();
1416 /* only update the region of the screen that is affected from fading */
1417 UpdateScreen(&dst_rect2);
1420 else /* fading in, fading out or cross-fading */
1425 for (alpha = 0.0; alpha < 255.0;)
1427 time_last = time_current;
1428 time_current = SDL_GetTicks();
1429 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1430 alpha_final = MIN(MAX(0, alpha), 255);
1432 /* draw existing (source) image to screen buffer */
1433 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1435 /* draw new (target) image to screen buffer using alpha blending */
1436 #if defined(TARGET_SDL2)
1437 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1438 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1440 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1442 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1444 if (draw_border_function != NULL)
1445 draw_border_function();
1447 /* only update the region of the screen that is affected from fading */
1448 UpdateScreen(&dst_rect);
1454 unsigned int time_post_delay;
1456 time_current = SDL_GetTicks();
1457 time_post_delay = time_current + post_delay;
1459 while (time_current < time_post_delay)
1461 // do not wait longer than 10 ms at a time to be able to ...
1462 Delay(MIN(10, time_post_delay - time_current));
1464 // ... continue drawing global animations during post delay
1467 time_current = SDL_GetTicks();
1471 // restore function for drawing global masked border
1472 gfx.draw_global_border_function = draw_global_border_function;
1475 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1476 int to_x, int to_y, Uint32 color)
1478 SDL_Surface *surface = dst_bitmap->surface;
1482 swap_numbers(&from_x, &to_x);
1485 swap_numbers(&from_y, &to_y);
1489 rect.w = (to_x - from_x + 1);
1490 rect.h = (to_y - from_y + 1);
1492 if (dst_bitmap == backbuffer || dst_bitmap == window)
1494 rect.x += video_xoffset;
1495 rect.y += video_yoffset;
1498 SDL_FillRect(surface, &rect, color);
1501 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1502 int to_x, int to_y, Uint32 color)
1504 if (dst_bitmap == backbuffer || dst_bitmap == window)
1506 from_x += video_xoffset;
1507 from_y += video_yoffset;
1508 to_x += video_xoffset;
1509 to_y += video_yoffset;
1512 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1515 #if ENABLE_UNUSED_CODE
1516 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1517 int num_points, Uint32 color)
1522 for (i = 0; i < num_points - 1; i++)
1524 for (x = 0; x < line_width; x++)
1526 for (y = 0; y < line_width; y++)
1528 int dx = x - line_width / 2;
1529 int dy = y - line_width / 2;
1531 if ((x == 0 && y == 0) ||
1532 (x == 0 && y == line_width - 1) ||
1533 (x == line_width - 1 && y == 0) ||
1534 (x == line_width - 1 && y == line_width - 1))
1537 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1538 points[i+1].x + dx, points[i+1].y + dy, color);
1545 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1547 SDL_Surface *surface = src_bitmap->surface;
1549 if (src_bitmap == backbuffer || src_bitmap == window)
1555 switch (surface->format->BytesPerPixel)
1557 case 1: /* assuming 8-bpp */
1559 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1563 case 2: /* probably 15-bpp or 16-bpp */
1565 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1569 case 3: /* slow 24-bpp mode; usually not used */
1571 /* does this work? */
1572 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1576 shift = surface->format->Rshift;
1577 color |= *(pix + shift / 8) >> shift;
1578 shift = surface->format->Gshift;
1579 color |= *(pix + shift / 8) >> shift;
1580 shift = surface->format->Bshift;
1581 color |= *(pix + shift / 8) >> shift;
1587 case 4: /* probably 32-bpp */
1589 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1598 /* ========================================================================= */
1599 /* The following functions were taken from the SGE library */
1600 /* (SDL Graphics Extension Library) by Anders Lindström */
1601 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1602 /* ========================================================================= */
1604 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1606 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1608 switch (surface->format->BytesPerPixel)
1612 /* Assuming 8-bpp */
1613 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1619 /* Probably 15-bpp or 16-bpp */
1620 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1626 /* Slow 24-bpp mode, usually not used */
1630 /* Gack - slow, but endian correct */
1631 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1632 shift = surface->format->Rshift;
1633 *(pix+shift/8) = color>>shift;
1634 shift = surface->format->Gshift;
1635 *(pix+shift/8) = color>>shift;
1636 shift = surface->format->Bshift;
1637 *(pix+shift/8) = color>>shift;
1643 /* Probably 32-bpp */
1644 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1651 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1652 Uint8 R, Uint8 G, Uint8 B)
1654 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1657 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1659 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1662 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1664 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1667 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1672 /* Gack - slow, but endian correct */
1673 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1674 shift = surface->format->Rshift;
1675 *(pix+shift/8) = color>>shift;
1676 shift = surface->format->Gshift;
1677 *(pix+shift/8) = color>>shift;
1678 shift = surface->format->Bshift;
1679 *(pix+shift/8) = color>>shift;
1682 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1684 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1687 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1689 switch (dest->format->BytesPerPixel)
1692 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1696 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1700 _PutPixel24(dest,x,y,color);
1704 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1709 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1711 if (SDL_MUSTLOCK(surface))
1713 if (SDL_LockSurface(surface) < 0)
1719 _PutPixel(surface, x, y, color);
1721 if (SDL_MUSTLOCK(surface))
1723 SDL_UnlockSurface(surface);
1727 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1728 Uint8 r, Uint8 g, Uint8 b)
1730 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1733 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1735 if (y >= 0 && y <= dest->h - 1)
1737 switch (dest->format->BytesPerPixel)
1740 return y*dest->pitch;
1744 return y*dest->pitch/2;
1748 return y*dest->pitch;
1752 return y*dest->pitch/4;
1760 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1762 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1764 switch (surface->format->BytesPerPixel)
1768 /* Assuming 8-bpp */
1769 *((Uint8 *)surface->pixels + ypitch + x) = color;
1775 /* Probably 15-bpp or 16-bpp */
1776 *((Uint16 *)surface->pixels + ypitch + x) = color;
1782 /* Slow 24-bpp mode, usually not used */
1786 /* Gack - slow, but endian correct */
1787 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1788 shift = surface->format->Rshift;
1789 *(pix+shift/8) = color>>shift;
1790 shift = surface->format->Gshift;
1791 *(pix+shift/8) = color>>shift;
1792 shift = surface->format->Bshift;
1793 *(pix+shift/8) = color>>shift;
1799 /* Probably 32-bpp */
1800 *((Uint32 *)surface->pixels + ypitch + x) = color;
1807 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1812 if (SDL_MUSTLOCK(Surface))
1814 if (SDL_LockSurface(Surface) < 0)
1827 /* Do the clipping */
1828 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1832 if (x2 > Surface->w - 1)
1833 x2 = Surface->w - 1;
1840 SDL_FillRect(Surface, &l, Color);
1842 if (SDL_MUSTLOCK(Surface))
1844 SDL_UnlockSurface(Surface);
1848 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1849 Uint8 R, Uint8 G, Uint8 B)
1851 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1854 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1865 /* Do the clipping */
1866 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1870 if (x2 > Surface->w - 1)
1871 x2 = Surface->w - 1;
1878 SDL_FillRect(Surface, &l, Color);
1881 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1886 if (SDL_MUSTLOCK(Surface))
1888 if (SDL_LockSurface(Surface) < 0)
1901 /* Do the clipping */
1902 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1906 if (y2 > Surface->h - 1)
1907 y2 = Surface->h - 1;
1914 SDL_FillRect(Surface, &l, Color);
1916 if (SDL_MUSTLOCK(Surface))
1918 SDL_UnlockSurface(Surface);
1922 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1923 Uint8 R, Uint8 G, Uint8 B)
1925 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1928 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1939 /* Do the clipping */
1940 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1944 if (y2 > Surface->h - 1)
1945 y2 = Surface->h - 1;
1952 SDL_FillRect(Surface, &l, Color);
1955 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1956 Sint16 x2, Sint16 y2, Uint32 Color,
1957 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1960 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1965 sdx = (dx < 0) ? -1 : 1;
1966 sdy = (dy < 0) ? -1 : 1;
1978 for (x = 0; x < dx; x++)
1980 Callback(Surface, px, py, Color);
1994 for (y = 0; y < dy; y++)
1996 Callback(Surface, px, py, Color);
2010 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
2011 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
2012 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
2015 sge_DoLine(Surface, X1, Y1, X2, Y2,
2016 SDL_MapRGB(Surface->format, R, G, B), Callback);
2019 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
2022 if (SDL_MUSTLOCK(Surface))
2024 if (SDL_LockSurface(Surface) < 0)
2029 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
2031 /* unlock the display */
2032 if (SDL_MUSTLOCK(Surface))
2034 SDL_UnlockSurface(Surface);
2038 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
2039 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
2041 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
2044 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
2046 if (dst_bitmap == backbuffer || dst_bitmap == window)
2052 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
2057 -----------------------------------------------------------------------------
2058 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
2059 -----------------------------------------------------------------------------
2062 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
2063 int width, int height, Uint32 color)
2067 for (y = src_y; y < src_y + height; y++)
2069 for (x = src_x; x < src_x + width; x++)
2071 Uint32 pixel = SDLGetPixel(bitmap, x, y);
2073 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
2078 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
2079 int src_x, int src_y, int width, int height,
2080 int dst_x, int dst_y)
2084 for (y = 0; y < height; y++)
2086 for (x = 0; x < width; x++)
2088 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
2090 if (pixel != BLACK_PIXEL)
2091 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
2097 /* ========================================================================= */
2098 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
2099 /* (Rotozoomer) by Andreas Schiffler */
2100 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
2101 /* ========================================================================= */
2104 -----------------------------------------------------------------------------
2107 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
2108 -----------------------------------------------------------------------------
2119 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
2122 tColorRGBA *sp, *csp, *dp;
2126 sp = csp = (tColorRGBA *) src->pixels;
2127 dp = (tColorRGBA *) dst->pixels;
2128 dgap = dst->pitch - dst->w * 4;
2130 for (y = 0; y < dst->h; y++)
2134 for (x = 0; x < dst->w; x++)
2136 tColorRGBA *sp0 = sp;
2137 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2138 tColorRGBA *sp00 = &sp0[0];
2139 tColorRGBA *sp01 = &sp0[1];
2140 tColorRGBA *sp10 = &sp1[0];
2141 tColorRGBA *sp11 = &sp1[1];
2144 /* create new color pixel from all four source color pixels */
2145 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2146 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2147 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2148 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2153 /* advance source pointers */
2156 /* advance destination pointer */
2160 /* advance source pointer */
2161 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2163 /* advance destination pointers */
2164 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2170 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2172 int x, y, *sax, *say, *csax, *csay;
2174 tColorRGBA *sp, *csp, *csp0, *dp;
2177 /* use specialized zoom function when scaling down to exactly half size */
2178 if (src->w == 2 * dst->w &&
2179 src->h == 2 * dst->h)
2180 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2182 /* variable setup */
2183 sx = (float) src->w / (float) dst->w;
2184 sy = (float) src->h / (float) dst->h;
2186 /* allocate memory for row increments */
2187 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2188 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2190 /* precalculate row increments */
2191 for (x = 0; x <= dst->w; x++)
2192 *csax++ = (int)(sx * x);
2194 for (y = 0; y <= dst->h; y++)
2195 *csay++ = (int)(sy * y);
2198 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2199 dp = (tColorRGBA *) dst->pixels;
2200 dgap = dst->pitch - dst->w * 4;
2203 for (y = 0; y < dst->h; y++)
2208 for (x = 0; x < dst->w; x++)
2213 /* advance source pointers */
2217 /* advance destination pointer */
2221 /* advance source pointer */
2223 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2225 /* advance destination pointers */
2226 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2236 -----------------------------------------------------------------------------
2239 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2240 -----------------------------------------------------------------------------
2243 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2245 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2246 Uint8 *sp, *dp, *csp;
2249 /* variable setup */
2250 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2251 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2253 /* allocate memory for row increments */
2254 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2255 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2257 /* precalculate row increments */
2260 for (x = 0; x < dst->w; x++)
2263 *csax = (csx >> 16);
2270 for (y = 0; y < dst->h; y++)
2273 *csay = (csy >> 16);
2280 for (x = 0; x < dst->w; x++)
2288 for (y = 0; y < dst->h; y++)
2295 sp = csp = (Uint8 *) src->pixels;
2296 dp = (Uint8 *) dst->pixels;
2297 dgap = dst->pitch - dst->w;
2301 for (y = 0; y < dst->h; y++)
2305 for (x = 0; x < dst->w; x++)
2310 /* advance source pointers */
2314 /* advance destination pointer */
2318 /* advance source pointer (for row) */
2319 csp += ((*csay) * src->pitch);
2322 /* advance destination pointers */
2333 -----------------------------------------------------------------------------
2336 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2337 'zoomx' and 'zoomy' are scaling factors for width and height.
2338 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2339 into a 32bit RGBA format on the fly.
2340 -----------------------------------------------------------------------------
2343 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2345 SDL_Surface *zoom_src = NULL;
2346 SDL_Surface *zoom_dst = NULL;
2347 boolean is_converted = FALSE;
2354 /* determine if source surface is 32 bit or 8 bit */
2355 is_32bit = (src->format->BitsPerPixel == 32);
2357 if (is_32bit || src->format->BitsPerPixel == 8)
2359 /* use source surface 'as is' */
2364 /* new source surface is 32 bit with a defined RGB ordering */
2365 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2366 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2367 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2369 is_converted = TRUE;
2372 /* allocate surface to completely contain the zoomed surface */
2375 /* target surface is 32 bit with source RGBA/ABGR ordering */
2376 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2377 zoom_src->format->Rmask,
2378 zoom_src->format->Gmask,
2379 zoom_src->format->Bmask, 0);
2383 /* target surface is 8 bit */
2384 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2388 /* lock source surface */
2389 SDL_LockSurface(zoom_src);
2391 /* check which kind of surface we have */
2394 /* call the 32 bit transformation routine to do the zooming */
2395 zoomSurfaceRGBA(zoom_src, zoom_dst);
2400 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2401 zoom_dst->format->palette->colors[i] =
2402 zoom_src->format->palette->colors[i];
2403 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2405 /* call the 8 bit transformation routine to do the zooming */
2406 zoomSurfaceY(zoom_src, zoom_dst);
2409 /* unlock source surface */
2410 SDL_UnlockSurface(zoom_src);
2412 /* free temporary surface */
2414 SDL_FreeSurface(zoom_src);
2416 /* return destination surface */
2420 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2422 Bitmap *dst_bitmap = CreateBitmapStruct();
2423 SDL_Surface **dst_surface = &dst_bitmap->surface;
2425 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2426 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2428 dst_bitmap->width = dst_width;
2429 dst_bitmap->height = dst_height;
2431 /* create zoomed temporary surface from source surface */
2432 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2434 /* create native format destination surface from zoomed temporary surface */
2435 SDLSetNativeSurface(dst_surface);
2441 /* ========================================================================= */
2442 /* load image to bitmap */
2443 /* ========================================================================= */
2445 Bitmap *SDLLoadImage(char *filename)
2447 Bitmap *new_bitmap = CreateBitmapStruct();
2448 SDL_Surface *sdl_image_tmp;
2450 print_timestamp_init("SDLLoadImage");
2452 print_timestamp_time(getBaseNamePtr(filename));
2454 /* load image to temporary surface */
2455 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2457 SetError("IMG_Load(): %s", SDL_GetError());
2462 print_timestamp_time("IMG_Load");
2464 UPDATE_BUSY_STATE();
2466 /* create native non-transparent surface for current image */
2467 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2469 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2474 print_timestamp_time("SDL_DisplayFormat (opaque)");
2476 UPDATE_BUSY_STATE();
2478 /* create native transparent surface for current image */
2479 if (sdl_image_tmp->format->Amask == 0)
2480 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2481 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2483 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2485 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2490 print_timestamp_time("SDL_DisplayFormat (masked)");
2492 UPDATE_BUSY_STATE();
2494 /* free temporary surface */
2495 SDL_FreeSurface(sdl_image_tmp);
2497 new_bitmap->width = new_bitmap->surface->w;
2498 new_bitmap->height = new_bitmap->surface->h;
2500 print_timestamp_done("SDLLoadImage");
2506 /* ------------------------------------------------------------------------- */
2507 /* custom cursor fuctions */
2508 /* ------------------------------------------------------------------------- */
2510 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2512 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2513 cursor_info->width, cursor_info->height,
2514 cursor_info->hot_x, cursor_info->hot_y);
2517 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2519 static struct MouseCursorInfo *last_cursor_info = NULL;
2520 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2521 static SDL_Cursor *cursor_default = NULL;
2522 static SDL_Cursor *cursor_current = NULL;
2524 /* if invoked for the first time, store the SDL default cursor */
2525 if (cursor_default == NULL)
2526 cursor_default = SDL_GetCursor();
2528 /* only create new cursor if cursor info (custom only) has changed */
2529 if (cursor_info != NULL && cursor_info != last_cursor_info)
2531 cursor_current = create_cursor(cursor_info);
2532 last_cursor_info = cursor_info;
2535 /* only set new cursor if cursor info (custom or NULL) has changed */
2536 if (cursor_info != last_cursor_info2)
2537 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2539 last_cursor_info2 = cursor_info;
2543 /* ========================================================================= */
2544 /* audio functions */
2545 /* ========================================================================= */
2547 void SDLOpenAudio(void)
2549 #if !defined(TARGET_SDL2)
2550 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2551 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2554 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2556 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2560 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2561 AUDIO_NUM_CHANNELS_STEREO,
2562 setup.system.audio_fragment_size) < 0)
2564 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2568 audio.sound_available = TRUE;
2569 audio.music_available = TRUE;
2570 audio.loops_available = TRUE;
2571 audio.sound_enabled = TRUE;
2573 /* set number of available mixer channels */
2574 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2575 audio.music_channel = MUSIC_CHANNEL;
2576 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2578 Mixer_InitChannels();
2581 void SDLCloseAudio(void)
2584 Mix_HaltChannel(-1);
2587 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2591 /* ========================================================================= */
2592 /* event functions */
2593 /* ========================================================================= */
2595 void SDLNextEvent(Event *event)
2597 SDL_WaitEvent(event);
2599 if (event->type == EVENT_BUTTONPRESS ||
2600 event->type == EVENT_BUTTONRELEASE)
2602 if (((ButtonEvent *)event)->x > video_xoffset)
2603 ((ButtonEvent *)event)->x -= video_xoffset;
2605 ((ButtonEvent *)event)->x = 0;
2606 if (((ButtonEvent *)event)->y > video_yoffset)
2607 ((ButtonEvent *)event)->y -= video_yoffset;
2609 ((ButtonEvent *)event)->y = 0;
2611 else if (event->type == EVENT_MOTIONNOTIFY)
2613 if (((MotionEvent *)event)->x > video_xoffset)
2614 ((MotionEvent *)event)->x -= video_xoffset;
2616 ((MotionEvent *)event)->x = 0;
2617 if (((MotionEvent *)event)->y > video_yoffset)
2618 ((MotionEvent *)event)->y -= video_yoffset;
2620 ((MotionEvent *)event)->y = 0;
2624 void SDLHandleWindowManagerEvent(Event *event)
2627 #if defined(PLATFORM_WIN32)
2628 // experimental drag and drop code
2630 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2631 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2633 #if defined(TARGET_SDL2)
2634 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2636 if (syswmmsg->msg == WM_DROPFILES)
2639 #if defined(TARGET_SDL2)
2640 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2642 HDROP hdrop = (HDROP)syswmmsg->wParam;
2646 printf("::: SDL_SYSWMEVENT:\n");
2648 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2650 for (i = 0; i < num_files; i++)
2652 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2653 char buffer[buffer_len + 1];
2655 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2657 printf("::: - '%s'\n", buffer);
2660 #if defined(TARGET_SDL2)
2661 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2663 DragFinish((HDROP)syswmmsg->wParam);
2671 /* ========================================================================= */
2672 /* joystick functions */
2673 /* ========================================================================= */
2675 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2676 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2677 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2679 static boolean SDLOpenJoystick(int nr)
2681 if (nr < 0 || nr > MAX_PLAYERS)
2684 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2687 static void SDLCloseJoystick(int nr)
2689 if (nr < 0 || nr > MAX_PLAYERS)
2692 SDL_JoystickClose(sdl_joystick[nr]);
2694 sdl_joystick[nr] = NULL;
2697 static boolean SDLCheckJoystickOpened(int nr)
2699 if (nr < 0 || nr > MAX_PLAYERS)
2702 #if defined(TARGET_SDL2)
2703 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2705 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2709 void HandleJoystickEvent(Event *event)
2713 case SDL_JOYAXISMOTION:
2714 if (event->jaxis.axis < 2)
2715 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2718 case SDL_JOYBUTTONDOWN:
2719 if (event->jbutton.button < 2)
2720 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2723 case SDL_JOYBUTTONUP:
2724 if (event->jbutton.button < 2)
2725 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2733 void SDLInitJoysticks()
2735 static boolean sdl_joystick_subsystem_initialized = FALSE;
2736 boolean print_warning = !sdl_joystick_subsystem_initialized;
2739 if (!sdl_joystick_subsystem_initialized)
2741 sdl_joystick_subsystem_initialized = TRUE;
2743 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2745 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2750 for (i = 0; i < MAX_PLAYERS; i++)
2752 /* get configured joystick for this player */
2753 char *device_name = setup.input[i].joy.device_name;
2754 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2756 if (joystick_nr >= SDL_NumJoysticks())
2758 if (setup.input[i].use_joystick && print_warning)
2759 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2764 /* misuse joystick file descriptor variable to store joystick number */
2765 joystick.fd[i] = joystick_nr;
2767 if (joystick_nr == -1)
2770 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2771 if (SDLCheckJoystickOpened(joystick_nr))
2772 SDLCloseJoystick(joystick_nr);
2774 if (!setup.input[i].use_joystick)
2777 if (!SDLOpenJoystick(joystick_nr))
2780 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2785 joystick.status = JOYSTICK_ACTIVATED;
2789 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2791 if (nr < 0 || nr >= MAX_PLAYERS)
2795 *x = sdl_js_axis[nr][0];
2797 *y = sdl_js_axis[nr][1];
2800 *b1 = sdl_js_button[nr][0];
2802 *b2 = sdl_js_button[nr][1];