1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
18 #define ENABLE_UNUSED_CODE 0 /* currently unused functions */
21 /* ========================================================================= */
23 /* ========================================================================= */
25 /* SDL internal variables */
26 #if defined(TARGET_SDL2)
27 static SDL_Window *sdl_window = NULL;
28 static SDL_Renderer *sdl_renderer = NULL;
29 static SDL_Texture *sdl_texture_stream = NULL;
30 static SDL_Texture *sdl_texture_target = NULL;
31 static boolean fullscreen_enabled = FALSE;
34 static boolean limit_screen_updates = FALSE;
37 /* functions from SGE library */
38 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
40 void SDLLimitScreenUpdates(boolean enable)
42 limit_screen_updates = enable;
45 static void FinalizeScreen()
47 // copy global animations to render target buffer, if defined (below border)
48 if (gfx.draw_global_anim_function != NULL)
49 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
51 // copy global masked border to render target buffer, if defined
52 if (gfx.draw_global_border_function != NULL)
53 gfx.draw_global_border_function(DRAW_TO_SCREEN);
55 // copy global animations to render target buffer, if defined (above border)
56 if (gfx.draw_global_anim_function != NULL)
57 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
60 static void UpdateScreenExt(SDL_Rect *rect, boolean with_frame_delay)
62 static unsigned int update_screen_delay = 0;
63 unsigned int update_screen_delay_value = 50; /* (milliseconds) */
64 SDL_Surface *screen = backbuffer->surface;
66 if (limit_screen_updates &&
67 !DelayReached(&update_screen_delay, update_screen_delay_value))
70 LimitScreenUpdates(FALSE);
74 static int LastFrameCounter = 0;
75 boolean changed = (FrameCounter != LastFrameCounter);
77 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
78 (changed ? "-" : "SAME FRAME UPDATED"));
80 LastFrameCounter = FrameCounter;
89 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP &&
90 gfx.final_screen_bitmap != NULL) // may not be initialized yet
92 // draw global animations using bitmaps instead of using textures
93 // to prevent texture scaling artefacts (this is potentially slower)
95 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
96 gfx.win_xsize, gfx.win_ysize, 0, 0);
100 screen = gfx.final_screen_bitmap->surface;
102 // force full window redraw
106 #if defined(TARGET_SDL2)
107 SDL_Texture *sdl_texture = sdl_texture_stream;
109 // deactivate use of target texture if render targets are not supported
110 if ((video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
111 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE) &&
112 sdl_texture_target == NULL)
113 video.screen_rendering_mode = SPECIAL_RENDERING_OFF;
115 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET)
116 sdl_texture = sdl_texture_target;
120 int bytes_x = screen->pitch / video.width;
121 int bytes_y = screen->pitch;
123 SDL_UpdateTexture(sdl_texture, rect,
124 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
129 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
132 // clear render target buffer
133 SDL_RenderClear(sdl_renderer);
135 // set renderer to use target texture for rendering
136 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
137 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
138 SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
140 // copy backbuffer texture to render target buffer
141 if (video.screen_rendering_mode != SPECIAL_RENDERING_TARGET)
142 SDL_RenderCopy(sdl_renderer, sdl_texture_stream, NULL, NULL);
144 if (video.screen_rendering_mode != SPECIAL_RENDERING_BITMAP)
147 // when using target texture, copy it to screen buffer
148 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
149 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
151 SDL_SetRenderTarget(sdl_renderer, NULL);
152 SDL_RenderCopy(sdl_renderer, sdl_texture_target, NULL, NULL);
156 // global synchronization point of the game to align video frame delay
157 if (with_frame_delay)
158 WaitUntilDelayReached(&video.frame_delay, video.frame_delay_value);
160 #if defined(TARGET_SDL2)
161 // show render target buffer on screen
162 SDL_RenderPresent(sdl_renderer);
165 SDL_UpdateRects(screen, 1, rect);
167 SDL_UpdateRect(screen, 0, 0, 0, 0);
171 static void UpdateScreen_WithFrameDelay(SDL_Rect *rect)
173 UpdateScreenExt(rect, TRUE);
176 static void UpdateScreen_WithoutFrameDelay(SDL_Rect *rect)
178 UpdateScreenExt(rect, FALSE);
181 static void SDLSetWindowIcon(char *basename)
183 /* (setting the window icon on Mac OS X would replace the high-quality
184 dock icon with the currently smaller (and uglier) icon from file) */
186 #if !defined(PLATFORM_MACOSX)
187 char *filename = getCustomImageFilename(basename);
188 SDL_Surface *surface;
190 if (filename == NULL)
192 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
197 if ((surface = IMG_Load(filename)) == NULL)
199 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
204 /* set transparent color */
205 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
206 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
208 #if defined(TARGET_SDL2)
209 SDL_SetWindowIcon(sdl_window, surface);
211 SDL_WM_SetIcon(surface, NULL);
216 #if defined(TARGET_SDL2)
218 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
219 SDL_PixelFormat *format2)
221 return (format1->format == format2->format &&
222 format1->BitsPerPixel == format2->BitsPerPixel &&
223 format1->BytesPerPixel == format2->BytesPerPixel &&
224 format1->Rmask == format2->Rmask &&
225 format1->Gmask == format2->Gmask &&
226 format1->Bmask == format2->Bmask &&
227 format1->Amask == format2->Amask);
230 boolean SDLSetNativeSurface(SDL_Surface **surface)
232 SDL_Surface *new_surface;
234 if (surface == NULL ||
236 backbuffer == NULL ||
237 backbuffer->surface == NULL)
240 // if pixel format already optimized for destination surface, do nothing
241 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
244 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
246 if (new_surface == NULL)
247 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
249 SDL_FreeSurface(*surface);
251 *surface = new_surface;
256 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
258 SDL_PixelFormat format;
259 SDL_Surface *new_surface;
264 if (backbuffer && backbuffer->surface)
266 format = *backbuffer->surface->format;
267 format.Amask = surface->format->Amask; // keep alpha channel
271 format = *surface->format;
274 new_surface = SDL_ConvertSurface(surface, &format, 0);
276 if (new_surface == NULL)
277 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
284 boolean SDLSetNativeSurface(SDL_Surface **surface)
286 SDL_Surface *new_surface;
288 if (surface == NULL ||
293 new_surface = SDL_DisplayFormat(*surface);
295 if (new_surface == NULL)
296 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
298 SDL_FreeSurface(*surface);
300 *surface = new_surface;
305 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
307 SDL_Surface *new_surface;
309 if (video.initialized)
310 new_surface = SDL_DisplayFormat(surface);
312 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
314 if (new_surface == NULL)
315 Error(ERR_EXIT, "%s() failed: %s",
316 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
324 #if defined(TARGET_SDL2)
325 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
327 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
330 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
337 void SDLCreateBitmapTextures(Bitmap *bitmap)
339 #if defined(TARGET_SDL2)
344 SDL_DestroyTexture(bitmap->texture);
345 if (bitmap->texture_masked)
346 SDL_DestroyTexture(bitmap->texture_masked);
348 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
349 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
353 void SDLFreeBitmapTextures(Bitmap *bitmap)
355 #if defined(TARGET_SDL2)
360 SDL_DestroyTexture(bitmap->texture);
361 if (bitmap->texture_masked)
362 SDL_DestroyTexture(bitmap->texture_masked);
364 bitmap->texture = NULL;
365 bitmap->texture_masked = NULL;
369 void SDLInitVideoDisplay(void)
371 #if !defined(TARGET_SDL2)
372 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
373 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
375 SDL_putenv("SDL_VIDEO_CENTERED=1");
378 /* initialize SDL video */
379 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
380 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
382 /* set default SDL depth */
383 #if !defined(TARGET_SDL2)
384 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
386 video.default_depth = 32; // (how to determine video depth in SDL2?)
390 void SDLInitVideoBuffer(boolean fullscreen)
392 video.window_scaling_percent = setup.window_scaling_percent;
393 video.window_scaling_quality = setup.window_scaling_quality;
395 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
397 #if defined(TARGET_SDL2)
398 // SDL 2.0: support for (desktop) fullscreen mode available
399 video.fullscreen_available = TRUE;
401 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
402 video.fullscreen_available = FALSE;
405 /* open SDL video output device (window or fullscreen mode) */
406 if (!SDLSetVideoMode(fullscreen))
407 Error(ERR_EXIT, "setting video mode failed");
409 /* !!! SDL2 can only set the window icon if the window already exists !!! */
410 /* set window icon */
411 SDLSetWindowIcon(program.icon_filename);
413 /* set window and icon title */
414 #if defined(TARGET_SDL2)
415 SDL_SetWindowTitle(sdl_window, program.window_title);
417 SDL_WM_SetCaption(program.window_title, program.window_title);
420 /* SDL cannot directly draw to the visible video framebuffer like X11,
421 but always uses a backbuffer, which is then blitted to the visible
422 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
423 visible video framebuffer with 'SDL_Flip', if the hardware supports
424 this). Therefore do not use an additional backbuffer for drawing, but
425 use a symbolic buffer (distinguishable from the SDL backbuffer) called
426 'window', which indicates that the SDL backbuffer should be updated to
427 the visible video framebuffer when attempting to blit to it.
429 For convenience, it seems to be a good idea to create this symbolic
430 buffer 'window' at the same size as the SDL backbuffer. Although it
431 should never be drawn to directly, it would do no harm nevertheless. */
433 /* create additional (symbolic) buffer for double-buffering */
434 ReCreateBitmap(&window, video.width, video.height, video.depth);
437 static boolean SDLCreateScreen(boolean fullscreen)
439 SDL_Surface *new_surface = NULL;
441 #if defined(TARGET_SDL2)
442 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
443 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
445 int surface_flags_window = SURFACE_FLAGS;
446 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
449 #if defined(TARGET_SDL2)
451 int renderer_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
453 /* If SDL_CreateRenderer() is called from within a VirtualBox Windows VM
454 _without_ enabling 2D/3D acceleration and/or guest additions installed,
455 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
456 it will try to use accelerated graphics and apparently fails miserably) */
457 int renderer_flags = SDL_RENDERER_SOFTWARE;
461 int width = video.width;
462 int height = video.height;
463 int surface_flags = (fullscreen ? surface_flags_fullscreen :
464 surface_flags_window);
466 // default window size is unscaled
467 video.window_width = video.width;
468 video.window_height = video.height;
470 #if defined(TARGET_SDL2)
472 // store if initial screen mode is fullscreen mode when changing screen size
473 video.fullscreen_initial = fullscreen;
475 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
477 video.window_width = window_scaling_factor * width;
478 video.window_height = window_scaling_factor * height;
480 if (sdl_texture_stream)
482 SDL_DestroyTexture(sdl_texture_stream);
483 sdl_texture_stream = NULL;
486 if (sdl_texture_target)
488 SDL_DestroyTexture(sdl_texture_target);
489 sdl_texture_target = NULL;
492 if (!(fullscreen && fullscreen_enabled))
496 SDL_DestroyRenderer(sdl_renderer);
502 SDL_DestroyWindow(sdl_window);
507 if (sdl_window == NULL)
508 sdl_window = SDL_CreateWindow(program.window_title,
509 SDL_WINDOWPOS_CENTERED,
510 SDL_WINDOWPOS_CENTERED,
515 if (sdl_window != NULL)
517 if (sdl_renderer == NULL)
518 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, renderer_flags);
520 if (sdl_renderer != NULL)
522 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
523 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
524 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
526 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
527 SDL_PIXELFORMAT_ARGB8888,
528 SDL_TEXTUREACCESS_STREAMING,
531 if (SDL_RenderTargetSupported(sdl_renderer))
532 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
533 SDL_PIXELFORMAT_ARGB8888,
534 SDL_TEXTUREACCESS_TARGET,
537 if (sdl_texture_stream != NULL)
539 // use SDL default values for RGB masks and no alpha channel
540 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
542 if (new_surface == NULL)
543 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
547 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
552 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
557 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
562 if (gfx.final_screen_bitmap == NULL)
563 gfx.final_screen_bitmap = CreateBitmapStruct();
565 gfx.final_screen_bitmap->width = width;
566 gfx.final_screen_bitmap->height = height;
568 gfx.final_screen_bitmap->surface =
569 SDL_SetVideoMode(width, height, video.depth, surface_flags);
571 if (gfx.final_screen_bitmap->surface != NULL)
574 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
576 if (new_surface == NULL)
577 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
580 new_surface = gfx.final_screen_bitmap->surface;
581 gfx.final_screen_bitmap = NULL;
587 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
591 #if defined(TARGET_SDL2)
592 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
593 if (new_surface != NULL)
594 fullscreen_enabled = fullscreen;
597 if (backbuffer == NULL)
598 backbuffer = CreateBitmapStruct();
600 backbuffer->width = video.width;
601 backbuffer->height = video.height;
603 if (backbuffer->surface)
604 SDL_FreeSurface(backbuffer->surface);
606 backbuffer->surface = new_surface;
608 return (new_surface != NULL);
611 boolean SDLSetVideoMode(boolean fullscreen)
613 boolean success = FALSE;
617 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
619 /* switch display to fullscreen mode, if available */
620 success = SDLCreateScreen(TRUE);
624 /* switching display to fullscreen mode failed -- do not try it again */
625 video.fullscreen_available = FALSE;
629 video.fullscreen_enabled = TRUE;
633 if ((!fullscreen && video.fullscreen_enabled) || !success)
635 /* switch display to window mode */
636 success = SDLCreateScreen(FALSE);
640 /* switching display to window mode failed -- should not happen */
644 video.fullscreen_enabled = FALSE;
645 video.window_scaling_percent = setup.window_scaling_percent;
646 video.window_scaling_quality = setup.window_scaling_quality;
648 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
652 #if defined(TARGET_SDL2)
653 SDLRedrawWindow(); // map window
657 #if defined(PLATFORM_WIN32)
658 // experimental drag and drop code
660 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
663 SDL_SysWMinfo wminfo;
665 boolean wminfo_success = FALSE;
667 SDL_VERSION(&wminfo.version);
668 #if defined(TARGET_SDL2)
670 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
672 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
677 #if defined(TARGET_SDL2)
678 hwnd = wminfo.info.win.window;
680 hwnd = wminfo.window;
683 DragAcceptFiles(hwnd, TRUE);
692 void SDLSetWindowTitle()
694 #if defined(TARGET_SDL2)
695 SDL_SetWindowTitle(sdl_window, program.window_title);
697 SDL_WM_SetCaption(program.window_title, program.window_title);
701 #if defined(TARGET_SDL2)
702 void SDLSetWindowScaling(int window_scaling_percent)
704 if (sdl_window == NULL)
707 float window_scaling_factor = (float)window_scaling_percent / 100;
708 int new_window_width = (int)(window_scaling_factor * video.width);
709 int new_window_height = (int)(window_scaling_factor * video.height);
711 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
713 video.window_scaling_percent = window_scaling_percent;
714 video.window_width = new_window_width;
715 video.window_height = new_window_height;
720 void SDLSetWindowScalingQuality(char *window_scaling_quality)
722 SDL_Texture *new_texture;
724 if (sdl_texture_stream == NULL)
727 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
729 new_texture = SDL_CreateTexture(sdl_renderer,
730 SDL_PIXELFORMAT_ARGB8888,
731 SDL_TEXTUREACCESS_STREAMING,
732 video.width, video.height);
734 if (new_texture != NULL)
736 SDL_DestroyTexture(sdl_texture_stream);
738 sdl_texture_stream = new_texture;
741 if (SDL_RenderTargetSupported(sdl_renderer))
742 new_texture = SDL_CreateTexture(sdl_renderer,
743 SDL_PIXELFORMAT_ARGB8888,
744 SDL_TEXTUREACCESS_TARGET,
745 video.width, video.height);
749 if (new_texture != NULL)
751 SDL_DestroyTexture(sdl_texture_target);
753 sdl_texture_target = new_texture;
758 video.window_scaling_quality = window_scaling_quality;
761 void SDLSetWindowFullscreen(boolean fullscreen)
763 if (sdl_window == NULL)
766 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
768 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
769 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
771 // if screen size was changed in fullscreen mode, correct desktop window size
772 if (!fullscreen && video.fullscreen_initial)
774 SDLSetWindowScaling(setup.window_scaling_percent);
775 SDL_SetWindowPosition(sdl_window,
776 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
778 video.fullscreen_initial = FALSE;
783 void SDLSetScreenRenderingMode(char *screen_rendering_mode)
785 #if defined(TARGET_SDL2)
786 video.screen_rendering_mode =
787 (strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
788 SPECIAL_RENDERING_BITMAP :
789 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
790 SPECIAL_RENDERING_TARGET:
791 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
792 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
794 video.screen_rendering_mode = SPECIAL_RENDERING_BITMAP;
798 void SDLRedrawWindow()
800 UpdateScreen_WithoutFrameDelay(NULL);
803 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
806 SDL_Surface *surface =
807 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
810 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
812 SDLSetNativeSurface(&surface);
814 bitmap->surface = surface;
817 void SDLFreeBitmapPointers(Bitmap *bitmap)
820 SDL_FreeSurface(bitmap->surface);
821 if (bitmap->surface_masked)
822 SDL_FreeSurface(bitmap->surface_masked);
824 bitmap->surface = NULL;
825 bitmap->surface_masked = NULL;
827 #if defined(TARGET_SDL2)
829 SDL_DestroyTexture(bitmap->texture);
830 if (bitmap->texture_masked)
831 SDL_DestroyTexture(bitmap->texture_masked);
833 bitmap->texture = NULL;
834 bitmap->texture_masked = NULL;
838 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
839 int src_x, int src_y, int width, int height,
840 int dst_x, int dst_y, int mask_mode)
842 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
843 SDL_Rect src_rect, dst_rect;
855 // if (src_bitmap != backbuffer || dst_bitmap != window)
856 if (!(src_bitmap == backbuffer && dst_bitmap == window))
857 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
858 src_bitmap->surface_masked : src_bitmap->surface),
859 &src_rect, real_dst_bitmap->surface, &dst_rect);
861 if (dst_bitmap == window)
862 UpdateScreen_WithFrameDelay(&dst_rect);
865 void SDLBlitTexture(Bitmap *bitmap,
866 int src_x, int src_y, int width, int height,
867 int dst_x, int dst_y, int mask_mode)
869 #if defined(TARGET_SDL2)
870 SDL_Texture *texture;
875 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
890 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
894 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
897 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
905 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
907 if (dst_bitmap == window)
908 UpdateScreen_WithFrameDelay(&rect);
911 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
912 int fade_mode, int fade_delay, int post_delay,
913 void (*draw_border_function)(void))
915 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
916 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
917 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
918 SDL_Surface *surface_screen = backbuffer->surface;
919 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
920 SDL_Rect src_rect, dst_rect;
922 int src_x = x, src_y = y;
923 int dst_x = x, dst_y = y;
924 unsigned int time_last, time_current;
926 // store function for drawing global masked border
927 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
929 // deactivate drawing of global border while fading, if needed
930 if (draw_border_function == NULL)
931 gfx.draw_global_border_function = NULL;
940 dst_rect.w = width; /* (ignored) */
941 dst_rect.h = height; /* (ignored) */
943 dst_rect2 = dst_rect;
945 /* copy source and target surfaces to temporary surfaces for fading */
946 if (fade_mode & FADE_TYPE_TRANSFORM)
948 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
949 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
951 draw_global_border_function(DRAW_TO_FADE_SOURCE);
952 draw_global_border_function(DRAW_TO_FADE_TARGET);
954 else if (fade_mode & FADE_TYPE_FADE_IN)
956 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
957 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
959 draw_global_border_function(DRAW_TO_FADE_TARGET);
961 else /* FADE_TYPE_FADE_OUT */
963 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
964 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
966 draw_global_border_function(DRAW_TO_FADE_SOURCE);
969 time_current = SDL_GetTicks();
971 if (fade_mode == FADE_MODE_MELT)
973 boolean done = FALSE;
975 int melt_columns = width / melt_pixels;
976 int ypos[melt_columns];
977 int max_steps = height / 8 + 32;
982 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
983 #if defined(TARGET_SDL2)
984 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
986 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
989 ypos[0] = -GetSimpleRandom(16);
991 for (i = 1 ; i < melt_columns; i++)
993 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
995 ypos[i] = ypos[i - 1] + r;
1008 time_last = time_current;
1009 time_current = SDL_GetTicks();
1010 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1011 steps_final = MIN(MAX(0, steps), max_steps);
1015 done = (steps_done >= steps_final);
1017 for (i = 0 ; i < melt_columns; i++)
1025 else if (ypos[i] < height)
1030 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1032 if (ypos[i] + dy >= height)
1033 dy = height - ypos[i];
1035 /* copy part of (appearing) target surface to upper area */
1036 src_rect.x = src_x + i * melt_pixels;
1037 // src_rect.y = src_y + ypos[i];
1039 src_rect.w = melt_pixels;
1041 src_rect.h = ypos[i] + dy;
1043 dst_rect.x = dst_x + i * melt_pixels;
1044 // dst_rect.y = dst_y + ypos[i];
1047 if (steps_done >= steps_final)
1048 SDL_BlitSurface(surface_target, &src_rect,
1049 surface_screen, &dst_rect);
1053 /* copy part of (disappearing) source surface to lower area */
1054 src_rect.x = src_x + i * melt_pixels;
1056 src_rect.w = melt_pixels;
1057 src_rect.h = height - ypos[i];
1059 dst_rect.x = dst_x + i * melt_pixels;
1060 dst_rect.y = dst_y + ypos[i];
1062 if (steps_done >= steps_final)
1063 SDL_BlitSurface(surface_source, &src_rect,
1064 surface_screen, &dst_rect);
1070 src_rect.x = src_x + i * melt_pixels;
1072 src_rect.w = melt_pixels;
1073 src_rect.h = height;
1075 dst_rect.x = dst_x + i * melt_pixels;
1078 if (steps_done >= steps_final)
1079 SDL_BlitSurface(surface_target, &src_rect,
1080 surface_screen, &dst_rect);
1084 if (steps_done >= steps_final)
1086 if (draw_border_function != NULL)
1087 draw_border_function();
1089 UpdateScreen_WithFrameDelay(&dst_rect2);
1093 else if (fade_mode == FADE_MODE_CURTAIN)
1097 int xx_size = width / 2;
1099 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1100 #if defined(TARGET_SDL2)
1101 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1103 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1106 for (xx = 0; xx < xx_size;)
1108 time_last = time_current;
1109 time_current = SDL_GetTicks();
1110 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1111 xx_final = MIN(MAX(0, xx), xx_size);
1116 src_rect.h = height;
1121 /* draw new (target) image to screen buffer */
1122 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1124 if (xx_final < xx_size)
1126 src_rect.w = xx_size - xx_final;
1127 src_rect.h = height;
1129 /* draw old (source) image to screen buffer (left side) */
1131 src_rect.x = src_x + xx_final;
1134 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1136 /* draw old (source) image to screen buffer (right side) */
1138 src_rect.x = src_x + xx_size;
1139 dst_rect.x = dst_x + xx_size + xx_final;
1141 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1144 if (draw_border_function != NULL)
1145 draw_border_function();
1147 /* only update the region of the screen that is affected from fading */
1148 UpdateScreen_WithFrameDelay(&dst_rect2);
1151 else /* fading in, fading out or cross-fading */
1156 for (alpha = 0.0; alpha < 255.0;)
1158 time_last = time_current;
1159 time_current = SDL_GetTicks();
1160 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1161 alpha_final = MIN(MAX(0, alpha), 255);
1163 /* draw existing (source) image to screen buffer */
1164 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1166 /* draw new (target) image to screen buffer using alpha blending */
1167 #if defined(TARGET_SDL2)
1168 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1169 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1171 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1173 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1175 if (draw_border_function != NULL)
1176 draw_border_function();
1178 /* only update the region of the screen that is affected from fading */
1179 UpdateScreen_WithFrameDelay(&dst_rect);
1185 unsigned int time_post_delay;
1187 time_current = SDL_GetTicks();
1188 time_post_delay = time_current + post_delay;
1190 while (time_current < time_post_delay)
1192 // updating the screen contains waiting for frame delay (non-busy)
1193 UpdateScreen_WithFrameDelay(NULL);
1195 time_current = SDL_GetTicks();
1199 // restore function for drawing global masked border
1200 gfx.draw_global_border_function = draw_global_border_function;
1203 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1204 int to_x, int to_y, Uint32 color)
1206 SDL_Surface *surface = dst_bitmap->surface;
1210 swap_numbers(&from_x, &to_x);
1213 swap_numbers(&from_y, &to_y);
1217 rect.w = (to_x - from_x + 1);
1218 rect.h = (to_y - from_y + 1);
1220 SDL_FillRect(surface, &rect, color);
1223 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1224 int to_x, int to_y, Uint32 color)
1226 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1229 #if ENABLE_UNUSED_CODE
1230 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1231 int num_points, Uint32 color)
1236 for (i = 0; i < num_points - 1; i++)
1238 for (x = 0; x < line_width; x++)
1240 for (y = 0; y < line_width; y++)
1242 int dx = x - line_width / 2;
1243 int dy = y - line_width / 2;
1245 if ((x == 0 && y == 0) ||
1246 (x == 0 && y == line_width - 1) ||
1247 (x == line_width - 1 && y == 0) ||
1248 (x == line_width - 1 && y == line_width - 1))
1251 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1252 points[i+1].x + dx, points[i+1].y + dy, color);
1259 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1261 SDL_Surface *surface = src_bitmap->surface;
1263 switch (surface->format->BytesPerPixel)
1265 case 1: /* assuming 8-bpp */
1267 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1271 case 2: /* probably 15-bpp or 16-bpp */
1273 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1277 case 3: /* slow 24-bpp mode; usually not used */
1279 /* does this work? */
1280 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1284 shift = surface->format->Rshift;
1285 color |= *(pix + shift / 8) >> shift;
1286 shift = surface->format->Gshift;
1287 color |= *(pix + shift / 8) >> shift;
1288 shift = surface->format->Bshift;
1289 color |= *(pix + shift / 8) >> shift;
1295 case 4: /* probably 32-bpp */
1297 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1306 /* ========================================================================= */
1307 /* The following functions were taken from the SGE library */
1308 /* (SDL Graphics Extension Library) by Anders Lindström */
1309 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1310 /* ========================================================================= */
1312 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1314 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1316 switch (surface->format->BytesPerPixel)
1320 /* Assuming 8-bpp */
1321 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1327 /* Probably 15-bpp or 16-bpp */
1328 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1334 /* Slow 24-bpp mode, usually not used */
1338 /* Gack - slow, but endian correct */
1339 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1340 shift = surface->format->Rshift;
1341 *(pix+shift/8) = color>>shift;
1342 shift = surface->format->Gshift;
1343 *(pix+shift/8) = color>>shift;
1344 shift = surface->format->Bshift;
1345 *(pix+shift/8) = color>>shift;
1351 /* Probably 32-bpp */
1352 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1359 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1360 Uint8 R, Uint8 G, Uint8 B)
1362 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1365 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1367 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1370 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1372 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1375 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1380 /* Gack - slow, but endian correct */
1381 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1382 shift = surface->format->Rshift;
1383 *(pix+shift/8) = color>>shift;
1384 shift = surface->format->Gshift;
1385 *(pix+shift/8) = color>>shift;
1386 shift = surface->format->Bshift;
1387 *(pix+shift/8) = color>>shift;
1390 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1392 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1395 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1397 switch (dest->format->BytesPerPixel)
1400 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1404 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1408 _PutPixel24(dest,x,y,color);
1412 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1417 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1419 if (SDL_MUSTLOCK(surface))
1421 if (SDL_LockSurface(surface) < 0)
1427 _PutPixel(surface, x, y, color);
1429 if (SDL_MUSTLOCK(surface))
1431 SDL_UnlockSurface(surface);
1435 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1436 Uint8 r, Uint8 g, Uint8 b)
1438 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1441 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1443 if (y >= 0 && y <= dest->h - 1)
1445 switch (dest->format->BytesPerPixel)
1448 return y*dest->pitch;
1452 return y*dest->pitch/2;
1456 return y*dest->pitch;
1460 return y*dest->pitch/4;
1468 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1470 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1472 switch (surface->format->BytesPerPixel)
1476 /* Assuming 8-bpp */
1477 *((Uint8 *)surface->pixels + ypitch + x) = color;
1483 /* Probably 15-bpp or 16-bpp */
1484 *((Uint16 *)surface->pixels + ypitch + x) = color;
1490 /* Slow 24-bpp mode, usually not used */
1494 /* Gack - slow, but endian correct */
1495 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1496 shift = surface->format->Rshift;
1497 *(pix+shift/8) = color>>shift;
1498 shift = surface->format->Gshift;
1499 *(pix+shift/8) = color>>shift;
1500 shift = surface->format->Bshift;
1501 *(pix+shift/8) = color>>shift;
1507 /* Probably 32-bpp */
1508 *((Uint32 *)surface->pixels + ypitch + x) = color;
1515 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1520 if (SDL_MUSTLOCK(Surface))
1522 if (SDL_LockSurface(Surface) < 0)
1535 /* Do the clipping */
1536 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1540 if (x2 > Surface->w - 1)
1541 x2 = Surface->w - 1;
1548 SDL_FillRect(Surface, &l, Color);
1550 if (SDL_MUSTLOCK(Surface))
1552 SDL_UnlockSurface(Surface);
1556 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1557 Uint8 R, Uint8 G, Uint8 B)
1559 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1562 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1573 /* Do the clipping */
1574 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1578 if (x2 > Surface->w - 1)
1579 x2 = Surface->w - 1;
1586 SDL_FillRect(Surface, &l, Color);
1589 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1594 if (SDL_MUSTLOCK(Surface))
1596 if (SDL_LockSurface(Surface) < 0)
1609 /* Do the clipping */
1610 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1614 if (y2 > Surface->h - 1)
1615 y2 = Surface->h - 1;
1622 SDL_FillRect(Surface, &l, Color);
1624 if (SDL_MUSTLOCK(Surface))
1626 SDL_UnlockSurface(Surface);
1630 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1631 Uint8 R, Uint8 G, Uint8 B)
1633 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1636 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1647 /* Do the clipping */
1648 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1652 if (y2 > Surface->h - 1)
1653 y2 = Surface->h - 1;
1660 SDL_FillRect(Surface, &l, Color);
1663 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1664 Sint16 x2, Sint16 y2, Uint32 Color,
1665 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1668 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1673 sdx = (dx < 0) ? -1 : 1;
1674 sdy = (dy < 0) ? -1 : 1;
1686 for (x = 0; x < dx; x++)
1688 Callback(Surface, px, py, Color);
1702 for (y = 0; y < dy; y++)
1704 Callback(Surface, px, py, Color);
1718 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1719 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1720 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1723 sge_DoLine(Surface, X1, Y1, X2, Y2,
1724 SDL_MapRGB(Surface->format, R, G, B), Callback);
1727 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1730 if (SDL_MUSTLOCK(Surface))
1732 if (SDL_LockSurface(Surface) < 0)
1737 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1739 /* unlock the display */
1740 if (SDL_MUSTLOCK(Surface))
1742 SDL_UnlockSurface(Surface);
1746 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1747 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1749 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1752 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1754 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1759 -----------------------------------------------------------------------------
1760 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1761 -----------------------------------------------------------------------------
1764 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1765 int width, int height, Uint32 color)
1769 for (y = src_y; y < src_y + height; y++)
1771 for (x = src_x; x < src_x + width; x++)
1773 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1775 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1780 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1781 int src_x, int src_y, int width, int height,
1782 int dst_x, int dst_y)
1786 for (y = 0; y < height; y++)
1788 for (x = 0; x < width; x++)
1790 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1792 if (pixel != BLACK_PIXEL)
1793 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1799 /* ========================================================================= */
1800 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1801 /* (Rotozoomer) by Andreas Schiffler */
1802 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1803 /* ========================================================================= */
1806 -----------------------------------------------------------------------------
1809 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1810 -----------------------------------------------------------------------------
1821 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1824 tColorRGBA *sp, *csp, *dp;
1828 sp = csp = (tColorRGBA *) src->pixels;
1829 dp = (tColorRGBA *) dst->pixels;
1830 dgap = dst->pitch - dst->w * 4;
1832 for (y = 0; y < dst->h; y++)
1836 for (x = 0; x < dst->w; x++)
1838 tColorRGBA *sp0 = sp;
1839 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1840 tColorRGBA *sp00 = &sp0[0];
1841 tColorRGBA *sp01 = &sp0[1];
1842 tColorRGBA *sp10 = &sp1[0];
1843 tColorRGBA *sp11 = &sp1[1];
1846 /* create new color pixel from all four source color pixels */
1847 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1848 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1849 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1850 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1855 /* advance source pointers */
1858 /* advance destination pointer */
1862 /* advance source pointer */
1863 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1865 /* advance destination pointers */
1866 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1872 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1874 int x, y, *sax, *say, *csax, *csay;
1876 tColorRGBA *sp, *csp, *csp0, *dp;
1879 /* use specialized zoom function when scaling down to exactly half size */
1880 if (src->w == 2 * dst->w &&
1881 src->h == 2 * dst->h)
1882 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1884 /* variable setup */
1885 sx = (float) src->w / (float) dst->w;
1886 sy = (float) src->h / (float) dst->h;
1888 /* allocate memory for row increments */
1889 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1890 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1892 /* precalculate row increments */
1893 for (x = 0; x <= dst->w; x++)
1894 *csax++ = (int)(sx * x);
1896 for (y = 0; y <= dst->h; y++)
1897 *csay++ = (int)(sy * y);
1900 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1901 dp = (tColorRGBA *) dst->pixels;
1902 dgap = dst->pitch - dst->w * 4;
1905 for (y = 0; y < dst->h; y++)
1910 for (x = 0; x < dst->w; x++)
1915 /* advance source pointers */
1919 /* advance destination pointer */
1923 /* advance source pointer */
1925 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1927 /* advance destination pointers */
1928 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1938 -----------------------------------------------------------------------------
1941 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1942 -----------------------------------------------------------------------------
1945 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1947 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1948 Uint8 *sp, *dp, *csp;
1951 /* variable setup */
1952 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1953 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1955 /* allocate memory for row increments */
1956 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1957 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1959 /* precalculate row increments */
1962 for (x = 0; x < dst->w; x++)
1965 *csax = (csx >> 16);
1972 for (y = 0; y < dst->h; y++)
1975 *csay = (csy >> 16);
1982 for (x = 0; x < dst->w; x++)
1990 for (y = 0; y < dst->h; y++)
1997 sp = csp = (Uint8 *) src->pixels;
1998 dp = (Uint8 *) dst->pixels;
1999 dgap = dst->pitch - dst->w;
2003 for (y = 0; y < dst->h; y++)
2007 for (x = 0; x < dst->w; x++)
2012 /* advance source pointers */
2016 /* advance destination pointer */
2020 /* advance source pointer (for row) */
2021 csp += ((*csay) * src->pitch);
2024 /* advance destination pointers */
2035 -----------------------------------------------------------------------------
2038 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2039 'zoomx' and 'zoomy' are scaling factors for width and height.
2040 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2041 into a 32bit RGBA format on the fly.
2042 -----------------------------------------------------------------------------
2045 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2047 SDL_Surface *zoom_src = NULL;
2048 SDL_Surface *zoom_dst = NULL;
2049 boolean is_converted = FALSE;
2056 /* determine if source surface is 32 bit or 8 bit */
2057 is_32bit = (src->format->BitsPerPixel == 32);
2059 if (is_32bit || src->format->BitsPerPixel == 8)
2061 /* use source surface 'as is' */
2066 /* new source surface is 32 bit with a defined RGB ordering */
2067 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2068 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2069 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2071 is_converted = TRUE;
2074 /* allocate surface to completely contain the zoomed surface */
2077 /* target surface is 32 bit with source RGBA/ABGR ordering */
2078 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2079 zoom_src->format->Rmask,
2080 zoom_src->format->Gmask,
2081 zoom_src->format->Bmask, 0);
2085 /* target surface is 8 bit */
2086 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2090 /* lock source surface */
2091 SDL_LockSurface(zoom_src);
2093 /* check which kind of surface we have */
2096 /* call the 32 bit transformation routine to do the zooming */
2097 zoomSurfaceRGBA(zoom_src, zoom_dst);
2102 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2103 zoom_dst->format->palette->colors[i] =
2104 zoom_src->format->palette->colors[i];
2105 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2107 /* call the 8 bit transformation routine to do the zooming */
2108 zoomSurfaceY(zoom_src, zoom_dst);
2111 /* unlock source surface */
2112 SDL_UnlockSurface(zoom_src);
2114 /* free temporary surface */
2116 SDL_FreeSurface(zoom_src);
2118 /* return destination surface */
2122 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2124 Bitmap *dst_bitmap = CreateBitmapStruct();
2125 SDL_Surface **dst_surface = &dst_bitmap->surface;
2127 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2128 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2130 dst_bitmap->width = dst_width;
2131 dst_bitmap->height = dst_height;
2133 /* create zoomed temporary surface from source surface */
2134 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2136 /* create native format destination surface from zoomed temporary surface */
2137 SDLSetNativeSurface(dst_surface);
2143 /* ========================================================================= */
2144 /* load image to bitmap */
2145 /* ========================================================================= */
2147 Bitmap *SDLLoadImage(char *filename)
2149 Bitmap *new_bitmap = CreateBitmapStruct();
2150 SDL_Surface *sdl_image_tmp;
2152 print_timestamp_init("SDLLoadImage");
2154 print_timestamp_time(getBaseNamePtr(filename));
2156 /* load image to temporary surface */
2157 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2159 SetError("IMG_Load(): %s", SDL_GetError());
2164 print_timestamp_time("IMG_Load");
2166 UPDATE_BUSY_STATE();
2168 /* create native non-transparent surface for current image */
2169 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2171 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2176 print_timestamp_time("SDL_DisplayFormat (opaque)");
2178 UPDATE_BUSY_STATE();
2180 /* create native transparent surface for current image */
2181 if (sdl_image_tmp->format->Amask == 0)
2182 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2183 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2185 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2187 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2192 print_timestamp_time("SDL_DisplayFormat (masked)");
2194 UPDATE_BUSY_STATE();
2196 /* free temporary surface */
2197 SDL_FreeSurface(sdl_image_tmp);
2199 new_bitmap->width = new_bitmap->surface->w;
2200 new_bitmap->height = new_bitmap->surface->h;
2202 print_timestamp_done("SDLLoadImage");
2208 /* ------------------------------------------------------------------------- */
2209 /* custom cursor fuctions */
2210 /* ------------------------------------------------------------------------- */
2212 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2214 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2215 cursor_info->width, cursor_info->height,
2216 cursor_info->hot_x, cursor_info->hot_y);
2219 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2221 static struct MouseCursorInfo *last_cursor_info = NULL;
2222 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2223 static SDL_Cursor *cursor_default = NULL;
2224 static SDL_Cursor *cursor_current = NULL;
2226 /* if invoked for the first time, store the SDL default cursor */
2227 if (cursor_default == NULL)
2228 cursor_default = SDL_GetCursor();
2230 /* only create new cursor if cursor info (custom only) has changed */
2231 if (cursor_info != NULL && cursor_info != last_cursor_info)
2233 cursor_current = create_cursor(cursor_info);
2234 last_cursor_info = cursor_info;
2237 /* only set new cursor if cursor info (custom or NULL) has changed */
2238 if (cursor_info != last_cursor_info2)
2239 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2241 last_cursor_info2 = cursor_info;
2245 /* ========================================================================= */
2246 /* audio functions */
2247 /* ========================================================================= */
2249 void SDLOpenAudio(void)
2251 #if !defined(TARGET_SDL2)
2252 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2253 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2256 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2258 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2262 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2263 AUDIO_NUM_CHANNELS_STEREO,
2264 setup.system.audio_fragment_size) < 0)
2266 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2270 audio.sound_available = TRUE;
2271 audio.music_available = TRUE;
2272 audio.loops_available = TRUE;
2273 audio.sound_enabled = TRUE;
2275 /* set number of available mixer channels */
2276 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2277 audio.music_channel = MUSIC_CHANNEL;
2278 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2280 Mixer_InitChannels();
2283 void SDLCloseAudio(void)
2286 Mix_HaltChannel(-1);
2289 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2293 /* ========================================================================= */
2294 /* event functions */
2295 /* ========================================================================= */
2297 void SDLNextEvent(Event *event)
2299 SDL_WaitEvent(event);
2302 void SDLHandleWindowManagerEvent(Event *event)
2305 #if defined(PLATFORM_WIN32)
2306 // experimental drag and drop code
2308 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2309 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2311 #if defined(TARGET_SDL2)
2312 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2314 if (syswmmsg->msg == WM_DROPFILES)
2317 #if defined(TARGET_SDL2)
2318 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2320 HDROP hdrop = (HDROP)syswmmsg->wParam;
2324 printf("::: SDL_SYSWMEVENT:\n");
2326 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2328 for (i = 0; i < num_files; i++)
2330 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2331 char buffer[buffer_len + 1];
2333 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2335 printf("::: - '%s'\n", buffer);
2338 #if defined(TARGET_SDL2)
2339 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2341 DragFinish((HDROP)syswmmsg->wParam);
2349 /* ========================================================================= */
2350 /* joystick functions */
2351 /* ========================================================================= */
2353 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2354 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2355 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2357 static boolean SDLOpenJoystick(int nr)
2359 if (nr < 0 || nr > MAX_PLAYERS)
2362 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2365 static void SDLCloseJoystick(int nr)
2367 if (nr < 0 || nr > MAX_PLAYERS)
2370 SDL_JoystickClose(sdl_joystick[nr]);
2372 sdl_joystick[nr] = NULL;
2375 static boolean SDLCheckJoystickOpened(int nr)
2377 if (nr < 0 || nr > MAX_PLAYERS)
2380 #if defined(TARGET_SDL2)
2381 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2383 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2387 void HandleJoystickEvent(Event *event)
2391 case SDL_JOYAXISMOTION:
2392 if (event->jaxis.axis < 2)
2393 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2396 case SDL_JOYBUTTONDOWN:
2397 if (event->jbutton.button < 2)
2398 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2401 case SDL_JOYBUTTONUP:
2402 if (event->jbutton.button < 2)
2403 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2411 void SDLInitJoysticks()
2413 static boolean sdl_joystick_subsystem_initialized = FALSE;
2414 boolean print_warning = !sdl_joystick_subsystem_initialized;
2417 if (!sdl_joystick_subsystem_initialized)
2419 sdl_joystick_subsystem_initialized = TRUE;
2421 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2423 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2428 for (i = 0; i < MAX_PLAYERS; i++)
2430 /* get configured joystick for this player */
2431 char *device_name = setup.input[i].joy.device_name;
2432 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2434 if (joystick_nr >= SDL_NumJoysticks())
2436 if (setup.input[i].use_joystick && print_warning)
2437 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2442 /* misuse joystick file descriptor variable to store joystick number */
2443 joystick.fd[i] = joystick_nr;
2445 if (joystick_nr == -1)
2448 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2449 if (SDLCheckJoystickOpened(joystick_nr))
2450 SDLCloseJoystick(joystick_nr);
2452 if (!setup.input[i].use_joystick)
2455 if (!SDLOpenJoystick(joystick_nr))
2458 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2463 joystick.status = JOYSTICK_ACTIVATED;
2467 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2469 if (nr < 0 || nr >= MAX_PLAYERS)
2473 *x = sdl_js_axis[nr][0];
2475 *y = sdl_js_axis[nr][1];
2478 *b1 = sdl_js_button[nr][0];
2480 *b2 = sdl_js_button[nr][1];