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 defined(TARGET_SDL2)
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 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
631 int surface_flags_window = SURFACE_FLAGS;
632 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
635 int width = (fullscreen ? fullscreen_width : video.width);
636 int height = (fullscreen ? fullscreen_height : video.height);
637 int surface_flags = (fullscreen ? surface_flags_fullscreen :
638 surface_flags_window);
640 // default window size is unscaled
641 video.window_width = video.width;
642 video.window_height = video.height;
644 #if defined(TARGET_SDL2)
646 // store if initial screen mode is fullscreen mode when changing screen size
647 video.fullscreen_initial = fullscreen;
649 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
651 video.window_width = window_scaling_factor * width;
652 video.window_height = window_scaling_factor * height;
654 if ((*backbuffer)->surface)
656 SDL_FreeSurface((*backbuffer)->surface);
657 (*backbuffer)->surface = NULL;
660 #if USE_TARGET_TEXTURE
661 if (sdl_texture_stream)
663 SDL_DestroyTexture(sdl_texture_stream);
664 sdl_texture_stream = NULL;
667 if (sdl_texture_target)
669 SDL_DestroyTexture(sdl_texture_target);
670 sdl_texture_target = NULL;
675 SDL_DestroyTexture(sdl_texture);
680 if (!(fullscreen && fullscreen_enabled))
684 SDL_DestroyRenderer(sdl_renderer);
690 SDL_DestroyWindow(sdl_window);
695 if (sdl_window == NULL)
696 sdl_window = SDL_CreateWindow(program.window_title,
697 SDL_WINDOWPOS_CENTERED,
698 SDL_WINDOWPOS_CENTERED,
703 if (sdl_window != NULL)
706 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
707 *without* enabling 2D/3D acceleration and/or guest additions installed,
708 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
709 it will try to use accelerated graphics and apparently fails miserably) */
710 if (sdl_renderer == NULL)
711 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
713 if (sdl_renderer == NULL)
714 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
717 if (sdl_renderer != NULL)
719 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
720 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
721 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
723 #if USE_TARGET_TEXTURE
724 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
725 SDL_PIXELFORMAT_ARGB8888,
726 SDL_TEXTUREACCESS_STREAMING,
729 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
730 SDL_PIXELFORMAT_ARGB8888,
731 SDL_TEXTUREACCESS_TARGET,
734 sdl_texture = SDL_CreateTexture(sdl_renderer,
735 SDL_PIXELFORMAT_ARGB8888,
736 SDL_TEXTUREACCESS_STREAMING,
740 #if USE_TARGET_TEXTURE
741 if (sdl_texture_stream != NULL &&
742 sdl_texture_target != NULL)
744 if (sdl_texture != NULL)
747 // use SDL default values for RGB masks and no alpha channel
748 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
750 if (new_surface == NULL)
751 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
756 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
761 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
766 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
770 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
773 #if defined(TARGET_SDL2)
774 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
775 if (new_surface != NULL)
776 fullscreen_enabled = fullscreen;
782 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
784 boolean success = TRUE;
785 SDL_Surface *new_surface = NULL;
789 if (*backbuffer == NULL)
790 *backbuffer = CreateBitmapStruct();
792 /* (real bitmap might be larger in fullscreen mode with video offsets) */
793 (*backbuffer)->width = video.width;
794 (*backbuffer)->height = video.height;
796 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
798 setFullscreenParameters(setup.fullscreen_mode);
800 video_xoffset = fullscreen_xoffset;
801 video_yoffset = fullscreen_yoffset;
803 /* switch display to fullscreen mode, if available */
804 new_surface = SDLCreateScreen(backbuffer, TRUE);
806 if (new_surface == NULL)
808 /* switching display to fullscreen mode failed */
809 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
811 /* do not try it again */
812 video.fullscreen_available = FALSE;
818 (*backbuffer)->surface = new_surface;
820 video.fullscreen_enabled = TRUE;
821 video.fullscreen_mode_current = setup.fullscreen_mode;
827 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
832 /* switch display to window mode */
833 new_surface = SDLCreateScreen(backbuffer, FALSE);
835 if (new_surface == NULL)
837 /* switching display to window mode failed -- should not happen */
838 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
844 (*backbuffer)->surface = new_surface;
846 video.fullscreen_enabled = FALSE;
847 video.window_scaling_percent = setup.window_scaling_percent;
848 video.window_scaling_quality = setup.window_scaling_quality;
854 #if defined(TARGET_SDL2)
855 SDLRedrawWindow(); // map window
859 #if defined(PLATFORM_WIN32)
860 // experimental drag and drop code
862 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
865 SDL_SysWMinfo wminfo;
867 boolean wminfo_success = FALSE;
869 SDL_VERSION(&wminfo.version);
870 #if defined(TARGET_SDL2)
872 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
874 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
879 #if defined(TARGET_SDL2)
880 hwnd = wminfo.info.win.window;
882 hwnd = wminfo.window;
885 DragAcceptFiles(hwnd, TRUE);
894 void SDLSetWindowTitle()
896 #if defined(TARGET_SDL2)
897 SDL_SetWindowTitle(sdl_window, program.window_title);
899 SDL_WM_SetCaption(program.window_title, program.window_title);
903 #if defined(TARGET_SDL2)
904 void SDLSetWindowScaling(int window_scaling_percent)
906 if (sdl_window == NULL)
909 float window_scaling_factor = (float)window_scaling_percent / 100;
910 int new_window_width = (int)(window_scaling_factor * video.width);
911 int new_window_height = (int)(window_scaling_factor * video.height);
913 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
915 video.window_scaling_percent = window_scaling_percent;
916 video.window_width = new_window_width;
917 video.window_height = new_window_height;
922 void SDLSetWindowScalingQuality(char *window_scaling_quality)
924 #if USE_TARGET_TEXTURE
925 SDL_Texture *new_texture;
927 if (sdl_texture_stream == NULL ||
928 sdl_texture_target == NULL)
931 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
933 new_texture = SDL_CreateTexture(sdl_renderer,
934 SDL_PIXELFORMAT_ARGB8888,
935 SDL_TEXTUREACCESS_STREAMING,
936 video.width, video.height);
938 if (new_texture != NULL)
940 SDL_DestroyTexture(sdl_texture_stream);
942 sdl_texture_stream = new_texture;
945 new_texture = SDL_CreateTexture(sdl_renderer,
946 SDL_PIXELFORMAT_ARGB8888,
947 SDL_TEXTUREACCESS_TARGET,
948 video.width, video.height);
950 if (new_texture != NULL)
952 SDL_DestroyTexture(sdl_texture_target);
954 sdl_texture_target = new_texture;
960 if (sdl_texture == NULL)
963 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
965 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
966 SDL_PIXELFORMAT_ARGB8888,
967 SDL_TEXTUREACCESS_STREAMING,
968 video.width, video.height);
970 if (new_texture != NULL)
972 SDL_DestroyTexture(sdl_texture);
974 sdl_texture = new_texture;
980 video.window_scaling_quality = window_scaling_quality;
983 void SDLSetWindowFullscreen(boolean fullscreen)
985 if (sdl_window == NULL)
988 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
990 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
991 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
993 // if screen size was changed in fullscreen mode, correct desktop window size
994 if (!fullscreen && video.fullscreen_initial)
996 SDLSetWindowScaling(setup.window_scaling_percent);
997 SDL_SetWindowPosition(sdl_window,
998 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
1000 video.fullscreen_initial = FALSE;
1004 void SDLRedrawWindow()
1010 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
1013 SDL_Surface *surface =
1014 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
1016 if (surface == NULL)
1017 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1019 SDLSetNativeSurface(&surface);
1021 bitmap->surface = surface;
1024 void SDLFreeBitmapPointers(Bitmap *bitmap)
1026 if (bitmap->surface)
1027 SDL_FreeSurface(bitmap->surface);
1028 if (bitmap->surface_masked)
1029 SDL_FreeSurface(bitmap->surface_masked);
1031 bitmap->surface = NULL;
1032 bitmap->surface_masked = NULL;
1034 #if defined(TARGET_SDL2)
1035 if (bitmap->texture)
1036 SDL_DestroyTexture(bitmap->texture);
1037 if (bitmap->texture_masked)
1038 SDL_DestroyTexture(bitmap->texture_masked);
1040 bitmap->texture = NULL;
1041 bitmap->texture_masked = NULL;
1045 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1046 int src_x, int src_y, int width, int height,
1047 int dst_x, int dst_y, int mask_mode)
1049 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1050 SDL_Rect src_rect, dst_rect;
1052 if (src_bitmap == backbuffer)
1054 src_x += video_xoffset;
1055 src_y += video_yoffset;
1061 src_rect.h = height;
1063 if (dst_bitmap == backbuffer || dst_bitmap == window)
1065 dst_x += video_xoffset;
1066 dst_y += video_yoffset;
1072 dst_rect.h = height;
1074 // if (src_bitmap != backbuffer || dst_bitmap != window)
1075 if (!(src_bitmap == backbuffer && dst_bitmap == window))
1076 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
1077 src_bitmap->surface_masked : src_bitmap->surface),
1078 &src_rect, real_dst_bitmap->surface, &dst_rect);
1080 #if defined(TARGET_SDL2)
1081 if (dst_bitmap == window)
1083 // SDL_UpdateWindowSurface(sdl_window);
1084 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1085 UpdateScreen(&dst_rect);
1088 if (dst_bitmap == window)
1090 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
1091 UpdateScreen(&dst_rect);
1096 void SDLBlitTexture(Bitmap *bitmap,
1097 int src_x, int src_y, int width, int height,
1098 int dst_x, int dst_y, int mask_mode)
1100 #if defined(TARGET_SDL2)
1101 SDL_Texture *texture;
1106 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
1108 if (texture == NULL)
1114 src_rect.h = height;
1119 dst_rect.h = height;
1121 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
1125 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
1128 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1131 if (dst_bitmap == backbuffer || dst_bitmap == window)
1142 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1144 #if defined(TARGET_SDL2)
1145 if (dst_bitmap == window)
1147 // SDL_UpdateWindowSurface(sdl_window);
1148 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
1149 UpdateScreen(&rect);
1152 if (dst_bitmap == window)
1154 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
1155 UpdateScreen(&rect);
1160 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
1161 int fade_mode, int fade_delay, int post_delay,
1162 void (*draw_border_function)(void))
1164 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
1165 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
1166 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
1167 SDL_Surface *surface_screen = backbuffer->surface;
1168 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
1169 SDL_Rect src_rect, dst_rect;
1171 int src_x = x, src_y = y;
1172 int dst_x = x, dst_y = y;
1173 unsigned int time_last, time_current;
1175 // store function for drawing global masked border
1176 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
1178 // deactivate drawing of global border while fading, if needed
1179 if (draw_border_function == NULL)
1180 gfx.draw_global_border_function = NULL;
1185 src_rect.h = height;
1187 dst_x += video_xoffset;
1188 dst_y += video_yoffset;
1192 dst_rect.w = width; /* (ignored) */
1193 dst_rect.h = height; /* (ignored) */
1195 dst_rect2 = dst_rect;
1197 /* copy source and target surfaces to temporary surfaces for fading */
1198 if (fade_mode & FADE_TYPE_TRANSFORM)
1200 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1201 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1203 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
1204 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
1206 else if (fade_mode & FADE_TYPE_FADE_IN)
1208 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1209 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1211 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
1213 else /* FADE_TYPE_FADE_OUT */
1215 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1216 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1218 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
1221 time_current = SDL_GetTicks();
1223 if (fade_mode == FADE_MODE_MELT)
1225 boolean done = FALSE;
1226 int melt_pixels = 2;
1227 int melt_columns = width / melt_pixels;
1228 int ypos[melt_columns];
1229 int max_steps = height / 8 + 32;
1234 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1235 #if defined(TARGET_SDL2)
1236 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1238 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1241 ypos[0] = -GetSimpleRandom(16);
1243 for (i = 1 ; i < melt_columns; i++)
1245 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1247 ypos[i] = ypos[i - 1] + r;
1260 time_last = time_current;
1261 time_current = SDL_GetTicks();
1262 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1263 steps_final = MIN(MAX(0, steps), max_steps);
1267 done = (steps_done >= steps_final);
1269 for (i = 0 ; i < melt_columns; i++)
1277 else if (ypos[i] < height)
1282 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1284 if (ypos[i] + dy >= height)
1285 dy = height - ypos[i];
1287 /* copy part of (appearing) target surface to upper area */
1288 src_rect.x = src_x + i * melt_pixels;
1289 // src_rect.y = src_y + ypos[i];
1291 src_rect.w = melt_pixels;
1293 src_rect.h = ypos[i] + dy;
1295 dst_rect.x = dst_x + i * melt_pixels;
1296 // dst_rect.y = dst_y + ypos[i];
1299 if (steps_done >= steps_final)
1300 SDL_BlitSurface(surface_target, &src_rect,
1301 surface_screen, &dst_rect);
1305 /* copy part of (disappearing) source surface to lower area */
1306 src_rect.x = src_x + i * melt_pixels;
1308 src_rect.w = melt_pixels;
1309 src_rect.h = height - ypos[i];
1311 dst_rect.x = dst_x + i * melt_pixels;
1312 dst_rect.y = dst_y + ypos[i];
1314 if (steps_done >= steps_final)
1315 SDL_BlitSurface(surface_source, &src_rect,
1316 surface_screen, &dst_rect);
1322 src_rect.x = src_x + i * melt_pixels;
1324 src_rect.w = melt_pixels;
1325 src_rect.h = height;
1327 dst_rect.x = dst_x + i * melt_pixels;
1330 if (steps_done >= steps_final)
1331 SDL_BlitSurface(surface_target, &src_rect,
1332 surface_screen, &dst_rect);
1336 if (steps_done >= steps_final)
1338 if (draw_border_function != NULL)
1339 draw_border_function();
1341 UpdateScreen(&dst_rect2);
1345 else if (fade_mode == FADE_MODE_CURTAIN)
1349 int xx_size = width / 2;
1351 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1352 #if defined(TARGET_SDL2)
1353 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1355 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1358 for (xx = 0; xx < xx_size;)
1360 time_last = time_current;
1361 time_current = SDL_GetTicks();
1362 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1363 xx_final = MIN(MAX(0, xx), xx_size);
1368 src_rect.h = height;
1373 /* draw new (target) image to screen buffer */
1374 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1376 if (xx_final < xx_size)
1378 src_rect.w = xx_size - xx_final;
1379 src_rect.h = height;
1381 /* draw old (source) image to screen buffer (left side) */
1383 src_rect.x = src_x + xx_final;
1386 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1388 /* draw old (source) image to screen buffer (right side) */
1390 src_rect.x = src_x + xx_size;
1391 dst_rect.x = dst_x + xx_size + xx_final;
1393 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1396 if (draw_border_function != NULL)
1397 draw_border_function();
1399 /* only update the region of the screen that is affected from fading */
1400 UpdateScreen(&dst_rect2);
1403 else /* fading in, fading out or cross-fading */
1408 for (alpha = 0.0; alpha < 255.0;)
1410 time_last = time_current;
1411 time_current = SDL_GetTicks();
1412 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1413 alpha_final = MIN(MAX(0, alpha), 255);
1415 /* draw existing (source) image to screen buffer */
1416 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1418 /* draw new (target) image to screen buffer using alpha blending */
1419 #if defined(TARGET_SDL2)
1420 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1421 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1423 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1425 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1427 if (draw_border_function != NULL)
1428 draw_border_function();
1430 /* only update the region of the screen that is affected from fading */
1431 UpdateScreen(&dst_rect);
1437 unsigned int time_post_delay;
1439 time_current = SDL_GetTicks();
1440 time_post_delay = time_current + post_delay;
1442 while (time_current < time_post_delay)
1444 // do not wait longer than 10 ms at a time to be able to ...
1445 Delay(MIN(10, time_post_delay - time_current));
1447 // ... continue drawing global animations during post delay
1450 time_current = SDL_GetTicks();
1454 // restore function for drawing global masked border
1455 gfx.draw_global_border_function = draw_global_border_function;
1458 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1459 int to_x, int to_y, Uint32 color)
1461 SDL_Surface *surface = dst_bitmap->surface;
1465 swap_numbers(&from_x, &to_x);
1468 swap_numbers(&from_y, &to_y);
1472 rect.w = (to_x - from_x + 1);
1473 rect.h = (to_y - from_y + 1);
1475 if (dst_bitmap == backbuffer || dst_bitmap == window)
1477 rect.x += video_xoffset;
1478 rect.y += video_yoffset;
1481 SDL_FillRect(surface, &rect, color);
1484 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1485 int to_x, int to_y, Uint32 color)
1487 if (dst_bitmap == backbuffer || dst_bitmap == window)
1489 from_x += video_xoffset;
1490 from_y += video_yoffset;
1491 to_x += video_xoffset;
1492 to_y += video_yoffset;
1495 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1498 #if ENABLE_UNUSED_CODE
1499 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1500 int num_points, Uint32 color)
1505 for (i = 0; i < num_points - 1; i++)
1507 for (x = 0; x < line_width; x++)
1509 for (y = 0; y < line_width; y++)
1511 int dx = x - line_width / 2;
1512 int dy = y - line_width / 2;
1514 if ((x == 0 && y == 0) ||
1515 (x == 0 && y == line_width - 1) ||
1516 (x == line_width - 1 && y == 0) ||
1517 (x == line_width - 1 && y == line_width - 1))
1520 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1521 points[i+1].x + dx, points[i+1].y + dy, color);
1528 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1530 SDL_Surface *surface = src_bitmap->surface;
1532 if (src_bitmap == backbuffer || src_bitmap == window)
1538 switch (surface->format->BytesPerPixel)
1540 case 1: /* assuming 8-bpp */
1542 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1546 case 2: /* probably 15-bpp or 16-bpp */
1548 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1552 case 3: /* slow 24-bpp mode; usually not used */
1554 /* does this work? */
1555 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1559 shift = surface->format->Rshift;
1560 color |= *(pix + shift / 8) >> shift;
1561 shift = surface->format->Gshift;
1562 color |= *(pix + shift / 8) >> shift;
1563 shift = surface->format->Bshift;
1564 color |= *(pix + shift / 8) >> shift;
1570 case 4: /* probably 32-bpp */
1572 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1581 /* ========================================================================= */
1582 /* The following functions were taken from the SGE library */
1583 /* (SDL Graphics Extension Library) by Anders Lindström */
1584 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1585 /* ========================================================================= */
1587 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1589 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1591 switch (surface->format->BytesPerPixel)
1595 /* Assuming 8-bpp */
1596 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1602 /* Probably 15-bpp or 16-bpp */
1603 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1609 /* Slow 24-bpp mode, usually not used */
1613 /* Gack - slow, but endian correct */
1614 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1615 shift = surface->format->Rshift;
1616 *(pix+shift/8) = color>>shift;
1617 shift = surface->format->Gshift;
1618 *(pix+shift/8) = color>>shift;
1619 shift = surface->format->Bshift;
1620 *(pix+shift/8) = color>>shift;
1626 /* Probably 32-bpp */
1627 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1634 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1635 Uint8 R, Uint8 G, Uint8 B)
1637 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1640 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1642 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1645 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1647 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1650 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1655 /* Gack - slow, but endian correct */
1656 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1657 shift = surface->format->Rshift;
1658 *(pix+shift/8) = color>>shift;
1659 shift = surface->format->Gshift;
1660 *(pix+shift/8) = color>>shift;
1661 shift = surface->format->Bshift;
1662 *(pix+shift/8) = color>>shift;
1665 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1667 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1670 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1672 switch (dest->format->BytesPerPixel)
1675 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1679 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1683 _PutPixel24(dest,x,y,color);
1687 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1692 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1694 if (SDL_MUSTLOCK(surface))
1696 if (SDL_LockSurface(surface) < 0)
1702 _PutPixel(surface, x, y, color);
1704 if (SDL_MUSTLOCK(surface))
1706 SDL_UnlockSurface(surface);
1710 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1711 Uint8 r, Uint8 g, Uint8 b)
1713 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1716 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1718 if (y >= 0 && y <= dest->h - 1)
1720 switch (dest->format->BytesPerPixel)
1723 return y*dest->pitch;
1727 return y*dest->pitch/2;
1731 return y*dest->pitch;
1735 return y*dest->pitch/4;
1743 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1745 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1747 switch (surface->format->BytesPerPixel)
1751 /* Assuming 8-bpp */
1752 *((Uint8 *)surface->pixels + ypitch + x) = color;
1758 /* Probably 15-bpp or 16-bpp */
1759 *((Uint16 *)surface->pixels + ypitch + x) = color;
1765 /* Slow 24-bpp mode, usually not used */
1769 /* Gack - slow, but endian correct */
1770 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1771 shift = surface->format->Rshift;
1772 *(pix+shift/8) = color>>shift;
1773 shift = surface->format->Gshift;
1774 *(pix+shift/8) = color>>shift;
1775 shift = surface->format->Bshift;
1776 *(pix+shift/8) = color>>shift;
1782 /* Probably 32-bpp */
1783 *((Uint32 *)surface->pixels + ypitch + x) = color;
1790 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1795 if (SDL_MUSTLOCK(Surface))
1797 if (SDL_LockSurface(Surface) < 0)
1810 /* Do the clipping */
1811 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1815 if (x2 > Surface->w - 1)
1816 x2 = Surface->w - 1;
1823 SDL_FillRect(Surface, &l, Color);
1825 if (SDL_MUSTLOCK(Surface))
1827 SDL_UnlockSurface(Surface);
1831 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1832 Uint8 R, Uint8 G, Uint8 B)
1834 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1837 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1848 /* Do the clipping */
1849 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1853 if (x2 > Surface->w - 1)
1854 x2 = Surface->w - 1;
1861 SDL_FillRect(Surface, &l, Color);
1864 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1869 if (SDL_MUSTLOCK(Surface))
1871 if (SDL_LockSurface(Surface) < 0)
1884 /* Do the clipping */
1885 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1889 if (y2 > Surface->h - 1)
1890 y2 = Surface->h - 1;
1897 SDL_FillRect(Surface, &l, Color);
1899 if (SDL_MUSTLOCK(Surface))
1901 SDL_UnlockSurface(Surface);
1905 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1906 Uint8 R, Uint8 G, Uint8 B)
1908 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1911 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1922 /* Do the clipping */
1923 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1927 if (y2 > Surface->h - 1)
1928 y2 = Surface->h - 1;
1935 SDL_FillRect(Surface, &l, Color);
1938 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1939 Sint16 x2, Sint16 y2, Uint32 Color,
1940 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1943 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1948 sdx = (dx < 0) ? -1 : 1;
1949 sdy = (dy < 0) ? -1 : 1;
1961 for (x = 0; x < dx; x++)
1963 Callback(Surface, px, py, Color);
1977 for (y = 0; y < dy; y++)
1979 Callback(Surface, px, py, Color);
1993 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1994 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1995 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1998 sge_DoLine(Surface, X1, Y1, X2, Y2,
1999 SDL_MapRGB(Surface->format, R, G, B), Callback);
2002 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
2005 if (SDL_MUSTLOCK(Surface))
2007 if (SDL_LockSurface(Surface) < 0)
2012 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
2014 /* unlock the display */
2015 if (SDL_MUSTLOCK(Surface))
2017 SDL_UnlockSurface(Surface);
2021 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
2022 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
2024 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
2027 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
2029 if (dst_bitmap == backbuffer || dst_bitmap == window)
2035 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
2040 -----------------------------------------------------------------------------
2041 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
2042 -----------------------------------------------------------------------------
2045 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
2046 int width, int height, Uint32 color)
2050 for (y = src_y; y < src_y + height; y++)
2052 for (x = src_x; x < src_x + width; x++)
2054 Uint32 pixel = SDLGetPixel(bitmap, x, y);
2056 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
2061 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
2062 int src_x, int src_y, int width, int height,
2063 int dst_x, int dst_y)
2067 for (y = 0; y < height; y++)
2069 for (x = 0; x < width; x++)
2071 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
2073 if (pixel != BLACK_PIXEL)
2074 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
2080 /* ========================================================================= */
2081 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
2082 /* (Rotozoomer) by Andreas Schiffler */
2083 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
2084 /* ========================================================================= */
2087 -----------------------------------------------------------------------------
2090 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
2091 -----------------------------------------------------------------------------
2102 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
2105 tColorRGBA *sp, *csp, *dp;
2109 sp = csp = (tColorRGBA *) src->pixels;
2110 dp = (tColorRGBA *) dst->pixels;
2111 dgap = dst->pitch - dst->w * 4;
2113 for (y = 0; y < dst->h; y++)
2117 for (x = 0; x < dst->w; x++)
2119 tColorRGBA *sp0 = sp;
2120 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2121 tColorRGBA *sp00 = &sp0[0];
2122 tColorRGBA *sp01 = &sp0[1];
2123 tColorRGBA *sp10 = &sp1[0];
2124 tColorRGBA *sp11 = &sp1[1];
2127 /* create new color pixel from all four source color pixels */
2128 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2129 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2130 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2131 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2136 /* advance source pointers */
2139 /* advance destination pointer */
2143 /* advance source pointer */
2144 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2146 /* advance destination pointers */
2147 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2153 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2155 int x, y, *sax, *say, *csax, *csay;
2157 tColorRGBA *sp, *csp, *csp0, *dp;
2160 /* use specialized zoom function when scaling down to exactly half size */
2161 if (src->w == 2 * dst->w &&
2162 src->h == 2 * dst->h)
2163 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2165 /* variable setup */
2166 sx = (float) src->w / (float) dst->w;
2167 sy = (float) src->h / (float) dst->h;
2169 /* allocate memory for row increments */
2170 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2171 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2173 /* precalculate row increments */
2174 for (x = 0; x <= dst->w; x++)
2175 *csax++ = (int)(sx * x);
2177 for (y = 0; y <= dst->h; y++)
2178 *csay++ = (int)(sy * y);
2181 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2182 dp = (tColorRGBA *) dst->pixels;
2183 dgap = dst->pitch - dst->w * 4;
2186 for (y = 0; y < dst->h; y++)
2191 for (x = 0; x < dst->w; x++)
2196 /* advance source pointers */
2200 /* advance destination pointer */
2204 /* advance source pointer */
2206 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2208 /* advance destination pointers */
2209 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2219 -----------------------------------------------------------------------------
2222 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2223 -----------------------------------------------------------------------------
2226 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2228 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2229 Uint8 *sp, *dp, *csp;
2232 /* variable setup */
2233 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2234 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2236 /* allocate memory for row increments */
2237 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2238 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2240 /* precalculate row increments */
2243 for (x = 0; x < dst->w; x++)
2246 *csax = (csx >> 16);
2253 for (y = 0; y < dst->h; y++)
2256 *csay = (csy >> 16);
2263 for (x = 0; x < dst->w; x++)
2271 for (y = 0; y < dst->h; y++)
2278 sp = csp = (Uint8 *) src->pixels;
2279 dp = (Uint8 *) dst->pixels;
2280 dgap = dst->pitch - dst->w;
2284 for (y = 0; y < dst->h; y++)
2288 for (x = 0; x < dst->w; x++)
2293 /* advance source pointers */
2297 /* advance destination pointer */
2301 /* advance source pointer (for row) */
2302 csp += ((*csay) * src->pitch);
2305 /* advance destination pointers */
2316 -----------------------------------------------------------------------------
2319 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2320 'zoomx' and 'zoomy' are scaling factors for width and height.
2321 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2322 into a 32bit RGBA format on the fly.
2323 -----------------------------------------------------------------------------
2326 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2328 SDL_Surface *zoom_src = NULL;
2329 SDL_Surface *zoom_dst = NULL;
2330 boolean is_converted = FALSE;
2337 /* determine if source surface is 32 bit or 8 bit */
2338 is_32bit = (src->format->BitsPerPixel == 32);
2340 if (is_32bit || src->format->BitsPerPixel == 8)
2342 /* use source surface 'as is' */
2347 /* new source surface is 32 bit with a defined RGB ordering */
2348 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2349 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2350 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2352 is_converted = TRUE;
2355 /* allocate surface to completely contain the zoomed surface */
2358 /* target surface is 32 bit with source RGBA/ABGR ordering */
2359 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2360 zoom_src->format->Rmask,
2361 zoom_src->format->Gmask,
2362 zoom_src->format->Bmask, 0);
2366 /* target surface is 8 bit */
2367 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2371 /* lock source surface */
2372 SDL_LockSurface(zoom_src);
2374 /* check which kind of surface we have */
2377 /* call the 32 bit transformation routine to do the zooming */
2378 zoomSurfaceRGBA(zoom_src, zoom_dst);
2383 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2384 zoom_dst->format->palette->colors[i] =
2385 zoom_src->format->palette->colors[i];
2386 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2388 /* call the 8 bit transformation routine to do the zooming */
2389 zoomSurfaceY(zoom_src, zoom_dst);
2392 /* unlock source surface */
2393 SDL_UnlockSurface(zoom_src);
2395 /* free temporary surface */
2397 SDL_FreeSurface(zoom_src);
2399 /* return destination surface */
2403 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2405 Bitmap *dst_bitmap = CreateBitmapStruct();
2406 SDL_Surface **dst_surface = &dst_bitmap->surface;
2408 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2409 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2411 dst_bitmap->width = dst_width;
2412 dst_bitmap->height = dst_height;
2414 /* create zoomed temporary surface from source surface */
2415 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2417 /* create native format destination surface from zoomed temporary surface */
2418 SDLSetNativeSurface(dst_surface);
2424 /* ========================================================================= */
2425 /* load image to bitmap */
2426 /* ========================================================================= */
2428 Bitmap *SDLLoadImage(char *filename)
2430 Bitmap *new_bitmap = CreateBitmapStruct();
2431 SDL_Surface *sdl_image_tmp;
2433 print_timestamp_init("SDLLoadImage");
2435 print_timestamp_time(getBaseNamePtr(filename));
2437 /* load image to temporary surface */
2438 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2440 SetError("IMG_Load(): %s", SDL_GetError());
2445 print_timestamp_time("IMG_Load");
2447 UPDATE_BUSY_STATE();
2449 /* create native non-transparent surface for current image */
2450 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2452 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2457 print_timestamp_time("SDL_DisplayFormat (opaque)");
2459 UPDATE_BUSY_STATE();
2461 /* create native transparent surface for current image */
2462 if (sdl_image_tmp->format->Amask == 0)
2463 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2464 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2466 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2468 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2473 print_timestamp_time("SDL_DisplayFormat (masked)");
2475 UPDATE_BUSY_STATE();
2477 /* free temporary surface */
2478 SDL_FreeSurface(sdl_image_tmp);
2480 new_bitmap->width = new_bitmap->surface->w;
2481 new_bitmap->height = new_bitmap->surface->h;
2483 print_timestamp_done("SDLLoadImage");
2489 /* ------------------------------------------------------------------------- */
2490 /* custom cursor fuctions */
2491 /* ------------------------------------------------------------------------- */
2493 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2495 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2496 cursor_info->width, cursor_info->height,
2497 cursor_info->hot_x, cursor_info->hot_y);
2500 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2502 static struct MouseCursorInfo *last_cursor_info = NULL;
2503 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2504 static SDL_Cursor *cursor_default = NULL;
2505 static SDL_Cursor *cursor_current = NULL;
2507 /* if invoked for the first time, store the SDL default cursor */
2508 if (cursor_default == NULL)
2509 cursor_default = SDL_GetCursor();
2511 /* only create new cursor if cursor info (custom only) has changed */
2512 if (cursor_info != NULL && cursor_info != last_cursor_info)
2514 cursor_current = create_cursor(cursor_info);
2515 last_cursor_info = cursor_info;
2518 /* only set new cursor if cursor info (custom or NULL) has changed */
2519 if (cursor_info != last_cursor_info2)
2520 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2522 last_cursor_info2 = cursor_info;
2526 /* ========================================================================= */
2527 /* audio functions */
2528 /* ========================================================================= */
2530 void SDLOpenAudio(void)
2532 #if !defined(TARGET_SDL2)
2533 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2534 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2537 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2539 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2543 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2544 AUDIO_NUM_CHANNELS_STEREO,
2545 setup.system.audio_fragment_size) < 0)
2547 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2551 audio.sound_available = TRUE;
2552 audio.music_available = TRUE;
2553 audio.loops_available = TRUE;
2554 audio.sound_enabled = TRUE;
2556 /* set number of available mixer channels */
2557 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2558 audio.music_channel = MUSIC_CHANNEL;
2559 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2561 Mixer_InitChannels();
2564 void SDLCloseAudio(void)
2567 Mix_HaltChannel(-1);
2570 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2574 /* ========================================================================= */
2575 /* event functions */
2576 /* ========================================================================= */
2578 void SDLNextEvent(Event *event)
2580 SDL_WaitEvent(event);
2582 if (event->type == EVENT_BUTTONPRESS ||
2583 event->type == EVENT_BUTTONRELEASE)
2585 if (((ButtonEvent *)event)->x > video_xoffset)
2586 ((ButtonEvent *)event)->x -= video_xoffset;
2588 ((ButtonEvent *)event)->x = 0;
2589 if (((ButtonEvent *)event)->y > video_yoffset)
2590 ((ButtonEvent *)event)->y -= video_yoffset;
2592 ((ButtonEvent *)event)->y = 0;
2594 else if (event->type == EVENT_MOTIONNOTIFY)
2596 if (((MotionEvent *)event)->x > video_xoffset)
2597 ((MotionEvent *)event)->x -= video_xoffset;
2599 ((MotionEvent *)event)->x = 0;
2600 if (((MotionEvent *)event)->y > video_yoffset)
2601 ((MotionEvent *)event)->y -= video_yoffset;
2603 ((MotionEvent *)event)->y = 0;
2607 void SDLHandleWindowManagerEvent(Event *event)
2610 #if defined(PLATFORM_WIN32)
2611 // experimental drag and drop code
2613 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2614 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2616 #if defined(TARGET_SDL2)
2617 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2619 if (syswmmsg->msg == WM_DROPFILES)
2622 #if defined(TARGET_SDL2)
2623 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2625 HDROP hdrop = (HDROP)syswmmsg->wParam;
2629 printf("::: SDL_SYSWMEVENT:\n");
2631 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2633 for (i = 0; i < num_files; i++)
2635 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2636 char buffer[buffer_len + 1];
2638 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2640 printf("::: - '%s'\n", buffer);
2643 #if defined(TARGET_SDL2)
2644 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2646 DragFinish((HDROP)syswmmsg->wParam);
2654 /* ========================================================================= */
2655 /* joystick functions */
2656 /* ========================================================================= */
2658 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2659 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2660 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2662 static boolean SDLOpenJoystick(int nr)
2664 if (nr < 0 || nr > MAX_PLAYERS)
2667 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2670 static void SDLCloseJoystick(int nr)
2672 if (nr < 0 || nr > MAX_PLAYERS)
2675 SDL_JoystickClose(sdl_joystick[nr]);
2677 sdl_joystick[nr] = NULL;
2680 static boolean SDLCheckJoystickOpened(int nr)
2682 if (nr < 0 || nr > MAX_PLAYERS)
2685 #if defined(TARGET_SDL2)
2686 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2688 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2692 void HandleJoystickEvent(Event *event)
2696 case SDL_JOYAXISMOTION:
2697 if (event->jaxis.axis < 2)
2698 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2701 case SDL_JOYBUTTONDOWN:
2702 if (event->jbutton.button < 2)
2703 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2706 case SDL_JOYBUTTONUP:
2707 if (event->jbutton.button < 2)
2708 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2716 void SDLInitJoysticks()
2718 static boolean sdl_joystick_subsystem_initialized = FALSE;
2719 boolean print_warning = !sdl_joystick_subsystem_initialized;
2722 if (!sdl_joystick_subsystem_initialized)
2724 sdl_joystick_subsystem_initialized = TRUE;
2726 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2728 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2733 for (i = 0; i < MAX_PLAYERS; i++)
2735 /* get configured joystick for this player */
2736 char *device_name = setup.input[i].joy.device_name;
2737 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2739 if (joystick_nr >= SDL_NumJoysticks())
2741 if (setup.input[i].use_joystick && print_warning)
2742 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2747 /* misuse joystick file descriptor variable to store joystick number */
2748 joystick.fd[i] = joystick_nr;
2750 if (joystick_nr == -1)
2753 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2754 if (SDLCheckJoystickOpened(joystick_nr))
2755 SDLCloseJoystick(joystick_nr);
2757 if (!setup.input[i].use_joystick)
2760 if (!SDLOpenJoystick(joystick_nr))
2763 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2768 joystick.status = JOYSTICK_ACTIVATED;
2772 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2774 if (nr < 0 || nr >= MAX_PLAYERS)
2778 *x = sdl_js_axis[nr][0];
2780 *y = sdl_js_axis[nr][1];
2783 *b1 = sdl_js_button[nr][0];
2785 *b2 = sdl_js_button[nr][1];