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 (dst_bitmap == window)
870 UpdateScreen(&dst_rect);
873 void SDLBlitTexture(Bitmap *bitmap,
874 int src_x, int src_y, int width, int height,
875 int dst_x, int dst_y, int mask_mode)
877 #if defined(TARGET_SDL2)
878 SDL_Texture *texture;
883 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
898 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
902 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
905 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
913 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
915 #if defined(TARGET_SDL2)
916 if (dst_bitmap == window)
918 // SDL_UpdateWindowSurface(sdl_window);
919 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
923 if (dst_bitmap == window)
925 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
931 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
932 int fade_mode, int fade_delay, int post_delay,
933 void (*draw_border_function)(void))
935 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
936 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
937 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
938 SDL_Surface *surface_screen = backbuffer->surface;
939 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
940 SDL_Rect src_rect, dst_rect;
942 int src_x = x, src_y = y;
943 int dst_x = x, dst_y = y;
944 unsigned int time_last, time_current;
946 // store function for drawing global masked border
947 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
949 // deactivate drawing of global border while fading, if needed
950 if (draw_border_function == NULL)
951 gfx.draw_global_border_function = NULL;
960 dst_rect.w = width; /* (ignored) */
961 dst_rect.h = height; /* (ignored) */
963 dst_rect2 = dst_rect;
965 /* copy source and target surfaces to temporary surfaces for fading */
966 if (fade_mode & FADE_TYPE_TRANSFORM)
968 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
969 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
971 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
972 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
974 else if (fade_mode & FADE_TYPE_FADE_IN)
976 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
977 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
979 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
981 else /* FADE_TYPE_FADE_OUT */
983 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
984 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
986 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
989 time_current = SDL_GetTicks();
991 if (fade_mode == FADE_MODE_MELT)
993 boolean done = FALSE;
995 int melt_columns = width / melt_pixels;
996 int ypos[melt_columns];
997 int max_steps = height / 8 + 32;
1002 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1003 #if defined(TARGET_SDL2)
1004 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1006 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1009 ypos[0] = -GetSimpleRandom(16);
1011 for (i = 1 ; i < melt_columns; i++)
1013 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1015 ypos[i] = ypos[i - 1] + r;
1028 time_last = time_current;
1029 time_current = SDL_GetTicks();
1030 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1031 steps_final = MIN(MAX(0, steps), max_steps);
1035 done = (steps_done >= steps_final);
1037 for (i = 0 ; i < melt_columns; i++)
1045 else if (ypos[i] < height)
1050 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1052 if (ypos[i] + dy >= height)
1053 dy = height - ypos[i];
1055 /* copy part of (appearing) target surface to upper area */
1056 src_rect.x = src_x + i * melt_pixels;
1057 // src_rect.y = src_y + ypos[i];
1059 src_rect.w = melt_pixels;
1061 src_rect.h = ypos[i] + dy;
1063 dst_rect.x = dst_x + i * melt_pixels;
1064 // dst_rect.y = dst_y + ypos[i];
1067 if (steps_done >= steps_final)
1068 SDL_BlitSurface(surface_target, &src_rect,
1069 surface_screen, &dst_rect);
1073 /* copy part of (disappearing) source surface to lower area */
1074 src_rect.x = src_x + i * melt_pixels;
1076 src_rect.w = melt_pixels;
1077 src_rect.h = height - ypos[i];
1079 dst_rect.x = dst_x + i * melt_pixels;
1080 dst_rect.y = dst_y + ypos[i];
1082 if (steps_done >= steps_final)
1083 SDL_BlitSurface(surface_source, &src_rect,
1084 surface_screen, &dst_rect);
1090 src_rect.x = src_x + i * melt_pixels;
1092 src_rect.w = melt_pixels;
1093 src_rect.h = height;
1095 dst_rect.x = dst_x + i * melt_pixels;
1098 if (steps_done >= steps_final)
1099 SDL_BlitSurface(surface_target, &src_rect,
1100 surface_screen, &dst_rect);
1104 if (steps_done >= steps_final)
1106 if (draw_border_function != NULL)
1107 draw_border_function();
1109 UpdateScreen(&dst_rect2);
1113 else if (fade_mode == FADE_MODE_CURTAIN)
1117 int xx_size = width / 2;
1119 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1120 #if defined(TARGET_SDL2)
1121 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1123 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1126 for (xx = 0; xx < xx_size;)
1128 time_last = time_current;
1129 time_current = SDL_GetTicks();
1130 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1131 xx_final = MIN(MAX(0, xx), xx_size);
1136 src_rect.h = height;
1141 /* draw new (target) image to screen buffer */
1142 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1144 if (xx_final < xx_size)
1146 src_rect.w = xx_size - xx_final;
1147 src_rect.h = height;
1149 /* draw old (source) image to screen buffer (left side) */
1151 src_rect.x = src_x + xx_final;
1154 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1156 /* draw old (source) image to screen buffer (right side) */
1158 src_rect.x = src_x + xx_size;
1159 dst_rect.x = dst_x + xx_size + xx_final;
1161 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1164 if (draw_border_function != NULL)
1165 draw_border_function();
1167 /* only update the region of the screen that is affected from fading */
1168 UpdateScreen(&dst_rect2);
1171 else /* fading in, fading out or cross-fading */
1176 for (alpha = 0.0; alpha < 255.0;)
1178 time_last = time_current;
1179 time_current = SDL_GetTicks();
1180 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1181 alpha_final = MIN(MAX(0, alpha), 255);
1183 /* draw existing (source) image to screen buffer */
1184 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1186 /* draw new (target) image to screen buffer using alpha blending */
1187 #if defined(TARGET_SDL2)
1188 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1189 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1191 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1193 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1195 if (draw_border_function != NULL)
1196 draw_border_function();
1198 /* only update the region of the screen that is affected from fading */
1199 UpdateScreen(&dst_rect);
1205 unsigned int time_post_delay;
1207 time_current = SDL_GetTicks();
1208 time_post_delay = time_current + post_delay;
1210 while (time_current < time_post_delay)
1212 // do not wait longer than 10 ms at a time to be able to ...
1213 Delay(MIN(10, time_post_delay - time_current));
1215 // ... continue drawing global animations during post delay
1218 time_current = SDL_GetTicks();
1222 // restore function for drawing global masked border
1223 gfx.draw_global_border_function = draw_global_border_function;
1226 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1227 int to_x, int to_y, Uint32 color)
1229 SDL_Surface *surface = dst_bitmap->surface;
1233 swap_numbers(&from_x, &to_x);
1236 swap_numbers(&from_y, &to_y);
1240 rect.w = (to_x - from_x + 1);
1241 rect.h = (to_y - from_y + 1);
1243 SDL_FillRect(surface, &rect, color);
1246 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1247 int to_x, int to_y, Uint32 color)
1249 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1252 #if ENABLE_UNUSED_CODE
1253 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1254 int num_points, Uint32 color)
1259 for (i = 0; i < num_points - 1; i++)
1261 for (x = 0; x < line_width; x++)
1263 for (y = 0; y < line_width; y++)
1265 int dx = x - line_width / 2;
1266 int dy = y - line_width / 2;
1268 if ((x == 0 && y == 0) ||
1269 (x == 0 && y == line_width - 1) ||
1270 (x == line_width - 1 && y == 0) ||
1271 (x == line_width - 1 && y == line_width - 1))
1274 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1275 points[i+1].x + dx, points[i+1].y + dy, color);
1282 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1284 SDL_Surface *surface = src_bitmap->surface;
1286 switch (surface->format->BytesPerPixel)
1288 case 1: /* assuming 8-bpp */
1290 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1294 case 2: /* probably 15-bpp or 16-bpp */
1296 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1300 case 3: /* slow 24-bpp mode; usually not used */
1302 /* does this work? */
1303 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1307 shift = surface->format->Rshift;
1308 color |= *(pix + shift / 8) >> shift;
1309 shift = surface->format->Gshift;
1310 color |= *(pix + shift / 8) >> shift;
1311 shift = surface->format->Bshift;
1312 color |= *(pix + shift / 8) >> shift;
1318 case 4: /* probably 32-bpp */
1320 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1329 /* ========================================================================= */
1330 /* The following functions were taken from the SGE library */
1331 /* (SDL Graphics Extension Library) by Anders Lindström */
1332 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1333 /* ========================================================================= */
1335 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1337 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1339 switch (surface->format->BytesPerPixel)
1343 /* Assuming 8-bpp */
1344 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1350 /* Probably 15-bpp or 16-bpp */
1351 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1357 /* Slow 24-bpp mode, usually not used */
1361 /* Gack - slow, but endian correct */
1362 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1363 shift = surface->format->Rshift;
1364 *(pix+shift/8) = color>>shift;
1365 shift = surface->format->Gshift;
1366 *(pix+shift/8) = color>>shift;
1367 shift = surface->format->Bshift;
1368 *(pix+shift/8) = color>>shift;
1374 /* Probably 32-bpp */
1375 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1382 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1383 Uint8 R, Uint8 G, Uint8 B)
1385 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1388 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1390 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1393 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1395 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1398 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1403 /* Gack - slow, but endian correct */
1404 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1405 shift = surface->format->Rshift;
1406 *(pix+shift/8) = color>>shift;
1407 shift = surface->format->Gshift;
1408 *(pix+shift/8) = color>>shift;
1409 shift = surface->format->Bshift;
1410 *(pix+shift/8) = color>>shift;
1413 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1415 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1418 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1420 switch (dest->format->BytesPerPixel)
1423 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1427 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1431 _PutPixel24(dest,x,y,color);
1435 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1440 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1442 if (SDL_MUSTLOCK(surface))
1444 if (SDL_LockSurface(surface) < 0)
1450 _PutPixel(surface, x, y, color);
1452 if (SDL_MUSTLOCK(surface))
1454 SDL_UnlockSurface(surface);
1458 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1459 Uint8 r, Uint8 g, Uint8 b)
1461 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1464 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1466 if (y >= 0 && y <= dest->h - 1)
1468 switch (dest->format->BytesPerPixel)
1471 return y*dest->pitch;
1475 return y*dest->pitch/2;
1479 return y*dest->pitch;
1483 return y*dest->pitch/4;
1491 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1493 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1495 switch (surface->format->BytesPerPixel)
1499 /* Assuming 8-bpp */
1500 *((Uint8 *)surface->pixels + ypitch + x) = color;
1506 /* Probably 15-bpp or 16-bpp */
1507 *((Uint16 *)surface->pixels + ypitch + x) = color;
1513 /* Slow 24-bpp mode, usually not used */
1517 /* Gack - slow, but endian correct */
1518 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1519 shift = surface->format->Rshift;
1520 *(pix+shift/8) = color>>shift;
1521 shift = surface->format->Gshift;
1522 *(pix+shift/8) = color>>shift;
1523 shift = surface->format->Bshift;
1524 *(pix+shift/8) = color>>shift;
1530 /* Probably 32-bpp */
1531 *((Uint32 *)surface->pixels + ypitch + x) = color;
1538 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1543 if (SDL_MUSTLOCK(Surface))
1545 if (SDL_LockSurface(Surface) < 0)
1558 /* Do the clipping */
1559 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1563 if (x2 > Surface->w - 1)
1564 x2 = Surface->w - 1;
1571 SDL_FillRect(Surface, &l, Color);
1573 if (SDL_MUSTLOCK(Surface))
1575 SDL_UnlockSurface(Surface);
1579 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1580 Uint8 R, Uint8 G, Uint8 B)
1582 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1585 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1596 /* Do the clipping */
1597 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1601 if (x2 > Surface->w - 1)
1602 x2 = Surface->w - 1;
1609 SDL_FillRect(Surface, &l, Color);
1612 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1617 if (SDL_MUSTLOCK(Surface))
1619 if (SDL_LockSurface(Surface) < 0)
1632 /* Do the clipping */
1633 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1637 if (y2 > Surface->h - 1)
1638 y2 = Surface->h - 1;
1645 SDL_FillRect(Surface, &l, Color);
1647 if (SDL_MUSTLOCK(Surface))
1649 SDL_UnlockSurface(Surface);
1653 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1654 Uint8 R, Uint8 G, Uint8 B)
1656 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1659 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1670 /* Do the clipping */
1671 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1675 if (y2 > Surface->h - 1)
1676 y2 = Surface->h - 1;
1683 SDL_FillRect(Surface, &l, Color);
1686 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1687 Sint16 x2, Sint16 y2, Uint32 Color,
1688 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1691 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1696 sdx = (dx < 0) ? -1 : 1;
1697 sdy = (dy < 0) ? -1 : 1;
1709 for (x = 0; x < dx; x++)
1711 Callback(Surface, px, py, Color);
1725 for (y = 0; y < dy; y++)
1727 Callback(Surface, px, py, Color);
1741 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1742 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1743 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1746 sge_DoLine(Surface, X1, Y1, X2, Y2,
1747 SDL_MapRGB(Surface->format, R, G, B), Callback);
1750 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1753 if (SDL_MUSTLOCK(Surface))
1755 if (SDL_LockSurface(Surface) < 0)
1760 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1762 /* unlock the display */
1763 if (SDL_MUSTLOCK(Surface))
1765 SDL_UnlockSurface(Surface);
1769 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1770 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1772 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1775 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1777 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1782 -----------------------------------------------------------------------------
1783 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1784 -----------------------------------------------------------------------------
1787 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1788 int width, int height, Uint32 color)
1792 for (y = src_y; y < src_y + height; y++)
1794 for (x = src_x; x < src_x + width; x++)
1796 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1798 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1803 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1804 int src_x, int src_y, int width, int height,
1805 int dst_x, int dst_y)
1809 for (y = 0; y < height; y++)
1811 for (x = 0; x < width; x++)
1813 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1815 if (pixel != BLACK_PIXEL)
1816 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1822 /* ========================================================================= */
1823 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1824 /* (Rotozoomer) by Andreas Schiffler */
1825 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1826 /* ========================================================================= */
1829 -----------------------------------------------------------------------------
1832 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1833 -----------------------------------------------------------------------------
1844 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1847 tColorRGBA *sp, *csp, *dp;
1851 sp = csp = (tColorRGBA *) src->pixels;
1852 dp = (tColorRGBA *) dst->pixels;
1853 dgap = dst->pitch - dst->w * 4;
1855 for (y = 0; y < dst->h; y++)
1859 for (x = 0; x < dst->w; x++)
1861 tColorRGBA *sp0 = sp;
1862 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1863 tColorRGBA *sp00 = &sp0[0];
1864 tColorRGBA *sp01 = &sp0[1];
1865 tColorRGBA *sp10 = &sp1[0];
1866 tColorRGBA *sp11 = &sp1[1];
1869 /* create new color pixel from all four source color pixels */
1870 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1871 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1872 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1873 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1878 /* advance source pointers */
1881 /* advance destination pointer */
1885 /* advance source pointer */
1886 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1888 /* advance destination pointers */
1889 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1895 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1897 int x, y, *sax, *say, *csax, *csay;
1899 tColorRGBA *sp, *csp, *csp0, *dp;
1902 /* use specialized zoom function when scaling down to exactly half size */
1903 if (src->w == 2 * dst->w &&
1904 src->h == 2 * dst->h)
1905 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1907 /* variable setup */
1908 sx = (float) src->w / (float) dst->w;
1909 sy = (float) src->h / (float) dst->h;
1911 /* allocate memory for row increments */
1912 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1913 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1915 /* precalculate row increments */
1916 for (x = 0; x <= dst->w; x++)
1917 *csax++ = (int)(sx * x);
1919 for (y = 0; y <= dst->h; y++)
1920 *csay++ = (int)(sy * y);
1923 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1924 dp = (tColorRGBA *) dst->pixels;
1925 dgap = dst->pitch - dst->w * 4;
1928 for (y = 0; y < dst->h; y++)
1933 for (x = 0; x < dst->w; x++)
1938 /* advance source pointers */
1942 /* advance destination pointer */
1946 /* advance source pointer */
1948 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1950 /* advance destination pointers */
1951 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1961 -----------------------------------------------------------------------------
1964 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1965 -----------------------------------------------------------------------------
1968 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1970 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1971 Uint8 *sp, *dp, *csp;
1974 /* variable setup */
1975 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1976 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1978 /* allocate memory for row increments */
1979 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1980 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1982 /* precalculate row increments */
1985 for (x = 0; x < dst->w; x++)
1988 *csax = (csx >> 16);
1995 for (y = 0; y < dst->h; y++)
1998 *csay = (csy >> 16);
2005 for (x = 0; x < dst->w; x++)
2013 for (y = 0; y < dst->h; y++)
2020 sp = csp = (Uint8 *) src->pixels;
2021 dp = (Uint8 *) dst->pixels;
2022 dgap = dst->pitch - dst->w;
2026 for (y = 0; y < dst->h; y++)
2030 for (x = 0; x < dst->w; x++)
2035 /* advance source pointers */
2039 /* advance destination pointer */
2043 /* advance source pointer (for row) */
2044 csp += ((*csay) * src->pitch);
2047 /* advance destination pointers */
2058 -----------------------------------------------------------------------------
2061 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2062 'zoomx' and 'zoomy' are scaling factors for width and height.
2063 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2064 into a 32bit RGBA format on the fly.
2065 -----------------------------------------------------------------------------
2068 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2070 SDL_Surface *zoom_src = NULL;
2071 SDL_Surface *zoom_dst = NULL;
2072 boolean is_converted = FALSE;
2079 /* determine if source surface is 32 bit or 8 bit */
2080 is_32bit = (src->format->BitsPerPixel == 32);
2082 if (is_32bit || src->format->BitsPerPixel == 8)
2084 /* use source surface 'as is' */
2089 /* new source surface is 32 bit with a defined RGB ordering */
2090 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2091 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2092 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2094 is_converted = TRUE;
2097 /* allocate surface to completely contain the zoomed surface */
2100 /* target surface is 32 bit with source RGBA/ABGR ordering */
2101 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2102 zoom_src->format->Rmask,
2103 zoom_src->format->Gmask,
2104 zoom_src->format->Bmask, 0);
2108 /* target surface is 8 bit */
2109 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2113 /* lock source surface */
2114 SDL_LockSurface(zoom_src);
2116 /* check which kind of surface we have */
2119 /* call the 32 bit transformation routine to do the zooming */
2120 zoomSurfaceRGBA(zoom_src, zoom_dst);
2125 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2126 zoom_dst->format->palette->colors[i] =
2127 zoom_src->format->palette->colors[i];
2128 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2130 /* call the 8 bit transformation routine to do the zooming */
2131 zoomSurfaceY(zoom_src, zoom_dst);
2134 /* unlock source surface */
2135 SDL_UnlockSurface(zoom_src);
2137 /* free temporary surface */
2139 SDL_FreeSurface(zoom_src);
2141 /* return destination surface */
2145 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2147 Bitmap *dst_bitmap = CreateBitmapStruct();
2148 SDL_Surface **dst_surface = &dst_bitmap->surface;
2150 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2151 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2153 dst_bitmap->width = dst_width;
2154 dst_bitmap->height = dst_height;
2156 /* create zoomed temporary surface from source surface */
2157 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2159 /* create native format destination surface from zoomed temporary surface */
2160 SDLSetNativeSurface(dst_surface);
2166 /* ========================================================================= */
2167 /* load image to bitmap */
2168 /* ========================================================================= */
2170 Bitmap *SDLLoadImage(char *filename)
2172 Bitmap *new_bitmap = CreateBitmapStruct();
2173 SDL_Surface *sdl_image_tmp;
2175 print_timestamp_init("SDLLoadImage");
2177 print_timestamp_time(getBaseNamePtr(filename));
2179 /* load image to temporary surface */
2180 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2182 SetError("IMG_Load(): %s", SDL_GetError());
2187 print_timestamp_time("IMG_Load");
2189 UPDATE_BUSY_STATE();
2191 /* create native non-transparent surface for current image */
2192 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2194 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2199 print_timestamp_time("SDL_DisplayFormat (opaque)");
2201 UPDATE_BUSY_STATE();
2203 /* create native transparent surface for current image */
2204 if (sdl_image_tmp->format->Amask == 0)
2205 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2206 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2208 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2210 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2215 print_timestamp_time("SDL_DisplayFormat (masked)");
2217 UPDATE_BUSY_STATE();
2219 /* free temporary surface */
2220 SDL_FreeSurface(sdl_image_tmp);
2222 new_bitmap->width = new_bitmap->surface->w;
2223 new_bitmap->height = new_bitmap->surface->h;
2225 print_timestamp_done("SDLLoadImage");
2231 /* ------------------------------------------------------------------------- */
2232 /* custom cursor fuctions */
2233 /* ------------------------------------------------------------------------- */
2235 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2237 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2238 cursor_info->width, cursor_info->height,
2239 cursor_info->hot_x, cursor_info->hot_y);
2242 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2244 static struct MouseCursorInfo *last_cursor_info = NULL;
2245 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2246 static SDL_Cursor *cursor_default = NULL;
2247 static SDL_Cursor *cursor_current = NULL;
2249 /* if invoked for the first time, store the SDL default cursor */
2250 if (cursor_default == NULL)
2251 cursor_default = SDL_GetCursor();
2253 /* only create new cursor if cursor info (custom only) has changed */
2254 if (cursor_info != NULL && cursor_info != last_cursor_info)
2256 cursor_current = create_cursor(cursor_info);
2257 last_cursor_info = cursor_info;
2260 /* only set new cursor if cursor info (custom or NULL) has changed */
2261 if (cursor_info != last_cursor_info2)
2262 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2264 last_cursor_info2 = cursor_info;
2268 /* ========================================================================= */
2269 /* audio functions */
2270 /* ========================================================================= */
2272 void SDLOpenAudio(void)
2274 #if !defined(TARGET_SDL2)
2275 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2276 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2279 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2281 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2285 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2286 AUDIO_NUM_CHANNELS_STEREO,
2287 setup.system.audio_fragment_size) < 0)
2289 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2293 audio.sound_available = TRUE;
2294 audio.music_available = TRUE;
2295 audio.loops_available = TRUE;
2296 audio.sound_enabled = TRUE;
2298 /* set number of available mixer channels */
2299 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2300 audio.music_channel = MUSIC_CHANNEL;
2301 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2303 Mixer_InitChannels();
2306 void SDLCloseAudio(void)
2309 Mix_HaltChannel(-1);
2312 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2316 /* ========================================================================= */
2317 /* event functions */
2318 /* ========================================================================= */
2320 void SDLNextEvent(Event *event)
2322 SDL_WaitEvent(event);
2325 void SDLHandleWindowManagerEvent(Event *event)
2328 #if defined(PLATFORM_WIN32)
2329 // experimental drag and drop code
2331 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2332 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2334 #if defined(TARGET_SDL2)
2335 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2337 if (syswmmsg->msg == WM_DROPFILES)
2340 #if defined(TARGET_SDL2)
2341 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2343 HDROP hdrop = (HDROP)syswmmsg->wParam;
2347 printf("::: SDL_SYSWMEVENT:\n");
2349 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2351 for (i = 0; i < num_files; i++)
2353 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2354 char buffer[buffer_len + 1];
2356 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2358 printf("::: - '%s'\n", buffer);
2361 #if defined(TARGET_SDL2)
2362 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2364 DragFinish((HDROP)syswmmsg->wParam);
2372 /* ========================================================================= */
2373 /* joystick functions */
2374 /* ========================================================================= */
2376 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2377 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2378 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2380 static boolean SDLOpenJoystick(int nr)
2382 if (nr < 0 || nr > MAX_PLAYERS)
2385 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2388 static void SDLCloseJoystick(int nr)
2390 if (nr < 0 || nr > MAX_PLAYERS)
2393 SDL_JoystickClose(sdl_joystick[nr]);
2395 sdl_joystick[nr] = NULL;
2398 static boolean SDLCheckJoystickOpened(int nr)
2400 if (nr < 0 || nr > MAX_PLAYERS)
2403 #if defined(TARGET_SDL2)
2404 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2406 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2410 void HandleJoystickEvent(Event *event)
2414 case SDL_JOYAXISMOTION:
2415 if (event->jaxis.axis < 2)
2416 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2419 case SDL_JOYBUTTONDOWN:
2420 if (event->jbutton.button < 2)
2421 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2424 case SDL_JOYBUTTONUP:
2425 if (event->jbutton.button < 2)
2426 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2434 void SDLInitJoysticks()
2436 static boolean sdl_joystick_subsystem_initialized = FALSE;
2437 boolean print_warning = !sdl_joystick_subsystem_initialized;
2440 if (!sdl_joystick_subsystem_initialized)
2442 sdl_joystick_subsystem_initialized = TRUE;
2444 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2446 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2451 for (i = 0; i < MAX_PLAYERS; i++)
2453 /* get configured joystick for this player */
2454 char *device_name = setup.input[i].joy.device_name;
2455 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2457 if (joystick_nr >= SDL_NumJoysticks())
2459 if (setup.input[i].use_joystick && print_warning)
2460 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2465 /* misuse joystick file descriptor variable to store joystick number */
2466 joystick.fd[i] = joystick_nr;
2468 if (joystick_nr == -1)
2471 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2472 if (SDLCheckJoystickOpened(joystick_nr))
2473 SDLCloseJoystick(joystick_nr);
2475 if (!setup.input[i].use_joystick)
2478 if (!SDLOpenJoystick(joystick_nr))
2481 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2486 joystick.status = JOYSTICK_ACTIVATED;
2490 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2492 if (nr < 0 || nr >= MAX_PLAYERS)
2496 *x = sdl_js_axis[nr][0];
2498 *y = sdl_js_axis[nr][1];
2501 *b1 = sdl_js_button[nr][0];
2503 *b2 = sdl_js_button[nr][1];