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 void SDLLimitScreenUpdates(boolean enable)
42 limit_screen_updates = enable;
45 static void FinalizeScreen()
47 // copy global animations to render target buffer, if defined (below border)
48 if (gfx.draw_global_anim_function != NULL)
49 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
51 // copy global masked border to render target buffer, if defined
52 if (gfx.draw_global_border_function != NULL)
53 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
55 // copy global animations to render target buffer, if defined (above border)
56 if (gfx.draw_global_anim_function != NULL)
57 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
60 static void UpdateScreenExt(SDL_Rect *rect, boolean with_frame_delay)
62 static unsigned int update_screen_delay = 0;
63 unsigned int update_screen_delay_value = 50; /* (milliseconds) */
64 SDL_Surface *screen = backbuffer->surface;
66 if (limit_screen_updates &&
67 !DelayReached(&update_screen_delay, update_screen_delay_value))
70 LimitScreenUpdates(FALSE);
74 static int LastFrameCounter = 0;
75 boolean changed = (FrameCounter != LastFrameCounter);
77 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
78 (changed ? "-" : "SAME FRAME UPDATED"));
80 LastFrameCounter = FrameCounter;
89 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP &&
90 gfx.final_screen_bitmap != NULL) // may not be initialized yet
92 // draw global animations using bitmaps instead of using textures
93 // to prevent texture scaling artefacts (this is potentially slower)
95 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
96 gfx.win_xsize, gfx.win_ysize, 0, 0);
100 screen = gfx.final_screen_bitmap->surface;
102 // force full window redraw
106 #if defined(TARGET_SDL2)
107 SDL_Texture *sdl_texture = sdl_texture_stream;
109 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET)
110 sdl_texture = sdl_texture_target;
114 int bytes_x = screen->pitch / video.width;
115 int bytes_y = screen->pitch;
117 SDL_UpdateTexture(sdl_texture, rect,
118 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
123 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
126 // clear render target buffer
127 SDL_RenderClear(sdl_renderer);
129 // set renderer to use target texture for rendering
130 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
131 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
132 SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
134 // copy backbuffer texture to render target buffer
135 if (video.screen_rendering_mode != SPECIAL_RENDERING_TARGET)
136 SDL_RenderCopy(sdl_renderer, sdl_texture_stream, NULL, NULL);
138 if (video.screen_rendering_mode != SPECIAL_RENDERING_BITMAP)
141 // when using target texture, copy it to screen buffer
142 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
143 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
145 SDL_SetRenderTarget(sdl_renderer, NULL);
146 SDL_RenderCopy(sdl_renderer, sdl_texture_target, NULL, NULL);
150 // global synchronization point of the game to align video frame delay
151 if (with_frame_delay)
152 WaitUntilDelayReached(&video.frame_delay, video.frame_delay_value);
154 #if defined(TARGET_SDL2)
155 // show render target buffer on screen
156 SDL_RenderPresent(sdl_renderer);
159 SDL_UpdateRects(screen, 1, rect);
161 SDL_UpdateRect(screen, 0, 0, 0, 0);
165 static void UpdateScreen_WithFrameDelay(SDL_Rect *rect)
167 UpdateScreenExt(rect, TRUE);
170 static void UpdateScreen_WithoutFrameDelay(SDL_Rect *rect)
172 UpdateScreenExt(rect, FALSE);
175 static void SDLSetWindowIcon(char *basename)
177 /* (setting the window icon on Mac OS X would replace the high-quality
178 dock icon with the currently smaller (and uglier) icon from file) */
180 #if !defined(PLATFORM_MACOSX)
181 char *filename = getCustomImageFilename(basename);
182 SDL_Surface *surface;
184 if (filename == NULL)
186 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
191 if ((surface = IMG_Load(filename)) == NULL)
193 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
198 /* set transparent color */
199 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
200 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
202 #if defined(TARGET_SDL2)
203 SDL_SetWindowIcon(sdl_window, surface);
205 SDL_WM_SetIcon(surface, NULL);
210 #if defined(TARGET_SDL2)
212 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
213 SDL_PixelFormat *format2)
215 return (format1->format == format2->format &&
216 format1->BitsPerPixel == format2->BitsPerPixel &&
217 format1->BytesPerPixel == format2->BytesPerPixel &&
218 format1->Rmask == format2->Rmask &&
219 format1->Gmask == format2->Gmask &&
220 format1->Bmask == format2->Bmask &&
221 format1->Amask == format2->Amask);
224 boolean SDLSetNativeSurface(SDL_Surface **surface)
226 SDL_Surface *new_surface;
228 if (surface == NULL ||
230 backbuffer == NULL ||
231 backbuffer->surface == NULL)
234 // if pixel format already optimized for destination surface, do nothing
235 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
238 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
240 if (new_surface == NULL)
241 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
243 SDL_FreeSurface(*surface);
245 *surface = new_surface;
250 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
252 SDL_PixelFormat format;
253 SDL_Surface *new_surface;
258 if (backbuffer && backbuffer->surface)
260 format = *backbuffer->surface->format;
261 format.Amask = surface->format->Amask; // keep alpha channel
265 format = *surface->format;
268 new_surface = SDL_ConvertSurface(surface, &format, 0);
270 if (new_surface == NULL)
271 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
278 boolean SDLSetNativeSurface(SDL_Surface **surface)
280 SDL_Surface *new_surface;
282 if (surface == NULL ||
287 new_surface = SDL_DisplayFormat(*surface);
289 if (new_surface == NULL)
290 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
292 SDL_FreeSurface(*surface);
294 *surface = new_surface;
299 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
301 SDL_Surface *new_surface;
303 if (video.initialized)
304 new_surface = SDL_DisplayFormat(surface);
306 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
308 if (new_surface == NULL)
309 Error(ERR_EXIT, "%s() failed: %s",
310 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
318 #if defined(TARGET_SDL2)
319 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
321 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
324 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
331 void SDLCreateBitmapTextures(Bitmap *bitmap)
333 #if defined(TARGET_SDL2)
338 SDL_DestroyTexture(bitmap->texture);
339 if (bitmap->texture_masked)
340 SDL_DestroyTexture(bitmap->texture_masked);
342 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
343 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
347 void SDLFreeBitmapTextures(Bitmap *bitmap)
349 #if defined(TARGET_SDL2)
354 SDL_DestroyTexture(bitmap->texture);
355 if (bitmap->texture_masked)
356 SDL_DestroyTexture(bitmap->texture_masked);
358 bitmap->texture = NULL;
359 bitmap->texture_masked = NULL;
363 void SDLInitVideoDisplay(void)
365 #if !defined(TARGET_SDL2)
366 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
367 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
369 SDL_putenv("SDL_VIDEO_CENTERED=1");
372 /* initialize SDL video */
373 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
374 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
376 /* set default SDL depth */
377 #if !defined(TARGET_SDL2)
378 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
380 video.default_depth = 32; // (how to determine video depth in SDL2?)
384 void SDLInitVideoBuffer(boolean fullscreen)
386 video.window_scaling_percent = setup.window_scaling_percent;
387 video.window_scaling_quality = setup.window_scaling_quality;
389 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
391 #if defined(TARGET_SDL2)
392 // SDL 2.0: support for (desktop) fullscreen mode available
393 video.fullscreen_available = TRUE;
395 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
396 video.fullscreen_available = FALSE;
399 /* open SDL video output device (window or fullscreen mode) */
400 if (!SDLSetVideoMode(fullscreen))
401 Error(ERR_EXIT, "setting video mode failed");
403 /* !!! SDL2 can only set the window icon if the window already exists !!! */
404 /* set window icon */
405 SDLSetWindowIcon(program.icon_filename);
407 /* set window and icon title */
408 #if defined(TARGET_SDL2)
409 SDL_SetWindowTitle(sdl_window, program.window_title);
411 SDL_WM_SetCaption(program.window_title, program.window_title);
414 /* SDL cannot directly draw to the visible video framebuffer like X11,
415 but always uses a backbuffer, which is then blitted to the visible
416 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
417 visible video framebuffer with 'SDL_Flip', if the hardware supports
418 this). Therefore do not use an additional backbuffer for drawing, but
419 use a symbolic buffer (distinguishable from the SDL backbuffer) called
420 'window', which indicates that the SDL backbuffer should be updated to
421 the visible video framebuffer when attempting to blit to it.
423 For convenience, it seems to be a good idea to create this symbolic
424 buffer 'window' at the same size as the SDL backbuffer. Although it
425 should never be drawn to directly, it would do no harm nevertheless. */
427 /* create additional (symbolic) buffer for double-buffering */
428 ReCreateBitmap(&window, video.width, video.height, video.depth);
431 static boolean SDLCreateScreen(boolean fullscreen)
433 SDL_Surface *new_surface = NULL;
435 #if defined(TARGET_SDL2)
436 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
437 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
439 int surface_flags_window = SURFACE_FLAGS;
440 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
443 int width = video.width;
444 int height = video.height;
445 int surface_flags = (fullscreen ? surface_flags_fullscreen :
446 surface_flags_window);
448 // default window size is unscaled
449 video.window_width = video.width;
450 video.window_height = video.height;
452 #if defined(TARGET_SDL2)
454 // store if initial screen mode is fullscreen mode when changing screen size
455 video.fullscreen_initial = fullscreen;
457 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
459 video.window_width = window_scaling_factor * width;
460 video.window_height = window_scaling_factor * height;
462 if (sdl_texture_stream)
464 SDL_DestroyTexture(sdl_texture_stream);
465 sdl_texture_stream = NULL;
468 if (sdl_texture_target)
470 SDL_DestroyTexture(sdl_texture_target);
471 sdl_texture_target = NULL;
474 if (!(fullscreen && fullscreen_enabled))
478 SDL_DestroyRenderer(sdl_renderer);
484 SDL_DestroyWindow(sdl_window);
489 if (sdl_window == NULL)
490 sdl_window = SDL_CreateWindow(program.window_title,
491 SDL_WINDOWPOS_CENTERED,
492 SDL_WINDOWPOS_CENTERED,
497 if (sdl_window != NULL)
500 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
501 *without* enabling 2D/3D acceleration and/or guest additions installed,
502 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
503 it will try to use accelerated graphics and apparently fails miserably) */
504 if (sdl_renderer == NULL)
505 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
507 if (sdl_renderer == NULL)
508 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
511 if (sdl_renderer != NULL)
513 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
514 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
515 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
517 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
518 SDL_PIXELFORMAT_ARGB8888,
519 SDL_TEXTUREACCESS_STREAMING,
522 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
523 SDL_PIXELFORMAT_ARGB8888,
524 SDL_TEXTUREACCESS_TARGET,
527 if (sdl_texture_stream != NULL &&
528 sdl_texture_target != NULL)
530 // use SDL default values for RGB masks and no alpha channel
531 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
533 if (new_surface == NULL)
534 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
538 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
543 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
548 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
553 if (gfx.final_screen_bitmap == NULL)
554 gfx.final_screen_bitmap = CreateBitmapStruct();
556 gfx.final_screen_bitmap->width = width;
557 gfx.final_screen_bitmap->height = height;
559 gfx.final_screen_bitmap->surface =
560 SDL_SetVideoMode(width, height, video.depth, surface_flags);
562 if (gfx.final_screen_bitmap->surface != NULL)
565 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
567 if (new_surface == NULL)
568 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
571 new_surface = gfx.final_screen_bitmap->surface;
572 gfx.final_screen_bitmap = NULL;
578 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
582 #if defined(TARGET_SDL2)
583 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
584 if (new_surface != NULL)
585 fullscreen_enabled = fullscreen;
588 if (backbuffer == NULL)
589 backbuffer = CreateBitmapStruct();
591 backbuffer->width = video.width;
592 backbuffer->height = video.height;
594 if (backbuffer->surface)
595 SDL_FreeSurface(backbuffer->surface);
597 backbuffer->surface = new_surface;
599 return (new_surface != NULL);
602 boolean SDLSetVideoMode(boolean fullscreen)
604 boolean success = FALSE;
608 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
610 /* switch display to fullscreen mode, if available */
611 success = SDLCreateScreen(TRUE);
615 /* switching display to fullscreen mode failed -- do not try it again */
616 video.fullscreen_available = FALSE;
620 video.fullscreen_enabled = TRUE;
624 if ((!fullscreen && video.fullscreen_enabled) || !success)
626 /* switch display to window mode */
627 success = SDLCreateScreen(FALSE);
631 /* switching display to window mode failed -- should not happen */
635 video.fullscreen_enabled = FALSE;
636 video.window_scaling_percent = setup.window_scaling_percent;
637 video.window_scaling_quality = setup.window_scaling_quality;
639 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
643 #if defined(TARGET_SDL2)
644 SDLRedrawWindow(); // map window
648 #if defined(PLATFORM_WIN32)
649 // experimental drag and drop code
651 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
654 SDL_SysWMinfo wminfo;
656 boolean wminfo_success = FALSE;
658 SDL_VERSION(&wminfo.version);
659 #if defined(TARGET_SDL2)
661 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
663 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
668 #if defined(TARGET_SDL2)
669 hwnd = wminfo.info.win.window;
671 hwnd = wminfo.window;
674 DragAcceptFiles(hwnd, TRUE);
683 void SDLSetWindowTitle()
685 #if defined(TARGET_SDL2)
686 SDL_SetWindowTitle(sdl_window, program.window_title);
688 SDL_WM_SetCaption(program.window_title, program.window_title);
692 #if defined(TARGET_SDL2)
693 void SDLSetWindowScaling(int window_scaling_percent)
695 if (sdl_window == NULL)
698 float window_scaling_factor = (float)window_scaling_percent / 100;
699 int new_window_width = (int)(window_scaling_factor * video.width);
700 int new_window_height = (int)(window_scaling_factor * video.height);
702 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
704 video.window_scaling_percent = window_scaling_percent;
705 video.window_width = new_window_width;
706 video.window_height = new_window_height;
711 void SDLSetWindowScalingQuality(char *window_scaling_quality)
713 SDL_Texture *new_texture;
715 if (sdl_texture_stream == NULL ||
716 sdl_texture_target == NULL)
719 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
721 new_texture = SDL_CreateTexture(sdl_renderer,
722 SDL_PIXELFORMAT_ARGB8888,
723 SDL_TEXTUREACCESS_STREAMING,
724 video.width, video.height);
726 if (new_texture != NULL)
728 SDL_DestroyTexture(sdl_texture_stream);
730 sdl_texture_stream = new_texture;
733 new_texture = SDL_CreateTexture(sdl_renderer,
734 SDL_PIXELFORMAT_ARGB8888,
735 SDL_TEXTUREACCESS_TARGET,
736 video.width, video.height);
738 if (new_texture != NULL)
740 SDL_DestroyTexture(sdl_texture_target);
742 sdl_texture_target = new_texture;
747 video.window_scaling_quality = window_scaling_quality;
750 void SDLSetWindowFullscreen(boolean fullscreen)
752 if (sdl_window == NULL)
755 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
757 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
758 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
760 // if screen size was changed in fullscreen mode, correct desktop window size
761 if (!fullscreen && video.fullscreen_initial)
763 SDLSetWindowScaling(setup.window_scaling_percent);
764 SDL_SetWindowPosition(sdl_window,
765 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
767 video.fullscreen_initial = FALSE;
772 void SDLSetScreenRenderingMode(char *screen_rendering_mode)
774 #if defined(TARGET_SDL2)
775 video.screen_rendering_mode =
776 (strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
777 SPECIAL_RENDERING_BITMAP :
778 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
779 SPECIAL_RENDERING_TARGET:
780 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
781 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
783 video.screen_rendering_mode = SPECIAL_RENDERING_BITMAP;
787 void SDLRedrawWindow()
789 UpdateScreen_WithoutFrameDelay(NULL);
792 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
795 SDL_Surface *surface =
796 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
799 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
801 SDLSetNativeSurface(&surface);
803 bitmap->surface = surface;
806 void SDLFreeBitmapPointers(Bitmap *bitmap)
809 SDL_FreeSurface(bitmap->surface);
810 if (bitmap->surface_masked)
811 SDL_FreeSurface(bitmap->surface_masked);
813 bitmap->surface = NULL;
814 bitmap->surface_masked = NULL;
816 #if defined(TARGET_SDL2)
818 SDL_DestroyTexture(bitmap->texture);
819 if (bitmap->texture_masked)
820 SDL_DestroyTexture(bitmap->texture_masked);
822 bitmap->texture = NULL;
823 bitmap->texture_masked = NULL;
827 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
828 int src_x, int src_y, int width, int height,
829 int dst_x, int dst_y, int mask_mode)
831 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
832 SDL_Rect src_rect, dst_rect;
844 // if (src_bitmap != backbuffer || dst_bitmap != window)
845 if (!(src_bitmap == backbuffer && dst_bitmap == window))
846 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
847 src_bitmap->surface_masked : src_bitmap->surface),
848 &src_rect, real_dst_bitmap->surface, &dst_rect);
850 if (dst_bitmap == window)
851 UpdateScreen_WithFrameDelay(&dst_rect);
854 void SDLBlitTexture(Bitmap *bitmap,
855 int src_x, int src_y, int width, int height,
856 int dst_x, int dst_y, int mask_mode)
858 #if defined(TARGET_SDL2)
859 SDL_Texture *texture;
864 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
879 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
883 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
886 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
894 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
896 if (dst_bitmap == window)
897 UpdateScreen_WithFrameDelay(&rect);
900 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
901 int fade_mode, int fade_delay, int post_delay,
902 void (*draw_border_function)(void))
904 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
905 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
906 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
907 SDL_Surface *surface_screen = backbuffer->surface;
908 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
909 SDL_Rect src_rect, dst_rect;
911 int src_x = x, src_y = y;
912 int dst_x = x, dst_y = y;
913 unsigned int time_last, time_current;
915 // store function for drawing global masked border
916 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
918 // deactivate drawing of global border while fading, if needed
919 if (draw_border_function == NULL)
920 gfx.draw_global_border_function = NULL;
929 dst_rect.w = width; /* (ignored) */
930 dst_rect.h = height; /* (ignored) */
932 dst_rect2 = dst_rect;
934 /* copy source and target surfaces to temporary surfaces for fading */
935 if (fade_mode & FADE_TYPE_TRANSFORM)
937 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
938 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
940 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
941 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
943 else if (fade_mode & FADE_TYPE_FADE_IN)
945 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
946 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
948 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
950 else /* FADE_TYPE_FADE_OUT */
952 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
953 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
955 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
958 time_current = SDL_GetTicks();
960 if (fade_mode == FADE_MODE_MELT)
962 boolean done = FALSE;
964 int melt_columns = width / melt_pixels;
965 int ypos[melt_columns];
966 int max_steps = height / 8 + 32;
971 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
972 #if defined(TARGET_SDL2)
973 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
975 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
978 ypos[0] = -GetSimpleRandom(16);
980 for (i = 1 ; i < melt_columns; i++)
982 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
984 ypos[i] = ypos[i - 1] + r;
997 time_last = time_current;
998 time_current = SDL_GetTicks();
999 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1000 steps_final = MIN(MAX(0, steps), max_steps);
1004 done = (steps_done >= steps_final);
1006 for (i = 0 ; i < melt_columns; i++)
1014 else if (ypos[i] < height)
1019 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1021 if (ypos[i] + dy >= height)
1022 dy = height - ypos[i];
1024 /* copy part of (appearing) target surface to upper area */
1025 src_rect.x = src_x + i * melt_pixels;
1026 // src_rect.y = src_y + ypos[i];
1028 src_rect.w = melt_pixels;
1030 src_rect.h = ypos[i] + dy;
1032 dst_rect.x = dst_x + i * melt_pixels;
1033 // dst_rect.y = dst_y + ypos[i];
1036 if (steps_done >= steps_final)
1037 SDL_BlitSurface(surface_target, &src_rect,
1038 surface_screen, &dst_rect);
1042 /* copy part of (disappearing) source surface to lower area */
1043 src_rect.x = src_x + i * melt_pixels;
1045 src_rect.w = melt_pixels;
1046 src_rect.h = height - ypos[i];
1048 dst_rect.x = dst_x + i * melt_pixels;
1049 dst_rect.y = dst_y + ypos[i];
1051 if (steps_done >= steps_final)
1052 SDL_BlitSurface(surface_source, &src_rect,
1053 surface_screen, &dst_rect);
1059 src_rect.x = src_x + i * melt_pixels;
1061 src_rect.w = melt_pixels;
1062 src_rect.h = height;
1064 dst_rect.x = dst_x + i * melt_pixels;
1067 if (steps_done >= steps_final)
1068 SDL_BlitSurface(surface_target, &src_rect,
1069 surface_screen, &dst_rect);
1073 if (steps_done >= steps_final)
1075 if (draw_border_function != NULL)
1076 draw_border_function();
1078 UpdateScreen_WithFrameDelay(&dst_rect2);
1082 else if (fade_mode == FADE_MODE_CURTAIN)
1086 int xx_size = width / 2;
1088 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1089 #if defined(TARGET_SDL2)
1090 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1092 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1095 for (xx = 0; xx < xx_size;)
1097 time_last = time_current;
1098 time_current = SDL_GetTicks();
1099 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1100 xx_final = MIN(MAX(0, xx), xx_size);
1105 src_rect.h = height;
1110 /* draw new (target) image to screen buffer */
1111 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1113 if (xx_final < xx_size)
1115 src_rect.w = xx_size - xx_final;
1116 src_rect.h = height;
1118 /* draw old (source) image to screen buffer (left side) */
1120 src_rect.x = src_x + xx_final;
1123 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1125 /* draw old (source) image to screen buffer (right side) */
1127 src_rect.x = src_x + xx_size;
1128 dst_rect.x = dst_x + xx_size + xx_final;
1130 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1133 if (draw_border_function != NULL)
1134 draw_border_function();
1136 /* only update the region of the screen that is affected from fading */
1137 UpdateScreen_WithFrameDelay(&dst_rect2);
1140 else /* fading in, fading out or cross-fading */
1145 for (alpha = 0.0; alpha < 255.0;)
1147 time_last = time_current;
1148 time_current = SDL_GetTicks();
1149 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1150 alpha_final = MIN(MAX(0, alpha), 255);
1152 /* draw existing (source) image to screen buffer */
1153 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1155 /* draw new (target) image to screen buffer using alpha blending */
1156 #if defined(TARGET_SDL2)
1157 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1158 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1160 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1162 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1164 if (draw_border_function != NULL)
1165 draw_border_function();
1167 /* only update the region of the screen that is affected from fading */
1168 UpdateScreen_WithFrameDelay(&dst_rect);
1174 unsigned int time_post_delay;
1176 time_current = SDL_GetTicks();
1177 time_post_delay = time_current + post_delay;
1179 while (time_current < time_post_delay)
1181 // updating the screen contains waiting for frame delay (non-busy)
1182 UpdateScreen_WithFrameDelay(NULL);
1184 time_current = SDL_GetTicks();
1188 // restore function for drawing global masked border
1189 gfx.draw_global_border_function = draw_global_border_function;
1192 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1193 int to_x, int to_y, Uint32 color)
1195 SDL_Surface *surface = dst_bitmap->surface;
1199 swap_numbers(&from_x, &to_x);
1202 swap_numbers(&from_y, &to_y);
1206 rect.w = (to_x - from_x + 1);
1207 rect.h = (to_y - from_y + 1);
1209 SDL_FillRect(surface, &rect, color);
1212 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1213 int to_x, int to_y, Uint32 color)
1215 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1218 #if ENABLE_UNUSED_CODE
1219 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1220 int num_points, Uint32 color)
1225 for (i = 0; i < num_points - 1; i++)
1227 for (x = 0; x < line_width; x++)
1229 for (y = 0; y < line_width; y++)
1231 int dx = x - line_width / 2;
1232 int dy = y - line_width / 2;
1234 if ((x == 0 && y == 0) ||
1235 (x == 0 && y == line_width - 1) ||
1236 (x == line_width - 1 && y == 0) ||
1237 (x == line_width - 1 && y == line_width - 1))
1240 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1241 points[i+1].x + dx, points[i+1].y + dy, color);
1248 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1250 SDL_Surface *surface = src_bitmap->surface;
1252 switch (surface->format->BytesPerPixel)
1254 case 1: /* assuming 8-bpp */
1256 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1260 case 2: /* probably 15-bpp or 16-bpp */
1262 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1266 case 3: /* slow 24-bpp mode; usually not used */
1268 /* does this work? */
1269 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1273 shift = surface->format->Rshift;
1274 color |= *(pix + shift / 8) >> shift;
1275 shift = surface->format->Gshift;
1276 color |= *(pix + shift / 8) >> shift;
1277 shift = surface->format->Bshift;
1278 color |= *(pix + shift / 8) >> shift;
1284 case 4: /* probably 32-bpp */
1286 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1295 /* ========================================================================= */
1296 /* The following functions were taken from the SGE library */
1297 /* (SDL Graphics Extension Library) by Anders Lindström */
1298 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1299 /* ========================================================================= */
1301 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1303 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1305 switch (surface->format->BytesPerPixel)
1309 /* Assuming 8-bpp */
1310 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1316 /* Probably 15-bpp or 16-bpp */
1317 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1323 /* Slow 24-bpp mode, usually not used */
1327 /* Gack - slow, but endian correct */
1328 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1329 shift = surface->format->Rshift;
1330 *(pix+shift/8) = color>>shift;
1331 shift = surface->format->Gshift;
1332 *(pix+shift/8) = color>>shift;
1333 shift = surface->format->Bshift;
1334 *(pix+shift/8) = color>>shift;
1340 /* Probably 32-bpp */
1341 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1348 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1349 Uint8 R, Uint8 G, Uint8 B)
1351 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1354 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1356 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1359 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1361 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1364 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1369 /* Gack - slow, but endian correct */
1370 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1371 shift = surface->format->Rshift;
1372 *(pix+shift/8) = color>>shift;
1373 shift = surface->format->Gshift;
1374 *(pix+shift/8) = color>>shift;
1375 shift = surface->format->Bshift;
1376 *(pix+shift/8) = color>>shift;
1379 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1381 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1384 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1386 switch (dest->format->BytesPerPixel)
1389 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1393 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1397 _PutPixel24(dest,x,y,color);
1401 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1406 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1408 if (SDL_MUSTLOCK(surface))
1410 if (SDL_LockSurface(surface) < 0)
1416 _PutPixel(surface, x, y, color);
1418 if (SDL_MUSTLOCK(surface))
1420 SDL_UnlockSurface(surface);
1424 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1425 Uint8 r, Uint8 g, Uint8 b)
1427 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1430 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1432 if (y >= 0 && y <= dest->h - 1)
1434 switch (dest->format->BytesPerPixel)
1437 return y*dest->pitch;
1441 return y*dest->pitch/2;
1445 return y*dest->pitch;
1449 return y*dest->pitch/4;
1457 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1459 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1461 switch (surface->format->BytesPerPixel)
1465 /* Assuming 8-bpp */
1466 *((Uint8 *)surface->pixels + ypitch + x) = color;
1472 /* Probably 15-bpp or 16-bpp */
1473 *((Uint16 *)surface->pixels + ypitch + x) = color;
1479 /* Slow 24-bpp mode, usually not used */
1483 /* Gack - slow, but endian correct */
1484 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1485 shift = surface->format->Rshift;
1486 *(pix+shift/8) = color>>shift;
1487 shift = surface->format->Gshift;
1488 *(pix+shift/8) = color>>shift;
1489 shift = surface->format->Bshift;
1490 *(pix+shift/8) = color>>shift;
1496 /* Probably 32-bpp */
1497 *((Uint32 *)surface->pixels + ypitch + x) = color;
1504 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1509 if (SDL_MUSTLOCK(Surface))
1511 if (SDL_LockSurface(Surface) < 0)
1524 /* Do the clipping */
1525 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1529 if (x2 > Surface->w - 1)
1530 x2 = Surface->w - 1;
1537 SDL_FillRect(Surface, &l, Color);
1539 if (SDL_MUSTLOCK(Surface))
1541 SDL_UnlockSurface(Surface);
1545 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1546 Uint8 R, Uint8 G, Uint8 B)
1548 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1551 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1562 /* Do the clipping */
1563 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1567 if (x2 > Surface->w - 1)
1568 x2 = Surface->w - 1;
1575 SDL_FillRect(Surface, &l, Color);
1578 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1583 if (SDL_MUSTLOCK(Surface))
1585 if (SDL_LockSurface(Surface) < 0)
1598 /* Do the clipping */
1599 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1603 if (y2 > Surface->h - 1)
1604 y2 = Surface->h - 1;
1611 SDL_FillRect(Surface, &l, Color);
1613 if (SDL_MUSTLOCK(Surface))
1615 SDL_UnlockSurface(Surface);
1619 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1620 Uint8 R, Uint8 G, Uint8 B)
1622 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1625 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1636 /* Do the clipping */
1637 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1641 if (y2 > Surface->h - 1)
1642 y2 = Surface->h - 1;
1649 SDL_FillRect(Surface, &l, Color);
1652 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1653 Sint16 x2, Sint16 y2, Uint32 Color,
1654 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1657 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1662 sdx = (dx < 0) ? -1 : 1;
1663 sdy = (dy < 0) ? -1 : 1;
1675 for (x = 0; x < dx; x++)
1677 Callback(Surface, px, py, Color);
1691 for (y = 0; y < dy; y++)
1693 Callback(Surface, px, py, Color);
1707 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1708 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1709 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1712 sge_DoLine(Surface, X1, Y1, X2, Y2,
1713 SDL_MapRGB(Surface->format, R, G, B), Callback);
1716 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1719 if (SDL_MUSTLOCK(Surface))
1721 if (SDL_LockSurface(Surface) < 0)
1726 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1728 /* unlock the display */
1729 if (SDL_MUSTLOCK(Surface))
1731 SDL_UnlockSurface(Surface);
1735 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1736 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1738 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1741 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1743 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1748 -----------------------------------------------------------------------------
1749 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1750 -----------------------------------------------------------------------------
1753 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1754 int width, int height, Uint32 color)
1758 for (y = src_y; y < src_y + height; y++)
1760 for (x = src_x; x < src_x + width; x++)
1762 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1764 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1769 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1770 int src_x, int src_y, int width, int height,
1771 int dst_x, int dst_y)
1775 for (y = 0; y < height; y++)
1777 for (x = 0; x < width; x++)
1779 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1781 if (pixel != BLACK_PIXEL)
1782 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1788 /* ========================================================================= */
1789 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1790 /* (Rotozoomer) by Andreas Schiffler */
1791 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1792 /* ========================================================================= */
1795 -----------------------------------------------------------------------------
1798 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1799 -----------------------------------------------------------------------------
1810 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1813 tColorRGBA *sp, *csp, *dp;
1817 sp = csp = (tColorRGBA *) src->pixels;
1818 dp = (tColorRGBA *) dst->pixels;
1819 dgap = dst->pitch - dst->w * 4;
1821 for (y = 0; y < dst->h; y++)
1825 for (x = 0; x < dst->w; x++)
1827 tColorRGBA *sp0 = sp;
1828 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1829 tColorRGBA *sp00 = &sp0[0];
1830 tColorRGBA *sp01 = &sp0[1];
1831 tColorRGBA *sp10 = &sp1[0];
1832 tColorRGBA *sp11 = &sp1[1];
1835 /* create new color pixel from all four source color pixels */
1836 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1837 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1838 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1839 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1844 /* advance source pointers */
1847 /* advance destination pointer */
1851 /* advance source pointer */
1852 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1854 /* advance destination pointers */
1855 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1861 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1863 int x, y, *sax, *say, *csax, *csay;
1865 tColorRGBA *sp, *csp, *csp0, *dp;
1868 /* use specialized zoom function when scaling down to exactly half size */
1869 if (src->w == 2 * dst->w &&
1870 src->h == 2 * dst->h)
1871 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1873 /* variable setup */
1874 sx = (float) src->w / (float) dst->w;
1875 sy = (float) src->h / (float) dst->h;
1877 /* allocate memory for row increments */
1878 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1879 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1881 /* precalculate row increments */
1882 for (x = 0; x <= dst->w; x++)
1883 *csax++ = (int)(sx * x);
1885 for (y = 0; y <= dst->h; y++)
1886 *csay++ = (int)(sy * y);
1889 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1890 dp = (tColorRGBA *) dst->pixels;
1891 dgap = dst->pitch - dst->w * 4;
1894 for (y = 0; y < dst->h; y++)
1899 for (x = 0; x < dst->w; x++)
1904 /* advance source pointers */
1908 /* advance destination pointer */
1912 /* advance source pointer */
1914 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1916 /* advance destination pointers */
1917 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1927 -----------------------------------------------------------------------------
1930 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1931 -----------------------------------------------------------------------------
1934 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1936 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1937 Uint8 *sp, *dp, *csp;
1940 /* variable setup */
1941 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1942 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1944 /* allocate memory for row increments */
1945 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1946 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1948 /* precalculate row increments */
1951 for (x = 0; x < dst->w; x++)
1954 *csax = (csx >> 16);
1961 for (y = 0; y < dst->h; y++)
1964 *csay = (csy >> 16);
1971 for (x = 0; x < dst->w; x++)
1979 for (y = 0; y < dst->h; y++)
1986 sp = csp = (Uint8 *) src->pixels;
1987 dp = (Uint8 *) dst->pixels;
1988 dgap = dst->pitch - dst->w;
1992 for (y = 0; y < dst->h; y++)
1996 for (x = 0; x < dst->w; x++)
2001 /* advance source pointers */
2005 /* advance destination pointer */
2009 /* advance source pointer (for row) */
2010 csp += ((*csay) * src->pitch);
2013 /* advance destination pointers */
2024 -----------------------------------------------------------------------------
2027 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2028 'zoomx' and 'zoomy' are scaling factors for width and height.
2029 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2030 into a 32bit RGBA format on the fly.
2031 -----------------------------------------------------------------------------
2034 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2036 SDL_Surface *zoom_src = NULL;
2037 SDL_Surface *zoom_dst = NULL;
2038 boolean is_converted = FALSE;
2045 /* determine if source surface is 32 bit or 8 bit */
2046 is_32bit = (src->format->BitsPerPixel == 32);
2048 if (is_32bit || src->format->BitsPerPixel == 8)
2050 /* use source surface 'as is' */
2055 /* new source surface is 32 bit with a defined RGB ordering */
2056 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2057 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2058 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2060 is_converted = TRUE;
2063 /* allocate surface to completely contain the zoomed surface */
2066 /* target surface is 32 bit with source RGBA/ABGR ordering */
2067 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2068 zoom_src->format->Rmask,
2069 zoom_src->format->Gmask,
2070 zoom_src->format->Bmask, 0);
2074 /* target surface is 8 bit */
2075 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2079 /* lock source surface */
2080 SDL_LockSurface(zoom_src);
2082 /* check which kind of surface we have */
2085 /* call the 32 bit transformation routine to do the zooming */
2086 zoomSurfaceRGBA(zoom_src, zoom_dst);
2091 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2092 zoom_dst->format->palette->colors[i] =
2093 zoom_src->format->palette->colors[i];
2094 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2096 /* call the 8 bit transformation routine to do the zooming */
2097 zoomSurfaceY(zoom_src, zoom_dst);
2100 /* unlock source surface */
2101 SDL_UnlockSurface(zoom_src);
2103 /* free temporary surface */
2105 SDL_FreeSurface(zoom_src);
2107 /* return destination surface */
2111 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2113 Bitmap *dst_bitmap = CreateBitmapStruct();
2114 SDL_Surface **dst_surface = &dst_bitmap->surface;
2116 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2117 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2119 dst_bitmap->width = dst_width;
2120 dst_bitmap->height = dst_height;
2122 /* create zoomed temporary surface from source surface */
2123 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2125 /* create native format destination surface from zoomed temporary surface */
2126 SDLSetNativeSurface(dst_surface);
2132 /* ========================================================================= */
2133 /* load image to bitmap */
2134 /* ========================================================================= */
2136 Bitmap *SDLLoadImage(char *filename)
2138 Bitmap *new_bitmap = CreateBitmapStruct();
2139 SDL_Surface *sdl_image_tmp;
2141 print_timestamp_init("SDLLoadImage");
2143 print_timestamp_time(getBaseNamePtr(filename));
2145 /* load image to temporary surface */
2146 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2148 SetError("IMG_Load(): %s", SDL_GetError());
2153 print_timestamp_time("IMG_Load");
2155 UPDATE_BUSY_STATE();
2157 /* create native non-transparent surface for current image */
2158 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2160 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2165 print_timestamp_time("SDL_DisplayFormat (opaque)");
2167 UPDATE_BUSY_STATE();
2169 /* create native transparent surface for current image */
2170 if (sdl_image_tmp->format->Amask == 0)
2171 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2172 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2174 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2176 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2181 print_timestamp_time("SDL_DisplayFormat (masked)");
2183 UPDATE_BUSY_STATE();
2185 /* free temporary surface */
2186 SDL_FreeSurface(sdl_image_tmp);
2188 new_bitmap->width = new_bitmap->surface->w;
2189 new_bitmap->height = new_bitmap->surface->h;
2191 print_timestamp_done("SDLLoadImage");
2197 /* ------------------------------------------------------------------------- */
2198 /* custom cursor fuctions */
2199 /* ------------------------------------------------------------------------- */
2201 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2203 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2204 cursor_info->width, cursor_info->height,
2205 cursor_info->hot_x, cursor_info->hot_y);
2208 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2210 static struct MouseCursorInfo *last_cursor_info = NULL;
2211 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2212 static SDL_Cursor *cursor_default = NULL;
2213 static SDL_Cursor *cursor_current = NULL;
2215 /* if invoked for the first time, store the SDL default cursor */
2216 if (cursor_default == NULL)
2217 cursor_default = SDL_GetCursor();
2219 /* only create new cursor if cursor info (custom only) has changed */
2220 if (cursor_info != NULL && cursor_info != last_cursor_info)
2222 cursor_current = create_cursor(cursor_info);
2223 last_cursor_info = cursor_info;
2226 /* only set new cursor if cursor info (custom or NULL) has changed */
2227 if (cursor_info != last_cursor_info2)
2228 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2230 last_cursor_info2 = cursor_info;
2234 /* ========================================================================= */
2235 /* audio functions */
2236 /* ========================================================================= */
2238 void SDLOpenAudio(void)
2240 #if !defined(TARGET_SDL2)
2241 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2242 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2245 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2247 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2251 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2252 AUDIO_NUM_CHANNELS_STEREO,
2253 setup.system.audio_fragment_size) < 0)
2255 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2259 audio.sound_available = TRUE;
2260 audio.music_available = TRUE;
2261 audio.loops_available = TRUE;
2262 audio.sound_enabled = TRUE;
2264 /* set number of available mixer channels */
2265 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2266 audio.music_channel = MUSIC_CHANNEL;
2267 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2269 Mixer_InitChannels();
2272 void SDLCloseAudio(void)
2275 Mix_HaltChannel(-1);
2278 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2282 /* ========================================================================= */
2283 /* event functions */
2284 /* ========================================================================= */
2286 void SDLNextEvent(Event *event)
2288 SDL_WaitEvent(event);
2291 void SDLHandleWindowManagerEvent(Event *event)
2294 #if defined(PLATFORM_WIN32)
2295 // experimental drag and drop code
2297 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2298 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2300 #if defined(TARGET_SDL2)
2301 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2303 if (syswmmsg->msg == WM_DROPFILES)
2306 #if defined(TARGET_SDL2)
2307 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2309 HDROP hdrop = (HDROP)syswmmsg->wParam;
2313 printf("::: SDL_SYSWMEVENT:\n");
2315 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2317 for (i = 0; i < num_files; i++)
2319 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2320 char buffer[buffer_len + 1];
2322 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2324 printf("::: - '%s'\n", buffer);
2327 #if defined(TARGET_SDL2)
2328 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2330 DragFinish((HDROP)syswmmsg->wParam);
2338 /* ========================================================================= */
2339 /* joystick functions */
2340 /* ========================================================================= */
2342 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2343 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2344 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2346 static boolean SDLOpenJoystick(int nr)
2348 if (nr < 0 || nr > MAX_PLAYERS)
2351 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2354 static void SDLCloseJoystick(int nr)
2356 if (nr < 0 || nr > MAX_PLAYERS)
2359 SDL_JoystickClose(sdl_joystick[nr]);
2361 sdl_joystick[nr] = NULL;
2364 static boolean SDLCheckJoystickOpened(int nr)
2366 if (nr < 0 || nr > MAX_PLAYERS)
2369 #if defined(TARGET_SDL2)
2370 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2372 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2376 void HandleJoystickEvent(Event *event)
2380 case SDL_JOYAXISMOTION:
2381 if (event->jaxis.axis < 2)
2382 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2385 case SDL_JOYBUTTONDOWN:
2386 if (event->jbutton.button < 2)
2387 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2390 case SDL_JOYBUTTONUP:
2391 if (event->jbutton.button < 2)
2392 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2400 void SDLInitJoysticks()
2402 static boolean sdl_joystick_subsystem_initialized = FALSE;
2403 boolean print_warning = !sdl_joystick_subsystem_initialized;
2406 if (!sdl_joystick_subsystem_initialized)
2408 sdl_joystick_subsystem_initialized = TRUE;
2410 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2412 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2417 for (i = 0; i < MAX_PLAYERS; i++)
2419 /* get configured joystick for this player */
2420 char *device_name = setup.input[i].joy.device_name;
2421 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2423 if (joystick_nr >= SDL_NumJoysticks())
2425 if (setup.input[i].use_joystick && print_warning)
2426 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2431 /* misuse joystick file descriptor variable to store joystick number */
2432 joystick.fd[i] = joystick_nr;
2434 if (joystick_nr == -1)
2437 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2438 if (SDLCheckJoystickOpened(joystick_nr))
2439 SDLCloseJoystick(joystick_nr);
2441 if (!setup.input[i].use_joystick)
2444 if (!SDLOpenJoystick(joystick_nr))
2447 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2452 joystick.status = JOYSTICK_ACTIVATED;
2456 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2458 if (nr < 0 || nr >= MAX_PLAYERS)
2462 *x = sdl_js_axis[nr][0];
2464 *y = sdl_js_axis[nr][1];
2467 *b1 = sdl_js_button[nr][0];
2469 *b2 = sdl_js_button[nr][1];