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 defined(TARGET_SDL2)
921 if (dst_bitmap == window)
923 // SDL_UpdateWindowSurface(sdl_window);
924 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
928 if (dst_bitmap == window)
930 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
936 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
937 int fade_mode, int fade_delay, int post_delay,
938 void (*draw_border_function)(void))
940 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
941 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
942 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
943 SDL_Surface *surface_screen = backbuffer->surface;
944 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
945 SDL_Rect src_rect, dst_rect;
947 int src_x = x, src_y = y;
948 int dst_x = x, dst_y = y;
949 unsigned int time_last, time_current;
951 // store function for drawing global masked border
952 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
954 // deactivate drawing of global border while fading, if needed
955 if (draw_border_function == NULL)
956 gfx.draw_global_border_function = NULL;
965 dst_rect.w = width; /* (ignored) */
966 dst_rect.h = height; /* (ignored) */
968 dst_rect2 = dst_rect;
970 /* copy source and target surfaces to temporary surfaces for fading */
971 if (fade_mode & FADE_TYPE_TRANSFORM)
973 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
974 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
976 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
977 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
979 else if (fade_mode & FADE_TYPE_FADE_IN)
981 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
982 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
984 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
986 else /* FADE_TYPE_FADE_OUT */
988 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
989 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
991 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
994 time_current = SDL_GetTicks();
996 if (fade_mode == FADE_MODE_MELT)
998 boolean done = FALSE;
1000 int melt_columns = width / melt_pixels;
1001 int ypos[melt_columns];
1002 int max_steps = height / 8 + 32;
1007 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1008 #if defined(TARGET_SDL2)
1009 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1011 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1014 ypos[0] = -GetSimpleRandom(16);
1016 for (i = 1 ; i < melt_columns; i++)
1018 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1020 ypos[i] = ypos[i - 1] + r;
1033 time_last = time_current;
1034 time_current = SDL_GetTicks();
1035 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1036 steps_final = MIN(MAX(0, steps), max_steps);
1040 done = (steps_done >= steps_final);
1042 for (i = 0 ; i < melt_columns; i++)
1050 else if (ypos[i] < height)
1055 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1057 if (ypos[i] + dy >= height)
1058 dy = height - ypos[i];
1060 /* copy part of (appearing) target surface to upper area */
1061 src_rect.x = src_x + i * melt_pixels;
1062 // src_rect.y = src_y + ypos[i];
1064 src_rect.w = melt_pixels;
1066 src_rect.h = ypos[i] + dy;
1068 dst_rect.x = dst_x + i * melt_pixels;
1069 // dst_rect.y = dst_y + ypos[i];
1072 if (steps_done >= steps_final)
1073 SDL_BlitSurface(surface_target, &src_rect,
1074 surface_screen, &dst_rect);
1078 /* copy part of (disappearing) source surface to lower area */
1079 src_rect.x = src_x + i * melt_pixels;
1081 src_rect.w = melt_pixels;
1082 src_rect.h = height - ypos[i];
1084 dst_rect.x = dst_x + i * melt_pixels;
1085 dst_rect.y = dst_y + ypos[i];
1087 if (steps_done >= steps_final)
1088 SDL_BlitSurface(surface_source, &src_rect,
1089 surface_screen, &dst_rect);
1095 src_rect.x = src_x + i * melt_pixels;
1097 src_rect.w = melt_pixels;
1098 src_rect.h = height;
1100 dst_rect.x = dst_x + i * melt_pixels;
1103 if (steps_done >= steps_final)
1104 SDL_BlitSurface(surface_target, &src_rect,
1105 surface_screen, &dst_rect);
1109 if (steps_done >= steps_final)
1111 if (draw_border_function != NULL)
1112 draw_border_function();
1114 UpdateScreen(&dst_rect2);
1118 else if (fade_mode == FADE_MODE_CURTAIN)
1122 int xx_size = width / 2;
1124 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1125 #if defined(TARGET_SDL2)
1126 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1128 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1131 for (xx = 0; xx < xx_size;)
1133 time_last = time_current;
1134 time_current = SDL_GetTicks();
1135 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1136 xx_final = MIN(MAX(0, xx), xx_size);
1141 src_rect.h = height;
1146 /* draw new (target) image to screen buffer */
1147 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1149 if (xx_final < xx_size)
1151 src_rect.w = xx_size - xx_final;
1152 src_rect.h = height;
1154 /* draw old (source) image to screen buffer (left side) */
1156 src_rect.x = src_x + xx_final;
1159 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1161 /* draw old (source) image to screen buffer (right side) */
1163 src_rect.x = src_x + xx_size;
1164 dst_rect.x = dst_x + xx_size + xx_final;
1166 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1169 if (draw_border_function != NULL)
1170 draw_border_function();
1172 /* only update the region of the screen that is affected from fading */
1173 UpdateScreen(&dst_rect2);
1176 else /* fading in, fading out or cross-fading */
1181 for (alpha = 0.0; alpha < 255.0;)
1183 time_last = time_current;
1184 time_current = SDL_GetTicks();
1185 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1186 alpha_final = MIN(MAX(0, alpha), 255);
1188 /* draw existing (source) image to screen buffer */
1189 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1191 /* draw new (target) image to screen buffer using alpha blending */
1192 #if defined(TARGET_SDL2)
1193 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1194 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1196 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1198 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1200 if (draw_border_function != NULL)
1201 draw_border_function();
1203 /* only update the region of the screen that is affected from fading */
1204 UpdateScreen(&dst_rect);
1210 unsigned int time_post_delay;
1212 time_current = SDL_GetTicks();
1213 time_post_delay = time_current + post_delay;
1215 while (time_current < time_post_delay)
1217 // do not wait longer than 10 ms at a time to be able to ...
1218 Delay(MIN(10, time_post_delay - time_current));
1220 // ... continue drawing global animations during post delay
1223 time_current = SDL_GetTicks();
1227 // restore function for drawing global masked border
1228 gfx.draw_global_border_function = draw_global_border_function;
1231 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1232 int to_x, int to_y, Uint32 color)
1234 SDL_Surface *surface = dst_bitmap->surface;
1238 swap_numbers(&from_x, &to_x);
1241 swap_numbers(&from_y, &to_y);
1245 rect.w = (to_x - from_x + 1);
1246 rect.h = (to_y - from_y + 1);
1248 SDL_FillRect(surface, &rect, color);
1251 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1252 int to_x, int to_y, Uint32 color)
1254 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1257 #if ENABLE_UNUSED_CODE
1258 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1259 int num_points, Uint32 color)
1264 for (i = 0; i < num_points - 1; i++)
1266 for (x = 0; x < line_width; x++)
1268 for (y = 0; y < line_width; y++)
1270 int dx = x - line_width / 2;
1271 int dy = y - line_width / 2;
1273 if ((x == 0 && y == 0) ||
1274 (x == 0 && y == line_width - 1) ||
1275 (x == line_width - 1 && y == 0) ||
1276 (x == line_width - 1 && y == line_width - 1))
1279 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1280 points[i+1].x + dx, points[i+1].y + dy, color);
1287 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1289 SDL_Surface *surface = src_bitmap->surface;
1291 switch (surface->format->BytesPerPixel)
1293 case 1: /* assuming 8-bpp */
1295 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1299 case 2: /* probably 15-bpp or 16-bpp */
1301 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1305 case 3: /* slow 24-bpp mode; usually not used */
1307 /* does this work? */
1308 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1312 shift = surface->format->Rshift;
1313 color |= *(pix + shift / 8) >> shift;
1314 shift = surface->format->Gshift;
1315 color |= *(pix + shift / 8) >> shift;
1316 shift = surface->format->Bshift;
1317 color |= *(pix + shift / 8) >> shift;
1323 case 4: /* probably 32-bpp */
1325 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1334 /* ========================================================================= */
1335 /* The following functions were taken from the SGE library */
1336 /* (SDL Graphics Extension Library) by Anders Lindström */
1337 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1338 /* ========================================================================= */
1340 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1342 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1344 switch (surface->format->BytesPerPixel)
1348 /* Assuming 8-bpp */
1349 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1355 /* Probably 15-bpp or 16-bpp */
1356 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1362 /* Slow 24-bpp mode, usually not used */
1366 /* Gack - slow, but endian correct */
1367 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1368 shift = surface->format->Rshift;
1369 *(pix+shift/8) = color>>shift;
1370 shift = surface->format->Gshift;
1371 *(pix+shift/8) = color>>shift;
1372 shift = surface->format->Bshift;
1373 *(pix+shift/8) = color>>shift;
1379 /* Probably 32-bpp */
1380 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1387 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1388 Uint8 R, Uint8 G, Uint8 B)
1390 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1393 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1395 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1398 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1400 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1403 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1408 /* Gack - slow, but endian correct */
1409 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1410 shift = surface->format->Rshift;
1411 *(pix+shift/8) = color>>shift;
1412 shift = surface->format->Gshift;
1413 *(pix+shift/8) = color>>shift;
1414 shift = surface->format->Bshift;
1415 *(pix+shift/8) = color>>shift;
1418 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1420 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1423 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1425 switch (dest->format->BytesPerPixel)
1428 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1432 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1436 _PutPixel24(dest,x,y,color);
1440 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1445 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1447 if (SDL_MUSTLOCK(surface))
1449 if (SDL_LockSurface(surface) < 0)
1455 _PutPixel(surface, x, y, color);
1457 if (SDL_MUSTLOCK(surface))
1459 SDL_UnlockSurface(surface);
1463 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1464 Uint8 r, Uint8 g, Uint8 b)
1466 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1469 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1471 if (y >= 0 && y <= dest->h - 1)
1473 switch (dest->format->BytesPerPixel)
1476 return y*dest->pitch;
1480 return y*dest->pitch/2;
1484 return y*dest->pitch;
1488 return y*dest->pitch/4;
1496 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1498 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1500 switch (surface->format->BytesPerPixel)
1504 /* Assuming 8-bpp */
1505 *((Uint8 *)surface->pixels + ypitch + x) = color;
1511 /* Probably 15-bpp or 16-bpp */
1512 *((Uint16 *)surface->pixels + ypitch + x) = color;
1518 /* Slow 24-bpp mode, usually not used */
1522 /* Gack - slow, but endian correct */
1523 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1524 shift = surface->format->Rshift;
1525 *(pix+shift/8) = color>>shift;
1526 shift = surface->format->Gshift;
1527 *(pix+shift/8) = color>>shift;
1528 shift = surface->format->Bshift;
1529 *(pix+shift/8) = color>>shift;
1535 /* Probably 32-bpp */
1536 *((Uint32 *)surface->pixels + ypitch + x) = color;
1543 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1548 if (SDL_MUSTLOCK(Surface))
1550 if (SDL_LockSurface(Surface) < 0)
1563 /* Do the clipping */
1564 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1568 if (x2 > Surface->w - 1)
1569 x2 = Surface->w - 1;
1576 SDL_FillRect(Surface, &l, Color);
1578 if (SDL_MUSTLOCK(Surface))
1580 SDL_UnlockSurface(Surface);
1584 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1585 Uint8 R, Uint8 G, Uint8 B)
1587 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1590 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1601 /* Do the clipping */
1602 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1606 if (x2 > Surface->w - 1)
1607 x2 = Surface->w - 1;
1614 SDL_FillRect(Surface, &l, Color);
1617 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1622 if (SDL_MUSTLOCK(Surface))
1624 if (SDL_LockSurface(Surface) < 0)
1637 /* Do the clipping */
1638 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1642 if (y2 > Surface->h - 1)
1643 y2 = Surface->h - 1;
1650 SDL_FillRect(Surface, &l, Color);
1652 if (SDL_MUSTLOCK(Surface))
1654 SDL_UnlockSurface(Surface);
1658 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1659 Uint8 R, Uint8 G, Uint8 B)
1661 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1664 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1675 /* Do the clipping */
1676 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1680 if (y2 > Surface->h - 1)
1681 y2 = Surface->h - 1;
1688 SDL_FillRect(Surface, &l, Color);
1691 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1692 Sint16 x2, Sint16 y2, Uint32 Color,
1693 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1696 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1701 sdx = (dx < 0) ? -1 : 1;
1702 sdy = (dy < 0) ? -1 : 1;
1714 for (x = 0; x < dx; x++)
1716 Callback(Surface, px, py, Color);
1730 for (y = 0; y < dy; y++)
1732 Callback(Surface, px, py, Color);
1746 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1747 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1748 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1751 sge_DoLine(Surface, X1, Y1, X2, Y2,
1752 SDL_MapRGB(Surface->format, R, G, B), Callback);
1755 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1758 if (SDL_MUSTLOCK(Surface))
1760 if (SDL_LockSurface(Surface) < 0)
1765 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1767 /* unlock the display */
1768 if (SDL_MUSTLOCK(Surface))
1770 SDL_UnlockSurface(Surface);
1774 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1775 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1777 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1780 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1782 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1787 -----------------------------------------------------------------------------
1788 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1789 -----------------------------------------------------------------------------
1792 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1793 int width, int height, Uint32 color)
1797 for (y = src_y; y < src_y + height; y++)
1799 for (x = src_x; x < src_x + width; x++)
1801 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1803 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1808 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1809 int src_x, int src_y, int width, int height,
1810 int dst_x, int dst_y)
1814 for (y = 0; y < height; y++)
1816 for (x = 0; x < width; x++)
1818 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1820 if (pixel != BLACK_PIXEL)
1821 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1827 /* ========================================================================= */
1828 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1829 /* (Rotozoomer) by Andreas Schiffler */
1830 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1831 /* ========================================================================= */
1834 -----------------------------------------------------------------------------
1837 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1838 -----------------------------------------------------------------------------
1849 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1852 tColorRGBA *sp, *csp, *dp;
1856 sp = csp = (tColorRGBA *) src->pixels;
1857 dp = (tColorRGBA *) dst->pixels;
1858 dgap = dst->pitch - dst->w * 4;
1860 for (y = 0; y < dst->h; y++)
1864 for (x = 0; x < dst->w; x++)
1866 tColorRGBA *sp0 = sp;
1867 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1868 tColorRGBA *sp00 = &sp0[0];
1869 tColorRGBA *sp01 = &sp0[1];
1870 tColorRGBA *sp10 = &sp1[0];
1871 tColorRGBA *sp11 = &sp1[1];
1874 /* create new color pixel from all four source color pixels */
1875 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1876 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1877 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1878 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1883 /* advance source pointers */
1886 /* advance destination pointer */
1890 /* advance source pointer */
1891 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1893 /* advance destination pointers */
1894 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1900 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1902 int x, y, *sax, *say, *csax, *csay;
1904 tColorRGBA *sp, *csp, *csp0, *dp;
1907 /* use specialized zoom function when scaling down to exactly half size */
1908 if (src->w == 2 * dst->w &&
1909 src->h == 2 * dst->h)
1910 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1912 /* variable setup */
1913 sx = (float) src->w / (float) dst->w;
1914 sy = (float) src->h / (float) dst->h;
1916 /* allocate memory for row increments */
1917 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1918 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1920 /* precalculate row increments */
1921 for (x = 0; x <= dst->w; x++)
1922 *csax++ = (int)(sx * x);
1924 for (y = 0; y <= dst->h; y++)
1925 *csay++ = (int)(sy * y);
1928 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1929 dp = (tColorRGBA *) dst->pixels;
1930 dgap = dst->pitch - dst->w * 4;
1933 for (y = 0; y < dst->h; y++)
1938 for (x = 0; x < dst->w; x++)
1943 /* advance source pointers */
1947 /* advance destination pointer */
1951 /* advance source pointer */
1953 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1955 /* advance destination pointers */
1956 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1966 -----------------------------------------------------------------------------
1969 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1970 -----------------------------------------------------------------------------
1973 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1975 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1976 Uint8 *sp, *dp, *csp;
1979 /* variable setup */
1980 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1981 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1983 /* allocate memory for row increments */
1984 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1985 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1987 /* precalculate row increments */
1990 for (x = 0; x < dst->w; x++)
1993 *csax = (csx >> 16);
2000 for (y = 0; y < dst->h; y++)
2003 *csay = (csy >> 16);
2010 for (x = 0; x < dst->w; x++)
2018 for (y = 0; y < dst->h; y++)
2025 sp = csp = (Uint8 *) src->pixels;
2026 dp = (Uint8 *) dst->pixels;
2027 dgap = dst->pitch - dst->w;
2031 for (y = 0; y < dst->h; y++)
2035 for (x = 0; x < dst->w; x++)
2040 /* advance source pointers */
2044 /* advance destination pointer */
2048 /* advance source pointer (for row) */
2049 csp += ((*csay) * src->pitch);
2052 /* advance destination pointers */
2063 -----------------------------------------------------------------------------
2066 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2067 'zoomx' and 'zoomy' are scaling factors for width and height.
2068 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2069 into a 32bit RGBA format on the fly.
2070 -----------------------------------------------------------------------------
2073 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2075 SDL_Surface *zoom_src = NULL;
2076 SDL_Surface *zoom_dst = NULL;
2077 boolean is_converted = FALSE;
2084 /* determine if source surface is 32 bit or 8 bit */
2085 is_32bit = (src->format->BitsPerPixel == 32);
2087 if (is_32bit || src->format->BitsPerPixel == 8)
2089 /* use source surface 'as is' */
2094 /* new source surface is 32 bit with a defined RGB ordering */
2095 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2096 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2097 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2099 is_converted = TRUE;
2102 /* allocate surface to completely contain the zoomed surface */
2105 /* target surface is 32 bit with source RGBA/ABGR ordering */
2106 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2107 zoom_src->format->Rmask,
2108 zoom_src->format->Gmask,
2109 zoom_src->format->Bmask, 0);
2113 /* target surface is 8 bit */
2114 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2118 /* lock source surface */
2119 SDL_LockSurface(zoom_src);
2121 /* check which kind of surface we have */
2124 /* call the 32 bit transformation routine to do the zooming */
2125 zoomSurfaceRGBA(zoom_src, zoom_dst);
2130 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2131 zoom_dst->format->palette->colors[i] =
2132 zoom_src->format->palette->colors[i];
2133 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2135 /* call the 8 bit transformation routine to do the zooming */
2136 zoomSurfaceY(zoom_src, zoom_dst);
2139 /* unlock source surface */
2140 SDL_UnlockSurface(zoom_src);
2142 /* free temporary surface */
2144 SDL_FreeSurface(zoom_src);
2146 /* return destination surface */
2150 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2152 Bitmap *dst_bitmap = CreateBitmapStruct();
2153 SDL_Surface **dst_surface = &dst_bitmap->surface;
2155 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2156 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2158 dst_bitmap->width = dst_width;
2159 dst_bitmap->height = dst_height;
2161 /* create zoomed temporary surface from source surface */
2162 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2164 /* create native format destination surface from zoomed temporary surface */
2165 SDLSetNativeSurface(dst_surface);
2171 /* ========================================================================= */
2172 /* load image to bitmap */
2173 /* ========================================================================= */
2175 Bitmap *SDLLoadImage(char *filename)
2177 Bitmap *new_bitmap = CreateBitmapStruct();
2178 SDL_Surface *sdl_image_tmp;
2180 print_timestamp_init("SDLLoadImage");
2182 print_timestamp_time(getBaseNamePtr(filename));
2184 /* load image to temporary surface */
2185 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2187 SetError("IMG_Load(): %s", SDL_GetError());
2192 print_timestamp_time("IMG_Load");
2194 UPDATE_BUSY_STATE();
2196 /* create native non-transparent surface for current image */
2197 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2199 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2204 print_timestamp_time("SDL_DisplayFormat (opaque)");
2206 UPDATE_BUSY_STATE();
2208 /* create native transparent surface for current image */
2209 if (sdl_image_tmp->format->Amask == 0)
2210 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2211 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2213 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2215 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2220 print_timestamp_time("SDL_DisplayFormat (masked)");
2222 UPDATE_BUSY_STATE();
2224 /* free temporary surface */
2225 SDL_FreeSurface(sdl_image_tmp);
2227 new_bitmap->width = new_bitmap->surface->w;
2228 new_bitmap->height = new_bitmap->surface->h;
2230 print_timestamp_done("SDLLoadImage");
2236 /* ------------------------------------------------------------------------- */
2237 /* custom cursor fuctions */
2238 /* ------------------------------------------------------------------------- */
2240 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2242 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2243 cursor_info->width, cursor_info->height,
2244 cursor_info->hot_x, cursor_info->hot_y);
2247 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2249 static struct MouseCursorInfo *last_cursor_info = NULL;
2250 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2251 static SDL_Cursor *cursor_default = NULL;
2252 static SDL_Cursor *cursor_current = NULL;
2254 /* if invoked for the first time, store the SDL default cursor */
2255 if (cursor_default == NULL)
2256 cursor_default = SDL_GetCursor();
2258 /* only create new cursor if cursor info (custom only) has changed */
2259 if (cursor_info != NULL && cursor_info != last_cursor_info)
2261 cursor_current = create_cursor(cursor_info);
2262 last_cursor_info = cursor_info;
2265 /* only set new cursor if cursor info (custom or NULL) has changed */
2266 if (cursor_info != last_cursor_info2)
2267 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2269 last_cursor_info2 = cursor_info;
2273 /* ========================================================================= */
2274 /* audio functions */
2275 /* ========================================================================= */
2277 void SDLOpenAudio(void)
2279 #if !defined(TARGET_SDL2)
2280 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2281 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2284 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2286 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2290 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2291 AUDIO_NUM_CHANNELS_STEREO,
2292 setup.system.audio_fragment_size) < 0)
2294 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2298 audio.sound_available = TRUE;
2299 audio.music_available = TRUE;
2300 audio.loops_available = TRUE;
2301 audio.sound_enabled = TRUE;
2303 /* set number of available mixer channels */
2304 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2305 audio.music_channel = MUSIC_CHANNEL;
2306 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2308 Mixer_InitChannels();
2311 void SDLCloseAudio(void)
2314 Mix_HaltChannel(-1);
2317 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2321 /* ========================================================================= */
2322 /* event functions */
2323 /* ========================================================================= */
2325 void SDLNextEvent(Event *event)
2327 SDL_WaitEvent(event);
2330 void SDLHandleWindowManagerEvent(Event *event)
2333 #if defined(PLATFORM_WIN32)
2334 // experimental drag and drop code
2336 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2337 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2339 #if defined(TARGET_SDL2)
2340 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2342 if (syswmmsg->msg == WM_DROPFILES)
2345 #if defined(TARGET_SDL2)
2346 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2348 HDROP hdrop = (HDROP)syswmmsg->wParam;
2352 printf("::: SDL_SYSWMEVENT:\n");
2354 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2356 for (i = 0; i < num_files; i++)
2358 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2359 char buffer[buffer_len + 1];
2361 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2363 printf("::: - '%s'\n", buffer);
2366 #if defined(TARGET_SDL2)
2367 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2369 DragFinish((HDROP)syswmmsg->wParam);
2377 /* ========================================================================= */
2378 /* joystick functions */
2379 /* ========================================================================= */
2381 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2382 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2383 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2385 static boolean SDLOpenJoystick(int nr)
2387 if (nr < 0 || nr > MAX_PLAYERS)
2390 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2393 static void SDLCloseJoystick(int nr)
2395 if (nr < 0 || nr > MAX_PLAYERS)
2398 SDL_JoystickClose(sdl_joystick[nr]);
2400 sdl_joystick[nr] = NULL;
2403 static boolean SDLCheckJoystickOpened(int nr)
2405 if (nr < 0 || nr > MAX_PLAYERS)
2408 #if defined(TARGET_SDL2)
2409 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2411 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2415 void HandleJoystickEvent(Event *event)
2419 case SDL_JOYAXISMOTION:
2420 if (event->jaxis.axis < 2)
2421 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2424 case SDL_JOYBUTTONDOWN:
2425 if (event->jbutton.button < 2)
2426 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2429 case SDL_JOYBUTTONUP:
2430 if (event->jbutton.button < 2)
2431 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2439 void SDLInitJoysticks()
2441 static boolean sdl_joystick_subsystem_initialized = FALSE;
2442 boolean print_warning = !sdl_joystick_subsystem_initialized;
2445 if (!sdl_joystick_subsystem_initialized)
2447 sdl_joystick_subsystem_initialized = TRUE;
2449 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2451 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2456 for (i = 0; i < MAX_PLAYERS; i++)
2458 /* get configured joystick for this player */
2459 char *device_name = setup.input[i].joy.device_name;
2460 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2462 if (joystick_nr >= SDL_NumJoysticks())
2464 if (setup.input[i].use_joystick && print_warning)
2465 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2470 /* misuse joystick file descriptor variable to store joystick number */
2471 joystick.fd[i] = joystick_nr;
2473 if (joystick_nr == -1)
2476 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2477 if (SDLCheckJoystickOpened(joystick_nr))
2478 SDLCloseJoystick(joystick_nr);
2480 if (!setup.input[i].use_joystick)
2483 if (!SDLOpenJoystick(joystick_nr))
2486 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2491 joystick.status = JOYSTICK_ACTIVATED;
2495 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2497 if (nr < 0 || nr >= MAX_PLAYERS)
2501 *x = sdl_js_axis[nr][0];
2503 *y = sdl_js_axis[nr][1];
2506 *b1 = sdl_js_button[nr][0];
2508 *b2 = sdl_js_button[nr][1];