1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
18 #define ENABLE_UNUSED_CODE 0 /* currently unused functions */
21 /* ========================================================================= */
23 /* ========================================================================= */
25 /* SDL internal variables */
26 #if defined(TARGET_SDL2)
27 static SDL_Window *sdl_window = NULL;
28 static SDL_Renderer *sdl_renderer = NULL;
29 static SDL_Texture *sdl_texture = NULL;
30 static boolean fullscreen_enabled = FALSE;
32 #define USE_RENDERER TRUE
35 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
36 static int fullscreen_width;
37 static int fullscreen_height;
38 static int fullscreen_xoffset;
39 static int fullscreen_yoffset;
40 static int video_xoffset;
41 static int video_yoffset;
42 static boolean limit_screen_updates = FALSE;
45 /* functions from SGE library */
46 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
48 void SDLLimitScreenUpdates(boolean enable)
50 limit_screen_updates = enable;
53 static void UpdateScreen(SDL_Rect *rect)
55 static unsigned int update_screen_delay = 0;
56 unsigned int update_screen_delay_value = 50; /* (milliseconds) */
57 SDL_Surface *screen = backbuffer->surface;
59 if (limit_screen_updates &&
60 !DelayReached(&update_screen_delay, update_screen_delay_value))
63 LimitScreenUpdates(FALSE);
67 static int LastFrameCounter = 0;
68 boolean changed = (FrameCounter != LastFrameCounter);
70 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
71 (changed ? "-" : "SAME FRAME UPDATED"));
73 LastFrameCounter = FrameCounter;
82 #if USE_FINAL_SCREEN_BITMAP
83 if (gfx.final_screen_bitmap != NULL) // may not be initialized yet
86 // draw global animations using bitmaps instead of using textures
87 // to prevent texture scaling artefacts (this is potentially slower)
89 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
90 gfx.win_xsize, gfx.win_ysize, 0, 0);
92 // copy global animations to render target buffer, if defined (below border)
93 if (gfx.draw_global_anim_function != NULL)
94 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
96 // copy global masked border to render target buffer, if defined
97 if (gfx.draw_global_border_function != NULL)
98 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
100 // copy global animations to render target buffer, if defined (above border)
101 if (gfx.draw_global_anim_function != NULL)
102 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
104 screen = gfx.final_screen_bitmap->surface;
106 // force full window redraw
111 #if defined(TARGET_SDL2)
115 int bytes_x = screen->pitch / video.width;
116 int bytes_y = screen->pitch;
118 if (video.fullscreen_enabled)
119 bytes_x = screen->pitch / fullscreen_width;
121 SDL_UpdateTexture(sdl_texture, rect,
122 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
127 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
130 // clear render target buffer
131 SDL_RenderClear(sdl_renderer);
133 // copy backbuffer to render target buffer
134 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
136 #if !USE_FINAL_SCREEN_BITMAP
137 // copy global animations to render target buffer, if defined (below border)
138 if (gfx.draw_global_anim_function != NULL)
139 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
141 // copy global masked border to render target buffer, if defined
142 if (gfx.draw_global_border_function != NULL)
143 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
145 // copy global animations to render target buffer, if defined (above border)
146 if (gfx.draw_global_anim_function != NULL)
147 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
150 // show render target buffer on screen
151 SDL_RenderPresent(sdl_renderer);
156 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
158 SDL_UpdateWindowSurface(sdl_window);
163 SDL_UpdateRects(screen, 1, rect);
165 SDL_UpdateRect(screen, 0, 0, 0, 0);
169 static void setFullscreenParameters(char *fullscreen_mode_string)
171 #if defined(TARGET_SDL2)
172 fullscreen_width = video.width;
173 fullscreen_height = video.height;
174 fullscreen_xoffset = 0;
175 fullscreen_yoffset = 0;
179 struct ScreenModeInfo *fullscreen_mode;
182 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
184 if (fullscreen_mode == NULL)
187 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
189 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
190 fullscreen_mode->height == video.fullscreen_modes[i].height)
192 fullscreen_width = fullscreen_mode->width;
193 fullscreen_height = fullscreen_mode->height;
195 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
196 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
204 static void SDLSetWindowIcon(char *basename)
206 /* (setting the window icon on Mac OS X would replace the high-quality
207 dock icon with the currently smaller (and uglier) icon from file) */
209 #if !defined(PLATFORM_MACOSX)
210 char *filename = getCustomImageFilename(basename);
211 SDL_Surface *surface;
213 if (filename == NULL)
215 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
220 if ((surface = IMG_Load(filename)) == NULL)
222 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
227 /* set transparent color */
228 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
229 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
231 #if defined(TARGET_SDL2)
232 SDL_SetWindowIcon(sdl_window, surface);
234 SDL_WM_SetIcon(surface, NULL);
239 #if defined(TARGET_SDL2)
241 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
242 SDL_PixelFormat *format2)
244 return (format1->format == format2->format &&
245 format1->BitsPerPixel == format2->BitsPerPixel &&
246 format1->BytesPerPixel == format2->BytesPerPixel &&
247 format1->Rmask == format2->Rmask &&
248 format1->Gmask == format2->Gmask &&
249 format1->Bmask == format2->Bmask &&
250 format1->Amask == format2->Amask);
253 boolean SDLSetNativeSurface(SDL_Surface **surface)
255 SDL_Surface *new_surface;
257 if (surface == NULL ||
259 backbuffer == NULL ||
260 backbuffer->surface == NULL)
263 // if pixel format already optimized for destination surface, do nothing
264 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
267 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
269 if (new_surface == NULL)
270 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
272 SDL_FreeSurface(*surface);
274 *surface = new_surface;
279 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
281 SDL_PixelFormat format;
282 SDL_Surface *new_surface;
287 if (backbuffer && backbuffer->surface)
289 format = *backbuffer->surface->format;
290 format.Amask = surface->format->Amask; // keep alpha channel
294 format = *surface->format;
297 new_surface = SDL_ConvertSurface(surface, &format, 0);
299 if (new_surface == NULL)
300 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
307 boolean SDLSetNativeSurface(SDL_Surface **surface)
309 SDL_Surface *new_surface;
311 if (surface == NULL ||
316 new_surface = SDL_DisplayFormat(*surface);
318 if (new_surface == NULL)
319 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
321 SDL_FreeSurface(*surface);
323 *surface = new_surface;
328 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
330 SDL_Surface *new_surface;
332 if (video.initialized)
333 new_surface = SDL_DisplayFormat(surface);
335 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
337 if (new_surface == NULL)
338 Error(ERR_EXIT, "%s() failed: %s",
339 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
347 #if defined(TARGET_SDL2)
348 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
350 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
353 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
360 void SDLCreateBitmapTextures(Bitmap *bitmap)
362 #if defined(TARGET_SDL2)
367 SDL_DestroyTexture(bitmap->texture);
368 if (bitmap->texture_masked)
369 SDL_DestroyTexture(bitmap->texture_masked);
371 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
372 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
376 void SDLFreeBitmapTextures(Bitmap *bitmap)
378 #if defined(TARGET_SDL2)
383 SDL_DestroyTexture(bitmap->texture);
384 if (bitmap->texture_masked)
385 SDL_DestroyTexture(bitmap->texture_masked);
387 bitmap->texture = NULL;
388 bitmap->texture_masked = NULL;
392 void SDLInitVideoDisplay(void)
394 #if !defined(TARGET_SDL2)
395 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
396 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
398 SDL_putenv("SDL_VIDEO_CENTERED=1");
401 /* initialize SDL video */
402 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
403 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
405 /* set default SDL depth */
406 #if !defined(TARGET_SDL2)
407 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
409 video.default_depth = 32; // (how to determine video depth in SDL2?)
413 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
416 #if !defined(TARGET_SDL2)
417 static int screen_xy[][2] =
425 SDL_Rect **modes = NULL;
426 boolean hardware_fullscreen_available = TRUE;
429 /* default: normal game window size */
430 fullscreen_width = video.width;
431 fullscreen_height = video.height;
432 fullscreen_xoffset = 0;
433 fullscreen_yoffset = 0;
435 #if !defined(TARGET_SDL2)
436 /* determine required standard fullscreen mode for game screen size */
437 for (i = 0; screen_xy[i][0] != -1; i++)
439 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
441 fullscreen_width = screen_xy[i][0];
442 fullscreen_height = screen_xy[i][1];
448 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
449 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
452 checked_free(video.fullscreen_modes);
454 video.fullscreen_modes = NULL;
455 video.fullscreen_mode_current = NULL;
457 video.window_scaling_percent = setup.window_scaling_percent;
458 video.window_scaling_quality = setup.window_scaling_quality;
460 #if defined(TARGET_SDL2)
461 int num_displays = SDL_GetNumVideoDisplays();
463 if (num_displays > 0)
465 // currently only display modes of first display supported
466 int num_modes = SDL_GetNumDisplayModes(0);
470 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
472 for (i = 0; i < num_modes; i++)
474 SDL_DisplayMode mode;
476 if (SDL_GetDisplayMode(0, i, &mode) < 0)
479 modes[i] = checked_calloc(sizeof(SDL_Rect));
481 modes[i]->w = mode.w;
482 modes[i]->h = mode.h;
487 /* get available hardware supported fullscreen modes */
488 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
493 /* no hardware screen modes available => no fullscreen mode support */
494 // video.fullscreen_available = FALSE;
495 hardware_fullscreen_available = FALSE;
497 else if (modes == (SDL_Rect **)-1)
499 /* fullscreen resolution is not restricted -- all resolutions available */
500 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
502 /* use native video buffer size for fullscreen mode */
503 video.fullscreen_modes[0].width = video.width;
504 video.fullscreen_modes[0].height = video.height;
506 video.fullscreen_modes[1].width = -1;
507 video.fullscreen_modes[1].height = -1;
511 /* in this case, a certain number of screen modes is available */
514 for (i = 0; modes[i] != NULL; i++)
516 boolean found_mode = FALSE;
518 /* screen mode is smaller than video buffer size -- skip it */
519 if (modes[i]->w < video.width || modes[i]->h < video.height)
522 if (video.fullscreen_modes != NULL)
523 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
524 if (modes[i]->w == video.fullscreen_modes[j].width &&
525 modes[i]->h == video.fullscreen_modes[j].height)
528 if (found_mode) /* screen mode already stored -- skip it */
531 /* new mode found; add it to list of available fullscreen modes */
535 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
537 sizeof(struct ScreenModeInfo));
539 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
540 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
542 video.fullscreen_modes[num_modes].width = -1;
543 video.fullscreen_modes[num_modes].height = -1;
548 /* no appropriate screen modes available => no fullscreen mode support */
549 // video.fullscreen_available = FALSE;
550 hardware_fullscreen_available = FALSE;
554 video.fullscreen_available = hardware_fullscreen_available;
556 #if USE_DESKTOP_FULLSCREEN
557 // in SDL 2.0, there is always support for desktop fullscreen mode
558 // (in SDL 1.2, there is only support for "real" fullscreen mode)
559 video.fullscreen_available = TRUE;
562 #if defined(TARGET_SDL2)
565 for (i = 0; modes[i] != NULL; i++)
566 checked_free(modes[i]);
572 /* open SDL video output device (window or fullscreen mode) */
573 if (!SDLSetVideoMode(backbuffer, fullscreen))
574 Error(ERR_EXIT, "setting video mode failed");
576 /* !!! SDL2 can only set the window icon if the window already exists !!! */
577 /* set window icon */
578 SDLSetWindowIcon(program.icon_filename);
580 /* set window and icon title */
581 #if defined(TARGET_SDL2)
582 SDL_SetWindowTitle(sdl_window, program.window_title);
584 SDL_WM_SetCaption(program.window_title, program.window_title);
587 /* SDL cannot directly draw to the visible video framebuffer like X11,
588 but always uses a backbuffer, which is then blitted to the visible
589 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
590 visible video framebuffer with 'SDL_Flip', if the hardware supports
591 this). Therefore do not use an additional backbuffer for drawing, but
592 use a symbolic buffer (distinguishable from the SDL backbuffer) called
593 'window', which indicates that the SDL backbuffer should be updated to
594 the visible video framebuffer when attempting to blit to it.
596 For convenience, it seems to be a good idea to create this symbolic
597 buffer 'window' at the same size as the SDL backbuffer. Although it
598 should never be drawn to directly, it would do no harm nevertheless. */
600 /* create additional (symbolic) buffer for double-buffering */
601 ReCreateBitmap(window, video.width, video.height, video.depth);
604 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
607 SDL_Surface *new_surface = NULL;
609 #if defined(TARGET_SDL2)
610 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
611 #if USE_DESKTOP_FULLSCREEN
612 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
614 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
618 int surface_flags_window = SURFACE_FLAGS;
619 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
622 int width = (fullscreen ? fullscreen_width : video.width);
623 int height = (fullscreen ? fullscreen_height : video.height);
624 int surface_flags = (fullscreen ? surface_flags_fullscreen :
625 surface_flags_window);
627 // default window size is unscaled
628 video.window_width = video.width;
629 video.window_height = video.height;
631 #if defined(TARGET_SDL2)
633 // store if initial screen mode is fullscreen mode when changing screen size
634 video.fullscreen_initial = fullscreen;
637 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
638 #if !USE_DESKTOP_FULLSCREEN
639 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
642 video.window_width = window_scaling_factor * width;
643 video.window_height = window_scaling_factor * height;
645 if ((*backbuffer)->surface)
647 SDL_FreeSurface((*backbuffer)->surface);
648 (*backbuffer)->surface = NULL;
653 SDL_DestroyTexture(sdl_texture);
657 if (!(fullscreen && fullscreen_enabled))
661 SDL_DestroyRenderer(sdl_renderer);
667 SDL_DestroyWindow(sdl_window);
672 if (sdl_window == NULL)
673 sdl_window = SDL_CreateWindow(program.window_title,
674 SDL_WINDOWPOS_CENTERED,
675 SDL_WINDOWPOS_CENTERED,
676 #if USE_DESKTOP_FULLSCREEN
680 (int)(screen_scaling_factor * width),
681 (int)(screen_scaling_factor * height),
685 if (sdl_window != NULL)
688 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
689 *without* enabling 2D/3D acceleration and/or guest additions installed,
690 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
691 it will try to use accelerated graphics and apparently fails miserably) */
692 if (sdl_renderer == NULL)
693 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
695 if (sdl_renderer == NULL)
696 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
699 if (sdl_renderer != NULL)
701 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
702 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
703 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
705 sdl_texture = SDL_CreateTexture(sdl_renderer,
706 SDL_PIXELFORMAT_ARGB8888,
707 SDL_TEXTUREACCESS_STREAMING,
710 if (sdl_texture != NULL)
712 // use SDL default values for RGB masks and no alpha channel
713 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
715 if (new_surface == NULL)
716 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
721 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
726 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
731 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
737 SDL_DestroyWindow(sdl_window);
739 sdl_window = SDL_CreateWindow(program.window_title,
740 SDL_WINDOWPOS_CENTERED,
741 SDL_WINDOWPOS_CENTERED,
745 if (sdl_window != NULL)
746 new_surface = SDL_GetWindowSurface(sdl_window);
750 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
753 #if defined(TARGET_SDL2)
754 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
755 if (new_surface != NULL)
756 fullscreen_enabled = fullscreen;
762 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
764 boolean success = TRUE;
765 SDL_Surface *new_surface = NULL;
769 if (*backbuffer == NULL)
770 *backbuffer = CreateBitmapStruct();
772 /* (real bitmap might be larger in fullscreen mode with video offsets) */
773 (*backbuffer)->width = video.width;
774 (*backbuffer)->height = video.height;
776 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
778 setFullscreenParameters(setup.fullscreen_mode);
780 video_xoffset = fullscreen_xoffset;
781 video_yoffset = fullscreen_yoffset;
783 /* switch display to fullscreen mode, if available */
784 new_surface = SDLCreateScreen(backbuffer, TRUE);
786 if (new_surface == NULL)
788 /* switching display to fullscreen mode failed */
789 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
791 /* do not try it again */
792 video.fullscreen_available = FALSE;
798 (*backbuffer)->surface = new_surface;
800 video.fullscreen_enabled = TRUE;
801 video.fullscreen_mode_current = setup.fullscreen_mode;
807 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
812 /* switch display to window mode */
813 new_surface = SDLCreateScreen(backbuffer, FALSE);
815 if (new_surface == NULL)
817 /* switching display to window mode failed -- should not happen */
818 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
824 (*backbuffer)->surface = new_surface;
826 video.fullscreen_enabled = FALSE;
827 video.window_scaling_percent = setup.window_scaling_percent;
828 video.window_scaling_quality = setup.window_scaling_quality;
834 #if defined(TARGET_SDL2)
835 SDLRedrawWindow(); // map window
839 #if defined(PLATFORM_WIN32)
840 // experimental drag and drop code
842 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
845 SDL_SysWMinfo wminfo;
847 boolean wminfo_success = FALSE;
849 SDL_VERSION(&wminfo.version);
850 #if defined(TARGET_SDL2)
852 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
854 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
859 #if defined(TARGET_SDL2)
860 hwnd = wminfo.info.win.window;
862 hwnd = wminfo.window;
865 DragAcceptFiles(hwnd, TRUE);
874 void SDLSetWindowTitle()
876 #if defined(TARGET_SDL2)
877 SDL_SetWindowTitle(sdl_window, program.window_title);
879 SDL_WM_SetCaption(program.window_title, program.window_title);
883 #if defined(TARGET_SDL2)
884 void SDLSetWindowScaling(int window_scaling_percent)
886 if (sdl_window == NULL)
889 float window_scaling_factor = (float)window_scaling_percent / 100;
890 int new_window_width = (int)(window_scaling_factor * video.width);
891 int new_window_height = (int)(window_scaling_factor * video.height);
893 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
895 video.window_scaling_percent = window_scaling_percent;
896 video.window_width = new_window_width;
897 video.window_height = new_window_height;
902 void SDLSetWindowScalingQuality(char *window_scaling_quality)
904 if (sdl_texture == NULL)
907 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
909 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
910 SDL_PIXELFORMAT_ARGB8888,
911 SDL_TEXTUREACCESS_STREAMING,
912 video.width, video.height);
914 if (new_texture != NULL)
916 SDL_DestroyTexture(sdl_texture);
918 sdl_texture = new_texture;
923 video.window_scaling_quality = window_scaling_quality;
926 void SDLSetWindowFullscreen(boolean fullscreen)
928 if (sdl_window == NULL)
931 #if USE_DESKTOP_FULLSCREEN
932 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
934 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
937 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
938 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
940 // if screen size was changed in fullscreen mode, correct desktop window size
941 if (!fullscreen && video.fullscreen_initial)
943 SDLSetWindowScaling(setup.window_scaling_percent);
944 SDL_SetWindowPosition(sdl_window,
945 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
947 video.fullscreen_initial = FALSE;
951 void SDLRedrawWindow()
957 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
960 SDL_Surface *surface =
961 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
964 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
966 SDLSetNativeSurface(&surface);
968 bitmap->surface = surface;
971 void SDLFreeBitmapPointers(Bitmap *bitmap)
974 SDL_FreeSurface(bitmap->surface);
975 if (bitmap->surface_masked)
976 SDL_FreeSurface(bitmap->surface_masked);
978 bitmap->surface = NULL;
979 bitmap->surface_masked = NULL;
981 #if defined(TARGET_SDL2)
983 SDL_DestroyTexture(bitmap->texture);
984 if (bitmap->texture_masked)
985 SDL_DestroyTexture(bitmap->texture_masked);
987 bitmap->texture = NULL;
988 bitmap->texture_masked = NULL;
992 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
993 int src_x, int src_y, int width, int height,
994 int dst_x, int dst_y, int mask_mode)
996 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
997 SDL_Rect src_rect, dst_rect;
999 if (src_bitmap == backbuffer)
1001 src_x += video_xoffset;
1002 src_y += video_yoffset;
1008 src_rect.h = height;
1010 if (dst_bitmap == backbuffer || dst_bitmap == window)
1012 dst_x += video_xoffset;
1013 dst_y += video_yoffset;
1019 dst_rect.h = height;
1021 // if (src_bitmap != backbuffer || dst_bitmap != window)
1022 if (!(src_bitmap == backbuffer && dst_bitmap == window))
1023 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
1024 src_bitmap->surface_masked : src_bitmap->surface),
1025 &src_rect, real_dst_bitmap->surface, &dst_rect);
1027 #if defined(TARGET_SDL2)
1028 if (dst_bitmap == window)
1030 // SDL_UpdateWindowSurface(sdl_window);
1031 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1032 UpdateScreen(&dst_rect);
1035 if (dst_bitmap == window)
1037 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
1038 UpdateScreen(&dst_rect);
1043 void SDLBlitTexture(Bitmap *bitmap,
1044 int src_x, int src_y, int width, int height,
1045 int dst_x, int dst_y, int mask_mode)
1047 #if defined(TARGET_SDL2)
1049 SDL_Texture *texture;
1054 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
1056 if (texture == NULL)
1062 src_rect.h = height;
1067 dst_rect.h = height;
1069 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
1074 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
1077 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1080 if (dst_bitmap == backbuffer || dst_bitmap == window)
1091 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1093 #if defined(TARGET_SDL2)
1094 if (dst_bitmap == window)
1096 // SDL_UpdateWindowSurface(sdl_window);
1097 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
1098 UpdateScreen(&rect);
1101 if (dst_bitmap == window)
1103 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
1104 UpdateScreen(&rect);
1109 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
1110 int fade_mode, int fade_delay, int post_delay,
1111 void (*draw_border_function)(void))
1113 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
1114 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
1115 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
1116 SDL_Surface *surface_screen = backbuffer->surface;
1117 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
1118 SDL_Rect src_rect, dst_rect;
1120 int src_x = x, src_y = y;
1121 int dst_x = x, dst_y = y;
1122 unsigned int time_last, time_current;
1124 // store function for drawing global masked border
1125 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
1127 // deactivate drawing of global border while fading, if needed
1128 if (draw_border_function == NULL)
1129 gfx.draw_global_border_function = NULL;
1134 src_rect.h = height;
1136 dst_x += video_xoffset;
1137 dst_y += video_yoffset;
1141 dst_rect.w = width; /* (ignored) */
1142 dst_rect.h = height; /* (ignored) */
1144 dst_rect2 = dst_rect;
1146 /* copy source and target surfaces to temporary surfaces for fading */
1147 if (fade_mode & FADE_TYPE_TRANSFORM)
1149 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1150 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1152 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
1153 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
1155 else if (fade_mode & FADE_TYPE_FADE_IN)
1157 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1158 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1160 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
1162 else /* FADE_TYPE_FADE_OUT */
1164 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1165 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1167 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
1170 time_current = SDL_GetTicks();
1172 if (fade_mode == FADE_MODE_MELT)
1174 boolean done = FALSE;
1175 int melt_pixels = 2;
1176 int melt_columns = width / melt_pixels;
1177 int ypos[melt_columns];
1178 int max_steps = height / 8 + 32;
1183 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1184 #if defined(TARGET_SDL2)
1185 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1187 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1190 ypos[0] = -GetSimpleRandom(16);
1192 for (i = 1 ; i < melt_columns; i++)
1194 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1196 ypos[i] = ypos[i - 1] + r;
1209 time_last = time_current;
1210 time_current = SDL_GetTicks();
1211 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1212 steps_final = MIN(MAX(0, steps), max_steps);
1216 done = (steps_done >= steps_final);
1218 for (i = 0 ; i < melt_columns; i++)
1226 else if (ypos[i] < height)
1231 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1233 if (ypos[i] + dy >= height)
1234 dy = height - ypos[i];
1236 /* copy part of (appearing) target surface to upper area */
1237 src_rect.x = src_x + i * melt_pixels;
1238 // src_rect.y = src_y + ypos[i];
1240 src_rect.w = melt_pixels;
1242 src_rect.h = ypos[i] + dy;
1244 dst_rect.x = dst_x + i * melt_pixels;
1245 // dst_rect.y = dst_y + ypos[i];
1248 if (steps_done >= steps_final)
1249 SDL_BlitSurface(surface_target, &src_rect,
1250 surface_screen, &dst_rect);
1254 /* copy part of (disappearing) source surface to lower area */
1255 src_rect.x = src_x + i * melt_pixels;
1257 src_rect.w = melt_pixels;
1258 src_rect.h = height - ypos[i];
1260 dst_rect.x = dst_x + i * melt_pixels;
1261 dst_rect.y = dst_y + ypos[i];
1263 if (steps_done >= steps_final)
1264 SDL_BlitSurface(surface_source, &src_rect,
1265 surface_screen, &dst_rect);
1271 src_rect.x = src_x + i * melt_pixels;
1273 src_rect.w = melt_pixels;
1274 src_rect.h = height;
1276 dst_rect.x = dst_x + i * melt_pixels;
1279 if (steps_done >= steps_final)
1280 SDL_BlitSurface(surface_target, &src_rect,
1281 surface_screen, &dst_rect);
1285 if (steps_done >= steps_final)
1287 if (draw_border_function != NULL)
1288 draw_border_function();
1290 UpdateScreen(&dst_rect2);
1294 else if (fade_mode == FADE_MODE_CURTAIN)
1298 int xx_size = width / 2;
1300 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1301 #if defined(TARGET_SDL2)
1302 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1304 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1307 for (xx = 0; xx < xx_size;)
1309 time_last = time_current;
1310 time_current = SDL_GetTicks();
1311 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1312 xx_final = MIN(MAX(0, xx), xx_size);
1317 src_rect.h = height;
1322 /* draw new (target) image to screen buffer */
1323 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1325 if (xx_final < xx_size)
1327 src_rect.w = xx_size - xx_final;
1328 src_rect.h = height;
1330 /* draw old (source) image to screen buffer (left side) */
1332 src_rect.x = src_x + xx_final;
1335 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1337 /* draw old (source) image to screen buffer (right side) */
1339 src_rect.x = src_x + xx_size;
1340 dst_rect.x = dst_x + xx_size + xx_final;
1342 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1345 if (draw_border_function != NULL)
1346 draw_border_function();
1348 /* only update the region of the screen that is affected from fading */
1349 UpdateScreen(&dst_rect2);
1352 else /* fading in, fading out or cross-fading */
1357 for (alpha = 0.0; alpha < 255.0;)
1359 time_last = time_current;
1360 time_current = SDL_GetTicks();
1361 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1362 alpha_final = MIN(MAX(0, alpha), 255);
1364 /* draw existing (source) image to screen buffer */
1365 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1367 /* draw new (target) image to screen buffer using alpha blending */
1368 #if defined(TARGET_SDL2)
1369 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1370 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1372 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1374 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1376 if (draw_border_function != NULL)
1377 draw_border_function();
1379 /* only update the region of the screen that is affected from fading */
1380 UpdateScreen(&dst_rect);
1386 unsigned int time_post_delay;
1388 time_current = SDL_GetTicks();
1389 time_post_delay = time_current + post_delay;
1391 while (time_current < time_post_delay)
1393 // do not wait longer than 10 ms at a time to be able to ...
1394 Delay(MIN(10, time_post_delay - time_current));
1396 // ... continue drawing global animations during post delay
1399 time_current = SDL_GetTicks();
1403 // restore function for drawing global masked border
1404 gfx.draw_global_border_function = draw_global_border_function;
1407 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1408 int to_x, int to_y, Uint32 color)
1410 SDL_Surface *surface = dst_bitmap->surface;
1414 swap_numbers(&from_x, &to_x);
1417 swap_numbers(&from_y, &to_y);
1421 rect.w = (to_x - from_x + 1);
1422 rect.h = (to_y - from_y + 1);
1424 if (dst_bitmap == backbuffer || dst_bitmap == window)
1426 rect.x += video_xoffset;
1427 rect.y += video_yoffset;
1430 SDL_FillRect(surface, &rect, color);
1433 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1434 int to_x, int to_y, Uint32 color)
1436 if (dst_bitmap == backbuffer || dst_bitmap == window)
1438 from_x += video_xoffset;
1439 from_y += video_yoffset;
1440 to_x += video_xoffset;
1441 to_y += video_yoffset;
1444 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1447 #if ENABLE_UNUSED_CODE
1448 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1449 int num_points, Uint32 color)
1454 for (i = 0; i < num_points - 1; i++)
1456 for (x = 0; x < line_width; x++)
1458 for (y = 0; y < line_width; y++)
1460 int dx = x - line_width / 2;
1461 int dy = y - line_width / 2;
1463 if ((x == 0 && y == 0) ||
1464 (x == 0 && y == line_width - 1) ||
1465 (x == line_width - 1 && y == 0) ||
1466 (x == line_width - 1 && y == line_width - 1))
1469 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1470 points[i+1].x + dx, points[i+1].y + dy, color);
1477 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1479 SDL_Surface *surface = src_bitmap->surface;
1481 if (src_bitmap == backbuffer || src_bitmap == window)
1487 switch (surface->format->BytesPerPixel)
1489 case 1: /* assuming 8-bpp */
1491 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1495 case 2: /* probably 15-bpp or 16-bpp */
1497 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1501 case 3: /* slow 24-bpp mode; usually not used */
1503 /* does this work? */
1504 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1508 shift = surface->format->Rshift;
1509 color |= *(pix + shift / 8) >> shift;
1510 shift = surface->format->Gshift;
1511 color |= *(pix + shift / 8) >> shift;
1512 shift = surface->format->Bshift;
1513 color |= *(pix + shift / 8) >> shift;
1519 case 4: /* probably 32-bpp */
1521 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1530 /* ========================================================================= */
1531 /* The following functions were taken from the SGE library */
1532 /* (SDL Graphics Extension Library) by Anders Lindström */
1533 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1534 /* ========================================================================= */
1536 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1538 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1540 switch (surface->format->BytesPerPixel)
1544 /* Assuming 8-bpp */
1545 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1551 /* Probably 15-bpp or 16-bpp */
1552 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1558 /* Slow 24-bpp mode, usually not used */
1562 /* Gack - slow, but endian correct */
1563 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1564 shift = surface->format->Rshift;
1565 *(pix+shift/8) = color>>shift;
1566 shift = surface->format->Gshift;
1567 *(pix+shift/8) = color>>shift;
1568 shift = surface->format->Bshift;
1569 *(pix+shift/8) = color>>shift;
1575 /* Probably 32-bpp */
1576 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1583 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1584 Uint8 R, Uint8 G, Uint8 B)
1586 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1589 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1591 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1594 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1596 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1599 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1604 /* Gack - slow, but endian correct */
1605 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1606 shift = surface->format->Rshift;
1607 *(pix+shift/8) = color>>shift;
1608 shift = surface->format->Gshift;
1609 *(pix+shift/8) = color>>shift;
1610 shift = surface->format->Bshift;
1611 *(pix+shift/8) = color>>shift;
1614 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1616 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1619 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1621 switch (dest->format->BytesPerPixel)
1624 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1628 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1632 _PutPixel24(dest,x,y,color);
1636 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1641 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1643 if (SDL_MUSTLOCK(surface))
1645 if (SDL_LockSurface(surface) < 0)
1651 _PutPixel(surface, x, y, color);
1653 if (SDL_MUSTLOCK(surface))
1655 SDL_UnlockSurface(surface);
1659 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1660 Uint8 r, Uint8 g, Uint8 b)
1662 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1665 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1667 if (y >= 0 && y <= dest->h - 1)
1669 switch (dest->format->BytesPerPixel)
1672 return y*dest->pitch;
1676 return y*dest->pitch/2;
1680 return y*dest->pitch;
1684 return y*dest->pitch/4;
1692 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1694 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1696 switch (surface->format->BytesPerPixel)
1700 /* Assuming 8-bpp */
1701 *((Uint8 *)surface->pixels + ypitch + x) = color;
1707 /* Probably 15-bpp or 16-bpp */
1708 *((Uint16 *)surface->pixels + ypitch + x) = color;
1714 /* Slow 24-bpp mode, usually not used */
1718 /* Gack - slow, but endian correct */
1719 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1720 shift = surface->format->Rshift;
1721 *(pix+shift/8) = color>>shift;
1722 shift = surface->format->Gshift;
1723 *(pix+shift/8) = color>>shift;
1724 shift = surface->format->Bshift;
1725 *(pix+shift/8) = color>>shift;
1731 /* Probably 32-bpp */
1732 *((Uint32 *)surface->pixels + ypitch + x) = color;
1739 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1744 if (SDL_MUSTLOCK(Surface))
1746 if (SDL_LockSurface(Surface) < 0)
1759 /* Do the clipping */
1760 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1764 if (x2 > Surface->w - 1)
1765 x2 = Surface->w - 1;
1772 SDL_FillRect(Surface, &l, Color);
1774 if (SDL_MUSTLOCK(Surface))
1776 SDL_UnlockSurface(Surface);
1780 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1781 Uint8 R, Uint8 G, Uint8 B)
1783 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1786 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1797 /* Do the clipping */
1798 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1802 if (x2 > Surface->w - 1)
1803 x2 = Surface->w - 1;
1810 SDL_FillRect(Surface, &l, Color);
1813 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1818 if (SDL_MUSTLOCK(Surface))
1820 if (SDL_LockSurface(Surface) < 0)
1833 /* Do the clipping */
1834 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1838 if (y2 > Surface->h - 1)
1839 y2 = Surface->h - 1;
1846 SDL_FillRect(Surface, &l, Color);
1848 if (SDL_MUSTLOCK(Surface))
1850 SDL_UnlockSurface(Surface);
1854 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1855 Uint8 R, Uint8 G, Uint8 B)
1857 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1860 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1871 /* Do the clipping */
1872 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1876 if (y2 > Surface->h - 1)
1877 y2 = Surface->h - 1;
1884 SDL_FillRect(Surface, &l, Color);
1887 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1888 Sint16 x2, Sint16 y2, Uint32 Color,
1889 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1892 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1897 sdx = (dx < 0) ? -1 : 1;
1898 sdy = (dy < 0) ? -1 : 1;
1910 for (x = 0; x < dx; x++)
1912 Callback(Surface, px, py, Color);
1926 for (y = 0; y < dy; y++)
1928 Callback(Surface, px, py, Color);
1942 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1943 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1944 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1947 sge_DoLine(Surface, X1, Y1, X2, Y2,
1948 SDL_MapRGB(Surface->format, R, G, B), Callback);
1951 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1954 if (SDL_MUSTLOCK(Surface))
1956 if (SDL_LockSurface(Surface) < 0)
1961 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1963 /* unlock the display */
1964 if (SDL_MUSTLOCK(Surface))
1966 SDL_UnlockSurface(Surface);
1970 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1971 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1973 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1976 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1978 if (dst_bitmap == backbuffer || dst_bitmap == window)
1984 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1989 -----------------------------------------------------------------------------
1990 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1991 -----------------------------------------------------------------------------
1994 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1995 int width, int height, Uint32 color)
1999 for (y = src_y; y < src_y + height; y++)
2001 for (x = src_x; x < src_x + width; x++)
2003 Uint32 pixel = SDLGetPixel(bitmap, x, y);
2005 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
2010 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
2011 int src_x, int src_y, int width, int height,
2012 int dst_x, int dst_y)
2016 for (y = 0; y < height; y++)
2018 for (x = 0; x < width; x++)
2020 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
2022 if (pixel != BLACK_PIXEL)
2023 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
2029 /* ========================================================================= */
2030 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
2031 /* (Rotozoomer) by Andreas Schiffler */
2032 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
2033 /* ========================================================================= */
2036 -----------------------------------------------------------------------------
2039 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
2040 -----------------------------------------------------------------------------
2051 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
2054 tColorRGBA *sp, *csp, *dp;
2058 sp = csp = (tColorRGBA *) src->pixels;
2059 dp = (tColorRGBA *) dst->pixels;
2060 dgap = dst->pitch - dst->w * 4;
2062 for (y = 0; y < dst->h; y++)
2066 for (x = 0; x < dst->w; x++)
2068 tColorRGBA *sp0 = sp;
2069 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2070 tColorRGBA *sp00 = &sp0[0];
2071 tColorRGBA *sp01 = &sp0[1];
2072 tColorRGBA *sp10 = &sp1[0];
2073 tColorRGBA *sp11 = &sp1[1];
2076 /* create new color pixel from all four source color pixels */
2077 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2078 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2079 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2080 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2085 /* advance source pointers */
2088 /* advance destination pointer */
2092 /* advance source pointer */
2093 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2095 /* advance destination pointers */
2096 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2102 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2104 int x, y, *sax, *say, *csax, *csay;
2106 tColorRGBA *sp, *csp, *csp0, *dp;
2109 /* use specialized zoom function when scaling down to exactly half size */
2110 if (src->w == 2 * dst->w &&
2111 src->h == 2 * dst->h)
2112 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2114 /* variable setup */
2115 sx = (float) src->w / (float) dst->w;
2116 sy = (float) src->h / (float) dst->h;
2118 /* allocate memory for row increments */
2119 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2120 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2122 /* precalculate row increments */
2123 for (x = 0; x <= dst->w; x++)
2124 *csax++ = (int)(sx * x);
2126 for (y = 0; y <= dst->h; y++)
2127 *csay++ = (int)(sy * y);
2130 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2131 dp = (tColorRGBA *) dst->pixels;
2132 dgap = dst->pitch - dst->w * 4;
2135 for (y = 0; y < dst->h; y++)
2140 for (x = 0; x < dst->w; x++)
2145 /* advance source pointers */
2149 /* advance destination pointer */
2153 /* advance source pointer */
2155 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2157 /* advance destination pointers */
2158 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2168 -----------------------------------------------------------------------------
2171 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2172 -----------------------------------------------------------------------------
2175 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2177 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2178 Uint8 *sp, *dp, *csp;
2181 /* variable setup */
2182 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2183 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2185 /* allocate memory for row increments */
2186 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2187 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2189 /* precalculate row increments */
2192 for (x = 0; x < dst->w; x++)
2195 *csax = (csx >> 16);
2202 for (y = 0; y < dst->h; y++)
2205 *csay = (csy >> 16);
2212 for (x = 0; x < dst->w; x++)
2220 for (y = 0; y < dst->h; y++)
2227 sp = csp = (Uint8 *) src->pixels;
2228 dp = (Uint8 *) dst->pixels;
2229 dgap = dst->pitch - dst->w;
2233 for (y = 0; y < dst->h; y++)
2237 for (x = 0; x < dst->w; x++)
2242 /* advance source pointers */
2246 /* advance destination pointer */
2250 /* advance source pointer (for row) */
2251 csp += ((*csay) * src->pitch);
2254 /* advance destination pointers */
2265 -----------------------------------------------------------------------------
2268 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2269 'zoomx' and 'zoomy' are scaling factors for width and height.
2270 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2271 into a 32bit RGBA format on the fly.
2272 -----------------------------------------------------------------------------
2275 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2277 SDL_Surface *zoom_src = NULL;
2278 SDL_Surface *zoom_dst = NULL;
2279 boolean is_converted = FALSE;
2286 /* determine if source surface is 32 bit or 8 bit */
2287 is_32bit = (src->format->BitsPerPixel == 32);
2289 if (is_32bit || src->format->BitsPerPixel == 8)
2291 /* use source surface 'as is' */
2296 /* new source surface is 32 bit with a defined RGB ordering */
2297 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2298 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2299 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2301 is_converted = TRUE;
2304 /* allocate surface to completely contain the zoomed surface */
2307 /* target surface is 32 bit with source RGBA/ABGR ordering */
2308 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2309 zoom_src->format->Rmask,
2310 zoom_src->format->Gmask,
2311 zoom_src->format->Bmask, 0);
2315 /* target surface is 8 bit */
2316 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2320 /* lock source surface */
2321 SDL_LockSurface(zoom_src);
2323 /* check which kind of surface we have */
2326 /* call the 32 bit transformation routine to do the zooming */
2327 zoomSurfaceRGBA(zoom_src, zoom_dst);
2332 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2333 zoom_dst->format->palette->colors[i] =
2334 zoom_src->format->palette->colors[i];
2335 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2337 /* call the 8 bit transformation routine to do the zooming */
2338 zoomSurfaceY(zoom_src, zoom_dst);
2341 /* unlock source surface */
2342 SDL_UnlockSurface(zoom_src);
2344 /* free temporary surface */
2346 SDL_FreeSurface(zoom_src);
2348 /* return destination surface */
2352 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2354 Bitmap *dst_bitmap = CreateBitmapStruct();
2355 SDL_Surface **dst_surface = &dst_bitmap->surface;
2357 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2358 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2360 dst_bitmap->width = dst_width;
2361 dst_bitmap->height = dst_height;
2363 /* create zoomed temporary surface from source surface */
2364 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2366 /* create native format destination surface from zoomed temporary surface */
2367 SDLSetNativeSurface(dst_surface);
2373 /* ========================================================================= */
2374 /* load image to bitmap */
2375 /* ========================================================================= */
2377 Bitmap *SDLLoadImage(char *filename)
2379 Bitmap *new_bitmap = CreateBitmapStruct();
2380 SDL_Surface *sdl_image_tmp;
2382 print_timestamp_init("SDLLoadImage");
2384 print_timestamp_time(getBaseNamePtr(filename));
2386 /* load image to temporary surface */
2387 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2389 SetError("IMG_Load(): %s", SDL_GetError());
2394 print_timestamp_time("IMG_Load");
2396 UPDATE_BUSY_STATE();
2398 /* create native non-transparent surface for current image */
2399 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2401 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2406 print_timestamp_time("SDL_DisplayFormat (opaque)");
2408 UPDATE_BUSY_STATE();
2410 /* create native transparent surface for current image */
2411 if (sdl_image_tmp->format->Amask == 0)
2412 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2413 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2415 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2417 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2422 print_timestamp_time("SDL_DisplayFormat (masked)");
2424 UPDATE_BUSY_STATE();
2426 /* free temporary surface */
2427 SDL_FreeSurface(sdl_image_tmp);
2429 new_bitmap->width = new_bitmap->surface->w;
2430 new_bitmap->height = new_bitmap->surface->h;
2432 print_timestamp_done("SDLLoadImage");
2438 /* ------------------------------------------------------------------------- */
2439 /* custom cursor fuctions */
2440 /* ------------------------------------------------------------------------- */
2442 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2444 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2445 cursor_info->width, cursor_info->height,
2446 cursor_info->hot_x, cursor_info->hot_y);
2449 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2451 static struct MouseCursorInfo *last_cursor_info = NULL;
2452 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2453 static SDL_Cursor *cursor_default = NULL;
2454 static SDL_Cursor *cursor_current = NULL;
2456 /* if invoked for the first time, store the SDL default cursor */
2457 if (cursor_default == NULL)
2458 cursor_default = SDL_GetCursor();
2460 /* only create new cursor if cursor info (custom only) has changed */
2461 if (cursor_info != NULL && cursor_info != last_cursor_info)
2463 cursor_current = create_cursor(cursor_info);
2464 last_cursor_info = cursor_info;
2467 /* only set new cursor if cursor info (custom or NULL) has changed */
2468 if (cursor_info != last_cursor_info2)
2469 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2471 last_cursor_info2 = cursor_info;
2475 /* ========================================================================= */
2476 /* audio functions */
2477 /* ========================================================================= */
2479 void SDLOpenAudio(void)
2481 #if !defined(TARGET_SDL2)
2482 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2483 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2486 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2488 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2492 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2493 AUDIO_NUM_CHANNELS_STEREO,
2494 setup.system.audio_fragment_size) < 0)
2496 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2500 audio.sound_available = TRUE;
2501 audio.music_available = TRUE;
2502 audio.loops_available = TRUE;
2503 audio.sound_enabled = TRUE;
2505 /* set number of available mixer channels */
2506 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2507 audio.music_channel = MUSIC_CHANNEL;
2508 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2510 Mixer_InitChannels();
2513 void SDLCloseAudio(void)
2516 Mix_HaltChannel(-1);
2519 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2523 /* ========================================================================= */
2524 /* event functions */
2525 /* ========================================================================= */
2527 void SDLNextEvent(Event *event)
2529 SDL_WaitEvent(event);
2531 if (event->type == EVENT_BUTTONPRESS ||
2532 event->type == EVENT_BUTTONRELEASE)
2534 if (((ButtonEvent *)event)->x > video_xoffset)
2535 ((ButtonEvent *)event)->x -= video_xoffset;
2537 ((ButtonEvent *)event)->x = 0;
2538 if (((ButtonEvent *)event)->y > video_yoffset)
2539 ((ButtonEvent *)event)->y -= video_yoffset;
2541 ((ButtonEvent *)event)->y = 0;
2543 else if (event->type == EVENT_MOTIONNOTIFY)
2545 if (((MotionEvent *)event)->x > video_xoffset)
2546 ((MotionEvent *)event)->x -= video_xoffset;
2548 ((MotionEvent *)event)->x = 0;
2549 if (((MotionEvent *)event)->y > video_yoffset)
2550 ((MotionEvent *)event)->y -= video_yoffset;
2552 ((MotionEvent *)event)->y = 0;
2556 void SDLHandleWindowManagerEvent(Event *event)
2559 #if defined(PLATFORM_WIN32)
2560 // experimental drag and drop code
2562 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2563 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2565 #if defined(TARGET_SDL2)
2566 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2568 if (syswmmsg->msg == WM_DROPFILES)
2571 #if defined(TARGET_SDL2)
2572 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2574 HDROP hdrop = (HDROP)syswmmsg->wParam;
2578 printf("::: SDL_SYSWMEVENT:\n");
2580 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2582 for (i = 0; i < num_files; i++)
2584 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2585 char buffer[buffer_len + 1];
2587 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2589 printf("::: - '%s'\n", buffer);
2592 #if defined(TARGET_SDL2)
2593 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2595 DragFinish((HDROP)syswmmsg->wParam);
2603 /* ========================================================================= */
2604 /* joystick functions */
2605 /* ========================================================================= */
2607 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2608 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2609 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2611 static boolean SDLOpenJoystick(int nr)
2613 if (nr < 0 || nr > MAX_PLAYERS)
2616 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2619 static void SDLCloseJoystick(int nr)
2621 if (nr < 0 || nr > MAX_PLAYERS)
2624 SDL_JoystickClose(sdl_joystick[nr]);
2626 sdl_joystick[nr] = NULL;
2629 static boolean SDLCheckJoystickOpened(int nr)
2631 if (nr < 0 || nr > MAX_PLAYERS)
2634 #if defined(TARGET_SDL2)
2635 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2637 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2641 void HandleJoystickEvent(Event *event)
2645 case SDL_JOYAXISMOTION:
2646 if (event->jaxis.axis < 2)
2647 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2650 case SDL_JOYBUTTONDOWN:
2651 if (event->jbutton.button < 2)
2652 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2655 case SDL_JOYBUTTONUP:
2656 if (event->jbutton.button < 2)
2657 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2665 void SDLInitJoysticks()
2667 static boolean sdl_joystick_subsystem_initialized = FALSE;
2668 boolean print_warning = !sdl_joystick_subsystem_initialized;
2671 if (!sdl_joystick_subsystem_initialized)
2673 sdl_joystick_subsystem_initialized = TRUE;
2675 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2677 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2682 for (i = 0; i < MAX_PLAYERS; i++)
2684 /* get configured joystick for this player */
2685 char *device_name = setup.input[i].joy.device_name;
2686 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2688 if (joystick_nr >= SDL_NumJoysticks())
2690 if (setup.input[i].use_joystick && print_warning)
2691 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2696 /* misuse joystick file descriptor variable to store joystick number */
2697 joystick.fd[i] = joystick_nr;
2699 if (joystick_nr == -1)
2702 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2703 if (SDLCheckJoystickOpened(joystick_nr))
2704 SDLCloseJoystick(joystick_nr);
2706 if (!setup.input[i].use_joystick)
2709 if (!SDLOpenJoystick(joystick_nr))
2712 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2717 joystick.status = JOYSTICK_ACTIVATED;
2721 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2723 if (nr < 0 || nr >= MAX_PLAYERS)
2727 *x = sdl_js_axis[nr][0];
2729 *y = sdl_js_axis[nr][1];
2732 *b1 = sdl_js_button[nr][0];
2734 *b2 = sdl_js_button[nr][1];