1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
18 #define ENABLE_UNUSED_CODE 0 /* currently unused functions */
21 /* ========================================================================= */
23 /* ========================================================================= */
25 /* SDL internal variables */
26 #if defined(TARGET_SDL2)
27 #define USE_TARGET_TEXTURE TRUE
28 #define USE_TARGET_TEXTURE_ONLY FALSE
30 static SDL_Window *sdl_window = NULL;
31 static SDL_Renderer *sdl_renderer = NULL;
32 #if USE_TARGET_TEXTURE
33 static SDL_Texture *sdl_texture_stream = NULL;
34 static SDL_Texture *sdl_texture_target = NULL;
36 static SDL_Texture *sdl_texture = NULL;
38 static boolean fullscreen_enabled = FALSE;
41 static boolean limit_screen_updates = FALSE;
44 /* functions from SGE library */
45 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
47 void SDLLimitScreenUpdates(boolean enable)
49 limit_screen_updates = enable;
52 static void UpdateScreen(SDL_Rect *rect)
54 static unsigned int update_screen_delay = 0;
55 unsigned int update_screen_delay_value = 50; /* (milliseconds) */
56 SDL_Surface *screen = backbuffer->surface;
58 if (limit_screen_updates &&
59 !DelayReached(&update_screen_delay, update_screen_delay_value))
62 LimitScreenUpdates(FALSE);
66 static int LastFrameCounter = 0;
67 boolean changed = (FrameCounter != LastFrameCounter);
69 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
70 (changed ? "-" : "SAME FRAME UPDATED"));
72 LastFrameCounter = FrameCounter;
81 #if USE_FINAL_SCREEN_BITMAP
82 if (gfx.final_screen_bitmap != NULL) // may not be initialized yet
85 // draw global animations using bitmaps instead of using textures
86 // to prevent texture scaling artefacts (this is potentially slower)
88 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
89 gfx.win_xsize, gfx.win_ysize, 0, 0);
91 // copy global animations to render target buffer, if defined (below border)
92 if (gfx.draw_global_anim_function != NULL)
93 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
95 // copy global masked border to render target buffer, if defined
96 if (gfx.draw_global_border_function != NULL)
97 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
99 // copy global animations to render target buffer, if defined (above border)
100 if (gfx.draw_global_anim_function != NULL)
101 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
103 screen = gfx.final_screen_bitmap->surface;
105 // force full window redraw
110 #if USE_TARGET_TEXTURE
111 #if USE_TARGET_TEXTURE_ONLY
112 SDL_Texture *sdl_texture = sdl_texture_target;
114 SDL_Texture *sdl_texture = sdl_texture_stream;
118 #if defined(TARGET_SDL2)
121 int bytes_x = screen->pitch / video.width;
122 int bytes_y = screen->pitch;
124 SDL_UpdateTexture(sdl_texture, rect,
125 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
130 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
133 // clear render target buffer
134 SDL_RenderClear(sdl_renderer);
136 #if USE_TARGET_TEXTURE
137 SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
139 // copy backbuffer to render target buffer
140 if (sdl_texture != sdl_texture_target)
141 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
143 // copy backbuffer to render target buffer
144 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
147 #if !USE_FINAL_SCREEN_BITMAP
148 // copy global animations to render target buffer, if defined (below border)
149 if (gfx.draw_global_anim_function != NULL)
150 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
152 // copy global masked border to render target buffer, if defined
153 if (gfx.draw_global_border_function != NULL)
154 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
156 // copy global animations to render target buffer, if defined (above border)
157 if (gfx.draw_global_anim_function != NULL)
158 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
161 #if USE_TARGET_TEXTURE
162 SDL_SetRenderTarget(sdl_renderer, NULL);
163 SDL_RenderCopy(sdl_renderer, sdl_texture_target, NULL, NULL);
166 // show render target buffer on screen
167 SDL_RenderPresent(sdl_renderer);
171 SDL_UpdateRects(screen, 1, rect);
173 SDL_UpdateRect(screen, 0, 0, 0, 0);
177 static void SDLSetWindowIcon(char *basename)
179 /* (setting the window icon on Mac OS X would replace the high-quality
180 dock icon with the currently smaller (and uglier) icon from file) */
182 #if !defined(PLATFORM_MACOSX)
183 char *filename = getCustomImageFilename(basename);
184 SDL_Surface *surface;
186 if (filename == NULL)
188 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
193 if ((surface = IMG_Load(filename)) == NULL)
195 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
200 /* set transparent color */
201 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
202 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
204 #if defined(TARGET_SDL2)
205 SDL_SetWindowIcon(sdl_window, surface);
207 SDL_WM_SetIcon(surface, NULL);
212 #if defined(TARGET_SDL2)
214 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
215 SDL_PixelFormat *format2)
217 return (format1->format == format2->format &&
218 format1->BitsPerPixel == format2->BitsPerPixel &&
219 format1->BytesPerPixel == format2->BytesPerPixel &&
220 format1->Rmask == format2->Rmask &&
221 format1->Gmask == format2->Gmask &&
222 format1->Bmask == format2->Bmask &&
223 format1->Amask == format2->Amask);
226 boolean SDLSetNativeSurface(SDL_Surface **surface)
228 SDL_Surface *new_surface;
230 if (surface == NULL ||
232 backbuffer == NULL ||
233 backbuffer->surface == NULL)
236 // if pixel format already optimized for destination surface, do nothing
237 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
240 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
242 if (new_surface == NULL)
243 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
245 SDL_FreeSurface(*surface);
247 *surface = new_surface;
252 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
254 SDL_PixelFormat format;
255 SDL_Surface *new_surface;
260 if (backbuffer && backbuffer->surface)
262 format = *backbuffer->surface->format;
263 format.Amask = surface->format->Amask; // keep alpha channel
267 format = *surface->format;
270 new_surface = SDL_ConvertSurface(surface, &format, 0);
272 if (new_surface == NULL)
273 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
280 boolean SDLSetNativeSurface(SDL_Surface **surface)
282 SDL_Surface *new_surface;
284 if (surface == NULL ||
289 new_surface = SDL_DisplayFormat(*surface);
291 if (new_surface == NULL)
292 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
294 SDL_FreeSurface(*surface);
296 *surface = new_surface;
301 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
303 SDL_Surface *new_surface;
305 if (video.initialized)
306 new_surface = SDL_DisplayFormat(surface);
308 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
310 if (new_surface == NULL)
311 Error(ERR_EXIT, "%s() failed: %s",
312 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
320 #if defined(TARGET_SDL2)
321 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
323 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
326 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
333 void SDLCreateBitmapTextures(Bitmap *bitmap)
335 #if defined(TARGET_SDL2)
340 SDL_DestroyTexture(bitmap->texture);
341 if (bitmap->texture_masked)
342 SDL_DestroyTexture(bitmap->texture_masked);
344 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
345 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
349 void SDLFreeBitmapTextures(Bitmap *bitmap)
351 #if defined(TARGET_SDL2)
356 SDL_DestroyTexture(bitmap->texture);
357 if (bitmap->texture_masked)
358 SDL_DestroyTexture(bitmap->texture_masked);
360 bitmap->texture = NULL;
361 bitmap->texture_masked = NULL;
365 void SDLInitVideoDisplay(void)
367 #if !defined(TARGET_SDL2)
368 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
369 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
371 SDL_putenv("SDL_VIDEO_CENTERED=1");
374 /* initialize SDL video */
375 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
376 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
378 /* set default SDL depth */
379 #if !defined(TARGET_SDL2)
380 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
382 video.default_depth = 32; // (how to determine video depth in SDL2?)
386 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
389 video.window_scaling_percent = setup.window_scaling_percent;
390 video.window_scaling_quality = setup.window_scaling_quality;
392 #if defined(TARGET_SDL2)
393 // SDL 2.0: support for (desktop) fullscreen mode available
394 video.fullscreen_available = TRUE;
396 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
397 video.fullscreen_available = FALSE;
400 /* open SDL video output device (window or fullscreen mode) */
401 if (!SDLSetVideoMode(backbuffer, fullscreen))
402 Error(ERR_EXIT, "setting video mode failed");
404 /* !!! SDL2 can only set the window icon if the window already exists !!! */
405 /* set window icon */
406 SDLSetWindowIcon(program.icon_filename);
408 /* set window and icon title */
409 #if defined(TARGET_SDL2)
410 SDL_SetWindowTitle(sdl_window, program.window_title);
412 SDL_WM_SetCaption(program.window_title, program.window_title);
415 /* SDL cannot directly draw to the visible video framebuffer like X11,
416 but always uses a backbuffer, which is then blitted to the visible
417 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
418 visible video framebuffer with 'SDL_Flip', if the hardware supports
419 this). Therefore do not use an additional backbuffer for drawing, but
420 use a symbolic buffer (distinguishable from the SDL backbuffer) called
421 'window', which indicates that the SDL backbuffer should be updated to
422 the visible video framebuffer when attempting to blit to it.
424 For convenience, it seems to be a good idea to create this symbolic
425 buffer 'window' at the same size as the SDL backbuffer. Although it
426 should never be drawn to directly, it would do no harm nevertheless. */
428 /* create additional (symbolic) buffer for double-buffering */
429 ReCreateBitmap(window, video.width, video.height, video.depth);
432 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
435 SDL_Surface *new_surface = NULL;
437 #if defined(TARGET_SDL2)
438 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
439 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
441 int surface_flags_window = SURFACE_FLAGS;
442 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
445 int width = video.width;
446 int height = video.height;
447 int surface_flags = (fullscreen ? surface_flags_fullscreen :
448 surface_flags_window);
450 // default window size is unscaled
451 video.window_width = video.width;
452 video.window_height = video.height;
454 #if defined(TARGET_SDL2)
456 // store if initial screen mode is fullscreen mode when changing screen size
457 video.fullscreen_initial = fullscreen;
459 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
461 video.window_width = window_scaling_factor * width;
462 video.window_height = window_scaling_factor * height;
464 if ((*backbuffer)->surface)
466 SDL_FreeSurface((*backbuffer)->surface);
467 (*backbuffer)->surface = NULL;
470 #if USE_TARGET_TEXTURE
471 if (sdl_texture_stream)
473 SDL_DestroyTexture(sdl_texture_stream);
474 sdl_texture_stream = NULL;
477 if (sdl_texture_target)
479 SDL_DestroyTexture(sdl_texture_target);
480 sdl_texture_target = NULL;
485 SDL_DestroyTexture(sdl_texture);
490 if (!(fullscreen && fullscreen_enabled))
494 SDL_DestroyRenderer(sdl_renderer);
500 SDL_DestroyWindow(sdl_window);
505 if (sdl_window == NULL)
506 sdl_window = SDL_CreateWindow(program.window_title,
507 SDL_WINDOWPOS_CENTERED,
508 SDL_WINDOWPOS_CENTERED,
513 if (sdl_window != NULL)
516 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
517 *without* enabling 2D/3D acceleration and/or guest additions installed,
518 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
519 it will try to use accelerated graphics and apparently fails miserably) */
520 if (sdl_renderer == NULL)
521 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
523 if (sdl_renderer == NULL)
524 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
527 if (sdl_renderer != NULL)
529 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
530 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
531 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
533 #if USE_TARGET_TEXTURE
534 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
535 SDL_PIXELFORMAT_ARGB8888,
536 SDL_TEXTUREACCESS_STREAMING,
539 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
540 SDL_PIXELFORMAT_ARGB8888,
541 SDL_TEXTUREACCESS_TARGET,
544 sdl_texture = SDL_CreateTexture(sdl_renderer,
545 SDL_PIXELFORMAT_ARGB8888,
546 SDL_TEXTUREACCESS_STREAMING,
550 #if USE_TARGET_TEXTURE
551 if (sdl_texture_stream != NULL &&
552 sdl_texture_target != NULL)
554 if (sdl_texture != NULL)
557 // use SDL default values for RGB masks and no alpha channel
558 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
560 if (new_surface == NULL)
561 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
565 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
570 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
575 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
579 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
581 if (new_surface == NULL)
582 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
585 #if defined(TARGET_SDL2)
586 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
587 if (new_surface != NULL)
588 fullscreen_enabled = fullscreen;
594 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
596 boolean success = TRUE;
597 SDL_Surface *new_surface = NULL;
601 if (*backbuffer == NULL)
602 *backbuffer = CreateBitmapStruct();
604 /* (real bitmap might be larger in fullscreen mode with video offsets) */
605 (*backbuffer)->width = video.width;
606 (*backbuffer)->height = video.height;
608 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
610 /* switch display to fullscreen mode, if available */
611 new_surface = SDLCreateScreen(backbuffer, TRUE);
613 if (new_surface == NULL)
615 /* switching display to fullscreen mode failed -- do not try it again */
616 video.fullscreen_available = FALSE;
622 (*backbuffer)->surface = new_surface;
624 video.fullscreen_enabled = TRUE;
630 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
632 /* switch display to window mode */
633 new_surface = SDLCreateScreen(backbuffer, FALSE);
635 if (new_surface == NULL)
637 /* switching display to window mode failed -- should not happen */
643 (*backbuffer)->surface = new_surface;
645 video.fullscreen_enabled = FALSE;
646 video.window_scaling_percent = setup.window_scaling_percent;
647 video.window_scaling_quality = setup.window_scaling_quality;
653 #if defined(TARGET_SDL2)
654 SDLRedrawWindow(); // map window
658 #if defined(PLATFORM_WIN32)
659 // experimental drag and drop code
661 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
664 SDL_SysWMinfo wminfo;
666 boolean wminfo_success = FALSE;
668 SDL_VERSION(&wminfo.version);
669 #if defined(TARGET_SDL2)
671 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
673 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
678 #if defined(TARGET_SDL2)
679 hwnd = wminfo.info.win.window;
681 hwnd = wminfo.window;
684 DragAcceptFiles(hwnd, TRUE);
693 void SDLSetWindowTitle()
695 #if defined(TARGET_SDL2)
696 SDL_SetWindowTitle(sdl_window, program.window_title);
698 SDL_WM_SetCaption(program.window_title, program.window_title);
702 #if defined(TARGET_SDL2)
703 void SDLSetWindowScaling(int window_scaling_percent)
705 if (sdl_window == NULL)
708 float window_scaling_factor = (float)window_scaling_percent / 100;
709 int new_window_width = (int)(window_scaling_factor * video.width);
710 int new_window_height = (int)(window_scaling_factor * video.height);
712 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
714 video.window_scaling_percent = window_scaling_percent;
715 video.window_width = new_window_width;
716 video.window_height = new_window_height;
721 void SDLSetWindowScalingQuality(char *window_scaling_quality)
723 #if USE_TARGET_TEXTURE
724 SDL_Texture *new_texture;
726 if (sdl_texture_stream == NULL ||
727 sdl_texture_target == NULL)
730 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
732 new_texture = SDL_CreateTexture(sdl_renderer,
733 SDL_PIXELFORMAT_ARGB8888,
734 SDL_TEXTUREACCESS_STREAMING,
735 video.width, video.height);
737 if (new_texture != NULL)
739 SDL_DestroyTexture(sdl_texture_stream);
741 sdl_texture_stream = new_texture;
744 new_texture = SDL_CreateTexture(sdl_renderer,
745 SDL_PIXELFORMAT_ARGB8888,
746 SDL_TEXTUREACCESS_TARGET,
747 video.width, video.height);
749 if (new_texture != NULL)
751 SDL_DestroyTexture(sdl_texture_target);
753 sdl_texture_target = new_texture;
759 if (sdl_texture == NULL)
762 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
764 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
765 SDL_PIXELFORMAT_ARGB8888,
766 SDL_TEXTUREACCESS_STREAMING,
767 video.width, video.height);
769 if (new_texture != NULL)
771 SDL_DestroyTexture(sdl_texture);
773 sdl_texture = new_texture;
779 video.window_scaling_quality = window_scaling_quality;
782 void SDLSetWindowFullscreen(boolean fullscreen)
784 if (sdl_window == NULL)
787 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
789 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
790 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
792 // if screen size was changed in fullscreen mode, correct desktop window size
793 if (!fullscreen && video.fullscreen_initial)
795 SDLSetWindowScaling(setup.window_scaling_percent);
796 SDL_SetWindowPosition(sdl_window,
797 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
799 video.fullscreen_initial = FALSE;
803 void SDLRedrawWindow()
809 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
812 SDL_Surface *surface =
813 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
816 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
818 SDLSetNativeSurface(&surface);
820 bitmap->surface = surface;
823 void SDLFreeBitmapPointers(Bitmap *bitmap)
826 SDL_FreeSurface(bitmap->surface);
827 if (bitmap->surface_masked)
828 SDL_FreeSurface(bitmap->surface_masked);
830 bitmap->surface = NULL;
831 bitmap->surface_masked = NULL;
833 #if defined(TARGET_SDL2)
835 SDL_DestroyTexture(bitmap->texture);
836 if (bitmap->texture_masked)
837 SDL_DestroyTexture(bitmap->texture_masked);
839 bitmap->texture = NULL;
840 bitmap->texture_masked = NULL;
844 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
845 int src_x, int src_y, int width, int height,
846 int dst_x, int dst_y, int mask_mode)
848 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
849 SDL_Rect src_rect, dst_rect;
861 // if (src_bitmap != backbuffer || dst_bitmap != window)
862 if (!(src_bitmap == backbuffer && dst_bitmap == window))
863 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
864 src_bitmap->surface_masked : src_bitmap->surface),
865 &src_rect, real_dst_bitmap->surface, &dst_rect);
867 if (dst_bitmap == window)
868 UpdateScreen(&dst_rect);
871 void SDLBlitTexture(Bitmap *bitmap,
872 int src_x, int src_y, int width, int height,
873 int dst_x, int dst_y, int mask_mode)
875 #if defined(TARGET_SDL2)
876 SDL_Texture *texture;
881 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
896 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
900 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
903 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
911 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
913 #if defined(TARGET_SDL2)
914 if (dst_bitmap == window)
916 // SDL_UpdateWindowSurface(sdl_window);
917 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
921 if (dst_bitmap == window)
923 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
929 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
930 int fade_mode, int fade_delay, int post_delay,
931 void (*draw_border_function)(void))
933 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
934 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
935 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
936 SDL_Surface *surface_screen = backbuffer->surface;
937 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
938 SDL_Rect src_rect, dst_rect;
940 int src_x = x, src_y = y;
941 int dst_x = x, dst_y = y;
942 unsigned int time_last, time_current;
944 // store function for drawing global masked border
945 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
947 // deactivate drawing of global border while fading, if needed
948 if (draw_border_function == NULL)
949 gfx.draw_global_border_function = NULL;
958 dst_rect.w = width; /* (ignored) */
959 dst_rect.h = height; /* (ignored) */
961 dst_rect2 = dst_rect;
963 /* copy source and target surfaces to temporary surfaces for fading */
964 if (fade_mode & FADE_TYPE_TRANSFORM)
966 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
967 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
969 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
970 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
972 else if (fade_mode & FADE_TYPE_FADE_IN)
974 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
975 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
977 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
979 else /* FADE_TYPE_FADE_OUT */
981 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
982 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
984 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
987 time_current = SDL_GetTicks();
989 if (fade_mode == FADE_MODE_MELT)
991 boolean done = FALSE;
993 int melt_columns = width / melt_pixels;
994 int ypos[melt_columns];
995 int max_steps = height / 8 + 32;
1000 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1001 #if defined(TARGET_SDL2)
1002 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1004 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1007 ypos[0] = -GetSimpleRandom(16);
1009 for (i = 1 ; i < melt_columns; i++)
1011 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1013 ypos[i] = ypos[i - 1] + r;
1026 time_last = time_current;
1027 time_current = SDL_GetTicks();
1028 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1029 steps_final = MIN(MAX(0, steps), max_steps);
1033 done = (steps_done >= steps_final);
1035 for (i = 0 ; i < melt_columns; i++)
1043 else if (ypos[i] < height)
1048 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1050 if (ypos[i] + dy >= height)
1051 dy = height - ypos[i];
1053 /* copy part of (appearing) target surface to upper area */
1054 src_rect.x = src_x + i * melt_pixels;
1055 // src_rect.y = src_y + ypos[i];
1057 src_rect.w = melt_pixels;
1059 src_rect.h = ypos[i] + dy;
1061 dst_rect.x = dst_x + i * melt_pixels;
1062 // dst_rect.y = dst_y + ypos[i];
1065 if (steps_done >= steps_final)
1066 SDL_BlitSurface(surface_target, &src_rect,
1067 surface_screen, &dst_rect);
1071 /* copy part of (disappearing) source surface to lower area */
1072 src_rect.x = src_x + i * melt_pixels;
1074 src_rect.w = melt_pixels;
1075 src_rect.h = height - ypos[i];
1077 dst_rect.x = dst_x + i * melt_pixels;
1078 dst_rect.y = dst_y + ypos[i];
1080 if (steps_done >= steps_final)
1081 SDL_BlitSurface(surface_source, &src_rect,
1082 surface_screen, &dst_rect);
1088 src_rect.x = src_x + i * melt_pixels;
1090 src_rect.w = melt_pixels;
1091 src_rect.h = height;
1093 dst_rect.x = dst_x + i * melt_pixels;
1096 if (steps_done >= steps_final)
1097 SDL_BlitSurface(surface_target, &src_rect,
1098 surface_screen, &dst_rect);
1102 if (steps_done >= steps_final)
1104 if (draw_border_function != NULL)
1105 draw_border_function();
1107 UpdateScreen(&dst_rect2);
1111 else if (fade_mode == FADE_MODE_CURTAIN)
1115 int xx_size = width / 2;
1117 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1118 #if defined(TARGET_SDL2)
1119 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1121 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1124 for (xx = 0; xx < xx_size;)
1126 time_last = time_current;
1127 time_current = SDL_GetTicks();
1128 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1129 xx_final = MIN(MAX(0, xx), xx_size);
1134 src_rect.h = height;
1139 /* draw new (target) image to screen buffer */
1140 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1142 if (xx_final < xx_size)
1144 src_rect.w = xx_size - xx_final;
1145 src_rect.h = height;
1147 /* draw old (source) image to screen buffer (left side) */
1149 src_rect.x = src_x + xx_final;
1152 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1154 /* draw old (source) image to screen buffer (right side) */
1156 src_rect.x = src_x + xx_size;
1157 dst_rect.x = dst_x + xx_size + xx_final;
1159 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1162 if (draw_border_function != NULL)
1163 draw_border_function();
1165 /* only update the region of the screen that is affected from fading */
1166 UpdateScreen(&dst_rect2);
1169 else /* fading in, fading out or cross-fading */
1174 for (alpha = 0.0; alpha < 255.0;)
1176 time_last = time_current;
1177 time_current = SDL_GetTicks();
1178 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1179 alpha_final = MIN(MAX(0, alpha), 255);
1181 /* draw existing (source) image to screen buffer */
1182 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1184 /* draw new (target) image to screen buffer using alpha blending */
1185 #if defined(TARGET_SDL2)
1186 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1187 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1189 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1191 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1193 if (draw_border_function != NULL)
1194 draw_border_function();
1196 /* only update the region of the screen that is affected from fading */
1197 UpdateScreen(&dst_rect);
1203 unsigned int time_post_delay;
1205 time_current = SDL_GetTicks();
1206 time_post_delay = time_current + post_delay;
1208 while (time_current < time_post_delay)
1210 // do not wait longer than 10 ms at a time to be able to ...
1211 Delay(MIN(10, time_post_delay - time_current));
1213 // ... continue drawing global animations during post delay
1216 time_current = SDL_GetTicks();
1220 // restore function for drawing global masked border
1221 gfx.draw_global_border_function = draw_global_border_function;
1224 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1225 int to_x, int to_y, Uint32 color)
1227 SDL_Surface *surface = dst_bitmap->surface;
1231 swap_numbers(&from_x, &to_x);
1234 swap_numbers(&from_y, &to_y);
1238 rect.w = (to_x - from_x + 1);
1239 rect.h = (to_y - from_y + 1);
1241 SDL_FillRect(surface, &rect, color);
1244 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1245 int to_x, int to_y, Uint32 color)
1247 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1250 #if ENABLE_UNUSED_CODE
1251 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1252 int num_points, Uint32 color)
1257 for (i = 0; i < num_points - 1; i++)
1259 for (x = 0; x < line_width; x++)
1261 for (y = 0; y < line_width; y++)
1263 int dx = x - line_width / 2;
1264 int dy = y - line_width / 2;
1266 if ((x == 0 && y == 0) ||
1267 (x == 0 && y == line_width - 1) ||
1268 (x == line_width - 1 && y == 0) ||
1269 (x == line_width - 1 && y == line_width - 1))
1272 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1273 points[i+1].x + dx, points[i+1].y + dy, color);
1280 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1282 SDL_Surface *surface = src_bitmap->surface;
1284 switch (surface->format->BytesPerPixel)
1286 case 1: /* assuming 8-bpp */
1288 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1292 case 2: /* probably 15-bpp or 16-bpp */
1294 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1298 case 3: /* slow 24-bpp mode; usually not used */
1300 /* does this work? */
1301 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1305 shift = surface->format->Rshift;
1306 color |= *(pix + shift / 8) >> shift;
1307 shift = surface->format->Gshift;
1308 color |= *(pix + shift / 8) >> shift;
1309 shift = surface->format->Bshift;
1310 color |= *(pix + shift / 8) >> shift;
1316 case 4: /* probably 32-bpp */
1318 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1327 /* ========================================================================= */
1328 /* The following functions were taken from the SGE library */
1329 /* (SDL Graphics Extension Library) by Anders Lindström */
1330 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1331 /* ========================================================================= */
1333 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1335 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1337 switch (surface->format->BytesPerPixel)
1341 /* Assuming 8-bpp */
1342 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1348 /* Probably 15-bpp or 16-bpp */
1349 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1355 /* Slow 24-bpp mode, usually not used */
1359 /* Gack - slow, but endian correct */
1360 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1361 shift = surface->format->Rshift;
1362 *(pix+shift/8) = color>>shift;
1363 shift = surface->format->Gshift;
1364 *(pix+shift/8) = color>>shift;
1365 shift = surface->format->Bshift;
1366 *(pix+shift/8) = color>>shift;
1372 /* Probably 32-bpp */
1373 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1380 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1381 Uint8 R, Uint8 G, Uint8 B)
1383 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1386 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1388 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1391 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1393 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1396 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1401 /* Gack - slow, but endian correct */
1402 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1403 shift = surface->format->Rshift;
1404 *(pix+shift/8) = color>>shift;
1405 shift = surface->format->Gshift;
1406 *(pix+shift/8) = color>>shift;
1407 shift = surface->format->Bshift;
1408 *(pix+shift/8) = color>>shift;
1411 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1413 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1416 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1418 switch (dest->format->BytesPerPixel)
1421 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1425 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1429 _PutPixel24(dest,x,y,color);
1433 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1438 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1440 if (SDL_MUSTLOCK(surface))
1442 if (SDL_LockSurface(surface) < 0)
1448 _PutPixel(surface, x, y, color);
1450 if (SDL_MUSTLOCK(surface))
1452 SDL_UnlockSurface(surface);
1456 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1457 Uint8 r, Uint8 g, Uint8 b)
1459 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1462 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1464 if (y >= 0 && y <= dest->h - 1)
1466 switch (dest->format->BytesPerPixel)
1469 return y*dest->pitch;
1473 return y*dest->pitch/2;
1477 return y*dest->pitch;
1481 return y*dest->pitch/4;
1489 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1491 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1493 switch (surface->format->BytesPerPixel)
1497 /* Assuming 8-bpp */
1498 *((Uint8 *)surface->pixels + ypitch + x) = color;
1504 /* Probably 15-bpp or 16-bpp */
1505 *((Uint16 *)surface->pixels + ypitch + x) = color;
1511 /* Slow 24-bpp mode, usually not used */
1515 /* Gack - slow, but endian correct */
1516 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1517 shift = surface->format->Rshift;
1518 *(pix+shift/8) = color>>shift;
1519 shift = surface->format->Gshift;
1520 *(pix+shift/8) = color>>shift;
1521 shift = surface->format->Bshift;
1522 *(pix+shift/8) = color>>shift;
1528 /* Probably 32-bpp */
1529 *((Uint32 *)surface->pixels + ypitch + x) = color;
1536 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1541 if (SDL_MUSTLOCK(Surface))
1543 if (SDL_LockSurface(Surface) < 0)
1556 /* Do the clipping */
1557 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1561 if (x2 > Surface->w - 1)
1562 x2 = Surface->w - 1;
1569 SDL_FillRect(Surface, &l, Color);
1571 if (SDL_MUSTLOCK(Surface))
1573 SDL_UnlockSurface(Surface);
1577 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1578 Uint8 R, Uint8 G, Uint8 B)
1580 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1583 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1594 /* Do the clipping */
1595 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1599 if (x2 > Surface->w - 1)
1600 x2 = Surface->w - 1;
1607 SDL_FillRect(Surface, &l, Color);
1610 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1615 if (SDL_MUSTLOCK(Surface))
1617 if (SDL_LockSurface(Surface) < 0)
1630 /* Do the clipping */
1631 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1635 if (y2 > Surface->h - 1)
1636 y2 = Surface->h - 1;
1643 SDL_FillRect(Surface, &l, Color);
1645 if (SDL_MUSTLOCK(Surface))
1647 SDL_UnlockSurface(Surface);
1651 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1652 Uint8 R, Uint8 G, Uint8 B)
1654 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1657 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1668 /* Do the clipping */
1669 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1673 if (y2 > Surface->h - 1)
1674 y2 = Surface->h - 1;
1681 SDL_FillRect(Surface, &l, Color);
1684 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1685 Sint16 x2, Sint16 y2, Uint32 Color,
1686 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1689 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1694 sdx = (dx < 0) ? -1 : 1;
1695 sdy = (dy < 0) ? -1 : 1;
1707 for (x = 0; x < dx; x++)
1709 Callback(Surface, px, py, Color);
1723 for (y = 0; y < dy; y++)
1725 Callback(Surface, px, py, Color);
1739 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1740 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1741 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1744 sge_DoLine(Surface, X1, Y1, X2, Y2,
1745 SDL_MapRGB(Surface->format, R, G, B), Callback);
1748 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1751 if (SDL_MUSTLOCK(Surface))
1753 if (SDL_LockSurface(Surface) < 0)
1758 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1760 /* unlock the display */
1761 if (SDL_MUSTLOCK(Surface))
1763 SDL_UnlockSurface(Surface);
1767 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1768 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1770 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1773 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1775 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1780 -----------------------------------------------------------------------------
1781 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1782 -----------------------------------------------------------------------------
1785 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1786 int width, int height, Uint32 color)
1790 for (y = src_y; y < src_y + height; y++)
1792 for (x = src_x; x < src_x + width; x++)
1794 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1796 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1801 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1802 int src_x, int src_y, int width, int height,
1803 int dst_x, int dst_y)
1807 for (y = 0; y < height; y++)
1809 for (x = 0; x < width; x++)
1811 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1813 if (pixel != BLACK_PIXEL)
1814 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1820 /* ========================================================================= */
1821 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1822 /* (Rotozoomer) by Andreas Schiffler */
1823 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1824 /* ========================================================================= */
1827 -----------------------------------------------------------------------------
1830 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1831 -----------------------------------------------------------------------------
1842 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1845 tColorRGBA *sp, *csp, *dp;
1849 sp = csp = (tColorRGBA *) src->pixels;
1850 dp = (tColorRGBA *) dst->pixels;
1851 dgap = dst->pitch - dst->w * 4;
1853 for (y = 0; y < dst->h; y++)
1857 for (x = 0; x < dst->w; x++)
1859 tColorRGBA *sp0 = sp;
1860 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1861 tColorRGBA *sp00 = &sp0[0];
1862 tColorRGBA *sp01 = &sp0[1];
1863 tColorRGBA *sp10 = &sp1[0];
1864 tColorRGBA *sp11 = &sp1[1];
1867 /* create new color pixel from all four source color pixels */
1868 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1869 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1870 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1871 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1876 /* advance source pointers */
1879 /* advance destination pointer */
1883 /* advance source pointer */
1884 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1886 /* advance destination pointers */
1887 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1893 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1895 int x, y, *sax, *say, *csax, *csay;
1897 tColorRGBA *sp, *csp, *csp0, *dp;
1900 /* use specialized zoom function when scaling down to exactly half size */
1901 if (src->w == 2 * dst->w &&
1902 src->h == 2 * dst->h)
1903 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1905 /* variable setup */
1906 sx = (float) src->w / (float) dst->w;
1907 sy = (float) src->h / (float) dst->h;
1909 /* allocate memory for row increments */
1910 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1911 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1913 /* precalculate row increments */
1914 for (x = 0; x <= dst->w; x++)
1915 *csax++ = (int)(sx * x);
1917 for (y = 0; y <= dst->h; y++)
1918 *csay++ = (int)(sy * y);
1921 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1922 dp = (tColorRGBA *) dst->pixels;
1923 dgap = dst->pitch - dst->w * 4;
1926 for (y = 0; y < dst->h; y++)
1931 for (x = 0; x < dst->w; x++)
1936 /* advance source pointers */
1940 /* advance destination pointer */
1944 /* advance source pointer */
1946 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1948 /* advance destination pointers */
1949 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1959 -----------------------------------------------------------------------------
1962 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1963 -----------------------------------------------------------------------------
1966 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1968 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1969 Uint8 *sp, *dp, *csp;
1972 /* variable setup */
1973 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1974 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1976 /* allocate memory for row increments */
1977 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1978 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1980 /* precalculate row increments */
1983 for (x = 0; x < dst->w; x++)
1986 *csax = (csx >> 16);
1993 for (y = 0; y < dst->h; y++)
1996 *csay = (csy >> 16);
2003 for (x = 0; x < dst->w; x++)
2011 for (y = 0; y < dst->h; y++)
2018 sp = csp = (Uint8 *) src->pixels;
2019 dp = (Uint8 *) dst->pixels;
2020 dgap = dst->pitch - dst->w;
2024 for (y = 0; y < dst->h; y++)
2028 for (x = 0; x < dst->w; x++)
2033 /* advance source pointers */
2037 /* advance destination pointer */
2041 /* advance source pointer (for row) */
2042 csp += ((*csay) * src->pitch);
2045 /* advance destination pointers */
2056 -----------------------------------------------------------------------------
2059 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2060 'zoomx' and 'zoomy' are scaling factors for width and height.
2061 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2062 into a 32bit RGBA format on the fly.
2063 -----------------------------------------------------------------------------
2066 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2068 SDL_Surface *zoom_src = NULL;
2069 SDL_Surface *zoom_dst = NULL;
2070 boolean is_converted = FALSE;
2077 /* determine if source surface is 32 bit or 8 bit */
2078 is_32bit = (src->format->BitsPerPixel == 32);
2080 if (is_32bit || src->format->BitsPerPixel == 8)
2082 /* use source surface 'as is' */
2087 /* new source surface is 32 bit with a defined RGB ordering */
2088 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2089 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2090 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2092 is_converted = TRUE;
2095 /* allocate surface to completely contain the zoomed surface */
2098 /* target surface is 32 bit with source RGBA/ABGR ordering */
2099 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2100 zoom_src->format->Rmask,
2101 zoom_src->format->Gmask,
2102 zoom_src->format->Bmask, 0);
2106 /* target surface is 8 bit */
2107 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2111 /* lock source surface */
2112 SDL_LockSurface(zoom_src);
2114 /* check which kind of surface we have */
2117 /* call the 32 bit transformation routine to do the zooming */
2118 zoomSurfaceRGBA(zoom_src, zoom_dst);
2123 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2124 zoom_dst->format->palette->colors[i] =
2125 zoom_src->format->palette->colors[i];
2126 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2128 /* call the 8 bit transformation routine to do the zooming */
2129 zoomSurfaceY(zoom_src, zoom_dst);
2132 /* unlock source surface */
2133 SDL_UnlockSurface(zoom_src);
2135 /* free temporary surface */
2137 SDL_FreeSurface(zoom_src);
2139 /* return destination surface */
2143 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2145 Bitmap *dst_bitmap = CreateBitmapStruct();
2146 SDL_Surface **dst_surface = &dst_bitmap->surface;
2148 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2149 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2151 dst_bitmap->width = dst_width;
2152 dst_bitmap->height = dst_height;
2154 /* create zoomed temporary surface from source surface */
2155 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2157 /* create native format destination surface from zoomed temporary surface */
2158 SDLSetNativeSurface(dst_surface);
2164 /* ========================================================================= */
2165 /* load image to bitmap */
2166 /* ========================================================================= */
2168 Bitmap *SDLLoadImage(char *filename)
2170 Bitmap *new_bitmap = CreateBitmapStruct();
2171 SDL_Surface *sdl_image_tmp;
2173 print_timestamp_init("SDLLoadImage");
2175 print_timestamp_time(getBaseNamePtr(filename));
2177 /* load image to temporary surface */
2178 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2180 SetError("IMG_Load(): %s", SDL_GetError());
2185 print_timestamp_time("IMG_Load");
2187 UPDATE_BUSY_STATE();
2189 /* create native non-transparent surface for current image */
2190 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2192 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2197 print_timestamp_time("SDL_DisplayFormat (opaque)");
2199 UPDATE_BUSY_STATE();
2201 /* create native transparent surface for current image */
2202 if (sdl_image_tmp->format->Amask == 0)
2203 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2204 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2206 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2208 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2213 print_timestamp_time("SDL_DisplayFormat (masked)");
2215 UPDATE_BUSY_STATE();
2217 /* free temporary surface */
2218 SDL_FreeSurface(sdl_image_tmp);
2220 new_bitmap->width = new_bitmap->surface->w;
2221 new_bitmap->height = new_bitmap->surface->h;
2223 print_timestamp_done("SDLLoadImage");
2229 /* ------------------------------------------------------------------------- */
2230 /* custom cursor fuctions */
2231 /* ------------------------------------------------------------------------- */
2233 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2235 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2236 cursor_info->width, cursor_info->height,
2237 cursor_info->hot_x, cursor_info->hot_y);
2240 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2242 static struct MouseCursorInfo *last_cursor_info = NULL;
2243 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2244 static SDL_Cursor *cursor_default = NULL;
2245 static SDL_Cursor *cursor_current = NULL;
2247 /* if invoked for the first time, store the SDL default cursor */
2248 if (cursor_default == NULL)
2249 cursor_default = SDL_GetCursor();
2251 /* only create new cursor if cursor info (custom only) has changed */
2252 if (cursor_info != NULL && cursor_info != last_cursor_info)
2254 cursor_current = create_cursor(cursor_info);
2255 last_cursor_info = cursor_info;
2258 /* only set new cursor if cursor info (custom or NULL) has changed */
2259 if (cursor_info != last_cursor_info2)
2260 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2262 last_cursor_info2 = cursor_info;
2266 /* ========================================================================= */
2267 /* audio functions */
2268 /* ========================================================================= */
2270 void SDLOpenAudio(void)
2272 #if !defined(TARGET_SDL2)
2273 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2274 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2277 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2279 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2283 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2284 AUDIO_NUM_CHANNELS_STEREO,
2285 setup.system.audio_fragment_size) < 0)
2287 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2291 audio.sound_available = TRUE;
2292 audio.music_available = TRUE;
2293 audio.loops_available = TRUE;
2294 audio.sound_enabled = TRUE;
2296 /* set number of available mixer channels */
2297 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2298 audio.music_channel = MUSIC_CHANNEL;
2299 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2301 Mixer_InitChannels();
2304 void SDLCloseAudio(void)
2307 Mix_HaltChannel(-1);
2310 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2314 /* ========================================================================= */
2315 /* event functions */
2316 /* ========================================================================= */
2318 void SDLNextEvent(Event *event)
2320 SDL_WaitEvent(event);
2323 void SDLHandleWindowManagerEvent(Event *event)
2326 #if defined(PLATFORM_WIN32)
2327 // experimental drag and drop code
2329 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2330 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2332 #if defined(TARGET_SDL2)
2333 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2335 if (syswmmsg->msg == WM_DROPFILES)
2338 #if defined(TARGET_SDL2)
2339 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2341 HDROP hdrop = (HDROP)syswmmsg->wParam;
2345 printf("::: SDL_SYSWMEVENT:\n");
2347 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2349 for (i = 0; i < num_files; i++)
2351 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2352 char buffer[buffer_len + 1];
2354 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2356 printf("::: - '%s'\n", buffer);
2359 #if defined(TARGET_SDL2)
2360 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2362 DragFinish((HDROP)syswmmsg->wParam);
2370 /* ========================================================================= */
2371 /* joystick functions */
2372 /* ========================================================================= */
2374 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2375 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2376 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2378 static boolean SDLOpenJoystick(int nr)
2380 if (nr < 0 || nr > MAX_PLAYERS)
2383 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2386 static void SDLCloseJoystick(int nr)
2388 if (nr < 0 || nr > MAX_PLAYERS)
2391 SDL_JoystickClose(sdl_joystick[nr]);
2393 sdl_joystick[nr] = NULL;
2396 static boolean SDLCheckJoystickOpened(int nr)
2398 if (nr < 0 || nr > MAX_PLAYERS)
2401 #if defined(TARGET_SDL2)
2402 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2404 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2408 void HandleJoystickEvent(Event *event)
2412 case SDL_JOYAXISMOTION:
2413 if (event->jaxis.axis < 2)
2414 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2417 case SDL_JOYBUTTONDOWN:
2418 if (event->jbutton.button < 2)
2419 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2422 case SDL_JOYBUTTONUP:
2423 if (event->jbutton.button < 2)
2424 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2432 void SDLInitJoysticks()
2434 static boolean sdl_joystick_subsystem_initialized = FALSE;
2435 boolean print_warning = !sdl_joystick_subsystem_initialized;
2438 if (!sdl_joystick_subsystem_initialized)
2440 sdl_joystick_subsystem_initialized = TRUE;
2442 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2444 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2449 for (i = 0; i < MAX_PLAYERS; i++)
2451 /* get configured joystick for this player */
2452 char *device_name = setup.input[i].joy.device_name;
2453 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2455 if (joystick_nr >= SDL_NumJoysticks())
2457 if (setup.input[i].use_joystick && print_warning)
2458 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2463 /* misuse joystick file descriptor variable to store joystick number */
2464 joystick.fd[i] = joystick_nr;
2466 if (joystick_nr == -1)
2469 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2470 if (SDLCheckJoystickOpened(joystick_nr))
2471 SDLCloseJoystick(joystick_nr);
2473 if (!setup.input[i].use_joystick)
2476 if (!SDLOpenJoystick(joystick_nr))
2479 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2484 joystick.status = JOYSTICK_ACTIVATED;
2488 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2490 if (nr < 0 || nr >= MAX_PLAYERS)
2494 *x = sdl_js_axis[nr][0];
2496 *y = sdl_js_axis[nr][1];
2499 *b1 = sdl_js_button[nr][0];
2501 *b2 = sdl_js_button[nr][1];