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_stream = NULL;
30 static SDL_Texture *sdl_texture_target = NULL;
31 static boolean fullscreen_enabled = FALSE;
34 static boolean limit_screen_updates = FALSE;
37 /* functions from SGE library */
38 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
40 #if defined(USE_TOUCH_INPUT_OVERLAY)
41 /* functions to draw overlay graphics for touch device input */
42 static void DrawTouchInputOverlay();
45 void SDLLimitScreenUpdates(boolean enable)
47 limit_screen_updates = enable;
50 static void FinalizeScreen(int draw_target)
52 // copy global animations to render target buffer, if defined (below border)
53 if (gfx.draw_global_anim_function != NULL)
54 gfx.draw_global_anim_function(draw_target, DRAW_GLOBAL_ANIM_STAGE_1);
56 // copy global masked border to render target buffer, if defined
57 if (gfx.draw_global_border_function != NULL)
58 gfx.draw_global_border_function(draw_target);
60 // copy global animations to render target buffer, if defined (above border)
61 if (gfx.draw_global_anim_function != NULL)
62 gfx.draw_global_anim_function(draw_target, DRAW_GLOBAL_ANIM_STAGE_2);
65 static void UpdateScreenExt(SDL_Rect *rect, boolean with_frame_delay)
67 static unsigned int update_screen_delay = 0;
68 unsigned int update_screen_delay_value = 50; /* (milliseconds) */
69 SDL_Surface *screen = backbuffer->surface;
71 if (limit_screen_updates &&
72 !DelayReached(&update_screen_delay, update_screen_delay_value))
75 LimitScreenUpdates(FALSE);
79 static int LastFrameCounter = 0;
80 boolean changed = (FrameCounter != LastFrameCounter);
82 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
83 (changed ? "-" : "SAME FRAME UPDATED"));
85 LastFrameCounter = FrameCounter;
94 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP &&
95 gfx.final_screen_bitmap != NULL) // may not be initialized yet
97 // draw global animations using bitmaps instead of using textures
98 // to prevent texture scaling artefacts (this is potentially slower)
100 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
101 gfx.win_xsize, gfx.win_ysize, 0, 0);
103 FinalizeScreen(DRAW_TO_SCREEN);
105 screen = gfx.final_screen_bitmap->surface;
107 // force full window redraw
111 #if defined(TARGET_SDL2)
112 SDL_Texture *sdl_texture = sdl_texture_stream;
114 // deactivate use of target texture if render targets are not supported
115 if ((video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
116 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE) &&
117 sdl_texture_target == NULL)
118 video.screen_rendering_mode = SPECIAL_RENDERING_OFF;
120 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET)
121 sdl_texture = sdl_texture_target;
125 int bytes_x = screen->pitch / video.width;
126 int bytes_y = screen->pitch;
128 SDL_UpdateTexture(sdl_texture, rect,
129 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
134 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
137 int xoff = video.screen_xoffset;
138 int yoff = video.screen_yoffset;
139 SDL_Rect dst_rect_screen = { xoff, yoff, video.width, video.height };
140 SDL_Rect *src_rect1 = NULL, *dst_rect1 = NULL;
141 SDL_Rect *src_rect2 = NULL, *dst_rect2 = NULL;
143 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
144 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
145 dst_rect2 = &dst_rect_screen;
147 dst_rect1 = &dst_rect_screen;
149 #if defined(HAS_SCREEN_KEYBOARD)
150 if (video.shifted_up || video.shifted_up_delay)
152 int time_current = SDL_GetTicks();
153 int pos = video.shifted_up_pos;
154 int pos_last = video.shifted_up_pos_last;
156 if (!DelayReachedExt(&video.shifted_up_delay, video.shifted_up_delay_value,
159 int delay = time_current - video.shifted_up_delay;
160 int delay_value = video.shifted_up_delay_value;
162 pos = pos_last + (pos - pos_last) * delay / delay_value;
166 video.shifted_up_pos_last = pos;
167 video.shifted_up_delay = 0;
170 SDL_Rect src_rect_up = { 0, pos, video.width, video.height - pos };
171 SDL_Rect dst_rect_up = { xoff, yoff, video.width, video.height - pos };
173 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
174 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
176 src_rect2 = &src_rect_up;
177 dst_rect2 = &dst_rect_up;
181 src_rect1 = &src_rect_up;
182 dst_rect1 = &dst_rect_up;
187 // clear render target buffer
188 SDL_RenderClear(sdl_renderer);
190 // set renderer to use target texture for rendering
191 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
192 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
193 SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
195 // copy backbuffer texture to render target buffer
196 if (video.screen_rendering_mode != SPECIAL_RENDERING_TARGET)
197 SDL_RenderCopy(sdl_renderer, sdl_texture_stream, src_rect1, dst_rect1);
199 if (video.screen_rendering_mode != SPECIAL_RENDERING_BITMAP)
200 FinalizeScreen(DRAW_TO_SCREEN);
202 // when using target texture, copy it to screen buffer
203 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
204 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
206 SDL_SetRenderTarget(sdl_renderer, NULL);
207 SDL_RenderCopy(sdl_renderer, sdl_texture_target, src_rect2, dst_rect2);
210 #if defined(USE_TOUCH_INPUT_OVERLAY)
211 // draw overlay graphics for touch device input, if needed
212 DrawTouchInputOverlay();
217 // global synchronization point of the game to align video frame delay
218 if (with_frame_delay)
219 WaitUntilDelayReached(&video.frame_delay, video.frame_delay_value);
221 #if defined(TARGET_SDL2)
222 // show render target buffer on screen
223 SDL_RenderPresent(sdl_renderer);
226 SDL_UpdateRects(screen, 1, rect);
228 SDL_UpdateRect(screen, 0, 0, 0, 0);
232 static void UpdateScreen_WithFrameDelay(SDL_Rect *rect)
234 UpdateScreenExt(rect, TRUE);
237 static void UpdateScreen_WithoutFrameDelay(SDL_Rect *rect)
239 UpdateScreenExt(rect, FALSE);
242 static void SDLSetWindowIcon(char *basename)
244 /* (setting the window icon on Mac OS X would replace the high-quality
245 dock icon with the currently smaller (and uglier) icon from file) */
247 #if !defined(PLATFORM_MACOSX)
248 char *filename = getCustomImageFilename(basename);
249 SDL_Surface *surface;
251 if (filename == NULL)
253 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
258 if ((surface = IMG_Load(filename)) == NULL)
260 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
265 /* set transparent color */
266 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
267 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
269 #if defined(TARGET_SDL2)
270 SDL_SetWindowIcon(sdl_window, surface);
272 SDL_WM_SetIcon(surface, NULL);
277 #if defined(TARGET_SDL2)
279 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
280 SDL_PixelFormat *format2)
282 return (format1->format == format2->format &&
283 format1->BitsPerPixel == format2->BitsPerPixel &&
284 format1->BytesPerPixel == format2->BytesPerPixel &&
285 format1->Rmask == format2->Rmask &&
286 format1->Gmask == format2->Gmask &&
287 format1->Bmask == format2->Bmask);
290 static Pixel SDLGetColorKey(SDL_Surface *surface)
294 if (SDL_GetColorKey(surface, &color_key) != 0)
300 static boolean SDLHasColorKey(SDL_Surface *surface)
302 return (SDLGetColorKey(surface) != -1);
305 static boolean SDLHasAlpha(SDL_Surface *surface)
307 SDL_BlendMode blend_mode;
309 if (SDL_GetSurfaceBlendMode(surface, &blend_mode) != 0)
312 return (blend_mode == SDL_BLENDMODE_BLEND);
315 static void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha)
317 SDL_BlendMode blend_mode = (set ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE);
319 SDL_SetSurfaceBlendMode(surface, blend_mode);
320 SDL_SetSurfaceAlphaMod(surface, alpha);
323 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
325 SDL_PixelFormat format;
326 SDL_Surface *new_surface;
331 if (backbuffer && backbuffer->surface)
333 format = *backbuffer->surface->format;
334 format.Amask = surface->format->Amask; // keep alpha channel
338 format = *surface->format;
341 new_surface = SDL_ConvertSurface(surface, &format, 0);
343 if (new_surface == NULL)
344 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
349 boolean SDLSetNativeSurface(SDL_Surface **surface)
351 SDL_Surface *new_surface;
353 if (surface == NULL ||
355 backbuffer == NULL ||
356 backbuffer->surface == NULL)
359 // if pixel format already optimized for destination surface, do nothing
360 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
363 new_surface = SDLGetNativeSurface(*surface);
365 SDL_FreeSurface(*surface);
367 *surface = new_surface;
374 static Pixel SDLGetColorKey(SDL_Surface *surface)
376 if ((surface->flags & SDL_SRCCOLORKEY) == 0)
379 return surface->format->colorkey;
382 static boolean SDLHasColorKey(SDL_Surface *surface)
384 return (SDLGetColorKey(surface) != -1);
387 static boolean SDLHasAlpha(SDL_Surface *surface)
389 return ((surface->flags & SDL_SRCALPHA) != 0);
392 static void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha)
394 SDL_SetAlpha(surface, (set ? SDL_SRCALPHA : 0), alpha);
397 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
399 SDL_Surface *new_surface;
404 if (!video.initialized)
405 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
406 else if (SDLHasAlpha(surface))
407 new_surface = SDL_DisplayFormatAlpha(surface);
409 new_surface = SDL_DisplayFormat(surface);
411 if (new_surface == NULL)
412 Error(ERR_EXIT, "%s() failed: %s",
413 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
419 boolean SDLSetNativeSurface(SDL_Surface **surface)
421 SDL_Surface *new_surface;
423 if (surface == NULL ||
428 new_surface = SDLGetNativeSurface(*surface);
430 SDL_FreeSurface(*surface);
432 *surface = new_surface;
439 #if defined(TARGET_SDL2)
440 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
442 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
445 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
452 void SDLCreateBitmapTextures(Bitmap *bitmap)
454 #if defined(TARGET_SDL2)
459 SDL_DestroyTexture(bitmap->texture);
460 if (bitmap->texture_masked)
461 SDL_DestroyTexture(bitmap->texture_masked);
463 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
464 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
468 void SDLFreeBitmapTextures(Bitmap *bitmap)
470 #if defined(TARGET_SDL2)
475 SDL_DestroyTexture(bitmap->texture);
476 if (bitmap->texture_masked)
477 SDL_DestroyTexture(bitmap->texture_masked);
479 bitmap->texture = NULL;
480 bitmap->texture_masked = NULL;
484 void SDLInitVideoDisplay(void)
486 #if !defined(TARGET_SDL2)
487 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
488 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
490 SDL_putenv("SDL_VIDEO_CENTERED=1");
493 /* initialize SDL video */
494 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
495 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
497 /* set default SDL depth */
498 #if !defined(TARGET_SDL2)
499 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
501 video.default_depth = 32; // (how to determine video depth in SDL2?)
505 void SDLInitVideoBuffer(boolean fullscreen)
507 video.window_scaling_percent = setup.window_scaling_percent;
508 video.window_scaling_quality = setup.window_scaling_quality;
510 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
512 #if defined(TARGET_SDL2)
513 // SDL 2.0: support for (desktop) fullscreen mode available
514 video.fullscreen_available = TRUE;
516 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
517 video.fullscreen_available = FALSE;
520 /* open SDL video output device (window or fullscreen mode) */
521 if (!SDLSetVideoMode(fullscreen))
522 Error(ERR_EXIT, "setting video mode failed");
524 /* !!! SDL2 can only set the window icon if the window already exists !!! */
525 /* set window icon */
526 SDLSetWindowIcon(program.icon_filename);
528 /* set window and icon title */
529 #if defined(TARGET_SDL2)
530 SDL_SetWindowTitle(sdl_window, program.window_title);
532 SDL_WM_SetCaption(program.window_title, program.window_title);
535 /* SDL cannot directly draw to the visible video framebuffer like X11,
536 but always uses a backbuffer, which is then blitted to the visible
537 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
538 visible video framebuffer with 'SDL_Flip', if the hardware supports
539 this). Therefore do not use an additional backbuffer for drawing, but
540 use a symbolic buffer (distinguishable from the SDL backbuffer) called
541 'window', which indicates that the SDL backbuffer should be updated to
542 the visible video framebuffer when attempting to blit to it.
544 For convenience, it seems to be a good idea to create this symbolic
545 buffer 'window' at the same size as the SDL backbuffer. Although it
546 should never be drawn to directly, it would do no harm nevertheless. */
548 /* create additional (symbolic) buffer for double-buffering */
549 ReCreateBitmap(&window, video.width, video.height);
552 static boolean SDLCreateScreen(boolean fullscreen)
554 SDL_Surface *new_surface = NULL;
556 #if defined(TARGET_SDL2)
557 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
558 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
560 int surface_flags_window = SURFACE_FLAGS;
561 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
564 #if defined(TARGET_SDL2)
566 int renderer_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
568 /* If SDL_CreateRenderer() is called from within a VirtualBox Windows VM
569 _without_ enabling 2D/3D acceleration and/or guest additions installed,
570 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
571 it will try to use accelerated graphics and apparently fails miserably) */
572 int renderer_flags = SDL_RENDERER_SOFTWARE;
575 SDLSetScreenSizeAndOffsets(video.width, video.height);
578 int width = video.width;
579 int height = video.height;
580 int screen_width = video.screen_width;
581 int screen_height = video.screen_height;
582 int surface_flags = (fullscreen ? surface_flags_fullscreen :
583 surface_flags_window);
585 // default window size is unscaled
586 video.window_width = screen_width;
587 video.window_height = screen_height;
589 #if defined(TARGET_SDL2)
591 // store if initial screen mode is fullscreen mode when changing screen size
592 video.fullscreen_initial = fullscreen;
594 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
596 video.window_width = window_scaling_factor * screen_width;
597 video.window_height = window_scaling_factor * screen_height;
599 if (sdl_texture_stream)
601 SDL_DestroyTexture(sdl_texture_stream);
602 sdl_texture_stream = NULL;
605 if (sdl_texture_target)
607 SDL_DestroyTexture(sdl_texture_target);
608 sdl_texture_target = NULL;
611 if (!(fullscreen && fullscreen_enabled))
615 SDL_DestroyRenderer(sdl_renderer);
621 SDL_DestroyWindow(sdl_window);
626 if (sdl_window == NULL)
627 sdl_window = SDL_CreateWindow(program.window_title,
628 SDL_WINDOWPOS_CENTERED,
629 SDL_WINDOWPOS_CENTERED,
634 if (sdl_window != NULL)
636 if (sdl_renderer == NULL)
637 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, renderer_flags);
639 if (sdl_renderer != NULL)
641 SDL_RenderSetLogicalSize(sdl_renderer, screen_width, screen_height);
642 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
643 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
645 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
646 SDL_PIXELFORMAT_ARGB8888,
647 SDL_TEXTUREACCESS_STREAMING,
650 if (SDL_RenderTargetSupported(sdl_renderer))
651 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
652 SDL_PIXELFORMAT_ARGB8888,
653 SDL_TEXTUREACCESS_TARGET,
656 if (sdl_texture_stream != NULL)
658 // use SDL default values for RGB masks and no alpha channel
659 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
661 if (new_surface == NULL)
662 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
666 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
671 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
676 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
681 if (gfx.final_screen_bitmap == NULL)
682 gfx.final_screen_bitmap = CreateBitmapStruct();
684 gfx.final_screen_bitmap->width = width;
685 gfx.final_screen_bitmap->height = height;
687 gfx.final_screen_bitmap->surface =
688 SDL_SetVideoMode(width, height, video.depth, surface_flags);
690 if (gfx.final_screen_bitmap->surface != NULL)
693 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
695 if (new_surface == NULL)
696 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
699 new_surface = gfx.final_screen_bitmap->surface;
700 gfx.final_screen_bitmap = NULL;
706 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
710 #if defined(TARGET_SDL2)
711 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
712 if (new_surface != NULL)
713 fullscreen_enabled = fullscreen;
716 if (backbuffer == NULL)
717 backbuffer = CreateBitmapStruct();
719 backbuffer->width = video.width;
720 backbuffer->height = video.height;
722 if (backbuffer->surface)
723 SDL_FreeSurface(backbuffer->surface);
725 backbuffer->surface = new_surface;
727 return (new_surface != NULL);
730 boolean SDLSetVideoMode(boolean fullscreen)
732 boolean success = FALSE;
736 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
738 /* switch display to fullscreen mode, if available */
739 success = SDLCreateScreen(TRUE);
743 /* switching display to fullscreen mode failed -- do not try it again */
744 video.fullscreen_available = FALSE;
748 video.fullscreen_enabled = TRUE;
752 if ((!fullscreen && video.fullscreen_enabled) || !success)
754 /* switch display to window mode */
755 success = SDLCreateScreen(FALSE);
759 /* switching display to window mode failed -- should not happen */
763 video.fullscreen_enabled = FALSE;
764 video.window_scaling_percent = setup.window_scaling_percent;
765 video.window_scaling_quality = setup.window_scaling_quality;
767 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
771 #if defined(TARGET_SDL2)
772 SDLRedrawWindow(); // map window
776 #if defined(PLATFORM_WIN32)
777 // experimental drag and drop code
779 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
782 SDL_SysWMinfo wminfo;
784 boolean wminfo_success = FALSE;
786 SDL_VERSION(&wminfo.version);
787 #if defined(TARGET_SDL2)
789 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
791 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
796 #if defined(TARGET_SDL2)
797 hwnd = wminfo.info.win.window;
799 hwnd = wminfo.window;
802 DragAcceptFiles(hwnd, TRUE);
811 void SDLSetWindowTitle()
813 #if defined(TARGET_SDL2)
814 SDL_SetWindowTitle(sdl_window, program.window_title);
816 SDL_WM_SetCaption(program.window_title, program.window_title);
820 #if defined(TARGET_SDL2)
821 void SDLSetWindowScaling(int window_scaling_percent)
823 if (sdl_window == NULL)
826 float window_scaling_factor = (float)window_scaling_percent / 100;
827 int new_window_width = (int)(window_scaling_factor * video.screen_width);
828 int new_window_height = (int)(window_scaling_factor * video.screen_height);
830 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
832 video.window_scaling_percent = window_scaling_percent;
833 video.window_width = new_window_width;
834 video.window_height = new_window_height;
839 void SDLSetWindowScalingQuality(char *window_scaling_quality)
841 SDL_Texture *new_texture;
843 if (sdl_texture_stream == NULL)
846 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
848 new_texture = SDL_CreateTexture(sdl_renderer,
849 SDL_PIXELFORMAT_ARGB8888,
850 SDL_TEXTUREACCESS_STREAMING,
851 video.width, video.height);
853 if (new_texture != NULL)
855 SDL_DestroyTexture(sdl_texture_stream);
857 sdl_texture_stream = new_texture;
860 if (SDL_RenderTargetSupported(sdl_renderer))
861 new_texture = SDL_CreateTexture(sdl_renderer,
862 SDL_PIXELFORMAT_ARGB8888,
863 SDL_TEXTUREACCESS_TARGET,
864 video.width, video.height);
868 if (new_texture != NULL)
870 SDL_DestroyTexture(sdl_texture_target);
872 sdl_texture_target = new_texture;
877 video.window_scaling_quality = window_scaling_quality;
880 void SDLSetWindowFullscreen(boolean fullscreen)
882 if (sdl_window == NULL)
885 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
887 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
888 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
890 // if screen size was changed in fullscreen mode, correct desktop window size
891 if (!fullscreen && video.fullscreen_initial)
893 SDLSetWindowScaling(setup.window_scaling_percent);
894 SDL_SetWindowPosition(sdl_window,
895 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
897 video.fullscreen_initial = FALSE;
901 void SDLSetDisplaySize()
903 SDL_Rect display_bounds;
905 SDL_GetDisplayBounds(0, &display_bounds);
907 video.display_width = display_bounds.w;
908 video.display_height = display_bounds.h;
911 Error(ERR_DEBUG, "SDL real screen size: %d x %d",
912 video.display_width, video.display_height);
916 void SDLSetScreenSizeAndOffsets(int width, int height)
918 // set default video screen size and offsets
919 video.screen_width = width;
920 video.screen_height = height;
921 video.screen_xoffset = 0;
922 video.screen_yoffset = 0;
924 #if defined(USE_COMPLETE_DISPLAY)
925 float ratio_video = (float) width / height;
926 float ratio_display = (float) video.display_width / video.display_height;
928 if (ratio_video != ratio_display)
930 // adjust drawable screen size to cover the whole device display
932 if (ratio_video < ratio_display)
933 video.screen_width *= ratio_display / ratio_video;
935 video.screen_height *= ratio_video / ratio_display;
937 video.screen_xoffset = (video.screen_width - width) / 2;
938 video.screen_yoffset = (video.screen_height - height) / 2;
941 Error(ERR_DEBUG, "Changing screen from %dx%d to %dx%d (%.2f to %.2f)",
943 video.screen_width, video.screen_height,
944 ratio_video, ratio_display);
950 void SDLSetScreenSizeForRenderer(int width, int height)
952 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
955 void SDLSetScreenProperties()
957 SDLSetScreenSizeAndOffsets(video.width, video.height);
958 SDLSetScreenSizeForRenderer(video.screen_width, video.screen_height);
963 void SDLSetScreenRenderingMode(char *screen_rendering_mode)
965 #if defined(TARGET_SDL2)
966 video.screen_rendering_mode =
967 (strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
968 SPECIAL_RENDERING_BITMAP :
969 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
970 SPECIAL_RENDERING_TARGET:
971 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
972 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
974 video.screen_rendering_mode = SPECIAL_RENDERING_BITMAP;
978 void SDLRedrawWindow()
980 UpdateScreen_WithoutFrameDelay(NULL);
983 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
986 SDL_Surface *surface =
987 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
990 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
992 SDLSetNativeSurface(&surface);
994 bitmap->surface = surface;
997 void SDLFreeBitmapPointers(Bitmap *bitmap)
1000 SDL_FreeSurface(bitmap->surface);
1001 if (bitmap->surface_masked)
1002 SDL_FreeSurface(bitmap->surface_masked);
1004 bitmap->surface = NULL;
1005 bitmap->surface_masked = NULL;
1007 #if defined(TARGET_SDL2)
1008 if (bitmap->texture)
1009 SDL_DestroyTexture(bitmap->texture);
1010 if (bitmap->texture_masked)
1011 SDL_DestroyTexture(bitmap->texture_masked);
1013 bitmap->texture = NULL;
1014 bitmap->texture_masked = NULL;
1018 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1019 int src_x, int src_y, int width, int height,
1020 int dst_x, int dst_y, int mask_mode)
1022 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1023 SDL_Rect src_rect, dst_rect;
1028 src_rect.h = height;
1033 dst_rect.h = height;
1035 // if (src_bitmap != backbuffer || dst_bitmap != window)
1036 if (!(src_bitmap == backbuffer && dst_bitmap == window))
1037 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
1038 src_bitmap->surface_masked : src_bitmap->surface),
1039 &src_rect, real_dst_bitmap->surface, &dst_rect);
1041 if (dst_bitmap == window)
1042 UpdateScreen_WithFrameDelay(&dst_rect);
1045 void SDLBlitTexture(Bitmap *bitmap,
1046 int src_x, int src_y, int width, int height,
1047 int dst_x, int dst_y, int mask_mode)
1049 #if defined(TARGET_SDL2)
1050 SDL_Texture *texture;
1055 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
1057 if (texture == NULL)
1063 src_rect.h = height;
1068 dst_rect.h = height;
1070 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);
1085 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1087 if (dst_bitmap == window)
1088 UpdateScreen_WithFrameDelay(&rect);
1091 void PrepareFadeBitmap(int draw_target)
1093 Bitmap *fade_bitmap =
1094 (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
1095 draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
1097 if (fade_bitmap == NULL)
1100 // copy backbuffer to fading buffer
1101 BlitBitmap(backbuffer, fade_bitmap, 0, 0, gfx.win_xsize, gfx.win_ysize, 0, 0);
1103 // add border and animations to fading buffer
1104 FinalizeScreen(draw_target);
1107 void SDLFadeRectangle(int x, int y, int width, int height,
1108 int fade_mode, int fade_delay, int post_delay,
1109 void (*draw_border_function)(void))
1111 SDL_Surface *surface_backup = gfx.fade_bitmap_backup->surface;
1112 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
1113 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
1114 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
1115 SDL_Surface *surface_screen = backbuffer->surface;
1116 SDL_Rect src_rect, dst_rect;
1118 int src_x = x, src_y = y;
1119 int dst_x = x, dst_y = y;
1120 unsigned int time_last, time_current;
1122 // store function for drawing global masked border
1123 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
1125 // deactivate drawing of global border while fading, if needed
1126 if (draw_border_function == NULL)
1127 gfx.draw_global_border_function = NULL;
1132 src_rect.h = height;
1136 dst_rect.w = width; /* (ignored) */
1137 dst_rect.h = height; /* (ignored) */
1139 dst_rect2 = dst_rect;
1141 // before fading in, store backbuffer (without animation graphics)
1142 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
1143 SDL_BlitSurface(surface_screen, &dst_rect, surface_backup, &src_rect);
1145 /* copy source and target surfaces to temporary surfaces for fading */
1146 if (fade_mode & FADE_TYPE_TRANSFORM)
1148 // (source and target fading buffer already prepared)
1150 else if (fade_mode & FADE_TYPE_FADE_IN)
1152 // (target fading buffer already prepared)
1153 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1155 else /* FADE_TYPE_FADE_OUT */
1157 // (source fading buffer already prepared)
1158 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1161 time_current = SDL_GetTicks();
1163 if (fade_mode == FADE_MODE_MELT)
1165 boolean done = FALSE;
1166 int melt_pixels = 2;
1167 int melt_columns = width / melt_pixels;
1168 int ypos[melt_columns];
1169 int max_steps = height / 8 + 32;
1174 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1176 SDLSetAlpha(surface_target, FALSE, 0); /* disable alpha blending */
1178 ypos[0] = -GetSimpleRandom(16);
1180 for (i = 1 ; i < melt_columns; i++)
1182 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1184 ypos[i] = ypos[i - 1] + r;
1197 time_last = time_current;
1198 time_current = SDL_GetTicks();
1199 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1200 steps_final = MIN(MAX(0, steps), max_steps);
1204 done = (steps_done >= steps_final);
1206 for (i = 0 ; i < melt_columns; i++)
1214 else if (ypos[i] < height)
1219 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1221 if (ypos[i] + dy >= height)
1222 dy = height - ypos[i];
1224 /* copy part of (appearing) target surface to upper area */
1225 src_rect.x = src_x + i * melt_pixels;
1226 // src_rect.y = src_y + ypos[i];
1228 src_rect.w = melt_pixels;
1230 src_rect.h = ypos[i] + dy;
1232 dst_rect.x = dst_x + i * melt_pixels;
1233 // dst_rect.y = dst_y + ypos[i];
1236 if (steps_done >= steps_final)
1237 SDL_BlitSurface(surface_target, &src_rect,
1238 surface_screen, &dst_rect);
1242 /* copy part of (disappearing) source surface to lower area */
1243 src_rect.x = src_x + i * melt_pixels;
1245 src_rect.w = melt_pixels;
1246 src_rect.h = height - ypos[i];
1248 dst_rect.x = dst_x + i * melt_pixels;
1249 dst_rect.y = dst_y + ypos[i];
1251 if (steps_done >= steps_final)
1252 SDL_BlitSurface(surface_source, &src_rect,
1253 surface_screen, &dst_rect);
1259 src_rect.x = src_x + i * melt_pixels;
1261 src_rect.w = melt_pixels;
1262 src_rect.h = height;
1264 dst_rect.x = dst_x + i * melt_pixels;
1267 if (steps_done >= steps_final)
1268 SDL_BlitSurface(surface_target, &src_rect,
1269 surface_screen, &dst_rect);
1273 if (steps_done >= steps_final)
1275 if (draw_border_function != NULL)
1276 draw_border_function();
1278 UpdateScreen_WithFrameDelay(&dst_rect2);
1282 else if (fade_mode == FADE_MODE_CURTAIN)
1286 int xx_size = width / 2;
1288 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1290 SDLSetAlpha(surface_source, FALSE, 0); /* disable alpha blending */
1292 for (xx = 0; xx < xx_size;)
1294 time_last = time_current;
1295 time_current = SDL_GetTicks();
1296 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1297 xx_final = MIN(MAX(0, xx), xx_size);
1302 src_rect.h = height;
1307 /* draw new (target) image to screen buffer */
1308 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1310 if (xx_final < xx_size)
1312 src_rect.w = xx_size - xx_final;
1313 src_rect.h = height;
1315 /* draw old (source) image to screen buffer (left side) */
1317 src_rect.x = src_x + xx_final;
1320 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1322 /* draw old (source) image to screen buffer (right side) */
1324 src_rect.x = src_x + xx_size;
1325 dst_rect.x = dst_x + xx_size + xx_final;
1327 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1330 if (draw_border_function != NULL)
1331 draw_border_function();
1333 /* only update the region of the screen that is affected from fading */
1334 UpdateScreen_WithFrameDelay(&dst_rect2);
1337 else /* fading in, fading out or cross-fading */
1342 for (alpha = 0.0; alpha < 255.0;)
1344 time_last = time_current;
1345 time_current = SDL_GetTicks();
1346 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1347 alpha_final = MIN(MAX(0, alpha), 255);
1349 /* draw existing (source) image to screen buffer */
1350 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1352 /* draw new (target) image to screen buffer using alpha blending */
1353 SDLSetAlpha(surface_target, TRUE, alpha_final);
1354 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1356 if (draw_border_function != NULL)
1357 draw_border_function();
1359 /* only update the region of the screen that is affected from fading */
1360 UpdateScreen_WithFrameDelay(&dst_rect);
1366 unsigned int time_post_delay;
1368 time_current = SDL_GetTicks();
1369 time_post_delay = time_current + post_delay;
1371 while (time_current < time_post_delay)
1373 // updating the screen contains waiting for frame delay (non-busy)
1374 UpdateScreen_WithFrameDelay(NULL);
1376 time_current = SDL_GetTicks();
1380 // restore function for drawing global masked border
1381 gfx.draw_global_border_function = draw_global_border_function;
1383 // after fading in, restore backbuffer (without animation graphics)
1384 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
1385 SDL_BlitSurface(surface_backup, &dst_rect, surface_screen, &src_rect);
1388 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1389 int to_x, int to_y, Uint32 color)
1391 SDL_Surface *surface = dst_bitmap->surface;
1395 swap_numbers(&from_x, &to_x);
1398 swap_numbers(&from_y, &to_y);
1402 rect.w = (to_x - from_x + 1);
1403 rect.h = (to_y - from_y + 1);
1405 SDL_FillRect(surface, &rect, color);
1408 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1409 int to_x, int to_y, Uint32 color)
1411 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1414 #if ENABLE_UNUSED_CODE
1415 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1416 int num_points, Uint32 color)
1421 for (i = 0; i < num_points - 1; i++)
1423 for (x = 0; x < line_width; x++)
1425 for (y = 0; y < line_width; y++)
1427 int dx = x - line_width / 2;
1428 int dy = y - line_width / 2;
1430 if ((x == 0 && y == 0) ||
1431 (x == 0 && y == line_width - 1) ||
1432 (x == line_width - 1 && y == 0) ||
1433 (x == line_width - 1 && y == line_width - 1))
1436 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1437 points[i+1].x + dx, points[i+1].y + dy, color);
1444 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1446 SDL_Surface *surface = src_bitmap->surface;
1448 switch (surface->format->BytesPerPixel)
1450 case 1: /* assuming 8-bpp */
1452 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1456 case 2: /* probably 15-bpp or 16-bpp */
1458 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1462 case 3: /* slow 24-bpp mode; usually not used */
1464 /* does this work? */
1465 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1469 shift = surface->format->Rshift;
1470 color |= *(pix + shift / 8) >> shift;
1471 shift = surface->format->Gshift;
1472 color |= *(pix + shift / 8) >> shift;
1473 shift = surface->format->Bshift;
1474 color |= *(pix + shift / 8) >> shift;
1480 case 4: /* probably 32-bpp */
1482 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1491 /* ========================================================================= */
1492 /* The following functions were taken from the SGE library */
1493 /* (SDL Graphics Extension Library) by Anders Lindström */
1494 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1495 /* ========================================================================= */
1497 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1499 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1501 switch (surface->format->BytesPerPixel)
1505 /* Assuming 8-bpp */
1506 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1512 /* Probably 15-bpp or 16-bpp */
1513 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1519 /* Slow 24-bpp mode, usually not used */
1523 /* Gack - slow, but endian correct */
1524 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1525 shift = surface->format->Rshift;
1526 *(pix+shift/8) = color>>shift;
1527 shift = surface->format->Gshift;
1528 *(pix+shift/8) = color>>shift;
1529 shift = surface->format->Bshift;
1530 *(pix+shift/8) = color>>shift;
1536 /* Probably 32-bpp */
1537 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1544 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1545 Uint8 R, Uint8 G, Uint8 B)
1547 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1550 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1552 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1555 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1557 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1560 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1565 /* Gack - slow, but endian correct */
1566 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1567 shift = surface->format->Rshift;
1568 *(pix+shift/8) = color>>shift;
1569 shift = surface->format->Gshift;
1570 *(pix+shift/8) = color>>shift;
1571 shift = surface->format->Bshift;
1572 *(pix+shift/8) = color>>shift;
1575 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1577 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1580 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1582 switch (dest->format->BytesPerPixel)
1585 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1589 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1593 _PutPixel24(dest,x,y,color);
1597 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1602 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1604 if (SDL_MUSTLOCK(surface))
1606 if (SDL_LockSurface(surface) < 0)
1612 _PutPixel(surface, x, y, color);
1614 if (SDL_MUSTLOCK(surface))
1616 SDL_UnlockSurface(surface);
1620 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1621 Uint8 r, Uint8 g, Uint8 b)
1623 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1626 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1628 if (y >= 0 && y <= dest->h - 1)
1630 switch (dest->format->BytesPerPixel)
1633 return y*dest->pitch;
1637 return y*dest->pitch/2;
1641 return y*dest->pitch;
1645 return y*dest->pitch/4;
1653 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1655 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1657 switch (surface->format->BytesPerPixel)
1661 /* Assuming 8-bpp */
1662 *((Uint8 *)surface->pixels + ypitch + x) = color;
1668 /* Probably 15-bpp or 16-bpp */
1669 *((Uint16 *)surface->pixels + ypitch + x) = color;
1675 /* Slow 24-bpp mode, usually not used */
1679 /* Gack - slow, but endian correct */
1680 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1681 shift = surface->format->Rshift;
1682 *(pix+shift/8) = color>>shift;
1683 shift = surface->format->Gshift;
1684 *(pix+shift/8) = color>>shift;
1685 shift = surface->format->Bshift;
1686 *(pix+shift/8) = color>>shift;
1692 /* Probably 32-bpp */
1693 *((Uint32 *)surface->pixels + ypitch + x) = color;
1700 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1705 if (SDL_MUSTLOCK(Surface))
1707 if (SDL_LockSurface(Surface) < 0)
1720 /* Do the clipping */
1721 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1725 if (x2 > Surface->w - 1)
1726 x2 = Surface->w - 1;
1733 SDL_FillRect(Surface, &l, Color);
1735 if (SDL_MUSTLOCK(Surface))
1737 SDL_UnlockSurface(Surface);
1741 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1742 Uint8 R, Uint8 G, Uint8 B)
1744 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1747 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1758 /* Do the clipping */
1759 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1763 if (x2 > Surface->w - 1)
1764 x2 = Surface->w - 1;
1771 SDL_FillRect(Surface, &l, Color);
1774 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1779 if (SDL_MUSTLOCK(Surface))
1781 if (SDL_LockSurface(Surface) < 0)
1794 /* Do the clipping */
1795 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1799 if (y2 > Surface->h - 1)
1800 y2 = Surface->h - 1;
1807 SDL_FillRect(Surface, &l, Color);
1809 if (SDL_MUSTLOCK(Surface))
1811 SDL_UnlockSurface(Surface);
1815 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1816 Uint8 R, Uint8 G, Uint8 B)
1818 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1821 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1832 /* Do the clipping */
1833 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1837 if (y2 > Surface->h - 1)
1838 y2 = Surface->h - 1;
1845 SDL_FillRect(Surface, &l, Color);
1848 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1849 Sint16 x2, Sint16 y2, Uint32 Color,
1850 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1853 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1858 sdx = (dx < 0) ? -1 : 1;
1859 sdy = (dy < 0) ? -1 : 1;
1871 for (x = 0; x < dx; x++)
1873 Callback(Surface, px, py, Color);
1887 for (y = 0; y < dy; y++)
1889 Callback(Surface, px, py, Color);
1903 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1904 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1905 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1908 sge_DoLine(Surface, X1, Y1, X2, Y2,
1909 SDL_MapRGB(Surface->format, R, G, B), Callback);
1912 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1915 if (SDL_MUSTLOCK(Surface))
1917 if (SDL_LockSurface(Surface) < 0)
1922 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1924 /* unlock the display */
1925 if (SDL_MUSTLOCK(Surface))
1927 SDL_UnlockSurface(Surface);
1931 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1932 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1934 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1937 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1939 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1944 -----------------------------------------------------------------------------
1945 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1946 -----------------------------------------------------------------------------
1949 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1950 int width, int height, Uint32 color)
1954 for (y = src_y; y < src_y + height; y++)
1956 for (x = src_x; x < src_x + width; x++)
1958 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1960 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1965 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1966 int src_x, int src_y, int width, int height,
1967 int dst_x, int dst_y)
1971 for (y = 0; y < height; y++)
1973 for (x = 0; x < width; x++)
1975 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1977 if (pixel != BLACK_PIXEL)
1978 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1984 /* ========================================================================= */
1985 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1986 /* (Rotozoomer) by Andreas Schiffler */
1987 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1988 /* ========================================================================= */
1991 -----------------------------------------------------------------------------
1994 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1995 -----------------------------------------------------------------------------
2006 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
2009 tColorRGBA *sp, *csp, *dp;
2013 sp = csp = (tColorRGBA *) src->pixels;
2014 dp = (tColorRGBA *) dst->pixels;
2015 dgap = dst->pitch - dst->w * 4;
2017 for (y = 0; y < dst->h; y++)
2021 for (x = 0; x < dst->w; x++)
2023 tColorRGBA *sp0 = sp;
2024 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2025 tColorRGBA *sp00 = &sp0[0];
2026 tColorRGBA *sp01 = &sp0[1];
2027 tColorRGBA *sp10 = &sp1[0];
2028 tColorRGBA *sp11 = &sp1[1];
2031 /* create new color pixel from all four source color pixels */
2032 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2033 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2034 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2035 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2040 /* advance source pointers */
2043 /* advance destination pointer */
2047 /* advance source pointer */
2048 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2050 /* advance destination pointers */
2051 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2057 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2059 int x, y, *sax, *say, *csax, *csay;
2061 tColorRGBA *sp, *csp, *csp0, *dp;
2064 /* use specialized zoom function when scaling down to exactly half size */
2065 if (src->w == 2 * dst->w &&
2066 src->h == 2 * dst->h)
2067 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2069 /* variable setup */
2070 sx = (float) src->w / (float) dst->w;
2071 sy = (float) src->h / (float) dst->h;
2073 /* allocate memory for row increments */
2074 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2075 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2077 /* precalculate row increments */
2078 for (x = 0; x <= dst->w; x++)
2079 *csax++ = (int)(sx * x);
2081 for (y = 0; y <= dst->h; y++)
2082 *csay++ = (int)(sy * y);
2085 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2086 dp = (tColorRGBA *) dst->pixels;
2087 dgap = dst->pitch - dst->w * 4;
2090 for (y = 0; y < dst->h; y++)
2095 for (x = 0; x < dst->w; x++)
2100 /* advance source pointers */
2104 /* advance destination pointer */
2108 /* advance source pointer */
2110 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2112 /* advance destination pointers */
2113 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2123 -----------------------------------------------------------------------------
2126 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2127 -----------------------------------------------------------------------------
2130 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2132 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2133 Uint8 *sp, *dp, *csp;
2136 /* variable setup */
2137 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2138 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2140 /* allocate memory for row increments */
2141 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2142 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2144 /* precalculate row increments */
2147 for (x = 0; x < dst->w; x++)
2150 *csax = (csx >> 16);
2157 for (y = 0; y < dst->h; y++)
2160 *csay = (csy >> 16);
2167 for (x = 0; x < dst->w; x++)
2175 for (y = 0; y < dst->h; y++)
2182 sp = csp = (Uint8 *) src->pixels;
2183 dp = (Uint8 *) dst->pixels;
2184 dgap = dst->pitch - dst->w;
2188 for (y = 0; y < dst->h; y++)
2192 for (x = 0; x < dst->w; x++)
2197 /* advance source pointers */
2201 /* advance destination pointer */
2205 /* advance source pointer (for row) */
2206 csp += ((*csay) * src->pitch);
2209 /* advance destination pointers */
2220 -----------------------------------------------------------------------------
2223 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2224 'zoomx' and 'zoomy' are scaling factors for width and height.
2225 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2226 into a 32bit RGBA format on the fly.
2227 -----------------------------------------------------------------------------
2230 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2232 SDL_Surface *zoom_src = NULL;
2233 SDL_Surface *zoom_dst = NULL;
2234 boolean is_converted = FALSE;
2241 /* determine if source surface is 32 bit or 8 bit */
2242 is_32bit = (src->format->BitsPerPixel == 32);
2244 if (is_32bit || src->format->BitsPerPixel == 8)
2246 /* use source surface 'as is' */
2251 /* new source surface is 32 bit with a defined RGB ordering */
2252 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2253 0x000000ff, 0x0000ff00, 0x00ff0000,
2254 (src->format->Amask ? 0xff000000 : 0));
2255 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2257 is_converted = TRUE;
2260 /* allocate surface to completely contain the zoomed surface */
2263 /* target surface is 32 bit with source RGBA/ABGR ordering */
2264 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2265 zoom_src->format->Rmask,
2266 zoom_src->format->Gmask,
2267 zoom_src->format->Bmask,
2268 zoom_src->format->Amask);
2272 /* target surface is 8 bit */
2273 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2277 /* lock source surface */
2278 SDL_LockSurface(zoom_src);
2280 /* check which kind of surface we have */
2283 /* call the 32 bit transformation routine to do the zooming */
2284 zoomSurfaceRGBA(zoom_src, zoom_dst);
2289 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2290 zoom_dst->format->palette->colors[i] =
2291 zoom_src->format->palette->colors[i];
2292 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2294 /* call the 8 bit transformation routine to do the zooming */
2295 zoomSurfaceY(zoom_src, zoom_dst);
2298 /* unlock source surface */
2299 SDL_UnlockSurface(zoom_src);
2301 /* free temporary surface */
2303 SDL_FreeSurface(zoom_src);
2305 /* return destination surface */
2309 static SDL_Surface *SDLGetOpaqueSurface(SDL_Surface *surface)
2311 SDL_Surface *new_surface;
2313 if (surface == NULL)
2316 if ((new_surface = SDLGetNativeSurface(surface)) == NULL)
2317 Error(ERR_EXIT, "SDLGetNativeSurface() failed");
2319 /* remove alpha channel from native non-transparent surface, if defined */
2320 SDLSetAlpha(new_surface, FALSE, 0);
2322 /* remove transparent color from native non-transparent surface, if defined */
2323 SDL_SetColorKey(new_surface, UNSET_TRANSPARENT_PIXEL, 0);
2328 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2330 Bitmap *dst_bitmap = CreateBitmapStruct();
2331 SDL_Surface *src_surface = src_bitmap->surface_masked;
2332 SDL_Surface *dst_surface;
2334 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2335 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2337 dst_bitmap->width = dst_width;
2338 dst_bitmap->height = dst_height;
2340 /* create zoomed temporary surface from source surface */
2341 dst_surface = zoomSurface(src_surface, dst_width, dst_height);
2343 /* create native format destination surface from zoomed temporary surface */
2344 SDLSetNativeSurface(&dst_surface);
2346 /* set color key for zoomed surface from source surface, if defined */
2347 if (SDLHasColorKey(src_surface))
2348 SDL_SetColorKey(dst_surface, SET_TRANSPARENT_PIXEL,
2349 SDLGetColorKey(src_surface));
2351 /* create native non-transparent surface for opaque blitting */
2352 dst_bitmap->surface = SDLGetOpaqueSurface(dst_surface);
2354 /* set native transparent surface for masked blitting */
2355 dst_bitmap->surface_masked = dst_surface;
2361 /* ========================================================================= */
2362 /* load image to bitmap */
2363 /* ========================================================================= */
2365 Bitmap *SDLLoadImage(char *filename)
2367 Bitmap *new_bitmap = CreateBitmapStruct();
2368 SDL_Surface *sdl_image_tmp;
2370 print_timestamp_init("SDLLoadImage");
2372 print_timestamp_time(getBaseNamePtr(filename));
2374 /* load image to temporary surface */
2375 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2376 Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError());
2378 print_timestamp_time("IMG_Load");
2380 UPDATE_BUSY_STATE();
2382 /* create native non-transparent surface for current image */
2383 if ((new_bitmap->surface = SDLGetOpaqueSurface(sdl_image_tmp)) == NULL)
2384 Error(ERR_EXIT, "SDLGetOpaqueSurface() failed");
2386 print_timestamp_time("SDLGetNativeSurface (opaque)");
2388 UPDATE_BUSY_STATE();
2390 /* set black pixel to transparent if no alpha channel / transparent color */
2391 if (!SDLHasAlpha(sdl_image_tmp) &&
2392 !SDLHasColorKey(sdl_image_tmp))
2393 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2394 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2396 /* create native transparent surface for current image */
2397 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2398 Error(ERR_EXIT, "SDLGetNativeSurface() failed");
2400 print_timestamp_time("SDLGetNativeSurface (masked)");
2402 UPDATE_BUSY_STATE();
2404 /* free temporary surface */
2405 SDL_FreeSurface(sdl_image_tmp);
2407 new_bitmap->width = new_bitmap->surface->w;
2408 new_bitmap->height = new_bitmap->surface->h;
2410 print_timestamp_done("SDLLoadImage");
2416 /* ------------------------------------------------------------------------- */
2417 /* custom cursor fuctions */
2418 /* ------------------------------------------------------------------------- */
2420 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2422 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2423 cursor_info->width, cursor_info->height,
2424 cursor_info->hot_x, cursor_info->hot_y);
2427 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2429 static struct MouseCursorInfo *last_cursor_info = NULL;
2430 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2431 static SDL_Cursor *cursor_default = NULL;
2432 static SDL_Cursor *cursor_current = NULL;
2434 /* if invoked for the first time, store the SDL default cursor */
2435 if (cursor_default == NULL)
2436 cursor_default = SDL_GetCursor();
2438 /* only create new cursor if cursor info (custom only) has changed */
2439 if (cursor_info != NULL && cursor_info != last_cursor_info)
2441 cursor_current = create_cursor(cursor_info);
2442 last_cursor_info = cursor_info;
2445 /* only set new cursor if cursor info (custom or NULL) has changed */
2446 if (cursor_info != last_cursor_info2)
2447 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2449 last_cursor_info2 = cursor_info;
2453 /* ========================================================================= */
2454 /* audio functions */
2455 /* ========================================================================= */
2457 void SDLOpenAudio(void)
2459 #if !defined(TARGET_SDL2)
2460 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2461 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2464 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2466 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2470 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2471 AUDIO_NUM_CHANNELS_STEREO,
2472 setup.system.audio_fragment_size) < 0)
2474 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2478 audio.sound_available = TRUE;
2479 audio.music_available = TRUE;
2480 audio.loops_available = TRUE;
2481 audio.sound_enabled = TRUE;
2483 /* set number of available mixer channels */
2484 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2485 audio.music_channel = MUSIC_CHANNEL;
2486 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2488 Mixer_InitChannels();
2491 void SDLCloseAudio(void)
2494 Mix_HaltChannel(-1);
2497 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2501 /* ========================================================================= */
2502 /* event functions */
2503 /* ========================================================================= */
2505 void SDLNextEvent(Event *event)
2507 SDL_WaitEvent(event);
2510 void SDLHandleWindowManagerEvent(Event *event)
2513 #if defined(PLATFORM_WIN32)
2514 // experimental drag and drop code
2516 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2517 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2519 #if defined(TARGET_SDL2)
2520 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2522 if (syswmmsg->msg == WM_DROPFILES)
2525 #if defined(TARGET_SDL2)
2526 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2528 HDROP hdrop = (HDROP)syswmmsg->wParam;
2532 printf("::: SDL_SYSWMEVENT:\n");
2534 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2536 for (i = 0; i < num_files; i++)
2538 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2539 char buffer[buffer_len + 1];
2541 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2543 printf("::: - '%s'\n", buffer);
2546 #if defined(TARGET_SDL2)
2547 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2549 DragFinish((HDROP)syswmmsg->wParam);
2557 /* ========================================================================= */
2558 /* joystick functions */
2559 /* ========================================================================= */
2561 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2562 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2563 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2565 static boolean SDLOpenJoystick(int nr)
2567 if (nr < 0 || nr > MAX_PLAYERS)
2570 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2573 static void SDLCloseJoystick(int nr)
2575 if (nr < 0 || nr > MAX_PLAYERS)
2578 SDL_JoystickClose(sdl_joystick[nr]);
2580 sdl_joystick[nr] = NULL;
2583 static boolean SDLCheckJoystickOpened(int nr)
2585 if (nr < 0 || nr > MAX_PLAYERS)
2588 #if defined(TARGET_SDL2)
2589 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2591 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2595 void HandleJoystickEvent(Event *event)
2599 case SDL_JOYAXISMOTION:
2600 if (event->jaxis.axis < 2)
2601 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2604 case SDL_JOYBUTTONDOWN:
2605 if (event->jbutton.button < 2)
2606 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2609 case SDL_JOYBUTTONUP:
2610 if (event->jbutton.button < 2)
2611 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2619 void SDLInitJoysticks()
2621 static boolean sdl_joystick_subsystem_initialized = FALSE;
2622 boolean print_warning = !sdl_joystick_subsystem_initialized;
2625 if (!sdl_joystick_subsystem_initialized)
2627 sdl_joystick_subsystem_initialized = TRUE;
2629 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2631 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2636 for (i = 0; i < MAX_PLAYERS; i++)
2638 /* get configured joystick for this player */
2639 char *device_name = setup.input[i].joy.device_name;
2640 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2642 if (joystick_nr >= SDL_NumJoysticks())
2644 if (setup.input[i].use_joystick && print_warning)
2645 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2650 /* misuse joystick file descriptor variable to store joystick number */
2651 joystick.fd[i] = joystick_nr;
2653 if (joystick_nr == -1)
2656 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2657 if (SDLCheckJoystickOpened(joystick_nr))
2658 SDLCloseJoystick(joystick_nr);
2660 if (!setup.input[i].use_joystick)
2663 if (!SDLOpenJoystick(joystick_nr))
2666 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2671 joystick.status = JOYSTICK_ACTIVATED;
2675 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2677 if (nr < 0 || nr >= MAX_PLAYERS)
2681 *x = sdl_js_axis[nr][0];
2683 *y = sdl_js_axis[nr][1];
2686 *b1 = sdl_js_button[nr][0];
2688 *b2 = sdl_js_button[nr][1];
2693 #if defined(USE_TOUCH_INPUT_OVERLAY)
2694 static void DrawTouchInputOverlay()
2696 static SDL_Texture *texture = NULL;
2697 static boolean initialized = FALSE;
2698 static boolean deactivated = TRUE;
2699 static int width = 0, height = 0;
2700 static int alpha_max = SDL_ALPHA_OPAQUE / 2;
2701 static int alpha_step = 5;
2702 static int alpha_last = 0;
2703 static int alpha = 0;
2705 if (!overlay.active && deactivated)
2710 if (alpha < alpha_max)
2711 alpha = MIN(alpha + alpha_step, alpha_max);
2713 deactivated = FALSE;
2717 alpha = MAX(0, alpha - alpha_step);
2725 char *basename = "overlay/VirtualButtons.png";
2726 char *filename = getCustomImageFilename(basename);
2728 if (filename == NULL)
2729 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
2731 SDL_Surface *surface;
2733 if ((surface = IMG_Load(filename)) == NULL)
2734 Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError());
2737 height = surface->h;
2739 /* set black pixel to transparent if no alpha channel / transparent color */
2740 if (!SDLHasAlpha(surface) &&
2741 !SDLHasColorKey(surface))
2742 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
2743 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
2745 if ((texture = SDLCreateTextureFromSurface(surface)) == NULL)
2746 Error(ERR_EXIT, "SDLCreateTextureFromSurface() failed");
2748 SDL_FreeSurface(surface);
2750 SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
2751 SDL_SetTextureAlphaMod(texture, alpha_max);
2756 if (alpha != alpha_last)
2757 SDL_SetTextureAlphaMod(texture, alpha);
2761 float ratio_overlay = (float) width / height;
2762 float ratio_screen = (float) video.screen_width / video.screen_height;
2763 int width_scaled, height_scaled;
2766 if (ratio_overlay > ratio_screen)
2768 width_scaled = video.screen_width;
2769 height_scaled = video.screen_height * ratio_screen / ratio_overlay;
2771 ypos = video.screen_height - height_scaled;
2775 width_scaled = video.screen_width * ratio_overlay / ratio_screen;
2776 height_scaled = video.screen_height;
2777 xpos = (video.screen_width - width_scaled) / 2;
2781 SDL_Rect src_rect = { 0, 0, width, height };
2782 SDL_Rect dst_rect = { xpos, ypos, width_scaled, height_scaled };
2784 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);