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 static Pixel SDLGetColorKey(SDL_Surface *surface)
233 if (SDL_GetColorKey(surface, &color_key) != 0)
239 static boolean SDLHasColorKey(SDL_Surface *surface)
241 return (SDLGetColorKey(surface) != -1);
244 static boolean SDLHasAlpha(SDL_Surface *surface)
246 SDL_BlendMode blend_mode;
248 if (SDL_GetSurfaceBlendMode(surface, &blend_mode) != 0)
251 return (blend_mode == SDL_BLENDMODE_BLEND);
254 static void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha)
256 SDL_BlendMode blend_mode = (set ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE);
258 SDL_SetSurfaceBlendMode(surface, blend_mode);
259 SDL_SetSurfaceAlphaMod(surface, alpha);
262 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
264 SDL_PixelFormat format;
265 SDL_Surface *new_surface;
270 if (backbuffer && backbuffer->surface)
272 format = *backbuffer->surface->format;
273 format.Amask = surface->format->Amask; // keep alpha channel
277 format = *surface->format;
280 new_surface = SDL_ConvertSurface(surface, &format, 0);
282 if (new_surface == NULL)
283 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
288 boolean SDLSetNativeSurface(SDL_Surface **surface)
290 SDL_Surface *new_surface;
292 if (surface == NULL ||
294 backbuffer == NULL ||
295 backbuffer->surface == NULL)
298 // if pixel format already optimized for destination surface, do nothing
299 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
302 new_surface = SDLGetNativeSurface(*surface);
304 SDL_FreeSurface(*surface);
306 *surface = new_surface;
313 static Pixel SDLGetColorKey(SDL_Surface *surface)
315 if ((surface->flags & SDL_SRCCOLORKEY) == 0)
318 return surface->format->colorkey;
321 static boolean SDLHasColorKey(SDL_Surface *surface)
323 return (SDLGetColorKey(surface) != -1);
326 static boolean SDLHasAlpha(SDL_Surface *surface)
328 return ((surface->flags & SDL_SRCALPHA) != 0);
331 static void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha)
333 SDL_SetAlpha(surface, (set ? SDL_SRCALPHA : 0), alpha);
336 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
338 SDL_Surface *new_surface;
343 if (!video.initialized)
344 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
345 else if (SDLHasAlpha(surface))
346 new_surface = SDL_DisplayFormatAlpha(surface);
348 new_surface = SDL_DisplayFormat(surface);
350 if (new_surface == NULL)
351 Error(ERR_EXIT, "%s() failed: %s",
352 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
358 boolean SDLSetNativeSurface(SDL_Surface **surface)
360 SDL_Surface *new_surface;
362 if (surface == NULL ||
367 new_surface = SDLGetNativeSurface(*surface);
369 SDL_FreeSurface(*surface);
371 *surface = new_surface;
378 #if defined(TARGET_SDL2)
379 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
381 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
384 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
391 void SDLCreateBitmapTextures(Bitmap *bitmap)
393 #if defined(TARGET_SDL2)
398 SDL_DestroyTexture(bitmap->texture);
399 if (bitmap->texture_masked)
400 SDL_DestroyTexture(bitmap->texture_masked);
402 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
403 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
407 void SDLFreeBitmapTextures(Bitmap *bitmap)
409 #if defined(TARGET_SDL2)
414 SDL_DestroyTexture(bitmap->texture);
415 if (bitmap->texture_masked)
416 SDL_DestroyTexture(bitmap->texture_masked);
418 bitmap->texture = NULL;
419 bitmap->texture_masked = NULL;
423 void SDLInitVideoDisplay(void)
425 #if !defined(TARGET_SDL2)
426 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
427 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
429 SDL_putenv("SDL_VIDEO_CENTERED=1");
432 /* initialize SDL video */
433 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
434 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
436 /* set default SDL depth */
437 #if !defined(TARGET_SDL2)
438 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
440 video.default_depth = 32; // (how to determine video depth in SDL2?)
444 void SDLInitVideoBuffer(boolean fullscreen)
446 video.window_scaling_percent = setup.window_scaling_percent;
447 video.window_scaling_quality = setup.window_scaling_quality;
449 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
451 #if defined(TARGET_SDL2)
452 // SDL 2.0: support for (desktop) fullscreen mode available
453 video.fullscreen_available = TRUE;
455 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
456 video.fullscreen_available = FALSE;
459 /* open SDL video output device (window or fullscreen mode) */
460 if (!SDLSetVideoMode(fullscreen))
461 Error(ERR_EXIT, "setting video mode failed");
463 /* !!! SDL2 can only set the window icon if the window already exists !!! */
464 /* set window icon */
465 SDLSetWindowIcon(program.icon_filename);
467 /* set window and icon title */
468 #if defined(TARGET_SDL2)
469 SDL_SetWindowTitle(sdl_window, program.window_title);
471 SDL_WM_SetCaption(program.window_title, program.window_title);
474 /* SDL cannot directly draw to the visible video framebuffer like X11,
475 but always uses a backbuffer, which is then blitted to the visible
476 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
477 visible video framebuffer with 'SDL_Flip', if the hardware supports
478 this). Therefore do not use an additional backbuffer for drawing, but
479 use a symbolic buffer (distinguishable from the SDL backbuffer) called
480 'window', which indicates that the SDL backbuffer should be updated to
481 the visible video framebuffer when attempting to blit to it.
483 For convenience, it seems to be a good idea to create this symbolic
484 buffer 'window' at the same size as the SDL backbuffer. Although it
485 should never be drawn to directly, it would do no harm nevertheless. */
487 /* create additional (symbolic) buffer for double-buffering */
488 ReCreateBitmap(&window, video.width, video.height);
491 static boolean SDLCreateScreen(boolean fullscreen)
493 SDL_Surface *new_surface = NULL;
495 #if defined(TARGET_SDL2)
496 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
497 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
499 int surface_flags_window = SURFACE_FLAGS;
500 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
503 #if defined(TARGET_SDL2)
505 int renderer_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
507 /* If SDL_CreateRenderer() is called from within a VirtualBox Windows VM
508 _without_ enabling 2D/3D acceleration and/or guest additions installed,
509 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
510 it will try to use accelerated graphics and apparently fails miserably) */
511 int renderer_flags = SDL_RENDERER_SOFTWARE;
515 int width = video.width;
516 int height = video.height;
517 int surface_flags = (fullscreen ? surface_flags_fullscreen :
518 surface_flags_window);
520 // default window size is unscaled
521 video.window_width = video.width;
522 video.window_height = video.height;
524 #if defined(TARGET_SDL2)
526 // store if initial screen mode is fullscreen mode when changing screen size
527 video.fullscreen_initial = fullscreen;
529 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
531 video.window_width = window_scaling_factor * width;
532 video.window_height = window_scaling_factor * height;
534 if (sdl_texture_stream)
536 SDL_DestroyTexture(sdl_texture_stream);
537 sdl_texture_stream = NULL;
540 if (sdl_texture_target)
542 SDL_DestroyTexture(sdl_texture_target);
543 sdl_texture_target = NULL;
546 if (!(fullscreen && fullscreen_enabled))
550 SDL_DestroyRenderer(sdl_renderer);
556 SDL_DestroyWindow(sdl_window);
561 if (sdl_window == NULL)
562 sdl_window = SDL_CreateWindow(program.window_title,
563 SDL_WINDOWPOS_CENTERED,
564 SDL_WINDOWPOS_CENTERED,
569 if (sdl_window != NULL)
571 if (sdl_renderer == NULL)
572 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, renderer_flags);
574 if (sdl_renderer != NULL)
576 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
577 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
578 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
580 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
581 SDL_PIXELFORMAT_ARGB8888,
582 SDL_TEXTUREACCESS_STREAMING,
585 if (SDL_RenderTargetSupported(sdl_renderer))
586 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
587 SDL_PIXELFORMAT_ARGB8888,
588 SDL_TEXTUREACCESS_TARGET,
591 if (sdl_texture_stream != NULL)
593 // use SDL default values for RGB masks and no alpha channel
594 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
596 if (new_surface == NULL)
597 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
601 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
606 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
611 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
616 if (gfx.final_screen_bitmap == NULL)
617 gfx.final_screen_bitmap = CreateBitmapStruct();
619 gfx.final_screen_bitmap->width = width;
620 gfx.final_screen_bitmap->height = height;
622 gfx.final_screen_bitmap->surface =
623 SDL_SetVideoMode(width, height, video.depth, surface_flags);
625 if (gfx.final_screen_bitmap->surface != NULL)
628 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
630 if (new_surface == NULL)
631 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
634 new_surface = gfx.final_screen_bitmap->surface;
635 gfx.final_screen_bitmap = NULL;
641 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
645 #if defined(TARGET_SDL2)
646 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
647 if (new_surface != NULL)
648 fullscreen_enabled = fullscreen;
651 if (backbuffer == NULL)
652 backbuffer = CreateBitmapStruct();
654 backbuffer->width = video.width;
655 backbuffer->height = video.height;
657 if (backbuffer->surface)
658 SDL_FreeSurface(backbuffer->surface);
660 backbuffer->surface = new_surface;
662 return (new_surface != NULL);
665 boolean SDLSetVideoMode(boolean fullscreen)
667 boolean success = FALSE;
671 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
673 /* switch display to fullscreen mode, if available */
674 success = SDLCreateScreen(TRUE);
678 /* switching display to fullscreen mode failed -- do not try it again */
679 video.fullscreen_available = FALSE;
683 video.fullscreen_enabled = TRUE;
687 if ((!fullscreen && video.fullscreen_enabled) || !success)
689 /* switch display to window mode */
690 success = SDLCreateScreen(FALSE);
694 /* switching display to window mode failed -- should not happen */
698 video.fullscreen_enabled = FALSE;
699 video.window_scaling_percent = setup.window_scaling_percent;
700 video.window_scaling_quality = setup.window_scaling_quality;
702 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
706 #if defined(TARGET_SDL2)
707 SDLRedrawWindow(); // map window
711 #if defined(PLATFORM_WIN32)
712 // experimental drag and drop code
714 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
717 SDL_SysWMinfo wminfo;
719 boolean wminfo_success = FALSE;
721 SDL_VERSION(&wminfo.version);
722 #if defined(TARGET_SDL2)
724 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
726 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
731 #if defined(TARGET_SDL2)
732 hwnd = wminfo.info.win.window;
734 hwnd = wminfo.window;
737 DragAcceptFiles(hwnd, TRUE);
746 void SDLSetWindowTitle()
748 #if defined(TARGET_SDL2)
749 SDL_SetWindowTitle(sdl_window, program.window_title);
751 SDL_WM_SetCaption(program.window_title, program.window_title);
755 #if defined(TARGET_SDL2)
756 void SDLSetWindowScaling(int window_scaling_percent)
758 if (sdl_window == NULL)
761 float window_scaling_factor = (float)window_scaling_percent / 100;
762 int new_window_width = (int)(window_scaling_factor * video.width);
763 int new_window_height = (int)(window_scaling_factor * video.height);
765 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
767 video.window_scaling_percent = window_scaling_percent;
768 video.window_width = new_window_width;
769 video.window_height = new_window_height;
774 void SDLSetWindowScalingQuality(char *window_scaling_quality)
776 SDL_Texture *new_texture;
778 if (sdl_texture_stream == NULL)
781 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
783 new_texture = SDL_CreateTexture(sdl_renderer,
784 SDL_PIXELFORMAT_ARGB8888,
785 SDL_TEXTUREACCESS_STREAMING,
786 video.width, video.height);
788 if (new_texture != NULL)
790 SDL_DestroyTexture(sdl_texture_stream);
792 sdl_texture_stream = new_texture;
795 if (SDL_RenderTargetSupported(sdl_renderer))
796 new_texture = SDL_CreateTexture(sdl_renderer,
797 SDL_PIXELFORMAT_ARGB8888,
798 SDL_TEXTUREACCESS_TARGET,
799 video.width, video.height);
803 if (new_texture != NULL)
805 SDL_DestroyTexture(sdl_texture_target);
807 sdl_texture_target = new_texture;
812 video.window_scaling_quality = window_scaling_quality;
815 void SDLSetWindowFullscreen(boolean fullscreen)
817 if (sdl_window == NULL)
820 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
822 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
823 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
825 // if screen size was changed in fullscreen mode, correct desktop window size
826 if (!fullscreen && video.fullscreen_initial)
828 SDLSetWindowScaling(setup.window_scaling_percent);
829 SDL_SetWindowPosition(sdl_window,
830 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
832 video.fullscreen_initial = FALSE;
837 void SDLSetScreenRenderingMode(char *screen_rendering_mode)
839 #if defined(TARGET_SDL2)
840 video.screen_rendering_mode =
841 (strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
842 SPECIAL_RENDERING_BITMAP :
843 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
844 SPECIAL_RENDERING_TARGET:
845 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
846 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
848 video.screen_rendering_mode = SPECIAL_RENDERING_BITMAP;
852 void SDLRedrawWindow()
854 UpdateScreen_WithoutFrameDelay(NULL);
857 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
860 SDL_Surface *surface =
861 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
864 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
866 SDLSetNativeSurface(&surface);
868 bitmap->surface = surface;
871 void SDLFreeBitmapPointers(Bitmap *bitmap)
874 SDL_FreeSurface(bitmap->surface);
875 if (bitmap->surface_masked)
876 SDL_FreeSurface(bitmap->surface_masked);
878 bitmap->surface = NULL;
879 bitmap->surface_masked = NULL;
881 #if defined(TARGET_SDL2)
883 SDL_DestroyTexture(bitmap->texture);
884 if (bitmap->texture_masked)
885 SDL_DestroyTexture(bitmap->texture_masked);
887 bitmap->texture = NULL;
888 bitmap->texture_masked = NULL;
892 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
893 int src_x, int src_y, int width, int height,
894 int dst_x, int dst_y, int mask_mode)
896 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
897 SDL_Rect src_rect, dst_rect;
909 // if (src_bitmap != backbuffer || dst_bitmap != window)
910 if (!(src_bitmap == backbuffer && dst_bitmap == window))
911 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
912 src_bitmap->surface_masked : src_bitmap->surface),
913 &src_rect, real_dst_bitmap->surface, &dst_rect);
915 if (dst_bitmap == window)
916 UpdateScreen_WithFrameDelay(&dst_rect);
919 void SDLBlitTexture(Bitmap *bitmap,
920 int src_x, int src_y, int width, int height,
921 int dst_x, int dst_y, int mask_mode)
923 #if defined(TARGET_SDL2)
924 SDL_Texture *texture;
929 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
944 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
948 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
951 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
959 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
961 if (dst_bitmap == window)
962 UpdateScreen_WithFrameDelay(&rect);
965 void PrepareFadeBitmap(int draw_target)
967 Bitmap *fade_bitmap =
968 (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
969 draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
971 if (fade_bitmap == NULL)
974 // copy backbuffer to fading buffer
975 BlitBitmap(backbuffer, fade_bitmap, 0, 0, gfx.win_xsize, gfx.win_ysize, 0, 0);
977 // add border and animations to fading buffer
978 FinalizeScreen(draw_target);
981 void SDLFadeRectangle(int x, int y, int width, int height,
982 int fade_mode, int fade_delay, int post_delay,
983 void (*draw_border_function)(void))
985 SDL_Surface *surface_backup = gfx.fade_bitmap_backup->surface;
986 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
987 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
988 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
989 SDL_Surface *surface_screen = backbuffer->surface;
990 SDL_Rect src_rect, dst_rect;
992 int src_x = x, src_y = y;
993 int dst_x = x, dst_y = y;
994 unsigned int time_last, time_current;
996 // store function for drawing global masked border
997 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
999 // deactivate drawing of global border while fading, if needed
1000 if (draw_border_function == NULL)
1001 gfx.draw_global_border_function = NULL;
1006 src_rect.h = height;
1010 dst_rect.w = width; /* (ignored) */
1011 dst_rect.h = height; /* (ignored) */
1013 dst_rect2 = dst_rect;
1015 // before fading in, store backbuffer (without animation graphics)
1016 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
1017 SDL_BlitSurface(surface_screen, &dst_rect, surface_backup, &src_rect);
1019 /* copy source and target surfaces to temporary surfaces for fading */
1020 if (fade_mode & FADE_TYPE_TRANSFORM)
1022 // (source and target fading buffer already prepared)
1024 else if (fade_mode & FADE_TYPE_FADE_IN)
1026 // (target fading buffer already prepared)
1027 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1029 else /* FADE_TYPE_FADE_OUT */
1031 // (source fading buffer already prepared)
1032 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1035 time_current = SDL_GetTicks();
1037 if (fade_mode == FADE_MODE_MELT)
1039 boolean done = FALSE;
1040 int melt_pixels = 2;
1041 int melt_columns = width / melt_pixels;
1042 int ypos[melt_columns];
1043 int max_steps = height / 8 + 32;
1048 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1050 SDLSetAlpha(surface_target, FALSE, 0); /* disable alpha blending */
1052 ypos[0] = -GetSimpleRandom(16);
1054 for (i = 1 ; i < melt_columns; i++)
1056 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1058 ypos[i] = ypos[i - 1] + r;
1071 time_last = time_current;
1072 time_current = SDL_GetTicks();
1073 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1074 steps_final = MIN(MAX(0, steps), max_steps);
1078 done = (steps_done >= steps_final);
1080 for (i = 0 ; i < melt_columns; i++)
1088 else if (ypos[i] < height)
1093 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1095 if (ypos[i] + dy >= height)
1096 dy = height - ypos[i];
1098 /* copy part of (appearing) target surface to upper area */
1099 src_rect.x = src_x + i * melt_pixels;
1100 // src_rect.y = src_y + ypos[i];
1102 src_rect.w = melt_pixels;
1104 src_rect.h = ypos[i] + dy;
1106 dst_rect.x = dst_x + i * melt_pixels;
1107 // dst_rect.y = dst_y + ypos[i];
1110 if (steps_done >= steps_final)
1111 SDL_BlitSurface(surface_target, &src_rect,
1112 surface_screen, &dst_rect);
1116 /* copy part of (disappearing) source surface to lower area */
1117 src_rect.x = src_x + i * melt_pixels;
1119 src_rect.w = melt_pixels;
1120 src_rect.h = height - ypos[i];
1122 dst_rect.x = dst_x + i * melt_pixels;
1123 dst_rect.y = dst_y + ypos[i];
1125 if (steps_done >= steps_final)
1126 SDL_BlitSurface(surface_source, &src_rect,
1127 surface_screen, &dst_rect);
1133 src_rect.x = src_x + i * melt_pixels;
1135 src_rect.w = melt_pixels;
1136 src_rect.h = height;
1138 dst_rect.x = dst_x + i * melt_pixels;
1141 if (steps_done >= steps_final)
1142 SDL_BlitSurface(surface_target, &src_rect,
1143 surface_screen, &dst_rect);
1147 if (steps_done >= steps_final)
1149 if (draw_border_function != NULL)
1150 draw_border_function();
1152 UpdateScreen_WithFrameDelay(&dst_rect2);
1156 else if (fade_mode == FADE_MODE_CURTAIN)
1160 int xx_size = width / 2;
1162 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1164 SDLSetAlpha(surface_source, FALSE, 0); /* disable alpha blending */
1166 for (xx = 0; xx < xx_size;)
1168 time_last = time_current;
1169 time_current = SDL_GetTicks();
1170 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1171 xx_final = MIN(MAX(0, xx), xx_size);
1176 src_rect.h = height;
1181 /* draw new (target) image to screen buffer */
1182 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1184 if (xx_final < xx_size)
1186 src_rect.w = xx_size - xx_final;
1187 src_rect.h = height;
1189 /* draw old (source) image to screen buffer (left side) */
1191 src_rect.x = src_x + xx_final;
1194 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1196 /* draw old (source) image to screen buffer (right side) */
1198 src_rect.x = src_x + xx_size;
1199 dst_rect.x = dst_x + xx_size + xx_final;
1201 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1204 if (draw_border_function != NULL)
1205 draw_border_function();
1207 /* only update the region of the screen that is affected from fading */
1208 UpdateScreen_WithFrameDelay(&dst_rect2);
1211 else /* fading in, fading out or cross-fading */
1216 for (alpha = 0.0; alpha < 255.0;)
1218 time_last = time_current;
1219 time_current = SDL_GetTicks();
1220 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1221 alpha_final = MIN(MAX(0, alpha), 255);
1223 /* draw existing (source) image to screen buffer */
1224 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1226 /* draw new (target) image to screen buffer using alpha blending */
1227 SDLSetAlpha(surface_target, TRUE, alpha_final);
1228 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1230 if (draw_border_function != NULL)
1231 draw_border_function();
1233 /* only update the region of the screen that is affected from fading */
1234 UpdateScreen_WithFrameDelay(&dst_rect);
1240 unsigned int time_post_delay;
1242 time_current = SDL_GetTicks();
1243 time_post_delay = time_current + post_delay;
1245 while (time_current < time_post_delay)
1247 // updating the screen contains waiting for frame delay (non-busy)
1248 UpdateScreen_WithFrameDelay(NULL);
1250 time_current = SDL_GetTicks();
1254 // restore function for drawing global masked border
1255 gfx.draw_global_border_function = draw_global_border_function;
1257 // after fading in, restore backbuffer (without animation graphics)
1258 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
1259 SDL_BlitSurface(surface_backup, &dst_rect, surface_screen, &src_rect);
1262 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1263 int to_x, int to_y, Uint32 color)
1265 SDL_Surface *surface = dst_bitmap->surface;
1269 swap_numbers(&from_x, &to_x);
1272 swap_numbers(&from_y, &to_y);
1276 rect.w = (to_x - from_x + 1);
1277 rect.h = (to_y - from_y + 1);
1279 SDL_FillRect(surface, &rect, color);
1282 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1283 int to_x, int to_y, Uint32 color)
1285 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1288 #if ENABLE_UNUSED_CODE
1289 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1290 int num_points, Uint32 color)
1295 for (i = 0; i < num_points - 1; i++)
1297 for (x = 0; x < line_width; x++)
1299 for (y = 0; y < line_width; y++)
1301 int dx = x - line_width / 2;
1302 int dy = y - line_width / 2;
1304 if ((x == 0 && y == 0) ||
1305 (x == 0 && y == line_width - 1) ||
1306 (x == line_width - 1 && y == 0) ||
1307 (x == line_width - 1 && y == line_width - 1))
1310 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1311 points[i+1].x + dx, points[i+1].y + dy, color);
1318 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1320 SDL_Surface *surface = src_bitmap->surface;
1322 switch (surface->format->BytesPerPixel)
1324 case 1: /* assuming 8-bpp */
1326 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1330 case 2: /* probably 15-bpp or 16-bpp */
1332 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1336 case 3: /* slow 24-bpp mode; usually not used */
1338 /* does this work? */
1339 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1343 shift = surface->format->Rshift;
1344 color |= *(pix + shift / 8) >> shift;
1345 shift = surface->format->Gshift;
1346 color |= *(pix + shift / 8) >> shift;
1347 shift = surface->format->Bshift;
1348 color |= *(pix + shift / 8) >> shift;
1354 case 4: /* probably 32-bpp */
1356 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1365 /* ========================================================================= */
1366 /* The following functions were taken from the SGE library */
1367 /* (SDL Graphics Extension Library) by Anders Lindström */
1368 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1369 /* ========================================================================= */
1371 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1373 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1375 switch (surface->format->BytesPerPixel)
1379 /* Assuming 8-bpp */
1380 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1386 /* Probably 15-bpp or 16-bpp */
1387 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1393 /* Slow 24-bpp mode, usually not used */
1397 /* Gack - slow, but endian correct */
1398 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1399 shift = surface->format->Rshift;
1400 *(pix+shift/8) = color>>shift;
1401 shift = surface->format->Gshift;
1402 *(pix+shift/8) = color>>shift;
1403 shift = surface->format->Bshift;
1404 *(pix+shift/8) = color>>shift;
1410 /* Probably 32-bpp */
1411 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1418 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1419 Uint8 R, Uint8 G, Uint8 B)
1421 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1424 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1426 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1429 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1431 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1434 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1439 /* Gack - slow, but endian correct */
1440 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1441 shift = surface->format->Rshift;
1442 *(pix+shift/8) = color>>shift;
1443 shift = surface->format->Gshift;
1444 *(pix+shift/8) = color>>shift;
1445 shift = surface->format->Bshift;
1446 *(pix+shift/8) = color>>shift;
1449 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1451 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1454 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1456 switch (dest->format->BytesPerPixel)
1459 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1463 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1467 _PutPixel24(dest,x,y,color);
1471 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1476 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1478 if (SDL_MUSTLOCK(surface))
1480 if (SDL_LockSurface(surface) < 0)
1486 _PutPixel(surface, x, y, color);
1488 if (SDL_MUSTLOCK(surface))
1490 SDL_UnlockSurface(surface);
1494 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1495 Uint8 r, Uint8 g, Uint8 b)
1497 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1500 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1502 if (y >= 0 && y <= dest->h - 1)
1504 switch (dest->format->BytesPerPixel)
1507 return y*dest->pitch;
1511 return y*dest->pitch/2;
1515 return y*dest->pitch;
1519 return y*dest->pitch/4;
1527 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1529 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1531 switch (surface->format->BytesPerPixel)
1535 /* Assuming 8-bpp */
1536 *((Uint8 *)surface->pixels + ypitch + x) = color;
1542 /* Probably 15-bpp or 16-bpp */
1543 *((Uint16 *)surface->pixels + ypitch + x) = color;
1549 /* Slow 24-bpp mode, usually not used */
1553 /* Gack - slow, but endian correct */
1554 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1555 shift = surface->format->Rshift;
1556 *(pix+shift/8) = color>>shift;
1557 shift = surface->format->Gshift;
1558 *(pix+shift/8) = color>>shift;
1559 shift = surface->format->Bshift;
1560 *(pix+shift/8) = color>>shift;
1566 /* Probably 32-bpp */
1567 *((Uint32 *)surface->pixels + ypitch + x) = color;
1574 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1579 if (SDL_MUSTLOCK(Surface))
1581 if (SDL_LockSurface(Surface) < 0)
1594 /* Do the clipping */
1595 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1599 if (x2 > Surface->w - 1)
1600 x2 = Surface->w - 1;
1607 SDL_FillRect(Surface, &l, Color);
1609 if (SDL_MUSTLOCK(Surface))
1611 SDL_UnlockSurface(Surface);
1615 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1616 Uint8 R, Uint8 G, Uint8 B)
1618 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1621 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1632 /* Do the clipping */
1633 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1637 if (x2 > Surface->w - 1)
1638 x2 = Surface->w - 1;
1645 SDL_FillRect(Surface, &l, Color);
1648 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1653 if (SDL_MUSTLOCK(Surface))
1655 if (SDL_LockSurface(Surface) < 0)
1668 /* Do the clipping */
1669 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1673 if (y2 > Surface->h - 1)
1674 y2 = Surface->h - 1;
1681 SDL_FillRect(Surface, &l, Color);
1683 if (SDL_MUSTLOCK(Surface))
1685 SDL_UnlockSurface(Surface);
1689 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1690 Uint8 R, Uint8 G, Uint8 B)
1692 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1695 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1706 /* Do the clipping */
1707 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1711 if (y2 > Surface->h - 1)
1712 y2 = Surface->h - 1;
1719 SDL_FillRect(Surface, &l, Color);
1722 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1723 Sint16 x2, Sint16 y2, Uint32 Color,
1724 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1727 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1732 sdx = (dx < 0) ? -1 : 1;
1733 sdy = (dy < 0) ? -1 : 1;
1745 for (x = 0; x < dx; x++)
1747 Callback(Surface, px, py, Color);
1761 for (y = 0; y < dy; y++)
1763 Callback(Surface, px, py, Color);
1777 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1778 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1779 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1782 sge_DoLine(Surface, X1, Y1, X2, Y2,
1783 SDL_MapRGB(Surface->format, R, G, B), Callback);
1786 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1789 if (SDL_MUSTLOCK(Surface))
1791 if (SDL_LockSurface(Surface) < 0)
1796 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1798 /* unlock the display */
1799 if (SDL_MUSTLOCK(Surface))
1801 SDL_UnlockSurface(Surface);
1805 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1806 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1808 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1811 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1813 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1818 -----------------------------------------------------------------------------
1819 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1820 -----------------------------------------------------------------------------
1823 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1824 int width, int height, Uint32 color)
1828 for (y = src_y; y < src_y + height; y++)
1830 for (x = src_x; x < src_x + width; x++)
1832 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1834 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1839 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1840 int src_x, int src_y, int width, int height,
1841 int dst_x, int dst_y)
1845 for (y = 0; y < height; y++)
1847 for (x = 0; x < width; x++)
1849 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1851 if (pixel != BLACK_PIXEL)
1852 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1858 /* ========================================================================= */
1859 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1860 /* (Rotozoomer) by Andreas Schiffler */
1861 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1862 /* ========================================================================= */
1865 -----------------------------------------------------------------------------
1868 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1869 -----------------------------------------------------------------------------
1880 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1883 tColorRGBA *sp, *csp, *dp;
1887 sp = csp = (tColorRGBA *) src->pixels;
1888 dp = (tColorRGBA *) dst->pixels;
1889 dgap = dst->pitch - dst->w * 4;
1891 for (y = 0; y < dst->h; y++)
1895 for (x = 0; x < dst->w; x++)
1897 tColorRGBA *sp0 = sp;
1898 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1899 tColorRGBA *sp00 = &sp0[0];
1900 tColorRGBA *sp01 = &sp0[1];
1901 tColorRGBA *sp10 = &sp1[0];
1902 tColorRGBA *sp11 = &sp1[1];
1905 /* create new color pixel from all four source color pixels */
1906 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1907 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1908 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1909 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1914 /* advance source pointers */
1917 /* advance destination pointer */
1921 /* advance source pointer */
1922 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1924 /* advance destination pointers */
1925 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1931 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1933 int x, y, *sax, *say, *csax, *csay;
1935 tColorRGBA *sp, *csp, *csp0, *dp;
1938 /* use specialized zoom function when scaling down to exactly half size */
1939 if (src->w == 2 * dst->w &&
1940 src->h == 2 * dst->h)
1941 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1943 /* variable setup */
1944 sx = (float) src->w / (float) dst->w;
1945 sy = (float) src->h / (float) dst->h;
1947 /* allocate memory for row increments */
1948 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1949 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1951 /* precalculate row increments */
1952 for (x = 0; x <= dst->w; x++)
1953 *csax++ = (int)(sx * x);
1955 for (y = 0; y <= dst->h; y++)
1956 *csay++ = (int)(sy * y);
1959 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1960 dp = (tColorRGBA *) dst->pixels;
1961 dgap = dst->pitch - dst->w * 4;
1964 for (y = 0; y < dst->h; y++)
1969 for (x = 0; x < dst->w; x++)
1974 /* advance source pointers */
1978 /* advance destination pointer */
1982 /* advance source pointer */
1984 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1986 /* advance destination pointers */
1987 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1997 -----------------------------------------------------------------------------
2000 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2001 -----------------------------------------------------------------------------
2004 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2006 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2007 Uint8 *sp, *dp, *csp;
2010 /* variable setup */
2011 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2012 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2014 /* allocate memory for row increments */
2015 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2016 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2018 /* precalculate row increments */
2021 for (x = 0; x < dst->w; x++)
2024 *csax = (csx >> 16);
2031 for (y = 0; y < dst->h; y++)
2034 *csay = (csy >> 16);
2041 for (x = 0; x < dst->w; x++)
2049 for (y = 0; y < dst->h; y++)
2056 sp = csp = (Uint8 *) src->pixels;
2057 dp = (Uint8 *) dst->pixels;
2058 dgap = dst->pitch - dst->w;
2062 for (y = 0; y < dst->h; y++)
2066 for (x = 0; x < dst->w; x++)
2071 /* advance source pointers */
2075 /* advance destination pointer */
2079 /* advance source pointer (for row) */
2080 csp += ((*csay) * src->pitch);
2083 /* advance destination pointers */
2094 -----------------------------------------------------------------------------
2097 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2098 'zoomx' and 'zoomy' are scaling factors for width and height.
2099 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2100 into a 32bit RGBA format on the fly.
2101 -----------------------------------------------------------------------------
2104 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2106 SDL_Surface *zoom_src = NULL;
2107 SDL_Surface *zoom_dst = NULL;
2108 boolean is_converted = FALSE;
2115 /* determine if source surface is 32 bit or 8 bit */
2116 is_32bit = (src->format->BitsPerPixel == 32);
2118 if (is_32bit || src->format->BitsPerPixel == 8)
2120 /* use source surface 'as is' */
2125 /* new source surface is 32 bit with a defined RGB ordering */
2126 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2127 0x000000ff, 0x0000ff00, 0x00ff0000,
2128 (src->format->Amask ? 0xff000000 : 0));
2129 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2131 is_converted = TRUE;
2134 /* allocate surface to completely contain the zoomed surface */
2137 /* target surface is 32 bit with source RGBA/ABGR ordering */
2138 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2139 zoom_src->format->Rmask,
2140 zoom_src->format->Gmask,
2141 zoom_src->format->Bmask,
2142 zoom_src->format->Amask);
2146 /* target surface is 8 bit */
2147 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2151 /* lock source surface */
2152 SDL_LockSurface(zoom_src);
2154 /* check which kind of surface we have */
2157 /* call the 32 bit transformation routine to do the zooming */
2158 zoomSurfaceRGBA(zoom_src, zoom_dst);
2163 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2164 zoom_dst->format->palette->colors[i] =
2165 zoom_src->format->palette->colors[i];
2166 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2168 /* call the 8 bit transformation routine to do the zooming */
2169 zoomSurfaceY(zoom_src, zoom_dst);
2172 /* unlock source surface */
2173 SDL_UnlockSurface(zoom_src);
2175 /* free temporary surface */
2177 SDL_FreeSurface(zoom_src);
2179 /* return destination surface */
2183 static SDL_Surface *SDLGetOpaqueSurface(SDL_Surface *surface)
2185 SDL_Surface *new_surface;
2187 if (surface == NULL)
2190 if ((new_surface = SDLGetNativeSurface(surface)) == NULL)
2191 Error(ERR_EXIT, "SDLGetNativeSurface() failed");
2193 /* remove alpha channel from native non-transparent surface, if defined */
2194 SDLSetAlpha(new_surface, FALSE, 0);
2196 /* remove transparent color from native non-transparent surface, if defined */
2197 SDL_SetColorKey(new_surface, UNSET_TRANSPARENT_PIXEL, 0);
2202 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2204 Bitmap *dst_bitmap = CreateBitmapStruct();
2205 SDL_Surface *src_surface = src_bitmap->surface_masked;
2206 SDL_Surface *dst_surface;
2208 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2209 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2211 dst_bitmap->width = dst_width;
2212 dst_bitmap->height = dst_height;
2214 /* create zoomed temporary surface from source surface */
2215 dst_surface = zoomSurface(src_surface, dst_width, dst_height);
2217 /* create native format destination surface from zoomed temporary surface */
2218 SDLSetNativeSurface(&dst_surface);
2220 /* set color key for zoomed surface from source surface, if defined */
2221 if (SDLHasColorKey(src_surface))
2222 SDL_SetColorKey(dst_surface, SET_TRANSPARENT_PIXEL,
2223 SDLGetColorKey(src_surface));
2225 /* create native non-transparent surface for opaque blitting */
2226 dst_bitmap->surface = SDLGetOpaqueSurface(dst_surface);
2228 /* set native transparent surface for masked blitting */
2229 dst_bitmap->surface_masked = dst_surface;
2235 /* ========================================================================= */
2236 /* load image to bitmap */
2237 /* ========================================================================= */
2239 Bitmap *SDLLoadImage(char *filename)
2241 Bitmap *new_bitmap = CreateBitmapStruct();
2242 SDL_Surface *sdl_image_tmp;
2244 print_timestamp_init("SDLLoadImage");
2246 print_timestamp_time(getBaseNamePtr(filename));
2248 /* load image to temporary surface */
2249 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2250 Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError());
2252 print_timestamp_time("IMG_Load");
2254 UPDATE_BUSY_STATE();
2256 /* create native non-transparent surface for current image */
2257 if ((new_bitmap->surface = SDLGetOpaqueSurface(sdl_image_tmp)) == NULL)
2258 Error(ERR_EXIT, "SDLGetOpaqueSurface() failed");
2260 print_timestamp_time("SDLGetNativeSurface (opaque)");
2262 UPDATE_BUSY_STATE();
2264 /* set black pixel to transparent if no alpha channel / transparent color */
2265 if (!SDLHasAlpha(sdl_image_tmp) &&
2266 !SDLHasColorKey(sdl_image_tmp))
2267 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2268 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2270 /* create native transparent surface for current image */
2271 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2272 Error(ERR_EXIT, "SDLGetNativeSurface() failed");
2274 print_timestamp_time("SDLGetNativeSurface (masked)");
2276 UPDATE_BUSY_STATE();
2278 /* free temporary surface */
2279 SDL_FreeSurface(sdl_image_tmp);
2281 new_bitmap->width = new_bitmap->surface->w;
2282 new_bitmap->height = new_bitmap->surface->h;
2284 print_timestamp_done("SDLLoadImage");
2290 /* ------------------------------------------------------------------------- */
2291 /* custom cursor fuctions */
2292 /* ------------------------------------------------------------------------- */
2294 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2296 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2297 cursor_info->width, cursor_info->height,
2298 cursor_info->hot_x, cursor_info->hot_y);
2301 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2303 static struct MouseCursorInfo *last_cursor_info = NULL;
2304 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2305 static SDL_Cursor *cursor_default = NULL;
2306 static SDL_Cursor *cursor_current = NULL;
2308 /* if invoked for the first time, store the SDL default cursor */
2309 if (cursor_default == NULL)
2310 cursor_default = SDL_GetCursor();
2312 /* only create new cursor if cursor info (custom only) has changed */
2313 if (cursor_info != NULL && cursor_info != last_cursor_info)
2315 cursor_current = create_cursor(cursor_info);
2316 last_cursor_info = cursor_info;
2319 /* only set new cursor if cursor info (custom or NULL) has changed */
2320 if (cursor_info != last_cursor_info2)
2321 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2323 last_cursor_info2 = cursor_info;
2327 /* ========================================================================= */
2328 /* audio functions */
2329 /* ========================================================================= */
2331 void SDLOpenAudio(void)
2333 #if !defined(TARGET_SDL2)
2334 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2335 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2338 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2340 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2344 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2345 AUDIO_NUM_CHANNELS_STEREO,
2346 setup.system.audio_fragment_size) < 0)
2348 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2352 audio.sound_available = TRUE;
2353 audio.music_available = TRUE;
2354 audio.loops_available = TRUE;
2355 audio.sound_enabled = TRUE;
2357 /* set number of available mixer channels */
2358 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2359 audio.music_channel = MUSIC_CHANNEL;
2360 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2362 Mixer_InitChannels();
2365 void SDLCloseAudio(void)
2368 Mix_HaltChannel(-1);
2371 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2375 /* ========================================================================= */
2376 /* event functions */
2377 /* ========================================================================= */
2379 void SDLNextEvent(Event *event)
2381 SDL_WaitEvent(event);
2384 void SDLHandleWindowManagerEvent(Event *event)
2387 #if defined(PLATFORM_WIN32)
2388 // experimental drag and drop code
2390 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2391 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2393 #if defined(TARGET_SDL2)
2394 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2396 if (syswmmsg->msg == WM_DROPFILES)
2399 #if defined(TARGET_SDL2)
2400 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2402 HDROP hdrop = (HDROP)syswmmsg->wParam;
2406 printf("::: SDL_SYSWMEVENT:\n");
2408 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2410 for (i = 0; i < num_files; i++)
2412 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2413 char buffer[buffer_len + 1];
2415 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2417 printf("::: - '%s'\n", buffer);
2420 #if defined(TARGET_SDL2)
2421 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2423 DragFinish((HDROP)syswmmsg->wParam);
2431 /* ========================================================================= */
2432 /* joystick functions */
2433 /* ========================================================================= */
2435 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2436 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2437 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2439 static boolean SDLOpenJoystick(int nr)
2441 if (nr < 0 || nr > MAX_PLAYERS)
2444 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2447 static void SDLCloseJoystick(int nr)
2449 if (nr < 0 || nr > MAX_PLAYERS)
2452 SDL_JoystickClose(sdl_joystick[nr]);
2454 sdl_joystick[nr] = NULL;
2457 static boolean SDLCheckJoystickOpened(int nr)
2459 if (nr < 0 || nr > MAX_PLAYERS)
2462 #if defined(TARGET_SDL2)
2463 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2465 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2469 void HandleJoystickEvent(Event *event)
2473 case SDL_JOYAXISMOTION:
2474 if (event->jaxis.axis < 2)
2475 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2478 case SDL_JOYBUTTONDOWN:
2479 if (event->jbutton.button < 2)
2480 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2483 case SDL_JOYBUTTONUP:
2484 if (event->jbutton.button < 2)
2485 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2493 void SDLInitJoysticks()
2495 static boolean sdl_joystick_subsystem_initialized = FALSE;
2496 boolean print_warning = !sdl_joystick_subsystem_initialized;
2499 if (!sdl_joystick_subsystem_initialized)
2501 sdl_joystick_subsystem_initialized = TRUE;
2503 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2505 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2510 for (i = 0; i < MAX_PLAYERS; i++)
2512 /* get configured joystick for this player */
2513 char *device_name = setup.input[i].joy.device_name;
2514 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2516 if (joystick_nr >= SDL_NumJoysticks())
2518 if (setup.input[i].use_joystick && print_warning)
2519 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2524 /* misuse joystick file descriptor variable to store joystick number */
2525 joystick.fd[i] = joystick_nr;
2527 if (joystick_nr == -1)
2530 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2531 if (SDLCheckJoystickOpened(joystick_nr))
2532 SDLCloseJoystick(joystick_nr);
2534 if (!setup.input[i].use_joystick)
2537 if (!SDLOpenJoystick(joystick_nr))
2540 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2545 joystick.status = JOYSTICK_ACTIVATED;
2549 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2551 if (nr < 0 || nr >= MAX_PLAYERS)
2555 *x = sdl_js_axis[nr][0];
2557 *y = sdl_js_axis[nr][1];
2560 *b1 = sdl_js_button[nr][0];
2562 *b2 = sdl_js_button[nr][1];