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 &&
227 format1->Amask == format2->Amask);
230 boolean SDLSetNativeSurface(SDL_Surface **surface)
232 SDL_Surface *new_surface;
234 if (surface == NULL ||
236 backbuffer == NULL ||
237 backbuffer->surface == NULL)
240 // if pixel format already optimized for destination surface, do nothing
241 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
244 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
246 if (new_surface == NULL)
247 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
249 SDL_FreeSurface(*surface);
251 *surface = new_surface;
256 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
258 SDL_PixelFormat format;
259 SDL_Surface *new_surface;
264 if (backbuffer && backbuffer->surface)
266 format = *backbuffer->surface->format;
267 format.Amask = surface->format->Amask; // keep alpha channel
271 format = *surface->format;
274 new_surface = SDL_ConvertSurface(surface, &format, 0);
276 if (new_surface == NULL)
277 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
284 boolean SDLSetNativeSurface(SDL_Surface **surface)
286 SDL_Surface *new_surface;
288 if (surface == NULL ||
293 new_surface = SDL_DisplayFormat(*surface);
295 if (new_surface == NULL)
296 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
298 SDL_FreeSurface(*surface);
300 *surface = new_surface;
305 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
307 SDL_Surface *new_surface;
309 if (video.initialized)
310 new_surface = SDL_DisplayFormat(surface);
312 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
314 if (new_surface == NULL)
315 Error(ERR_EXIT, "%s() failed: %s",
316 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
324 #if defined(TARGET_SDL2)
325 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
327 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
330 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
337 void SDLCreateBitmapTextures(Bitmap *bitmap)
339 #if defined(TARGET_SDL2)
344 SDL_DestroyTexture(bitmap->texture);
345 if (bitmap->texture_masked)
346 SDL_DestroyTexture(bitmap->texture_masked);
348 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
349 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
353 void SDLFreeBitmapTextures(Bitmap *bitmap)
355 #if defined(TARGET_SDL2)
360 SDL_DestroyTexture(bitmap->texture);
361 if (bitmap->texture_masked)
362 SDL_DestroyTexture(bitmap->texture_masked);
364 bitmap->texture = NULL;
365 bitmap->texture_masked = NULL;
369 void SDLInitVideoDisplay(void)
371 #if !defined(TARGET_SDL2)
372 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
373 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
375 SDL_putenv("SDL_VIDEO_CENTERED=1");
378 /* initialize SDL video */
379 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
380 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
382 /* set default SDL depth */
383 #if !defined(TARGET_SDL2)
384 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
386 video.default_depth = 32; // (how to determine video depth in SDL2?)
390 void SDLInitVideoBuffer(boolean fullscreen)
392 video.window_scaling_percent = setup.window_scaling_percent;
393 video.window_scaling_quality = setup.window_scaling_quality;
395 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
397 #if defined(TARGET_SDL2)
398 // SDL 2.0: support for (desktop) fullscreen mode available
399 video.fullscreen_available = TRUE;
401 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
402 video.fullscreen_available = FALSE;
405 /* open SDL video output device (window or fullscreen mode) */
406 if (!SDLSetVideoMode(fullscreen))
407 Error(ERR_EXIT, "setting video mode failed");
409 /* !!! SDL2 can only set the window icon if the window already exists !!! */
410 /* set window icon */
411 SDLSetWindowIcon(program.icon_filename);
413 /* set window and icon title */
414 #if defined(TARGET_SDL2)
415 SDL_SetWindowTitle(sdl_window, program.window_title);
417 SDL_WM_SetCaption(program.window_title, program.window_title);
420 /* SDL cannot directly draw to the visible video framebuffer like X11,
421 but always uses a backbuffer, which is then blitted to the visible
422 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
423 visible video framebuffer with 'SDL_Flip', if the hardware supports
424 this). Therefore do not use an additional backbuffer for drawing, but
425 use a symbolic buffer (distinguishable from the SDL backbuffer) called
426 'window', which indicates that the SDL backbuffer should be updated to
427 the visible video framebuffer when attempting to blit to it.
429 For convenience, it seems to be a good idea to create this symbolic
430 buffer 'window' at the same size as the SDL backbuffer. Although it
431 should never be drawn to directly, it would do no harm nevertheless. */
433 /* create additional (symbolic) buffer for double-buffering */
434 ReCreateBitmap(&window, video.width, video.height, video.depth);
437 static boolean SDLCreateScreen(boolean fullscreen)
439 SDL_Surface *new_surface = NULL;
441 #if defined(TARGET_SDL2)
442 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
443 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
445 int surface_flags_window = SURFACE_FLAGS;
446 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
449 #if defined(TARGET_SDL2)
451 int renderer_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
453 /* If SDL_CreateRenderer() is called from within a VirtualBox Windows VM
454 _without_ enabling 2D/3D acceleration and/or guest additions installed,
455 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
456 it will try to use accelerated graphics and apparently fails miserably) */
457 int renderer_flags = SDL_RENDERER_SOFTWARE;
461 int width = video.width;
462 int height = video.height;
463 int surface_flags = (fullscreen ? surface_flags_fullscreen :
464 surface_flags_window);
466 // default window size is unscaled
467 video.window_width = video.width;
468 video.window_height = video.height;
470 #if defined(TARGET_SDL2)
472 // store if initial screen mode is fullscreen mode when changing screen size
473 video.fullscreen_initial = fullscreen;
475 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
477 video.window_width = window_scaling_factor * width;
478 video.window_height = window_scaling_factor * height;
480 if (sdl_texture_stream)
482 SDL_DestroyTexture(sdl_texture_stream);
483 sdl_texture_stream = NULL;
486 if (sdl_texture_target)
488 SDL_DestroyTexture(sdl_texture_target);
489 sdl_texture_target = NULL;
492 if (!(fullscreen && fullscreen_enabled))
496 SDL_DestroyRenderer(sdl_renderer);
502 SDL_DestroyWindow(sdl_window);
507 if (sdl_window == NULL)
508 sdl_window = SDL_CreateWindow(program.window_title,
509 SDL_WINDOWPOS_CENTERED,
510 SDL_WINDOWPOS_CENTERED,
515 if (sdl_window != NULL)
517 if (sdl_renderer == NULL)
518 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, renderer_flags);
520 if (sdl_renderer != NULL)
522 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
523 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
524 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
526 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
527 SDL_PIXELFORMAT_ARGB8888,
528 SDL_TEXTUREACCESS_STREAMING,
531 if (SDL_RenderTargetSupported(sdl_renderer))
532 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
533 SDL_PIXELFORMAT_ARGB8888,
534 SDL_TEXTUREACCESS_TARGET,
537 if (sdl_texture_stream != NULL)
539 // use SDL default values for RGB masks and no alpha channel
540 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
542 if (new_surface == NULL)
543 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
547 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
552 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
557 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
562 if (gfx.final_screen_bitmap == NULL)
563 gfx.final_screen_bitmap = CreateBitmapStruct();
565 gfx.final_screen_bitmap->width = width;
566 gfx.final_screen_bitmap->height = height;
568 gfx.final_screen_bitmap->surface =
569 SDL_SetVideoMode(width, height, video.depth, surface_flags);
571 if (gfx.final_screen_bitmap->surface != NULL)
574 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
576 if (new_surface == NULL)
577 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
580 new_surface = gfx.final_screen_bitmap->surface;
581 gfx.final_screen_bitmap = NULL;
587 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
591 #if defined(TARGET_SDL2)
592 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
593 if (new_surface != NULL)
594 fullscreen_enabled = fullscreen;
597 if (backbuffer == NULL)
598 backbuffer = CreateBitmapStruct();
600 backbuffer->width = video.width;
601 backbuffer->height = video.height;
603 if (backbuffer->surface)
604 SDL_FreeSurface(backbuffer->surface);
606 backbuffer->surface = new_surface;
608 return (new_surface != NULL);
611 boolean SDLSetVideoMode(boolean fullscreen)
613 boolean success = FALSE;
617 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
619 /* switch display to fullscreen mode, if available */
620 success = SDLCreateScreen(TRUE);
624 /* switching display to fullscreen mode failed -- do not try it again */
625 video.fullscreen_available = FALSE;
629 video.fullscreen_enabled = TRUE;
633 if ((!fullscreen && video.fullscreen_enabled) || !success)
635 /* switch display to window mode */
636 success = SDLCreateScreen(FALSE);
640 /* switching display to window mode failed -- should not happen */
644 video.fullscreen_enabled = FALSE;
645 video.window_scaling_percent = setup.window_scaling_percent;
646 video.window_scaling_quality = setup.window_scaling_quality;
648 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
652 #if defined(TARGET_SDL2)
653 SDLRedrawWindow(); // map window
657 #if defined(PLATFORM_WIN32)
658 // experimental drag and drop code
660 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
663 SDL_SysWMinfo wminfo;
665 boolean wminfo_success = FALSE;
667 SDL_VERSION(&wminfo.version);
668 #if defined(TARGET_SDL2)
670 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
672 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
677 #if defined(TARGET_SDL2)
678 hwnd = wminfo.info.win.window;
680 hwnd = wminfo.window;
683 DragAcceptFiles(hwnd, TRUE);
692 void SDLSetWindowTitle()
694 #if defined(TARGET_SDL2)
695 SDL_SetWindowTitle(sdl_window, program.window_title);
697 SDL_WM_SetCaption(program.window_title, program.window_title);
701 #if defined(TARGET_SDL2)
702 void SDLSetWindowScaling(int window_scaling_percent)
704 if (sdl_window == NULL)
707 float window_scaling_factor = (float)window_scaling_percent / 100;
708 int new_window_width = (int)(window_scaling_factor * video.width);
709 int new_window_height = (int)(window_scaling_factor * video.height);
711 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
713 video.window_scaling_percent = window_scaling_percent;
714 video.window_width = new_window_width;
715 video.window_height = new_window_height;
720 void SDLSetWindowScalingQuality(char *window_scaling_quality)
722 SDL_Texture *new_texture;
724 if (sdl_texture_stream == NULL)
727 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
729 new_texture = SDL_CreateTexture(sdl_renderer,
730 SDL_PIXELFORMAT_ARGB8888,
731 SDL_TEXTUREACCESS_STREAMING,
732 video.width, video.height);
734 if (new_texture != NULL)
736 SDL_DestroyTexture(sdl_texture_stream);
738 sdl_texture_stream = new_texture;
741 if (SDL_RenderTargetSupported(sdl_renderer))
742 new_texture = SDL_CreateTexture(sdl_renderer,
743 SDL_PIXELFORMAT_ARGB8888,
744 SDL_TEXTUREACCESS_TARGET,
745 video.width, video.height);
749 if (new_texture != NULL)
751 SDL_DestroyTexture(sdl_texture_target);
753 sdl_texture_target = new_texture;
758 video.window_scaling_quality = window_scaling_quality;
761 void SDLSetWindowFullscreen(boolean fullscreen)
763 if (sdl_window == NULL)
766 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
768 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
769 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
771 // if screen size was changed in fullscreen mode, correct desktop window size
772 if (!fullscreen && video.fullscreen_initial)
774 SDLSetWindowScaling(setup.window_scaling_percent);
775 SDL_SetWindowPosition(sdl_window,
776 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
778 video.fullscreen_initial = FALSE;
783 void SDLSetScreenRenderingMode(char *screen_rendering_mode)
785 #if defined(TARGET_SDL2)
786 video.screen_rendering_mode =
787 (strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
788 SPECIAL_RENDERING_BITMAP :
789 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
790 SPECIAL_RENDERING_TARGET:
791 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
792 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
794 video.screen_rendering_mode = SPECIAL_RENDERING_BITMAP;
798 void SDLRedrawWindow()
800 UpdateScreen_WithoutFrameDelay(NULL);
803 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
806 SDL_Surface *surface =
807 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
810 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
812 SDLSetNativeSurface(&surface);
814 bitmap->surface = surface;
817 void SDLFreeBitmapPointers(Bitmap *bitmap)
820 SDL_FreeSurface(bitmap->surface);
821 if (bitmap->surface_masked)
822 SDL_FreeSurface(bitmap->surface_masked);
824 bitmap->surface = NULL;
825 bitmap->surface_masked = NULL;
827 #if defined(TARGET_SDL2)
829 SDL_DestroyTexture(bitmap->texture);
830 if (bitmap->texture_masked)
831 SDL_DestroyTexture(bitmap->texture_masked);
833 bitmap->texture = NULL;
834 bitmap->texture_masked = NULL;
838 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
839 int src_x, int src_y, int width, int height,
840 int dst_x, int dst_y, int mask_mode)
842 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
843 SDL_Rect src_rect, dst_rect;
855 // if (src_bitmap != backbuffer || dst_bitmap != window)
856 if (!(src_bitmap == backbuffer && dst_bitmap == window))
857 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
858 src_bitmap->surface_masked : src_bitmap->surface),
859 &src_rect, real_dst_bitmap->surface, &dst_rect);
861 if (dst_bitmap == window)
862 UpdateScreen_WithFrameDelay(&dst_rect);
865 void SDLBlitTexture(Bitmap *bitmap,
866 int src_x, int src_y, int width, int height,
867 int dst_x, int dst_y, int mask_mode)
869 #if defined(TARGET_SDL2)
870 SDL_Texture *texture;
875 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
890 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
894 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
897 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
905 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
907 if (dst_bitmap == window)
908 UpdateScreen_WithFrameDelay(&rect);
911 void PrepareFadeBitmap(int draw_target)
913 Bitmap *fade_bitmap =
914 (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
915 draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
917 if (fade_bitmap == NULL)
920 // copy backbuffer to fading buffer
921 BlitBitmap(backbuffer, fade_bitmap, 0, 0, gfx.win_xsize, gfx.win_ysize, 0, 0);
923 // add border and animations to fading buffer
924 FinalizeScreen(draw_target);
927 void SDLFadeRectangle(int x, int y, int width, int height,
928 int fade_mode, int fade_delay, int post_delay,
929 void (*draw_border_function)(void))
931 SDL_Surface *surface_backup = gfx.fade_bitmap_backup->surface;
932 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
933 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
934 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
935 SDL_Surface *surface_screen = backbuffer->surface;
936 SDL_Rect src_rect, dst_rect;
938 int src_x = x, src_y = y;
939 int dst_x = x, dst_y = y;
940 unsigned int time_last, time_current;
942 // store function for drawing global masked border
943 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
945 // deactivate drawing of global border while fading, if needed
946 if (draw_border_function == NULL)
947 gfx.draw_global_border_function = NULL;
956 dst_rect.w = width; /* (ignored) */
957 dst_rect.h = height; /* (ignored) */
959 dst_rect2 = dst_rect;
961 // before fading in, store backbuffer (without animation graphics)
962 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
963 SDL_BlitSurface(surface_screen, &dst_rect, surface_backup, &src_rect);
965 /* copy source and target surfaces to temporary surfaces for fading */
966 if (fade_mode & FADE_TYPE_TRANSFORM)
968 // (source and target fading buffer already prepared)
970 else if (fade_mode & FADE_TYPE_FADE_IN)
972 // (target fading buffer already prepared)
973 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
975 else /* FADE_TYPE_FADE_OUT */
977 // (source fading buffer already prepared)
978 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
981 time_current = SDL_GetTicks();
983 if (fade_mode == FADE_MODE_MELT)
985 boolean done = FALSE;
987 int melt_columns = width / melt_pixels;
988 int ypos[melt_columns];
989 int max_steps = height / 8 + 32;
994 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
995 #if defined(TARGET_SDL2)
996 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
998 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1001 ypos[0] = -GetSimpleRandom(16);
1003 for (i = 1 ; i < melt_columns; i++)
1005 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1007 ypos[i] = ypos[i - 1] + r;
1020 time_last = time_current;
1021 time_current = SDL_GetTicks();
1022 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1023 steps_final = MIN(MAX(0, steps), max_steps);
1027 done = (steps_done >= steps_final);
1029 for (i = 0 ; i < melt_columns; i++)
1037 else if (ypos[i] < height)
1042 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1044 if (ypos[i] + dy >= height)
1045 dy = height - ypos[i];
1047 /* copy part of (appearing) target surface to upper area */
1048 src_rect.x = src_x + i * melt_pixels;
1049 // src_rect.y = src_y + ypos[i];
1051 src_rect.w = melt_pixels;
1053 src_rect.h = ypos[i] + dy;
1055 dst_rect.x = dst_x + i * melt_pixels;
1056 // dst_rect.y = dst_y + ypos[i];
1059 if (steps_done >= steps_final)
1060 SDL_BlitSurface(surface_target, &src_rect,
1061 surface_screen, &dst_rect);
1065 /* copy part of (disappearing) source surface to lower area */
1066 src_rect.x = src_x + i * melt_pixels;
1068 src_rect.w = melt_pixels;
1069 src_rect.h = height - ypos[i];
1071 dst_rect.x = dst_x + i * melt_pixels;
1072 dst_rect.y = dst_y + ypos[i];
1074 if (steps_done >= steps_final)
1075 SDL_BlitSurface(surface_source, &src_rect,
1076 surface_screen, &dst_rect);
1082 src_rect.x = src_x + i * melt_pixels;
1084 src_rect.w = melt_pixels;
1085 src_rect.h = height;
1087 dst_rect.x = dst_x + i * melt_pixels;
1090 if (steps_done >= steps_final)
1091 SDL_BlitSurface(surface_target, &src_rect,
1092 surface_screen, &dst_rect);
1096 if (steps_done >= steps_final)
1098 if (draw_border_function != NULL)
1099 draw_border_function();
1101 UpdateScreen_WithFrameDelay(&dst_rect2);
1105 else if (fade_mode == FADE_MODE_CURTAIN)
1109 int xx_size = width / 2;
1111 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1112 #if defined(TARGET_SDL2)
1113 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1115 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1118 for (xx = 0; xx < xx_size;)
1120 time_last = time_current;
1121 time_current = SDL_GetTicks();
1122 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1123 xx_final = MIN(MAX(0, xx), xx_size);
1128 src_rect.h = height;
1133 /* draw new (target) image to screen buffer */
1134 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1136 if (xx_final < xx_size)
1138 src_rect.w = xx_size - xx_final;
1139 src_rect.h = height;
1141 /* draw old (source) image to screen buffer (left side) */
1143 src_rect.x = src_x + xx_final;
1146 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1148 /* draw old (source) image to screen buffer (right side) */
1150 src_rect.x = src_x + xx_size;
1151 dst_rect.x = dst_x + xx_size + xx_final;
1153 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1156 if (draw_border_function != NULL)
1157 draw_border_function();
1159 /* only update the region of the screen that is affected from fading */
1160 UpdateScreen_WithFrameDelay(&dst_rect2);
1163 else /* fading in, fading out or cross-fading */
1168 for (alpha = 0.0; alpha < 255.0;)
1170 time_last = time_current;
1171 time_current = SDL_GetTicks();
1172 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1173 alpha_final = MIN(MAX(0, alpha), 255);
1175 /* draw existing (source) image to screen buffer */
1176 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1178 /* draw new (target) image to screen buffer using alpha blending */
1179 #if defined(TARGET_SDL2)
1180 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1181 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1183 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1185 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1187 if (draw_border_function != NULL)
1188 draw_border_function();
1190 /* only update the region of the screen that is affected from fading */
1191 UpdateScreen_WithFrameDelay(&dst_rect);
1197 unsigned int time_post_delay;
1199 time_current = SDL_GetTicks();
1200 time_post_delay = time_current + post_delay;
1202 while (time_current < time_post_delay)
1204 // updating the screen contains waiting for frame delay (non-busy)
1205 UpdateScreen_WithFrameDelay(NULL);
1207 time_current = SDL_GetTicks();
1211 // restore function for drawing global masked border
1212 gfx.draw_global_border_function = draw_global_border_function;
1214 // after fading in, restore backbuffer (without animation graphics)
1215 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
1216 SDL_BlitSurface(surface_backup, &dst_rect, surface_screen, &src_rect);
1219 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1220 int to_x, int to_y, Uint32 color)
1222 SDL_Surface *surface = dst_bitmap->surface;
1226 swap_numbers(&from_x, &to_x);
1229 swap_numbers(&from_y, &to_y);
1233 rect.w = (to_x - from_x + 1);
1234 rect.h = (to_y - from_y + 1);
1236 SDL_FillRect(surface, &rect, color);
1239 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1240 int to_x, int to_y, Uint32 color)
1242 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1245 #if ENABLE_UNUSED_CODE
1246 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1247 int num_points, Uint32 color)
1252 for (i = 0; i < num_points - 1; i++)
1254 for (x = 0; x < line_width; x++)
1256 for (y = 0; y < line_width; y++)
1258 int dx = x - line_width / 2;
1259 int dy = y - line_width / 2;
1261 if ((x == 0 && y == 0) ||
1262 (x == 0 && y == line_width - 1) ||
1263 (x == line_width - 1 && y == 0) ||
1264 (x == line_width - 1 && y == line_width - 1))
1267 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1268 points[i+1].x + dx, points[i+1].y + dy, color);
1275 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1277 SDL_Surface *surface = src_bitmap->surface;
1279 switch (surface->format->BytesPerPixel)
1281 case 1: /* assuming 8-bpp */
1283 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1287 case 2: /* probably 15-bpp or 16-bpp */
1289 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1293 case 3: /* slow 24-bpp mode; usually not used */
1295 /* does this work? */
1296 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1300 shift = surface->format->Rshift;
1301 color |= *(pix + shift / 8) >> shift;
1302 shift = surface->format->Gshift;
1303 color |= *(pix + shift / 8) >> shift;
1304 shift = surface->format->Bshift;
1305 color |= *(pix + shift / 8) >> shift;
1311 case 4: /* probably 32-bpp */
1313 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1322 /* ========================================================================= */
1323 /* The following functions were taken from the SGE library */
1324 /* (SDL Graphics Extension Library) by Anders Lindström */
1325 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1326 /* ========================================================================= */
1328 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1330 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1332 switch (surface->format->BytesPerPixel)
1336 /* Assuming 8-bpp */
1337 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1343 /* Probably 15-bpp or 16-bpp */
1344 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1350 /* Slow 24-bpp mode, usually not used */
1354 /* Gack - slow, but endian correct */
1355 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1356 shift = surface->format->Rshift;
1357 *(pix+shift/8) = color>>shift;
1358 shift = surface->format->Gshift;
1359 *(pix+shift/8) = color>>shift;
1360 shift = surface->format->Bshift;
1361 *(pix+shift/8) = color>>shift;
1367 /* Probably 32-bpp */
1368 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1375 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1376 Uint8 R, Uint8 G, Uint8 B)
1378 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1381 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1383 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1386 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1388 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1391 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1396 /* Gack - slow, but endian correct */
1397 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1398 shift = surface->format->Rshift;
1399 *(pix+shift/8) = color>>shift;
1400 shift = surface->format->Gshift;
1401 *(pix+shift/8) = color>>shift;
1402 shift = surface->format->Bshift;
1403 *(pix+shift/8) = color>>shift;
1406 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1408 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1411 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1413 switch (dest->format->BytesPerPixel)
1416 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1420 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1424 _PutPixel24(dest,x,y,color);
1428 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1433 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1435 if (SDL_MUSTLOCK(surface))
1437 if (SDL_LockSurface(surface) < 0)
1443 _PutPixel(surface, x, y, color);
1445 if (SDL_MUSTLOCK(surface))
1447 SDL_UnlockSurface(surface);
1451 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1452 Uint8 r, Uint8 g, Uint8 b)
1454 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1457 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1459 if (y >= 0 && y <= dest->h - 1)
1461 switch (dest->format->BytesPerPixel)
1464 return y*dest->pitch;
1468 return y*dest->pitch/2;
1472 return y*dest->pitch;
1476 return y*dest->pitch/4;
1484 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1486 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1488 switch (surface->format->BytesPerPixel)
1492 /* Assuming 8-bpp */
1493 *((Uint8 *)surface->pixels + ypitch + x) = color;
1499 /* Probably 15-bpp or 16-bpp */
1500 *((Uint16 *)surface->pixels + ypitch + x) = color;
1506 /* Slow 24-bpp mode, usually not used */
1510 /* Gack - slow, but endian correct */
1511 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1512 shift = surface->format->Rshift;
1513 *(pix+shift/8) = color>>shift;
1514 shift = surface->format->Gshift;
1515 *(pix+shift/8) = color>>shift;
1516 shift = surface->format->Bshift;
1517 *(pix+shift/8) = color>>shift;
1523 /* Probably 32-bpp */
1524 *((Uint32 *)surface->pixels + ypitch + x) = color;
1531 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1536 if (SDL_MUSTLOCK(Surface))
1538 if (SDL_LockSurface(Surface) < 0)
1551 /* Do the clipping */
1552 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1556 if (x2 > Surface->w - 1)
1557 x2 = Surface->w - 1;
1564 SDL_FillRect(Surface, &l, Color);
1566 if (SDL_MUSTLOCK(Surface))
1568 SDL_UnlockSurface(Surface);
1572 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1573 Uint8 R, Uint8 G, Uint8 B)
1575 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1578 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1589 /* Do the clipping */
1590 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1594 if (x2 > Surface->w - 1)
1595 x2 = Surface->w - 1;
1602 SDL_FillRect(Surface, &l, Color);
1605 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1610 if (SDL_MUSTLOCK(Surface))
1612 if (SDL_LockSurface(Surface) < 0)
1625 /* Do the clipping */
1626 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1630 if (y2 > Surface->h - 1)
1631 y2 = Surface->h - 1;
1638 SDL_FillRect(Surface, &l, Color);
1640 if (SDL_MUSTLOCK(Surface))
1642 SDL_UnlockSurface(Surface);
1646 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1647 Uint8 R, Uint8 G, Uint8 B)
1649 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1652 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1663 /* Do the clipping */
1664 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1668 if (y2 > Surface->h - 1)
1669 y2 = Surface->h - 1;
1676 SDL_FillRect(Surface, &l, Color);
1679 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1680 Sint16 x2, Sint16 y2, Uint32 Color,
1681 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1684 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1689 sdx = (dx < 0) ? -1 : 1;
1690 sdy = (dy < 0) ? -1 : 1;
1702 for (x = 0; x < dx; x++)
1704 Callback(Surface, px, py, Color);
1718 for (y = 0; y < dy; y++)
1720 Callback(Surface, px, py, Color);
1734 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1735 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1736 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1739 sge_DoLine(Surface, X1, Y1, X2, Y2,
1740 SDL_MapRGB(Surface->format, R, G, B), Callback);
1743 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1746 if (SDL_MUSTLOCK(Surface))
1748 if (SDL_LockSurface(Surface) < 0)
1753 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1755 /* unlock the display */
1756 if (SDL_MUSTLOCK(Surface))
1758 SDL_UnlockSurface(Surface);
1762 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1763 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1765 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1768 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1770 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1775 -----------------------------------------------------------------------------
1776 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1777 -----------------------------------------------------------------------------
1780 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1781 int width, int height, Uint32 color)
1785 for (y = src_y; y < src_y + height; y++)
1787 for (x = src_x; x < src_x + width; x++)
1789 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1791 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1796 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1797 int src_x, int src_y, int width, int height,
1798 int dst_x, int dst_y)
1802 for (y = 0; y < height; y++)
1804 for (x = 0; x < width; x++)
1806 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1808 if (pixel != BLACK_PIXEL)
1809 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1815 /* ========================================================================= */
1816 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1817 /* (Rotozoomer) by Andreas Schiffler */
1818 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1819 /* ========================================================================= */
1822 -----------------------------------------------------------------------------
1825 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1826 -----------------------------------------------------------------------------
1837 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1840 tColorRGBA *sp, *csp, *dp;
1844 sp = csp = (tColorRGBA *) src->pixels;
1845 dp = (tColorRGBA *) dst->pixels;
1846 dgap = dst->pitch - dst->w * 4;
1848 for (y = 0; y < dst->h; y++)
1852 for (x = 0; x < dst->w; x++)
1854 tColorRGBA *sp0 = sp;
1855 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1856 tColorRGBA *sp00 = &sp0[0];
1857 tColorRGBA *sp01 = &sp0[1];
1858 tColorRGBA *sp10 = &sp1[0];
1859 tColorRGBA *sp11 = &sp1[1];
1862 /* create new color pixel from all four source color pixels */
1863 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1864 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1865 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1866 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1871 /* advance source pointers */
1874 /* advance destination pointer */
1878 /* advance source pointer */
1879 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1881 /* advance destination pointers */
1882 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1888 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1890 int x, y, *sax, *say, *csax, *csay;
1892 tColorRGBA *sp, *csp, *csp0, *dp;
1895 /* use specialized zoom function when scaling down to exactly half size */
1896 if (src->w == 2 * dst->w &&
1897 src->h == 2 * dst->h)
1898 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1900 /* variable setup */
1901 sx = (float) src->w / (float) dst->w;
1902 sy = (float) src->h / (float) dst->h;
1904 /* allocate memory for row increments */
1905 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1906 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1908 /* precalculate row increments */
1909 for (x = 0; x <= dst->w; x++)
1910 *csax++ = (int)(sx * x);
1912 for (y = 0; y <= dst->h; y++)
1913 *csay++ = (int)(sy * y);
1916 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1917 dp = (tColorRGBA *) dst->pixels;
1918 dgap = dst->pitch - dst->w * 4;
1921 for (y = 0; y < dst->h; y++)
1926 for (x = 0; x < dst->w; x++)
1931 /* advance source pointers */
1935 /* advance destination pointer */
1939 /* advance source pointer */
1941 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1943 /* advance destination pointers */
1944 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1954 -----------------------------------------------------------------------------
1957 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1958 -----------------------------------------------------------------------------
1961 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1963 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1964 Uint8 *sp, *dp, *csp;
1967 /* variable setup */
1968 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1969 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1971 /* allocate memory for row increments */
1972 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1973 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1975 /* precalculate row increments */
1978 for (x = 0; x < dst->w; x++)
1981 *csax = (csx >> 16);
1988 for (y = 0; y < dst->h; y++)
1991 *csay = (csy >> 16);
1998 for (x = 0; x < dst->w; x++)
2006 for (y = 0; y < dst->h; y++)
2013 sp = csp = (Uint8 *) src->pixels;
2014 dp = (Uint8 *) dst->pixels;
2015 dgap = dst->pitch - dst->w;
2019 for (y = 0; y < dst->h; y++)
2023 for (x = 0; x < dst->w; x++)
2028 /* advance source pointers */
2032 /* advance destination pointer */
2036 /* advance source pointer (for row) */
2037 csp += ((*csay) * src->pitch);
2040 /* advance destination pointers */
2051 -----------------------------------------------------------------------------
2054 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2055 'zoomx' and 'zoomy' are scaling factors for width and height.
2056 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2057 into a 32bit RGBA format on the fly.
2058 -----------------------------------------------------------------------------
2061 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2063 SDL_Surface *zoom_src = NULL;
2064 SDL_Surface *zoom_dst = NULL;
2065 boolean is_converted = FALSE;
2072 /* determine if source surface is 32 bit or 8 bit */
2073 is_32bit = (src->format->BitsPerPixel == 32);
2075 if (is_32bit || src->format->BitsPerPixel == 8)
2077 /* use source surface 'as is' */
2082 /* new source surface is 32 bit with a defined RGB ordering */
2083 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2084 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2085 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2087 is_converted = TRUE;
2090 /* allocate surface to completely contain the zoomed surface */
2093 /* target surface is 32 bit with source RGBA/ABGR ordering */
2094 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2095 zoom_src->format->Rmask,
2096 zoom_src->format->Gmask,
2097 zoom_src->format->Bmask, 0);
2101 /* target surface is 8 bit */
2102 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2106 /* lock source surface */
2107 SDL_LockSurface(zoom_src);
2109 /* check which kind of surface we have */
2112 /* call the 32 bit transformation routine to do the zooming */
2113 zoomSurfaceRGBA(zoom_src, zoom_dst);
2118 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2119 zoom_dst->format->palette->colors[i] =
2120 zoom_src->format->palette->colors[i];
2121 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2123 /* call the 8 bit transformation routine to do the zooming */
2124 zoomSurfaceY(zoom_src, zoom_dst);
2127 /* unlock source surface */
2128 SDL_UnlockSurface(zoom_src);
2130 /* free temporary surface */
2132 SDL_FreeSurface(zoom_src);
2134 /* return destination surface */
2138 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2140 Bitmap *dst_bitmap = CreateBitmapStruct();
2141 SDL_Surface **dst_surface = &dst_bitmap->surface;
2143 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2144 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2146 dst_bitmap->width = dst_width;
2147 dst_bitmap->height = dst_height;
2149 /* create zoomed temporary surface from source surface */
2150 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2152 /* create native format destination surface from zoomed temporary surface */
2153 SDLSetNativeSurface(dst_surface);
2159 /* ========================================================================= */
2160 /* load image to bitmap */
2161 /* ========================================================================= */
2163 Bitmap *SDLLoadImage(char *filename)
2165 Bitmap *new_bitmap = CreateBitmapStruct();
2166 SDL_Surface *sdl_image_tmp;
2168 print_timestamp_init("SDLLoadImage");
2170 print_timestamp_time(getBaseNamePtr(filename));
2172 /* load image to temporary surface */
2173 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2175 SetError("IMG_Load(): %s", SDL_GetError());
2180 print_timestamp_time("IMG_Load");
2182 UPDATE_BUSY_STATE();
2184 /* create native non-transparent surface for current image */
2185 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2187 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2192 print_timestamp_time("SDL_DisplayFormat (opaque)");
2194 UPDATE_BUSY_STATE();
2196 /* create native transparent surface for current image */
2197 if (sdl_image_tmp->format->Amask == 0)
2198 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2199 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2201 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2203 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2208 print_timestamp_time("SDL_DisplayFormat (masked)");
2210 UPDATE_BUSY_STATE();
2212 /* free temporary surface */
2213 SDL_FreeSurface(sdl_image_tmp);
2215 new_bitmap->width = new_bitmap->surface->w;
2216 new_bitmap->height = new_bitmap->surface->h;
2218 print_timestamp_done("SDLLoadImage");
2224 /* ------------------------------------------------------------------------- */
2225 /* custom cursor fuctions */
2226 /* ------------------------------------------------------------------------- */
2228 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2230 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2231 cursor_info->width, cursor_info->height,
2232 cursor_info->hot_x, cursor_info->hot_y);
2235 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2237 static struct MouseCursorInfo *last_cursor_info = NULL;
2238 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2239 static SDL_Cursor *cursor_default = NULL;
2240 static SDL_Cursor *cursor_current = NULL;
2242 /* if invoked for the first time, store the SDL default cursor */
2243 if (cursor_default == NULL)
2244 cursor_default = SDL_GetCursor();
2246 /* only create new cursor if cursor info (custom only) has changed */
2247 if (cursor_info != NULL && cursor_info != last_cursor_info)
2249 cursor_current = create_cursor(cursor_info);
2250 last_cursor_info = cursor_info;
2253 /* only set new cursor if cursor info (custom or NULL) has changed */
2254 if (cursor_info != last_cursor_info2)
2255 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2257 last_cursor_info2 = cursor_info;
2261 /* ========================================================================= */
2262 /* audio functions */
2263 /* ========================================================================= */
2265 void SDLOpenAudio(void)
2267 #if !defined(TARGET_SDL2)
2268 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2269 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2272 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2274 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2278 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2279 AUDIO_NUM_CHANNELS_STEREO,
2280 setup.system.audio_fragment_size) < 0)
2282 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2286 audio.sound_available = TRUE;
2287 audio.music_available = TRUE;
2288 audio.loops_available = TRUE;
2289 audio.sound_enabled = TRUE;
2291 /* set number of available mixer channels */
2292 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2293 audio.music_channel = MUSIC_CHANNEL;
2294 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2296 Mixer_InitChannels();
2299 void SDLCloseAudio(void)
2302 Mix_HaltChannel(-1);
2305 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2309 /* ========================================================================= */
2310 /* event functions */
2311 /* ========================================================================= */
2313 void SDLNextEvent(Event *event)
2315 SDL_WaitEvent(event);
2318 void SDLHandleWindowManagerEvent(Event *event)
2321 #if defined(PLATFORM_WIN32)
2322 // experimental drag and drop code
2324 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2325 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2327 #if defined(TARGET_SDL2)
2328 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2330 if (syswmmsg->msg == WM_DROPFILES)
2333 #if defined(TARGET_SDL2)
2334 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2336 HDROP hdrop = (HDROP)syswmmsg->wParam;
2340 printf("::: SDL_SYSWMEVENT:\n");
2342 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2344 for (i = 0; i < num_files; i++)
2346 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2347 char buffer[buffer_len + 1];
2349 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2351 printf("::: - '%s'\n", buffer);
2354 #if defined(TARGET_SDL2)
2355 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2357 DragFinish((HDROP)syswmmsg->wParam);
2365 /* ========================================================================= */
2366 /* joystick functions */
2367 /* ========================================================================= */
2369 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2370 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2371 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2373 static boolean SDLOpenJoystick(int nr)
2375 if (nr < 0 || nr > MAX_PLAYERS)
2378 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2381 static void SDLCloseJoystick(int nr)
2383 if (nr < 0 || nr > MAX_PLAYERS)
2386 SDL_JoystickClose(sdl_joystick[nr]);
2388 sdl_joystick[nr] = NULL;
2391 static boolean SDLCheckJoystickOpened(int nr)
2393 if (nr < 0 || nr > MAX_PLAYERS)
2396 #if defined(TARGET_SDL2)
2397 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2399 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2403 void HandleJoystickEvent(Event *event)
2407 case SDL_JOYAXISMOTION:
2408 if (event->jaxis.axis < 2)
2409 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2412 case SDL_JOYBUTTONDOWN:
2413 if (event->jbutton.button < 2)
2414 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2417 case SDL_JOYBUTTONUP:
2418 if (event->jbutton.button < 2)
2419 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2427 void SDLInitJoysticks()
2429 static boolean sdl_joystick_subsystem_initialized = FALSE;
2430 boolean print_warning = !sdl_joystick_subsystem_initialized;
2433 if (!sdl_joystick_subsystem_initialized)
2435 sdl_joystick_subsystem_initialized = TRUE;
2437 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2439 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2444 for (i = 0; i < MAX_PLAYERS; i++)
2446 /* get configured joystick for this player */
2447 char *device_name = setup.input[i].joy.device_name;
2448 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2450 if (joystick_nr >= SDL_NumJoysticks())
2452 if (setup.input[i].use_joystick && print_warning)
2453 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2458 /* misuse joystick file descriptor variable to store joystick number */
2459 joystick.fd[i] = joystick_nr;
2461 if (joystick_nr == -1)
2464 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2465 if (SDLCheckJoystickOpened(joystick_nr))
2466 SDLCloseJoystick(joystick_nr);
2468 if (!setup.input[i].use_joystick)
2471 if (!SDLOpenJoystick(joystick_nr))
2474 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2479 joystick.status = JOYSTICK_ACTIVATED;
2483 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2485 if (nr < 0 || nr >= MAX_PLAYERS)
2489 *x = sdl_js_axis[nr][0];
2491 *y = sdl_js_axis[nr][1];
2494 *b1 = sdl_js_button[nr][0];
2496 *b2 = sdl_js_button[nr][1];