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(int draw_target)
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_target, 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_target);
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_target, 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);
98 FinalizeScreen(DRAW_TO_SCREEN);
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)
145 FinalizeScreen(DRAW_TO_SCREEN);
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);
229 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
231 SDL_PixelFormat format;
232 SDL_Surface *new_surface;
237 if (backbuffer && backbuffer->surface)
239 format = *backbuffer->surface->format;
240 format.Amask = surface->format->Amask; // keep alpha channel
244 format = *surface->format;
247 new_surface = SDL_ConvertSurface(surface, &format, 0);
249 if (new_surface == NULL)
250 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
255 boolean SDLSetNativeSurface(SDL_Surface **surface)
257 SDL_Surface *new_surface;
259 if (surface == NULL ||
261 backbuffer == NULL ||
262 backbuffer->surface == NULL)
265 // if pixel format already optimized for destination surface, do nothing
266 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
269 new_surface = SDLGetNativeSurface(*surface);
271 SDL_FreeSurface(*surface);
273 *surface = new_surface;
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 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
393 #if defined(TARGET_SDL2)
394 // SDL 2.0: support for (desktop) fullscreen mode available
395 video.fullscreen_available = TRUE;
397 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
398 video.fullscreen_available = FALSE;
401 /* open SDL video output device (window or fullscreen mode) */
402 if (!SDLSetVideoMode(fullscreen))
403 Error(ERR_EXIT, "setting video mode failed");
405 /* !!! SDL2 can only set the window icon if the window already exists !!! */
406 /* set window icon */
407 SDLSetWindowIcon(program.icon_filename);
409 /* set window and icon title */
410 #if defined(TARGET_SDL2)
411 SDL_SetWindowTitle(sdl_window, program.window_title);
413 SDL_WM_SetCaption(program.window_title, program.window_title);
416 /* SDL cannot directly draw to the visible video framebuffer like X11,
417 but always uses a backbuffer, which is then blitted to the visible
418 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
419 visible video framebuffer with 'SDL_Flip', if the hardware supports
420 this). Therefore do not use an additional backbuffer for drawing, but
421 use a symbolic buffer (distinguishable from the SDL backbuffer) called
422 'window', which indicates that the SDL backbuffer should be updated to
423 the visible video framebuffer when attempting to blit to it.
425 For convenience, it seems to be a good idea to create this symbolic
426 buffer 'window' at the same size as the SDL backbuffer. Although it
427 should never be drawn to directly, it would do no harm nevertheless. */
429 /* create additional (symbolic) buffer for double-buffering */
430 ReCreateBitmap(&window, video.width, video.height);
433 static boolean SDLCreateScreen(boolean fullscreen)
435 SDL_Surface *new_surface = NULL;
437 #if defined(TARGET_SDL2)
438 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
439 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
441 int surface_flags_window = SURFACE_FLAGS;
442 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
445 #if defined(TARGET_SDL2)
447 int renderer_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
449 /* If SDL_CreateRenderer() is called from within a VirtualBox Windows VM
450 _without_ enabling 2D/3D acceleration and/or guest additions installed,
451 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
452 it will try to use accelerated graphics and apparently fails miserably) */
453 int renderer_flags = SDL_RENDERER_SOFTWARE;
457 int width = video.width;
458 int height = video.height;
459 int surface_flags = (fullscreen ? surface_flags_fullscreen :
460 surface_flags_window);
462 // default window size is unscaled
463 video.window_width = video.width;
464 video.window_height = video.height;
466 #if defined(TARGET_SDL2)
468 // store if initial screen mode is fullscreen mode when changing screen size
469 video.fullscreen_initial = fullscreen;
471 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
473 video.window_width = window_scaling_factor * width;
474 video.window_height = window_scaling_factor * height;
476 if (sdl_texture_stream)
478 SDL_DestroyTexture(sdl_texture_stream);
479 sdl_texture_stream = NULL;
482 if (sdl_texture_target)
484 SDL_DestroyTexture(sdl_texture_target);
485 sdl_texture_target = NULL;
488 if (!(fullscreen && fullscreen_enabled))
492 SDL_DestroyRenderer(sdl_renderer);
498 SDL_DestroyWindow(sdl_window);
503 if (sdl_window == NULL)
504 sdl_window = SDL_CreateWindow(program.window_title,
505 SDL_WINDOWPOS_CENTERED,
506 SDL_WINDOWPOS_CENTERED,
511 if (sdl_window != NULL)
513 if (sdl_renderer == NULL)
514 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, renderer_flags);
516 if (sdl_renderer != NULL)
518 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
519 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
520 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
522 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
523 SDL_PIXELFORMAT_ARGB8888,
524 SDL_TEXTUREACCESS_STREAMING,
527 if (SDL_RenderTargetSupported(sdl_renderer))
528 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
529 SDL_PIXELFORMAT_ARGB8888,
530 SDL_TEXTUREACCESS_TARGET,
533 if (sdl_texture_stream != NULL)
535 // use SDL default values for RGB masks and no alpha channel
536 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
538 if (new_surface == NULL)
539 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
543 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
548 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
553 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
558 if (gfx.final_screen_bitmap == NULL)
559 gfx.final_screen_bitmap = CreateBitmapStruct();
561 gfx.final_screen_bitmap->width = width;
562 gfx.final_screen_bitmap->height = height;
564 gfx.final_screen_bitmap->surface =
565 SDL_SetVideoMode(width, height, video.depth, surface_flags);
567 if (gfx.final_screen_bitmap->surface != NULL)
570 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
572 if (new_surface == NULL)
573 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
576 new_surface = gfx.final_screen_bitmap->surface;
577 gfx.final_screen_bitmap = NULL;
583 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
587 #if defined(TARGET_SDL2)
588 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
589 if (new_surface != NULL)
590 fullscreen_enabled = fullscreen;
593 if (backbuffer == NULL)
594 backbuffer = CreateBitmapStruct();
596 backbuffer->width = video.width;
597 backbuffer->height = video.height;
599 if (backbuffer->surface)
600 SDL_FreeSurface(backbuffer->surface);
602 backbuffer->surface = new_surface;
604 return (new_surface != NULL);
607 boolean SDLSetVideoMode(boolean fullscreen)
609 boolean success = FALSE;
613 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
615 /* switch display to fullscreen mode, if available */
616 success = SDLCreateScreen(TRUE);
620 /* switching display to fullscreen mode failed -- do not try it again */
621 video.fullscreen_available = FALSE;
625 video.fullscreen_enabled = TRUE;
629 if ((!fullscreen && video.fullscreen_enabled) || !success)
631 /* switch display to window mode */
632 success = SDLCreateScreen(FALSE);
636 /* switching display to window mode failed -- should not happen */
640 video.fullscreen_enabled = FALSE;
641 video.window_scaling_percent = setup.window_scaling_percent;
642 video.window_scaling_quality = setup.window_scaling_quality;
644 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
648 #if defined(TARGET_SDL2)
649 SDLRedrawWindow(); // map window
653 #if defined(PLATFORM_WIN32)
654 // experimental drag and drop code
656 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
659 SDL_SysWMinfo wminfo;
661 boolean wminfo_success = FALSE;
663 SDL_VERSION(&wminfo.version);
664 #if defined(TARGET_SDL2)
666 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
668 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
673 #if defined(TARGET_SDL2)
674 hwnd = wminfo.info.win.window;
676 hwnd = wminfo.window;
679 DragAcceptFiles(hwnd, TRUE);
688 void SDLSetWindowTitle()
690 #if defined(TARGET_SDL2)
691 SDL_SetWindowTitle(sdl_window, program.window_title);
693 SDL_WM_SetCaption(program.window_title, program.window_title);
697 #if defined(TARGET_SDL2)
698 void SDLSetWindowScaling(int window_scaling_percent)
700 if (sdl_window == NULL)
703 float window_scaling_factor = (float)window_scaling_percent / 100;
704 int new_window_width = (int)(window_scaling_factor * video.width);
705 int new_window_height = (int)(window_scaling_factor * video.height);
707 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
709 video.window_scaling_percent = window_scaling_percent;
710 video.window_width = new_window_width;
711 video.window_height = new_window_height;
716 void SDLSetWindowScalingQuality(char *window_scaling_quality)
718 SDL_Texture *new_texture;
720 if (sdl_texture_stream == NULL)
723 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
725 new_texture = SDL_CreateTexture(sdl_renderer,
726 SDL_PIXELFORMAT_ARGB8888,
727 SDL_TEXTUREACCESS_STREAMING,
728 video.width, video.height);
730 if (new_texture != NULL)
732 SDL_DestroyTexture(sdl_texture_stream);
734 sdl_texture_stream = new_texture;
737 if (SDL_RenderTargetSupported(sdl_renderer))
738 new_texture = SDL_CreateTexture(sdl_renderer,
739 SDL_PIXELFORMAT_ARGB8888,
740 SDL_TEXTUREACCESS_TARGET,
741 video.width, video.height);
745 if (new_texture != NULL)
747 SDL_DestroyTexture(sdl_texture_target);
749 sdl_texture_target = new_texture;
754 video.window_scaling_quality = window_scaling_quality;
757 void SDLSetWindowFullscreen(boolean fullscreen)
759 if (sdl_window == NULL)
762 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
764 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
765 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
767 // if screen size was changed in fullscreen mode, correct desktop window size
768 if (!fullscreen && video.fullscreen_initial)
770 SDLSetWindowScaling(setup.window_scaling_percent);
771 SDL_SetWindowPosition(sdl_window,
772 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
774 video.fullscreen_initial = FALSE;
779 void SDLSetScreenRenderingMode(char *screen_rendering_mode)
781 #if defined(TARGET_SDL2)
782 video.screen_rendering_mode =
783 (strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
784 SPECIAL_RENDERING_BITMAP :
785 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
786 SPECIAL_RENDERING_TARGET:
787 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
788 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
790 video.screen_rendering_mode = SPECIAL_RENDERING_BITMAP;
794 void SDLRedrawWindow()
796 UpdateScreen_WithoutFrameDelay(NULL);
799 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
802 SDL_Surface *surface =
803 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
806 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
808 SDLSetNativeSurface(&surface);
810 bitmap->surface = surface;
813 void SDLFreeBitmapPointers(Bitmap *bitmap)
816 SDL_FreeSurface(bitmap->surface);
817 if (bitmap->surface_masked)
818 SDL_FreeSurface(bitmap->surface_masked);
820 bitmap->surface = NULL;
821 bitmap->surface_masked = NULL;
823 #if defined(TARGET_SDL2)
825 SDL_DestroyTexture(bitmap->texture);
826 if (bitmap->texture_masked)
827 SDL_DestroyTexture(bitmap->texture_masked);
829 bitmap->texture = NULL;
830 bitmap->texture_masked = NULL;
834 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
835 int src_x, int src_y, int width, int height,
836 int dst_x, int dst_y, int mask_mode)
838 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
839 SDL_Rect src_rect, dst_rect;
851 // if (src_bitmap != backbuffer || dst_bitmap != window)
852 if (!(src_bitmap == backbuffer && dst_bitmap == window))
853 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
854 src_bitmap->surface_masked : src_bitmap->surface),
855 &src_rect, real_dst_bitmap->surface, &dst_rect);
857 if (dst_bitmap == window)
858 UpdateScreen_WithFrameDelay(&dst_rect);
861 void SDLBlitTexture(Bitmap *bitmap,
862 int src_x, int src_y, int width, int height,
863 int dst_x, int dst_y, int mask_mode)
865 #if defined(TARGET_SDL2)
866 SDL_Texture *texture;
871 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
886 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
890 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
893 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
901 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
903 if (dst_bitmap == window)
904 UpdateScreen_WithFrameDelay(&rect);
907 void PrepareFadeBitmap(int draw_target)
909 Bitmap *fade_bitmap =
910 (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
911 draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
913 if (fade_bitmap == NULL)
916 // copy backbuffer to fading buffer
917 BlitBitmap(backbuffer, fade_bitmap, 0, 0, gfx.win_xsize, gfx.win_ysize, 0, 0);
919 // add border and animations to fading buffer
920 FinalizeScreen(draw_target);
923 void SDLFadeRectangle(int x, int y, int width, int height,
924 int fade_mode, int fade_delay, int post_delay,
925 void (*draw_border_function)(void))
927 SDL_Surface *surface_backup = gfx.fade_bitmap_backup->surface;
928 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
929 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
930 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
931 SDL_Surface *surface_screen = backbuffer->surface;
932 SDL_Rect src_rect, dst_rect;
934 int src_x = x, src_y = y;
935 int dst_x = x, dst_y = y;
936 unsigned int time_last, time_current;
938 // store function for drawing global masked border
939 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
941 // deactivate drawing of global border while fading, if needed
942 if (draw_border_function == NULL)
943 gfx.draw_global_border_function = NULL;
952 dst_rect.w = width; /* (ignored) */
953 dst_rect.h = height; /* (ignored) */
955 dst_rect2 = dst_rect;
957 // before fading in, store backbuffer (without animation graphics)
958 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
959 SDL_BlitSurface(surface_screen, &dst_rect, surface_backup, &src_rect);
961 /* copy source and target surfaces to temporary surfaces for fading */
962 if (fade_mode & FADE_TYPE_TRANSFORM)
964 // (source and target fading buffer already prepared)
966 else if (fade_mode & FADE_TYPE_FADE_IN)
968 // (target fading buffer already prepared)
969 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
971 else /* FADE_TYPE_FADE_OUT */
973 // (source fading buffer already prepared)
974 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
977 time_current = SDL_GetTicks();
979 if (fade_mode == FADE_MODE_MELT)
981 boolean done = FALSE;
983 int melt_columns = width / melt_pixels;
984 int ypos[melt_columns];
985 int max_steps = height / 8 + 32;
990 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
991 #if defined(TARGET_SDL2)
992 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
994 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
997 ypos[0] = -GetSimpleRandom(16);
999 for (i = 1 ; i < melt_columns; i++)
1001 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1003 ypos[i] = ypos[i - 1] + r;
1016 time_last = time_current;
1017 time_current = SDL_GetTicks();
1018 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1019 steps_final = MIN(MAX(0, steps), max_steps);
1023 done = (steps_done >= steps_final);
1025 for (i = 0 ; i < melt_columns; i++)
1033 else if (ypos[i] < height)
1038 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1040 if (ypos[i] + dy >= height)
1041 dy = height - ypos[i];
1043 /* copy part of (appearing) target surface to upper area */
1044 src_rect.x = src_x + i * melt_pixels;
1045 // src_rect.y = src_y + ypos[i];
1047 src_rect.w = melt_pixels;
1049 src_rect.h = ypos[i] + dy;
1051 dst_rect.x = dst_x + i * melt_pixels;
1052 // dst_rect.y = dst_y + ypos[i];
1055 if (steps_done >= steps_final)
1056 SDL_BlitSurface(surface_target, &src_rect,
1057 surface_screen, &dst_rect);
1061 /* copy part of (disappearing) source surface to lower area */
1062 src_rect.x = src_x + i * melt_pixels;
1064 src_rect.w = melt_pixels;
1065 src_rect.h = height - ypos[i];
1067 dst_rect.x = dst_x + i * melt_pixels;
1068 dst_rect.y = dst_y + ypos[i];
1070 if (steps_done >= steps_final)
1071 SDL_BlitSurface(surface_source, &src_rect,
1072 surface_screen, &dst_rect);
1078 src_rect.x = src_x + i * melt_pixels;
1080 src_rect.w = melt_pixels;
1081 src_rect.h = height;
1083 dst_rect.x = dst_x + i * melt_pixels;
1086 if (steps_done >= steps_final)
1087 SDL_BlitSurface(surface_target, &src_rect,
1088 surface_screen, &dst_rect);
1092 if (steps_done >= steps_final)
1094 if (draw_border_function != NULL)
1095 draw_border_function();
1097 UpdateScreen_WithFrameDelay(&dst_rect2);
1101 else if (fade_mode == FADE_MODE_CURTAIN)
1105 int xx_size = width / 2;
1107 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1108 #if defined(TARGET_SDL2)
1109 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1111 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1114 for (xx = 0; xx < xx_size;)
1116 time_last = time_current;
1117 time_current = SDL_GetTicks();
1118 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1119 xx_final = MIN(MAX(0, xx), xx_size);
1124 src_rect.h = height;
1129 /* draw new (target) image to screen buffer */
1130 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1132 if (xx_final < xx_size)
1134 src_rect.w = xx_size - xx_final;
1135 src_rect.h = height;
1137 /* draw old (source) image to screen buffer (left side) */
1139 src_rect.x = src_x + xx_final;
1142 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1144 /* draw old (source) image to screen buffer (right side) */
1146 src_rect.x = src_x + xx_size;
1147 dst_rect.x = dst_x + xx_size + xx_final;
1149 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1152 if (draw_border_function != NULL)
1153 draw_border_function();
1155 /* only update the region of the screen that is affected from fading */
1156 UpdateScreen_WithFrameDelay(&dst_rect2);
1159 else /* fading in, fading out or cross-fading */
1164 for (alpha = 0.0; alpha < 255.0;)
1166 time_last = time_current;
1167 time_current = SDL_GetTicks();
1168 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1169 alpha_final = MIN(MAX(0, alpha), 255);
1171 /* draw existing (source) image to screen buffer */
1172 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1174 /* draw new (target) image to screen buffer using alpha blending */
1175 #if defined(TARGET_SDL2)
1176 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1177 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1179 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1181 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1183 if (draw_border_function != NULL)
1184 draw_border_function();
1186 /* only update the region of the screen that is affected from fading */
1187 UpdateScreen_WithFrameDelay(&dst_rect);
1193 unsigned int time_post_delay;
1195 time_current = SDL_GetTicks();
1196 time_post_delay = time_current + post_delay;
1198 while (time_current < time_post_delay)
1200 // updating the screen contains waiting for frame delay (non-busy)
1201 UpdateScreen_WithFrameDelay(NULL);
1203 time_current = SDL_GetTicks();
1207 // restore function for drawing global masked border
1208 gfx.draw_global_border_function = draw_global_border_function;
1210 // after fading in, restore backbuffer (without animation graphics)
1211 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
1212 SDL_BlitSurface(surface_backup, &dst_rect, surface_screen, &src_rect);
1215 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1216 int to_x, int to_y, Uint32 color)
1218 SDL_Surface *surface = dst_bitmap->surface;
1222 swap_numbers(&from_x, &to_x);
1225 swap_numbers(&from_y, &to_y);
1229 rect.w = (to_x - from_x + 1);
1230 rect.h = (to_y - from_y + 1);
1232 SDL_FillRect(surface, &rect, color);
1235 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1236 int to_x, int to_y, Uint32 color)
1238 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1241 #if ENABLE_UNUSED_CODE
1242 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1243 int num_points, Uint32 color)
1248 for (i = 0; i < num_points - 1; i++)
1250 for (x = 0; x < line_width; x++)
1252 for (y = 0; y < line_width; y++)
1254 int dx = x - line_width / 2;
1255 int dy = y - line_width / 2;
1257 if ((x == 0 && y == 0) ||
1258 (x == 0 && y == line_width - 1) ||
1259 (x == line_width - 1 && y == 0) ||
1260 (x == line_width - 1 && y == line_width - 1))
1263 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1264 points[i+1].x + dx, points[i+1].y + dy, color);
1271 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1273 SDL_Surface *surface = src_bitmap->surface;
1275 switch (surface->format->BytesPerPixel)
1277 case 1: /* assuming 8-bpp */
1279 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1283 case 2: /* probably 15-bpp or 16-bpp */
1285 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1289 case 3: /* slow 24-bpp mode; usually not used */
1291 /* does this work? */
1292 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1296 shift = surface->format->Rshift;
1297 color |= *(pix + shift / 8) >> shift;
1298 shift = surface->format->Gshift;
1299 color |= *(pix + shift / 8) >> shift;
1300 shift = surface->format->Bshift;
1301 color |= *(pix + shift / 8) >> shift;
1307 case 4: /* probably 32-bpp */
1309 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1318 /* ========================================================================= */
1319 /* The following functions were taken from the SGE library */
1320 /* (SDL Graphics Extension Library) by Anders Lindström */
1321 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1322 /* ========================================================================= */
1324 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1326 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1328 switch (surface->format->BytesPerPixel)
1332 /* Assuming 8-bpp */
1333 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1339 /* Probably 15-bpp or 16-bpp */
1340 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1346 /* Slow 24-bpp mode, usually not used */
1350 /* Gack - slow, but endian correct */
1351 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1352 shift = surface->format->Rshift;
1353 *(pix+shift/8) = color>>shift;
1354 shift = surface->format->Gshift;
1355 *(pix+shift/8) = color>>shift;
1356 shift = surface->format->Bshift;
1357 *(pix+shift/8) = color>>shift;
1363 /* Probably 32-bpp */
1364 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1371 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1372 Uint8 R, Uint8 G, Uint8 B)
1374 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1377 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1379 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1382 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1384 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1387 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1392 /* Gack - slow, but endian correct */
1393 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1394 shift = surface->format->Rshift;
1395 *(pix+shift/8) = color>>shift;
1396 shift = surface->format->Gshift;
1397 *(pix+shift/8) = color>>shift;
1398 shift = surface->format->Bshift;
1399 *(pix+shift/8) = color>>shift;
1402 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1404 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1407 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1409 switch (dest->format->BytesPerPixel)
1412 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1416 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1420 _PutPixel24(dest,x,y,color);
1424 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1429 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1431 if (SDL_MUSTLOCK(surface))
1433 if (SDL_LockSurface(surface) < 0)
1439 _PutPixel(surface, x, y, color);
1441 if (SDL_MUSTLOCK(surface))
1443 SDL_UnlockSurface(surface);
1447 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1448 Uint8 r, Uint8 g, Uint8 b)
1450 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1453 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1455 if (y >= 0 && y <= dest->h - 1)
1457 switch (dest->format->BytesPerPixel)
1460 return y*dest->pitch;
1464 return y*dest->pitch/2;
1468 return y*dest->pitch;
1472 return y*dest->pitch/4;
1480 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1482 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1484 switch (surface->format->BytesPerPixel)
1488 /* Assuming 8-bpp */
1489 *((Uint8 *)surface->pixels + ypitch + x) = color;
1495 /* Probably 15-bpp or 16-bpp */
1496 *((Uint16 *)surface->pixels + ypitch + x) = color;
1502 /* Slow 24-bpp mode, usually not used */
1506 /* Gack - slow, but endian correct */
1507 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1508 shift = surface->format->Rshift;
1509 *(pix+shift/8) = color>>shift;
1510 shift = surface->format->Gshift;
1511 *(pix+shift/8) = color>>shift;
1512 shift = surface->format->Bshift;
1513 *(pix+shift/8) = color>>shift;
1519 /* Probably 32-bpp */
1520 *((Uint32 *)surface->pixels + ypitch + x) = color;
1527 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1532 if (SDL_MUSTLOCK(Surface))
1534 if (SDL_LockSurface(Surface) < 0)
1547 /* Do the clipping */
1548 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1552 if (x2 > Surface->w - 1)
1553 x2 = Surface->w - 1;
1560 SDL_FillRect(Surface, &l, Color);
1562 if (SDL_MUSTLOCK(Surface))
1564 SDL_UnlockSurface(Surface);
1568 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1569 Uint8 R, Uint8 G, Uint8 B)
1571 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1574 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1585 /* Do the clipping */
1586 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1590 if (x2 > Surface->w - 1)
1591 x2 = Surface->w - 1;
1598 SDL_FillRect(Surface, &l, Color);
1601 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1606 if (SDL_MUSTLOCK(Surface))
1608 if (SDL_LockSurface(Surface) < 0)
1621 /* Do the clipping */
1622 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1626 if (y2 > Surface->h - 1)
1627 y2 = Surface->h - 1;
1634 SDL_FillRect(Surface, &l, Color);
1636 if (SDL_MUSTLOCK(Surface))
1638 SDL_UnlockSurface(Surface);
1642 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1643 Uint8 R, Uint8 G, Uint8 B)
1645 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1648 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1659 /* Do the clipping */
1660 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1664 if (y2 > Surface->h - 1)
1665 y2 = Surface->h - 1;
1672 SDL_FillRect(Surface, &l, Color);
1675 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1676 Sint16 x2, Sint16 y2, Uint32 Color,
1677 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1680 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1685 sdx = (dx < 0) ? -1 : 1;
1686 sdy = (dy < 0) ? -1 : 1;
1698 for (x = 0; x < dx; x++)
1700 Callback(Surface, px, py, Color);
1714 for (y = 0; y < dy; y++)
1716 Callback(Surface, px, py, Color);
1730 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1731 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1732 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1735 sge_DoLine(Surface, X1, Y1, X2, Y2,
1736 SDL_MapRGB(Surface->format, R, G, B), Callback);
1739 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1742 if (SDL_MUSTLOCK(Surface))
1744 if (SDL_LockSurface(Surface) < 0)
1749 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1751 /* unlock the display */
1752 if (SDL_MUSTLOCK(Surface))
1754 SDL_UnlockSurface(Surface);
1758 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1759 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1761 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1764 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1766 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1771 -----------------------------------------------------------------------------
1772 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1773 -----------------------------------------------------------------------------
1776 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1777 int width, int height, Uint32 color)
1781 for (y = src_y; y < src_y + height; y++)
1783 for (x = src_x; x < src_x + width; x++)
1785 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1787 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1792 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1793 int src_x, int src_y, int width, int height,
1794 int dst_x, int dst_y)
1798 for (y = 0; y < height; y++)
1800 for (x = 0; x < width; x++)
1802 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1804 if (pixel != BLACK_PIXEL)
1805 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1811 /* ========================================================================= */
1812 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1813 /* (Rotozoomer) by Andreas Schiffler */
1814 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1815 /* ========================================================================= */
1818 -----------------------------------------------------------------------------
1821 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1822 -----------------------------------------------------------------------------
1833 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1836 tColorRGBA *sp, *csp, *dp;
1840 sp = csp = (tColorRGBA *) src->pixels;
1841 dp = (tColorRGBA *) dst->pixels;
1842 dgap = dst->pitch - dst->w * 4;
1844 for (y = 0; y < dst->h; y++)
1848 for (x = 0; x < dst->w; x++)
1850 tColorRGBA *sp0 = sp;
1851 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1852 tColorRGBA *sp00 = &sp0[0];
1853 tColorRGBA *sp01 = &sp0[1];
1854 tColorRGBA *sp10 = &sp1[0];
1855 tColorRGBA *sp11 = &sp1[1];
1858 /* create new color pixel from all four source color pixels */
1859 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1860 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1861 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1862 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1867 /* advance source pointers */
1870 /* advance destination pointer */
1874 /* advance source pointer */
1875 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1877 /* advance destination pointers */
1878 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1884 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1886 int x, y, *sax, *say, *csax, *csay;
1888 tColorRGBA *sp, *csp, *csp0, *dp;
1891 /* use specialized zoom function when scaling down to exactly half size */
1892 if (src->w == 2 * dst->w &&
1893 src->h == 2 * dst->h)
1894 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1896 /* variable setup */
1897 sx = (float) src->w / (float) dst->w;
1898 sy = (float) src->h / (float) dst->h;
1900 /* allocate memory for row increments */
1901 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1902 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1904 /* precalculate row increments */
1905 for (x = 0; x <= dst->w; x++)
1906 *csax++ = (int)(sx * x);
1908 for (y = 0; y <= dst->h; y++)
1909 *csay++ = (int)(sy * y);
1912 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1913 dp = (tColorRGBA *) dst->pixels;
1914 dgap = dst->pitch - dst->w * 4;
1917 for (y = 0; y < dst->h; y++)
1922 for (x = 0; x < dst->w; x++)
1927 /* advance source pointers */
1931 /* advance destination pointer */
1935 /* advance source pointer */
1937 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1939 /* advance destination pointers */
1940 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1950 -----------------------------------------------------------------------------
1953 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1954 -----------------------------------------------------------------------------
1957 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1959 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1960 Uint8 *sp, *dp, *csp;
1963 /* variable setup */
1964 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1965 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1967 /* allocate memory for row increments */
1968 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1969 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1971 /* precalculate row increments */
1974 for (x = 0; x < dst->w; x++)
1977 *csax = (csx >> 16);
1984 for (y = 0; y < dst->h; y++)
1987 *csay = (csy >> 16);
1994 for (x = 0; x < dst->w; x++)
2002 for (y = 0; y < dst->h; y++)
2009 sp = csp = (Uint8 *) src->pixels;
2010 dp = (Uint8 *) dst->pixels;
2011 dgap = dst->pitch - dst->w;
2015 for (y = 0; y < dst->h; y++)
2019 for (x = 0; x < dst->w; x++)
2024 /* advance source pointers */
2028 /* advance destination pointer */
2032 /* advance source pointer (for row) */
2033 csp += ((*csay) * src->pitch);
2036 /* advance destination pointers */
2047 -----------------------------------------------------------------------------
2050 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2051 'zoomx' and 'zoomy' are scaling factors for width and height.
2052 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2053 into a 32bit RGBA format on the fly.
2054 -----------------------------------------------------------------------------
2057 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2059 SDL_Surface *zoom_src = NULL;
2060 SDL_Surface *zoom_dst = NULL;
2061 boolean is_converted = FALSE;
2068 /* determine if source surface is 32 bit or 8 bit */
2069 is_32bit = (src->format->BitsPerPixel == 32);
2071 if (is_32bit || src->format->BitsPerPixel == 8)
2073 /* use source surface 'as is' */
2078 /* new source surface is 32 bit with a defined RGB ordering */
2079 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2080 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2081 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2083 is_converted = TRUE;
2086 /* allocate surface to completely contain the zoomed surface */
2089 /* target surface is 32 bit with source RGBA/ABGR ordering */
2090 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2091 zoom_src->format->Rmask,
2092 zoom_src->format->Gmask,
2093 zoom_src->format->Bmask, 0);
2097 /* target surface is 8 bit */
2098 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2102 /* lock source surface */
2103 SDL_LockSurface(zoom_src);
2105 /* check which kind of surface we have */
2108 /* call the 32 bit transformation routine to do the zooming */
2109 zoomSurfaceRGBA(zoom_src, zoom_dst);
2114 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2115 zoom_dst->format->palette->colors[i] =
2116 zoom_src->format->palette->colors[i];
2117 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2119 /* call the 8 bit transformation routine to do the zooming */
2120 zoomSurfaceY(zoom_src, zoom_dst);
2123 /* unlock source surface */
2124 SDL_UnlockSurface(zoom_src);
2126 /* free temporary surface */
2128 SDL_FreeSurface(zoom_src);
2130 /* return destination surface */
2134 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2136 Bitmap *dst_bitmap = CreateBitmapStruct();
2137 SDL_Surface **dst_surface = &dst_bitmap->surface;
2139 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2140 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2142 dst_bitmap->width = dst_width;
2143 dst_bitmap->height = dst_height;
2145 /* create zoomed temporary surface from source surface */
2146 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2148 /* create native format destination surface from zoomed temporary surface */
2149 SDLSetNativeSurface(dst_surface);
2155 /* ========================================================================= */
2156 /* load image to bitmap */
2157 /* ========================================================================= */
2159 Bitmap *SDLLoadImage(char *filename)
2161 Bitmap *new_bitmap = CreateBitmapStruct();
2162 SDL_Surface *sdl_image_tmp;
2164 print_timestamp_init("SDLLoadImage");
2166 print_timestamp_time(getBaseNamePtr(filename));
2168 /* load image to temporary surface */
2169 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2171 SetError("IMG_Load(): %s", SDL_GetError());
2176 print_timestamp_time("IMG_Load");
2178 UPDATE_BUSY_STATE();
2180 /* create native non-transparent surface for current image */
2181 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2183 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2188 print_timestamp_time("SDL_DisplayFormat (opaque)");
2190 UPDATE_BUSY_STATE();
2192 /* create native transparent surface for current image */
2193 if (sdl_image_tmp->format->Amask == 0)
2194 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2195 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2197 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2199 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2204 print_timestamp_time("SDL_DisplayFormat (masked)");
2206 UPDATE_BUSY_STATE();
2208 /* free temporary surface */
2209 SDL_FreeSurface(sdl_image_tmp);
2211 new_bitmap->width = new_bitmap->surface->w;
2212 new_bitmap->height = new_bitmap->surface->h;
2214 print_timestamp_done("SDLLoadImage");
2220 /* ------------------------------------------------------------------------- */
2221 /* custom cursor fuctions */
2222 /* ------------------------------------------------------------------------- */
2224 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2226 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2227 cursor_info->width, cursor_info->height,
2228 cursor_info->hot_x, cursor_info->hot_y);
2231 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2233 static struct MouseCursorInfo *last_cursor_info = NULL;
2234 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2235 static SDL_Cursor *cursor_default = NULL;
2236 static SDL_Cursor *cursor_current = NULL;
2238 /* if invoked for the first time, store the SDL default cursor */
2239 if (cursor_default == NULL)
2240 cursor_default = SDL_GetCursor();
2242 /* only create new cursor if cursor info (custom only) has changed */
2243 if (cursor_info != NULL && cursor_info != last_cursor_info)
2245 cursor_current = create_cursor(cursor_info);
2246 last_cursor_info = cursor_info;
2249 /* only set new cursor if cursor info (custom or NULL) has changed */
2250 if (cursor_info != last_cursor_info2)
2251 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2253 last_cursor_info2 = cursor_info;
2257 /* ========================================================================= */
2258 /* audio functions */
2259 /* ========================================================================= */
2261 void SDLOpenAudio(void)
2263 #if !defined(TARGET_SDL2)
2264 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2265 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2268 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2270 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2274 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2275 AUDIO_NUM_CHANNELS_STEREO,
2276 setup.system.audio_fragment_size) < 0)
2278 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2282 audio.sound_available = TRUE;
2283 audio.music_available = TRUE;
2284 audio.loops_available = TRUE;
2285 audio.sound_enabled = TRUE;
2287 /* set number of available mixer channels */
2288 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2289 audio.music_channel = MUSIC_CHANNEL;
2290 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2292 Mixer_InitChannels();
2295 void SDLCloseAudio(void)
2298 Mix_HaltChannel(-1);
2301 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2305 /* ========================================================================= */
2306 /* event functions */
2307 /* ========================================================================= */
2309 void SDLNextEvent(Event *event)
2311 SDL_WaitEvent(event);
2314 void SDLHandleWindowManagerEvent(Event *event)
2317 #if defined(PLATFORM_WIN32)
2318 // experimental drag and drop code
2320 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2321 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2323 #if defined(TARGET_SDL2)
2324 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2326 if (syswmmsg->msg == WM_DROPFILES)
2329 #if defined(TARGET_SDL2)
2330 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2332 HDROP hdrop = (HDROP)syswmmsg->wParam;
2336 printf("::: SDL_SYSWMEVENT:\n");
2338 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2340 for (i = 0; i < num_files; i++)
2342 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2343 char buffer[buffer_len + 1];
2345 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2347 printf("::: - '%s'\n", buffer);
2350 #if defined(TARGET_SDL2)
2351 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2353 DragFinish((HDROP)syswmmsg->wParam);
2361 /* ========================================================================= */
2362 /* joystick functions */
2363 /* ========================================================================= */
2365 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2366 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2367 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2369 static boolean SDLOpenJoystick(int nr)
2371 if (nr < 0 || nr > MAX_PLAYERS)
2374 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2377 static void SDLCloseJoystick(int nr)
2379 if (nr < 0 || nr > MAX_PLAYERS)
2382 SDL_JoystickClose(sdl_joystick[nr]);
2384 sdl_joystick[nr] = NULL;
2387 static boolean SDLCheckJoystickOpened(int nr)
2389 if (nr < 0 || nr > MAX_PLAYERS)
2392 #if defined(TARGET_SDL2)
2393 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2395 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2399 void HandleJoystickEvent(Event *event)
2403 case SDL_JOYAXISMOTION:
2404 if (event->jaxis.axis < 2)
2405 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2408 case SDL_JOYBUTTONDOWN:
2409 if (event->jbutton.button < 2)
2410 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2413 case SDL_JOYBUTTONUP:
2414 if (event->jbutton.button < 2)
2415 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2423 void SDLInitJoysticks()
2425 static boolean sdl_joystick_subsystem_initialized = FALSE;
2426 boolean print_warning = !sdl_joystick_subsystem_initialized;
2429 if (!sdl_joystick_subsystem_initialized)
2431 sdl_joystick_subsystem_initialized = TRUE;
2433 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2435 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2440 for (i = 0; i < MAX_PLAYERS; i++)
2442 /* get configured joystick for this player */
2443 char *device_name = setup.input[i].joy.device_name;
2444 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2446 if (joystick_nr >= SDL_NumJoysticks())
2448 if (setup.input[i].use_joystick && print_warning)
2449 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2454 /* misuse joystick file descriptor variable to store joystick number */
2455 joystick.fd[i] = joystick_nr;
2457 if (joystick_nr == -1)
2460 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2461 if (SDLCheckJoystickOpened(joystick_nr))
2462 SDLCloseJoystick(joystick_nr);
2464 if (!setup.input[i].use_joystick)
2467 if (!SDLOpenJoystick(joystick_nr))
2470 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2475 joystick.status = JOYSTICK_ACTIVATED;
2479 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2481 if (nr < 0 || nr >= MAX_PLAYERS)
2485 *x = sdl_js_axis[nr][0];
2487 *y = sdl_js_axis[nr][1];
2490 *b1 = sdl_js_button[nr][0];
2492 *b2 = sdl_js_button[nr][1];