1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
18 #define ENABLE_UNUSED_CODE 0 /* currently unused functions */
21 /* ========================================================================= */
23 /* ========================================================================= */
25 /* SDL internal variables */
26 #if defined(TARGET_SDL2)
27 static SDL_Window *sdl_window = NULL;
28 static SDL_Renderer *sdl_renderer = NULL;
29 static SDL_Texture *sdl_texture = NULL;
30 static boolean fullscreen_enabled = FALSE;
32 #define USE_RENDERER TRUE
35 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
36 static int fullscreen_width;
37 static int fullscreen_height;
38 static int fullscreen_xoffset;
39 static int fullscreen_yoffset;
40 static int video_xoffset;
41 static int video_yoffset;
42 static boolean limit_screen_updates = FALSE;
45 /* functions from SGE library */
46 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
48 void SDLLimitScreenUpdates(boolean enable)
50 limit_screen_updates = enable;
53 static void UpdateScreen(SDL_Rect *rect)
55 static unsigned int update_screen_delay = 0;
56 unsigned int update_screen_delay_value = 50; /* (milliseconds) */
57 SDL_Surface *screen = backbuffer->surface;
59 if (limit_screen_updates &&
60 !DelayReached(&update_screen_delay, update_screen_delay_value))
63 LimitScreenUpdates(FALSE);
67 static int LastFrameCounter = 0;
68 boolean changed = (FrameCounter != LastFrameCounter);
70 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
71 (changed ? "-" : "SAME FRAME UPDATED"));
73 LastFrameCounter = FrameCounter;
82 #if USE_FINAL_SCREEN_BITMAP
83 if (gfx.final_screen_bitmap != NULL) // may not be initialized yet
86 // draw global animations using bitmaps instead of using textures
87 // to prevent texture scaling artefacts (this is potentially slower)
89 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
90 gfx.win_xsize, gfx.win_ysize, 0, 0);
92 // copy global animations to render target buffer, if defined (below border)
93 if (gfx.draw_global_anim_function != NULL)
94 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
96 // copy global masked border to render target buffer, if defined
97 if (gfx.draw_global_border_function != NULL)
98 gfx.draw_global_border_function(REDRAW_ALL);
100 // copy global animations to render target buffer, if defined (above border)
101 if (gfx.draw_global_anim_function != NULL)
102 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
104 screen = gfx.final_screen_bitmap->surface;
106 // force full window redraw
111 #if defined(TARGET_SDL2)
115 int bytes_x = screen->pitch / video.width;
116 int bytes_y = screen->pitch;
118 if (video.fullscreen_enabled)
119 bytes_x = screen->pitch / fullscreen_width;
121 SDL_UpdateTexture(sdl_texture, rect,
122 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
127 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
130 // clear render target buffer
131 SDL_RenderClear(sdl_renderer);
133 // copy backbuffer to render target buffer
134 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
136 #if !USE_FINAL_SCREEN_BITMAP
137 // copy global animations to render target buffer, if defined (below border)
138 if (gfx.draw_global_anim_function != NULL)
139 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
141 // copy global masked border to render target buffer, if defined
142 if (gfx.draw_global_border_function != NULL)
143 gfx.draw_global_border_function(REDRAW_ALL);
145 // copy global animations to render target buffer, if defined (above border)
146 if (gfx.draw_global_anim_function != NULL)
147 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
150 // show render target buffer on screen
151 SDL_RenderPresent(sdl_renderer);
156 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
158 SDL_UpdateWindowSurface(sdl_window);
163 SDL_UpdateRects(screen, 1, rect);
165 SDL_UpdateRect(screen, 0, 0, 0, 0);
169 static void setFullscreenParameters(char *fullscreen_mode_string)
171 #if defined(TARGET_SDL2)
172 fullscreen_width = video.width;
173 fullscreen_height = video.height;
174 fullscreen_xoffset = 0;
175 fullscreen_yoffset = 0;
179 struct ScreenModeInfo *fullscreen_mode;
182 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
184 if (fullscreen_mode == NULL)
187 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
189 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
190 fullscreen_mode->height == video.fullscreen_modes[i].height)
192 fullscreen_width = fullscreen_mode->width;
193 fullscreen_height = fullscreen_mode->height;
195 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
196 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
204 static void SDLSetWindowIcon(char *basename)
206 /* (setting the window icon on Mac OS X would replace the high-quality
207 dock icon with the currently smaller (and uglier) icon from file) */
209 #if !defined(PLATFORM_MACOSX)
210 char *filename = getCustomImageFilename(basename);
211 SDL_Surface *surface;
213 if (filename == NULL)
215 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
220 if ((surface = IMG_Load(filename)) == NULL)
222 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
227 /* set transparent color */
228 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
229 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
231 #if defined(TARGET_SDL2)
232 SDL_SetWindowIcon(sdl_window, surface);
234 SDL_WM_SetIcon(surface, NULL);
239 #if defined(TARGET_SDL2)
241 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
242 SDL_PixelFormat *format2)
244 return (format1->format == format2->format &&
245 format1->BitsPerPixel == format2->BitsPerPixel &&
246 format1->BytesPerPixel == format2->BytesPerPixel &&
247 format1->Rmask == format2->Rmask &&
248 format1->Gmask == format2->Gmask &&
249 format1->Bmask == format2->Bmask &&
250 format1->Amask == format2->Amask);
253 boolean SDLSetNativeSurface(SDL_Surface **surface)
255 SDL_Surface *new_surface;
257 if (surface == NULL ||
259 backbuffer == NULL ||
260 backbuffer->surface == NULL)
263 // if pixel format already optimized for destination surface, do nothing
264 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
267 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
269 if (new_surface == NULL)
270 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
272 SDL_FreeSurface(*surface);
274 *surface = new_surface;
279 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
281 SDL_PixelFormat format;
282 SDL_Surface *new_surface;
287 if (backbuffer && backbuffer->surface)
289 format = *backbuffer->surface->format;
290 format.Amask = surface->format->Amask; // keep alpha channel
294 format = *surface->format;
297 new_surface = SDL_ConvertSurface(surface, &format, 0);
299 if (new_surface == NULL)
300 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
307 boolean SDLSetNativeSurface(SDL_Surface **surface)
309 SDL_Surface *new_surface;
311 if (surface == NULL ||
316 new_surface = SDL_DisplayFormat(*surface);
318 if (new_surface == NULL)
319 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
321 SDL_FreeSurface(*surface);
323 *surface = new_surface;
328 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
330 SDL_Surface *new_surface;
332 if (video.initialized)
333 new_surface = SDL_DisplayFormat(surface);
335 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
337 if (new_surface == NULL)
338 Error(ERR_EXIT, "%s() failed: %s",
339 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
347 #if defined(TARGET_SDL2)
348 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
350 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
353 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
360 void SDLCreateBitmapTextures(Bitmap *bitmap)
362 #if defined(TARGET_SDL2)
367 SDL_DestroyTexture(bitmap->texture);
368 if (bitmap->texture_masked)
369 SDL_DestroyTexture(bitmap->texture_masked);
371 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
372 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
376 void SDLFreeBitmapTextures(Bitmap *bitmap)
378 #if defined(TARGET_SDL2)
383 SDL_DestroyTexture(bitmap->texture);
384 if (bitmap->texture_masked)
385 SDL_DestroyTexture(bitmap->texture_masked);
387 bitmap->texture = NULL;
388 bitmap->texture_masked = NULL;
392 void SDLInitVideoDisplay(void)
394 #if !defined(TARGET_SDL2)
395 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
396 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
398 SDL_putenv("SDL_VIDEO_CENTERED=1");
401 /* initialize SDL video */
402 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
403 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
405 /* set default SDL depth */
406 #if !defined(TARGET_SDL2)
407 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
409 video.default_depth = 32; // (how to determine video depth in SDL2?)
413 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
416 #if !defined(TARGET_SDL2)
417 static int screen_xy[][2] =
425 SDL_Rect **modes = NULL;
426 boolean hardware_fullscreen_available = TRUE;
429 /* default: normal game window size */
430 fullscreen_width = video.width;
431 fullscreen_height = video.height;
432 fullscreen_xoffset = 0;
433 fullscreen_yoffset = 0;
435 #if !defined(TARGET_SDL2)
436 /* determine required standard fullscreen mode for game screen size */
437 for (i = 0; screen_xy[i][0] != -1; i++)
439 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
441 fullscreen_width = screen_xy[i][0];
442 fullscreen_height = screen_xy[i][1];
448 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
449 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
452 checked_free(video.fullscreen_modes);
454 video.fullscreen_modes = NULL;
455 video.fullscreen_mode_current = NULL;
457 video.window_scaling_percent = setup.window_scaling_percent;
458 video.window_scaling_quality = setup.window_scaling_quality;
460 #if defined(TARGET_SDL2)
461 int num_displays = SDL_GetNumVideoDisplays();
463 if (num_displays > 0)
465 // currently only display modes of first display supported
466 int num_modes = SDL_GetNumDisplayModes(0);
470 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
472 for (i = 0; i < num_modes; i++)
474 SDL_DisplayMode mode;
476 if (SDL_GetDisplayMode(0, i, &mode) < 0)
479 modes[i] = checked_calloc(sizeof(SDL_Rect));
481 modes[i]->w = mode.w;
482 modes[i]->h = mode.h;
487 /* get available hardware supported fullscreen modes */
488 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
493 /* no hardware screen modes available => no fullscreen mode support */
494 // video.fullscreen_available = FALSE;
495 hardware_fullscreen_available = FALSE;
497 else if (modes == (SDL_Rect **)-1)
499 /* fullscreen resolution is not restricted -- all resolutions available */
500 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
502 /* use native video buffer size for fullscreen mode */
503 video.fullscreen_modes[0].width = video.width;
504 video.fullscreen_modes[0].height = video.height;
506 video.fullscreen_modes[1].width = -1;
507 video.fullscreen_modes[1].height = -1;
511 /* in this case, a certain number of screen modes is available */
514 for (i = 0; modes[i] != NULL; i++)
516 boolean found_mode = FALSE;
518 /* screen mode is smaller than video buffer size -- skip it */
519 if (modes[i]->w < video.width || modes[i]->h < video.height)
522 if (video.fullscreen_modes != NULL)
523 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
524 if (modes[i]->w == video.fullscreen_modes[j].width &&
525 modes[i]->h == video.fullscreen_modes[j].height)
528 if (found_mode) /* screen mode already stored -- skip it */
531 /* new mode found; add it to list of available fullscreen modes */
535 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
537 sizeof(struct ScreenModeInfo));
539 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
540 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
542 video.fullscreen_modes[num_modes].width = -1;
543 video.fullscreen_modes[num_modes].height = -1;
548 /* no appropriate screen modes available => no fullscreen mode support */
549 // video.fullscreen_available = FALSE;
550 hardware_fullscreen_available = FALSE;
554 video.fullscreen_available = hardware_fullscreen_available;
556 #if USE_DESKTOP_FULLSCREEN
557 // in SDL 2.0, there is always support for desktop fullscreen mode
558 // (in SDL 1.2, there is only support for "real" fullscreen mode)
559 video.fullscreen_available = TRUE;
562 #if defined(TARGET_SDL2)
565 for (i = 0; modes[i] != NULL; i++)
566 checked_free(modes[i]);
572 /* open SDL video output device (window or fullscreen mode) */
573 if (!SDLSetVideoMode(backbuffer, fullscreen))
574 Error(ERR_EXIT, "setting video mode failed");
576 /* !!! SDL2 can only set the window icon if the window already exists !!! */
577 /* set window icon */
578 SDLSetWindowIcon(program.icon_filename);
580 /* set window and icon title */
581 #if defined(TARGET_SDL2)
582 SDL_SetWindowTitle(sdl_window, program.window_title);
584 SDL_WM_SetCaption(program.window_title, program.window_title);
587 /* SDL cannot directly draw to the visible video framebuffer like X11,
588 but always uses a backbuffer, which is then blitted to the visible
589 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
590 visible video framebuffer with 'SDL_Flip', if the hardware supports
591 this). Therefore do not use an additional backbuffer for drawing, but
592 use a symbolic buffer (distinguishable from the SDL backbuffer) called
593 'window', which indicates that the SDL backbuffer should be updated to
594 the visible video framebuffer when attempting to blit to it.
596 For convenience, it seems to be a good idea to create this symbolic
597 buffer 'window' at the same size as the SDL backbuffer. Although it
598 should never be drawn to directly, it would do no harm nevertheless. */
600 /* create additional (symbolic) buffer for double-buffering */
601 ReCreateBitmap(window, video.width, video.height, video.depth);
604 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
607 SDL_Surface *new_surface = NULL;
609 #if defined(TARGET_SDL2)
610 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
611 #if USE_DESKTOP_FULLSCREEN
612 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
614 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
618 int surface_flags_window = SURFACE_FLAGS;
619 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
622 int width = (fullscreen ? fullscreen_width : video.width);
623 int height = (fullscreen ? fullscreen_height : video.height);
624 int surface_flags = (fullscreen ? surface_flags_fullscreen :
625 surface_flags_window);
627 // default window size is unscaled
628 video.window_width = video.width;
629 video.window_height = video.height;
631 #if defined(TARGET_SDL2)
633 // store if initial screen mode is fullscreen mode when changing screen size
634 video.fullscreen_initial = fullscreen;
637 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
638 #if !USE_DESKTOP_FULLSCREEN
639 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
642 video.window_width = window_scaling_factor * width;
643 video.window_height = window_scaling_factor * height;
645 if ((*backbuffer)->surface)
647 SDL_FreeSurface((*backbuffer)->surface);
648 (*backbuffer)->surface = NULL;
653 SDL_DestroyTexture(sdl_texture);
657 if (!(fullscreen && fullscreen_enabled))
661 SDL_DestroyRenderer(sdl_renderer);
667 SDL_DestroyWindow(sdl_window);
672 if (sdl_window == NULL)
673 sdl_window = SDL_CreateWindow(program.window_title,
674 SDL_WINDOWPOS_CENTERED,
675 SDL_WINDOWPOS_CENTERED,
676 #if USE_DESKTOP_FULLSCREEN
680 (int)(screen_scaling_factor * width),
681 (int)(screen_scaling_factor * height),
685 if (sdl_window != NULL)
688 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
689 *without* enabling 2D/3D acceleration and/or guest additions installed,
690 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
691 it will try to use accelerated graphics and apparently fails miserably) */
692 if (sdl_renderer == NULL)
693 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
695 if (sdl_renderer == NULL)
696 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
699 if (sdl_renderer != NULL)
701 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
702 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
703 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
705 sdl_texture = SDL_CreateTexture(sdl_renderer,
706 SDL_PIXELFORMAT_ARGB8888,
707 SDL_TEXTUREACCESS_STREAMING,
710 if (sdl_texture != NULL)
712 // use SDL default values for RGB masks and no alpha channel
713 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
715 if (new_surface == NULL)
716 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
721 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
726 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
731 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
737 SDL_DestroyWindow(sdl_window);
739 sdl_window = SDL_CreateWindow(program.window_title,
740 SDL_WINDOWPOS_CENTERED,
741 SDL_WINDOWPOS_CENTERED,
745 if (sdl_window != NULL)
746 new_surface = SDL_GetWindowSurface(sdl_window);
750 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
753 #if defined(TARGET_SDL2)
754 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
755 if (new_surface != NULL)
756 fullscreen_enabled = fullscreen;
762 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
764 boolean success = TRUE;
765 SDL_Surface *new_surface = NULL;
769 if (*backbuffer == NULL)
770 *backbuffer = CreateBitmapStruct();
772 /* (real bitmap might be larger in fullscreen mode with video offsets) */
773 (*backbuffer)->width = video.width;
774 (*backbuffer)->height = video.height;
776 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
778 setFullscreenParameters(setup.fullscreen_mode);
780 video_xoffset = fullscreen_xoffset;
781 video_yoffset = fullscreen_yoffset;
783 /* switch display to fullscreen mode, if available */
784 new_surface = SDLCreateScreen(backbuffer, TRUE);
786 if (new_surface == NULL)
788 /* switching display to fullscreen mode failed */
789 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
791 /* do not try it again */
792 video.fullscreen_available = FALSE;
798 (*backbuffer)->surface = new_surface;
800 video.fullscreen_enabled = TRUE;
801 video.fullscreen_mode_current = setup.fullscreen_mode;
807 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
812 /* switch display to window mode */
813 new_surface = SDLCreateScreen(backbuffer, FALSE);
815 if (new_surface == NULL)
817 /* switching display to window mode failed -- should not happen */
818 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
824 (*backbuffer)->surface = new_surface;
826 video.fullscreen_enabled = FALSE;
827 video.window_scaling_percent = setup.window_scaling_percent;
828 video.window_scaling_quality = setup.window_scaling_quality;
834 #if defined(TARGET_SDL2)
835 SDLRedrawWindow(); // map window
839 #if defined(PLATFORM_WIN32)
840 // experimental drag and drop code
842 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
845 SDL_SysWMinfo wminfo;
847 boolean wminfo_success = FALSE;
849 SDL_VERSION(&wminfo.version);
850 #if defined(TARGET_SDL2)
852 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
854 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
859 #if defined(TARGET_SDL2)
860 hwnd = wminfo.info.win.window;
862 hwnd = wminfo.window;
865 DragAcceptFiles(hwnd, TRUE);
874 void SDLSetWindowTitle()
876 #if defined(TARGET_SDL2)
877 SDL_SetWindowTitle(sdl_window, program.window_title);
879 SDL_WM_SetCaption(program.window_title, program.window_title);
883 #if defined(TARGET_SDL2)
884 void SDLSetWindowScaling(int window_scaling_percent)
886 if (sdl_window == NULL)
889 float window_scaling_factor = (float)window_scaling_percent / 100;
890 int new_window_width = (int)(window_scaling_factor * video.width);
891 int new_window_height = (int)(window_scaling_factor * video.height);
893 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
895 video.window_scaling_percent = window_scaling_percent;
896 video.window_width = new_window_width;
897 video.window_height = new_window_height;
902 void SDLSetWindowScalingQuality(char *window_scaling_quality)
904 if (sdl_texture == NULL)
907 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
909 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
910 SDL_PIXELFORMAT_ARGB8888,
911 SDL_TEXTUREACCESS_STREAMING,
912 video.width, video.height);
914 if (new_texture != NULL)
916 SDL_DestroyTexture(sdl_texture);
918 sdl_texture = new_texture;
923 video.window_scaling_quality = window_scaling_quality;
926 void SDLSetWindowFullscreen(boolean fullscreen)
928 if (sdl_window == NULL)
931 #if USE_DESKTOP_FULLSCREEN
932 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
934 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
937 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
938 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
940 // if screen size was changed in fullscreen mode, correct desktop window size
941 if (!fullscreen && video.fullscreen_initial)
943 SDLSetWindowScaling(setup.window_scaling_percent);
944 SDL_SetWindowPosition(sdl_window,
945 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
947 video.fullscreen_initial = FALSE;
951 void SDLRedrawWindow()
957 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
960 SDL_Surface *surface =
961 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
964 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
966 SDLSetNativeSurface(&surface);
968 bitmap->surface = surface;
971 void SDLFreeBitmapPointers(Bitmap *bitmap)
974 SDL_FreeSurface(bitmap->surface);
975 if (bitmap->surface_masked)
976 SDL_FreeSurface(bitmap->surface_masked);
978 bitmap->surface = NULL;
979 bitmap->surface_masked = NULL;
981 #if defined(TARGET_SDL2)
983 SDL_DestroyTexture(bitmap->texture);
984 if (bitmap->texture_masked)
985 SDL_DestroyTexture(bitmap->texture_masked);
987 bitmap->texture = NULL;
988 bitmap->texture_masked = NULL;
992 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
993 int src_x, int src_y, int width, int height,
994 int dst_x, int dst_y, int mask_mode)
996 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
997 SDL_Rect src_rect, dst_rect;
999 if (src_bitmap == backbuffer)
1001 src_x += video_xoffset;
1002 src_y += video_yoffset;
1008 src_rect.h = height;
1010 if (dst_bitmap == backbuffer || dst_bitmap == window)
1012 dst_x += video_xoffset;
1013 dst_y += video_yoffset;
1019 dst_rect.h = height;
1021 // if (src_bitmap != backbuffer || dst_bitmap != window)
1022 if (!(src_bitmap == backbuffer && dst_bitmap == window))
1023 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
1024 src_bitmap->surface_masked : src_bitmap->surface),
1025 &src_rect, real_dst_bitmap->surface, &dst_rect);
1027 #if defined(TARGET_SDL2)
1028 if (dst_bitmap == window)
1030 // SDL_UpdateWindowSurface(sdl_window);
1031 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1032 UpdateScreen(&dst_rect);
1035 if (dst_bitmap == window)
1037 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
1038 UpdateScreen(&dst_rect);
1043 void SDLBlitTexture(Bitmap *bitmap,
1044 int src_x, int src_y, int width, int height,
1045 int dst_x, int dst_y, int mask_mode)
1047 #if defined(TARGET_SDL2)
1049 SDL_Texture *texture;
1054 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
1056 if (texture == NULL)
1062 src_rect.h = height;
1067 dst_rect.h = height;
1069 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
1074 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
1077 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1080 if (dst_bitmap == backbuffer || dst_bitmap == window)
1091 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1093 #if defined(TARGET_SDL2)
1094 if (dst_bitmap == window)
1096 // SDL_UpdateWindowSurface(sdl_window);
1097 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
1098 UpdateScreen(&rect);
1101 if (dst_bitmap == window)
1103 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
1104 UpdateScreen(&rect);
1109 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
1110 int fade_mode, int fade_delay, int post_delay,
1111 void (*draw_border_function)(void))
1113 static boolean initialization_needed = TRUE;
1114 static SDL_Surface *surface_source = NULL;
1115 static SDL_Surface *surface_target = NULL;
1116 static SDL_Surface *surface_black = NULL;
1117 SDL_Surface *surface_screen = backbuffer->surface;
1118 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
1119 SDL_Rect src_rect, dst_rect;
1121 int src_x = x, src_y = y;
1122 int dst_x = x, dst_y = y;
1123 unsigned int time_last, time_current;
1125 // store function for drawing global masked border
1126 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
1128 // deactivate drawing of global border while fading, if needed
1129 if (draw_border_function == NULL)
1130 gfx.draw_global_border_function = NULL;
1132 /* check if screen size has changed */
1133 if (surface_source != NULL && (video.width != surface_source->w ||
1134 video.height != surface_source->h))
1136 SDL_FreeSurface(surface_source);
1137 SDL_FreeSurface(surface_target);
1138 SDL_FreeSurface(surface_black);
1140 initialization_needed = TRUE;
1146 src_rect.h = height;
1148 dst_x += video_xoffset;
1149 dst_y += video_yoffset;
1153 dst_rect.w = width; /* (ignored) */
1154 dst_rect.h = height; /* (ignored) */
1156 dst_rect2 = dst_rect;
1158 if (initialization_needed)
1160 #if defined(TARGET_SDL2)
1161 unsigned int flags = 0;
1163 unsigned int flags = SDL_SRCALPHA;
1165 /* use same surface type as screen surface */
1166 if ((surface_screen->flags & SDL_HWSURFACE))
1167 flags |= SDL_HWSURFACE;
1169 flags |= SDL_SWSURFACE;
1172 /* create surface for temporary copy of screen buffer (source) */
1173 if ((surface_source =
1174 SDL_CreateRGBSurface(flags,
1177 surface_screen->format->BitsPerPixel,
1178 surface_screen->format->Rmask,
1179 surface_screen->format->Gmask,
1180 surface_screen->format->Bmask,
1181 surface_screen->format->Amask)) == NULL)
1182 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1184 /* create surface for cross-fading screen buffer (target) */
1185 if ((surface_target =
1186 SDL_CreateRGBSurface(flags,
1189 surface_screen->format->BitsPerPixel,
1190 surface_screen->format->Rmask,
1191 surface_screen->format->Gmask,
1192 surface_screen->format->Bmask,
1193 surface_screen->format->Amask)) == NULL)
1194 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1196 /* create black surface for fading from/to black */
1197 if ((surface_black =
1198 SDL_CreateRGBSurface(flags,
1201 surface_screen->format->BitsPerPixel,
1202 surface_screen->format->Rmask,
1203 surface_screen->format->Gmask,
1204 surface_screen->format->Bmask,
1205 surface_screen->format->Amask)) == NULL)
1206 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1208 /* completely fill the surface with black color pixels */
1209 SDL_FillRect(surface_black, NULL,
1210 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1212 initialization_needed = FALSE;
1215 /* copy source and target surfaces to temporary surfaces for fading */
1216 if (fade_mode & FADE_TYPE_TRANSFORM)
1218 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1219 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1221 else if (fade_mode & FADE_TYPE_FADE_IN)
1223 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1224 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1226 else /* FADE_TYPE_FADE_OUT */
1228 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1229 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1232 time_current = SDL_GetTicks();
1234 if (fade_mode == FADE_MODE_MELT)
1236 boolean done = FALSE;
1237 int melt_pixels = 2;
1238 int melt_columns = width / melt_pixels;
1239 int ypos[melt_columns];
1240 int max_steps = height / 8 + 32;
1245 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1246 #if defined(TARGET_SDL2)
1247 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1249 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1252 ypos[0] = -GetSimpleRandom(16);
1254 for (i = 1 ; i < melt_columns; i++)
1256 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1258 ypos[i] = ypos[i - 1] + r;
1271 time_last = time_current;
1272 time_current = SDL_GetTicks();
1273 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1274 steps_final = MIN(MAX(0, steps), max_steps);
1278 done = (steps_done >= steps_final);
1280 for (i = 0 ; i < melt_columns; i++)
1288 else if (ypos[i] < height)
1293 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1295 if (ypos[i] + dy >= height)
1296 dy = height - ypos[i];
1298 /* copy part of (appearing) target surface to upper area */
1299 src_rect.x = src_x + i * melt_pixels;
1300 // src_rect.y = src_y + ypos[i];
1302 src_rect.w = melt_pixels;
1304 src_rect.h = ypos[i] + dy;
1306 dst_rect.x = dst_x + i * melt_pixels;
1307 // dst_rect.y = dst_y + ypos[i];
1310 if (steps_done >= steps_final)
1311 SDL_BlitSurface(surface_target, &src_rect,
1312 surface_screen, &dst_rect);
1316 /* copy part of (disappearing) source surface to lower area */
1317 src_rect.x = src_x + i * melt_pixels;
1319 src_rect.w = melt_pixels;
1320 src_rect.h = height - ypos[i];
1322 dst_rect.x = dst_x + i * melt_pixels;
1323 dst_rect.y = dst_y + ypos[i];
1325 if (steps_done >= steps_final)
1326 SDL_BlitSurface(surface_source, &src_rect,
1327 surface_screen, &dst_rect);
1333 src_rect.x = src_x + i * melt_pixels;
1335 src_rect.w = melt_pixels;
1336 src_rect.h = height;
1338 dst_rect.x = dst_x + i * melt_pixels;
1341 if (steps_done >= steps_final)
1342 SDL_BlitSurface(surface_target, &src_rect,
1343 surface_screen, &dst_rect);
1347 if (steps_done >= steps_final)
1349 if (draw_border_function != NULL)
1350 draw_border_function();
1352 UpdateScreen(&dst_rect2);
1356 else if (fade_mode == FADE_MODE_CURTAIN)
1360 int xx_size = width / 2;
1362 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1363 #if defined(TARGET_SDL2)
1364 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1366 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1369 for (xx = 0; xx < xx_size;)
1371 time_last = time_current;
1372 time_current = SDL_GetTicks();
1373 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1374 xx_final = MIN(MAX(0, xx), xx_size);
1379 src_rect.h = height;
1384 /* draw new (target) image to screen buffer */
1385 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1387 if (xx_final < xx_size)
1389 src_rect.w = xx_size - xx_final;
1390 src_rect.h = height;
1392 /* draw old (source) image to screen buffer (left side) */
1394 src_rect.x = src_x + xx_final;
1397 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1399 /* draw old (source) image to screen buffer (right side) */
1401 src_rect.x = src_x + xx_size;
1402 dst_rect.x = dst_x + xx_size + xx_final;
1404 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1407 if (draw_border_function != NULL)
1408 draw_border_function();
1410 /* only update the region of the screen that is affected from fading */
1411 UpdateScreen(&dst_rect2);
1414 else /* fading in, fading out or cross-fading */
1419 for (alpha = 0.0; alpha < 255.0;)
1421 time_last = time_current;
1422 time_current = SDL_GetTicks();
1423 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1424 alpha_final = MIN(MAX(0, alpha), 255);
1426 /* draw existing (source) image to screen buffer */
1427 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1429 /* draw new (target) image to screen buffer using alpha blending */
1430 #if defined(TARGET_SDL2)
1431 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1432 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1434 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1436 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1438 if (draw_border_function != NULL)
1439 draw_border_function();
1441 /* only update the region of the screen that is affected from fading */
1442 UpdateScreen(&dst_rect);
1448 unsigned int time_post_delay;
1450 time_current = SDL_GetTicks();
1451 time_post_delay = time_current + post_delay;
1453 while (time_current < time_post_delay)
1455 // do not wait longer than 10 ms at a time to be able to ...
1456 Delay(MIN(10, time_post_delay - time_current));
1458 // ... continue drawing global animations during post delay
1461 time_current = SDL_GetTicks();
1465 // restore function for drawing global masked border
1466 gfx.draw_global_border_function = draw_global_border_function;
1469 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1470 int to_x, int to_y, Uint32 color)
1472 SDL_Surface *surface = dst_bitmap->surface;
1476 swap_numbers(&from_x, &to_x);
1479 swap_numbers(&from_y, &to_y);
1483 rect.w = (to_x - from_x + 1);
1484 rect.h = (to_y - from_y + 1);
1486 if (dst_bitmap == backbuffer || dst_bitmap == window)
1488 rect.x += video_xoffset;
1489 rect.y += video_yoffset;
1492 SDL_FillRect(surface, &rect, color);
1495 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1496 int to_x, int to_y, Uint32 color)
1498 if (dst_bitmap == backbuffer || dst_bitmap == window)
1500 from_x += video_xoffset;
1501 from_y += video_yoffset;
1502 to_x += video_xoffset;
1503 to_y += video_yoffset;
1506 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1509 #if ENABLE_UNUSED_CODE
1510 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1511 int num_points, Uint32 color)
1516 for (i = 0; i < num_points - 1; i++)
1518 for (x = 0; x < line_width; x++)
1520 for (y = 0; y < line_width; y++)
1522 int dx = x - line_width / 2;
1523 int dy = y - line_width / 2;
1525 if ((x == 0 && y == 0) ||
1526 (x == 0 && y == line_width - 1) ||
1527 (x == line_width - 1 && y == 0) ||
1528 (x == line_width - 1 && y == line_width - 1))
1531 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1532 points[i+1].x + dx, points[i+1].y + dy, color);
1539 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1541 SDL_Surface *surface = src_bitmap->surface;
1543 if (src_bitmap == backbuffer || src_bitmap == window)
1549 switch (surface->format->BytesPerPixel)
1551 case 1: /* assuming 8-bpp */
1553 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1557 case 2: /* probably 15-bpp or 16-bpp */
1559 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1563 case 3: /* slow 24-bpp mode; usually not used */
1565 /* does this work? */
1566 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1570 shift = surface->format->Rshift;
1571 color |= *(pix + shift / 8) >> shift;
1572 shift = surface->format->Gshift;
1573 color |= *(pix + shift / 8) >> shift;
1574 shift = surface->format->Bshift;
1575 color |= *(pix + shift / 8) >> shift;
1581 case 4: /* probably 32-bpp */
1583 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1592 /* ========================================================================= */
1593 /* The following functions were taken from the SGE library */
1594 /* (SDL Graphics Extension Library) by Anders Lindström */
1595 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1596 /* ========================================================================= */
1598 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1600 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1602 switch (surface->format->BytesPerPixel)
1606 /* Assuming 8-bpp */
1607 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1613 /* Probably 15-bpp or 16-bpp */
1614 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1620 /* Slow 24-bpp mode, usually not used */
1624 /* Gack - slow, but endian correct */
1625 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1626 shift = surface->format->Rshift;
1627 *(pix+shift/8) = color>>shift;
1628 shift = surface->format->Gshift;
1629 *(pix+shift/8) = color>>shift;
1630 shift = surface->format->Bshift;
1631 *(pix+shift/8) = color>>shift;
1637 /* Probably 32-bpp */
1638 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1645 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1646 Uint8 R, Uint8 G, Uint8 B)
1648 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1651 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1653 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1656 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1658 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1661 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1666 /* Gack - slow, but endian correct */
1667 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1668 shift = surface->format->Rshift;
1669 *(pix+shift/8) = color>>shift;
1670 shift = surface->format->Gshift;
1671 *(pix+shift/8) = color>>shift;
1672 shift = surface->format->Bshift;
1673 *(pix+shift/8) = color>>shift;
1676 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1678 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1681 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1683 switch (dest->format->BytesPerPixel)
1686 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1690 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1694 _PutPixel24(dest,x,y,color);
1698 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1703 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1705 if (SDL_MUSTLOCK(surface))
1707 if (SDL_LockSurface(surface) < 0)
1713 _PutPixel(surface, x, y, color);
1715 if (SDL_MUSTLOCK(surface))
1717 SDL_UnlockSurface(surface);
1721 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1722 Uint8 r, Uint8 g, Uint8 b)
1724 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1727 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1729 if (y >= 0 && y <= dest->h - 1)
1731 switch (dest->format->BytesPerPixel)
1734 return y*dest->pitch;
1738 return y*dest->pitch/2;
1742 return y*dest->pitch;
1746 return y*dest->pitch/4;
1754 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1756 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1758 switch (surface->format->BytesPerPixel)
1762 /* Assuming 8-bpp */
1763 *((Uint8 *)surface->pixels + ypitch + x) = color;
1769 /* Probably 15-bpp or 16-bpp */
1770 *((Uint16 *)surface->pixels + ypitch + x) = color;
1776 /* Slow 24-bpp mode, usually not used */
1780 /* Gack - slow, but endian correct */
1781 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1782 shift = surface->format->Rshift;
1783 *(pix+shift/8) = color>>shift;
1784 shift = surface->format->Gshift;
1785 *(pix+shift/8) = color>>shift;
1786 shift = surface->format->Bshift;
1787 *(pix+shift/8) = color>>shift;
1793 /* Probably 32-bpp */
1794 *((Uint32 *)surface->pixels + ypitch + x) = color;
1801 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1806 if (SDL_MUSTLOCK(Surface))
1808 if (SDL_LockSurface(Surface) < 0)
1821 /* Do the clipping */
1822 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1826 if (x2 > Surface->w - 1)
1827 x2 = Surface->w - 1;
1834 SDL_FillRect(Surface, &l, Color);
1836 if (SDL_MUSTLOCK(Surface))
1838 SDL_UnlockSurface(Surface);
1842 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1843 Uint8 R, Uint8 G, Uint8 B)
1845 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1848 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1859 /* Do the clipping */
1860 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1864 if (x2 > Surface->w - 1)
1865 x2 = Surface->w - 1;
1872 SDL_FillRect(Surface, &l, Color);
1875 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1880 if (SDL_MUSTLOCK(Surface))
1882 if (SDL_LockSurface(Surface) < 0)
1895 /* Do the clipping */
1896 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1900 if (y2 > Surface->h - 1)
1901 y2 = Surface->h - 1;
1908 SDL_FillRect(Surface, &l, Color);
1910 if (SDL_MUSTLOCK(Surface))
1912 SDL_UnlockSurface(Surface);
1916 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1917 Uint8 R, Uint8 G, Uint8 B)
1919 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1922 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1933 /* Do the clipping */
1934 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1938 if (y2 > Surface->h - 1)
1939 y2 = Surface->h - 1;
1946 SDL_FillRect(Surface, &l, Color);
1949 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1950 Sint16 x2, Sint16 y2, Uint32 Color,
1951 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1954 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1959 sdx = (dx < 0) ? -1 : 1;
1960 sdy = (dy < 0) ? -1 : 1;
1972 for (x = 0; x < dx; x++)
1974 Callback(Surface, px, py, Color);
1988 for (y = 0; y < dy; y++)
1990 Callback(Surface, px, py, Color);
2004 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
2005 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
2006 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
2009 sge_DoLine(Surface, X1, Y1, X2, Y2,
2010 SDL_MapRGB(Surface->format, R, G, B), Callback);
2013 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
2016 if (SDL_MUSTLOCK(Surface))
2018 if (SDL_LockSurface(Surface) < 0)
2023 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
2025 /* unlock the display */
2026 if (SDL_MUSTLOCK(Surface))
2028 SDL_UnlockSurface(Surface);
2032 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
2033 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
2035 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
2038 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
2040 if (dst_bitmap == backbuffer || dst_bitmap == window)
2046 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
2051 -----------------------------------------------------------------------------
2052 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
2053 -----------------------------------------------------------------------------
2056 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
2057 int width, int height, Uint32 color)
2061 for (y = src_y; y < src_y + height; y++)
2063 for (x = src_x; x < src_x + width; x++)
2065 Uint32 pixel = SDLGetPixel(bitmap, x, y);
2067 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
2072 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
2073 int src_x, int src_y, int width, int height,
2074 int dst_x, int dst_y)
2078 for (y = 0; y < height; y++)
2080 for (x = 0; x < width; x++)
2082 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
2084 if (pixel != BLACK_PIXEL)
2085 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
2091 /* ========================================================================= */
2092 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
2093 /* (Rotozoomer) by Andreas Schiffler */
2094 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
2095 /* ========================================================================= */
2098 -----------------------------------------------------------------------------
2101 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
2102 -----------------------------------------------------------------------------
2113 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
2116 tColorRGBA *sp, *csp, *dp;
2120 sp = csp = (tColorRGBA *) src->pixels;
2121 dp = (tColorRGBA *) dst->pixels;
2122 dgap = dst->pitch - dst->w * 4;
2124 for (y = 0; y < dst->h; y++)
2128 for (x = 0; x < dst->w; x++)
2130 tColorRGBA *sp0 = sp;
2131 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2132 tColorRGBA *sp00 = &sp0[0];
2133 tColorRGBA *sp01 = &sp0[1];
2134 tColorRGBA *sp10 = &sp1[0];
2135 tColorRGBA *sp11 = &sp1[1];
2138 /* create new color pixel from all four source color pixels */
2139 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2140 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2141 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2142 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2147 /* advance source pointers */
2150 /* advance destination pointer */
2154 /* advance source pointer */
2155 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2157 /* advance destination pointers */
2158 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2164 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2166 int x, y, *sax, *say, *csax, *csay;
2168 tColorRGBA *sp, *csp, *csp0, *dp;
2171 /* use specialized zoom function when scaling down to exactly half size */
2172 if (src->w == 2 * dst->w &&
2173 src->h == 2 * dst->h)
2174 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2176 /* variable setup */
2177 sx = (float) src->w / (float) dst->w;
2178 sy = (float) src->h / (float) dst->h;
2180 /* allocate memory for row increments */
2181 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2182 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2184 /* precalculate row increments */
2185 for (x = 0; x <= dst->w; x++)
2186 *csax++ = (int)(sx * x);
2188 for (y = 0; y <= dst->h; y++)
2189 *csay++ = (int)(sy * y);
2192 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2193 dp = (tColorRGBA *) dst->pixels;
2194 dgap = dst->pitch - dst->w * 4;
2197 for (y = 0; y < dst->h; y++)
2202 for (x = 0; x < dst->w; x++)
2207 /* advance source pointers */
2211 /* advance destination pointer */
2215 /* advance source pointer */
2217 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2219 /* advance destination pointers */
2220 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2230 -----------------------------------------------------------------------------
2233 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2234 -----------------------------------------------------------------------------
2237 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2239 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2240 Uint8 *sp, *dp, *csp;
2243 /* variable setup */
2244 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2245 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2247 /* allocate memory for row increments */
2248 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2249 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2251 /* precalculate row increments */
2254 for (x = 0; x < dst->w; x++)
2257 *csax = (csx >> 16);
2264 for (y = 0; y < dst->h; y++)
2267 *csay = (csy >> 16);
2274 for (x = 0; x < dst->w; x++)
2282 for (y = 0; y < dst->h; y++)
2289 sp = csp = (Uint8 *) src->pixels;
2290 dp = (Uint8 *) dst->pixels;
2291 dgap = dst->pitch - dst->w;
2295 for (y = 0; y < dst->h; y++)
2299 for (x = 0; x < dst->w; x++)
2304 /* advance source pointers */
2308 /* advance destination pointer */
2312 /* advance source pointer (for row) */
2313 csp += ((*csay) * src->pitch);
2316 /* advance destination pointers */
2327 -----------------------------------------------------------------------------
2330 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2331 'zoomx' and 'zoomy' are scaling factors for width and height.
2332 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2333 into a 32bit RGBA format on the fly.
2334 -----------------------------------------------------------------------------
2337 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2339 SDL_Surface *zoom_src = NULL;
2340 SDL_Surface *zoom_dst = NULL;
2341 boolean is_converted = FALSE;
2348 /* determine if source surface is 32 bit or 8 bit */
2349 is_32bit = (src->format->BitsPerPixel == 32);
2351 if (is_32bit || src->format->BitsPerPixel == 8)
2353 /* use source surface 'as is' */
2358 /* new source surface is 32 bit with a defined RGB ordering */
2359 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2360 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2361 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2363 is_converted = TRUE;
2366 /* allocate surface to completely contain the zoomed surface */
2369 /* target surface is 32 bit with source RGBA/ABGR ordering */
2370 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2371 zoom_src->format->Rmask,
2372 zoom_src->format->Gmask,
2373 zoom_src->format->Bmask, 0);
2377 /* target surface is 8 bit */
2378 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2382 /* lock source surface */
2383 SDL_LockSurface(zoom_src);
2385 /* check which kind of surface we have */
2388 /* call the 32 bit transformation routine to do the zooming */
2389 zoomSurfaceRGBA(zoom_src, zoom_dst);
2394 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2395 zoom_dst->format->palette->colors[i] =
2396 zoom_src->format->palette->colors[i];
2397 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2399 /* call the 8 bit transformation routine to do the zooming */
2400 zoomSurfaceY(zoom_src, zoom_dst);
2403 /* unlock source surface */
2404 SDL_UnlockSurface(zoom_src);
2406 /* free temporary surface */
2408 SDL_FreeSurface(zoom_src);
2410 /* return destination surface */
2414 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2416 Bitmap *dst_bitmap = CreateBitmapStruct();
2417 SDL_Surface **dst_surface = &dst_bitmap->surface;
2419 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2420 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2422 dst_bitmap->width = dst_width;
2423 dst_bitmap->height = dst_height;
2425 /* create zoomed temporary surface from source surface */
2426 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2428 /* create native format destination surface from zoomed temporary surface */
2429 SDLSetNativeSurface(dst_surface);
2435 /* ========================================================================= */
2436 /* load image to bitmap */
2437 /* ========================================================================= */
2439 Bitmap *SDLLoadImage(char *filename)
2441 Bitmap *new_bitmap = CreateBitmapStruct();
2442 SDL_Surface *sdl_image_tmp;
2444 print_timestamp_init("SDLLoadImage");
2446 print_timestamp_time(getBaseNamePtr(filename));
2448 /* load image to temporary surface */
2449 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2451 SetError("IMG_Load(): %s", SDL_GetError());
2456 print_timestamp_time("IMG_Load");
2458 UPDATE_BUSY_STATE();
2460 /* create native non-transparent surface for current image */
2461 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2463 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2468 print_timestamp_time("SDL_DisplayFormat (opaque)");
2470 UPDATE_BUSY_STATE();
2472 /* create native transparent surface for current image */
2473 if (sdl_image_tmp->format->Amask == 0)
2474 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2475 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2477 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2479 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2484 print_timestamp_time("SDL_DisplayFormat (masked)");
2486 UPDATE_BUSY_STATE();
2488 /* free temporary surface */
2489 SDL_FreeSurface(sdl_image_tmp);
2491 new_bitmap->width = new_bitmap->surface->w;
2492 new_bitmap->height = new_bitmap->surface->h;
2494 print_timestamp_done("SDLLoadImage");
2500 /* ------------------------------------------------------------------------- */
2501 /* custom cursor fuctions */
2502 /* ------------------------------------------------------------------------- */
2504 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2506 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2507 cursor_info->width, cursor_info->height,
2508 cursor_info->hot_x, cursor_info->hot_y);
2511 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2513 static struct MouseCursorInfo *last_cursor_info = NULL;
2514 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2515 static SDL_Cursor *cursor_default = NULL;
2516 static SDL_Cursor *cursor_current = NULL;
2518 /* if invoked for the first time, store the SDL default cursor */
2519 if (cursor_default == NULL)
2520 cursor_default = SDL_GetCursor();
2522 /* only create new cursor if cursor info (custom only) has changed */
2523 if (cursor_info != NULL && cursor_info != last_cursor_info)
2525 cursor_current = create_cursor(cursor_info);
2526 last_cursor_info = cursor_info;
2529 /* only set new cursor if cursor info (custom or NULL) has changed */
2530 if (cursor_info != last_cursor_info2)
2531 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2533 last_cursor_info2 = cursor_info;
2537 /* ========================================================================= */
2538 /* audio functions */
2539 /* ========================================================================= */
2541 void SDLOpenAudio(void)
2543 #if !defined(TARGET_SDL2)
2544 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2545 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2548 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2550 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2554 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2555 AUDIO_NUM_CHANNELS_STEREO,
2556 setup.system.audio_fragment_size) < 0)
2558 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2562 audio.sound_available = TRUE;
2563 audio.music_available = TRUE;
2564 audio.loops_available = TRUE;
2565 audio.sound_enabled = TRUE;
2567 /* set number of available mixer channels */
2568 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2569 audio.music_channel = MUSIC_CHANNEL;
2570 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2572 Mixer_InitChannels();
2575 void SDLCloseAudio(void)
2578 Mix_HaltChannel(-1);
2581 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2585 /* ========================================================================= */
2586 /* event functions */
2587 /* ========================================================================= */
2589 void SDLNextEvent(Event *event)
2591 SDL_WaitEvent(event);
2593 if (event->type == EVENT_BUTTONPRESS ||
2594 event->type == EVENT_BUTTONRELEASE)
2596 if (((ButtonEvent *)event)->x > video_xoffset)
2597 ((ButtonEvent *)event)->x -= video_xoffset;
2599 ((ButtonEvent *)event)->x = 0;
2600 if (((ButtonEvent *)event)->y > video_yoffset)
2601 ((ButtonEvent *)event)->y -= video_yoffset;
2603 ((ButtonEvent *)event)->y = 0;
2605 else if (event->type == EVENT_MOTIONNOTIFY)
2607 if (((MotionEvent *)event)->x > video_xoffset)
2608 ((MotionEvent *)event)->x -= video_xoffset;
2610 ((MotionEvent *)event)->x = 0;
2611 if (((MotionEvent *)event)->y > video_yoffset)
2612 ((MotionEvent *)event)->y -= video_yoffset;
2614 ((MotionEvent *)event)->y = 0;
2618 void SDLHandleWindowManagerEvent(Event *event)
2621 #if defined(PLATFORM_WIN32)
2622 // experimental drag and drop code
2624 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2625 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2627 #if defined(TARGET_SDL2)
2628 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2630 if (syswmmsg->msg == WM_DROPFILES)
2633 #if defined(TARGET_SDL2)
2634 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2636 HDROP hdrop = (HDROP)syswmmsg->wParam;
2640 printf("::: SDL_SYSWMEVENT:\n");
2642 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2644 for (i = 0; i < num_files; i++)
2646 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2647 char buffer[buffer_len + 1];
2649 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2651 printf("::: - '%s'\n", buffer);
2654 #if defined(TARGET_SDL2)
2655 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2657 DragFinish((HDROP)syswmmsg->wParam);
2665 /* ========================================================================= */
2666 /* joystick functions */
2667 /* ========================================================================= */
2669 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2670 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2671 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2673 static boolean SDLOpenJoystick(int nr)
2675 if (nr < 0 || nr > MAX_PLAYERS)
2678 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2681 static void SDLCloseJoystick(int nr)
2683 if (nr < 0 || nr > MAX_PLAYERS)
2686 SDL_JoystickClose(sdl_joystick[nr]);
2688 sdl_joystick[nr] = NULL;
2691 static boolean SDLCheckJoystickOpened(int nr)
2693 if (nr < 0 || nr > MAX_PLAYERS)
2696 #if defined(TARGET_SDL2)
2697 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2699 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2703 void HandleJoystickEvent(Event *event)
2707 case SDL_JOYAXISMOTION:
2708 if (event->jaxis.axis < 2)
2709 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2712 case SDL_JOYBUTTONDOWN:
2713 if (event->jbutton.button < 2)
2714 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2717 case SDL_JOYBUTTONUP:
2718 if (event->jbutton.button < 2)
2719 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2727 void SDLInitJoysticks()
2729 static boolean sdl_joystick_subsystem_initialized = FALSE;
2730 boolean print_warning = !sdl_joystick_subsystem_initialized;
2733 if (!sdl_joystick_subsystem_initialized)
2735 sdl_joystick_subsystem_initialized = TRUE;
2737 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2739 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2744 for (i = 0; i < MAX_PLAYERS; i++)
2746 /* get configured joystick for this player */
2747 char *device_name = setup.input[i].joy.device_name;
2748 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2750 if (joystick_nr >= SDL_NumJoysticks())
2752 if (setup.input[i].use_joystick && print_warning)
2753 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2758 /* misuse joystick file descriptor variable to store joystick number */
2759 joystick.fd[i] = joystick_nr;
2761 if (joystick_nr == -1)
2764 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2765 if (SDLCheckJoystickOpened(joystick_nr))
2766 SDLCloseJoystick(joystick_nr);
2768 if (!setup.input[i].use_joystick)
2771 if (!SDLOpenJoystick(joystick_nr))
2774 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2779 joystick.status = JOYSTICK_ACTIVATED;
2783 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2785 if (nr < 0 || nr >= MAX_PLAYERS)
2789 *x = sdl_js_axis[nr][0];
2791 *y = sdl_js_axis[nr][1];
2794 *b1 = sdl_js_button[nr][0];
2796 *b2 = sdl_js_button[nr][1];