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 /* functions to draw overlay graphics for touch device input */
41 static void DrawTouchInputOverlay();
43 void SDLLimitScreenUpdates(boolean enable)
45 limit_screen_updates = enable;
48 static void FinalizeScreen(int draw_target)
50 // copy global animations to render target buffer, if defined (below border)
51 if (gfx.draw_global_anim_function != NULL)
52 gfx.draw_global_anim_function(draw_target, DRAW_GLOBAL_ANIM_STAGE_1);
54 // copy global masked border to render target buffer, if defined
55 if (gfx.draw_global_border_function != NULL)
56 gfx.draw_global_border_function(draw_target);
58 // copy global animations to render target buffer, if defined (above border)
59 if (gfx.draw_global_anim_function != NULL)
60 gfx.draw_global_anim_function(draw_target, DRAW_GLOBAL_ANIM_STAGE_2);
63 static void UpdateScreenExt(SDL_Rect *rect, boolean with_frame_delay)
65 static unsigned int update_screen_delay = 0;
66 unsigned int update_screen_delay_value = 50; /* (milliseconds) */
67 SDL_Surface *screen = backbuffer->surface;
69 if (limit_screen_updates &&
70 !DelayReached(&update_screen_delay, update_screen_delay_value))
73 LimitScreenUpdates(FALSE);
77 static int LastFrameCounter = 0;
78 boolean changed = (FrameCounter != LastFrameCounter);
80 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
81 (changed ? "-" : "SAME FRAME UPDATED"));
83 LastFrameCounter = FrameCounter;
92 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP &&
93 gfx.final_screen_bitmap != NULL) // may not be initialized yet
95 // draw global animations using bitmaps instead of using textures
96 // to prevent texture scaling artefacts (this is potentially slower)
98 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
99 gfx.win_xsize, gfx.win_ysize, 0, 0);
101 FinalizeScreen(DRAW_TO_SCREEN);
103 screen = gfx.final_screen_bitmap->surface;
105 // force full window redraw
109 #if defined(TARGET_SDL2)
110 SDL_Texture *sdl_texture = sdl_texture_stream;
112 // deactivate use of target texture if render targets are not supported
113 if ((video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
114 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE) &&
115 sdl_texture_target == NULL)
116 video.screen_rendering_mode = SPECIAL_RENDERING_OFF;
118 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET)
119 sdl_texture = sdl_texture_target;
123 int bytes_x = screen->pitch / video.width;
124 int bytes_y = screen->pitch;
126 SDL_UpdateTexture(sdl_texture, rect,
127 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
132 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
135 int xoff = video.screen_xoffset;
136 int yoff = video.screen_yoffset;
137 SDL_Rect dst_rect_screen = { xoff, yoff, video.width, video.height };
138 SDL_Rect *src_rect1 = NULL, *dst_rect1 = NULL;
139 SDL_Rect *src_rect2 = NULL, *dst_rect2 = NULL;
141 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
142 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
143 dst_rect2 = &dst_rect_screen;
145 dst_rect1 = &dst_rect_screen;
147 #if defined(HAS_SCREEN_KEYBOARD)
148 if (video.shifted_up || video.shifted_up_delay)
150 int time_current = SDL_GetTicks();
151 int pos = video.shifted_up_pos;
152 int pos_last = video.shifted_up_pos_last;
154 if (!DelayReachedExt(&video.shifted_up_delay, video.shifted_up_delay_value,
157 int delay = time_current - video.shifted_up_delay;
158 int delay_value = video.shifted_up_delay_value;
160 pos = pos_last + (pos - pos_last) * delay / delay_value;
164 video.shifted_up_pos_last = pos;
165 video.shifted_up_delay = 0;
168 SDL_Rect src_rect_up = { 0, pos, video.width, video.height - pos };
169 SDL_Rect dst_rect_up = { xoff, yoff, video.width, video.height - pos };
171 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
172 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
174 src_rect2 = &src_rect_up;
175 dst_rect2 = &dst_rect_up;
179 src_rect1 = &src_rect_up;
180 dst_rect1 = &dst_rect_up;
185 // clear render target buffer
186 SDL_RenderClear(sdl_renderer);
188 // set renderer to use target texture for rendering
189 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
190 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
191 SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
193 // copy backbuffer texture to render target buffer
194 if (video.screen_rendering_mode != SPECIAL_RENDERING_TARGET)
195 SDL_RenderCopy(sdl_renderer, sdl_texture_stream, src_rect1, dst_rect1);
197 if (video.screen_rendering_mode != SPECIAL_RENDERING_BITMAP)
198 FinalizeScreen(DRAW_TO_SCREEN);
200 // when using target texture, copy it to screen buffer
201 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
202 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
204 SDL_SetRenderTarget(sdl_renderer, NULL);
205 SDL_RenderCopy(sdl_renderer, sdl_texture_target, src_rect2, dst_rect2);
208 // draw overlay graphics for touch device input, if needed
209 DrawTouchInputOverlay();
212 // global synchronization point of the game to align video frame delay
213 if (with_frame_delay)
214 WaitUntilDelayReached(&video.frame_delay, video.frame_delay_value);
216 #if defined(TARGET_SDL2)
217 // show render target buffer on screen
218 SDL_RenderPresent(sdl_renderer);
221 SDL_UpdateRects(screen, 1, rect);
223 SDL_UpdateRect(screen, 0, 0, 0, 0);
227 static void UpdateScreen_WithFrameDelay(SDL_Rect *rect)
229 UpdateScreenExt(rect, TRUE);
232 static void UpdateScreen_WithoutFrameDelay(SDL_Rect *rect)
234 UpdateScreenExt(rect, FALSE);
237 static void SDLSetWindowIcon(char *basename)
239 /* (setting the window icon on Mac OS X would replace the high-quality
240 dock icon with the currently smaller (and uglier) icon from file) */
242 #if !defined(PLATFORM_MACOSX)
243 char *filename = getCustomImageFilename(basename);
244 SDL_Surface *surface;
246 if (filename == NULL)
248 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
253 if ((surface = IMG_Load(filename)) == NULL)
255 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
260 /* set transparent color */
261 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
262 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
264 #if defined(TARGET_SDL2)
265 SDL_SetWindowIcon(sdl_window, surface);
267 SDL_WM_SetIcon(surface, NULL);
272 #if defined(TARGET_SDL2)
274 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
275 SDL_PixelFormat *format2)
277 return (format1->format == format2->format &&
278 format1->BitsPerPixel == format2->BitsPerPixel &&
279 format1->BytesPerPixel == format2->BytesPerPixel &&
280 format1->Rmask == format2->Rmask &&
281 format1->Gmask == format2->Gmask &&
282 format1->Bmask == format2->Bmask);
285 static Pixel SDLGetColorKey(SDL_Surface *surface)
289 if (SDL_GetColorKey(surface, &color_key) != 0)
295 static boolean SDLHasColorKey(SDL_Surface *surface)
297 return (SDLGetColorKey(surface) != -1);
300 static boolean SDLHasAlpha(SDL_Surface *surface)
302 SDL_BlendMode blend_mode;
304 if (SDL_GetSurfaceBlendMode(surface, &blend_mode) != 0)
307 return (blend_mode == SDL_BLENDMODE_BLEND);
310 static void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha)
312 SDL_BlendMode blend_mode = (set ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE);
314 SDL_SetSurfaceBlendMode(surface, blend_mode);
315 SDL_SetSurfaceAlphaMod(surface, alpha);
318 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
320 SDL_PixelFormat format;
321 SDL_Surface *new_surface;
326 if (backbuffer && backbuffer->surface)
328 format = *backbuffer->surface->format;
329 format.Amask = surface->format->Amask; // keep alpha channel
333 format = *surface->format;
336 new_surface = SDL_ConvertSurface(surface, &format, 0);
338 if (new_surface == NULL)
339 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
344 boolean SDLSetNativeSurface(SDL_Surface **surface)
346 SDL_Surface *new_surface;
348 if (surface == NULL ||
350 backbuffer == NULL ||
351 backbuffer->surface == NULL)
354 // if pixel format already optimized for destination surface, do nothing
355 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
358 new_surface = SDLGetNativeSurface(*surface);
360 SDL_FreeSurface(*surface);
362 *surface = new_surface;
369 static Pixel SDLGetColorKey(SDL_Surface *surface)
371 if ((surface->flags & SDL_SRCCOLORKEY) == 0)
374 return surface->format->colorkey;
377 static boolean SDLHasColorKey(SDL_Surface *surface)
379 return (SDLGetColorKey(surface) != -1);
382 static boolean SDLHasAlpha(SDL_Surface *surface)
384 return ((surface->flags & SDL_SRCALPHA) != 0);
387 static void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha)
389 SDL_SetAlpha(surface, (set ? SDL_SRCALPHA : 0), alpha);
392 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
394 SDL_Surface *new_surface;
399 if (!video.initialized)
400 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
401 else if (SDLHasAlpha(surface))
402 new_surface = SDL_DisplayFormatAlpha(surface);
404 new_surface = SDL_DisplayFormat(surface);
406 if (new_surface == NULL)
407 Error(ERR_EXIT, "%s() failed: %s",
408 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
414 boolean SDLSetNativeSurface(SDL_Surface **surface)
416 SDL_Surface *new_surface;
418 if (surface == NULL ||
423 new_surface = SDLGetNativeSurface(*surface);
425 SDL_FreeSurface(*surface);
427 *surface = new_surface;
434 #if defined(TARGET_SDL2)
435 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
437 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
440 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
447 void SDLCreateBitmapTextures(Bitmap *bitmap)
449 #if defined(TARGET_SDL2)
454 SDL_DestroyTexture(bitmap->texture);
455 if (bitmap->texture_masked)
456 SDL_DestroyTexture(bitmap->texture_masked);
458 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
459 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
463 void SDLFreeBitmapTextures(Bitmap *bitmap)
465 #if defined(TARGET_SDL2)
470 SDL_DestroyTexture(bitmap->texture);
471 if (bitmap->texture_masked)
472 SDL_DestroyTexture(bitmap->texture_masked);
474 bitmap->texture = NULL;
475 bitmap->texture_masked = NULL;
479 void SDLInitVideoDisplay(void)
481 #if !defined(TARGET_SDL2)
482 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
483 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
485 SDL_putenv("SDL_VIDEO_CENTERED=1");
488 /* initialize SDL video */
489 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
490 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
492 /* set default SDL depth */
493 #if !defined(TARGET_SDL2)
494 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
496 video.default_depth = 32; // (how to determine video depth in SDL2?)
500 void SDLInitVideoBuffer(boolean fullscreen)
502 video.window_scaling_percent = setup.window_scaling_percent;
503 video.window_scaling_quality = setup.window_scaling_quality;
505 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
507 #if defined(TARGET_SDL2)
508 // SDL 2.0: support for (desktop) fullscreen mode available
509 video.fullscreen_available = TRUE;
511 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
512 video.fullscreen_available = FALSE;
515 /* open SDL video output device (window or fullscreen mode) */
516 if (!SDLSetVideoMode(fullscreen))
517 Error(ERR_EXIT, "setting video mode failed");
519 /* !!! SDL2 can only set the window icon if the window already exists !!! */
520 /* set window icon */
521 SDLSetWindowIcon(program.icon_filename);
523 /* set window and icon title */
524 #if defined(TARGET_SDL2)
525 SDL_SetWindowTitle(sdl_window, program.window_title);
527 SDL_WM_SetCaption(program.window_title, program.window_title);
530 /* SDL cannot directly draw to the visible video framebuffer like X11,
531 but always uses a backbuffer, which is then blitted to the visible
532 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
533 visible video framebuffer with 'SDL_Flip', if the hardware supports
534 this). Therefore do not use an additional backbuffer for drawing, but
535 use a symbolic buffer (distinguishable from the SDL backbuffer) called
536 'window', which indicates that the SDL backbuffer should be updated to
537 the visible video framebuffer when attempting to blit to it.
539 For convenience, it seems to be a good idea to create this symbolic
540 buffer 'window' at the same size as the SDL backbuffer. Although it
541 should never be drawn to directly, it would do no harm nevertheless. */
543 /* create additional (symbolic) buffer for double-buffering */
544 ReCreateBitmap(&window, video.width, video.height);
547 static boolean SDLCreateScreen(boolean fullscreen)
549 SDL_Surface *new_surface = NULL;
551 #if defined(TARGET_SDL2)
552 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
553 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
555 int surface_flags_window = SURFACE_FLAGS;
556 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
559 #if defined(TARGET_SDL2)
561 int renderer_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
563 /* If SDL_CreateRenderer() is called from within a VirtualBox Windows VM
564 _without_ enabling 2D/3D acceleration and/or guest additions installed,
565 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
566 it will try to use accelerated graphics and apparently fails miserably) */
567 int renderer_flags = SDL_RENDERER_SOFTWARE;
571 SDLSetScreenSizeAndOffsets(video.width, video.height);
573 int width = video.width;
574 int height = video.height;
575 int screen_width = video.screen_width;
576 int screen_height = video.screen_height;
577 int surface_flags = (fullscreen ? surface_flags_fullscreen :
578 surface_flags_window);
580 // default window size is unscaled
581 video.window_width = screen_width;
582 video.window_height = screen_height;
584 #if defined(TARGET_SDL2)
586 // store if initial screen mode is fullscreen mode when changing screen size
587 video.fullscreen_initial = fullscreen;
589 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
591 video.window_width = window_scaling_factor * screen_width;
592 video.window_height = window_scaling_factor * screen_height;
594 if (sdl_texture_stream)
596 SDL_DestroyTexture(sdl_texture_stream);
597 sdl_texture_stream = NULL;
600 if (sdl_texture_target)
602 SDL_DestroyTexture(sdl_texture_target);
603 sdl_texture_target = NULL;
606 if (!(fullscreen && fullscreen_enabled))
610 SDL_DestroyRenderer(sdl_renderer);
616 SDL_DestroyWindow(sdl_window);
621 if (sdl_window == NULL)
622 sdl_window = SDL_CreateWindow(program.window_title,
623 SDL_WINDOWPOS_CENTERED,
624 SDL_WINDOWPOS_CENTERED,
629 if (sdl_window != NULL)
631 if (sdl_renderer == NULL)
632 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, renderer_flags);
634 if (sdl_renderer != NULL)
636 SDL_RenderSetLogicalSize(sdl_renderer, screen_width, screen_height);
637 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
638 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
640 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
641 SDL_PIXELFORMAT_ARGB8888,
642 SDL_TEXTUREACCESS_STREAMING,
645 if (SDL_RenderTargetSupported(sdl_renderer))
646 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
647 SDL_PIXELFORMAT_ARGB8888,
648 SDL_TEXTUREACCESS_TARGET,
651 if (sdl_texture_stream != NULL)
653 // use SDL default values for RGB masks and no alpha channel
654 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
656 if (new_surface == NULL)
657 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
661 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
666 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
671 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
676 if (gfx.final_screen_bitmap == NULL)
677 gfx.final_screen_bitmap = CreateBitmapStruct();
679 gfx.final_screen_bitmap->width = width;
680 gfx.final_screen_bitmap->height = height;
682 gfx.final_screen_bitmap->surface =
683 SDL_SetVideoMode(width, height, video.depth, surface_flags);
685 if (gfx.final_screen_bitmap->surface != NULL)
688 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
690 if (new_surface == NULL)
691 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
694 new_surface = gfx.final_screen_bitmap->surface;
695 gfx.final_screen_bitmap = NULL;
701 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
705 #if defined(TARGET_SDL2)
706 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
707 if (new_surface != NULL)
708 fullscreen_enabled = fullscreen;
711 if (backbuffer == NULL)
712 backbuffer = CreateBitmapStruct();
714 backbuffer->width = video.width;
715 backbuffer->height = video.height;
717 if (backbuffer->surface)
718 SDL_FreeSurface(backbuffer->surface);
720 backbuffer->surface = new_surface;
722 return (new_surface != NULL);
725 boolean SDLSetVideoMode(boolean fullscreen)
727 boolean success = FALSE;
731 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
733 /* switch display to fullscreen mode, if available */
734 success = SDLCreateScreen(TRUE);
738 /* switching display to fullscreen mode failed -- do not try it again */
739 video.fullscreen_available = FALSE;
743 video.fullscreen_enabled = TRUE;
747 if ((!fullscreen && video.fullscreen_enabled) || !success)
749 /* switch display to window mode */
750 success = SDLCreateScreen(FALSE);
754 /* switching display to window mode failed -- should not happen */
758 video.fullscreen_enabled = FALSE;
759 video.window_scaling_percent = setup.window_scaling_percent;
760 video.window_scaling_quality = setup.window_scaling_quality;
762 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
766 #if defined(TARGET_SDL2)
767 SDLRedrawWindow(); // map window
771 #if defined(PLATFORM_WIN32)
772 // experimental drag and drop code
774 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
777 SDL_SysWMinfo wminfo;
779 boolean wminfo_success = FALSE;
781 SDL_VERSION(&wminfo.version);
782 #if defined(TARGET_SDL2)
784 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
786 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
791 #if defined(TARGET_SDL2)
792 hwnd = wminfo.info.win.window;
794 hwnd = wminfo.window;
797 DragAcceptFiles(hwnd, TRUE);
806 void SDLSetWindowTitle()
808 #if defined(TARGET_SDL2)
809 SDL_SetWindowTitle(sdl_window, program.window_title);
811 SDL_WM_SetCaption(program.window_title, program.window_title);
815 #if defined(TARGET_SDL2)
816 void SDLSetWindowScaling(int window_scaling_percent)
818 if (sdl_window == NULL)
821 float window_scaling_factor = (float)window_scaling_percent / 100;
822 int new_window_width = (int)(window_scaling_factor * video.screen_width);
823 int new_window_height = (int)(window_scaling_factor * video.screen_height);
825 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
827 video.window_scaling_percent = window_scaling_percent;
828 video.window_width = new_window_width;
829 video.window_height = new_window_height;
834 void SDLSetWindowScalingQuality(char *window_scaling_quality)
836 SDL_Texture *new_texture;
838 if (sdl_texture_stream == NULL)
841 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
843 new_texture = SDL_CreateTexture(sdl_renderer,
844 SDL_PIXELFORMAT_ARGB8888,
845 SDL_TEXTUREACCESS_STREAMING,
846 video.width, video.height);
848 if (new_texture != NULL)
850 SDL_DestroyTexture(sdl_texture_stream);
852 sdl_texture_stream = new_texture;
855 if (SDL_RenderTargetSupported(sdl_renderer))
856 new_texture = SDL_CreateTexture(sdl_renderer,
857 SDL_PIXELFORMAT_ARGB8888,
858 SDL_TEXTUREACCESS_TARGET,
859 video.width, video.height);
863 if (new_texture != NULL)
865 SDL_DestroyTexture(sdl_texture_target);
867 sdl_texture_target = new_texture;
872 video.window_scaling_quality = window_scaling_quality;
875 void SDLSetWindowFullscreen(boolean fullscreen)
877 if (sdl_window == NULL)
880 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
882 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
883 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
885 // if screen size was changed in fullscreen mode, correct desktop window size
886 if (!fullscreen && video.fullscreen_initial)
888 SDLSetWindowScaling(setup.window_scaling_percent);
889 SDL_SetWindowPosition(sdl_window,
890 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
892 video.fullscreen_initial = FALSE;
896 void SDLSetDisplaySize()
898 SDL_Rect display_bounds;
900 SDL_GetDisplayBounds(0, &display_bounds);
902 video.display_width = display_bounds.w;
903 video.display_height = display_bounds.h;
906 Error(ERR_DEBUG, "SDL real screen size: %d x %d",
907 video.display_width, video.display_height);
911 void SDLSetScreenSizeAndOffsets(int width, int height)
913 // set default video screen size and offsets
914 video.screen_width = width;
915 video.screen_height = height;
916 video.screen_xoffset = 0;
917 video.screen_yoffset = 0;
919 #if defined(USE_COMPLETE_DISPLAY)
920 float ratio_video = (float) width / height;
921 float ratio_display = (float) video.display_width / video.display_height;
923 if (ratio_video != ratio_display)
925 // adjust drawable screen size to cover the whole device display
927 if (ratio_video < ratio_display)
928 video.screen_width *= ratio_display / ratio_video;
930 video.screen_height *= ratio_video / ratio_display;
932 video.screen_xoffset = (video.screen_width - width) / 2;
933 video.screen_yoffset = (video.screen_height - height) / 2;
936 Error(ERR_DEBUG, "Changing screen from %dx%d to %dx%d (%.2f to %.2f)",
938 video.screen_width, video.screen_height,
939 ratio_video, ratio_display);
945 void SDLSetScreenSizeForRenderer(int width, int height)
947 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
950 void SDLSetScreenProperties()
952 SDLSetScreenSizeAndOffsets(video.width, video.height);
953 SDLSetScreenSizeForRenderer(video.screen_width, video.screen_height);
958 void SDLSetScreenRenderingMode(char *screen_rendering_mode)
960 #if defined(TARGET_SDL2)
961 video.screen_rendering_mode =
962 (strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
963 SPECIAL_RENDERING_BITMAP :
964 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
965 SPECIAL_RENDERING_TARGET:
966 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
967 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
969 video.screen_rendering_mode = SPECIAL_RENDERING_BITMAP;
973 void SDLRedrawWindow()
975 UpdateScreen_WithoutFrameDelay(NULL);
978 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
981 SDL_Surface *surface =
982 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
985 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
987 SDLSetNativeSurface(&surface);
989 bitmap->surface = surface;
992 void SDLFreeBitmapPointers(Bitmap *bitmap)
995 SDL_FreeSurface(bitmap->surface);
996 if (bitmap->surface_masked)
997 SDL_FreeSurface(bitmap->surface_masked);
999 bitmap->surface = NULL;
1000 bitmap->surface_masked = NULL;
1002 #if defined(TARGET_SDL2)
1003 if (bitmap->texture)
1004 SDL_DestroyTexture(bitmap->texture);
1005 if (bitmap->texture_masked)
1006 SDL_DestroyTexture(bitmap->texture_masked);
1008 bitmap->texture = NULL;
1009 bitmap->texture_masked = NULL;
1013 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1014 int src_x, int src_y, int width, int height,
1015 int dst_x, int dst_y, int mask_mode)
1017 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1018 SDL_Rect src_rect, dst_rect;
1023 src_rect.h = height;
1028 dst_rect.h = height;
1030 // if (src_bitmap != backbuffer || dst_bitmap != window)
1031 if (!(src_bitmap == backbuffer && dst_bitmap == window))
1032 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
1033 src_bitmap->surface_masked : src_bitmap->surface),
1034 &src_rect, real_dst_bitmap->surface, &dst_rect);
1036 if (dst_bitmap == window)
1037 UpdateScreen_WithFrameDelay(&dst_rect);
1040 void SDLBlitTexture(Bitmap *bitmap,
1041 int src_x, int src_y, int width, int height,
1042 int dst_x, int dst_y, int mask_mode)
1044 #if defined(TARGET_SDL2)
1045 SDL_Texture *texture;
1050 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
1052 if (texture == NULL)
1058 src_rect.h = height;
1063 dst_rect.h = height;
1065 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
1069 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
1072 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
1080 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
1082 if (dst_bitmap == window)
1083 UpdateScreen_WithFrameDelay(&rect);
1086 void PrepareFadeBitmap(int draw_target)
1088 Bitmap *fade_bitmap =
1089 (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
1090 draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
1092 if (fade_bitmap == NULL)
1095 // copy backbuffer to fading buffer
1096 BlitBitmap(backbuffer, fade_bitmap, 0, 0, gfx.win_xsize, gfx.win_ysize, 0, 0);
1098 // add border and animations to fading buffer
1099 FinalizeScreen(draw_target);
1102 void SDLFadeRectangle(int x, int y, int width, int height,
1103 int fade_mode, int fade_delay, int post_delay,
1104 void (*draw_border_function)(void))
1106 SDL_Surface *surface_backup = gfx.fade_bitmap_backup->surface;
1107 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
1108 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
1109 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
1110 SDL_Surface *surface_screen = backbuffer->surface;
1111 SDL_Rect src_rect, dst_rect;
1113 int src_x = x, src_y = y;
1114 int dst_x = x, dst_y = y;
1115 unsigned int time_last, time_current;
1117 // store function for drawing global masked border
1118 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
1120 // deactivate drawing of global border while fading, if needed
1121 if (draw_border_function == NULL)
1122 gfx.draw_global_border_function = NULL;
1127 src_rect.h = height;
1131 dst_rect.w = width; /* (ignored) */
1132 dst_rect.h = height; /* (ignored) */
1134 dst_rect2 = dst_rect;
1136 // before fading in, store backbuffer (without animation graphics)
1137 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
1138 SDL_BlitSurface(surface_screen, &dst_rect, surface_backup, &src_rect);
1140 /* copy source and target surfaces to temporary surfaces for fading */
1141 if (fade_mode & FADE_TYPE_TRANSFORM)
1143 // (source and target fading buffer already prepared)
1145 else if (fade_mode & FADE_TYPE_FADE_IN)
1147 // (target fading buffer already prepared)
1148 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1150 else /* FADE_TYPE_FADE_OUT */
1152 // (source fading buffer already prepared)
1153 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1156 time_current = SDL_GetTicks();
1158 if (fade_mode == FADE_MODE_MELT)
1160 boolean done = FALSE;
1161 int melt_pixels = 2;
1162 int melt_columns = width / melt_pixels;
1163 int ypos[melt_columns];
1164 int max_steps = height / 8 + 32;
1169 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1171 SDLSetAlpha(surface_target, FALSE, 0); /* disable alpha blending */
1173 ypos[0] = -GetSimpleRandom(16);
1175 for (i = 1 ; i < melt_columns; i++)
1177 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1179 ypos[i] = ypos[i - 1] + r;
1192 time_last = time_current;
1193 time_current = SDL_GetTicks();
1194 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1195 steps_final = MIN(MAX(0, steps), max_steps);
1199 done = (steps_done >= steps_final);
1201 for (i = 0 ; i < melt_columns; i++)
1209 else if (ypos[i] < height)
1214 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1216 if (ypos[i] + dy >= height)
1217 dy = height - ypos[i];
1219 /* copy part of (appearing) target surface to upper area */
1220 src_rect.x = src_x + i * melt_pixels;
1221 // src_rect.y = src_y + ypos[i];
1223 src_rect.w = melt_pixels;
1225 src_rect.h = ypos[i] + dy;
1227 dst_rect.x = dst_x + i * melt_pixels;
1228 // dst_rect.y = dst_y + ypos[i];
1231 if (steps_done >= steps_final)
1232 SDL_BlitSurface(surface_target, &src_rect,
1233 surface_screen, &dst_rect);
1237 /* copy part of (disappearing) source surface to lower area */
1238 src_rect.x = src_x + i * melt_pixels;
1240 src_rect.w = melt_pixels;
1241 src_rect.h = height - ypos[i];
1243 dst_rect.x = dst_x + i * melt_pixels;
1244 dst_rect.y = dst_y + ypos[i];
1246 if (steps_done >= steps_final)
1247 SDL_BlitSurface(surface_source, &src_rect,
1248 surface_screen, &dst_rect);
1254 src_rect.x = src_x + i * melt_pixels;
1256 src_rect.w = melt_pixels;
1257 src_rect.h = height;
1259 dst_rect.x = dst_x + i * melt_pixels;
1262 if (steps_done >= steps_final)
1263 SDL_BlitSurface(surface_target, &src_rect,
1264 surface_screen, &dst_rect);
1268 if (steps_done >= steps_final)
1270 if (draw_border_function != NULL)
1271 draw_border_function();
1273 UpdateScreen_WithFrameDelay(&dst_rect2);
1277 else if (fade_mode == FADE_MODE_CURTAIN)
1281 int xx_size = width / 2;
1283 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1285 SDLSetAlpha(surface_source, FALSE, 0); /* disable alpha blending */
1287 for (xx = 0; xx < xx_size;)
1289 time_last = time_current;
1290 time_current = SDL_GetTicks();
1291 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1292 xx_final = MIN(MAX(0, xx), xx_size);
1297 src_rect.h = height;
1302 /* draw new (target) image to screen buffer */
1303 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1305 if (xx_final < xx_size)
1307 src_rect.w = xx_size - xx_final;
1308 src_rect.h = height;
1310 /* draw old (source) image to screen buffer (left side) */
1312 src_rect.x = src_x + xx_final;
1315 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1317 /* draw old (source) image to screen buffer (right side) */
1319 src_rect.x = src_x + xx_size;
1320 dst_rect.x = dst_x + xx_size + xx_final;
1322 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1325 if (draw_border_function != NULL)
1326 draw_border_function();
1328 /* only update the region of the screen that is affected from fading */
1329 UpdateScreen_WithFrameDelay(&dst_rect2);
1332 else /* fading in, fading out or cross-fading */
1337 for (alpha = 0.0; alpha < 255.0;)
1339 time_last = time_current;
1340 time_current = SDL_GetTicks();
1341 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1342 alpha_final = MIN(MAX(0, alpha), 255);
1344 /* draw existing (source) image to screen buffer */
1345 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1347 /* draw new (target) image to screen buffer using alpha blending */
1348 SDLSetAlpha(surface_target, TRUE, alpha_final);
1349 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1351 if (draw_border_function != NULL)
1352 draw_border_function();
1354 /* only update the region of the screen that is affected from fading */
1355 UpdateScreen_WithFrameDelay(&dst_rect);
1361 unsigned int time_post_delay;
1363 time_current = SDL_GetTicks();
1364 time_post_delay = time_current + post_delay;
1366 while (time_current < time_post_delay)
1368 // updating the screen contains waiting for frame delay (non-busy)
1369 UpdateScreen_WithFrameDelay(NULL);
1371 time_current = SDL_GetTicks();
1375 // restore function for drawing global masked border
1376 gfx.draw_global_border_function = draw_global_border_function;
1378 // after fading in, restore backbuffer (without animation graphics)
1379 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
1380 SDL_BlitSurface(surface_backup, &dst_rect, surface_screen, &src_rect);
1383 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1384 int to_x, int to_y, Uint32 color)
1386 SDL_Surface *surface = dst_bitmap->surface;
1390 swap_numbers(&from_x, &to_x);
1393 swap_numbers(&from_y, &to_y);
1397 rect.w = (to_x - from_x + 1);
1398 rect.h = (to_y - from_y + 1);
1400 SDL_FillRect(surface, &rect, color);
1403 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1404 int to_x, int to_y, Uint32 color)
1406 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1409 #if ENABLE_UNUSED_CODE
1410 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1411 int num_points, Uint32 color)
1416 for (i = 0; i < num_points - 1; i++)
1418 for (x = 0; x < line_width; x++)
1420 for (y = 0; y < line_width; y++)
1422 int dx = x - line_width / 2;
1423 int dy = y - line_width / 2;
1425 if ((x == 0 && y == 0) ||
1426 (x == 0 && y == line_width - 1) ||
1427 (x == line_width - 1 && y == 0) ||
1428 (x == line_width - 1 && y == line_width - 1))
1431 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1432 points[i+1].x + dx, points[i+1].y + dy, color);
1439 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1441 SDL_Surface *surface = src_bitmap->surface;
1443 switch (surface->format->BytesPerPixel)
1445 case 1: /* assuming 8-bpp */
1447 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1451 case 2: /* probably 15-bpp or 16-bpp */
1453 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1457 case 3: /* slow 24-bpp mode; usually not used */
1459 /* does this work? */
1460 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1464 shift = surface->format->Rshift;
1465 color |= *(pix + shift / 8) >> shift;
1466 shift = surface->format->Gshift;
1467 color |= *(pix + shift / 8) >> shift;
1468 shift = surface->format->Bshift;
1469 color |= *(pix + shift / 8) >> shift;
1475 case 4: /* probably 32-bpp */
1477 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1486 /* ========================================================================= */
1487 /* The following functions were taken from the SGE library */
1488 /* (SDL Graphics Extension Library) by Anders Lindström */
1489 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1490 /* ========================================================================= */
1492 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1494 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1496 switch (surface->format->BytesPerPixel)
1500 /* Assuming 8-bpp */
1501 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1507 /* Probably 15-bpp or 16-bpp */
1508 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1514 /* Slow 24-bpp mode, usually not used */
1518 /* Gack - slow, but endian correct */
1519 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1520 shift = surface->format->Rshift;
1521 *(pix+shift/8) = color>>shift;
1522 shift = surface->format->Gshift;
1523 *(pix+shift/8) = color>>shift;
1524 shift = surface->format->Bshift;
1525 *(pix+shift/8) = color>>shift;
1531 /* Probably 32-bpp */
1532 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1539 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1540 Uint8 R, Uint8 G, Uint8 B)
1542 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1545 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1547 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1550 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1552 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1555 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1560 /* Gack - slow, but endian correct */
1561 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1562 shift = surface->format->Rshift;
1563 *(pix+shift/8) = color>>shift;
1564 shift = surface->format->Gshift;
1565 *(pix+shift/8) = color>>shift;
1566 shift = surface->format->Bshift;
1567 *(pix+shift/8) = color>>shift;
1570 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1572 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1575 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1577 switch (dest->format->BytesPerPixel)
1580 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1584 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1588 _PutPixel24(dest,x,y,color);
1592 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1597 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1599 if (SDL_MUSTLOCK(surface))
1601 if (SDL_LockSurface(surface) < 0)
1607 _PutPixel(surface, x, y, color);
1609 if (SDL_MUSTLOCK(surface))
1611 SDL_UnlockSurface(surface);
1615 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1616 Uint8 r, Uint8 g, Uint8 b)
1618 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1621 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1623 if (y >= 0 && y <= dest->h - 1)
1625 switch (dest->format->BytesPerPixel)
1628 return y*dest->pitch;
1632 return y*dest->pitch/2;
1636 return y*dest->pitch;
1640 return y*dest->pitch/4;
1648 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1650 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1652 switch (surface->format->BytesPerPixel)
1656 /* Assuming 8-bpp */
1657 *((Uint8 *)surface->pixels + ypitch + x) = color;
1663 /* Probably 15-bpp or 16-bpp */
1664 *((Uint16 *)surface->pixels + ypitch + x) = color;
1670 /* Slow 24-bpp mode, usually not used */
1674 /* Gack - slow, but endian correct */
1675 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1676 shift = surface->format->Rshift;
1677 *(pix+shift/8) = color>>shift;
1678 shift = surface->format->Gshift;
1679 *(pix+shift/8) = color>>shift;
1680 shift = surface->format->Bshift;
1681 *(pix+shift/8) = color>>shift;
1687 /* Probably 32-bpp */
1688 *((Uint32 *)surface->pixels + ypitch + x) = color;
1695 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1700 if (SDL_MUSTLOCK(Surface))
1702 if (SDL_LockSurface(Surface) < 0)
1715 /* Do the clipping */
1716 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1720 if (x2 > Surface->w - 1)
1721 x2 = Surface->w - 1;
1728 SDL_FillRect(Surface, &l, Color);
1730 if (SDL_MUSTLOCK(Surface))
1732 SDL_UnlockSurface(Surface);
1736 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1737 Uint8 R, Uint8 G, Uint8 B)
1739 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1742 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1753 /* Do the clipping */
1754 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1758 if (x2 > Surface->w - 1)
1759 x2 = Surface->w - 1;
1766 SDL_FillRect(Surface, &l, Color);
1769 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1774 if (SDL_MUSTLOCK(Surface))
1776 if (SDL_LockSurface(Surface) < 0)
1789 /* Do the clipping */
1790 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1794 if (y2 > Surface->h - 1)
1795 y2 = Surface->h - 1;
1802 SDL_FillRect(Surface, &l, Color);
1804 if (SDL_MUSTLOCK(Surface))
1806 SDL_UnlockSurface(Surface);
1810 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1811 Uint8 R, Uint8 G, Uint8 B)
1813 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1816 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1827 /* Do the clipping */
1828 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1832 if (y2 > Surface->h - 1)
1833 y2 = Surface->h - 1;
1840 SDL_FillRect(Surface, &l, Color);
1843 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1844 Sint16 x2, Sint16 y2, Uint32 Color,
1845 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1848 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1853 sdx = (dx < 0) ? -1 : 1;
1854 sdy = (dy < 0) ? -1 : 1;
1866 for (x = 0; x < dx; x++)
1868 Callback(Surface, px, py, Color);
1882 for (y = 0; y < dy; y++)
1884 Callback(Surface, px, py, Color);
1898 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1899 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1900 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1903 sge_DoLine(Surface, X1, Y1, X2, Y2,
1904 SDL_MapRGB(Surface->format, R, G, B), Callback);
1907 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1910 if (SDL_MUSTLOCK(Surface))
1912 if (SDL_LockSurface(Surface) < 0)
1917 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1919 /* unlock the display */
1920 if (SDL_MUSTLOCK(Surface))
1922 SDL_UnlockSurface(Surface);
1926 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1927 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1929 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1932 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1934 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1939 -----------------------------------------------------------------------------
1940 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1941 -----------------------------------------------------------------------------
1944 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1945 int width, int height, Uint32 color)
1949 for (y = src_y; y < src_y + height; y++)
1951 for (x = src_x; x < src_x + width; x++)
1953 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1955 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1960 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1961 int src_x, int src_y, int width, int height,
1962 int dst_x, int dst_y)
1966 for (y = 0; y < height; y++)
1968 for (x = 0; x < width; x++)
1970 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1972 if (pixel != BLACK_PIXEL)
1973 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1979 /* ========================================================================= */
1980 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1981 /* (Rotozoomer) by Andreas Schiffler */
1982 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1983 /* ========================================================================= */
1986 -----------------------------------------------------------------------------
1989 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1990 -----------------------------------------------------------------------------
2001 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
2004 tColorRGBA *sp, *csp, *dp;
2008 sp = csp = (tColorRGBA *) src->pixels;
2009 dp = (tColorRGBA *) dst->pixels;
2010 dgap = dst->pitch - dst->w * 4;
2012 for (y = 0; y < dst->h; y++)
2016 for (x = 0; x < dst->w; x++)
2018 tColorRGBA *sp0 = sp;
2019 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
2020 tColorRGBA *sp00 = &sp0[0];
2021 tColorRGBA *sp01 = &sp0[1];
2022 tColorRGBA *sp10 = &sp1[0];
2023 tColorRGBA *sp11 = &sp1[1];
2026 /* create new color pixel from all four source color pixels */
2027 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
2028 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
2029 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
2030 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
2035 /* advance source pointers */
2038 /* advance destination pointer */
2042 /* advance source pointer */
2043 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
2045 /* advance destination pointers */
2046 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2052 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
2054 int x, y, *sax, *say, *csax, *csay;
2056 tColorRGBA *sp, *csp, *csp0, *dp;
2059 /* use specialized zoom function when scaling down to exactly half size */
2060 if (src->w == 2 * dst->w &&
2061 src->h == 2 * dst->h)
2062 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
2064 /* variable setup */
2065 sx = (float) src->w / (float) dst->w;
2066 sy = (float) src->h / (float) dst->h;
2068 /* allocate memory for row increments */
2069 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
2070 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
2072 /* precalculate row increments */
2073 for (x = 0; x <= dst->w; x++)
2074 *csax++ = (int)(sx * x);
2076 for (y = 0; y <= dst->h; y++)
2077 *csay++ = (int)(sy * y);
2080 sp = csp = csp0 = (tColorRGBA *) src->pixels;
2081 dp = (tColorRGBA *) dst->pixels;
2082 dgap = dst->pitch - dst->w * 4;
2085 for (y = 0; y < dst->h; y++)
2090 for (x = 0; x < dst->w; x++)
2095 /* advance source pointers */
2099 /* advance destination pointer */
2103 /* advance source pointer */
2105 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
2107 /* advance destination pointers */
2108 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2118 -----------------------------------------------------------------------------
2121 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2122 -----------------------------------------------------------------------------
2125 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2127 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2128 Uint8 *sp, *dp, *csp;
2131 /* variable setup */
2132 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2133 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2135 /* allocate memory for row increments */
2136 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2137 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2139 /* precalculate row increments */
2142 for (x = 0; x < dst->w; x++)
2145 *csax = (csx >> 16);
2152 for (y = 0; y < dst->h; y++)
2155 *csay = (csy >> 16);
2162 for (x = 0; x < dst->w; x++)
2170 for (y = 0; y < dst->h; y++)
2177 sp = csp = (Uint8 *) src->pixels;
2178 dp = (Uint8 *) dst->pixels;
2179 dgap = dst->pitch - dst->w;
2183 for (y = 0; y < dst->h; y++)
2187 for (x = 0; x < dst->w; x++)
2192 /* advance source pointers */
2196 /* advance destination pointer */
2200 /* advance source pointer (for row) */
2201 csp += ((*csay) * src->pitch);
2204 /* advance destination pointers */
2215 -----------------------------------------------------------------------------
2218 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2219 'zoomx' and 'zoomy' are scaling factors for width and height.
2220 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2221 into a 32bit RGBA format on the fly.
2222 -----------------------------------------------------------------------------
2225 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2227 SDL_Surface *zoom_src = NULL;
2228 SDL_Surface *zoom_dst = NULL;
2229 boolean is_converted = FALSE;
2236 /* determine if source surface is 32 bit or 8 bit */
2237 is_32bit = (src->format->BitsPerPixel == 32);
2239 if (is_32bit || src->format->BitsPerPixel == 8)
2241 /* use source surface 'as is' */
2246 /* new source surface is 32 bit with a defined RGB ordering */
2247 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2248 0x000000ff, 0x0000ff00, 0x00ff0000,
2249 (src->format->Amask ? 0xff000000 : 0));
2250 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2252 is_converted = TRUE;
2255 /* allocate surface to completely contain the zoomed surface */
2258 /* target surface is 32 bit with source RGBA/ABGR ordering */
2259 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2260 zoom_src->format->Rmask,
2261 zoom_src->format->Gmask,
2262 zoom_src->format->Bmask,
2263 zoom_src->format->Amask);
2267 /* target surface is 8 bit */
2268 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2272 /* lock source surface */
2273 SDL_LockSurface(zoom_src);
2275 /* check which kind of surface we have */
2278 /* call the 32 bit transformation routine to do the zooming */
2279 zoomSurfaceRGBA(zoom_src, zoom_dst);
2284 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2285 zoom_dst->format->palette->colors[i] =
2286 zoom_src->format->palette->colors[i];
2287 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2289 /* call the 8 bit transformation routine to do the zooming */
2290 zoomSurfaceY(zoom_src, zoom_dst);
2293 /* unlock source surface */
2294 SDL_UnlockSurface(zoom_src);
2296 /* free temporary surface */
2298 SDL_FreeSurface(zoom_src);
2300 /* return destination surface */
2304 static SDL_Surface *SDLGetOpaqueSurface(SDL_Surface *surface)
2306 SDL_Surface *new_surface;
2308 if (surface == NULL)
2311 if ((new_surface = SDLGetNativeSurface(surface)) == NULL)
2312 Error(ERR_EXIT, "SDLGetNativeSurface() failed");
2314 /* remove alpha channel from native non-transparent surface, if defined */
2315 SDLSetAlpha(new_surface, FALSE, 0);
2317 /* remove transparent color from native non-transparent surface, if defined */
2318 SDL_SetColorKey(new_surface, UNSET_TRANSPARENT_PIXEL, 0);
2323 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2325 Bitmap *dst_bitmap = CreateBitmapStruct();
2326 SDL_Surface *src_surface = src_bitmap->surface_masked;
2327 SDL_Surface *dst_surface;
2329 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2330 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2332 dst_bitmap->width = dst_width;
2333 dst_bitmap->height = dst_height;
2335 /* create zoomed temporary surface from source surface */
2336 dst_surface = zoomSurface(src_surface, dst_width, dst_height);
2338 /* create native format destination surface from zoomed temporary surface */
2339 SDLSetNativeSurface(&dst_surface);
2341 /* set color key for zoomed surface from source surface, if defined */
2342 if (SDLHasColorKey(src_surface))
2343 SDL_SetColorKey(dst_surface, SET_TRANSPARENT_PIXEL,
2344 SDLGetColorKey(src_surface));
2346 /* create native non-transparent surface for opaque blitting */
2347 dst_bitmap->surface = SDLGetOpaqueSurface(dst_surface);
2349 /* set native transparent surface for masked blitting */
2350 dst_bitmap->surface_masked = dst_surface;
2356 /* ========================================================================= */
2357 /* load image to bitmap */
2358 /* ========================================================================= */
2360 Bitmap *SDLLoadImage(char *filename)
2362 Bitmap *new_bitmap = CreateBitmapStruct();
2363 SDL_Surface *sdl_image_tmp;
2365 print_timestamp_init("SDLLoadImage");
2367 print_timestamp_time(getBaseNamePtr(filename));
2369 /* load image to temporary surface */
2370 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2371 Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError());
2373 print_timestamp_time("IMG_Load");
2375 UPDATE_BUSY_STATE();
2377 /* create native non-transparent surface for current image */
2378 if ((new_bitmap->surface = SDLGetOpaqueSurface(sdl_image_tmp)) == NULL)
2379 Error(ERR_EXIT, "SDLGetOpaqueSurface() failed");
2381 print_timestamp_time("SDLGetNativeSurface (opaque)");
2383 UPDATE_BUSY_STATE();
2385 /* set black pixel to transparent if no alpha channel / transparent color */
2386 if (!SDLHasAlpha(sdl_image_tmp) &&
2387 !SDLHasColorKey(sdl_image_tmp))
2388 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2389 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2391 /* create native transparent surface for current image */
2392 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2393 Error(ERR_EXIT, "SDLGetNativeSurface() failed");
2395 print_timestamp_time("SDLGetNativeSurface (masked)");
2397 UPDATE_BUSY_STATE();
2399 /* free temporary surface */
2400 SDL_FreeSurface(sdl_image_tmp);
2402 new_bitmap->width = new_bitmap->surface->w;
2403 new_bitmap->height = new_bitmap->surface->h;
2405 print_timestamp_done("SDLLoadImage");
2411 /* ------------------------------------------------------------------------- */
2412 /* custom cursor fuctions */
2413 /* ------------------------------------------------------------------------- */
2415 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2417 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2418 cursor_info->width, cursor_info->height,
2419 cursor_info->hot_x, cursor_info->hot_y);
2422 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2424 static struct MouseCursorInfo *last_cursor_info = NULL;
2425 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2426 static SDL_Cursor *cursor_default = NULL;
2427 static SDL_Cursor *cursor_current = NULL;
2429 /* if invoked for the first time, store the SDL default cursor */
2430 if (cursor_default == NULL)
2431 cursor_default = SDL_GetCursor();
2433 /* only create new cursor if cursor info (custom only) has changed */
2434 if (cursor_info != NULL && cursor_info != last_cursor_info)
2436 cursor_current = create_cursor(cursor_info);
2437 last_cursor_info = cursor_info;
2440 /* only set new cursor if cursor info (custom or NULL) has changed */
2441 if (cursor_info != last_cursor_info2)
2442 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2444 last_cursor_info2 = cursor_info;
2448 /* ========================================================================= */
2449 /* audio functions */
2450 /* ========================================================================= */
2452 void SDLOpenAudio(void)
2454 #if !defined(TARGET_SDL2)
2455 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2456 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2459 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2461 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2465 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2466 AUDIO_NUM_CHANNELS_STEREO,
2467 setup.system.audio_fragment_size) < 0)
2469 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2473 audio.sound_available = TRUE;
2474 audio.music_available = TRUE;
2475 audio.loops_available = TRUE;
2476 audio.sound_enabled = TRUE;
2478 /* set number of available mixer channels */
2479 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2480 audio.music_channel = MUSIC_CHANNEL;
2481 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2483 Mixer_InitChannels();
2486 void SDLCloseAudio(void)
2489 Mix_HaltChannel(-1);
2492 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2496 /* ========================================================================= */
2497 /* event functions */
2498 /* ========================================================================= */
2500 void SDLNextEvent(Event *event)
2502 SDL_WaitEvent(event);
2505 void SDLHandleWindowManagerEvent(Event *event)
2508 #if defined(PLATFORM_WIN32)
2509 // experimental drag and drop code
2511 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2512 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2514 #if defined(TARGET_SDL2)
2515 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2517 if (syswmmsg->msg == WM_DROPFILES)
2520 #if defined(TARGET_SDL2)
2521 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2523 HDROP hdrop = (HDROP)syswmmsg->wParam;
2527 printf("::: SDL_SYSWMEVENT:\n");
2529 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2531 for (i = 0; i < num_files; i++)
2533 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2534 char buffer[buffer_len + 1];
2536 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2538 printf("::: - '%s'\n", buffer);
2541 #if defined(TARGET_SDL2)
2542 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2544 DragFinish((HDROP)syswmmsg->wParam);
2552 /* ========================================================================= */
2553 /* joystick functions */
2554 /* ========================================================================= */
2556 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2557 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2558 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2560 static boolean SDLOpenJoystick(int nr)
2562 if (nr < 0 || nr > MAX_PLAYERS)
2565 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2568 static void SDLCloseJoystick(int nr)
2570 if (nr < 0 || nr > MAX_PLAYERS)
2573 SDL_JoystickClose(sdl_joystick[nr]);
2575 sdl_joystick[nr] = NULL;
2578 static boolean SDLCheckJoystickOpened(int nr)
2580 if (nr < 0 || nr > MAX_PLAYERS)
2583 #if defined(TARGET_SDL2)
2584 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2586 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2590 void HandleJoystickEvent(Event *event)
2594 case SDL_JOYAXISMOTION:
2595 if (event->jaxis.axis < 2)
2596 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2599 case SDL_JOYBUTTONDOWN:
2600 if (event->jbutton.button < 2)
2601 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2604 case SDL_JOYBUTTONUP:
2605 if (event->jbutton.button < 2)
2606 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2614 void SDLInitJoysticks()
2616 static boolean sdl_joystick_subsystem_initialized = FALSE;
2617 boolean print_warning = !sdl_joystick_subsystem_initialized;
2620 if (!sdl_joystick_subsystem_initialized)
2622 sdl_joystick_subsystem_initialized = TRUE;
2624 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2626 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2631 for (i = 0; i < MAX_PLAYERS; i++)
2633 /* get configured joystick for this player */
2634 char *device_name = setup.input[i].joy.device_name;
2635 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2637 if (joystick_nr >= SDL_NumJoysticks())
2639 if (setup.input[i].use_joystick && print_warning)
2640 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2645 /* misuse joystick file descriptor variable to store joystick number */
2646 joystick.fd[i] = joystick_nr;
2648 if (joystick_nr == -1)
2651 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2652 if (SDLCheckJoystickOpened(joystick_nr))
2653 SDLCloseJoystick(joystick_nr);
2655 if (!setup.input[i].use_joystick)
2658 if (!SDLOpenJoystick(joystick_nr))
2661 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2666 joystick.status = JOYSTICK_ACTIVATED;
2670 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2672 if (nr < 0 || nr >= MAX_PLAYERS)
2676 *x = sdl_js_axis[nr][0];
2678 *y = sdl_js_axis[nr][1];
2681 *b1 = sdl_js_button[nr][0];
2683 *b2 = sdl_js_button[nr][1];
2688 static void DrawTouchInputOverlay()
2690 #if defined(USE_TOUCH_INPUT_OVERLAY)
2691 static SDL_Texture *texture = NULL;
2692 static boolean initialized = FALSE;
2693 static boolean deactivated = TRUE;
2694 static int width = 0, height = 0;
2695 static int alpha_max = SDL_ALPHA_OPAQUE / 2;
2696 static int alpha_step = 5;
2697 static int alpha_last = 0;
2698 static int alpha = 0;
2700 if (!overlay.active && deactivated)
2705 if (alpha < alpha_max)
2706 alpha = MIN(alpha + alpha_step, alpha_max);
2708 deactivated = FALSE;
2712 alpha = MAX(0, alpha - alpha_step);
2720 char *basename = "overlay/VirtualButtons.png";
2721 char *filename = getCustomImageFilename(basename);
2723 if (filename == NULL)
2724 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
2726 SDL_Surface *surface;
2728 if ((surface = IMG_Load(filename)) == NULL)
2729 Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError());
2732 height = surface->h;
2734 /* set black pixel to transparent if no alpha channel / transparent color */
2735 if (!SDLHasAlpha(surface) &&
2736 !SDLHasColorKey(surface))
2737 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
2738 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
2740 if ((texture = SDLCreateTextureFromSurface(surface)) == NULL)
2741 Error(ERR_EXIT, "SDLCreateTextureFromSurface() failed");
2743 SDL_FreeSurface(surface);
2745 SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
2746 SDL_SetTextureAlphaMod(texture, alpha_max);
2751 if (alpha != alpha_last)
2752 SDL_SetTextureAlphaMod(texture, alpha);
2756 SDL_Rect src_rect = { 0, 0, width, height };
2757 SDL_Rect dst_rect = { 0, 0, video.screen_width, video.screen_height };
2759 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);