-/***********************************************************
-* Artsoft Retro-Game Library *
-*----------------------------------------------------------*
-* (c) 1994-2002 Artsoft Entertainment *
-* Holger Schemel *
-* Detmolder Strasse 189 *
-* 33604 Bielefeld *
-* Germany *
-* e-mail: info@artsoft.org *
-*----------------------------------------------------------*
-* sdl.c *
-***********************************************************/
+// ============================================================================
+// Artsoft Retro-Game Library
+// ----------------------------------------------------------------------------
+// (c) 1995-2014 by Artsoft Entertainment
+// Holger Schemel
+// info@artsoft.org
+// http://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// sdl.c
+// ============================================================================
#include "system.h"
#include "sound.h"
#include "joystick.h"
#include "misc.h"
+#include "setup.h"
+#define ENABLE_UNUSED_CODE 0 /* currently unused functions */
-#if defined(TARGET_SDL)
/* ========================================================================= */
/* video functions */
/* ========================================================================= */
-/* functions from SGE library */
-inline void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
+/* SDL internal variables */
+#if defined(TARGET_SDL2)
+static SDL_Window *sdl_window = NULL;
+static SDL_Renderer *sdl_renderer = NULL;
+static SDL_Texture *sdl_texture = NULL;
-/* #ifdef PLATFORM_WIN32 */
-#define FULLSCREEN_BUG
-/* #endif */
+#define USE_RENDERER TRUE
+#endif
/* stuff needed to work around SDL/Windows fullscreen drawing bug */
static int fullscreen_width;
static int fullscreen_yoffset;
static int video_xoffset;
static int video_yoffset;
+static boolean limit_screen_updates = FALSE;
+
+
+/* functions from SGE library */
+void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
+
+void SDLLimitScreenUpdates(boolean enable)
+{
+ limit_screen_updates = enable;
+}
+
+static void UpdateScreen(SDL_Rect *rect)
+{
+ static unsigned int update_screen_delay = 0;
+ unsigned int update_screen_delay_value = 20; /* (milliseconds) */
+
+ if (limit_screen_updates &&
+ !DelayReached(&update_screen_delay, update_screen_delay_value))
+ return;
+
+ LimitScreenUpdates(FALSE);
+
+#if defined(TARGET_SDL2)
+#if USE_RENDERER
+ SDL_Surface *screen = backbuffer->surface;
+
+ if (rect)
+ {
+ int bytes_x = screen->pitch / video.width;
+ int bytes_y = screen->pitch;
+
+ if (video.fullscreen_enabled)
+ bytes_x = screen->pitch / fullscreen_width;
+
+ SDL_UpdateTexture(sdl_texture, rect,
+ screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
+ screen->pitch);
+ }
+ else
+ {
+ SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
+ }
+ SDL_RenderClear(sdl_renderer);
+ SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
+ SDL_RenderPresent(sdl_renderer);
+#else
+ if (rect)
+ SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
+ else
+ SDL_UpdateWindowSurface(sdl_window);
+#endif
+
+#else // TARGET_SDL
+ if (rect)
+ SDL_UpdateRects(backbuffer->surface, 1, rect);
+ else
+ SDL_UpdateRect(backbuffer->surface, 0, 0, 0, 0);
+#endif
+}
+
+static void setFullscreenParameters(char *fullscreen_mode_string)
+{
+#if defined(TARGET_SDL2)
+ fullscreen_width = video.width;
+ fullscreen_height = video.height;
+ fullscreen_xoffset = 0;
+ fullscreen_yoffset = 0;
+
+#else
+
+ struct ScreenModeInfo *fullscreen_mode;
+ int i;
+
+ fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
+
+ if (fullscreen_mode == NULL)
+ return;
+
+ for (i = 0; video.fullscreen_modes[i].width != -1; i++)
+ {
+ if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
+ fullscreen_mode->height == video.fullscreen_modes[i].height)
+ {
+ fullscreen_width = fullscreen_mode->width;
+ fullscreen_height = fullscreen_mode->height;
+
+ fullscreen_xoffset = (fullscreen_width - video.width) / 2;
+ fullscreen_yoffset = (fullscreen_height - video.height) / 2;
-inline void SDLInitVideoDisplay(void)
+ break;
+ }
+ }
+#endif
+}
+
+static void SDLSetWindowIcon(char *basename)
{
- putenv("SDL_VIDEO_CENTERED=1");
+ /* (setting the window icon on Mac OS X would replace the high-quality
+ dock icon with the currently smaller (and uglier) icon from file) */
+
+#if !defined(PLATFORM_MACOSX)
+ char *filename = getCustomImageFilename(basename);
+ SDL_Surface *surface;
+
+ if (filename == NULL)
+ {
+ Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
+
+ return;
+ }
+
+ if ((surface = IMG_Load(filename)) == NULL)
+ {
+ Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
+
+ return;
+ }
+
+ /* set transparent color */
+ SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
+ SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
+
+#if defined(TARGET_SDL2)
+ SDL_SetWindowIcon(sdl_window, surface);
+#else
+ SDL_WM_SetIcon(surface, NULL);
+#endif
+#endif
+}
+
+#if defined(TARGET_SDL2)
+
+static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
+ SDL_PixelFormat *format2)
+{
+ return (format1->format == format2->format &&
+ format1->BitsPerPixel == format2->BitsPerPixel &&
+ format1->BytesPerPixel == format2->BytesPerPixel &&
+ format1->Rmask == format2->Rmask &&
+ format1->Gmask == format2->Gmask &&
+ format1->Bmask == format2->Bmask &&
+ format1->Amask == format2->Amask);
+}
+
+boolean SDLSetNativeSurface(SDL_Surface **surface)
+{
+ SDL_Surface *new_surface;
+
+ if (surface == NULL ||
+ *surface == NULL ||
+ backbuffer == NULL ||
+ backbuffer->surface == NULL)
+ return FALSE;
+
+ // if pixel format already optimized for destination surface, do nothing
+ if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
+ return FALSE;
+
+ new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
+
+ if (new_surface == NULL)
+ Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
+
+ SDL_FreeSurface(*surface);
+
+ *surface = new_surface;
+
+ return TRUE;
+}
+
+SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
+{
+ SDL_Surface *new_surface;
+
+ if (surface == NULL)
+ return NULL;
+
+ if (backbuffer && backbuffer->surface)
+ new_surface = SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
+ else
+ new_surface = SDL_ConvertSurface(surface, surface->format, 0);
+
+ if (new_surface == NULL)
+ Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
+
+ return new_surface;
+}
+
+#else
+
+boolean SDLSetNativeSurface(SDL_Surface **surface)
+{
+ SDL_Surface *new_surface;
+
+ if (surface == NULL ||
+ *surface == NULL ||
+ !video.initialized)
+ return FALSE;
+
+ new_surface = SDL_DisplayFormat(*surface);
+
+ if (new_surface == NULL)
+ Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
+
+ SDL_FreeSurface(*surface);
+
+ *surface = new_surface;
+
+ return TRUE;
+}
+
+SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
+{
+ SDL_Surface *new_surface;
+
+ if (video.initialized)
+ new_surface = SDL_DisplayFormat(surface);
+ else
+ new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
+
+ if (new_surface == NULL)
+ Error(ERR_EXIT, "%s() failed: %s",
+ (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
+ SDL_GetError());
+
+ return new_surface;
+}
+
+#endif
+
+void SDLInitVideoDisplay(void)
+{
+#if !defined(TARGET_SDL2)
+ if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
+ SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
+
+ SDL_putenv("SDL_VIDEO_CENTERED=1");
+#endif
/* initialize SDL video */
if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
/* set default SDL depth */
+#if !defined(TARGET_SDL2)
video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
+#else
+ video.default_depth = 32; // (how to determine video depth in SDL2?)
+#endif
}
-inline void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
- boolean fullscreen)
+void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
+ boolean fullscreen)
{
-#ifdef FULLSCREEN_BUG
- int i;
+#if !defined(TARGET_SDL2)
static int screen_xy[][2] =
{
{ 640, 480 },
{ -1, -1 }
};
#endif
+ SDL_Rect **modes = NULL;
+ boolean hardware_fullscreen_available = TRUE;
+ int i, j;
/* default: normal game window size */
fullscreen_width = video.width;
fullscreen_xoffset = 0;
fullscreen_yoffset = 0;
-#ifdef FULLSCREEN_BUG
- for (i=0; screen_xy[i][0] != -1; i++)
+#if !defined(TARGET_SDL2)
+ /* determine required standard fullscreen mode for game screen size */
+ for (i = 0; screen_xy[i][0] != -1; i++)
{
- if (video.width <= screen_xy[i][0] && video.height <= screen_xy[i][1])
+ if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
{
- fullscreen_width = screen_xy[i][0];
+ fullscreen_width = screen_xy[i][0];
fullscreen_height = screen_xy[i][1];
+
break;
}
}
- fullscreen_xoffset = (fullscreen_width - video.width) / 2;
+ fullscreen_xoffset = (fullscreen_width - video.width) / 2;
fullscreen_yoffset = (fullscreen_height - video.height) / 2;
#endif
+ checked_free(video.fullscreen_modes);
+
+ video.fullscreen_modes = NULL;
+ video.fullscreen_mode_current = NULL;
+
+ video.window_scaling_percent = setup.window_scaling_percent;
+ video.window_scaling_quality = setup.window_scaling_quality;
+
+#if defined(TARGET_SDL2)
+ int num_displays = SDL_GetNumVideoDisplays();
+
+ if (num_displays > 0)
+ {
+ // currently only display modes of first display supported
+ int num_modes = SDL_GetNumDisplayModes(0);
+
+ if (num_modes > 0)
+ {
+ modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
+
+ for (i = 0; i < num_modes; i++)
+ {
+ SDL_DisplayMode mode;
+
+ if (SDL_GetDisplayMode(0, i, &mode) < 0)
+ break;
+
+ modes[i] = checked_calloc(sizeof(SDL_Rect));
+
+ modes[i]->w = mode.w;
+ modes[i]->h = mode.h;
+ }
+ }
+ }
+#else
+ /* get available hardware supported fullscreen modes */
+ modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
+#endif
+
+ if (modes == NULL)
+ {
+ /* no hardware screen modes available => no fullscreen mode support */
+ // video.fullscreen_available = FALSE;
+ hardware_fullscreen_available = FALSE;
+ }
+ else if (modes == (SDL_Rect **)-1)
+ {
+ /* fullscreen resolution is not restricted -- all resolutions available */
+ video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
+
+ /* use native video buffer size for fullscreen mode */
+ video.fullscreen_modes[0].width = video.width;
+ video.fullscreen_modes[0].height = video.height;
+
+ video.fullscreen_modes[1].width = -1;
+ video.fullscreen_modes[1].height = -1;
+ }
+ else
+ {
+ /* in this case, a certain number of screen modes is available */
+ int num_modes = 0;
+
+ for (i = 0; modes[i] != NULL; i++)
+ {
+ boolean found_mode = FALSE;
+
+ /* screen mode is smaller than video buffer size -- skip it */
+ if (modes[i]->w < video.width || modes[i]->h < video.height)
+ continue;
+
+ if (video.fullscreen_modes != NULL)
+ for (j = 0; video.fullscreen_modes[j].width != -1; j++)
+ if (modes[i]->w == video.fullscreen_modes[j].width &&
+ modes[i]->h == video.fullscreen_modes[j].height)
+ found_mode = TRUE;
+
+ if (found_mode) /* screen mode already stored -- skip it */
+ continue;
+
+ /* new mode found; add it to list of available fullscreen modes */
+
+ num_modes++;
+
+ video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
+ (num_modes + 1) *
+ sizeof(struct ScreenModeInfo));
+
+ video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
+ video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
+
+ video.fullscreen_modes[num_modes].width = -1;
+ video.fullscreen_modes[num_modes].height = -1;
+ }
+
+ if (num_modes == 0)
+ {
+ /* no appropriate screen modes available => no fullscreen mode support */
+ // video.fullscreen_available = FALSE;
+ hardware_fullscreen_available = FALSE;
+ }
+ }
+
+ video.fullscreen_available = hardware_fullscreen_available;
+
+#if USE_DESKTOP_FULLSCREEN
+ // in SDL 2.0, there is always support for desktop fullscreen mode
+ // (in SDL 1.2, there is only support for "real" fullscreen mode)
+ video.fullscreen_available = TRUE;
+#endif
+
+#if defined(TARGET_SDL2)
+ if (modes)
+ {
+ for (i = 0; modes[i] != NULL; i++)
+ checked_free(modes[i]);
+
+ checked_free(modes);
+ }
+#endif
+
/* open SDL video output device (window or fullscreen mode) */
if (!SDLSetVideoMode(backbuffer, fullscreen))
Error(ERR_EXIT, "setting video mode failed");
+ /* !!! SDL2 can only set the window icon if the window already exists !!! */
+ /* set window icon */
+ SDLSetWindowIcon(program.icon_filename);
+
/* set window and icon title */
+#if defined(TARGET_SDL2)
+ SDL_SetWindowTitle(sdl_window, program.window_title);
+#else
SDL_WM_SetCaption(program.window_title, program.window_title);
+#endif
/* SDL cannot directly draw to the visible video framebuffer like X11,
but always uses a backbuffer, which is then blitted to the visible
buffer 'window' at the same size as the SDL backbuffer. Although it
should never be drawn to directly, it would do no harm nevertheless. */
- /* create additional (symbolic) buffer for double-buffering */
- *window = CreateBitmap(video.width, video.height, video.depth);
+ /* create additional (symbolic) buffer for double-buffering */
+ ReCreateBitmap(window, video.width, video.height, video.depth);
+}
+
+static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
+ boolean fullscreen)
+{
+ SDL_Surface *new_surface = NULL;
+
+#if defined(TARGET_SDL2)
+ static boolean fullscreen_enabled = FALSE;
+ int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
+#if USE_DESKTOP_FULLSCREEN
+ int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
+#else
+ int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
+#endif
+
+#else
+ int surface_flags_window = SURFACE_FLAGS;
+ int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
+#endif
+
+ int width = (fullscreen ? fullscreen_width : video.width);
+ int height = (fullscreen ? fullscreen_height : video.height);
+ int surface_flags = (fullscreen ? surface_flags_fullscreen :
+ surface_flags_window);
+
+ // default window size is unscaled
+ video.window_width = video.width;
+ video.window_height = video.height;
+
+#if defined(TARGET_SDL2)
+
+ // store if initial screen mode on game start is fullscreen mode
+ if (sdl_window == NULL)
+ video.fullscreen_initial = fullscreen;
+
+#if USE_RENDERER
+ float window_scaling_factor = (float)setup.window_scaling_percent / 100;
+#if !USE_DESKTOP_FULLSCREEN
+ float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
+#endif
+
+ video.window_width = window_scaling_factor * width;
+ video.window_height = window_scaling_factor * height;
+
+ if ((*backbuffer)->surface)
+ {
+ SDL_FreeSurface((*backbuffer)->surface);
+ (*backbuffer)->surface = NULL;
+ }
+
+ if (sdl_texture)
+ {
+ SDL_DestroyTexture(sdl_texture);
+ sdl_texture = NULL;
+ }
+
+ if (!(fullscreen && fullscreen_enabled))
+ {
+ if (sdl_renderer)
+ {
+ SDL_DestroyRenderer(sdl_renderer);
+ sdl_renderer = NULL;
+ }
+
+ if (sdl_window)
+ {
+ SDL_DestroyWindow(sdl_window);
+ sdl_window = NULL;
+ }
+ }
+
+ if (sdl_window == NULL)
+ sdl_window = SDL_CreateWindow(program.window_title,
+ SDL_WINDOWPOS_CENTERED,
+ SDL_WINDOWPOS_CENTERED,
+#if USE_DESKTOP_FULLSCREEN
+ video.window_width,
+ video.window_height,
+#else
+ (int)(screen_scaling_factor * width),
+ (int)(screen_scaling_factor * height),
+#endif
+ surface_flags);
+
+ if (sdl_window != NULL)
+ {
+#if 0
+ /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
+ *without* enabling 2D/3D acceleration and/or guest additions installed,
+ it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
+ it will try to use accelerated graphics and apparently fails miserably) */
+ if (sdl_renderer == NULL)
+ sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
+#else
+ if (sdl_renderer == NULL)
+ sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
+#endif
+
+ if (sdl_renderer != NULL)
+ {
+ SDL_RenderSetLogicalSize(sdl_renderer, width, height);
+ // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
+
+ sdl_texture = SDL_CreateTexture(sdl_renderer,
+ SDL_PIXELFORMAT_ARGB8888,
+ SDL_TEXTUREACCESS_STREAMING,
+ width, height);
+
+ if (sdl_texture != NULL)
+ {
+ // use SDL default values for RGB masks and no alpha channel
+ new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
+
+ if (new_surface == NULL)
+ Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
+ SDL_GetError());
+ }
+ else
+ {
+ Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
+ }
+ }
+ else
+ {
+ Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
+ }
+ }
+ else
+ {
+ Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
+ }
+
+#else
+
+ if (sdl_window)
+ SDL_DestroyWindow(sdl_window);
+
+ sdl_window = SDL_CreateWindow(program.window_title,
+ SDL_WINDOWPOS_CENTERED,
+ SDL_WINDOWPOS_CENTERED,
+ width, height,
+ surface_flags);
+
+ if (sdl_window != NULL)
+ new_surface = SDL_GetWindowSurface(sdl_window);
+#endif
+
+#else
+ new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
+#endif
+
+#if defined(TARGET_SDL2)
+ // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
+ if (new_surface != NULL)
+ fullscreen_enabled = fullscreen;
+#endif
+
+ return new_surface;
+}
+
+boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
+{
+ boolean success = TRUE;
+ SDL_Surface *new_surface = NULL;
+
+ SetWindowTitle();
+
+ if (*backbuffer == NULL)
+ *backbuffer = CreateBitmapStruct();
+
+ /* (real bitmap might be larger in fullscreen mode with video offsets) */
+ (*backbuffer)->width = video.width;
+ (*backbuffer)->height = video.height;
+
+ if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
+ {
+ setFullscreenParameters(setup.fullscreen_mode);
+
+ video_xoffset = fullscreen_xoffset;
+ video_yoffset = fullscreen_yoffset;
+
+ /* switch display to fullscreen mode, if available */
+ new_surface = SDLCreateScreen(backbuffer, TRUE);
+
+ if (new_surface == NULL)
+ {
+ /* switching display to fullscreen mode failed */
+ Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
+
+ /* do not try it again */
+ video.fullscreen_available = FALSE;
+
+ success = FALSE;
+ }
+ else
+ {
+ (*backbuffer)->surface = new_surface;
+
+ video.fullscreen_enabled = TRUE;
+ video.fullscreen_mode_current = setup.fullscreen_mode;
+
+ success = TRUE;
+ }
+ }
+
+ if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
+ {
+ video_xoffset = 0;
+ video_yoffset = 0;
+
+ /* switch display to window mode */
+ new_surface = SDLCreateScreen(backbuffer, FALSE);
+
+ if (new_surface == NULL)
+ {
+ /* switching display to window mode failed -- should not happen */
+ Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
+
+ success = FALSE;
+ }
+ else
+ {
+ (*backbuffer)->surface = new_surface;
+
+ video.fullscreen_enabled = FALSE;
+ video.window_scaling_percent = setup.window_scaling_percent;
+ video.window_scaling_quality = setup.window_scaling_quality;
+
+ success = TRUE;
+ }
+ }
+
+#if defined(TARGET_SDL2)
+ SDLRedrawWindow(); // map window
+#endif
+
+#ifdef DEBUG
+#if defined(PLATFORM_WIN32)
+ // experimental drag and drop code
+
+ SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
+
+ {
+ SDL_SysWMinfo wminfo;
+ HWND hwnd;
+ boolean wminfo_success = FALSE;
+
+ SDL_VERSION(&wminfo.version);
+#if defined(TARGET_SDL2)
+ if (sdl_window)
+ wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
+#else
+ wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
+#endif
+
+ if (wminfo_success)
+ {
+#if defined(TARGET_SDL2)
+ hwnd = wminfo.info.win.window;
+#else
+ hwnd = wminfo.window;
+#endif
+
+ DragAcceptFiles(hwnd, TRUE);
+ }
+ }
+#endif
+#endif
+
+ return success;
+}
+
+void SDLSetWindowTitle()
+{
+#if defined(TARGET_SDL2)
+ SDL_SetWindowTitle(sdl_window, program.window_title);
+#else
+ SDL_WM_SetCaption(program.window_title, program.window_title);
+#endif
+}
+
+#if defined(TARGET_SDL2)
+void SDLSetWindowScaling(int window_scaling_percent)
+{
+ if (sdl_window == NULL)
+ return;
+
+ float window_scaling_factor = (float)window_scaling_percent / 100;
+ int new_window_width = (int)(window_scaling_factor * video.width);
+ int new_window_height = (int)(window_scaling_factor * video.height);
+
+ SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
+
+ video.window_scaling_percent = window_scaling_percent;
+ video.window_width = new_window_width;
+ video.window_height = new_window_height;
+
+ SetWindowTitle();
}
-inline boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
+void SDLSetWindowScalingQuality(char *window_scaling_quality)
{
- boolean success = TRUE;
- int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
- int surface_flags_window = SURFACE_FLAGS;
- SDL_Surface *new_surface = NULL;
+ if (sdl_texture == NULL)
+ return;
- if (*backbuffer == NULL)
- *backbuffer = CreateBitmapStruct();
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
- if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
- {
- video_xoffset = fullscreen_xoffset;
- video_yoffset = fullscreen_yoffset;
+ SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
+ SDL_PIXELFORMAT_ARGB8888,
+ SDL_TEXTUREACCESS_STREAMING,
+ video.width, video.height);
- /* switch display to fullscreen mode, if available */
- if ((new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
- video.depth, surface_flags_fullscreen))
- == NULL)
- {
- /* switching display to fullscreen mode failed */
- Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
+ if (new_texture != NULL)
+ {
+ SDL_DestroyTexture(sdl_texture);
- /* do not try it again */
- video.fullscreen_available = FALSE;
- success = FALSE;
- }
- else
- {
- (*backbuffer)->surface = new_surface;
+ sdl_texture = new_texture;
- video.fullscreen_enabled = TRUE;
- success = TRUE;
- }
+ SDLRedrawWindow();
}
- if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
- {
- video_xoffset = 0;
- video_yoffset = 0;
+ video.window_scaling_quality = window_scaling_quality;
+}
- /* switch display to window mode */
- if ((new_surface = SDL_SetVideoMode(video.width, video.height,
- video.depth, surface_flags_window))
- == NULL)
- {
- /* switching display to window mode failed -- should not happen */
- Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
+void SDLSetWindowFullscreen(boolean fullscreen)
+{
+ if (sdl_window == NULL)
+ return;
- success = FALSE;
- }
- else
- {
- (*backbuffer)->surface = new_surface;
+#if USE_DESKTOP_FULLSCREEN
+ int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
+#else
+ int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
+#endif
- video.fullscreen_enabled = FALSE;
- success = TRUE;
- }
+ if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
+ video.fullscreen_enabled = fullscreen;
+
+ // if game started in fullscreen mode, window will also get fullscreen size
+ if (!fullscreen && video.fullscreen_initial)
+ {
+ SDLSetWindowScaling(setup.window_scaling_percent);
+ SDL_SetWindowPosition(sdl_window,
+ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
+
+ video.fullscreen_initial = FALSE;
}
+}
- return success;
+void SDLRedrawWindow()
+{
+ UpdateScreen(NULL);
}
+#endif
-inline void SDLCreateBitmapContent(Bitmap *new_bitmap,
- int width, int height, int depth)
+void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
+ int depth)
{
- SDL_Surface *surface_tmp, *surface_native;
+ SDL_Surface *surface =
+ SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
- if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
- 0, 0, 0, 0))
- == NULL)
+ if (surface == NULL)
Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
- if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
- Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
-
- SDL_FreeSurface(surface_tmp);
+ SDLSetNativeSurface(&surface);
- new_bitmap->surface = surface_native;
+ bitmap->surface = surface;
}
-inline void SDLFreeBitmapPointers(Bitmap *bitmap)
+void SDLFreeBitmapPointers(Bitmap *bitmap)
{
if (bitmap->surface)
SDL_FreeSurface(bitmap->surface);
bitmap->surface_masked = NULL;
}
-inline void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
- int src_x, int src_y,
- int width, int height,
- int dst_x, int dst_y, int mask_mode)
+void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
+ int src_x, int src_y, int width, int height,
+ int dst_x, int dst_y, int mask_mode)
{
Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
SDL_Rect src_rect, dst_rect;
-#ifdef FULLSCREEN_BUG
if (src_bitmap == backbuffer)
{
src_x += video_xoffset;
src_y += video_yoffset;
}
-#endif
src_rect.x = src_x;
src_rect.y = src_y;
src_rect.w = width;
src_rect.h = height;
-#ifdef FULLSCREEN_BUG
if (dst_bitmap == backbuffer || dst_bitmap == window)
{
dst_x += video_xoffset;
dst_y += video_yoffset;
}
-#endif
dst_rect.x = dst_x;
dst_rect.y = dst_y;
dst_rect.w = width;
dst_rect.h = height;
- if (src_bitmap != backbuffer || dst_bitmap != window)
+ // if (src_bitmap != backbuffer || dst_bitmap != window)
+ if (!(src_bitmap == backbuffer && dst_bitmap == window))
SDL_BlitSurface((mask_mode == BLIT_MASKED ?
src_bitmap->surface_masked : src_bitmap->surface),
&src_rect, real_dst_bitmap->surface, &dst_rect);
+#if defined(TARGET_SDL2)
+ if (dst_bitmap == window)
+ {
+ // SDL_UpdateWindowSurface(sdl_window);
+ // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
+ UpdateScreen(&dst_rect);
+ }
+#else
if (dst_bitmap == window)
- SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
+ {
+ // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
+ UpdateScreen(&dst_rect);
+ }
+#endif
}
-inline void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y,
- int width, int height, Uint32 color)
+void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
+ Uint32 color)
{
Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
SDL_Rect rect;
-#if 0
- unsigned int color_r = (color >> 16) & 0xff;
- unsigned int color_g = (color >> 8) & 0xff;
- unsigned int color_b = (color >> 0) & 0xff;
-#endif
-#ifdef FULLSCREEN_BUG
if (dst_bitmap == backbuffer || dst_bitmap == window)
{
x += video_xoffset;
y += video_yoffset;
}
-#endif
rect.x = x;
rect.y = y;
rect.w = width;
rect.h = height;
-#if 1
SDL_FillRect(real_dst_bitmap->surface, &rect, color);
+
+#if defined(TARGET_SDL2)
+ if (dst_bitmap == window)
+ {
+ // SDL_UpdateWindowSurface(sdl_window);
+ // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
+ UpdateScreen(&rect);
+ }
#else
- SDL_FillRect(real_dst_bitmap->surface, &rect,
- SDL_MapRGB(real_dst_bitmap->surface->format,
- color_r, color_g, color_b));
+ if (dst_bitmap == window)
+ {
+ // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
+ UpdateScreen(&rect);
+ }
#endif
+}
- if (dst_bitmap == window)
- SDL_UpdateRect(backbuffer->surface, x, y, width, height);
+void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
+ int fade_mode, int fade_delay, int post_delay,
+ void (*draw_border_function)(void))
+{
+ static boolean initialization_needed = TRUE;
+ static SDL_Surface *surface_source = NULL;
+ static SDL_Surface *surface_target = NULL;
+ static SDL_Surface *surface_black = NULL;
+ SDL_Surface *surface_screen = backbuffer->surface;
+ SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
+ SDL_Rect src_rect, dst_rect;
+ SDL_Rect dst_rect2;
+ int src_x = x, src_y = y;
+ int dst_x = x, dst_y = y;
+ unsigned int time_last, time_current;
+
+ /* check if screen size has changed */
+ if (surface_source != NULL && (video.width != surface_source->w ||
+ video.height != surface_source->h))
+ {
+ SDL_FreeSurface(surface_source);
+ SDL_FreeSurface(surface_target);
+ SDL_FreeSurface(surface_black);
+
+ initialization_needed = TRUE;
+ }
+
+ src_rect.x = src_x;
+ src_rect.y = src_y;
+ src_rect.w = width;
+ src_rect.h = height;
+
+ dst_x += video_xoffset;
+ dst_y += video_yoffset;
+
+ dst_rect.x = dst_x;
+ dst_rect.y = dst_y;
+ dst_rect.w = width; /* (ignored) */
+ dst_rect.h = height; /* (ignored) */
+
+ dst_rect2 = dst_rect;
+
+ if (initialization_needed)
+ {
+#if defined(TARGET_SDL2)
+ unsigned int flags = 0;
+#else
+ unsigned int flags = SDL_SRCALPHA;
+
+ /* use same surface type as screen surface */
+ if ((surface_screen->flags & SDL_HWSURFACE))
+ flags |= SDL_HWSURFACE;
+ else
+ flags |= SDL_SWSURFACE;
+#endif
+
+ /* create surface for temporary copy of screen buffer (source) */
+ if ((surface_source =
+ SDL_CreateRGBSurface(flags,
+ video.width,
+ video.height,
+ surface_screen->format->BitsPerPixel,
+ surface_screen->format->Rmask,
+ surface_screen->format->Gmask,
+ surface_screen->format->Bmask,
+ surface_screen->format->Amask)) == NULL)
+ Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
+
+ /* create surface for cross-fading screen buffer (target) */
+ if ((surface_target =
+ SDL_CreateRGBSurface(flags,
+ video.width,
+ video.height,
+ surface_screen->format->BitsPerPixel,
+ surface_screen->format->Rmask,
+ surface_screen->format->Gmask,
+ surface_screen->format->Bmask,
+ surface_screen->format->Amask)) == NULL)
+ Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
+
+ /* create black surface for fading from/to black */
+ if ((surface_black =
+ SDL_CreateRGBSurface(flags,
+ video.width,
+ video.height,
+ surface_screen->format->BitsPerPixel,
+ surface_screen->format->Rmask,
+ surface_screen->format->Gmask,
+ surface_screen->format->Bmask,
+ surface_screen->format->Amask)) == NULL)
+ Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
+
+ /* completely fill the surface with black color pixels */
+ SDL_FillRect(surface_black, NULL,
+ SDL_MapRGB(surface_screen->format, 0, 0, 0));
+
+ initialization_needed = FALSE;
+ }
+
+ /* copy source and target surfaces to temporary surfaces for fading */
+ if (fade_mode & FADE_TYPE_TRANSFORM)
+ {
+ SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
+ SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
+ }
+ else if (fade_mode & FADE_TYPE_FADE_IN)
+ {
+ SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
+ SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
+ }
+ else /* FADE_TYPE_FADE_OUT */
+ {
+ SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
+ SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
+ }
+
+ time_current = SDL_GetTicks();
+
+ if (fade_mode == FADE_MODE_MELT)
+ {
+ boolean done = FALSE;
+ int melt_pixels = 2;
+ int melt_columns = width / melt_pixels;
+ int ypos[melt_columns];
+ int max_steps = height / 8 + 32;
+ int steps_done = 0;
+ float steps = 0;
+ int i;
+
+ SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
+#if defined(TARGET_SDL2)
+ SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
+#else
+ SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
+#endif
+
+ ypos[0] = -GetSimpleRandom(16);
+
+ for (i = 1 ; i < melt_columns; i++)
+ {
+ int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
+
+ ypos[i] = ypos[i - 1] + r;
+
+ if (ypos[i] > 0)
+ ypos[i] = 0;
+ else
+ if (ypos[i] == -16)
+ ypos[i] = -15;
+ }
+
+ while (!done)
+ {
+ int steps_final;
+
+ time_last = time_current;
+ time_current = SDL_GetTicks();
+ steps += max_steps * ((float)(time_current - time_last) / fade_delay);
+ steps_final = MIN(MAX(0, steps), max_steps);
+
+ steps_done++;
+
+ done = (steps_done >= steps_final);
+
+ for (i = 0 ; i < melt_columns; i++)
+ {
+ if (ypos[i] < 0)
+ {
+ ypos[i]++;
+
+ done = FALSE;
+ }
+ else if (ypos[i] < height)
+ {
+ int y1 = 16;
+ int y2 = 8;
+ int y3 = 8;
+ int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
+
+ if (ypos[i] + dy >= height)
+ dy = height - ypos[i];
+
+ /* copy part of (appearing) target surface to upper area */
+ src_rect.x = src_x + i * melt_pixels;
+ // src_rect.y = src_y + ypos[i];
+ src_rect.y = src_y;
+ src_rect.w = melt_pixels;
+ // src_rect.h = dy;
+ src_rect.h = ypos[i] + dy;
+
+ dst_rect.x = dst_x + i * melt_pixels;
+ // dst_rect.y = dst_y + ypos[i];
+ dst_rect.y = dst_y;
+
+ if (steps_done >= steps_final)
+ SDL_BlitSurface(surface_target, &src_rect,
+ surface_screen, &dst_rect);
+
+ ypos[i] += dy;
+
+ /* copy part of (disappearing) source surface to lower area */
+ src_rect.x = src_x + i * melt_pixels;
+ src_rect.y = src_y;
+ src_rect.w = melt_pixels;
+ src_rect.h = height - ypos[i];
+
+ dst_rect.x = dst_x + i * melt_pixels;
+ dst_rect.y = dst_y + ypos[i];
+
+ if (steps_done >= steps_final)
+ SDL_BlitSurface(surface_source, &src_rect,
+ surface_screen, &dst_rect);
+
+ done = FALSE;
+ }
+ else
+ {
+ src_rect.x = src_x + i * melt_pixels;
+ src_rect.y = src_y;
+ src_rect.w = melt_pixels;
+ src_rect.h = height;
+
+ dst_rect.x = dst_x + i * melt_pixels;
+ dst_rect.y = dst_y;
+
+ if (steps_done >= steps_final)
+ SDL_BlitSurface(surface_target, &src_rect,
+ surface_screen, &dst_rect);
+ }
+ }
+
+ if (steps_done >= steps_final)
+ {
+ if (draw_border_function != NULL)
+ draw_border_function();
+
+#if defined(TARGET_SDL2)
+ // SDL_UpdateWindowSurface(sdl_window);
+ // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
+ UpdateScreen(&dst_rect2);
+#else
+ // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
+ UpdateScreen(&dst_rect2);
+#endif
+ }
+ }
+ }
+ else
+ {
+ float alpha;
+ int alpha_final;
+
+ for (alpha = 0.0; alpha < 255.0;)
+ {
+ time_last = time_current;
+ time_current = SDL_GetTicks();
+ alpha += 255 * ((float)(time_current - time_last) / fade_delay);
+ alpha_final = MIN(MAX(0, alpha), 255);
+
+ /* draw existing (source) image to screen buffer */
+ SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
+
+ /* draw new (target) image to screen buffer using alpha blending */
+#if defined(TARGET_SDL2)
+ SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
+ SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
+#else
+ SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
+#endif
+ SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
+
+ if (draw_border_function != NULL)
+ draw_border_function();
+
+ /* only update the region of the screen that is affected from fading */
+ UpdateScreen(&dst_rect);
+ }
+ }
+
+ Delay(post_delay);
}
-inline void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
- int to_x, int to_y, Uint32 color)
+void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
+ int to_x, int to_y, Uint32 color)
{
SDL_Surface *surface = dst_bitmap->surface;
SDL_Rect rect;
-#if 0
- unsigned int color_r = (color >> 16) & 0xff;
- unsigned int color_g = (color >> 8) & 0xff;
- unsigned int color_b = (color >> 0) & 0xff;
-#endif
if (from_x > to_x)
swap_numbers(&from_x, &to_x);
rect.w = (to_x - from_x + 1);
rect.h = (to_y - from_y + 1);
-#ifdef FULLSCREEN_BUG
if (dst_bitmap == backbuffer || dst_bitmap == window)
{
rect.x += video_xoffset;
rect.y += video_yoffset;
}
-#endif
-#if 1
SDL_FillRect(surface, &rect, color);
-#else
- SDL_FillRect(surface, &rect,
- SDL_MapRGB(surface->format, color_r, color_g, color_b));
-#endif
}
-inline void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
- int to_x, int to_y, Uint32 color)
+void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
+ int to_x, int to_y, Uint32 color)
{
-#ifdef FULLSCREEN_BUG
if (dst_bitmap == backbuffer || dst_bitmap == window)
{
from_x += video_xoffset;
to_x += video_xoffset;
to_y += video_yoffset;
}
-#endif
sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
}
-#if 0
-inline void SDLDrawLines(SDL_Surface *surface, struct XY *points,
- int num_points, Uint32 color)
+#if ENABLE_UNUSED_CODE
+void SDLDrawLines(SDL_Surface *surface, struct XY *points,
+ int num_points, Uint32 color)
{
int i, x, y;
int line_width = 4;
- for (i=0; i<num_points - 1; i++)
+ for (i = 0; i < num_points - 1; i++)
{
- for (x=0; x<line_width; x++)
+ for (x = 0; x < line_width; x++)
{
- for (y=0; y<line_width; y++)
+ for (y = 0; y < line_width; y++)
{
int dx = x - line_width / 2;
int dy = y - line_width / 2;
}
#endif
-inline Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
+Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
{
SDL_Surface *surface = src_bitmap->surface;
-#ifdef FULLSCREEN_BUG
if (src_bitmap == backbuffer || src_bitmap == window)
{
x += video_xoffset;
y += video_yoffset;
}
-#endif
switch (surface->format->BytesPerPixel)
{
/* ========================================================================= */
/* The following functions were taken from the SGE library */
-/* (SDL Graphics Extension Library) by Anders Lindström */
+/* (SDL Graphics Extension Library) by Anders Lindström */
/* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
/* ========================================================================= */
sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
}
-inline void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
+void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
{
-#ifdef FULLSCREEN_BUG
if (dst_bitmap == backbuffer || dst_bitmap == window)
{
x += video_xoffset;
y += video_yoffset;
}
-#endif
sge_PutPixel(dst_bitmap->surface, x, y, pixel);
}
-----------------------------------------------------------------------------
*/
-inline void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
- int width, int height, Uint32 color)
+void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
+ int width, int height, Uint32 color)
{
int x, y;
- for (y=src_y; y < src_y + height; y++)
+ for (y = src_y; y < src_y + height; y++)
{
- for (x=src_x; x < src_x + width; x++)
+ for (x = src_x; x < src_x + width; x++)
{
Uint32 pixel = SDLGetPixel(bitmap, x, y);
}
}
-inline void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
- int src_x, int src_y, int width, int height,
- int dst_x, int dst_y)
+void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
+ int src_x, int src_y, int width, int height,
+ int dst_x, int dst_y)
{
int x, y;
- for (y=0; y < height; y++)
+ for (y = 0; y < height; y++)
{
- for (x=0; x < width; x++)
+ for (x = 0; x < width; x++)
{
Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
Uint8 a;
} tColorRGBA;
-int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
+int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
{
- int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
+ int x, y;
tColorRGBA *sp, *csp, *dp;
- int sgap, dgap;
+ int dgap;
+
+ /* pointer setup */
+ sp = csp = (tColorRGBA *) src->pixels;
+ dp = (tColorRGBA *) dst->pixels;
+ dgap = dst->pitch - dst->w * 4;
+
+ for (y = 0; y < dst->h; y++)
+ {
+ sp = csp;
+
+ for (x = 0; x < dst->w; x++)
+ {
+ tColorRGBA *sp0 = sp;
+ tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
+ tColorRGBA *sp00 = &sp0[0];
+ tColorRGBA *sp01 = &sp0[1];
+ tColorRGBA *sp10 = &sp1[0];
+ tColorRGBA *sp11 = &sp1[1];
+ tColorRGBA new;
+
+ /* create new color pixel from all four source color pixels */
+ new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
+ new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
+ new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
+ new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
+
+ /* draw */
+ *dp = new;
+
+ /* advance source pointers */
+ sp += 2;
+
+ /* advance destination pointer */
+ dp++;
+ }
+
+ /* advance source pointer */
+ csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
+
+ /* advance destination pointers */
+ dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
+ }
+
+ return 0;
+}
+
+int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
+{
+ int x, y, *sax, *say, *csax, *csay;
+ float sx, sy;
+ tColorRGBA *sp, *csp, *csp0, *dp;
+ int dgap;
+
+ /* use specialized zoom function when scaling down to exactly half size */
+ if (src->w == 2 * dst->w &&
+ src->h == 2 * dst->h)
+ return zoomSurfaceRGBA_scaleDownBy2(src, dst);
/* variable setup */
- sx = (int) (65536.0 * (float) src->w / (float) dst->w);
- sy = (int) (65536.0 * (float) src->h / (float) dst->h);
+ sx = (float) src->w / (float) dst->w;
+ sy = (float) src->h / (float) dst->h;
/* allocate memory for row increments */
- sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
- say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
+ csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
+ csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
/* precalculate row increments */
- csx = 0;
- csax = sax;
for (x = 0; x <= dst->w; x++)
- {
- *csax = csx;
- csax++;
- csx &= 0xffff;
- csx += sx;
- }
+ *csax++ = (int)(sx * x);
- csy = 0;
- csay = say;
for (y = 0; y <= dst->h; y++)
- {
- *csay = csy;
- csay++;
- csy &= 0xffff;
- csy += sy;
- }
+ *csay++ = (int)(sy * y);
/* pointer setup */
- sp = csp = (tColorRGBA *) src->pixels;
+ sp = csp = csp0 = (tColorRGBA *) src->pixels;
dp = (tColorRGBA *) dst->pixels;
- sgap = src->pitch - src->w * 4;
dgap = dst->pitch - dst->w * 4;
csay = say;
/* advance source pointers */
csax++;
- sp += (*csax >> 16);
+ sp = csp + *csax;
/* advance destination pointer */
dp++;
/* advance source pointer */
csay++;
- csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
+ csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
/* advance destination pointers */
dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
-----------------------------------------------------------------------------
zoomSurface()
- Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
+ Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
'zoomx' and 'zoomy' are scaling factors for width and height.
- If 'smooth' is 1 then the destination 32bit surface is anti-aliased.
If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
into a 32bit RGBA format on the fly.
-----------------------------------------------------------------------------
else
{
/* new source surface is 32 bit with a defined RGB ordering */
- zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
+ zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
0x000000ff, 0x0000ff00, 0x00ff0000, 0);
SDL_BlitSurface(src, NULL, zoom_src, NULL);
is_32bit = TRUE;
if (is_32bit)
{
/* target surface is 32 bit with source RGBA/ABGR ordering */
- zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
+ zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
zoom_src->format->Rmask,
zoom_src->format->Gmask,
zoom_src->format->Bmask, 0);
else
{
/* target surface is 8 bit */
- zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
+ zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
0, 0, 0, 0);
}
else
{
/* copy palette */
- for (i=0; i < zoom_src->format->palette->ncolors; i++)
+ for (i = 0; i < zoom_src->format->palette->ncolors; i++)
zoom_dst->format->palette->colors[i] =
zoom_src->format->palette->colors[i];
zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
return zoom_dst;
}
-void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
+Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
{
- SDL_Surface *sdl_surface_tmp;
- int dst_width = dst_bitmap->width;
- int dst_height = dst_bitmap->height;
+ Bitmap *dst_bitmap = CreateBitmapStruct();
+ SDL_Surface **dst_surface = &dst_bitmap->surface;
+
+ dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
+ dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
- /* throw away old destination surface */
- SDL_FreeSurface(dst_bitmap->surface);
+ dst_bitmap->width = dst_width;
+ dst_bitmap->height = dst_height;
/* create zoomed temporary surface from source surface */
- sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
+ *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
/* create native format destination surface from zoomed temporary surface */
- dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
+ SDLSetNativeSurface(dst_surface);
- /* free temporary surface */
- SDL_FreeSurface(sdl_surface_tmp);
+ return dst_bitmap;
}
Bitmap *new_bitmap = CreateBitmapStruct();
SDL_Surface *sdl_image_tmp;
+ print_timestamp_init("SDLLoadImage");
+
+ print_timestamp_time(getBaseNamePtr(filename));
+
/* load image to temporary surface */
if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
{
SetError("IMG_Load(): %s", SDL_GetError());
+
return NULL;
}
+ print_timestamp_time("IMG_Load");
+
+ UPDATE_BUSY_STATE();
+
/* create native non-transparent surface for current image */
- if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
+ if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
{
SetError("SDL_DisplayFormat(): %s", SDL_GetError());
+
return NULL;
}
+ print_timestamp_time("SDL_DisplayFormat (opaque)");
+
+ UPDATE_BUSY_STATE();
+
/* create native transparent surface for current image */
- SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
+ SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
- if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
+
+ if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
{
SetError("SDL_DisplayFormat(): %s", SDL_GetError());
+
return NULL;
}
+ print_timestamp_time("SDL_DisplayFormat (masked)");
+
+ UPDATE_BUSY_STATE();
+
/* free temporary surface */
SDL_FreeSurface(sdl_image_tmp);
new_bitmap->width = new_bitmap->surface->w;
new_bitmap->height = new_bitmap->surface->h;
+ print_timestamp_done("SDLLoadImage");
+
return new_bitmap;
}
void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
{
static struct MouseCursorInfo *last_cursor_info = NULL;
+ static struct MouseCursorInfo *last_cursor_info2 = NULL;
static SDL_Cursor *cursor_default = NULL;
static SDL_Cursor *cursor_current = NULL;
+ /* if invoked for the first time, store the SDL default cursor */
if (cursor_default == NULL)
cursor_default = SDL_GetCursor();
+ /* only create new cursor if cursor info (custom only) has changed */
if (cursor_info != NULL && cursor_info != last_cursor_info)
{
cursor_current = create_cursor(cursor_info);
last_cursor_info = cursor_info;
}
- SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
+ /* only set new cursor if cursor info (custom or NULL) has changed */
+ if (cursor_info != last_cursor_info2)
+ SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
+
+ last_cursor_info2 = cursor_info;
}
/* audio functions */
/* ========================================================================= */
-inline void SDLOpenAudio(void)
+void SDLOpenAudio(void)
{
- if (strcmp(setup.system.sdl_audiodriver, ARG_DEFAULT) != 0)
- putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
+#if !defined(TARGET_SDL2)
+ if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
+ SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
+#endif
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
{
Mixer_InitChannels();
}
-inline void SDLCloseAudio(void)
+void SDLCloseAudio(void)
{
Mix_HaltMusic();
Mix_HaltChannel(-1);
/* event functions */
/* ========================================================================= */
-inline void SDLNextEvent(Event *event)
+void SDLNextEvent(Event *event)
{
SDL_WaitEvent(event);
-#ifdef FULLSCREEN_BUG
if (event->type == EVENT_BUTTONPRESS ||
event->type == EVENT_BUTTONRELEASE)
{
else
((MotionEvent *)event)->y = 0;
}
+}
+
+void SDLHandleWindowManagerEvent(Event *event)
+{
+#ifdef DEBUG
+#if defined(PLATFORM_WIN32)
+ // experimental drag and drop code
+
+ SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
+ SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
+
+#if defined(TARGET_SDL2)
+ if (syswmmsg->msg.win.msg == WM_DROPFILES)
+#else
+ if (syswmmsg->msg == WM_DROPFILES)
+#endif
+ {
+#if defined(TARGET_SDL2)
+ HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
+#else
+ HDROP hdrop = (HDROP)syswmmsg->wParam;
+#endif
+ int i, num_files;
+
+ printf("::: SDL_SYSWMEVENT:\n");
+
+ num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
+
+ for (i = 0; i < num_files; i++)
+ {
+ int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
+ char buffer[buffer_len + 1];
+
+ DragQueryFile(hdrop, i, buffer, buffer_len + 1);
+
+ printf("::: - '%s'\n", buffer);
+ }
+
+#if defined(TARGET_SDL2)
+ DragFinish((HDROP)syswmmsg->msg.win.wParam);
+#else
+ DragFinish((HDROP)syswmmsg->wParam);
+#endif
+ }
+#endif
#endif
}
return;
SDL_JoystickClose(sdl_joystick[nr]);
+
+ sdl_joystick[nr] = NULL;
}
static boolean SDLCheckJoystickOpened(int nr)
if (nr < 0 || nr > MAX_PLAYERS)
return FALSE;
+#if defined(TARGET_SDL2)
+ return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
+#else
return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
+#endif
}
void HandleJoystickEvent(Event *event)
void SDLInitJoysticks()
{
static boolean sdl_joystick_subsystem_initialized = FALSE;
+ boolean print_warning = !sdl_joystick_subsystem_initialized;
int i;
if (!sdl_joystick_subsystem_initialized)
{
sdl_joystick_subsystem_initialized = TRUE;
- if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
+ if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
{
Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
return;
}
}
- for (i=0; i<MAX_PLAYERS; i++)
+ for (i = 0; i < MAX_PLAYERS; i++)
{
+ /* get configured joystick for this player */
char *device_name = setup.input[i].joy.device_name;
int joystick_nr = getJoystickNrFromDeviceName(device_name);
if (joystick_nr >= SDL_NumJoysticks())
+ {
+ if (setup.input[i].use_joystick && print_warning)
+ Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
+
joystick_nr = -1;
+ }
/* misuse joystick file descriptor variable to store joystick number */
joystick.fd[i] = joystick_nr;
+ if (joystick_nr == -1)
+ continue;
+
/* this allows subsequent calls to 'InitJoysticks' for re-initialization */
if (SDLCheckJoystickOpened(joystick_nr))
SDLCloseJoystick(joystick_nr);
if (!SDLOpenJoystick(joystick_nr))
{
- Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
+ if (print_warning)
+ Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
+
continue;
}
return TRUE;
}
-
-#endif /* TARGET_SDL */