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);
1047 #if defined(TARGET_SDL2)
1048 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1050 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1053 ypos[0] = -GetSimpleRandom(16);
1055 for (i = 1 ; i < melt_columns; i++)
1057 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1059 ypos[i] = ypos[i - 1] + r;
1072 time_last = time_current;
1073 time_current = SDL_GetTicks();
1074 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1075 steps_final = MIN(MAX(0, steps), max_steps);
1079 done = (steps_done >= steps_final);
1081 for (i = 0 ; i < melt_columns; i++)
1089 else if (ypos[i] < height)
1094 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1096 if (ypos[i] + dy >= height)
1097 dy = height - ypos[i];
1099 /* copy part of (appearing) target surface to upper area */
1100 src_rect.x = src_x + i * melt_pixels;
1101 // src_rect.y = src_y + ypos[i];
1103 src_rect.w = melt_pixels;
1105 src_rect.h = ypos[i] + dy;
1107 dst_rect.x = dst_x + i * melt_pixels;
1108 // dst_rect.y = dst_y + ypos[i];
1111 if (steps_done >= steps_final)
1112 SDL_BlitSurface(surface_target, &src_rect,
1113 surface_screen, &dst_rect);
1117 /* copy part of (disappearing) source surface to lower area */
1118 src_rect.x = src_x + i * melt_pixels;
1120 src_rect.w = melt_pixels;
1121 src_rect.h = height - ypos[i];
1123 dst_rect.x = dst_x + i * melt_pixels;
1124 dst_rect.y = dst_y + ypos[i];
1126 if (steps_done >= steps_final)
1127 SDL_BlitSurface(surface_source, &src_rect,
1128 surface_screen, &dst_rect);
1134 src_rect.x = src_x + i * melt_pixels;
1136 src_rect.w = melt_pixels;
1137 src_rect.h = height;
1139 dst_rect.x = dst_x + i * melt_pixels;
1142 if (steps_done >= steps_final)
1143 SDL_BlitSurface(surface_target, &src_rect,
1144 surface_screen, &dst_rect);
1148 if (steps_done >= steps_final)
1150 if (draw_border_function != NULL)
1151 draw_border_function();
1153 UpdateScreen_WithFrameDelay(&dst_rect2);
1157 else if (fade_mode == FADE_MODE_CURTAIN)
1161 int xx_size = width / 2;
1163 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1164 #if defined(TARGET_SDL2)
1165 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1167 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1170 for (xx = 0; xx < xx_size;)
1172 time_last = time_current;
1173 time_current = SDL_GetTicks();
1174 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1175 xx_final = MIN(MAX(0, xx), xx_size);
1180 src_rect.h = height;
1185 /* draw new (target) image to screen buffer */
1186 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1188 if (xx_final < xx_size)
1190 src_rect.w = xx_size - xx_final;
1191 src_rect.h = height;
1193 /* draw old (source) image to screen buffer (left side) */
1195 src_rect.x = src_x + xx_final;
1198 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1200 /* draw old (source) image to screen buffer (right side) */
1202 src_rect.x = src_x + xx_size;
1203 dst_rect.x = dst_x + xx_size + xx_final;
1205 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1208 if (draw_border_function != NULL)
1209 draw_border_function();
1211 /* only update the region of the screen that is affected from fading */
1212 UpdateScreen_WithFrameDelay(&dst_rect2);
1215 else /* fading in, fading out or cross-fading */
1220 for (alpha = 0.0; alpha < 255.0;)
1222 time_last = time_current;
1223 time_current = SDL_GetTicks();
1224 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1225 alpha_final = MIN(MAX(0, alpha), 255);
1227 /* draw existing (source) image to screen buffer */
1228 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1230 /* draw new (target) image to screen buffer using alpha blending */
1231 #if defined(TARGET_SDL2)
1232 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1233 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1235 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1237 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1239 if (draw_border_function != NULL)
1240 draw_border_function();
1242 /* only update the region of the screen that is affected from fading */
1243 UpdateScreen_WithFrameDelay(&dst_rect);
1249 unsigned int time_post_delay;
1251 time_current = SDL_GetTicks();
1252 time_post_delay = time_current + post_delay;
1254 while (time_current < time_post_delay)
1256 // updating the screen contains waiting for frame delay (non-busy)
1257 UpdateScreen_WithFrameDelay(NULL);
1259 time_current = SDL_GetTicks();
1263 // restore function for drawing global masked border
1264 gfx.draw_global_border_function = draw_global_border_function;
1266 // after fading in, restore backbuffer (without animation graphics)
1267 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
1268 SDL_BlitSurface(surface_backup, &dst_rect, surface_screen, &src_rect);
1271 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1272 int to_x, int to_y, Uint32 color)
1274 SDL_Surface *surface = dst_bitmap->surface;
1278 swap_numbers(&from_x, &to_x);
1281 swap_numbers(&from_y, &to_y);
1285 rect.w = (to_x - from_x + 1);
1286 rect.h = (to_y - from_y + 1);
1288 SDL_FillRect(surface, &rect, color);
1291 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1292 int to_x, int to_y, Uint32 color)
1294 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1297 #if ENABLE_UNUSED_CODE
1298 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1299 int num_points, Uint32 color)
1304 for (i = 0; i < num_points - 1; i++)
1306 for (x = 0; x < line_width; x++)
1308 for (y = 0; y < line_width; y++)
1310 int dx = x - line_width / 2;
1311 int dy = y - line_width / 2;
1313 if ((x == 0 && y == 0) ||
1314 (x == 0 && y == line_width - 1) ||
1315 (x == line_width - 1 && y == 0) ||
1316 (x == line_width - 1 && y == line_width - 1))
1319 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1320 points[i+1].x + dx, points[i+1].y + dy, color);
1327 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1329 SDL_Surface *surface = src_bitmap->surface;
1331 switch (surface->format->BytesPerPixel)
1333 case 1: /* assuming 8-bpp */
1335 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1339 case 2: /* probably 15-bpp or 16-bpp */
1341 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1345 case 3: /* slow 24-bpp mode; usually not used */
1347 /* does this work? */
1348 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1352 shift = surface->format->Rshift;
1353 color |= *(pix + shift / 8) >> shift;
1354 shift = surface->format->Gshift;
1355 color |= *(pix + shift / 8) >> shift;
1356 shift = surface->format->Bshift;
1357 color |= *(pix + shift / 8) >> shift;
1363 case 4: /* probably 32-bpp */
1365 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1374 /* ========================================================================= */
1375 /* The following functions were taken from the SGE library */
1376 /* (SDL Graphics Extension Library) by Anders Lindström */
1377 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1378 /* ========================================================================= */
1380 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1382 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1384 switch (surface->format->BytesPerPixel)
1388 /* Assuming 8-bpp */
1389 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1395 /* Probably 15-bpp or 16-bpp */
1396 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1402 /* Slow 24-bpp mode, usually not used */
1406 /* Gack - slow, but endian correct */
1407 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1408 shift = surface->format->Rshift;
1409 *(pix+shift/8) = color>>shift;
1410 shift = surface->format->Gshift;
1411 *(pix+shift/8) = color>>shift;
1412 shift = surface->format->Bshift;
1413 *(pix+shift/8) = color>>shift;
1419 /* Probably 32-bpp */
1420 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1427 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1428 Uint8 R, Uint8 G, Uint8 B)
1430 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1433 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1435 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1438 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1440 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1443 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1448 /* Gack - slow, but endian correct */
1449 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1450 shift = surface->format->Rshift;
1451 *(pix+shift/8) = color>>shift;
1452 shift = surface->format->Gshift;
1453 *(pix+shift/8) = color>>shift;
1454 shift = surface->format->Bshift;
1455 *(pix+shift/8) = color>>shift;
1458 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1460 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1463 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1465 switch (dest->format->BytesPerPixel)
1468 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1472 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1476 _PutPixel24(dest,x,y,color);
1480 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1485 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1487 if (SDL_MUSTLOCK(surface))
1489 if (SDL_LockSurface(surface) < 0)
1495 _PutPixel(surface, x, y, color);
1497 if (SDL_MUSTLOCK(surface))
1499 SDL_UnlockSurface(surface);
1503 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1504 Uint8 r, Uint8 g, Uint8 b)
1506 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1509 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1511 if (y >= 0 && y <= dest->h - 1)
1513 switch (dest->format->BytesPerPixel)
1516 return y*dest->pitch;
1520 return y*dest->pitch/2;
1524 return y*dest->pitch;
1528 return y*dest->pitch/4;
1536 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1538 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1540 switch (surface->format->BytesPerPixel)
1544 /* Assuming 8-bpp */
1545 *((Uint8 *)surface->pixels + ypitch + x) = color;
1551 /* Probably 15-bpp or 16-bpp */
1552 *((Uint16 *)surface->pixels + ypitch + x) = color;
1558 /* Slow 24-bpp mode, usually not used */
1562 /* Gack - slow, but endian correct */
1563 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1564 shift = surface->format->Rshift;
1565 *(pix+shift/8) = color>>shift;
1566 shift = surface->format->Gshift;
1567 *(pix+shift/8) = color>>shift;
1568 shift = surface->format->Bshift;
1569 *(pix+shift/8) = color>>shift;
1575 /* Probably 32-bpp */
1576 *((Uint32 *)surface->pixels + ypitch + x) = color;
1583 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1588 if (SDL_MUSTLOCK(Surface))
1590 if (SDL_LockSurface(Surface) < 0)
1603 /* Do the clipping */
1604 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1608 if (x2 > Surface->w - 1)
1609 x2 = Surface->w - 1;
1616 SDL_FillRect(Surface, &l, Color);
1618 if (SDL_MUSTLOCK(Surface))
1620 SDL_UnlockSurface(Surface);
1624 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1625 Uint8 R, Uint8 G, Uint8 B)
1627 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1630 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1641 /* Do the clipping */
1642 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1646 if (x2 > Surface->w - 1)
1647 x2 = Surface->w - 1;
1654 SDL_FillRect(Surface, &l, Color);
1657 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1662 if (SDL_MUSTLOCK(Surface))
1664 if (SDL_LockSurface(Surface) < 0)
1677 /* Do the clipping */
1678 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1682 if (y2 > Surface->h - 1)
1683 y2 = Surface->h - 1;
1690 SDL_FillRect(Surface, &l, Color);
1692 if (SDL_MUSTLOCK(Surface))
1694 SDL_UnlockSurface(Surface);
1698 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1699 Uint8 R, Uint8 G, Uint8 B)
1701 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1704 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1715 /* Do the clipping */
1716 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1720 if (y2 > Surface->h - 1)
1721 y2 = Surface->h - 1;
1728 SDL_FillRect(Surface, &l, Color);
1731 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1732 Sint16 x2, Sint16 y2, Uint32 Color,
1733 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1736 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1741 sdx = (dx < 0) ? -1 : 1;
1742 sdy = (dy < 0) ? -1 : 1;
1754 for (x = 0; x < dx; x++)
1756 Callback(Surface, px, py, Color);
1770 for (y = 0; y < dy; y++)
1772 Callback(Surface, px, py, Color);
1786 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1787 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1788 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1791 sge_DoLine(Surface, X1, Y1, X2, Y2,
1792 SDL_MapRGB(Surface->format, R, G, B), Callback);
1795 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1798 if (SDL_MUSTLOCK(Surface))
1800 if (SDL_LockSurface(Surface) < 0)
1805 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1807 /* unlock the display */
1808 if (SDL_MUSTLOCK(Surface))
1810 SDL_UnlockSurface(Surface);
1814 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1815 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1817 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1820 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1822 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1827 -----------------------------------------------------------------------------
1828 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1829 -----------------------------------------------------------------------------
1832 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1833 int width, int height, Uint32 color)
1837 for (y = src_y; y < src_y + height; y++)
1839 for (x = src_x; x < src_x + width; x++)
1841 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1843 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1848 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1849 int src_x, int src_y, int width, int height,
1850 int dst_x, int dst_y)
1854 for (y = 0; y < height; y++)
1856 for (x = 0; x < width; x++)
1858 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1860 if (pixel != BLACK_PIXEL)
1861 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1867 /* ========================================================================= */
1868 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1869 /* (Rotozoomer) by Andreas Schiffler */
1870 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1871 /* ========================================================================= */
1874 -----------------------------------------------------------------------------
1877 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1878 -----------------------------------------------------------------------------
1889 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1892 tColorRGBA *sp, *csp, *dp;
1896 sp = csp = (tColorRGBA *) src->pixels;
1897 dp = (tColorRGBA *) dst->pixels;
1898 dgap = dst->pitch - dst->w * 4;
1900 for (y = 0; y < dst->h; y++)
1904 for (x = 0; x < dst->w; x++)
1906 tColorRGBA *sp0 = sp;
1907 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1908 tColorRGBA *sp00 = &sp0[0];
1909 tColorRGBA *sp01 = &sp0[1];
1910 tColorRGBA *sp10 = &sp1[0];
1911 tColorRGBA *sp11 = &sp1[1];
1914 /* create new color pixel from all four source color pixels */
1915 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1916 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1917 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1918 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1923 /* advance source pointers */
1926 /* advance destination pointer */
1930 /* advance source pointer */
1931 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1933 /* advance destination pointers */
1934 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1940 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1942 int x, y, *sax, *say, *csax, *csay;
1944 tColorRGBA *sp, *csp, *csp0, *dp;
1947 /* use specialized zoom function when scaling down to exactly half size */
1948 if (src->w == 2 * dst->w &&
1949 src->h == 2 * dst->h)
1950 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1952 /* variable setup */
1953 sx = (float) src->w / (float) dst->w;
1954 sy = (float) src->h / (float) dst->h;
1956 /* allocate memory for row increments */
1957 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1958 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1960 /* precalculate row increments */
1961 for (x = 0; x <= dst->w; x++)
1962 *csax++ = (int)(sx * x);
1964 for (y = 0; y <= dst->h; y++)
1965 *csay++ = (int)(sy * y);
1968 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1969 dp = (tColorRGBA *) dst->pixels;
1970 dgap = dst->pitch - dst->w * 4;
1973 for (y = 0; y < dst->h; y++)
1978 for (x = 0; x < dst->w; x++)
1983 /* advance source pointers */
1987 /* advance destination pointer */
1991 /* advance source pointer */
1993 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1995 /* advance destination pointers */
1996 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2006 -----------------------------------------------------------------------------
2009 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2010 -----------------------------------------------------------------------------
2013 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2015 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2016 Uint8 *sp, *dp, *csp;
2019 /* variable setup */
2020 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2021 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2023 /* allocate memory for row increments */
2024 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2025 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2027 /* precalculate row increments */
2030 for (x = 0; x < dst->w; x++)
2033 *csax = (csx >> 16);
2040 for (y = 0; y < dst->h; y++)
2043 *csay = (csy >> 16);
2050 for (x = 0; x < dst->w; x++)
2058 for (y = 0; y < dst->h; y++)
2065 sp = csp = (Uint8 *) src->pixels;
2066 dp = (Uint8 *) dst->pixels;
2067 dgap = dst->pitch - dst->w;
2071 for (y = 0; y < dst->h; y++)
2075 for (x = 0; x < dst->w; x++)
2080 /* advance source pointers */
2084 /* advance destination pointer */
2088 /* advance source pointer (for row) */
2089 csp += ((*csay) * src->pitch);
2092 /* advance destination pointers */
2103 -----------------------------------------------------------------------------
2106 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2107 'zoomx' and 'zoomy' are scaling factors for width and height.
2108 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2109 into a 32bit RGBA format on the fly.
2110 -----------------------------------------------------------------------------
2113 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2115 SDL_Surface *zoom_src = NULL;
2116 SDL_Surface *zoom_dst = NULL;
2117 boolean is_converted = FALSE;
2124 /* determine if source surface is 32 bit or 8 bit */
2125 is_32bit = (src->format->BitsPerPixel == 32);
2127 if (is_32bit || src->format->BitsPerPixel == 8)
2129 /* use source surface 'as is' */
2134 /* new source surface is 32 bit with a defined RGB ordering */
2135 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2136 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2137 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2139 is_converted = TRUE;
2142 /* allocate surface to completely contain the zoomed surface */
2145 /* target surface is 32 bit with source RGBA/ABGR ordering */
2146 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2147 zoom_src->format->Rmask,
2148 zoom_src->format->Gmask,
2149 zoom_src->format->Bmask, 0);
2153 /* target surface is 8 bit */
2154 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2158 /* lock source surface */
2159 SDL_LockSurface(zoom_src);
2161 /* check which kind of surface we have */
2164 /* call the 32 bit transformation routine to do the zooming */
2165 zoomSurfaceRGBA(zoom_src, zoom_dst);
2170 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2171 zoom_dst->format->palette->colors[i] =
2172 zoom_src->format->palette->colors[i];
2173 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2175 /* call the 8 bit transformation routine to do the zooming */
2176 zoomSurfaceY(zoom_src, zoom_dst);
2179 /* unlock source surface */
2180 SDL_UnlockSurface(zoom_src);
2182 /* free temporary surface */
2184 SDL_FreeSurface(zoom_src);
2186 /* return destination surface */
2190 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2192 Bitmap *dst_bitmap = CreateBitmapStruct();
2193 SDL_Surface **dst_surface = &dst_bitmap->surface;
2195 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2196 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2198 dst_bitmap->width = dst_width;
2199 dst_bitmap->height = dst_height;
2201 /* create zoomed temporary surface from source surface */
2202 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2204 /* create native format destination surface from zoomed temporary surface */
2205 SDLSetNativeSurface(dst_surface);
2211 /* ========================================================================= */
2212 /* load image to bitmap */
2213 /* ========================================================================= */
2215 Bitmap *SDLLoadImage(char *filename)
2217 Bitmap *new_bitmap = CreateBitmapStruct();
2218 SDL_Surface *sdl_image_tmp;
2220 print_timestamp_init("SDLLoadImage");
2222 print_timestamp_time(getBaseNamePtr(filename));
2224 /* load image to temporary surface */
2225 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2227 SetError("IMG_Load(): %s", SDL_GetError());
2232 print_timestamp_time("IMG_Load");
2234 UPDATE_BUSY_STATE();
2236 /* create native non-transparent surface for current image */
2237 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2239 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2244 print_timestamp_time("SDL_DisplayFormat (opaque)");
2246 UPDATE_BUSY_STATE();
2248 /* create native transparent surface for current image */
2249 if (sdl_image_tmp->format->Amask == 0)
2250 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2251 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2253 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2255 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2260 print_timestamp_time("SDL_DisplayFormat (masked)");
2262 UPDATE_BUSY_STATE();
2264 /* free temporary surface */
2265 SDL_FreeSurface(sdl_image_tmp);
2267 new_bitmap->width = new_bitmap->surface->w;
2268 new_bitmap->height = new_bitmap->surface->h;
2270 print_timestamp_done("SDLLoadImage");
2276 /* ------------------------------------------------------------------------- */
2277 /* custom cursor fuctions */
2278 /* ------------------------------------------------------------------------- */
2280 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2282 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2283 cursor_info->width, cursor_info->height,
2284 cursor_info->hot_x, cursor_info->hot_y);
2287 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2289 static struct MouseCursorInfo *last_cursor_info = NULL;
2290 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2291 static SDL_Cursor *cursor_default = NULL;
2292 static SDL_Cursor *cursor_current = NULL;
2294 /* if invoked for the first time, store the SDL default cursor */
2295 if (cursor_default == NULL)
2296 cursor_default = SDL_GetCursor();
2298 /* only create new cursor if cursor info (custom only) has changed */
2299 if (cursor_info != NULL && cursor_info != last_cursor_info)
2301 cursor_current = create_cursor(cursor_info);
2302 last_cursor_info = cursor_info;
2305 /* only set new cursor if cursor info (custom or NULL) has changed */
2306 if (cursor_info != last_cursor_info2)
2307 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2309 last_cursor_info2 = cursor_info;
2313 /* ========================================================================= */
2314 /* audio functions */
2315 /* ========================================================================= */
2317 void SDLOpenAudio(void)
2319 #if !defined(TARGET_SDL2)
2320 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2321 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2324 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2326 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2330 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2331 AUDIO_NUM_CHANNELS_STEREO,
2332 setup.system.audio_fragment_size) < 0)
2334 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2338 audio.sound_available = TRUE;
2339 audio.music_available = TRUE;
2340 audio.loops_available = TRUE;
2341 audio.sound_enabled = TRUE;
2343 /* set number of available mixer channels */
2344 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2345 audio.music_channel = MUSIC_CHANNEL;
2346 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2348 Mixer_InitChannels();
2351 void SDLCloseAudio(void)
2354 Mix_HaltChannel(-1);
2357 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2361 /* ========================================================================= */
2362 /* event functions */
2363 /* ========================================================================= */
2365 void SDLNextEvent(Event *event)
2367 SDL_WaitEvent(event);
2370 void SDLHandleWindowManagerEvent(Event *event)
2373 #if defined(PLATFORM_WIN32)
2374 // experimental drag and drop code
2376 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2377 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2379 #if defined(TARGET_SDL2)
2380 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2382 if (syswmmsg->msg == WM_DROPFILES)
2385 #if defined(TARGET_SDL2)
2386 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2388 HDROP hdrop = (HDROP)syswmmsg->wParam;
2392 printf("::: SDL_SYSWMEVENT:\n");
2394 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2396 for (i = 0; i < num_files; i++)
2398 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2399 char buffer[buffer_len + 1];
2401 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2403 printf("::: - '%s'\n", buffer);
2406 #if defined(TARGET_SDL2)
2407 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2409 DragFinish((HDROP)syswmmsg->wParam);
2417 /* ========================================================================= */
2418 /* joystick functions */
2419 /* ========================================================================= */
2421 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2422 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2423 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2425 static boolean SDLOpenJoystick(int nr)
2427 if (nr < 0 || nr > MAX_PLAYERS)
2430 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2433 static void SDLCloseJoystick(int nr)
2435 if (nr < 0 || nr > MAX_PLAYERS)
2438 SDL_JoystickClose(sdl_joystick[nr]);
2440 sdl_joystick[nr] = NULL;
2443 static boolean SDLCheckJoystickOpened(int nr)
2445 if (nr < 0 || nr > MAX_PLAYERS)
2448 #if defined(TARGET_SDL2)
2449 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2451 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2455 void HandleJoystickEvent(Event *event)
2459 case SDL_JOYAXISMOTION:
2460 if (event->jaxis.axis < 2)
2461 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2464 case SDL_JOYBUTTONDOWN:
2465 if (event->jbutton.button < 2)
2466 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2469 case SDL_JOYBUTTONUP:
2470 if (event->jbutton.button < 2)
2471 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2479 void SDLInitJoysticks()
2481 static boolean sdl_joystick_subsystem_initialized = FALSE;
2482 boolean print_warning = !sdl_joystick_subsystem_initialized;
2485 if (!sdl_joystick_subsystem_initialized)
2487 sdl_joystick_subsystem_initialized = TRUE;
2489 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2491 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2496 for (i = 0; i < MAX_PLAYERS; i++)
2498 /* get configured joystick for this player */
2499 char *device_name = setup.input[i].joy.device_name;
2500 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2502 if (joystick_nr >= SDL_NumJoysticks())
2504 if (setup.input[i].use_joystick && print_warning)
2505 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2510 /* misuse joystick file descriptor variable to store joystick number */
2511 joystick.fd[i] = joystick_nr;
2513 if (joystick_nr == -1)
2516 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2517 if (SDLCheckJoystickOpened(joystick_nr))
2518 SDLCloseJoystick(joystick_nr);
2520 if (!setup.input[i].use_joystick)
2523 if (!SDLOpenJoystick(joystick_nr))
2526 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2531 joystick.status = JOYSTICK_ACTIVATED;
2535 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2537 if (nr < 0 || nr >= MAX_PLAYERS)
2541 *x = sdl_js_axis[nr][0];
2543 *y = sdl_js_axis[nr][1];
2546 *b1 = sdl_js_button[nr][0];
2548 *b2 = sdl_js_button[nr][1];