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 #define USE_TARGET_TEXTURE TRUE
28 #define USE_TARGET_TEXTURE_ONLY FALSE
30 static SDL_Window *sdl_window = NULL;
31 static SDL_Renderer *sdl_renderer = NULL;
32 #if USE_TARGET_TEXTURE
33 static SDL_Texture *sdl_texture_stream = NULL;
34 static SDL_Texture *sdl_texture_target = NULL;
36 static SDL_Texture *sdl_texture = NULL;
38 static boolean fullscreen_enabled = FALSE;
41 static boolean limit_screen_updates = FALSE;
44 /* functions from SGE library */
45 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
47 void SDLLimitScreenUpdates(boolean enable)
49 limit_screen_updates = enable;
52 static void UpdateScreen(SDL_Rect *rect)
54 static unsigned int update_screen_delay = 0;
55 unsigned int update_screen_delay_value = 50; /* (milliseconds) */
56 SDL_Surface *screen = backbuffer->surface;
58 if (limit_screen_updates &&
59 !DelayReached(&update_screen_delay, update_screen_delay_value))
62 LimitScreenUpdates(FALSE);
66 static int LastFrameCounter = 0;
67 boolean changed = (FrameCounter != LastFrameCounter);
69 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
70 (changed ? "-" : "SAME FRAME UPDATED"));
72 LastFrameCounter = FrameCounter;
81 #if USE_FINAL_SCREEN_BITMAP
82 if (gfx.final_screen_bitmap != NULL) // may not be initialized yet
85 // draw global animations using bitmaps instead of using textures
86 // to prevent texture scaling artefacts (this is potentially slower)
88 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
89 gfx.win_xsize, gfx.win_ysize, 0, 0);
91 // copy global animations to render target buffer, if defined (below border)
92 if (gfx.draw_global_anim_function != NULL)
93 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
95 // copy global masked border to render target buffer, if defined
96 if (gfx.draw_global_border_function != NULL)
97 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
99 // copy global animations to render target buffer, if defined (above border)
100 if (gfx.draw_global_anim_function != NULL)
101 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
103 screen = gfx.final_screen_bitmap->surface;
105 // force full window redraw
110 #if USE_TARGET_TEXTURE
111 #if USE_TARGET_TEXTURE_ONLY
112 SDL_Texture *sdl_texture = sdl_texture_target;
114 SDL_Texture *sdl_texture = sdl_texture_stream;
118 #if defined(TARGET_SDL2)
121 int bytes_x = screen->pitch / video.width;
122 int bytes_y = screen->pitch;
124 SDL_UpdateTexture(sdl_texture, rect,
125 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
130 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
133 // clear render target buffer
134 SDL_RenderClear(sdl_renderer);
136 #if USE_TARGET_TEXTURE
137 SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
139 // copy backbuffer to render target buffer
140 if (sdl_texture != sdl_texture_target)
141 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
143 // copy backbuffer to render target buffer
144 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
147 #if !USE_FINAL_SCREEN_BITMAP
148 // copy global animations to render target buffer, if defined (below border)
149 if (gfx.draw_global_anim_function != NULL)
150 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
152 // copy global masked border to render target buffer, if defined
153 if (gfx.draw_global_border_function != NULL)
154 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
156 // copy global animations to render target buffer, if defined (above border)
157 if (gfx.draw_global_anim_function != NULL)
158 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
161 #if USE_TARGET_TEXTURE
162 SDL_SetRenderTarget(sdl_renderer, NULL);
163 SDL_RenderCopy(sdl_renderer, sdl_texture_target, NULL, NULL);
166 // show render target buffer on screen
167 SDL_RenderPresent(sdl_renderer);
171 SDL_UpdateRects(screen, 1, rect);
173 SDL_UpdateRect(screen, 0, 0, 0, 0);
177 static void SDLSetWindowIcon(char *basename)
179 /* (setting the window icon on Mac OS X would replace the high-quality
180 dock icon with the currently smaller (and uglier) icon from file) */
182 #if !defined(PLATFORM_MACOSX)
183 char *filename = getCustomImageFilename(basename);
184 SDL_Surface *surface;
186 if (filename == NULL)
188 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
193 if ((surface = IMG_Load(filename)) == NULL)
195 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
200 /* set transparent color */
201 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
202 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
204 #if defined(TARGET_SDL2)
205 SDL_SetWindowIcon(sdl_window, surface);
207 SDL_WM_SetIcon(surface, NULL);
212 #if defined(TARGET_SDL2)
214 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
215 SDL_PixelFormat *format2)
217 return (format1->format == format2->format &&
218 format1->BitsPerPixel == format2->BitsPerPixel &&
219 format1->BytesPerPixel == format2->BytesPerPixel &&
220 format1->Rmask == format2->Rmask &&
221 format1->Gmask == format2->Gmask &&
222 format1->Bmask == format2->Bmask &&
223 format1->Amask == format2->Amask);
226 boolean SDLSetNativeSurface(SDL_Surface **surface)
228 SDL_Surface *new_surface;
230 if (surface == NULL ||
232 backbuffer == NULL ||
233 backbuffer->surface == NULL)
236 // if pixel format already optimized for destination surface, do nothing
237 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
240 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
242 if (new_surface == NULL)
243 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
245 SDL_FreeSurface(*surface);
247 *surface = new_surface;
252 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
254 SDL_PixelFormat format;
255 SDL_Surface *new_surface;
260 if (backbuffer && backbuffer->surface)
262 format = *backbuffer->surface->format;
263 format.Amask = surface->format->Amask; // keep alpha channel
267 format = *surface->format;
270 new_surface = SDL_ConvertSurface(surface, &format, 0);
272 if (new_surface == NULL)
273 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
280 boolean SDLSetNativeSurface(SDL_Surface **surface)
282 SDL_Surface *new_surface;
284 if (surface == NULL ||
289 new_surface = SDL_DisplayFormat(*surface);
291 if (new_surface == NULL)
292 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
294 SDL_FreeSurface(*surface);
296 *surface = new_surface;
301 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
303 SDL_Surface *new_surface;
305 if (video.initialized)
306 new_surface = SDL_DisplayFormat(surface);
308 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
310 if (new_surface == NULL)
311 Error(ERR_EXIT, "%s() failed: %s",
312 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
320 #if defined(TARGET_SDL2)
321 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
323 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
326 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
333 void SDLCreateBitmapTextures(Bitmap *bitmap)
335 #if defined(TARGET_SDL2)
340 SDL_DestroyTexture(bitmap->texture);
341 if (bitmap->texture_masked)
342 SDL_DestroyTexture(bitmap->texture_masked);
344 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
345 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
349 void SDLFreeBitmapTextures(Bitmap *bitmap)
351 #if defined(TARGET_SDL2)
356 SDL_DestroyTexture(bitmap->texture);
357 if (bitmap->texture_masked)
358 SDL_DestroyTexture(bitmap->texture_masked);
360 bitmap->texture = NULL;
361 bitmap->texture_masked = NULL;
365 void SDLInitVideoDisplay(void)
367 #if !defined(TARGET_SDL2)
368 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
369 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
371 SDL_putenv("SDL_VIDEO_CENTERED=1");
374 /* initialize SDL video */
375 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
376 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
378 /* set default SDL depth */
379 #if !defined(TARGET_SDL2)
380 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
382 video.default_depth = 32; // (how to determine video depth in SDL2?)
386 void SDLInitVideoBuffer(boolean fullscreen)
388 video.window_scaling_percent = setup.window_scaling_percent;
389 video.window_scaling_quality = setup.window_scaling_quality;
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 USE_TARGET_TEXTURE
463 if (sdl_texture_stream)
465 SDL_DestroyTexture(sdl_texture_stream);
466 sdl_texture_stream = NULL;
469 if (sdl_texture_target)
471 SDL_DestroyTexture(sdl_texture_target);
472 sdl_texture_target = NULL;
477 SDL_DestroyTexture(sdl_texture);
482 if (!(fullscreen && fullscreen_enabled))
486 SDL_DestroyRenderer(sdl_renderer);
492 SDL_DestroyWindow(sdl_window);
497 if (sdl_window == NULL)
498 sdl_window = SDL_CreateWindow(program.window_title,
499 SDL_WINDOWPOS_CENTERED,
500 SDL_WINDOWPOS_CENTERED,
505 if (sdl_window != NULL)
508 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
509 *without* enabling 2D/3D acceleration and/or guest additions installed,
510 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
511 it will try to use accelerated graphics and apparently fails miserably) */
512 if (sdl_renderer == NULL)
513 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
515 if (sdl_renderer == NULL)
516 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
519 if (sdl_renderer != NULL)
521 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
522 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
523 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
525 #if USE_TARGET_TEXTURE
526 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
527 SDL_PIXELFORMAT_ARGB8888,
528 SDL_TEXTUREACCESS_STREAMING,
531 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
532 SDL_PIXELFORMAT_ARGB8888,
533 SDL_TEXTUREACCESS_TARGET,
536 sdl_texture = SDL_CreateTexture(sdl_renderer,
537 SDL_PIXELFORMAT_ARGB8888,
538 SDL_TEXTUREACCESS_STREAMING,
542 #if USE_TARGET_TEXTURE
543 if (sdl_texture_stream != NULL &&
544 sdl_texture_target != NULL)
546 if (sdl_texture != NULL)
549 // use SDL default values for RGB masks and no alpha channel
550 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
552 if (new_surface == NULL)
553 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
557 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
562 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
567 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
572 if (gfx.final_screen_bitmap == NULL)
573 gfx.final_screen_bitmap = CreateBitmapStruct();
575 gfx.final_screen_bitmap->width = width;
576 gfx.final_screen_bitmap->height = height;
578 gfx.final_screen_bitmap->surface =
579 SDL_SetVideoMode(width, height, video.depth, surface_flags);
581 if (gfx.final_screen_bitmap->surface != NULL)
584 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
586 if (new_surface == NULL)
587 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
590 new_surface = gfx.final_screen_bitmap->surface;
591 gfx.final_screen_bitmap = NULL;
597 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
601 #if defined(TARGET_SDL2)
602 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
603 if (new_surface != NULL)
604 fullscreen_enabled = fullscreen;
607 if (backbuffer == NULL)
608 backbuffer = CreateBitmapStruct();
610 backbuffer->width = video.width;
611 backbuffer->height = video.height;
613 if (backbuffer->surface)
614 SDL_FreeSurface(backbuffer->surface);
616 backbuffer->surface = new_surface;
618 return (new_surface != NULL);
621 boolean SDLSetVideoMode(boolean fullscreen)
623 boolean success = FALSE;
627 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
629 /* switch display to fullscreen mode, if available */
630 success = SDLCreateScreen(TRUE);
634 /* switching display to fullscreen mode failed -- do not try it again */
635 video.fullscreen_available = FALSE;
639 video.fullscreen_enabled = TRUE;
643 if ((!fullscreen && video.fullscreen_enabled) || !success)
645 /* switch display to window mode */
646 success = SDLCreateScreen(FALSE);
650 /* switching display to window mode failed -- should not happen */
654 video.fullscreen_enabled = FALSE;
655 video.window_scaling_percent = setup.window_scaling_percent;
656 video.window_scaling_quality = setup.window_scaling_quality;
660 #if defined(TARGET_SDL2)
661 SDLRedrawWindow(); // map window
665 #if defined(PLATFORM_WIN32)
666 // experimental drag and drop code
668 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
671 SDL_SysWMinfo wminfo;
673 boolean wminfo_success = FALSE;
675 SDL_VERSION(&wminfo.version);
676 #if defined(TARGET_SDL2)
678 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
680 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
685 #if defined(TARGET_SDL2)
686 hwnd = wminfo.info.win.window;
688 hwnd = wminfo.window;
691 DragAcceptFiles(hwnd, TRUE);
700 void SDLSetWindowTitle()
702 #if defined(TARGET_SDL2)
703 SDL_SetWindowTitle(sdl_window, program.window_title);
705 SDL_WM_SetCaption(program.window_title, program.window_title);
709 #if defined(TARGET_SDL2)
710 void SDLSetWindowScaling(int window_scaling_percent)
712 if (sdl_window == NULL)
715 float window_scaling_factor = (float)window_scaling_percent / 100;
716 int new_window_width = (int)(window_scaling_factor * video.width);
717 int new_window_height = (int)(window_scaling_factor * video.height);
719 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
721 video.window_scaling_percent = window_scaling_percent;
722 video.window_width = new_window_width;
723 video.window_height = new_window_height;
728 void SDLSetWindowScalingQuality(char *window_scaling_quality)
730 #if USE_TARGET_TEXTURE
731 SDL_Texture *new_texture;
733 if (sdl_texture_stream == NULL ||
734 sdl_texture_target == NULL)
737 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
739 new_texture = SDL_CreateTexture(sdl_renderer,
740 SDL_PIXELFORMAT_ARGB8888,
741 SDL_TEXTUREACCESS_STREAMING,
742 video.width, video.height);
744 if (new_texture != NULL)
746 SDL_DestroyTexture(sdl_texture_stream);
748 sdl_texture_stream = new_texture;
751 new_texture = SDL_CreateTexture(sdl_renderer,
752 SDL_PIXELFORMAT_ARGB8888,
753 SDL_TEXTUREACCESS_TARGET,
754 video.width, video.height);
756 if (new_texture != NULL)
758 SDL_DestroyTexture(sdl_texture_target);
760 sdl_texture_target = new_texture;
766 if (sdl_texture == NULL)
769 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
771 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
772 SDL_PIXELFORMAT_ARGB8888,
773 SDL_TEXTUREACCESS_STREAMING,
774 video.width, video.height);
776 if (new_texture != NULL)
778 SDL_DestroyTexture(sdl_texture);
780 sdl_texture = new_texture;
786 video.window_scaling_quality = window_scaling_quality;
789 void SDLSetWindowFullscreen(boolean fullscreen)
791 if (sdl_window == NULL)
794 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
796 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
797 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
799 // if screen size was changed in fullscreen mode, correct desktop window size
800 if (!fullscreen && video.fullscreen_initial)
802 SDLSetWindowScaling(setup.window_scaling_percent);
803 SDL_SetWindowPosition(sdl_window,
804 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
806 video.fullscreen_initial = FALSE;
810 void SDLRedrawWindow()
816 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
819 SDL_Surface *surface =
820 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
823 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
825 SDLSetNativeSurface(&surface);
827 bitmap->surface = surface;
830 void SDLFreeBitmapPointers(Bitmap *bitmap)
833 SDL_FreeSurface(bitmap->surface);
834 if (bitmap->surface_masked)
835 SDL_FreeSurface(bitmap->surface_masked);
837 bitmap->surface = NULL;
838 bitmap->surface_masked = NULL;
840 #if defined(TARGET_SDL2)
842 SDL_DestroyTexture(bitmap->texture);
843 if (bitmap->texture_masked)
844 SDL_DestroyTexture(bitmap->texture_masked);
846 bitmap->texture = NULL;
847 bitmap->texture_masked = NULL;
851 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
852 int src_x, int src_y, int width, int height,
853 int dst_x, int dst_y, int mask_mode)
855 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
856 SDL_Rect src_rect, dst_rect;
868 // if (src_bitmap != backbuffer || dst_bitmap != window)
869 if (!(src_bitmap == backbuffer && dst_bitmap == window))
870 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
871 src_bitmap->surface_masked : src_bitmap->surface),
872 &src_rect, real_dst_bitmap->surface, &dst_rect);
874 if (dst_bitmap == window)
875 UpdateScreen(&dst_rect);
878 void SDLBlitTexture(Bitmap *bitmap,
879 int src_x, int src_y, int width, int height,
880 int dst_x, int dst_y, int mask_mode)
882 #if defined(TARGET_SDL2)
883 SDL_Texture *texture;
888 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
903 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
907 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
910 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
918 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
920 if (dst_bitmap == window)
924 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
925 int fade_mode, int fade_delay, int post_delay,
926 void (*draw_border_function)(void))
928 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
929 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
930 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
931 SDL_Surface *surface_screen = backbuffer->surface;
932 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
933 SDL_Rect src_rect, dst_rect;
935 int src_x = x, src_y = y;
936 int dst_x = x, dst_y = y;
937 unsigned int time_last, time_current;
939 // store function for drawing global masked border
940 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
942 // deactivate drawing of global border while fading, if needed
943 if (draw_border_function == NULL)
944 gfx.draw_global_border_function = NULL;
953 dst_rect.w = width; /* (ignored) */
954 dst_rect.h = height; /* (ignored) */
956 dst_rect2 = dst_rect;
958 /* copy source and target surfaces to temporary surfaces for fading */
959 if (fade_mode & FADE_TYPE_TRANSFORM)
961 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
962 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
964 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
965 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
967 else if (fade_mode & FADE_TYPE_FADE_IN)
969 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
970 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
972 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
974 else /* FADE_TYPE_FADE_OUT */
976 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
977 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
979 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
982 time_current = SDL_GetTicks();
984 if (fade_mode == FADE_MODE_MELT)
986 boolean done = FALSE;
988 int melt_columns = width / melt_pixels;
989 int ypos[melt_columns];
990 int max_steps = height / 8 + 32;
995 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
996 #if defined(TARGET_SDL2)
997 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
999 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1002 ypos[0] = -GetSimpleRandom(16);
1004 for (i = 1 ; i < melt_columns; i++)
1006 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1008 ypos[i] = ypos[i - 1] + r;
1021 time_last = time_current;
1022 time_current = SDL_GetTicks();
1023 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1024 steps_final = MIN(MAX(0, steps), max_steps);
1028 done = (steps_done >= steps_final);
1030 for (i = 0 ; i < melt_columns; i++)
1038 else if (ypos[i] < height)
1043 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1045 if (ypos[i] + dy >= height)
1046 dy = height - ypos[i];
1048 /* copy part of (appearing) target surface to upper area */
1049 src_rect.x = src_x + i * melt_pixels;
1050 // src_rect.y = src_y + ypos[i];
1052 src_rect.w = melt_pixels;
1054 src_rect.h = ypos[i] + dy;
1056 dst_rect.x = dst_x + i * melt_pixels;
1057 // dst_rect.y = dst_y + ypos[i];
1060 if (steps_done >= steps_final)
1061 SDL_BlitSurface(surface_target, &src_rect,
1062 surface_screen, &dst_rect);
1066 /* copy part of (disappearing) source surface to lower area */
1067 src_rect.x = src_x + i * melt_pixels;
1069 src_rect.w = melt_pixels;
1070 src_rect.h = height - ypos[i];
1072 dst_rect.x = dst_x + i * melt_pixels;
1073 dst_rect.y = dst_y + ypos[i];
1075 if (steps_done >= steps_final)
1076 SDL_BlitSurface(surface_source, &src_rect,
1077 surface_screen, &dst_rect);
1083 src_rect.x = src_x + i * melt_pixels;
1085 src_rect.w = melt_pixels;
1086 src_rect.h = height;
1088 dst_rect.x = dst_x + i * melt_pixels;
1091 if (steps_done >= steps_final)
1092 SDL_BlitSurface(surface_target, &src_rect,
1093 surface_screen, &dst_rect);
1097 if (steps_done >= steps_final)
1099 if (draw_border_function != NULL)
1100 draw_border_function();
1102 UpdateScreen(&dst_rect2);
1106 else if (fade_mode == FADE_MODE_CURTAIN)
1110 int xx_size = width / 2;
1112 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1113 #if defined(TARGET_SDL2)
1114 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1116 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1119 for (xx = 0; xx < xx_size;)
1121 time_last = time_current;
1122 time_current = SDL_GetTicks();
1123 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1124 xx_final = MIN(MAX(0, xx), xx_size);
1129 src_rect.h = height;
1134 /* draw new (target) image to screen buffer */
1135 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1137 if (xx_final < xx_size)
1139 src_rect.w = xx_size - xx_final;
1140 src_rect.h = height;
1142 /* draw old (source) image to screen buffer (left side) */
1144 src_rect.x = src_x + xx_final;
1147 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1149 /* draw old (source) image to screen buffer (right side) */
1151 src_rect.x = src_x + xx_size;
1152 dst_rect.x = dst_x + xx_size + xx_final;
1154 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1157 if (draw_border_function != NULL)
1158 draw_border_function();
1160 /* only update the region of the screen that is affected from fading */
1161 UpdateScreen(&dst_rect2);
1164 else /* fading in, fading out or cross-fading */
1169 for (alpha = 0.0; alpha < 255.0;)
1171 time_last = time_current;
1172 time_current = SDL_GetTicks();
1173 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1174 alpha_final = MIN(MAX(0, alpha), 255);
1176 /* draw existing (source) image to screen buffer */
1177 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1179 /* draw new (target) image to screen buffer using alpha blending */
1180 #if defined(TARGET_SDL2)
1181 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1182 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1184 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1186 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1188 if (draw_border_function != NULL)
1189 draw_border_function();
1191 /* only update the region of the screen that is affected from fading */
1192 UpdateScreen(&dst_rect);
1198 unsigned int time_post_delay;
1200 time_current = SDL_GetTicks();
1201 time_post_delay = time_current + post_delay;
1203 while (time_current < time_post_delay)
1205 // do not wait longer than 10 ms at a time to be able to ...
1206 Delay(MIN(10, time_post_delay - time_current));
1208 // ... continue drawing global animations during post delay
1211 time_current = SDL_GetTicks();
1215 // restore function for drawing global masked border
1216 gfx.draw_global_border_function = draw_global_border_function;
1219 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1220 int to_x, int to_y, Uint32 color)
1222 SDL_Surface *surface = dst_bitmap->surface;
1226 swap_numbers(&from_x, &to_x);
1229 swap_numbers(&from_y, &to_y);
1233 rect.w = (to_x - from_x + 1);
1234 rect.h = (to_y - from_y + 1);
1236 SDL_FillRect(surface, &rect, color);
1239 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1240 int to_x, int to_y, Uint32 color)
1242 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1245 #if ENABLE_UNUSED_CODE
1246 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1247 int num_points, Uint32 color)
1252 for (i = 0; i < num_points - 1; i++)
1254 for (x = 0; x < line_width; x++)
1256 for (y = 0; y < line_width; y++)
1258 int dx = x - line_width / 2;
1259 int dy = y - line_width / 2;
1261 if ((x == 0 && y == 0) ||
1262 (x == 0 && y == line_width - 1) ||
1263 (x == line_width - 1 && y == 0) ||
1264 (x == line_width - 1 && y == line_width - 1))
1267 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1268 points[i+1].x + dx, points[i+1].y + dy, color);
1275 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1277 SDL_Surface *surface = src_bitmap->surface;
1279 switch (surface->format->BytesPerPixel)
1281 case 1: /* assuming 8-bpp */
1283 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1287 case 2: /* probably 15-bpp or 16-bpp */
1289 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1293 case 3: /* slow 24-bpp mode; usually not used */
1295 /* does this work? */
1296 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1300 shift = surface->format->Rshift;
1301 color |= *(pix + shift / 8) >> shift;
1302 shift = surface->format->Gshift;
1303 color |= *(pix + shift / 8) >> shift;
1304 shift = surface->format->Bshift;
1305 color |= *(pix + shift / 8) >> shift;
1311 case 4: /* probably 32-bpp */
1313 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1322 /* ========================================================================= */
1323 /* The following functions were taken from the SGE library */
1324 /* (SDL Graphics Extension Library) by Anders Lindström */
1325 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1326 /* ========================================================================= */
1328 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1330 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1332 switch (surface->format->BytesPerPixel)
1336 /* Assuming 8-bpp */
1337 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1343 /* Probably 15-bpp or 16-bpp */
1344 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1350 /* Slow 24-bpp mode, usually not used */
1354 /* Gack - slow, but endian correct */
1355 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1356 shift = surface->format->Rshift;
1357 *(pix+shift/8) = color>>shift;
1358 shift = surface->format->Gshift;
1359 *(pix+shift/8) = color>>shift;
1360 shift = surface->format->Bshift;
1361 *(pix+shift/8) = color>>shift;
1367 /* Probably 32-bpp */
1368 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1375 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1376 Uint8 R, Uint8 G, Uint8 B)
1378 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1381 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1383 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1386 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1388 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1391 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1396 /* Gack - slow, but endian correct */
1397 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1398 shift = surface->format->Rshift;
1399 *(pix+shift/8) = color>>shift;
1400 shift = surface->format->Gshift;
1401 *(pix+shift/8) = color>>shift;
1402 shift = surface->format->Bshift;
1403 *(pix+shift/8) = color>>shift;
1406 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1408 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1411 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1413 switch (dest->format->BytesPerPixel)
1416 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1420 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1424 _PutPixel24(dest,x,y,color);
1428 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1433 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1435 if (SDL_MUSTLOCK(surface))
1437 if (SDL_LockSurface(surface) < 0)
1443 _PutPixel(surface, x, y, color);
1445 if (SDL_MUSTLOCK(surface))
1447 SDL_UnlockSurface(surface);
1451 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1452 Uint8 r, Uint8 g, Uint8 b)
1454 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1457 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1459 if (y >= 0 && y <= dest->h - 1)
1461 switch (dest->format->BytesPerPixel)
1464 return y*dest->pitch;
1468 return y*dest->pitch/2;
1472 return y*dest->pitch;
1476 return y*dest->pitch/4;
1484 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1486 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1488 switch (surface->format->BytesPerPixel)
1492 /* Assuming 8-bpp */
1493 *((Uint8 *)surface->pixels + ypitch + x) = color;
1499 /* Probably 15-bpp or 16-bpp */
1500 *((Uint16 *)surface->pixels + ypitch + x) = color;
1506 /* Slow 24-bpp mode, usually not used */
1510 /* Gack - slow, but endian correct */
1511 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1512 shift = surface->format->Rshift;
1513 *(pix+shift/8) = color>>shift;
1514 shift = surface->format->Gshift;
1515 *(pix+shift/8) = color>>shift;
1516 shift = surface->format->Bshift;
1517 *(pix+shift/8) = color>>shift;
1523 /* Probably 32-bpp */
1524 *((Uint32 *)surface->pixels + ypitch + x) = color;
1531 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1536 if (SDL_MUSTLOCK(Surface))
1538 if (SDL_LockSurface(Surface) < 0)
1551 /* Do the clipping */
1552 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1556 if (x2 > Surface->w - 1)
1557 x2 = Surface->w - 1;
1564 SDL_FillRect(Surface, &l, Color);
1566 if (SDL_MUSTLOCK(Surface))
1568 SDL_UnlockSurface(Surface);
1572 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1573 Uint8 R, Uint8 G, Uint8 B)
1575 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1578 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1589 /* Do the clipping */
1590 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1594 if (x2 > Surface->w - 1)
1595 x2 = Surface->w - 1;
1602 SDL_FillRect(Surface, &l, Color);
1605 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1610 if (SDL_MUSTLOCK(Surface))
1612 if (SDL_LockSurface(Surface) < 0)
1625 /* Do the clipping */
1626 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1630 if (y2 > Surface->h - 1)
1631 y2 = Surface->h - 1;
1638 SDL_FillRect(Surface, &l, Color);
1640 if (SDL_MUSTLOCK(Surface))
1642 SDL_UnlockSurface(Surface);
1646 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1647 Uint8 R, Uint8 G, Uint8 B)
1649 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1652 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1663 /* Do the clipping */
1664 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1668 if (y2 > Surface->h - 1)
1669 y2 = Surface->h - 1;
1676 SDL_FillRect(Surface, &l, Color);
1679 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1680 Sint16 x2, Sint16 y2, Uint32 Color,
1681 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1684 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1689 sdx = (dx < 0) ? -1 : 1;
1690 sdy = (dy < 0) ? -1 : 1;
1702 for (x = 0; x < dx; x++)
1704 Callback(Surface, px, py, Color);
1718 for (y = 0; y < dy; y++)
1720 Callback(Surface, px, py, Color);
1734 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1735 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1736 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1739 sge_DoLine(Surface, X1, Y1, X2, Y2,
1740 SDL_MapRGB(Surface->format, R, G, B), Callback);
1743 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1746 if (SDL_MUSTLOCK(Surface))
1748 if (SDL_LockSurface(Surface) < 0)
1753 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1755 /* unlock the display */
1756 if (SDL_MUSTLOCK(Surface))
1758 SDL_UnlockSurface(Surface);
1762 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1763 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1765 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1768 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1770 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1775 -----------------------------------------------------------------------------
1776 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1777 -----------------------------------------------------------------------------
1780 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1781 int width, int height, Uint32 color)
1785 for (y = src_y; y < src_y + height; y++)
1787 for (x = src_x; x < src_x + width; x++)
1789 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1791 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1796 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1797 int src_x, int src_y, int width, int height,
1798 int dst_x, int dst_y)
1802 for (y = 0; y < height; y++)
1804 for (x = 0; x < width; x++)
1806 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1808 if (pixel != BLACK_PIXEL)
1809 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1815 /* ========================================================================= */
1816 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1817 /* (Rotozoomer) by Andreas Schiffler */
1818 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1819 /* ========================================================================= */
1822 -----------------------------------------------------------------------------
1825 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1826 -----------------------------------------------------------------------------
1837 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1840 tColorRGBA *sp, *csp, *dp;
1844 sp = csp = (tColorRGBA *) src->pixels;
1845 dp = (tColorRGBA *) dst->pixels;
1846 dgap = dst->pitch - dst->w * 4;
1848 for (y = 0; y < dst->h; y++)
1852 for (x = 0; x < dst->w; x++)
1854 tColorRGBA *sp0 = sp;
1855 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1856 tColorRGBA *sp00 = &sp0[0];
1857 tColorRGBA *sp01 = &sp0[1];
1858 tColorRGBA *sp10 = &sp1[0];
1859 tColorRGBA *sp11 = &sp1[1];
1862 /* create new color pixel from all four source color pixels */
1863 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1864 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1865 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1866 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1871 /* advance source pointers */
1874 /* advance destination pointer */
1878 /* advance source pointer */
1879 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1881 /* advance destination pointers */
1882 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1888 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1890 int x, y, *sax, *say, *csax, *csay;
1892 tColorRGBA *sp, *csp, *csp0, *dp;
1895 /* use specialized zoom function when scaling down to exactly half size */
1896 if (src->w == 2 * dst->w &&
1897 src->h == 2 * dst->h)
1898 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1900 /* variable setup */
1901 sx = (float) src->w / (float) dst->w;
1902 sy = (float) src->h / (float) dst->h;
1904 /* allocate memory for row increments */
1905 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1906 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1908 /* precalculate row increments */
1909 for (x = 0; x <= dst->w; x++)
1910 *csax++ = (int)(sx * x);
1912 for (y = 0; y <= dst->h; y++)
1913 *csay++ = (int)(sy * y);
1916 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1917 dp = (tColorRGBA *) dst->pixels;
1918 dgap = dst->pitch - dst->w * 4;
1921 for (y = 0; y < dst->h; y++)
1926 for (x = 0; x < dst->w; x++)
1931 /* advance source pointers */
1935 /* advance destination pointer */
1939 /* advance source pointer */
1941 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1943 /* advance destination pointers */
1944 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1954 -----------------------------------------------------------------------------
1957 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1958 -----------------------------------------------------------------------------
1961 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1963 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1964 Uint8 *sp, *dp, *csp;
1967 /* variable setup */
1968 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1969 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1971 /* allocate memory for row increments */
1972 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1973 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1975 /* precalculate row increments */
1978 for (x = 0; x < dst->w; x++)
1981 *csax = (csx >> 16);
1988 for (y = 0; y < dst->h; y++)
1991 *csay = (csy >> 16);
1998 for (x = 0; x < dst->w; x++)
2006 for (y = 0; y < dst->h; y++)
2013 sp = csp = (Uint8 *) src->pixels;
2014 dp = (Uint8 *) dst->pixels;
2015 dgap = dst->pitch - dst->w;
2019 for (y = 0; y < dst->h; y++)
2023 for (x = 0; x < dst->w; x++)
2028 /* advance source pointers */
2032 /* advance destination pointer */
2036 /* advance source pointer (for row) */
2037 csp += ((*csay) * src->pitch);
2040 /* advance destination pointers */
2051 -----------------------------------------------------------------------------
2054 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2055 'zoomx' and 'zoomy' are scaling factors for width and height.
2056 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2057 into a 32bit RGBA format on the fly.
2058 -----------------------------------------------------------------------------
2061 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2063 SDL_Surface *zoom_src = NULL;
2064 SDL_Surface *zoom_dst = NULL;
2065 boolean is_converted = FALSE;
2072 /* determine if source surface is 32 bit or 8 bit */
2073 is_32bit = (src->format->BitsPerPixel == 32);
2075 if (is_32bit || src->format->BitsPerPixel == 8)
2077 /* use source surface 'as is' */
2082 /* new source surface is 32 bit with a defined RGB ordering */
2083 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2084 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2085 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2087 is_converted = TRUE;
2090 /* allocate surface to completely contain the zoomed surface */
2093 /* target surface is 32 bit with source RGBA/ABGR ordering */
2094 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2095 zoom_src->format->Rmask,
2096 zoom_src->format->Gmask,
2097 zoom_src->format->Bmask, 0);
2101 /* target surface is 8 bit */
2102 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2106 /* lock source surface */
2107 SDL_LockSurface(zoom_src);
2109 /* check which kind of surface we have */
2112 /* call the 32 bit transformation routine to do the zooming */
2113 zoomSurfaceRGBA(zoom_src, zoom_dst);
2118 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2119 zoom_dst->format->palette->colors[i] =
2120 zoom_src->format->palette->colors[i];
2121 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2123 /* call the 8 bit transformation routine to do the zooming */
2124 zoomSurfaceY(zoom_src, zoom_dst);
2127 /* unlock source surface */
2128 SDL_UnlockSurface(zoom_src);
2130 /* free temporary surface */
2132 SDL_FreeSurface(zoom_src);
2134 /* return destination surface */
2138 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2140 Bitmap *dst_bitmap = CreateBitmapStruct();
2141 SDL_Surface **dst_surface = &dst_bitmap->surface;
2143 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2144 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2146 dst_bitmap->width = dst_width;
2147 dst_bitmap->height = dst_height;
2149 /* create zoomed temporary surface from source surface */
2150 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2152 /* create native format destination surface from zoomed temporary surface */
2153 SDLSetNativeSurface(dst_surface);
2159 /* ========================================================================= */
2160 /* load image to bitmap */
2161 /* ========================================================================= */
2163 Bitmap *SDLLoadImage(char *filename)
2165 Bitmap *new_bitmap = CreateBitmapStruct();
2166 SDL_Surface *sdl_image_tmp;
2168 print_timestamp_init("SDLLoadImage");
2170 print_timestamp_time(getBaseNamePtr(filename));
2172 /* load image to temporary surface */
2173 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2175 SetError("IMG_Load(): %s", SDL_GetError());
2180 print_timestamp_time("IMG_Load");
2182 UPDATE_BUSY_STATE();
2184 /* create native non-transparent surface for current image */
2185 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2187 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2192 print_timestamp_time("SDL_DisplayFormat (opaque)");
2194 UPDATE_BUSY_STATE();
2196 /* create native transparent surface for current image */
2197 if (sdl_image_tmp->format->Amask == 0)
2198 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2199 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2201 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2203 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2208 print_timestamp_time("SDL_DisplayFormat (masked)");
2210 UPDATE_BUSY_STATE();
2212 /* free temporary surface */
2213 SDL_FreeSurface(sdl_image_tmp);
2215 new_bitmap->width = new_bitmap->surface->w;
2216 new_bitmap->height = new_bitmap->surface->h;
2218 print_timestamp_done("SDLLoadImage");
2224 /* ------------------------------------------------------------------------- */
2225 /* custom cursor fuctions */
2226 /* ------------------------------------------------------------------------- */
2228 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2230 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2231 cursor_info->width, cursor_info->height,
2232 cursor_info->hot_x, cursor_info->hot_y);
2235 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2237 static struct MouseCursorInfo *last_cursor_info = NULL;
2238 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2239 static SDL_Cursor *cursor_default = NULL;
2240 static SDL_Cursor *cursor_current = NULL;
2242 /* if invoked for the first time, store the SDL default cursor */
2243 if (cursor_default == NULL)
2244 cursor_default = SDL_GetCursor();
2246 /* only create new cursor if cursor info (custom only) has changed */
2247 if (cursor_info != NULL && cursor_info != last_cursor_info)
2249 cursor_current = create_cursor(cursor_info);
2250 last_cursor_info = cursor_info;
2253 /* only set new cursor if cursor info (custom or NULL) has changed */
2254 if (cursor_info != last_cursor_info2)
2255 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2257 last_cursor_info2 = cursor_info;
2261 /* ========================================================================= */
2262 /* audio functions */
2263 /* ========================================================================= */
2265 void SDLOpenAudio(void)
2267 #if !defined(TARGET_SDL2)
2268 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2269 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2272 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2274 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2278 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2279 AUDIO_NUM_CHANNELS_STEREO,
2280 setup.system.audio_fragment_size) < 0)
2282 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2286 audio.sound_available = TRUE;
2287 audio.music_available = TRUE;
2288 audio.loops_available = TRUE;
2289 audio.sound_enabled = TRUE;
2291 /* set number of available mixer channels */
2292 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2293 audio.music_channel = MUSIC_CHANNEL;
2294 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2296 Mixer_InitChannels();
2299 void SDLCloseAudio(void)
2302 Mix_HaltChannel(-1);
2305 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2309 /* ========================================================================= */
2310 /* event functions */
2311 /* ========================================================================= */
2313 void SDLNextEvent(Event *event)
2315 SDL_WaitEvent(event);
2318 void SDLHandleWindowManagerEvent(Event *event)
2321 #if defined(PLATFORM_WIN32)
2322 // experimental drag and drop code
2324 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2325 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2327 #if defined(TARGET_SDL2)
2328 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2330 if (syswmmsg->msg == WM_DROPFILES)
2333 #if defined(TARGET_SDL2)
2334 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2336 HDROP hdrop = (HDROP)syswmmsg->wParam;
2340 printf("::: SDL_SYSWMEVENT:\n");
2342 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2344 for (i = 0; i < num_files; i++)
2346 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2347 char buffer[buffer_len + 1];
2349 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2351 printf("::: - '%s'\n", buffer);
2354 #if defined(TARGET_SDL2)
2355 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2357 DragFinish((HDROP)syswmmsg->wParam);
2365 /* ========================================================================= */
2366 /* joystick functions */
2367 /* ========================================================================= */
2369 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2370 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2371 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2373 static boolean SDLOpenJoystick(int nr)
2375 if (nr < 0 || nr > MAX_PLAYERS)
2378 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2381 static void SDLCloseJoystick(int nr)
2383 if (nr < 0 || nr > MAX_PLAYERS)
2386 SDL_JoystickClose(sdl_joystick[nr]);
2388 sdl_joystick[nr] = NULL;
2391 static boolean SDLCheckJoystickOpened(int nr)
2393 if (nr < 0 || nr > MAX_PLAYERS)
2396 #if defined(TARGET_SDL2)
2397 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2399 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2403 void HandleJoystickEvent(Event *event)
2407 case SDL_JOYAXISMOTION:
2408 if (event->jaxis.axis < 2)
2409 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2412 case SDL_JOYBUTTONDOWN:
2413 if (event->jbutton.button < 2)
2414 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2417 case SDL_JOYBUTTONUP:
2418 if (event->jbutton.button < 2)
2419 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2427 void SDLInitJoysticks()
2429 static boolean sdl_joystick_subsystem_initialized = FALSE;
2430 boolean print_warning = !sdl_joystick_subsystem_initialized;
2433 if (!sdl_joystick_subsystem_initialized)
2435 sdl_joystick_subsystem_initialized = TRUE;
2437 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2439 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2444 for (i = 0; i < MAX_PLAYERS; i++)
2446 /* get configured joystick for this player */
2447 char *device_name = setup.input[i].joy.device_name;
2448 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2450 if (joystick_nr >= SDL_NumJoysticks())
2452 if (setup.input[i].use_joystick && print_warning)
2453 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2458 /* misuse joystick file descriptor variable to store joystick number */
2459 joystick.fd[i] = joystick_nr;
2461 if (joystick_nr == -1)
2464 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2465 if (SDLCheckJoystickOpened(joystick_nr))
2466 SDLCloseJoystick(joystick_nr);
2468 if (!setup.input[i].use_joystick)
2471 if (!SDLOpenJoystick(joystick_nr))
2474 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2479 joystick.status = JOYSTICK_ACTIVATED;
2483 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2485 if (nr < 0 || nr >= MAX_PLAYERS)
2489 *x = sdl_js_axis[nr][0];
2491 *y = sdl_js_axis[nr][1];
2494 *b1 = sdl_js_button[nr][0];
2496 *b2 = sdl_js_button[nr][1];