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_DisplayFormat(surface);
346 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
348 if (new_surface == NULL)
349 Error(ERR_EXIT, "%s() failed: %s",
350 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
356 boolean SDLSetNativeSurface(SDL_Surface **surface)
358 SDL_Surface *new_surface;
360 if (surface == NULL ||
365 new_surface = SDLGetNativeSurface(*surface);
367 SDL_FreeSurface(*surface);
369 *surface = new_surface;
376 #if defined(TARGET_SDL2)
377 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
379 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
382 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
389 void SDLCreateBitmapTextures(Bitmap *bitmap)
391 #if defined(TARGET_SDL2)
396 SDL_DestroyTexture(bitmap->texture);
397 if (bitmap->texture_masked)
398 SDL_DestroyTexture(bitmap->texture_masked);
400 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
401 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
405 void SDLFreeBitmapTextures(Bitmap *bitmap)
407 #if defined(TARGET_SDL2)
412 SDL_DestroyTexture(bitmap->texture);
413 if (bitmap->texture_masked)
414 SDL_DestroyTexture(bitmap->texture_masked);
416 bitmap->texture = NULL;
417 bitmap->texture_masked = NULL;
421 void SDLInitVideoDisplay(void)
423 #if !defined(TARGET_SDL2)
424 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
425 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
427 SDL_putenv("SDL_VIDEO_CENTERED=1");
430 /* initialize SDL video */
431 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
432 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
434 /* set default SDL depth */
435 #if !defined(TARGET_SDL2)
436 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
438 video.default_depth = 32; // (how to determine video depth in SDL2?)
442 void SDLInitVideoBuffer(boolean fullscreen)
444 video.window_scaling_percent = setup.window_scaling_percent;
445 video.window_scaling_quality = setup.window_scaling_quality;
447 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
449 #if defined(TARGET_SDL2)
450 // SDL 2.0: support for (desktop) fullscreen mode available
451 video.fullscreen_available = TRUE;
453 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
454 video.fullscreen_available = FALSE;
457 /* open SDL video output device (window or fullscreen mode) */
458 if (!SDLSetVideoMode(fullscreen))
459 Error(ERR_EXIT, "setting video mode failed");
461 /* !!! SDL2 can only set the window icon if the window already exists !!! */
462 /* set window icon */
463 SDLSetWindowIcon(program.icon_filename);
465 /* set window and icon title */
466 #if defined(TARGET_SDL2)
467 SDL_SetWindowTitle(sdl_window, program.window_title);
469 SDL_WM_SetCaption(program.window_title, program.window_title);
472 /* SDL cannot directly draw to the visible video framebuffer like X11,
473 but always uses a backbuffer, which is then blitted to the visible
474 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
475 visible video framebuffer with 'SDL_Flip', if the hardware supports
476 this). Therefore do not use an additional backbuffer for drawing, but
477 use a symbolic buffer (distinguishable from the SDL backbuffer) called
478 'window', which indicates that the SDL backbuffer should be updated to
479 the visible video framebuffer when attempting to blit to it.
481 For convenience, it seems to be a good idea to create this symbolic
482 buffer 'window' at the same size as the SDL backbuffer. Although it
483 should never be drawn to directly, it would do no harm nevertheless. */
485 /* create additional (symbolic) buffer for double-buffering */
486 ReCreateBitmap(&window, video.width, video.height);
489 static boolean SDLCreateScreen(boolean fullscreen)
491 SDL_Surface *new_surface = NULL;
493 #if defined(TARGET_SDL2)
494 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
495 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
497 int surface_flags_window = SURFACE_FLAGS;
498 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
501 #if defined(TARGET_SDL2)
503 int renderer_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
505 /* If SDL_CreateRenderer() is called from within a VirtualBox Windows VM
506 _without_ enabling 2D/3D acceleration and/or guest additions installed,
507 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
508 it will try to use accelerated graphics and apparently fails miserably) */
509 int renderer_flags = SDL_RENDERER_SOFTWARE;
513 int width = video.width;
514 int height = video.height;
515 int surface_flags = (fullscreen ? surface_flags_fullscreen :
516 surface_flags_window);
518 // default window size is unscaled
519 video.window_width = video.width;
520 video.window_height = video.height;
522 #if defined(TARGET_SDL2)
524 // store if initial screen mode is fullscreen mode when changing screen size
525 video.fullscreen_initial = fullscreen;
527 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
529 video.window_width = window_scaling_factor * width;
530 video.window_height = window_scaling_factor * height;
532 if (sdl_texture_stream)
534 SDL_DestroyTexture(sdl_texture_stream);
535 sdl_texture_stream = NULL;
538 if (sdl_texture_target)
540 SDL_DestroyTexture(sdl_texture_target);
541 sdl_texture_target = NULL;
544 if (!(fullscreen && fullscreen_enabled))
548 SDL_DestroyRenderer(sdl_renderer);
554 SDL_DestroyWindow(sdl_window);
559 if (sdl_window == NULL)
560 sdl_window = SDL_CreateWindow(program.window_title,
561 SDL_WINDOWPOS_CENTERED,
562 SDL_WINDOWPOS_CENTERED,
567 if (sdl_window != NULL)
569 if (sdl_renderer == NULL)
570 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, renderer_flags);
572 if (sdl_renderer != NULL)
574 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
575 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
576 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
578 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
579 SDL_PIXELFORMAT_ARGB8888,
580 SDL_TEXTUREACCESS_STREAMING,
583 if (SDL_RenderTargetSupported(sdl_renderer))
584 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
585 SDL_PIXELFORMAT_ARGB8888,
586 SDL_TEXTUREACCESS_TARGET,
589 if (sdl_texture_stream != NULL)
591 // use SDL default values for RGB masks and no alpha channel
592 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
594 if (new_surface == NULL)
595 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
599 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
604 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
609 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
614 if (gfx.final_screen_bitmap == NULL)
615 gfx.final_screen_bitmap = CreateBitmapStruct();
617 gfx.final_screen_bitmap->width = width;
618 gfx.final_screen_bitmap->height = height;
620 gfx.final_screen_bitmap->surface =
621 SDL_SetVideoMode(width, height, video.depth, surface_flags);
623 if (gfx.final_screen_bitmap->surface != NULL)
626 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
628 if (new_surface == NULL)
629 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
632 new_surface = gfx.final_screen_bitmap->surface;
633 gfx.final_screen_bitmap = NULL;
639 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
643 #if defined(TARGET_SDL2)
644 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
645 if (new_surface != NULL)
646 fullscreen_enabled = fullscreen;
649 if (backbuffer == NULL)
650 backbuffer = CreateBitmapStruct();
652 backbuffer->width = video.width;
653 backbuffer->height = video.height;
655 if (backbuffer->surface)
656 SDL_FreeSurface(backbuffer->surface);
658 backbuffer->surface = new_surface;
660 return (new_surface != NULL);
663 boolean SDLSetVideoMode(boolean fullscreen)
665 boolean success = FALSE;
669 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
671 /* switch display to fullscreen mode, if available */
672 success = SDLCreateScreen(TRUE);
676 /* switching display to fullscreen mode failed -- do not try it again */
677 video.fullscreen_available = FALSE;
681 video.fullscreen_enabled = TRUE;
685 if ((!fullscreen && video.fullscreen_enabled) || !success)
687 /* switch display to window mode */
688 success = SDLCreateScreen(FALSE);
692 /* switching display to window mode failed -- should not happen */
696 video.fullscreen_enabled = FALSE;
697 video.window_scaling_percent = setup.window_scaling_percent;
698 video.window_scaling_quality = setup.window_scaling_quality;
700 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
704 #if defined(TARGET_SDL2)
705 SDLRedrawWindow(); // map window
709 #if defined(PLATFORM_WIN32)
710 // experimental drag and drop code
712 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
715 SDL_SysWMinfo wminfo;
717 boolean wminfo_success = FALSE;
719 SDL_VERSION(&wminfo.version);
720 #if defined(TARGET_SDL2)
722 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
724 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
729 #if defined(TARGET_SDL2)
730 hwnd = wminfo.info.win.window;
732 hwnd = wminfo.window;
735 DragAcceptFiles(hwnd, TRUE);
744 void SDLSetWindowTitle()
746 #if defined(TARGET_SDL2)
747 SDL_SetWindowTitle(sdl_window, program.window_title);
749 SDL_WM_SetCaption(program.window_title, program.window_title);
753 #if defined(TARGET_SDL2)
754 void SDLSetWindowScaling(int window_scaling_percent)
756 if (sdl_window == NULL)
759 float window_scaling_factor = (float)window_scaling_percent / 100;
760 int new_window_width = (int)(window_scaling_factor * video.width);
761 int new_window_height = (int)(window_scaling_factor * video.height);
763 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
765 video.window_scaling_percent = window_scaling_percent;
766 video.window_width = new_window_width;
767 video.window_height = new_window_height;
772 void SDLSetWindowScalingQuality(char *window_scaling_quality)
774 SDL_Texture *new_texture;
776 if (sdl_texture_stream == NULL)
779 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
781 new_texture = SDL_CreateTexture(sdl_renderer,
782 SDL_PIXELFORMAT_ARGB8888,
783 SDL_TEXTUREACCESS_STREAMING,
784 video.width, video.height);
786 if (new_texture != NULL)
788 SDL_DestroyTexture(sdl_texture_stream);
790 sdl_texture_stream = new_texture;
793 if (SDL_RenderTargetSupported(sdl_renderer))
794 new_texture = SDL_CreateTexture(sdl_renderer,
795 SDL_PIXELFORMAT_ARGB8888,
796 SDL_TEXTUREACCESS_TARGET,
797 video.width, video.height);
801 if (new_texture != NULL)
803 SDL_DestroyTexture(sdl_texture_target);
805 sdl_texture_target = new_texture;
810 video.window_scaling_quality = window_scaling_quality;
813 void SDLSetWindowFullscreen(boolean fullscreen)
815 if (sdl_window == NULL)
818 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
820 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
821 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
823 // if screen size was changed in fullscreen mode, correct desktop window size
824 if (!fullscreen && video.fullscreen_initial)
826 SDLSetWindowScaling(setup.window_scaling_percent);
827 SDL_SetWindowPosition(sdl_window,
828 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
830 video.fullscreen_initial = FALSE;
835 void SDLSetScreenRenderingMode(char *screen_rendering_mode)
837 #if defined(TARGET_SDL2)
838 video.screen_rendering_mode =
839 (strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
840 SPECIAL_RENDERING_BITMAP :
841 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
842 SPECIAL_RENDERING_TARGET:
843 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
844 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
846 video.screen_rendering_mode = SPECIAL_RENDERING_BITMAP;
850 void SDLRedrawWindow()
852 UpdateScreen_WithoutFrameDelay(NULL);
855 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
858 SDL_Surface *surface =
859 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
862 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
864 SDLSetNativeSurface(&surface);
866 bitmap->surface = surface;
869 void SDLFreeBitmapPointers(Bitmap *bitmap)
872 SDL_FreeSurface(bitmap->surface);
873 if (bitmap->surface_masked)
874 SDL_FreeSurface(bitmap->surface_masked);
876 bitmap->surface = NULL;
877 bitmap->surface_masked = NULL;
879 #if defined(TARGET_SDL2)
881 SDL_DestroyTexture(bitmap->texture);
882 if (bitmap->texture_masked)
883 SDL_DestroyTexture(bitmap->texture_masked);
885 bitmap->texture = NULL;
886 bitmap->texture_masked = NULL;
890 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
891 int src_x, int src_y, int width, int height,
892 int dst_x, int dst_y, int mask_mode)
894 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
895 SDL_Rect src_rect, dst_rect;
907 // if (src_bitmap != backbuffer || dst_bitmap != window)
908 if (!(src_bitmap == backbuffer && dst_bitmap == window))
909 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
910 src_bitmap->surface_masked : src_bitmap->surface),
911 &src_rect, real_dst_bitmap->surface, &dst_rect);
913 if (dst_bitmap == window)
914 UpdateScreen_WithFrameDelay(&dst_rect);
917 void SDLBlitTexture(Bitmap *bitmap,
918 int src_x, int src_y, int width, int height,
919 int dst_x, int dst_y, int mask_mode)
921 #if defined(TARGET_SDL2)
922 SDL_Texture *texture;
927 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
942 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
946 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
949 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
957 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
959 if (dst_bitmap == window)
960 UpdateScreen_WithFrameDelay(&rect);
963 void PrepareFadeBitmap(int draw_target)
965 Bitmap *fade_bitmap =
966 (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
967 draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
969 if (fade_bitmap == NULL)
972 // copy backbuffer to fading buffer
973 BlitBitmap(backbuffer, fade_bitmap, 0, 0, gfx.win_xsize, gfx.win_ysize, 0, 0);
975 // add border and animations to fading buffer
976 FinalizeScreen(draw_target);
979 void SDLFadeRectangle(int x, int y, int width, int height,
980 int fade_mode, int fade_delay, int post_delay,
981 void (*draw_border_function)(void))
983 SDL_Surface *surface_backup = gfx.fade_bitmap_backup->surface;
984 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
985 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
986 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
987 SDL_Surface *surface_screen = backbuffer->surface;
988 SDL_Rect src_rect, dst_rect;
990 int src_x = x, src_y = y;
991 int dst_x = x, dst_y = y;
992 unsigned int time_last, time_current;
994 // store function for drawing global masked border
995 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
997 // deactivate drawing of global border while fading, if needed
998 if (draw_border_function == NULL)
999 gfx.draw_global_border_function = NULL;
1004 src_rect.h = height;
1008 dst_rect.w = width; /* (ignored) */
1009 dst_rect.h = height; /* (ignored) */
1011 dst_rect2 = dst_rect;
1013 // before fading in, store backbuffer (without animation graphics)
1014 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
1015 SDL_BlitSurface(surface_screen, &dst_rect, surface_backup, &src_rect);
1017 /* copy source and target surfaces to temporary surfaces for fading */
1018 if (fade_mode & FADE_TYPE_TRANSFORM)
1020 // (source and target fading buffer already prepared)
1022 else if (fade_mode & FADE_TYPE_FADE_IN)
1024 // (target fading buffer already prepared)
1025 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1027 else /* FADE_TYPE_FADE_OUT */
1029 // (source fading buffer already prepared)
1030 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1033 time_current = SDL_GetTicks();
1035 if (fade_mode == FADE_MODE_MELT)
1037 boolean done = FALSE;
1038 int melt_pixels = 2;
1039 int melt_columns = width / melt_pixels;
1040 int ypos[melt_columns];
1041 int max_steps = height / 8 + 32;
1046 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1048 SDLSetAlpha(surface_target, FALSE, 0); /* disable alpha blending */
1050 ypos[0] = -GetSimpleRandom(16);
1052 for (i = 1 ; i < melt_columns; i++)
1054 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1056 ypos[i] = ypos[i - 1] + r;
1069 time_last = time_current;
1070 time_current = SDL_GetTicks();
1071 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1072 steps_final = MIN(MAX(0, steps), max_steps);
1076 done = (steps_done >= steps_final);
1078 for (i = 0 ; i < melt_columns; i++)
1086 else if (ypos[i] < height)
1091 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1093 if (ypos[i] + dy >= height)
1094 dy = height - ypos[i];
1096 /* copy part of (appearing) target surface to upper area */
1097 src_rect.x = src_x + i * melt_pixels;
1098 // src_rect.y = src_y + ypos[i];
1100 src_rect.w = melt_pixels;
1102 src_rect.h = ypos[i] + dy;
1104 dst_rect.x = dst_x + i * melt_pixels;
1105 // dst_rect.y = dst_y + ypos[i];
1108 if (steps_done >= steps_final)
1109 SDL_BlitSurface(surface_target, &src_rect,
1110 surface_screen, &dst_rect);
1114 /* copy part of (disappearing) source surface to lower area */
1115 src_rect.x = src_x + i * melt_pixels;
1117 src_rect.w = melt_pixels;
1118 src_rect.h = height - ypos[i];
1120 dst_rect.x = dst_x + i * melt_pixels;
1121 dst_rect.y = dst_y + ypos[i];
1123 if (steps_done >= steps_final)
1124 SDL_BlitSurface(surface_source, &src_rect,
1125 surface_screen, &dst_rect);
1131 src_rect.x = src_x + i * melt_pixels;
1133 src_rect.w = melt_pixels;
1134 src_rect.h = height;
1136 dst_rect.x = dst_x + i * melt_pixels;
1139 if (steps_done >= steps_final)
1140 SDL_BlitSurface(surface_target, &src_rect,
1141 surface_screen, &dst_rect);
1145 if (steps_done >= steps_final)
1147 if (draw_border_function != NULL)
1148 draw_border_function();
1150 UpdateScreen_WithFrameDelay(&dst_rect2);
1154 else if (fade_mode == FADE_MODE_CURTAIN)
1158 int xx_size = width / 2;
1160 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1162 SDLSetAlpha(surface_source, FALSE, 0); /* disable alpha blending */
1164 for (xx = 0; xx < xx_size;)
1166 time_last = time_current;
1167 time_current = SDL_GetTicks();
1168 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1169 xx_final = MIN(MAX(0, xx), xx_size);
1174 src_rect.h = height;
1179 /* draw new (target) image to screen buffer */
1180 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1182 if (xx_final < xx_size)
1184 src_rect.w = xx_size - xx_final;
1185 src_rect.h = height;
1187 /* draw old (source) image to screen buffer (left side) */
1189 src_rect.x = src_x + xx_final;
1192 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1194 /* draw old (source) image to screen buffer (right side) */
1196 src_rect.x = src_x + xx_size;
1197 dst_rect.x = dst_x + xx_size + xx_final;
1199 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1202 if (draw_border_function != NULL)
1203 draw_border_function();
1205 /* only update the region of the screen that is affected from fading */
1206 UpdateScreen_WithFrameDelay(&dst_rect2);
1209 else /* fading in, fading out or cross-fading */
1214 for (alpha = 0.0; alpha < 255.0;)
1216 time_last = time_current;
1217 time_current = SDL_GetTicks();
1218 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1219 alpha_final = MIN(MAX(0, alpha), 255);
1221 /* draw existing (source) image to screen buffer */
1222 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1224 /* draw new (target) image to screen buffer using alpha blending */
1225 SDLSetAlpha(surface_target, TRUE, alpha_final);
1226 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1228 if (draw_border_function != NULL)
1229 draw_border_function();
1231 /* only update the region of the screen that is affected from fading */
1232 UpdateScreen_WithFrameDelay(&dst_rect);
1238 unsigned int time_post_delay;
1240 time_current = SDL_GetTicks();
1241 time_post_delay = time_current + post_delay;
1243 while (time_current < time_post_delay)
1245 // updating the screen contains waiting for frame delay (non-busy)
1246 UpdateScreen_WithFrameDelay(NULL);
1248 time_current = SDL_GetTicks();
1252 // restore function for drawing global masked border
1253 gfx.draw_global_border_function = draw_global_border_function;
1255 // after fading in, restore backbuffer (without animation graphics)
1256 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
1257 SDL_BlitSurface(surface_backup, &dst_rect, surface_screen, &src_rect);
1260 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1261 int to_x, int to_y, Uint32 color)
1263 SDL_Surface *surface = dst_bitmap->surface;
1267 swap_numbers(&from_x, &to_x);
1270 swap_numbers(&from_y, &to_y);
1274 rect.w = (to_x - from_x + 1);
1275 rect.h = (to_y - from_y + 1);
1277 SDL_FillRect(surface, &rect, color);
1280 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1281 int to_x, int to_y, Uint32 color)
1283 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1286 #if ENABLE_UNUSED_CODE
1287 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1288 int num_points, Uint32 color)
1293 for (i = 0; i < num_points - 1; i++)
1295 for (x = 0; x < line_width; x++)
1297 for (y = 0; y < line_width; y++)
1299 int dx = x - line_width / 2;
1300 int dy = y - line_width / 2;
1302 if ((x == 0 && y == 0) ||
1303 (x == 0 && y == line_width - 1) ||
1304 (x == line_width - 1 && y == 0) ||
1305 (x == line_width - 1 && y == line_width - 1))
1308 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1309 points[i+1].x + dx, points[i+1].y + dy, color);
1316 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1318 SDL_Surface *surface = src_bitmap->surface;
1320 switch (surface->format->BytesPerPixel)
1322 case 1: /* assuming 8-bpp */
1324 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1328 case 2: /* probably 15-bpp or 16-bpp */
1330 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1334 case 3: /* slow 24-bpp mode; usually not used */
1336 /* does this work? */
1337 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1341 shift = surface->format->Rshift;
1342 color |= *(pix + shift / 8) >> shift;
1343 shift = surface->format->Gshift;
1344 color |= *(pix + shift / 8) >> shift;
1345 shift = surface->format->Bshift;
1346 color |= *(pix + shift / 8) >> shift;
1352 case 4: /* probably 32-bpp */
1354 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1363 /* ========================================================================= */
1364 /* The following functions were taken from the SGE library */
1365 /* (SDL Graphics Extension Library) by Anders Lindström */
1366 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1367 /* ========================================================================= */
1369 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1371 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1373 switch (surface->format->BytesPerPixel)
1377 /* Assuming 8-bpp */
1378 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1384 /* Probably 15-bpp or 16-bpp */
1385 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1391 /* Slow 24-bpp mode, usually not used */
1395 /* Gack - slow, but endian correct */
1396 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1397 shift = surface->format->Rshift;
1398 *(pix+shift/8) = color>>shift;
1399 shift = surface->format->Gshift;
1400 *(pix+shift/8) = color>>shift;
1401 shift = surface->format->Bshift;
1402 *(pix+shift/8) = color>>shift;
1408 /* Probably 32-bpp */
1409 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1416 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1417 Uint8 R, Uint8 G, Uint8 B)
1419 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1422 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1424 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1427 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1429 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1432 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1437 /* Gack - slow, but endian correct */
1438 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1439 shift = surface->format->Rshift;
1440 *(pix+shift/8) = color>>shift;
1441 shift = surface->format->Gshift;
1442 *(pix+shift/8) = color>>shift;
1443 shift = surface->format->Bshift;
1444 *(pix+shift/8) = color>>shift;
1447 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1449 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1452 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1454 switch (dest->format->BytesPerPixel)
1457 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1461 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1465 _PutPixel24(dest,x,y,color);
1469 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1474 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1476 if (SDL_MUSTLOCK(surface))
1478 if (SDL_LockSurface(surface) < 0)
1484 _PutPixel(surface, x, y, color);
1486 if (SDL_MUSTLOCK(surface))
1488 SDL_UnlockSurface(surface);
1492 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1493 Uint8 r, Uint8 g, Uint8 b)
1495 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1498 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1500 if (y >= 0 && y <= dest->h - 1)
1502 switch (dest->format->BytesPerPixel)
1505 return y*dest->pitch;
1509 return y*dest->pitch/2;
1513 return y*dest->pitch;
1517 return y*dest->pitch/4;
1525 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1527 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1529 switch (surface->format->BytesPerPixel)
1533 /* Assuming 8-bpp */
1534 *((Uint8 *)surface->pixels + ypitch + x) = color;
1540 /* Probably 15-bpp or 16-bpp */
1541 *((Uint16 *)surface->pixels + ypitch + x) = color;
1547 /* Slow 24-bpp mode, usually not used */
1551 /* Gack - slow, but endian correct */
1552 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1553 shift = surface->format->Rshift;
1554 *(pix+shift/8) = color>>shift;
1555 shift = surface->format->Gshift;
1556 *(pix+shift/8) = color>>shift;
1557 shift = surface->format->Bshift;
1558 *(pix+shift/8) = color>>shift;
1564 /* Probably 32-bpp */
1565 *((Uint32 *)surface->pixels + ypitch + x) = color;
1572 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1577 if (SDL_MUSTLOCK(Surface))
1579 if (SDL_LockSurface(Surface) < 0)
1592 /* Do the clipping */
1593 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1597 if (x2 > Surface->w - 1)
1598 x2 = Surface->w - 1;
1605 SDL_FillRect(Surface, &l, Color);
1607 if (SDL_MUSTLOCK(Surface))
1609 SDL_UnlockSurface(Surface);
1613 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1614 Uint8 R, Uint8 G, Uint8 B)
1616 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1619 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1630 /* Do the clipping */
1631 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1635 if (x2 > Surface->w - 1)
1636 x2 = Surface->w - 1;
1643 SDL_FillRect(Surface, &l, Color);
1646 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1651 if (SDL_MUSTLOCK(Surface))
1653 if (SDL_LockSurface(Surface) < 0)
1666 /* Do the clipping */
1667 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1671 if (y2 > Surface->h - 1)
1672 y2 = Surface->h - 1;
1679 SDL_FillRect(Surface, &l, Color);
1681 if (SDL_MUSTLOCK(Surface))
1683 SDL_UnlockSurface(Surface);
1687 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1688 Uint8 R, Uint8 G, Uint8 B)
1690 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1693 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1704 /* Do the clipping */
1705 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1709 if (y2 > Surface->h - 1)
1710 y2 = Surface->h - 1;
1717 SDL_FillRect(Surface, &l, Color);
1720 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1721 Sint16 x2, Sint16 y2, Uint32 Color,
1722 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1725 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1730 sdx = (dx < 0) ? -1 : 1;
1731 sdy = (dy < 0) ? -1 : 1;
1743 for (x = 0; x < dx; x++)
1745 Callback(Surface, px, py, Color);
1759 for (y = 0; y < dy; y++)
1761 Callback(Surface, px, py, Color);
1775 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1776 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1777 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1780 sge_DoLine(Surface, X1, Y1, X2, Y2,
1781 SDL_MapRGB(Surface->format, R, G, B), Callback);
1784 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1787 if (SDL_MUSTLOCK(Surface))
1789 if (SDL_LockSurface(Surface) < 0)
1794 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1796 /* unlock the display */
1797 if (SDL_MUSTLOCK(Surface))
1799 SDL_UnlockSurface(Surface);
1803 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1804 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1806 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1809 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1811 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1816 -----------------------------------------------------------------------------
1817 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1818 -----------------------------------------------------------------------------
1821 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1822 int width, int height, Uint32 color)
1826 for (y = src_y; y < src_y + height; y++)
1828 for (x = src_x; x < src_x + width; x++)
1830 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1832 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1837 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1838 int src_x, int src_y, int width, int height,
1839 int dst_x, int dst_y)
1843 for (y = 0; y < height; y++)
1845 for (x = 0; x < width; x++)
1847 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1849 if (pixel != BLACK_PIXEL)
1850 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1856 /* ========================================================================= */
1857 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1858 /* (Rotozoomer) by Andreas Schiffler */
1859 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1860 /* ========================================================================= */
1863 -----------------------------------------------------------------------------
1866 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1867 -----------------------------------------------------------------------------
1878 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1881 tColorRGBA *sp, *csp, *dp;
1885 sp = csp = (tColorRGBA *) src->pixels;
1886 dp = (tColorRGBA *) dst->pixels;
1887 dgap = dst->pitch - dst->w * 4;
1889 for (y = 0; y < dst->h; y++)
1893 for (x = 0; x < dst->w; x++)
1895 tColorRGBA *sp0 = sp;
1896 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1897 tColorRGBA *sp00 = &sp0[0];
1898 tColorRGBA *sp01 = &sp0[1];
1899 tColorRGBA *sp10 = &sp1[0];
1900 tColorRGBA *sp11 = &sp1[1];
1903 /* create new color pixel from all four source color pixels */
1904 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1905 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1906 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1907 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1912 /* advance source pointers */
1915 /* advance destination pointer */
1919 /* advance source pointer */
1920 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1922 /* advance destination pointers */
1923 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1929 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1931 int x, y, *sax, *say, *csax, *csay;
1933 tColorRGBA *sp, *csp, *csp0, *dp;
1936 /* use specialized zoom function when scaling down to exactly half size */
1937 if (src->w == 2 * dst->w &&
1938 src->h == 2 * dst->h)
1939 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1941 /* variable setup */
1942 sx = (float) src->w / (float) dst->w;
1943 sy = (float) src->h / (float) dst->h;
1945 /* allocate memory for row increments */
1946 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1947 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1949 /* precalculate row increments */
1950 for (x = 0; x <= dst->w; x++)
1951 *csax++ = (int)(sx * x);
1953 for (y = 0; y <= dst->h; y++)
1954 *csay++ = (int)(sy * y);
1957 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1958 dp = (tColorRGBA *) dst->pixels;
1959 dgap = dst->pitch - dst->w * 4;
1962 for (y = 0; y < dst->h; y++)
1967 for (x = 0; x < dst->w; x++)
1972 /* advance source pointers */
1976 /* advance destination pointer */
1980 /* advance source pointer */
1982 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1984 /* advance destination pointers */
1985 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1995 -----------------------------------------------------------------------------
1998 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1999 -----------------------------------------------------------------------------
2002 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2004 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2005 Uint8 *sp, *dp, *csp;
2008 /* variable setup */
2009 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2010 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2012 /* allocate memory for row increments */
2013 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2014 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2016 /* precalculate row increments */
2019 for (x = 0; x < dst->w; x++)
2022 *csax = (csx >> 16);
2029 for (y = 0; y < dst->h; y++)
2032 *csay = (csy >> 16);
2039 for (x = 0; x < dst->w; x++)
2047 for (y = 0; y < dst->h; y++)
2054 sp = csp = (Uint8 *) src->pixels;
2055 dp = (Uint8 *) dst->pixels;
2056 dgap = dst->pitch - dst->w;
2060 for (y = 0; y < dst->h; y++)
2064 for (x = 0; x < dst->w; x++)
2069 /* advance source pointers */
2073 /* advance destination pointer */
2077 /* advance source pointer (for row) */
2078 csp += ((*csay) * src->pitch);
2081 /* advance destination pointers */
2092 -----------------------------------------------------------------------------
2095 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2096 'zoomx' and 'zoomy' are scaling factors for width and height.
2097 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2098 into a 32bit RGBA format on the fly.
2099 -----------------------------------------------------------------------------
2102 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2104 SDL_Surface *zoom_src = NULL;
2105 SDL_Surface *zoom_dst = NULL;
2106 boolean is_converted = FALSE;
2113 /* determine if source surface is 32 bit or 8 bit */
2114 is_32bit = (src->format->BitsPerPixel == 32);
2116 if (is_32bit || src->format->BitsPerPixel == 8)
2118 /* use source surface 'as is' */
2123 /* new source surface is 32 bit with a defined RGB ordering */
2124 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2125 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2126 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2128 is_converted = TRUE;
2131 /* allocate surface to completely contain the zoomed surface */
2134 /* target surface is 32 bit with source RGBA/ABGR ordering */
2135 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2136 zoom_src->format->Rmask,
2137 zoom_src->format->Gmask,
2138 zoom_src->format->Bmask, 0);
2142 /* target surface is 8 bit */
2143 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2147 /* lock source surface */
2148 SDL_LockSurface(zoom_src);
2150 /* check which kind of surface we have */
2153 /* call the 32 bit transformation routine to do the zooming */
2154 zoomSurfaceRGBA(zoom_src, zoom_dst);
2159 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2160 zoom_dst->format->palette->colors[i] =
2161 zoom_src->format->palette->colors[i];
2162 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2164 /* call the 8 bit transformation routine to do the zooming */
2165 zoomSurfaceY(zoom_src, zoom_dst);
2168 /* unlock source surface */
2169 SDL_UnlockSurface(zoom_src);
2171 /* free temporary surface */
2173 SDL_FreeSurface(zoom_src);
2175 /* return destination surface */
2179 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2181 Bitmap *dst_bitmap = CreateBitmapStruct();
2182 SDL_Surface **dst_surface = &dst_bitmap->surface;
2184 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2185 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2187 dst_bitmap->width = dst_width;
2188 dst_bitmap->height = dst_height;
2190 /* create zoomed temporary surface from source surface */
2191 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2193 /* create native format destination surface from zoomed temporary surface */
2194 SDLSetNativeSurface(dst_surface);
2200 /* ========================================================================= */
2201 /* load image to bitmap */
2202 /* ========================================================================= */
2204 Bitmap *SDLLoadImage(char *filename)
2206 Bitmap *new_bitmap = CreateBitmapStruct();
2207 SDL_Surface *sdl_image_tmp;
2209 print_timestamp_init("SDLLoadImage");
2211 print_timestamp_time(getBaseNamePtr(filename));
2213 /* load image to temporary surface */
2214 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2216 SetError("IMG_Load(): %s", SDL_GetError());
2221 print_timestamp_time("IMG_Load");
2223 UPDATE_BUSY_STATE();
2225 /* create native non-transparent surface for current image */
2226 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2228 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2233 print_timestamp_time("SDL_DisplayFormat (opaque)");
2235 UPDATE_BUSY_STATE();
2237 /* create native transparent surface for current image */
2238 if (sdl_image_tmp->format->Amask == 0)
2239 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2240 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2242 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2244 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2249 print_timestamp_time("SDL_DisplayFormat (masked)");
2251 UPDATE_BUSY_STATE();
2253 /* free temporary surface */
2254 SDL_FreeSurface(sdl_image_tmp);
2256 new_bitmap->width = new_bitmap->surface->w;
2257 new_bitmap->height = new_bitmap->surface->h;
2259 print_timestamp_done("SDLLoadImage");
2265 /* ------------------------------------------------------------------------- */
2266 /* custom cursor fuctions */
2267 /* ------------------------------------------------------------------------- */
2269 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2271 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2272 cursor_info->width, cursor_info->height,
2273 cursor_info->hot_x, cursor_info->hot_y);
2276 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2278 static struct MouseCursorInfo *last_cursor_info = NULL;
2279 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2280 static SDL_Cursor *cursor_default = NULL;
2281 static SDL_Cursor *cursor_current = NULL;
2283 /* if invoked for the first time, store the SDL default cursor */
2284 if (cursor_default == NULL)
2285 cursor_default = SDL_GetCursor();
2287 /* only create new cursor if cursor info (custom only) has changed */
2288 if (cursor_info != NULL && cursor_info != last_cursor_info)
2290 cursor_current = create_cursor(cursor_info);
2291 last_cursor_info = cursor_info;
2294 /* only set new cursor if cursor info (custom or NULL) has changed */
2295 if (cursor_info != last_cursor_info2)
2296 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2298 last_cursor_info2 = cursor_info;
2302 /* ========================================================================= */
2303 /* audio functions */
2304 /* ========================================================================= */
2306 void SDLOpenAudio(void)
2308 #if !defined(TARGET_SDL2)
2309 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2310 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2313 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2315 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2319 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2320 AUDIO_NUM_CHANNELS_STEREO,
2321 setup.system.audio_fragment_size) < 0)
2323 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2327 audio.sound_available = TRUE;
2328 audio.music_available = TRUE;
2329 audio.loops_available = TRUE;
2330 audio.sound_enabled = TRUE;
2332 /* set number of available mixer channels */
2333 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2334 audio.music_channel = MUSIC_CHANNEL;
2335 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2337 Mixer_InitChannels();
2340 void SDLCloseAudio(void)
2343 Mix_HaltChannel(-1);
2346 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2350 /* ========================================================================= */
2351 /* event functions */
2352 /* ========================================================================= */
2354 void SDLNextEvent(Event *event)
2356 SDL_WaitEvent(event);
2359 void SDLHandleWindowManagerEvent(Event *event)
2362 #if defined(PLATFORM_WIN32)
2363 // experimental drag and drop code
2365 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2366 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2368 #if defined(TARGET_SDL2)
2369 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2371 if (syswmmsg->msg == WM_DROPFILES)
2374 #if defined(TARGET_SDL2)
2375 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2377 HDROP hdrop = (HDROP)syswmmsg->wParam;
2381 printf("::: SDL_SYSWMEVENT:\n");
2383 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2385 for (i = 0; i < num_files; i++)
2387 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2388 char buffer[buffer_len + 1];
2390 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2392 printf("::: - '%s'\n", buffer);
2395 #if defined(TARGET_SDL2)
2396 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2398 DragFinish((HDROP)syswmmsg->wParam);
2406 /* ========================================================================= */
2407 /* joystick functions */
2408 /* ========================================================================= */
2410 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2411 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2412 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2414 static boolean SDLOpenJoystick(int nr)
2416 if (nr < 0 || nr > MAX_PLAYERS)
2419 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2422 static void SDLCloseJoystick(int nr)
2424 if (nr < 0 || nr > MAX_PLAYERS)
2427 SDL_JoystickClose(sdl_joystick[nr]);
2429 sdl_joystick[nr] = NULL;
2432 static boolean SDLCheckJoystickOpened(int nr)
2434 if (nr < 0 || nr > MAX_PLAYERS)
2437 #if defined(TARGET_SDL2)
2438 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2440 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2444 void HandleJoystickEvent(Event *event)
2448 case SDL_JOYAXISMOTION:
2449 if (event->jaxis.axis < 2)
2450 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2453 case SDL_JOYBUTTONDOWN:
2454 if (event->jbutton.button < 2)
2455 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2458 case SDL_JOYBUTTONUP:
2459 if (event->jbutton.button < 2)
2460 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2468 void SDLInitJoysticks()
2470 static boolean sdl_joystick_subsystem_initialized = FALSE;
2471 boolean print_warning = !sdl_joystick_subsystem_initialized;
2474 if (!sdl_joystick_subsystem_initialized)
2476 sdl_joystick_subsystem_initialized = TRUE;
2478 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2480 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2485 for (i = 0; i < MAX_PLAYERS; i++)
2487 /* get configured joystick for this player */
2488 char *device_name = setup.input[i].joy.device_name;
2489 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2491 if (joystick_nr >= SDL_NumJoysticks())
2493 if (setup.input[i].use_joystick && print_warning)
2494 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2499 /* misuse joystick file descriptor variable to store joystick number */
2500 joystick.fd[i] = joystick_nr;
2502 if (joystick_nr == -1)
2505 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2506 if (SDLCheckJoystickOpened(joystick_nr))
2507 SDLCloseJoystick(joystick_nr);
2509 if (!setup.input[i].use_joystick)
2512 if (!SDLOpenJoystick(joystick_nr))
2515 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2520 joystick.status = JOYSTICK_ACTIVATED;
2524 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2526 if (nr < 0 || nr >= MAX_PLAYERS)
2530 *x = sdl_js_axis[nr][0];
2532 *y = sdl_js_axis[nr][1];
2535 *b1 = sdl_js_button[nr][0];
2537 *b2 = sdl_js_button[nr][1];