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",
566 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
571 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
576 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
580 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
583 #if defined(TARGET_SDL2)
584 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
585 if (new_surface != NULL)
586 fullscreen_enabled = fullscreen;
592 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
594 boolean success = TRUE;
595 SDL_Surface *new_surface = NULL;
599 if (*backbuffer == NULL)
600 *backbuffer = CreateBitmapStruct();
602 /* (real bitmap might be larger in fullscreen mode with video offsets) */
603 (*backbuffer)->width = video.width;
604 (*backbuffer)->height = video.height;
606 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
608 /* switch display to fullscreen mode, if available */
609 new_surface = SDLCreateScreen(backbuffer, TRUE);
611 if (new_surface == NULL)
613 /* switching display to fullscreen mode failed */
614 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
616 /* do not try it again */
617 video.fullscreen_available = FALSE;
623 (*backbuffer)->surface = new_surface;
625 video.fullscreen_enabled = TRUE;
631 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
633 /* switch display to window mode */
634 new_surface = SDLCreateScreen(backbuffer, FALSE);
636 if (new_surface == NULL)
638 /* switching display to window mode failed -- should not happen */
639 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
645 (*backbuffer)->surface = new_surface;
647 video.fullscreen_enabled = FALSE;
648 video.window_scaling_percent = setup.window_scaling_percent;
649 video.window_scaling_quality = setup.window_scaling_quality;
655 #if defined(TARGET_SDL2)
656 SDLRedrawWindow(); // map window
660 #if defined(PLATFORM_WIN32)
661 // experimental drag and drop code
663 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
666 SDL_SysWMinfo wminfo;
668 boolean wminfo_success = FALSE;
670 SDL_VERSION(&wminfo.version);
671 #if defined(TARGET_SDL2)
673 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
675 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
680 #if defined(TARGET_SDL2)
681 hwnd = wminfo.info.win.window;
683 hwnd = wminfo.window;
686 DragAcceptFiles(hwnd, TRUE);
695 void SDLSetWindowTitle()
697 #if defined(TARGET_SDL2)
698 SDL_SetWindowTitle(sdl_window, program.window_title);
700 SDL_WM_SetCaption(program.window_title, program.window_title);
704 #if defined(TARGET_SDL2)
705 void SDLSetWindowScaling(int window_scaling_percent)
707 if (sdl_window == NULL)
710 float window_scaling_factor = (float)window_scaling_percent / 100;
711 int new_window_width = (int)(window_scaling_factor * video.width);
712 int new_window_height = (int)(window_scaling_factor * video.height);
714 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
716 video.window_scaling_percent = window_scaling_percent;
717 video.window_width = new_window_width;
718 video.window_height = new_window_height;
723 void SDLSetWindowScalingQuality(char *window_scaling_quality)
725 #if USE_TARGET_TEXTURE
726 SDL_Texture *new_texture;
728 if (sdl_texture_stream == NULL ||
729 sdl_texture_target == NULL)
732 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
734 new_texture = SDL_CreateTexture(sdl_renderer,
735 SDL_PIXELFORMAT_ARGB8888,
736 SDL_TEXTUREACCESS_STREAMING,
737 video.width, video.height);
739 if (new_texture != NULL)
741 SDL_DestroyTexture(sdl_texture_stream);
743 sdl_texture_stream = new_texture;
746 new_texture = SDL_CreateTexture(sdl_renderer,
747 SDL_PIXELFORMAT_ARGB8888,
748 SDL_TEXTUREACCESS_TARGET,
749 video.width, video.height);
751 if (new_texture != NULL)
753 SDL_DestroyTexture(sdl_texture_target);
755 sdl_texture_target = new_texture;
761 if (sdl_texture == NULL)
764 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
766 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
767 SDL_PIXELFORMAT_ARGB8888,
768 SDL_TEXTUREACCESS_STREAMING,
769 video.width, video.height);
771 if (new_texture != NULL)
773 SDL_DestroyTexture(sdl_texture);
775 sdl_texture = new_texture;
781 video.window_scaling_quality = window_scaling_quality;
784 void SDLSetWindowFullscreen(boolean fullscreen)
786 if (sdl_window == NULL)
789 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
791 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
792 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
794 // if screen size was changed in fullscreen mode, correct desktop window size
795 if (!fullscreen && video.fullscreen_initial)
797 SDLSetWindowScaling(setup.window_scaling_percent);
798 SDL_SetWindowPosition(sdl_window,
799 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
801 video.fullscreen_initial = FALSE;
805 void SDLRedrawWindow()
811 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
814 SDL_Surface *surface =
815 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
818 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
820 SDLSetNativeSurface(&surface);
822 bitmap->surface = surface;
825 void SDLFreeBitmapPointers(Bitmap *bitmap)
828 SDL_FreeSurface(bitmap->surface);
829 if (bitmap->surface_masked)
830 SDL_FreeSurface(bitmap->surface_masked);
832 bitmap->surface = NULL;
833 bitmap->surface_masked = NULL;
835 #if defined(TARGET_SDL2)
837 SDL_DestroyTexture(bitmap->texture);
838 if (bitmap->texture_masked)
839 SDL_DestroyTexture(bitmap->texture_masked);
841 bitmap->texture = NULL;
842 bitmap->texture_masked = NULL;
846 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
847 int src_x, int src_y, int width, int height,
848 int dst_x, int dst_y, int mask_mode)
850 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
851 SDL_Rect src_rect, dst_rect;
863 // if (src_bitmap != backbuffer || dst_bitmap != window)
864 if (!(src_bitmap == backbuffer && dst_bitmap == window))
865 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
866 src_bitmap->surface_masked : src_bitmap->surface),
867 &src_rect, real_dst_bitmap->surface, &dst_rect);
869 #if defined(TARGET_SDL2)
870 if (dst_bitmap == window)
872 // SDL_UpdateWindowSurface(sdl_window);
873 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
874 UpdateScreen(&dst_rect);
877 if (dst_bitmap == window)
879 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
880 UpdateScreen(&dst_rect);
885 void SDLBlitTexture(Bitmap *bitmap,
886 int src_x, int src_y, int width, int height,
887 int dst_x, int dst_y, int mask_mode)
889 #if defined(TARGET_SDL2)
890 SDL_Texture *texture;
895 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
910 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
914 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
917 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
925 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
927 #if defined(TARGET_SDL2)
928 if (dst_bitmap == window)
930 // SDL_UpdateWindowSurface(sdl_window);
931 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
935 if (dst_bitmap == window)
937 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
943 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
944 int fade_mode, int fade_delay, int post_delay,
945 void (*draw_border_function)(void))
947 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
948 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
949 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
950 SDL_Surface *surface_screen = backbuffer->surface;
951 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
952 SDL_Rect src_rect, dst_rect;
954 int src_x = x, src_y = y;
955 int dst_x = x, dst_y = y;
956 unsigned int time_last, time_current;
958 // store function for drawing global masked border
959 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
961 // deactivate drawing of global border while fading, if needed
962 if (draw_border_function == NULL)
963 gfx.draw_global_border_function = NULL;
972 dst_rect.w = width; /* (ignored) */
973 dst_rect.h = height; /* (ignored) */
975 dst_rect2 = dst_rect;
977 /* copy source and target surfaces to temporary surfaces for fading */
978 if (fade_mode & FADE_TYPE_TRANSFORM)
980 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
981 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
983 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
984 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
986 else if (fade_mode & FADE_TYPE_FADE_IN)
988 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
989 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
991 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
993 else /* FADE_TYPE_FADE_OUT */
995 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
996 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
998 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
1001 time_current = SDL_GetTicks();
1003 if (fade_mode == FADE_MODE_MELT)
1005 boolean done = FALSE;
1006 int melt_pixels = 2;
1007 int melt_columns = width / melt_pixels;
1008 int ypos[melt_columns];
1009 int max_steps = height / 8 + 32;
1014 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1015 #if defined(TARGET_SDL2)
1016 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1018 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1021 ypos[0] = -GetSimpleRandom(16);
1023 for (i = 1 ; i < melt_columns; i++)
1025 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1027 ypos[i] = ypos[i - 1] + r;
1040 time_last = time_current;
1041 time_current = SDL_GetTicks();
1042 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1043 steps_final = MIN(MAX(0, steps), max_steps);
1047 done = (steps_done >= steps_final);
1049 for (i = 0 ; i < melt_columns; i++)
1057 else if (ypos[i] < height)
1062 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1064 if (ypos[i] + dy >= height)
1065 dy = height - ypos[i];
1067 /* copy part of (appearing) target surface to upper area */
1068 src_rect.x = src_x + i * melt_pixels;
1069 // src_rect.y = src_y + ypos[i];
1071 src_rect.w = melt_pixels;
1073 src_rect.h = ypos[i] + dy;
1075 dst_rect.x = dst_x + i * melt_pixels;
1076 // dst_rect.y = dst_y + ypos[i];
1079 if (steps_done >= steps_final)
1080 SDL_BlitSurface(surface_target, &src_rect,
1081 surface_screen, &dst_rect);
1085 /* copy part of (disappearing) source surface to lower area */
1086 src_rect.x = src_x + i * melt_pixels;
1088 src_rect.w = melt_pixels;
1089 src_rect.h = height - ypos[i];
1091 dst_rect.x = dst_x + i * melt_pixels;
1092 dst_rect.y = dst_y + ypos[i];
1094 if (steps_done >= steps_final)
1095 SDL_BlitSurface(surface_source, &src_rect,
1096 surface_screen, &dst_rect);
1102 src_rect.x = src_x + i * melt_pixels;
1104 src_rect.w = melt_pixels;
1105 src_rect.h = height;
1107 dst_rect.x = dst_x + i * melt_pixels;
1110 if (steps_done >= steps_final)
1111 SDL_BlitSurface(surface_target, &src_rect,
1112 surface_screen, &dst_rect);
1116 if (steps_done >= steps_final)
1118 if (draw_border_function != NULL)
1119 draw_border_function();
1121 UpdateScreen(&dst_rect2);
1125 else if (fade_mode == FADE_MODE_CURTAIN)
1129 int xx_size = width / 2;
1131 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1132 #if defined(TARGET_SDL2)
1133 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1135 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1138 for (xx = 0; xx < xx_size;)
1140 time_last = time_current;
1141 time_current = SDL_GetTicks();
1142 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1143 xx_final = MIN(MAX(0, xx), xx_size);
1148 src_rect.h = height;
1153 /* draw new (target) image to screen buffer */
1154 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1156 if (xx_final < xx_size)
1158 src_rect.w = xx_size - xx_final;
1159 src_rect.h = height;
1161 /* draw old (source) image to screen buffer (left side) */
1163 src_rect.x = src_x + xx_final;
1166 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1168 /* draw old (source) image to screen buffer (right side) */
1170 src_rect.x = src_x + xx_size;
1171 dst_rect.x = dst_x + xx_size + xx_final;
1173 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1176 if (draw_border_function != NULL)
1177 draw_border_function();
1179 /* only update the region of the screen that is affected from fading */
1180 UpdateScreen(&dst_rect2);
1183 else /* fading in, fading out or cross-fading */
1188 for (alpha = 0.0; alpha < 255.0;)
1190 time_last = time_current;
1191 time_current = SDL_GetTicks();
1192 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1193 alpha_final = MIN(MAX(0, alpha), 255);
1195 /* draw existing (source) image to screen buffer */
1196 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1198 /* draw new (target) image to screen buffer using alpha blending */
1199 #if defined(TARGET_SDL2)
1200 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1201 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1203 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1205 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1207 if (draw_border_function != NULL)
1208 draw_border_function();
1210 /* only update the region of the screen that is affected from fading */
1211 UpdateScreen(&dst_rect);
1217 unsigned int time_post_delay;
1219 time_current = SDL_GetTicks();
1220 time_post_delay = time_current + post_delay;
1222 while (time_current < time_post_delay)
1224 // do not wait longer than 10 ms at a time to be able to ...
1225 Delay(MIN(10, time_post_delay - time_current));
1227 // ... continue drawing global animations during post delay
1230 time_current = SDL_GetTicks();
1234 // restore function for drawing global masked border
1235 gfx.draw_global_border_function = draw_global_border_function;
1238 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1239 int to_x, int to_y, Uint32 color)
1241 SDL_Surface *surface = dst_bitmap->surface;
1245 swap_numbers(&from_x, &to_x);
1248 swap_numbers(&from_y, &to_y);
1252 rect.w = (to_x - from_x + 1);
1253 rect.h = (to_y - from_y + 1);
1255 SDL_FillRect(surface, &rect, color);
1258 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1259 int to_x, int to_y, Uint32 color)
1261 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1264 #if ENABLE_UNUSED_CODE
1265 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1266 int num_points, Uint32 color)
1271 for (i = 0; i < num_points - 1; i++)
1273 for (x = 0; x < line_width; x++)
1275 for (y = 0; y < line_width; y++)
1277 int dx = x - line_width / 2;
1278 int dy = y - line_width / 2;
1280 if ((x == 0 && y == 0) ||
1281 (x == 0 && y == line_width - 1) ||
1282 (x == line_width - 1 && y == 0) ||
1283 (x == line_width - 1 && y == line_width - 1))
1286 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1287 points[i+1].x + dx, points[i+1].y + dy, color);
1294 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1296 SDL_Surface *surface = src_bitmap->surface;
1298 switch (surface->format->BytesPerPixel)
1300 case 1: /* assuming 8-bpp */
1302 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1306 case 2: /* probably 15-bpp or 16-bpp */
1308 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1312 case 3: /* slow 24-bpp mode; usually not used */
1314 /* does this work? */
1315 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1319 shift = surface->format->Rshift;
1320 color |= *(pix + shift / 8) >> shift;
1321 shift = surface->format->Gshift;
1322 color |= *(pix + shift / 8) >> shift;
1323 shift = surface->format->Bshift;
1324 color |= *(pix + shift / 8) >> shift;
1330 case 4: /* probably 32-bpp */
1332 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1341 /* ========================================================================= */
1342 /* The following functions were taken from the SGE library */
1343 /* (SDL Graphics Extension Library) by Anders Lindström */
1344 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1345 /* ========================================================================= */
1347 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1349 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1351 switch (surface->format->BytesPerPixel)
1355 /* Assuming 8-bpp */
1356 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1362 /* Probably 15-bpp or 16-bpp */
1363 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1369 /* Slow 24-bpp mode, usually not used */
1373 /* Gack - slow, but endian correct */
1374 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1375 shift = surface->format->Rshift;
1376 *(pix+shift/8) = color>>shift;
1377 shift = surface->format->Gshift;
1378 *(pix+shift/8) = color>>shift;
1379 shift = surface->format->Bshift;
1380 *(pix+shift/8) = color>>shift;
1386 /* Probably 32-bpp */
1387 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1394 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1395 Uint8 R, Uint8 G, Uint8 B)
1397 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1400 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1402 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1405 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1407 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1410 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1415 /* Gack - slow, but endian correct */
1416 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1417 shift = surface->format->Rshift;
1418 *(pix+shift/8) = color>>shift;
1419 shift = surface->format->Gshift;
1420 *(pix+shift/8) = color>>shift;
1421 shift = surface->format->Bshift;
1422 *(pix+shift/8) = color>>shift;
1425 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1427 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1430 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1432 switch (dest->format->BytesPerPixel)
1435 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1439 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1443 _PutPixel24(dest,x,y,color);
1447 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1452 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1454 if (SDL_MUSTLOCK(surface))
1456 if (SDL_LockSurface(surface) < 0)
1462 _PutPixel(surface, x, y, color);
1464 if (SDL_MUSTLOCK(surface))
1466 SDL_UnlockSurface(surface);
1470 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1471 Uint8 r, Uint8 g, Uint8 b)
1473 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1476 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1478 if (y >= 0 && y <= dest->h - 1)
1480 switch (dest->format->BytesPerPixel)
1483 return y*dest->pitch;
1487 return y*dest->pitch/2;
1491 return y*dest->pitch;
1495 return y*dest->pitch/4;
1503 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1505 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1507 switch (surface->format->BytesPerPixel)
1511 /* Assuming 8-bpp */
1512 *((Uint8 *)surface->pixels + ypitch + x) = color;
1518 /* Probably 15-bpp or 16-bpp */
1519 *((Uint16 *)surface->pixels + ypitch + x) = color;
1525 /* Slow 24-bpp mode, usually not used */
1529 /* Gack - slow, but endian correct */
1530 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1531 shift = surface->format->Rshift;
1532 *(pix+shift/8) = color>>shift;
1533 shift = surface->format->Gshift;
1534 *(pix+shift/8) = color>>shift;
1535 shift = surface->format->Bshift;
1536 *(pix+shift/8) = color>>shift;
1542 /* Probably 32-bpp */
1543 *((Uint32 *)surface->pixels + ypitch + x) = color;
1550 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1555 if (SDL_MUSTLOCK(Surface))
1557 if (SDL_LockSurface(Surface) < 0)
1570 /* Do the clipping */
1571 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1575 if (x2 > Surface->w - 1)
1576 x2 = Surface->w - 1;
1583 SDL_FillRect(Surface, &l, Color);
1585 if (SDL_MUSTLOCK(Surface))
1587 SDL_UnlockSurface(Surface);
1591 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1592 Uint8 R, Uint8 G, Uint8 B)
1594 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1597 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1608 /* Do the clipping */
1609 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1613 if (x2 > Surface->w - 1)
1614 x2 = Surface->w - 1;
1621 SDL_FillRect(Surface, &l, Color);
1624 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1629 if (SDL_MUSTLOCK(Surface))
1631 if (SDL_LockSurface(Surface) < 0)
1644 /* Do the clipping */
1645 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1649 if (y2 > Surface->h - 1)
1650 y2 = Surface->h - 1;
1657 SDL_FillRect(Surface, &l, Color);
1659 if (SDL_MUSTLOCK(Surface))
1661 SDL_UnlockSurface(Surface);
1665 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1666 Uint8 R, Uint8 G, Uint8 B)
1668 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1671 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1682 /* Do the clipping */
1683 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1687 if (y2 > Surface->h - 1)
1688 y2 = Surface->h - 1;
1695 SDL_FillRect(Surface, &l, Color);
1698 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1699 Sint16 x2, Sint16 y2, Uint32 Color,
1700 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1703 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1708 sdx = (dx < 0) ? -1 : 1;
1709 sdy = (dy < 0) ? -1 : 1;
1721 for (x = 0; x < dx; x++)
1723 Callback(Surface, px, py, Color);
1737 for (y = 0; y < dy; y++)
1739 Callback(Surface, px, py, Color);
1753 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1754 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1755 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1758 sge_DoLine(Surface, X1, Y1, X2, Y2,
1759 SDL_MapRGB(Surface->format, R, G, B), Callback);
1762 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1765 if (SDL_MUSTLOCK(Surface))
1767 if (SDL_LockSurface(Surface) < 0)
1772 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1774 /* unlock the display */
1775 if (SDL_MUSTLOCK(Surface))
1777 SDL_UnlockSurface(Surface);
1781 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1782 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1784 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1787 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1789 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1794 -----------------------------------------------------------------------------
1795 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1796 -----------------------------------------------------------------------------
1799 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1800 int width, int height, Uint32 color)
1804 for (y = src_y; y < src_y + height; y++)
1806 for (x = src_x; x < src_x + width; x++)
1808 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1810 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1815 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1816 int src_x, int src_y, int width, int height,
1817 int dst_x, int dst_y)
1821 for (y = 0; y < height; y++)
1823 for (x = 0; x < width; x++)
1825 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1827 if (pixel != BLACK_PIXEL)
1828 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1834 /* ========================================================================= */
1835 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1836 /* (Rotozoomer) by Andreas Schiffler */
1837 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1838 /* ========================================================================= */
1841 -----------------------------------------------------------------------------
1844 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1845 -----------------------------------------------------------------------------
1856 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1859 tColorRGBA *sp, *csp, *dp;
1863 sp = csp = (tColorRGBA *) src->pixels;
1864 dp = (tColorRGBA *) dst->pixels;
1865 dgap = dst->pitch - dst->w * 4;
1867 for (y = 0; y < dst->h; y++)
1871 for (x = 0; x < dst->w; x++)
1873 tColorRGBA *sp0 = sp;
1874 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1875 tColorRGBA *sp00 = &sp0[0];
1876 tColorRGBA *sp01 = &sp0[1];
1877 tColorRGBA *sp10 = &sp1[0];
1878 tColorRGBA *sp11 = &sp1[1];
1881 /* create new color pixel from all four source color pixels */
1882 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1883 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1884 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1885 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1890 /* advance source pointers */
1893 /* advance destination pointer */
1897 /* advance source pointer */
1898 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1900 /* advance destination pointers */
1901 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1907 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1909 int x, y, *sax, *say, *csax, *csay;
1911 tColorRGBA *sp, *csp, *csp0, *dp;
1914 /* use specialized zoom function when scaling down to exactly half size */
1915 if (src->w == 2 * dst->w &&
1916 src->h == 2 * dst->h)
1917 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1919 /* variable setup */
1920 sx = (float) src->w / (float) dst->w;
1921 sy = (float) src->h / (float) dst->h;
1923 /* allocate memory for row increments */
1924 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1925 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1927 /* precalculate row increments */
1928 for (x = 0; x <= dst->w; x++)
1929 *csax++ = (int)(sx * x);
1931 for (y = 0; y <= dst->h; y++)
1932 *csay++ = (int)(sy * y);
1935 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1936 dp = (tColorRGBA *) dst->pixels;
1937 dgap = dst->pitch - dst->w * 4;
1940 for (y = 0; y < dst->h; y++)
1945 for (x = 0; x < dst->w; x++)
1950 /* advance source pointers */
1954 /* advance destination pointer */
1958 /* advance source pointer */
1960 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1962 /* advance destination pointers */
1963 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1973 -----------------------------------------------------------------------------
1976 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1977 -----------------------------------------------------------------------------
1980 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1982 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1983 Uint8 *sp, *dp, *csp;
1986 /* variable setup */
1987 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1988 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1990 /* allocate memory for row increments */
1991 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1992 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1994 /* precalculate row increments */
1997 for (x = 0; x < dst->w; x++)
2000 *csax = (csx >> 16);
2007 for (y = 0; y < dst->h; y++)
2010 *csay = (csy >> 16);
2017 for (x = 0; x < dst->w; x++)
2025 for (y = 0; y < dst->h; y++)
2032 sp = csp = (Uint8 *) src->pixels;
2033 dp = (Uint8 *) dst->pixels;
2034 dgap = dst->pitch - dst->w;
2038 for (y = 0; y < dst->h; y++)
2042 for (x = 0; x < dst->w; x++)
2047 /* advance source pointers */
2051 /* advance destination pointer */
2055 /* advance source pointer (for row) */
2056 csp += ((*csay) * src->pitch);
2059 /* advance destination pointers */
2070 -----------------------------------------------------------------------------
2073 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2074 'zoomx' and 'zoomy' are scaling factors for width and height.
2075 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2076 into a 32bit RGBA format on the fly.
2077 -----------------------------------------------------------------------------
2080 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2082 SDL_Surface *zoom_src = NULL;
2083 SDL_Surface *zoom_dst = NULL;
2084 boolean is_converted = FALSE;
2091 /* determine if source surface is 32 bit or 8 bit */
2092 is_32bit = (src->format->BitsPerPixel == 32);
2094 if (is_32bit || src->format->BitsPerPixel == 8)
2096 /* use source surface 'as is' */
2101 /* new source surface is 32 bit with a defined RGB ordering */
2102 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2103 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2104 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2106 is_converted = TRUE;
2109 /* allocate surface to completely contain the zoomed surface */
2112 /* target surface is 32 bit with source RGBA/ABGR ordering */
2113 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2114 zoom_src->format->Rmask,
2115 zoom_src->format->Gmask,
2116 zoom_src->format->Bmask, 0);
2120 /* target surface is 8 bit */
2121 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2125 /* lock source surface */
2126 SDL_LockSurface(zoom_src);
2128 /* check which kind of surface we have */
2131 /* call the 32 bit transformation routine to do the zooming */
2132 zoomSurfaceRGBA(zoom_src, zoom_dst);
2137 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2138 zoom_dst->format->palette->colors[i] =
2139 zoom_src->format->palette->colors[i];
2140 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2142 /* call the 8 bit transformation routine to do the zooming */
2143 zoomSurfaceY(zoom_src, zoom_dst);
2146 /* unlock source surface */
2147 SDL_UnlockSurface(zoom_src);
2149 /* free temporary surface */
2151 SDL_FreeSurface(zoom_src);
2153 /* return destination surface */
2157 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2159 Bitmap *dst_bitmap = CreateBitmapStruct();
2160 SDL_Surface **dst_surface = &dst_bitmap->surface;
2162 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2163 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2165 dst_bitmap->width = dst_width;
2166 dst_bitmap->height = dst_height;
2168 /* create zoomed temporary surface from source surface */
2169 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2171 /* create native format destination surface from zoomed temporary surface */
2172 SDLSetNativeSurface(dst_surface);
2178 /* ========================================================================= */
2179 /* load image to bitmap */
2180 /* ========================================================================= */
2182 Bitmap *SDLLoadImage(char *filename)
2184 Bitmap *new_bitmap = CreateBitmapStruct();
2185 SDL_Surface *sdl_image_tmp;
2187 print_timestamp_init("SDLLoadImage");
2189 print_timestamp_time(getBaseNamePtr(filename));
2191 /* load image to temporary surface */
2192 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2194 SetError("IMG_Load(): %s", SDL_GetError());
2199 print_timestamp_time("IMG_Load");
2201 UPDATE_BUSY_STATE();
2203 /* create native non-transparent surface for current image */
2204 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2206 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2211 print_timestamp_time("SDL_DisplayFormat (opaque)");
2213 UPDATE_BUSY_STATE();
2215 /* create native transparent surface for current image */
2216 if (sdl_image_tmp->format->Amask == 0)
2217 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2218 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2220 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2222 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2227 print_timestamp_time("SDL_DisplayFormat (masked)");
2229 UPDATE_BUSY_STATE();
2231 /* free temporary surface */
2232 SDL_FreeSurface(sdl_image_tmp);
2234 new_bitmap->width = new_bitmap->surface->w;
2235 new_bitmap->height = new_bitmap->surface->h;
2237 print_timestamp_done("SDLLoadImage");
2243 /* ------------------------------------------------------------------------- */
2244 /* custom cursor fuctions */
2245 /* ------------------------------------------------------------------------- */
2247 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2249 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2250 cursor_info->width, cursor_info->height,
2251 cursor_info->hot_x, cursor_info->hot_y);
2254 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2256 static struct MouseCursorInfo *last_cursor_info = NULL;
2257 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2258 static SDL_Cursor *cursor_default = NULL;
2259 static SDL_Cursor *cursor_current = NULL;
2261 /* if invoked for the first time, store the SDL default cursor */
2262 if (cursor_default == NULL)
2263 cursor_default = SDL_GetCursor();
2265 /* only create new cursor if cursor info (custom only) has changed */
2266 if (cursor_info != NULL && cursor_info != last_cursor_info)
2268 cursor_current = create_cursor(cursor_info);
2269 last_cursor_info = cursor_info;
2272 /* only set new cursor if cursor info (custom or NULL) has changed */
2273 if (cursor_info != last_cursor_info2)
2274 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2276 last_cursor_info2 = cursor_info;
2280 /* ========================================================================= */
2281 /* audio functions */
2282 /* ========================================================================= */
2284 void SDLOpenAudio(void)
2286 #if !defined(TARGET_SDL2)
2287 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2288 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2291 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2293 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2297 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2298 AUDIO_NUM_CHANNELS_STEREO,
2299 setup.system.audio_fragment_size) < 0)
2301 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2305 audio.sound_available = TRUE;
2306 audio.music_available = TRUE;
2307 audio.loops_available = TRUE;
2308 audio.sound_enabled = TRUE;
2310 /* set number of available mixer channels */
2311 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2312 audio.music_channel = MUSIC_CHANNEL;
2313 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2315 Mixer_InitChannels();
2318 void SDLCloseAudio(void)
2321 Mix_HaltChannel(-1);
2324 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2328 /* ========================================================================= */
2329 /* event functions */
2330 /* ========================================================================= */
2332 void SDLNextEvent(Event *event)
2334 SDL_WaitEvent(event);
2337 void SDLHandleWindowManagerEvent(Event *event)
2340 #if defined(PLATFORM_WIN32)
2341 // experimental drag and drop code
2343 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2344 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2346 #if defined(TARGET_SDL2)
2347 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2349 if (syswmmsg->msg == WM_DROPFILES)
2352 #if defined(TARGET_SDL2)
2353 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2355 HDROP hdrop = (HDROP)syswmmsg->wParam;
2359 printf("::: SDL_SYSWMEVENT:\n");
2361 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2363 for (i = 0; i < num_files; i++)
2365 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2366 char buffer[buffer_len + 1];
2368 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2370 printf("::: - '%s'\n", buffer);
2373 #if defined(TARGET_SDL2)
2374 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2376 DragFinish((HDROP)syswmmsg->wParam);
2384 /* ========================================================================= */
2385 /* joystick functions */
2386 /* ========================================================================= */
2388 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2389 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2390 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2392 static boolean SDLOpenJoystick(int nr)
2394 if (nr < 0 || nr > MAX_PLAYERS)
2397 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2400 static void SDLCloseJoystick(int nr)
2402 if (nr < 0 || nr > MAX_PLAYERS)
2405 SDL_JoystickClose(sdl_joystick[nr]);
2407 sdl_joystick[nr] = NULL;
2410 static boolean SDLCheckJoystickOpened(int nr)
2412 if (nr < 0 || nr > MAX_PLAYERS)
2415 #if defined(TARGET_SDL2)
2416 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2418 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2422 void HandleJoystickEvent(Event *event)
2426 case SDL_JOYAXISMOTION:
2427 if (event->jaxis.axis < 2)
2428 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2431 case SDL_JOYBUTTONDOWN:
2432 if (event->jbutton.button < 2)
2433 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2436 case SDL_JOYBUTTONUP:
2437 if (event->jbutton.button < 2)
2438 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2446 void SDLInitJoysticks()
2448 static boolean sdl_joystick_subsystem_initialized = FALSE;
2449 boolean print_warning = !sdl_joystick_subsystem_initialized;
2452 if (!sdl_joystick_subsystem_initialized)
2454 sdl_joystick_subsystem_initialized = TRUE;
2456 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2458 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2463 for (i = 0; i < MAX_PLAYERS; i++)
2465 /* get configured joystick for this player */
2466 char *device_name = setup.input[i].joy.device_name;
2467 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2469 if (joystick_nr >= SDL_NumJoysticks())
2471 if (setup.input[i].use_joystick && print_warning)
2472 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2477 /* misuse joystick file descriptor variable to store joystick number */
2478 joystick.fd[i] = joystick_nr;
2480 if (joystick_nr == -1)
2483 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2484 if (SDLCheckJoystickOpened(joystick_nr))
2485 SDLCloseJoystick(joystick_nr);
2487 if (!setup.input[i].use_joystick)
2490 if (!SDLOpenJoystick(joystick_nr))
2493 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2498 joystick.status = JOYSTICK_ACTIVATED;
2502 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2504 if (nr < 0 || nr >= MAX_PLAYERS)
2508 *x = sdl_js_axis[nr][0];
2510 *y = sdl_js_axis[nr][1];
2513 *b1 = sdl_js_button[nr][0];
2515 *b2 = sdl_js_button[nr][1];