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 #define USE_TARGET_TEXTURE TRUE
28 #define USE_TARGET_TEXTURE_ONLY FALSE
30 static SDL_Window *sdl_window = NULL;
31 static SDL_Renderer *sdl_renderer = NULL;
32 #if USE_TARGET_TEXTURE
33 static SDL_Texture *sdl_texture_stream = NULL;
34 static SDL_Texture *sdl_texture_target = NULL;
36 static SDL_Texture *sdl_texture = NULL;
38 static boolean fullscreen_enabled = FALSE;
41 static boolean limit_screen_updates = FALSE;
44 /* functions from SGE library */
45 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
47 void SDLLimitScreenUpdates(boolean enable)
49 limit_screen_updates = enable;
52 static void UpdateScreen(SDL_Rect *rect)
54 static unsigned int update_screen_delay = 0;
55 unsigned int update_screen_delay_value = 50; /* (milliseconds) */
56 SDL_Surface *screen = backbuffer->surface;
58 if (limit_screen_updates &&
59 !DelayReached(&update_screen_delay, update_screen_delay_value))
62 LimitScreenUpdates(FALSE);
66 static int LastFrameCounter = 0;
67 boolean changed = (FrameCounter != LastFrameCounter);
69 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
70 (changed ? "-" : "SAME FRAME UPDATED"));
72 LastFrameCounter = FrameCounter;
81 #if USE_FINAL_SCREEN_BITMAP
82 if (gfx.final_screen_bitmap != NULL) // may not be initialized yet
85 // draw global animations using bitmaps instead of using textures
86 // to prevent texture scaling artefacts (this is potentially slower)
88 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
89 gfx.win_xsize, gfx.win_ysize, 0, 0);
91 // copy global animations to render target buffer, if defined (below border)
92 if (gfx.draw_global_anim_function != NULL)
93 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
95 // copy global masked border to render target buffer, if defined
96 if (gfx.draw_global_border_function != NULL)
97 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
99 // copy global animations to render target buffer, if defined (above border)
100 if (gfx.draw_global_anim_function != NULL)
101 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
103 screen = gfx.final_screen_bitmap->surface;
105 // force full window redraw
110 #if USE_TARGET_TEXTURE
111 #if USE_TARGET_TEXTURE_ONLY
112 SDL_Texture *sdl_texture = sdl_texture_target;
114 SDL_Texture *sdl_texture = sdl_texture_stream;
118 #if defined(TARGET_SDL2)
121 int bytes_x = screen->pitch / video.width;
122 int bytes_y = screen->pitch;
124 SDL_UpdateTexture(sdl_texture, rect,
125 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
130 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
133 // clear render target buffer
134 SDL_RenderClear(sdl_renderer);
136 #if USE_TARGET_TEXTURE
137 SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
139 // copy backbuffer to render target buffer
140 if (sdl_texture != sdl_texture_target)
141 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
143 // copy backbuffer to render target buffer
144 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
147 #if !USE_FINAL_SCREEN_BITMAP
148 // copy global animations to render target buffer, if defined (below border)
149 if (gfx.draw_global_anim_function != NULL)
150 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
152 // copy global masked border to render target buffer, if defined
153 if (gfx.draw_global_border_function != NULL)
154 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
156 // copy global animations to render target buffer, if defined (above border)
157 if (gfx.draw_global_anim_function != NULL)
158 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
161 #if USE_TARGET_TEXTURE
162 SDL_SetRenderTarget(sdl_renderer, NULL);
163 SDL_RenderCopy(sdl_renderer, sdl_texture_target, NULL, NULL);
166 // show render target buffer on screen
167 SDL_RenderPresent(sdl_renderer);
171 SDL_UpdateRects(screen, 1, rect);
173 SDL_UpdateRect(screen, 0, 0, 0, 0);
177 static void SDLSetWindowIcon(char *basename)
179 /* (setting the window icon on Mac OS X would replace the high-quality
180 dock icon with the currently smaller (and uglier) icon from file) */
182 #if !defined(PLATFORM_MACOSX)
183 char *filename = getCustomImageFilename(basename);
184 SDL_Surface *surface;
186 if (filename == NULL)
188 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
193 if ((surface = IMG_Load(filename)) == NULL)
195 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
200 /* set transparent color */
201 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
202 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
204 #if defined(TARGET_SDL2)
205 SDL_SetWindowIcon(sdl_window, surface);
207 SDL_WM_SetIcon(surface, NULL);
212 #if defined(TARGET_SDL2)
214 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
215 SDL_PixelFormat *format2)
217 return (format1->format == format2->format &&
218 format1->BitsPerPixel == format2->BitsPerPixel &&
219 format1->BytesPerPixel == format2->BytesPerPixel &&
220 format1->Rmask == format2->Rmask &&
221 format1->Gmask == format2->Gmask &&
222 format1->Bmask == format2->Bmask &&
223 format1->Amask == format2->Amask);
226 boolean SDLSetNativeSurface(SDL_Surface **surface)
228 SDL_Surface *new_surface;
230 if (surface == NULL ||
232 backbuffer == NULL ||
233 backbuffer->surface == NULL)
236 // if pixel format already optimized for destination surface, do nothing
237 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
240 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
242 if (new_surface == NULL)
243 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
245 SDL_FreeSurface(*surface);
247 *surface = new_surface;
252 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
254 SDL_PixelFormat format;
255 SDL_Surface *new_surface;
260 if (backbuffer && backbuffer->surface)
262 format = *backbuffer->surface->format;
263 format.Amask = surface->format->Amask; // keep alpha channel
267 format = *surface->format;
270 new_surface = SDL_ConvertSurface(surface, &format, 0);
272 if (new_surface == NULL)
273 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
280 boolean SDLSetNativeSurface(SDL_Surface **surface)
282 SDL_Surface *new_surface;
284 if (surface == NULL ||
289 new_surface = SDL_DisplayFormat(*surface);
291 if (new_surface == NULL)
292 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
294 SDL_FreeSurface(*surface);
296 *surface = new_surface;
301 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
303 SDL_Surface *new_surface;
305 if (video.initialized)
306 new_surface = SDL_DisplayFormat(surface);
308 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
310 if (new_surface == NULL)
311 Error(ERR_EXIT, "%s() failed: %s",
312 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
320 #if defined(TARGET_SDL2)
321 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
323 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
326 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
333 void SDLCreateBitmapTextures(Bitmap *bitmap)
335 #if defined(TARGET_SDL2)
340 SDL_DestroyTexture(bitmap->texture);
341 if (bitmap->texture_masked)
342 SDL_DestroyTexture(bitmap->texture_masked);
344 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
345 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
349 void SDLFreeBitmapTextures(Bitmap *bitmap)
351 #if defined(TARGET_SDL2)
356 SDL_DestroyTexture(bitmap->texture);
357 if (bitmap->texture_masked)
358 SDL_DestroyTexture(bitmap->texture_masked);
360 bitmap->texture = NULL;
361 bitmap->texture_masked = NULL;
365 void SDLInitVideoDisplay(void)
367 #if !defined(TARGET_SDL2)
368 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
369 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
371 SDL_putenv("SDL_VIDEO_CENTERED=1");
374 /* initialize SDL video */
375 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
376 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
378 /* set default SDL depth */
379 #if !defined(TARGET_SDL2)
380 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
382 video.default_depth = 32; // (how to determine video depth in SDL2?)
386 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
389 video.window_scaling_percent = setup.window_scaling_percent;
390 video.window_scaling_quality = setup.window_scaling_quality;
392 #if defined(TARGET_SDL2)
393 // SDL 2.0: support for (desktop) fullscreen mode available
394 video.fullscreen_available = TRUE;
396 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
397 video.fullscreen_available = FALSE;
400 /* open SDL video output device (window or fullscreen mode) */
401 if (!SDLSetVideoMode(backbuffer, fullscreen))
402 Error(ERR_EXIT, "setting video mode failed");
404 /* !!! SDL2 can only set the window icon if the window already exists !!! */
405 /* set window icon */
406 SDLSetWindowIcon(program.icon_filename);
408 /* set window and icon title */
409 #if defined(TARGET_SDL2)
410 SDL_SetWindowTitle(sdl_window, program.window_title);
412 SDL_WM_SetCaption(program.window_title, program.window_title);
415 /* SDL cannot directly draw to the visible video framebuffer like X11,
416 but always uses a backbuffer, which is then blitted to the visible
417 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
418 visible video framebuffer with 'SDL_Flip', if the hardware supports
419 this). Therefore do not use an additional backbuffer for drawing, but
420 use a symbolic buffer (distinguishable from the SDL backbuffer) called
421 'window', which indicates that the SDL backbuffer should be updated to
422 the visible video framebuffer when attempting to blit to it.
424 For convenience, it seems to be a good idea to create this symbolic
425 buffer 'window' at the same size as the SDL backbuffer. Although it
426 should never be drawn to directly, it would do no harm nevertheless. */
428 /* create additional (symbolic) buffer for double-buffering */
429 ReCreateBitmap(window, video.width, video.height, video.depth);
432 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
435 SDL_Surface *new_surface = NULL;
437 #if defined(TARGET_SDL2)
438 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
439 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
441 int surface_flags_window = SURFACE_FLAGS;
442 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
445 int width = video.width;
446 int height = video.height;
447 int surface_flags = (fullscreen ? surface_flags_fullscreen :
448 surface_flags_window);
450 // default window size is unscaled
451 video.window_width = video.width;
452 video.window_height = video.height;
454 #if defined(TARGET_SDL2)
456 // store if initial screen mode is fullscreen mode when changing screen size
457 video.fullscreen_initial = fullscreen;
459 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
461 video.window_width = window_scaling_factor * width;
462 video.window_height = window_scaling_factor * height;
464 if ((*backbuffer)->surface)
466 SDL_FreeSurface((*backbuffer)->surface);
467 (*backbuffer)->surface = NULL;
470 #if USE_TARGET_TEXTURE
471 if (sdl_texture_stream)
473 SDL_DestroyTexture(sdl_texture_stream);
474 sdl_texture_stream = NULL;
477 if (sdl_texture_target)
479 SDL_DestroyTexture(sdl_texture_target);
480 sdl_texture_target = NULL;
485 SDL_DestroyTexture(sdl_texture);
490 if (!(fullscreen && fullscreen_enabled))
494 SDL_DestroyRenderer(sdl_renderer);
500 SDL_DestroyWindow(sdl_window);
505 if (sdl_window == NULL)
506 sdl_window = SDL_CreateWindow(program.window_title,
507 SDL_WINDOWPOS_CENTERED,
508 SDL_WINDOWPOS_CENTERED,
513 if (sdl_window != NULL)
516 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
517 *without* enabling 2D/3D acceleration and/or guest additions installed,
518 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
519 it will try to use accelerated graphics and apparently fails miserably) */
520 if (sdl_renderer == NULL)
521 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
523 if (sdl_renderer == NULL)
524 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
527 if (sdl_renderer != NULL)
529 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
530 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
531 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
533 #if USE_TARGET_TEXTURE
534 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
535 SDL_PIXELFORMAT_ARGB8888,
536 SDL_TEXTUREACCESS_STREAMING,
539 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
540 SDL_PIXELFORMAT_ARGB8888,
541 SDL_TEXTUREACCESS_TARGET,
544 sdl_texture = SDL_CreateTexture(sdl_renderer,
545 SDL_PIXELFORMAT_ARGB8888,
546 SDL_TEXTUREACCESS_STREAMING,
550 #if USE_TARGET_TEXTURE
551 if (sdl_texture_stream != NULL &&
552 sdl_texture_target != NULL)
554 if (sdl_texture != NULL)
557 // use SDL default values for RGB masks and no alpha channel
558 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
560 if (new_surface == NULL)
561 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
565 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
570 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
575 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
580 if ((*backbuffer)->surface)
582 SDL_FreeSurface((*backbuffer)->surface);
583 (*backbuffer)->surface = NULL;
586 if (gfx.final_screen_bitmap == NULL)
587 gfx.final_screen_bitmap = CreateBitmapStruct();
589 gfx.final_screen_bitmap->width = width;
590 gfx.final_screen_bitmap->height = height;
592 gfx.final_screen_bitmap->surface =
593 SDL_SetVideoMode(width, height, video.depth, surface_flags);
595 if (gfx.final_screen_bitmap->surface != NULL)
598 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
600 if (new_surface == NULL)
601 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
604 new_surface = gfx.final_screen_bitmap->surface;
605 gfx.final_screen_bitmap = NULL;
611 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
615 #if defined(TARGET_SDL2)
616 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
617 if (new_surface != NULL)
618 fullscreen_enabled = fullscreen;
624 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
626 boolean success = TRUE;
627 SDL_Surface *new_surface = NULL;
631 if (*backbuffer == NULL)
632 *backbuffer = CreateBitmapStruct();
634 /* (real bitmap might be larger in fullscreen mode with video offsets) */
635 (*backbuffer)->width = video.width;
636 (*backbuffer)->height = video.height;
638 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
640 /* switch display to fullscreen mode, if available */
641 new_surface = SDLCreateScreen(backbuffer, TRUE);
643 if (new_surface == NULL)
645 /* switching display to fullscreen mode failed -- do not try it again */
646 video.fullscreen_available = FALSE;
652 (*backbuffer)->surface = new_surface;
654 video.fullscreen_enabled = TRUE;
660 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
662 /* switch display to window mode */
663 new_surface = SDLCreateScreen(backbuffer, FALSE);
665 if (new_surface == NULL)
667 /* switching display to window mode failed -- should not happen */
673 (*backbuffer)->surface = new_surface;
675 video.fullscreen_enabled = FALSE;
676 video.window_scaling_percent = setup.window_scaling_percent;
677 video.window_scaling_quality = setup.window_scaling_quality;
683 #if defined(TARGET_SDL2)
684 SDLRedrawWindow(); // map window
688 #if defined(PLATFORM_WIN32)
689 // experimental drag and drop code
691 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
694 SDL_SysWMinfo wminfo;
696 boolean wminfo_success = FALSE;
698 SDL_VERSION(&wminfo.version);
699 #if defined(TARGET_SDL2)
701 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
703 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
708 #if defined(TARGET_SDL2)
709 hwnd = wminfo.info.win.window;
711 hwnd = wminfo.window;
714 DragAcceptFiles(hwnd, TRUE);
723 void SDLSetWindowTitle()
725 #if defined(TARGET_SDL2)
726 SDL_SetWindowTitle(sdl_window, program.window_title);
728 SDL_WM_SetCaption(program.window_title, program.window_title);
732 #if defined(TARGET_SDL2)
733 void SDLSetWindowScaling(int window_scaling_percent)
735 if (sdl_window == NULL)
738 float window_scaling_factor = (float)window_scaling_percent / 100;
739 int new_window_width = (int)(window_scaling_factor * video.width);
740 int new_window_height = (int)(window_scaling_factor * video.height);
742 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
744 video.window_scaling_percent = window_scaling_percent;
745 video.window_width = new_window_width;
746 video.window_height = new_window_height;
751 void SDLSetWindowScalingQuality(char *window_scaling_quality)
753 #if USE_TARGET_TEXTURE
754 SDL_Texture *new_texture;
756 if (sdl_texture_stream == NULL ||
757 sdl_texture_target == NULL)
760 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
762 new_texture = SDL_CreateTexture(sdl_renderer,
763 SDL_PIXELFORMAT_ARGB8888,
764 SDL_TEXTUREACCESS_STREAMING,
765 video.width, video.height);
767 if (new_texture != NULL)
769 SDL_DestroyTexture(sdl_texture_stream);
771 sdl_texture_stream = new_texture;
774 new_texture = SDL_CreateTexture(sdl_renderer,
775 SDL_PIXELFORMAT_ARGB8888,
776 SDL_TEXTUREACCESS_TARGET,
777 video.width, video.height);
779 if (new_texture != NULL)
781 SDL_DestroyTexture(sdl_texture_target);
783 sdl_texture_target = new_texture;
789 if (sdl_texture == NULL)
792 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
794 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
795 SDL_PIXELFORMAT_ARGB8888,
796 SDL_TEXTUREACCESS_STREAMING,
797 video.width, video.height);
799 if (new_texture != NULL)
801 SDL_DestroyTexture(sdl_texture);
803 sdl_texture = new_texture;
809 video.window_scaling_quality = window_scaling_quality;
812 void SDLSetWindowFullscreen(boolean fullscreen)
814 if (sdl_window == NULL)
817 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
819 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
820 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
822 // if screen size was changed in fullscreen mode, correct desktop window size
823 if (!fullscreen && video.fullscreen_initial)
825 SDLSetWindowScaling(setup.window_scaling_percent);
826 SDL_SetWindowPosition(sdl_window,
827 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
829 video.fullscreen_initial = FALSE;
833 void SDLRedrawWindow()
839 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
842 SDL_Surface *surface =
843 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
846 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
848 SDLSetNativeSurface(&surface);
850 bitmap->surface = surface;
853 void SDLFreeBitmapPointers(Bitmap *bitmap)
856 SDL_FreeSurface(bitmap->surface);
857 if (bitmap->surface_masked)
858 SDL_FreeSurface(bitmap->surface_masked);
860 bitmap->surface = NULL;
861 bitmap->surface_masked = NULL;
863 #if defined(TARGET_SDL2)
865 SDL_DestroyTexture(bitmap->texture);
866 if (bitmap->texture_masked)
867 SDL_DestroyTexture(bitmap->texture_masked);
869 bitmap->texture = NULL;
870 bitmap->texture_masked = NULL;
874 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
875 int src_x, int src_y, int width, int height,
876 int dst_x, int dst_y, int mask_mode)
878 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
879 SDL_Rect src_rect, dst_rect;
891 // if (src_bitmap != backbuffer || dst_bitmap != window)
892 if (!(src_bitmap == backbuffer && dst_bitmap == window))
893 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
894 src_bitmap->surface_masked : src_bitmap->surface),
895 &src_rect, real_dst_bitmap->surface, &dst_rect);
897 if (dst_bitmap == window)
898 UpdateScreen(&dst_rect);
901 void SDLBlitTexture(Bitmap *bitmap,
902 int src_x, int src_y, int width, int height,
903 int dst_x, int dst_y, int mask_mode)
905 #if defined(TARGET_SDL2)
906 SDL_Texture *texture;
911 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
926 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
930 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
933 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
941 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
943 #if defined(TARGET_SDL2)
944 if (dst_bitmap == window)
946 // SDL_UpdateWindowSurface(sdl_window);
947 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
951 if (dst_bitmap == window)
953 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
959 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
960 int fade_mode, int fade_delay, int post_delay,
961 void (*draw_border_function)(void))
963 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
964 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
965 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
966 SDL_Surface *surface_screen = backbuffer->surface;
967 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
968 SDL_Rect src_rect, dst_rect;
970 int src_x = x, src_y = y;
971 int dst_x = x, dst_y = y;
972 unsigned int time_last, time_current;
974 // store function for drawing global masked border
975 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
977 // deactivate drawing of global border while fading, if needed
978 if (draw_border_function == NULL)
979 gfx.draw_global_border_function = NULL;
988 dst_rect.w = width; /* (ignored) */
989 dst_rect.h = height; /* (ignored) */
991 dst_rect2 = dst_rect;
993 /* copy source and target surfaces to temporary surfaces for fading */
994 if (fade_mode & FADE_TYPE_TRANSFORM)
996 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
997 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
999 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
1000 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
1002 else if (fade_mode & FADE_TYPE_FADE_IN)
1004 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1005 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1007 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
1009 else /* FADE_TYPE_FADE_OUT */
1011 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1012 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1014 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
1017 time_current = SDL_GetTicks();
1019 if (fade_mode == FADE_MODE_MELT)
1021 boolean done = FALSE;
1022 int melt_pixels = 2;
1023 int melt_columns = width / melt_pixels;
1024 int ypos[melt_columns];
1025 int max_steps = height / 8 + 32;
1030 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1031 #if defined(TARGET_SDL2)
1032 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1034 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1037 ypos[0] = -GetSimpleRandom(16);
1039 for (i = 1 ; i < melt_columns; i++)
1041 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1043 ypos[i] = ypos[i - 1] + r;
1056 time_last = time_current;
1057 time_current = SDL_GetTicks();
1058 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1059 steps_final = MIN(MAX(0, steps), max_steps);
1063 done = (steps_done >= steps_final);
1065 for (i = 0 ; i < melt_columns; i++)
1073 else if (ypos[i] < height)
1078 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1080 if (ypos[i] + dy >= height)
1081 dy = height - ypos[i];
1083 /* copy part of (appearing) target surface to upper area */
1084 src_rect.x = src_x + i * melt_pixels;
1085 // src_rect.y = src_y + ypos[i];
1087 src_rect.w = melt_pixels;
1089 src_rect.h = ypos[i] + dy;
1091 dst_rect.x = dst_x + i * melt_pixels;
1092 // dst_rect.y = dst_y + ypos[i];
1095 if (steps_done >= steps_final)
1096 SDL_BlitSurface(surface_target, &src_rect,
1097 surface_screen, &dst_rect);
1101 /* copy part of (disappearing) source surface to lower area */
1102 src_rect.x = src_x + i * melt_pixels;
1104 src_rect.w = melt_pixels;
1105 src_rect.h = height - ypos[i];
1107 dst_rect.x = dst_x + i * melt_pixels;
1108 dst_rect.y = dst_y + ypos[i];
1110 if (steps_done >= steps_final)
1111 SDL_BlitSurface(surface_source, &src_rect,
1112 surface_screen, &dst_rect);
1118 src_rect.x = src_x + i * melt_pixels;
1120 src_rect.w = melt_pixels;
1121 src_rect.h = height;
1123 dst_rect.x = dst_x + i * melt_pixels;
1126 if (steps_done >= steps_final)
1127 SDL_BlitSurface(surface_target, &src_rect,
1128 surface_screen, &dst_rect);
1132 if (steps_done >= steps_final)
1134 if (draw_border_function != NULL)
1135 draw_border_function();
1137 UpdateScreen(&dst_rect2);
1141 else if (fade_mode == FADE_MODE_CURTAIN)
1145 int xx_size = width / 2;
1147 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1148 #if defined(TARGET_SDL2)
1149 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1151 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1154 for (xx = 0; xx < xx_size;)
1156 time_last = time_current;
1157 time_current = SDL_GetTicks();
1158 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1159 xx_final = MIN(MAX(0, xx), xx_size);
1164 src_rect.h = height;
1169 /* draw new (target) image to screen buffer */
1170 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1172 if (xx_final < xx_size)
1174 src_rect.w = xx_size - xx_final;
1175 src_rect.h = height;
1177 /* draw old (source) image to screen buffer (left side) */
1179 src_rect.x = src_x + xx_final;
1182 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1184 /* draw old (source) image to screen buffer (right side) */
1186 src_rect.x = src_x + xx_size;
1187 dst_rect.x = dst_x + xx_size + xx_final;
1189 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1192 if (draw_border_function != NULL)
1193 draw_border_function();
1195 /* only update the region of the screen that is affected from fading */
1196 UpdateScreen(&dst_rect2);
1199 else /* fading in, fading out or cross-fading */
1204 for (alpha = 0.0; alpha < 255.0;)
1206 time_last = time_current;
1207 time_current = SDL_GetTicks();
1208 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1209 alpha_final = MIN(MAX(0, alpha), 255);
1211 /* draw existing (source) image to screen buffer */
1212 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1214 /* draw new (target) image to screen buffer using alpha blending */
1215 #if defined(TARGET_SDL2)
1216 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1217 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1219 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1221 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1223 if (draw_border_function != NULL)
1224 draw_border_function();
1226 /* only update the region of the screen that is affected from fading */
1227 UpdateScreen(&dst_rect);
1233 unsigned int time_post_delay;
1235 time_current = SDL_GetTicks();
1236 time_post_delay = time_current + post_delay;
1238 while (time_current < time_post_delay)
1240 // do not wait longer than 10 ms at a time to be able to ...
1241 Delay(MIN(10, time_post_delay - time_current));
1243 // ... continue drawing global animations during post delay
1246 time_current = SDL_GetTicks();
1250 // restore function for drawing global masked border
1251 gfx.draw_global_border_function = draw_global_border_function;
1254 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1255 int to_x, int to_y, Uint32 color)
1257 SDL_Surface *surface = dst_bitmap->surface;
1261 swap_numbers(&from_x, &to_x);
1264 swap_numbers(&from_y, &to_y);
1268 rect.w = (to_x - from_x + 1);
1269 rect.h = (to_y - from_y + 1);
1271 SDL_FillRect(surface, &rect, color);
1274 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1275 int to_x, int to_y, Uint32 color)
1277 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1280 #if ENABLE_UNUSED_CODE
1281 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1282 int num_points, Uint32 color)
1287 for (i = 0; i < num_points - 1; i++)
1289 for (x = 0; x < line_width; x++)
1291 for (y = 0; y < line_width; y++)
1293 int dx = x - line_width / 2;
1294 int dy = y - line_width / 2;
1296 if ((x == 0 && y == 0) ||
1297 (x == 0 && y == line_width - 1) ||
1298 (x == line_width - 1 && y == 0) ||
1299 (x == line_width - 1 && y == line_width - 1))
1302 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1303 points[i+1].x + dx, points[i+1].y + dy, color);
1310 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1312 SDL_Surface *surface = src_bitmap->surface;
1314 switch (surface->format->BytesPerPixel)
1316 case 1: /* assuming 8-bpp */
1318 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1322 case 2: /* probably 15-bpp or 16-bpp */
1324 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1328 case 3: /* slow 24-bpp mode; usually not used */
1330 /* does this work? */
1331 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1335 shift = surface->format->Rshift;
1336 color |= *(pix + shift / 8) >> shift;
1337 shift = surface->format->Gshift;
1338 color |= *(pix + shift / 8) >> shift;
1339 shift = surface->format->Bshift;
1340 color |= *(pix + shift / 8) >> shift;
1346 case 4: /* probably 32-bpp */
1348 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1357 /* ========================================================================= */
1358 /* The following functions were taken from the SGE library */
1359 /* (SDL Graphics Extension Library) by Anders Lindström */
1360 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1361 /* ========================================================================= */
1363 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1365 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1367 switch (surface->format->BytesPerPixel)
1371 /* Assuming 8-bpp */
1372 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1378 /* Probably 15-bpp or 16-bpp */
1379 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1385 /* Slow 24-bpp mode, usually not used */
1389 /* Gack - slow, but endian correct */
1390 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1391 shift = surface->format->Rshift;
1392 *(pix+shift/8) = color>>shift;
1393 shift = surface->format->Gshift;
1394 *(pix+shift/8) = color>>shift;
1395 shift = surface->format->Bshift;
1396 *(pix+shift/8) = color>>shift;
1402 /* Probably 32-bpp */
1403 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1410 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1411 Uint8 R, Uint8 G, Uint8 B)
1413 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1416 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1418 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1421 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1423 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1426 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1431 /* Gack - slow, but endian correct */
1432 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1433 shift = surface->format->Rshift;
1434 *(pix+shift/8) = color>>shift;
1435 shift = surface->format->Gshift;
1436 *(pix+shift/8) = color>>shift;
1437 shift = surface->format->Bshift;
1438 *(pix+shift/8) = color>>shift;
1441 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1443 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1446 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1448 switch (dest->format->BytesPerPixel)
1451 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1455 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1459 _PutPixel24(dest,x,y,color);
1463 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1468 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1470 if (SDL_MUSTLOCK(surface))
1472 if (SDL_LockSurface(surface) < 0)
1478 _PutPixel(surface, x, y, color);
1480 if (SDL_MUSTLOCK(surface))
1482 SDL_UnlockSurface(surface);
1486 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1487 Uint8 r, Uint8 g, Uint8 b)
1489 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1492 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1494 if (y >= 0 && y <= dest->h - 1)
1496 switch (dest->format->BytesPerPixel)
1499 return y*dest->pitch;
1503 return y*dest->pitch/2;
1507 return y*dest->pitch;
1511 return y*dest->pitch/4;
1519 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1521 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1523 switch (surface->format->BytesPerPixel)
1527 /* Assuming 8-bpp */
1528 *((Uint8 *)surface->pixels + ypitch + x) = color;
1534 /* Probably 15-bpp or 16-bpp */
1535 *((Uint16 *)surface->pixels + ypitch + x) = color;
1541 /* Slow 24-bpp mode, usually not used */
1545 /* Gack - slow, but endian correct */
1546 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1547 shift = surface->format->Rshift;
1548 *(pix+shift/8) = color>>shift;
1549 shift = surface->format->Gshift;
1550 *(pix+shift/8) = color>>shift;
1551 shift = surface->format->Bshift;
1552 *(pix+shift/8) = color>>shift;
1558 /* Probably 32-bpp */
1559 *((Uint32 *)surface->pixels + ypitch + x) = color;
1566 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1571 if (SDL_MUSTLOCK(Surface))
1573 if (SDL_LockSurface(Surface) < 0)
1586 /* Do the clipping */
1587 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1591 if (x2 > Surface->w - 1)
1592 x2 = Surface->w - 1;
1599 SDL_FillRect(Surface, &l, Color);
1601 if (SDL_MUSTLOCK(Surface))
1603 SDL_UnlockSurface(Surface);
1607 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1608 Uint8 R, Uint8 G, Uint8 B)
1610 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1613 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1624 /* Do the clipping */
1625 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1629 if (x2 > Surface->w - 1)
1630 x2 = Surface->w - 1;
1637 SDL_FillRect(Surface, &l, Color);
1640 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1645 if (SDL_MUSTLOCK(Surface))
1647 if (SDL_LockSurface(Surface) < 0)
1660 /* Do the clipping */
1661 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1665 if (y2 > Surface->h - 1)
1666 y2 = Surface->h - 1;
1673 SDL_FillRect(Surface, &l, Color);
1675 if (SDL_MUSTLOCK(Surface))
1677 SDL_UnlockSurface(Surface);
1681 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1682 Uint8 R, Uint8 G, Uint8 B)
1684 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1687 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1698 /* Do the clipping */
1699 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1703 if (y2 > Surface->h - 1)
1704 y2 = Surface->h - 1;
1711 SDL_FillRect(Surface, &l, Color);
1714 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1715 Sint16 x2, Sint16 y2, Uint32 Color,
1716 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1719 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1724 sdx = (dx < 0) ? -1 : 1;
1725 sdy = (dy < 0) ? -1 : 1;
1737 for (x = 0; x < dx; x++)
1739 Callback(Surface, px, py, Color);
1753 for (y = 0; y < dy; y++)
1755 Callback(Surface, px, py, Color);
1769 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1770 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1771 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1774 sge_DoLine(Surface, X1, Y1, X2, Y2,
1775 SDL_MapRGB(Surface->format, R, G, B), Callback);
1778 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1781 if (SDL_MUSTLOCK(Surface))
1783 if (SDL_LockSurface(Surface) < 0)
1788 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1790 /* unlock the display */
1791 if (SDL_MUSTLOCK(Surface))
1793 SDL_UnlockSurface(Surface);
1797 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1798 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1800 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1803 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1805 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1810 -----------------------------------------------------------------------------
1811 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1812 -----------------------------------------------------------------------------
1815 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1816 int width, int height, Uint32 color)
1820 for (y = src_y; y < src_y + height; y++)
1822 for (x = src_x; x < src_x + width; x++)
1824 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1826 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1831 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1832 int src_x, int src_y, int width, int height,
1833 int dst_x, int dst_y)
1837 for (y = 0; y < height; y++)
1839 for (x = 0; x < width; x++)
1841 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1843 if (pixel != BLACK_PIXEL)
1844 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1850 /* ========================================================================= */
1851 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1852 /* (Rotozoomer) by Andreas Schiffler */
1853 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1854 /* ========================================================================= */
1857 -----------------------------------------------------------------------------
1860 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1861 -----------------------------------------------------------------------------
1872 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1875 tColorRGBA *sp, *csp, *dp;
1879 sp = csp = (tColorRGBA *) src->pixels;
1880 dp = (tColorRGBA *) dst->pixels;
1881 dgap = dst->pitch - dst->w * 4;
1883 for (y = 0; y < dst->h; y++)
1887 for (x = 0; x < dst->w; x++)
1889 tColorRGBA *sp0 = sp;
1890 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1891 tColorRGBA *sp00 = &sp0[0];
1892 tColorRGBA *sp01 = &sp0[1];
1893 tColorRGBA *sp10 = &sp1[0];
1894 tColorRGBA *sp11 = &sp1[1];
1897 /* create new color pixel from all four source color pixels */
1898 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1899 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1900 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1901 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1906 /* advance source pointers */
1909 /* advance destination pointer */
1913 /* advance source pointer */
1914 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1916 /* advance destination pointers */
1917 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1923 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1925 int x, y, *sax, *say, *csax, *csay;
1927 tColorRGBA *sp, *csp, *csp0, *dp;
1930 /* use specialized zoom function when scaling down to exactly half size */
1931 if (src->w == 2 * dst->w &&
1932 src->h == 2 * dst->h)
1933 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1935 /* variable setup */
1936 sx = (float) src->w / (float) dst->w;
1937 sy = (float) src->h / (float) dst->h;
1939 /* allocate memory for row increments */
1940 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1941 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1943 /* precalculate row increments */
1944 for (x = 0; x <= dst->w; x++)
1945 *csax++ = (int)(sx * x);
1947 for (y = 0; y <= dst->h; y++)
1948 *csay++ = (int)(sy * y);
1951 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1952 dp = (tColorRGBA *) dst->pixels;
1953 dgap = dst->pitch - dst->w * 4;
1956 for (y = 0; y < dst->h; y++)
1961 for (x = 0; x < dst->w; x++)
1966 /* advance source pointers */
1970 /* advance destination pointer */
1974 /* advance source pointer */
1976 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1978 /* advance destination pointers */
1979 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1989 -----------------------------------------------------------------------------
1992 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1993 -----------------------------------------------------------------------------
1996 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1998 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1999 Uint8 *sp, *dp, *csp;
2002 /* variable setup */
2003 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2004 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2006 /* allocate memory for row increments */
2007 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2008 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2010 /* precalculate row increments */
2013 for (x = 0; x < dst->w; x++)
2016 *csax = (csx >> 16);
2023 for (y = 0; y < dst->h; y++)
2026 *csay = (csy >> 16);
2033 for (x = 0; x < dst->w; x++)
2041 for (y = 0; y < dst->h; y++)
2048 sp = csp = (Uint8 *) src->pixels;
2049 dp = (Uint8 *) dst->pixels;
2050 dgap = dst->pitch - dst->w;
2054 for (y = 0; y < dst->h; y++)
2058 for (x = 0; x < dst->w; x++)
2063 /* advance source pointers */
2067 /* advance destination pointer */
2071 /* advance source pointer (for row) */
2072 csp += ((*csay) * src->pitch);
2075 /* advance destination pointers */
2086 -----------------------------------------------------------------------------
2089 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2090 'zoomx' and 'zoomy' are scaling factors for width and height.
2091 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2092 into a 32bit RGBA format on the fly.
2093 -----------------------------------------------------------------------------
2096 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2098 SDL_Surface *zoom_src = NULL;
2099 SDL_Surface *zoom_dst = NULL;
2100 boolean is_converted = FALSE;
2107 /* determine if source surface is 32 bit or 8 bit */
2108 is_32bit = (src->format->BitsPerPixel == 32);
2110 if (is_32bit || src->format->BitsPerPixel == 8)
2112 /* use source surface 'as is' */
2117 /* new source surface is 32 bit with a defined RGB ordering */
2118 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2119 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2120 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2122 is_converted = TRUE;
2125 /* allocate surface to completely contain the zoomed surface */
2128 /* target surface is 32 bit with source RGBA/ABGR ordering */
2129 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2130 zoom_src->format->Rmask,
2131 zoom_src->format->Gmask,
2132 zoom_src->format->Bmask, 0);
2136 /* target surface is 8 bit */
2137 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2141 /* lock source surface */
2142 SDL_LockSurface(zoom_src);
2144 /* check which kind of surface we have */
2147 /* call the 32 bit transformation routine to do the zooming */
2148 zoomSurfaceRGBA(zoom_src, zoom_dst);
2153 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2154 zoom_dst->format->palette->colors[i] =
2155 zoom_src->format->palette->colors[i];
2156 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2158 /* call the 8 bit transformation routine to do the zooming */
2159 zoomSurfaceY(zoom_src, zoom_dst);
2162 /* unlock source surface */
2163 SDL_UnlockSurface(zoom_src);
2165 /* free temporary surface */
2167 SDL_FreeSurface(zoom_src);
2169 /* return destination surface */
2173 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2175 Bitmap *dst_bitmap = CreateBitmapStruct();
2176 SDL_Surface **dst_surface = &dst_bitmap->surface;
2178 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2179 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2181 dst_bitmap->width = dst_width;
2182 dst_bitmap->height = dst_height;
2184 /* create zoomed temporary surface from source surface */
2185 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2187 /* create native format destination surface from zoomed temporary surface */
2188 SDLSetNativeSurface(dst_surface);
2194 /* ========================================================================= */
2195 /* load image to bitmap */
2196 /* ========================================================================= */
2198 Bitmap *SDLLoadImage(char *filename)
2200 Bitmap *new_bitmap = CreateBitmapStruct();
2201 SDL_Surface *sdl_image_tmp;
2203 print_timestamp_init("SDLLoadImage");
2205 print_timestamp_time(getBaseNamePtr(filename));
2207 /* load image to temporary surface */
2208 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2210 SetError("IMG_Load(): %s", SDL_GetError());
2215 print_timestamp_time("IMG_Load");
2217 UPDATE_BUSY_STATE();
2219 /* create native non-transparent surface for current image */
2220 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2222 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2227 print_timestamp_time("SDL_DisplayFormat (opaque)");
2229 UPDATE_BUSY_STATE();
2231 /* create native transparent surface for current image */
2232 if (sdl_image_tmp->format->Amask == 0)
2233 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2234 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2236 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2238 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2243 print_timestamp_time("SDL_DisplayFormat (masked)");
2245 UPDATE_BUSY_STATE();
2247 /* free temporary surface */
2248 SDL_FreeSurface(sdl_image_tmp);
2250 new_bitmap->width = new_bitmap->surface->w;
2251 new_bitmap->height = new_bitmap->surface->h;
2253 print_timestamp_done("SDLLoadImage");
2259 /* ------------------------------------------------------------------------- */
2260 /* custom cursor fuctions */
2261 /* ------------------------------------------------------------------------- */
2263 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2265 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2266 cursor_info->width, cursor_info->height,
2267 cursor_info->hot_x, cursor_info->hot_y);
2270 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2272 static struct MouseCursorInfo *last_cursor_info = NULL;
2273 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2274 static SDL_Cursor *cursor_default = NULL;
2275 static SDL_Cursor *cursor_current = NULL;
2277 /* if invoked for the first time, store the SDL default cursor */
2278 if (cursor_default == NULL)
2279 cursor_default = SDL_GetCursor();
2281 /* only create new cursor if cursor info (custom only) has changed */
2282 if (cursor_info != NULL && cursor_info != last_cursor_info)
2284 cursor_current = create_cursor(cursor_info);
2285 last_cursor_info = cursor_info;
2288 /* only set new cursor if cursor info (custom or NULL) has changed */
2289 if (cursor_info != last_cursor_info2)
2290 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2292 last_cursor_info2 = cursor_info;
2296 /* ========================================================================= */
2297 /* audio functions */
2298 /* ========================================================================= */
2300 void SDLOpenAudio(void)
2302 #if !defined(TARGET_SDL2)
2303 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2304 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2307 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2309 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2313 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2314 AUDIO_NUM_CHANNELS_STEREO,
2315 setup.system.audio_fragment_size) < 0)
2317 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2321 audio.sound_available = TRUE;
2322 audio.music_available = TRUE;
2323 audio.loops_available = TRUE;
2324 audio.sound_enabled = TRUE;
2326 /* set number of available mixer channels */
2327 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2328 audio.music_channel = MUSIC_CHANNEL;
2329 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2331 Mixer_InitChannels();
2334 void SDLCloseAudio(void)
2337 Mix_HaltChannel(-1);
2340 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2344 /* ========================================================================= */
2345 /* event functions */
2346 /* ========================================================================= */
2348 void SDLNextEvent(Event *event)
2350 SDL_WaitEvent(event);
2353 void SDLHandleWindowManagerEvent(Event *event)
2356 #if defined(PLATFORM_WIN32)
2357 // experimental drag and drop code
2359 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2360 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2362 #if defined(TARGET_SDL2)
2363 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2365 if (syswmmsg->msg == WM_DROPFILES)
2368 #if defined(TARGET_SDL2)
2369 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2371 HDROP hdrop = (HDROP)syswmmsg->wParam;
2375 printf("::: SDL_SYSWMEVENT:\n");
2377 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2379 for (i = 0; i < num_files; i++)
2381 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2382 char buffer[buffer_len + 1];
2384 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2386 printf("::: - '%s'\n", buffer);
2389 #if defined(TARGET_SDL2)
2390 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2392 DragFinish((HDROP)syswmmsg->wParam);
2400 /* ========================================================================= */
2401 /* joystick functions */
2402 /* ========================================================================= */
2404 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2405 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2406 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2408 static boolean SDLOpenJoystick(int nr)
2410 if (nr < 0 || nr > MAX_PLAYERS)
2413 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2416 static void SDLCloseJoystick(int nr)
2418 if (nr < 0 || nr > MAX_PLAYERS)
2421 SDL_JoystickClose(sdl_joystick[nr]);
2423 sdl_joystick[nr] = NULL;
2426 static boolean SDLCheckJoystickOpened(int nr)
2428 if (nr < 0 || nr > MAX_PLAYERS)
2431 #if defined(TARGET_SDL2)
2432 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2434 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2438 void HandleJoystickEvent(Event *event)
2442 case SDL_JOYAXISMOTION:
2443 if (event->jaxis.axis < 2)
2444 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2447 case SDL_JOYBUTTONDOWN:
2448 if (event->jbutton.button < 2)
2449 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2452 case SDL_JOYBUTTONUP:
2453 if (event->jbutton.button < 2)
2454 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2462 void SDLInitJoysticks()
2464 static boolean sdl_joystick_subsystem_initialized = FALSE;
2465 boolean print_warning = !sdl_joystick_subsystem_initialized;
2468 if (!sdl_joystick_subsystem_initialized)
2470 sdl_joystick_subsystem_initialized = TRUE;
2472 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2474 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2479 for (i = 0; i < MAX_PLAYERS; i++)
2481 /* get configured joystick for this player */
2482 char *device_name = setup.input[i].joy.device_name;
2483 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2485 if (joystick_nr >= SDL_NumJoysticks())
2487 if (setup.input[i].use_joystick && print_warning)
2488 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2493 /* misuse joystick file descriptor variable to store joystick number */
2494 joystick.fd[i] = joystick_nr;
2496 if (joystick_nr == -1)
2499 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2500 if (SDLCheckJoystickOpened(joystick_nr))
2501 SDLCloseJoystick(joystick_nr);
2503 if (!setup.input[i].use_joystick)
2506 if (!SDLOpenJoystick(joystick_nr))
2509 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2514 joystick.status = JOYSTICK_ACTIVATED;
2518 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2520 if (nr < 0 || nr >= MAX_PLAYERS)
2524 *x = sdl_js_axis[nr][0];
2526 *y = sdl_js_axis[nr][1];
2529 *b1 = sdl_js_button[nr][0];
2531 *b2 = sdl_js_button[nr][1];