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 else if (fade_mode & FADE_TYPE_FADE_IN)
1154 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1155 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1157 else /* FADE_TYPE_FADE_OUT */
1159 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1160 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1163 time_current = SDL_GetTicks();
1165 if (fade_mode == FADE_MODE_MELT)
1167 boolean done = FALSE;
1168 int melt_pixels = 2;
1169 int melt_columns = width / melt_pixels;
1170 int ypos[melt_columns];
1171 int max_steps = height / 8 + 32;
1176 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1177 #if defined(TARGET_SDL2)
1178 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1180 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1183 ypos[0] = -GetSimpleRandom(16);
1185 for (i = 1 ; i < melt_columns; i++)
1187 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1189 ypos[i] = ypos[i - 1] + r;
1202 time_last = time_current;
1203 time_current = SDL_GetTicks();
1204 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1205 steps_final = MIN(MAX(0, steps), max_steps);
1209 done = (steps_done >= steps_final);
1211 for (i = 0 ; i < melt_columns; i++)
1219 else if (ypos[i] < height)
1224 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1226 if (ypos[i] + dy >= height)
1227 dy = height - ypos[i];
1229 /* copy part of (appearing) target surface to upper area */
1230 src_rect.x = src_x + i * melt_pixels;
1231 // src_rect.y = src_y + ypos[i];
1233 src_rect.w = melt_pixels;
1235 src_rect.h = ypos[i] + dy;
1237 dst_rect.x = dst_x + i * melt_pixels;
1238 // dst_rect.y = dst_y + ypos[i];
1241 if (steps_done >= steps_final)
1242 SDL_BlitSurface(surface_target, &src_rect,
1243 surface_screen, &dst_rect);
1247 /* copy part of (disappearing) source surface to lower area */
1248 src_rect.x = src_x + i * melt_pixels;
1250 src_rect.w = melt_pixels;
1251 src_rect.h = height - ypos[i];
1253 dst_rect.x = dst_x + i * melt_pixels;
1254 dst_rect.y = dst_y + ypos[i];
1256 if (steps_done >= steps_final)
1257 SDL_BlitSurface(surface_source, &src_rect,
1258 surface_screen, &dst_rect);
1264 src_rect.x = src_x + i * melt_pixels;
1266 src_rect.w = melt_pixels;
1267 src_rect.h = height;
1269 dst_rect.x = dst_x + i * melt_pixels;
1272 if (steps_done >= steps_final)
1273 SDL_BlitSurface(surface_target, &src_rect,
1274 surface_screen, &dst_rect);
1278 if (steps_done >= steps_final)
1280 if (draw_border_function != NULL)
1281 draw_border_function();
1283 UpdateScreen(&dst_rect2);
1287 else if (fade_mode == FADE_MODE_CURTAIN)
1291 int xx_size = width / 2;
1293 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1294 #if defined(TARGET_SDL2)
1295 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1297 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1300 for (xx = 0; xx < xx_size;)
1302 time_last = time_current;
1303 time_current = SDL_GetTicks();
1304 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1305 xx_final = MIN(MAX(0, xx), xx_size);
1310 src_rect.h = height;
1315 /* draw new (target) image to screen buffer */
1316 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1318 if (xx_final < xx_size)
1320 src_rect.w = xx_size - xx_final;
1321 src_rect.h = height;
1323 /* draw old (source) image to screen buffer (left side) */
1325 src_rect.x = src_x + xx_final;
1328 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1330 /* draw old (source) image to screen buffer (right side) */
1332 src_rect.x = src_x + xx_size;
1333 dst_rect.x = dst_x + xx_size + xx_final;
1335 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1338 if (draw_border_function != NULL)
1339 draw_border_function();
1341 /* only update the region of the screen that is affected from fading */
1342 UpdateScreen(&dst_rect2);
1345 else /* fading in, fading out or cross-fading */
1350 for (alpha = 0.0; alpha < 255.0;)
1352 time_last = time_current;
1353 time_current = SDL_GetTicks();
1354 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1355 alpha_final = MIN(MAX(0, alpha), 255);
1357 /* draw existing (source) image to screen buffer */
1358 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1360 /* draw new (target) image to screen buffer using alpha blending */
1361 #if defined(TARGET_SDL2)
1362 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1363 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1365 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1367 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1369 if (draw_border_function != NULL)
1370 draw_border_function();
1372 /* only update the region of the screen that is affected from fading */
1373 UpdateScreen(&dst_rect);
1379 unsigned int time_post_delay;
1381 time_current = SDL_GetTicks();
1382 time_post_delay = time_current + post_delay;
1384 while (time_current < time_post_delay)
1386 // do not wait longer than 10 ms at a time to be able to ...
1387 Delay(MIN(10, time_post_delay - time_current));
1389 // ... continue drawing global animations during post delay
1392 time_current = SDL_GetTicks();
1396 // restore function for drawing global masked border
1397 gfx.draw_global_border_function = draw_global_border_function;
1400 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1401 int to_x, int to_y, Uint32 color)
1403 SDL_Surface *surface = dst_bitmap->surface;
1407 swap_numbers(&from_x, &to_x);
1410 swap_numbers(&from_y, &to_y);
1414 rect.w = (to_x - from_x + 1);
1415 rect.h = (to_y - from_y + 1);
1417 if (dst_bitmap == backbuffer || dst_bitmap == window)
1419 rect.x += video_xoffset;
1420 rect.y += video_yoffset;
1423 SDL_FillRect(surface, &rect, color);
1426 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1427 int to_x, int to_y, Uint32 color)
1429 if (dst_bitmap == backbuffer || dst_bitmap == window)
1431 from_x += video_xoffset;
1432 from_y += video_yoffset;
1433 to_x += video_xoffset;
1434 to_y += video_yoffset;
1437 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1440 #if ENABLE_UNUSED_CODE
1441 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1442 int num_points, Uint32 color)
1447 for (i = 0; i < num_points - 1; i++)
1449 for (x = 0; x < line_width; x++)
1451 for (y = 0; y < line_width; y++)
1453 int dx = x - line_width / 2;
1454 int dy = y - line_width / 2;
1456 if ((x == 0 && y == 0) ||
1457 (x == 0 && y == line_width - 1) ||
1458 (x == line_width - 1 && y == 0) ||
1459 (x == line_width - 1 && y == line_width - 1))
1462 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1463 points[i+1].x + dx, points[i+1].y + dy, color);
1470 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1472 SDL_Surface *surface = src_bitmap->surface;
1474 if (src_bitmap == backbuffer || src_bitmap == window)
1480 switch (surface->format->BytesPerPixel)
1482 case 1: /* assuming 8-bpp */
1484 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1488 case 2: /* probably 15-bpp or 16-bpp */
1490 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1494 case 3: /* slow 24-bpp mode; usually not used */
1496 /* does this work? */
1497 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1501 shift = surface->format->Rshift;
1502 color |= *(pix + shift / 8) >> shift;
1503 shift = surface->format->Gshift;
1504 color |= *(pix + shift / 8) >> shift;
1505 shift = surface->format->Bshift;
1506 color |= *(pix + shift / 8) >> shift;
1512 case 4: /* probably 32-bpp */
1514 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1523 /* ========================================================================= */
1524 /* The following functions were taken from the SGE library */
1525 /* (SDL Graphics Extension Library) by Anders Lindström */
1526 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1527 /* ========================================================================= */
1529 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1531 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1533 switch (surface->format->BytesPerPixel)
1537 /* Assuming 8-bpp */
1538 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1544 /* Probably 15-bpp or 16-bpp */
1545 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1551 /* Slow 24-bpp mode, usually not used */
1555 /* Gack - slow, but endian correct */
1556 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1557 shift = surface->format->Rshift;
1558 *(pix+shift/8) = color>>shift;
1559 shift = surface->format->Gshift;
1560 *(pix+shift/8) = color>>shift;
1561 shift = surface->format->Bshift;
1562 *(pix+shift/8) = color>>shift;
1568 /* Probably 32-bpp */
1569 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1576 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1577 Uint8 R, Uint8 G, Uint8 B)
1579 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1582 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1584 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1587 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1589 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1592 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1597 /* Gack - slow, but endian correct */
1598 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1599 shift = surface->format->Rshift;
1600 *(pix+shift/8) = color>>shift;
1601 shift = surface->format->Gshift;
1602 *(pix+shift/8) = color>>shift;
1603 shift = surface->format->Bshift;
1604 *(pix+shift/8) = color>>shift;
1607 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1609 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1612 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1614 switch (dest->format->BytesPerPixel)
1617 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1621 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1625 _PutPixel24(dest,x,y,color);
1629 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1634 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1636 if (SDL_MUSTLOCK(surface))
1638 if (SDL_LockSurface(surface) < 0)
1644 _PutPixel(surface, x, y, color);
1646 if (SDL_MUSTLOCK(surface))
1648 SDL_UnlockSurface(surface);
1652 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1653 Uint8 r, Uint8 g, Uint8 b)
1655 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1658 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1660 if (y >= 0 && y <= dest->h - 1)
1662 switch (dest->format->BytesPerPixel)
1665 return y*dest->pitch;
1669 return y*dest->pitch/2;
1673 return y*dest->pitch;
1677 return y*dest->pitch/4;
1685 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1687 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1689 switch (surface->format->BytesPerPixel)
1693 /* Assuming 8-bpp */
1694 *((Uint8 *)surface->pixels + ypitch + x) = color;
1700 /* Probably 15-bpp or 16-bpp */
1701 *((Uint16 *)surface->pixels + ypitch + x) = color;
1707 /* Slow 24-bpp mode, usually not used */
1711 /* Gack - slow, but endian correct */
1712 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1713 shift = surface->format->Rshift;
1714 *(pix+shift/8) = color>>shift;
1715 shift = surface->format->Gshift;
1716 *(pix+shift/8) = color>>shift;
1717 shift = surface->format->Bshift;
1718 *(pix+shift/8) = color>>shift;
1724 /* Probably 32-bpp */
1725 *((Uint32 *)surface->pixels + ypitch + x) = color;
1732 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1737 if (SDL_MUSTLOCK(Surface))
1739 if (SDL_LockSurface(Surface) < 0)
1752 /* Do the clipping */
1753 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1757 if (x2 > Surface->w - 1)
1758 x2 = Surface->w - 1;
1765 SDL_FillRect(Surface, &l, Color);
1767 if (SDL_MUSTLOCK(Surface))
1769 SDL_UnlockSurface(Surface);
1773 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1774 Uint8 R, Uint8 G, Uint8 B)
1776 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1779 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1790 /* Do the clipping */
1791 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1795 if (x2 > Surface->w - 1)
1796 x2 = Surface->w - 1;
1803 SDL_FillRect(Surface, &l, Color);
1806 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1811 if (SDL_MUSTLOCK(Surface))
1813 if (SDL_LockSurface(Surface) < 0)
1826 /* Do the clipping */
1827 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1831 if (y2 > Surface->h - 1)
1832 y2 = Surface->h - 1;
1839 SDL_FillRect(Surface, &l, Color);
1841 if (SDL_MUSTLOCK(Surface))
1843 SDL_UnlockSurface(Surface);
1847 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1848 Uint8 R, Uint8 G, Uint8 B)
1850 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1853 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1864 /* Do the clipping */
1865 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1869 if (y2 > Surface->h - 1)
1870 y2 = Surface->h - 1;
1877 SDL_FillRect(Surface, &l, Color);
1880 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1881 Sint16 x2, Sint16 y2, Uint32 Color,
1882 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1885 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1890 sdx = (dx < 0) ? -1 : 1;
1891 sdy = (dy < 0) ? -1 : 1;
1903 for (x = 0; x < dx; x++)
1905 Callback(Surface, px, py, Color);
1919 for (y = 0; y < dy; y++)
1921 Callback(Surface, px, py, Color);
1935 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1936 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1937 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1940 sge_DoLine(Surface, X1, Y1, X2, Y2,
1941 SDL_MapRGB(Surface->format, R, G, B), Callback);
1944 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1947 if (SDL_MUSTLOCK(Surface))
1949 if (SDL_LockSurface(Surface) < 0)
1954 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1956 /* unlock the display */
1957 if (SDL_MUSTLOCK(Surface))
1959 SDL_UnlockSurface(Surface);
1963 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1964 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1966 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1969 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1971 if (dst_bitmap == backbuffer || dst_bitmap == window)
1977 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1982 -----------------------------------------------------------------------------
1983 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1984 -----------------------------------------------------------------------------
1987 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1988 int width, int height, Uint32 color)
1992 for (y = src_y; y < src_y + height; y++)
1994 for (x = src_x; x < src_x + width; x++)
1996 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1998 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
2003 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
2004 int src_x, int src_y, int width, int height,
2005 int dst_x, int dst_y)
2009 for (y = 0; y < height; y++)
2011 for (x = 0; x < width; x++)
2013 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
2015 if (pixel != BLACK_PIXEL)
2016 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
2022 /* ========================================================================= */
2023 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
2024 /* (Rotozoomer) by Andreas Schiffler */
2025 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
2026 /* ========================================================================= */
2029 -----------------------------------------------------------------------------
2032 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
2033 -----------------------------------------------------------------------------
2044 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
2047 tColorRGBA *sp, *csp, *dp;
2051 sp = csp = (tColorRGBA *) src->pixels;
2052 dp = (tColorRGBA *) dst->pixels;
2053 dgap = dst->pitch - dst->w * 4;
2055 for (y = 0; y < dst->h; y++)
2059 for (x = 0; x < dst->w; x++)
2061 tColorRGBA *sp0 = sp;
2062 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2063 tColorRGBA *sp00 = &sp0[0];
2064 tColorRGBA *sp01 = &sp0[1];
2065 tColorRGBA *sp10 = &sp1[0];
2066 tColorRGBA *sp11 = &sp1[1];
2069 /* create new color pixel from all four source color pixels */
2070 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2071 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2072 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2073 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2078 /* advance source pointers */
2081 /* advance destination pointer */
2085 /* advance source pointer */
2086 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2088 /* advance destination pointers */
2089 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2095 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2097 int x, y, *sax, *say, *csax, *csay;
2099 tColorRGBA *sp, *csp, *csp0, *dp;
2102 /* use specialized zoom function when scaling down to exactly half size */
2103 if (src->w == 2 * dst->w &&
2104 src->h == 2 * dst->h)
2105 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2107 /* variable setup */
2108 sx = (float) src->w / (float) dst->w;
2109 sy = (float) src->h / (float) dst->h;
2111 /* allocate memory for row increments */
2112 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2113 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2115 /* precalculate row increments */
2116 for (x = 0; x <= dst->w; x++)
2117 *csax++ = (int)(sx * x);
2119 for (y = 0; y <= dst->h; y++)
2120 *csay++ = (int)(sy * y);
2123 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2124 dp = (tColorRGBA *) dst->pixels;
2125 dgap = dst->pitch - dst->w * 4;
2128 for (y = 0; y < dst->h; y++)
2133 for (x = 0; x < dst->w; x++)
2138 /* advance source pointers */
2142 /* advance destination pointer */
2146 /* advance source pointer */
2148 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2150 /* advance destination pointers */
2151 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2161 -----------------------------------------------------------------------------
2164 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2165 -----------------------------------------------------------------------------
2168 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2170 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2171 Uint8 *sp, *dp, *csp;
2174 /* variable setup */
2175 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2176 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2178 /* allocate memory for row increments */
2179 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2180 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2182 /* precalculate row increments */
2185 for (x = 0; x < dst->w; x++)
2188 *csax = (csx >> 16);
2195 for (y = 0; y < dst->h; y++)
2198 *csay = (csy >> 16);
2205 for (x = 0; x < dst->w; x++)
2213 for (y = 0; y < dst->h; y++)
2220 sp = csp = (Uint8 *) src->pixels;
2221 dp = (Uint8 *) dst->pixels;
2222 dgap = dst->pitch - dst->w;
2226 for (y = 0; y < dst->h; y++)
2230 for (x = 0; x < dst->w; x++)
2235 /* advance source pointers */
2239 /* advance destination pointer */
2243 /* advance source pointer (for row) */
2244 csp += ((*csay) * src->pitch);
2247 /* advance destination pointers */
2258 -----------------------------------------------------------------------------
2261 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2262 'zoomx' and 'zoomy' are scaling factors for width and height.
2263 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2264 into a 32bit RGBA format on the fly.
2265 -----------------------------------------------------------------------------
2268 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2270 SDL_Surface *zoom_src = NULL;
2271 SDL_Surface *zoom_dst = NULL;
2272 boolean is_converted = FALSE;
2279 /* determine if source surface is 32 bit or 8 bit */
2280 is_32bit = (src->format->BitsPerPixel == 32);
2282 if (is_32bit || src->format->BitsPerPixel == 8)
2284 /* use source surface 'as is' */
2289 /* new source surface is 32 bit with a defined RGB ordering */
2290 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2291 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2292 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2294 is_converted = TRUE;
2297 /* allocate surface to completely contain the zoomed surface */
2300 /* target surface is 32 bit with source RGBA/ABGR ordering */
2301 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2302 zoom_src->format->Rmask,
2303 zoom_src->format->Gmask,
2304 zoom_src->format->Bmask, 0);
2308 /* target surface is 8 bit */
2309 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2313 /* lock source surface */
2314 SDL_LockSurface(zoom_src);
2316 /* check which kind of surface we have */
2319 /* call the 32 bit transformation routine to do the zooming */
2320 zoomSurfaceRGBA(zoom_src, zoom_dst);
2325 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2326 zoom_dst->format->palette->colors[i] =
2327 zoom_src->format->palette->colors[i];
2328 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2330 /* call the 8 bit transformation routine to do the zooming */
2331 zoomSurfaceY(zoom_src, zoom_dst);
2334 /* unlock source surface */
2335 SDL_UnlockSurface(zoom_src);
2337 /* free temporary surface */
2339 SDL_FreeSurface(zoom_src);
2341 /* return destination surface */
2345 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2347 Bitmap *dst_bitmap = CreateBitmapStruct();
2348 SDL_Surface **dst_surface = &dst_bitmap->surface;
2350 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2351 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2353 dst_bitmap->width = dst_width;
2354 dst_bitmap->height = dst_height;
2356 /* create zoomed temporary surface from source surface */
2357 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2359 /* create native format destination surface from zoomed temporary surface */
2360 SDLSetNativeSurface(dst_surface);
2366 /* ========================================================================= */
2367 /* load image to bitmap */
2368 /* ========================================================================= */
2370 Bitmap *SDLLoadImage(char *filename)
2372 Bitmap *new_bitmap = CreateBitmapStruct();
2373 SDL_Surface *sdl_image_tmp;
2375 print_timestamp_init("SDLLoadImage");
2377 print_timestamp_time(getBaseNamePtr(filename));
2379 /* load image to temporary surface */
2380 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2382 SetError("IMG_Load(): %s", SDL_GetError());
2387 print_timestamp_time("IMG_Load");
2389 UPDATE_BUSY_STATE();
2391 /* create native non-transparent surface for current image */
2392 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2394 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2399 print_timestamp_time("SDL_DisplayFormat (opaque)");
2401 UPDATE_BUSY_STATE();
2403 /* create native transparent surface for current image */
2404 if (sdl_image_tmp->format->Amask == 0)
2405 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2406 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2408 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2410 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2415 print_timestamp_time("SDL_DisplayFormat (masked)");
2417 UPDATE_BUSY_STATE();
2419 /* free temporary surface */
2420 SDL_FreeSurface(sdl_image_tmp);
2422 new_bitmap->width = new_bitmap->surface->w;
2423 new_bitmap->height = new_bitmap->surface->h;
2425 print_timestamp_done("SDLLoadImage");
2431 /* ------------------------------------------------------------------------- */
2432 /* custom cursor fuctions */
2433 /* ------------------------------------------------------------------------- */
2435 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2437 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2438 cursor_info->width, cursor_info->height,
2439 cursor_info->hot_x, cursor_info->hot_y);
2442 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2444 static struct MouseCursorInfo *last_cursor_info = NULL;
2445 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2446 static SDL_Cursor *cursor_default = NULL;
2447 static SDL_Cursor *cursor_current = NULL;
2449 /* if invoked for the first time, store the SDL default cursor */
2450 if (cursor_default == NULL)
2451 cursor_default = SDL_GetCursor();
2453 /* only create new cursor if cursor info (custom only) has changed */
2454 if (cursor_info != NULL && cursor_info != last_cursor_info)
2456 cursor_current = create_cursor(cursor_info);
2457 last_cursor_info = cursor_info;
2460 /* only set new cursor if cursor info (custom or NULL) has changed */
2461 if (cursor_info != last_cursor_info2)
2462 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2464 last_cursor_info2 = cursor_info;
2468 /* ========================================================================= */
2469 /* audio functions */
2470 /* ========================================================================= */
2472 void SDLOpenAudio(void)
2474 #if !defined(TARGET_SDL2)
2475 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2476 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2479 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2481 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2485 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2486 AUDIO_NUM_CHANNELS_STEREO,
2487 setup.system.audio_fragment_size) < 0)
2489 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2493 audio.sound_available = TRUE;
2494 audio.music_available = TRUE;
2495 audio.loops_available = TRUE;
2496 audio.sound_enabled = TRUE;
2498 /* set number of available mixer channels */
2499 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2500 audio.music_channel = MUSIC_CHANNEL;
2501 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2503 Mixer_InitChannels();
2506 void SDLCloseAudio(void)
2509 Mix_HaltChannel(-1);
2512 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2516 /* ========================================================================= */
2517 /* event functions */
2518 /* ========================================================================= */
2520 void SDLNextEvent(Event *event)
2522 SDL_WaitEvent(event);
2524 if (event->type == EVENT_BUTTONPRESS ||
2525 event->type == EVENT_BUTTONRELEASE)
2527 if (((ButtonEvent *)event)->x > video_xoffset)
2528 ((ButtonEvent *)event)->x -= video_xoffset;
2530 ((ButtonEvent *)event)->x = 0;
2531 if (((ButtonEvent *)event)->y > video_yoffset)
2532 ((ButtonEvent *)event)->y -= video_yoffset;
2534 ((ButtonEvent *)event)->y = 0;
2536 else if (event->type == EVENT_MOTIONNOTIFY)
2538 if (((MotionEvent *)event)->x > video_xoffset)
2539 ((MotionEvent *)event)->x -= video_xoffset;
2541 ((MotionEvent *)event)->x = 0;
2542 if (((MotionEvent *)event)->y > video_yoffset)
2543 ((MotionEvent *)event)->y -= video_yoffset;
2545 ((MotionEvent *)event)->y = 0;
2549 void SDLHandleWindowManagerEvent(Event *event)
2552 #if defined(PLATFORM_WIN32)
2553 // experimental drag and drop code
2555 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2556 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2558 #if defined(TARGET_SDL2)
2559 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2561 if (syswmmsg->msg == WM_DROPFILES)
2564 #if defined(TARGET_SDL2)
2565 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2567 HDROP hdrop = (HDROP)syswmmsg->wParam;
2571 printf("::: SDL_SYSWMEVENT:\n");
2573 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2575 for (i = 0; i < num_files; i++)
2577 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2578 char buffer[buffer_len + 1];
2580 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2582 printf("::: - '%s'\n", buffer);
2585 #if defined(TARGET_SDL2)
2586 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2588 DragFinish((HDROP)syswmmsg->wParam);
2596 /* ========================================================================= */
2597 /* joystick functions */
2598 /* ========================================================================= */
2600 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2601 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2602 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2604 static boolean SDLOpenJoystick(int nr)
2606 if (nr < 0 || nr > MAX_PLAYERS)
2609 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2612 static void SDLCloseJoystick(int nr)
2614 if (nr < 0 || nr > MAX_PLAYERS)
2617 SDL_JoystickClose(sdl_joystick[nr]);
2619 sdl_joystick[nr] = NULL;
2622 static boolean SDLCheckJoystickOpened(int nr)
2624 if (nr < 0 || nr > MAX_PLAYERS)
2627 #if defined(TARGET_SDL2)
2628 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2630 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2634 void HandleJoystickEvent(Event *event)
2638 case SDL_JOYAXISMOTION:
2639 if (event->jaxis.axis < 2)
2640 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2643 case SDL_JOYBUTTONDOWN:
2644 if (event->jbutton.button < 2)
2645 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2648 case SDL_JOYBUTTONUP:
2649 if (event->jbutton.button < 2)
2650 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2658 void SDLInitJoysticks()
2660 static boolean sdl_joystick_subsystem_initialized = FALSE;
2661 boolean print_warning = !sdl_joystick_subsystem_initialized;
2664 if (!sdl_joystick_subsystem_initialized)
2666 sdl_joystick_subsystem_initialized = TRUE;
2668 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2670 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2675 for (i = 0; i < MAX_PLAYERS; i++)
2677 /* get configured joystick for this player */
2678 char *device_name = setup.input[i].joy.device_name;
2679 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2681 if (joystick_nr >= SDL_NumJoysticks())
2683 if (setup.input[i].use_joystick && print_warning)
2684 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2689 /* misuse joystick file descriptor variable to store joystick number */
2690 joystick.fd[i] = joystick_nr;
2692 if (joystick_nr == -1)
2695 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2696 if (SDLCheckJoystickOpened(joystick_nr))
2697 SDLCloseJoystick(joystick_nr);
2699 if (!setup.input[i].use_joystick)
2702 if (!SDLOpenJoystick(joystick_nr))
2705 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2710 joystick.status = JOYSTICK_ACTIVATED;
2714 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2716 if (nr < 0 || nr >= MAX_PLAYERS)
2720 *x = sdl_js_axis[nr][0];
2722 *y = sdl_js_axis[nr][1];
2725 *b1 = sdl_js_button[nr][0];
2727 *b2 = sdl_js_button[nr][1];