1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
18 #define ENABLE_UNUSED_CODE 0 /* currently unused functions */
21 /* ========================================================================= */
23 /* ========================================================================= */
25 /* SDL internal variables */
26 #if defined(TARGET_SDL2)
27 static SDL_Window *sdl_window = NULL;
28 static SDL_Renderer *sdl_renderer = NULL;
29 static SDL_Texture *sdl_texture_stream = NULL;
30 static SDL_Texture *sdl_texture_target = NULL;
31 static boolean fullscreen_enabled = FALSE;
34 static boolean limit_screen_updates = FALSE;
37 /* functions from SGE library */
38 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
40 void SDLLimitScreenUpdates(boolean enable)
42 limit_screen_updates = enable;
45 static void FinalizeScreen()
47 // copy global animations to render target buffer, if defined (below border)
48 if (gfx.draw_global_anim_function != NULL)
49 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_1);
51 // copy global masked border to render target buffer, if defined
52 if (gfx.draw_global_border_function != NULL)
53 gfx.draw_global_border_function(DRAW_BORDER_TO_SCREEN);
55 // copy global animations to render target buffer, if defined (above border)
56 if (gfx.draw_global_anim_function != NULL)
57 gfx.draw_global_anim_function(DRAW_GLOBAL_ANIM_STAGE_2);
60 static void UpdateScreen(SDL_Rect *rect)
62 static unsigned int update_screen_delay = 0;
63 unsigned int update_screen_delay_value = 50; /* (milliseconds) */
64 SDL_Surface *screen = backbuffer->surface;
66 if (limit_screen_updates &&
67 !DelayReached(&update_screen_delay, update_screen_delay_value))
70 LimitScreenUpdates(FALSE);
74 static int LastFrameCounter = 0;
75 boolean changed = (FrameCounter != LastFrameCounter);
77 printf("::: FrameCounter == %d [%s]\n", FrameCounter,
78 (changed ? "-" : "SAME FRAME UPDATED"));
80 LastFrameCounter = FrameCounter;
89 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP &&
90 gfx.final_screen_bitmap != NULL) // may not be initialized yet
92 // draw global animations using bitmaps instead of using textures
93 // to prevent texture scaling artefacts (this is potentially slower)
95 BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0,
96 gfx.win_xsize, gfx.win_ysize, 0, 0);
100 screen = gfx.final_screen_bitmap->surface;
102 // force full window redraw
106 #if defined(TARGET_SDL2)
107 SDL_Texture *sdl_texture = sdl_texture_stream;
109 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET)
110 sdl_texture = sdl_texture_target;
114 int bytes_x = screen->pitch / video.width;
115 int bytes_y = screen->pitch;
117 SDL_UpdateTexture(sdl_texture, rect,
118 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
123 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
126 // clear render target buffer
127 SDL_RenderClear(sdl_renderer);
129 // set renderer to use target texture for rendering
130 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
131 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
132 SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
134 // copy backbuffer texture to render target buffer
135 if (video.screen_rendering_mode != SPECIAL_RENDERING_TARGET)
136 SDL_RenderCopy(sdl_renderer, sdl_texture_stream, NULL, NULL);
138 if (video.screen_rendering_mode != SPECIAL_RENDERING_BITMAP)
141 // when using target texture, copy it to screen buffer
142 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
143 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
145 SDL_SetRenderTarget(sdl_renderer, NULL);
146 SDL_RenderCopy(sdl_renderer, sdl_texture_target, NULL, NULL);
149 // show render target buffer on screen
150 SDL_RenderPresent(sdl_renderer);
154 SDL_UpdateRects(screen, 1, rect);
156 SDL_UpdateRect(screen, 0, 0, 0, 0);
160 static void SDLSetWindowIcon(char *basename)
162 /* (setting the window icon on Mac OS X would replace the high-quality
163 dock icon with the currently smaller (and uglier) icon from file) */
165 #if !defined(PLATFORM_MACOSX)
166 char *filename = getCustomImageFilename(basename);
167 SDL_Surface *surface;
169 if (filename == NULL)
171 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
176 if ((surface = IMG_Load(filename)) == NULL)
178 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
183 /* set transparent color */
184 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
185 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
187 #if defined(TARGET_SDL2)
188 SDL_SetWindowIcon(sdl_window, surface);
190 SDL_WM_SetIcon(surface, NULL);
195 #if defined(TARGET_SDL2)
197 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
198 SDL_PixelFormat *format2)
200 return (format1->format == format2->format &&
201 format1->BitsPerPixel == format2->BitsPerPixel &&
202 format1->BytesPerPixel == format2->BytesPerPixel &&
203 format1->Rmask == format2->Rmask &&
204 format1->Gmask == format2->Gmask &&
205 format1->Bmask == format2->Bmask &&
206 format1->Amask == format2->Amask);
209 boolean SDLSetNativeSurface(SDL_Surface **surface)
211 SDL_Surface *new_surface;
213 if (surface == NULL ||
215 backbuffer == NULL ||
216 backbuffer->surface == NULL)
219 // if pixel format already optimized for destination surface, do nothing
220 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
223 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
225 if (new_surface == NULL)
226 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
228 SDL_FreeSurface(*surface);
230 *surface = new_surface;
235 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
237 SDL_PixelFormat format;
238 SDL_Surface *new_surface;
243 if (backbuffer && backbuffer->surface)
245 format = *backbuffer->surface->format;
246 format.Amask = surface->format->Amask; // keep alpha channel
250 format = *surface->format;
253 new_surface = SDL_ConvertSurface(surface, &format, 0);
255 if (new_surface == NULL)
256 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
263 boolean SDLSetNativeSurface(SDL_Surface **surface)
265 SDL_Surface *new_surface;
267 if (surface == NULL ||
272 new_surface = SDL_DisplayFormat(*surface);
274 if (new_surface == NULL)
275 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
277 SDL_FreeSurface(*surface);
279 *surface = new_surface;
284 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
286 SDL_Surface *new_surface;
288 if (video.initialized)
289 new_surface = SDL_DisplayFormat(surface);
291 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
293 if (new_surface == NULL)
294 Error(ERR_EXIT, "%s() failed: %s",
295 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
303 #if defined(TARGET_SDL2)
304 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
306 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
309 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
316 void SDLCreateBitmapTextures(Bitmap *bitmap)
318 #if defined(TARGET_SDL2)
323 SDL_DestroyTexture(bitmap->texture);
324 if (bitmap->texture_masked)
325 SDL_DestroyTexture(bitmap->texture_masked);
327 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
328 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
332 void SDLFreeBitmapTextures(Bitmap *bitmap)
334 #if defined(TARGET_SDL2)
339 SDL_DestroyTexture(bitmap->texture);
340 if (bitmap->texture_masked)
341 SDL_DestroyTexture(bitmap->texture_masked);
343 bitmap->texture = NULL;
344 bitmap->texture_masked = NULL;
348 void SDLInitVideoDisplay(void)
350 #if !defined(TARGET_SDL2)
351 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
352 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
354 SDL_putenv("SDL_VIDEO_CENTERED=1");
357 /* initialize SDL video */
358 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
359 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
361 /* set default SDL depth */
362 #if !defined(TARGET_SDL2)
363 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
365 video.default_depth = 32; // (how to determine video depth in SDL2?)
369 void SDLInitVideoBuffer(boolean fullscreen)
371 video.window_scaling_percent = setup.window_scaling_percent;
372 video.window_scaling_quality = setup.window_scaling_quality;
373 video.screen_rendering_mode =
374 (strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
375 SPECIAL_RENDERING_BITMAP :
376 strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
377 SPECIAL_RENDERING_TARGET:
378 strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
379 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
381 #if defined(TARGET_SDL2)
382 // SDL 2.0: support for (desktop) fullscreen mode available
383 video.fullscreen_available = TRUE;
385 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
386 video.fullscreen_available = FALSE;
389 /* open SDL video output device (window or fullscreen mode) */
390 if (!SDLSetVideoMode(fullscreen))
391 Error(ERR_EXIT, "setting video mode failed");
393 /* !!! SDL2 can only set the window icon if the window already exists !!! */
394 /* set window icon */
395 SDLSetWindowIcon(program.icon_filename);
397 /* set window and icon title */
398 #if defined(TARGET_SDL2)
399 SDL_SetWindowTitle(sdl_window, program.window_title);
401 SDL_WM_SetCaption(program.window_title, program.window_title);
404 /* SDL cannot directly draw to the visible video framebuffer like X11,
405 but always uses a backbuffer, which is then blitted to the visible
406 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
407 visible video framebuffer with 'SDL_Flip', if the hardware supports
408 this). Therefore do not use an additional backbuffer for drawing, but
409 use a symbolic buffer (distinguishable from the SDL backbuffer) called
410 'window', which indicates that the SDL backbuffer should be updated to
411 the visible video framebuffer when attempting to blit to it.
413 For convenience, it seems to be a good idea to create this symbolic
414 buffer 'window' at the same size as the SDL backbuffer. Although it
415 should never be drawn to directly, it would do no harm nevertheless. */
417 /* create additional (symbolic) buffer for double-buffering */
418 ReCreateBitmap(&window, video.width, video.height, video.depth);
421 static boolean SDLCreateScreen(boolean fullscreen)
423 SDL_Surface *new_surface = NULL;
425 #if defined(TARGET_SDL2)
426 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
427 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
429 int surface_flags_window = SURFACE_FLAGS;
430 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
433 int width = video.width;
434 int height = video.height;
435 int surface_flags = (fullscreen ? surface_flags_fullscreen :
436 surface_flags_window);
438 // default window size is unscaled
439 video.window_width = video.width;
440 video.window_height = video.height;
442 #if defined(TARGET_SDL2)
444 // store if initial screen mode is fullscreen mode when changing screen size
445 video.fullscreen_initial = fullscreen;
447 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
449 video.window_width = window_scaling_factor * width;
450 video.window_height = window_scaling_factor * height;
452 if (sdl_texture_stream)
454 SDL_DestroyTexture(sdl_texture_stream);
455 sdl_texture_stream = NULL;
458 if (sdl_texture_target)
460 SDL_DestroyTexture(sdl_texture_target);
461 sdl_texture_target = NULL;
464 if (!(fullscreen && fullscreen_enabled))
468 SDL_DestroyRenderer(sdl_renderer);
474 SDL_DestroyWindow(sdl_window);
479 if (sdl_window == NULL)
480 sdl_window = SDL_CreateWindow(program.window_title,
481 SDL_WINDOWPOS_CENTERED,
482 SDL_WINDOWPOS_CENTERED,
487 if (sdl_window != NULL)
490 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
491 *without* enabling 2D/3D acceleration and/or guest additions installed,
492 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
493 it will try to use accelerated graphics and apparently fails miserably) */
494 if (sdl_renderer == NULL)
495 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
497 if (sdl_renderer == NULL)
498 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
501 if (sdl_renderer != NULL)
503 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
504 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
505 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
507 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
508 SDL_PIXELFORMAT_ARGB8888,
509 SDL_TEXTUREACCESS_STREAMING,
512 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
513 SDL_PIXELFORMAT_ARGB8888,
514 SDL_TEXTUREACCESS_TARGET,
517 if (sdl_texture_stream != NULL &&
518 sdl_texture_target != NULL)
520 // use SDL default values for RGB masks and no alpha channel
521 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
523 if (new_surface == NULL)
524 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
528 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
533 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
538 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
543 if (gfx.final_screen_bitmap == NULL)
544 gfx.final_screen_bitmap = CreateBitmapStruct();
546 gfx.final_screen_bitmap->width = width;
547 gfx.final_screen_bitmap->height = height;
549 gfx.final_screen_bitmap->surface =
550 SDL_SetVideoMode(width, height, video.depth, surface_flags);
552 if (gfx.final_screen_bitmap->surface != NULL)
555 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
557 if (new_surface == NULL)
558 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
561 new_surface = gfx.final_screen_bitmap->surface;
562 gfx.final_screen_bitmap = NULL;
568 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
572 #if defined(TARGET_SDL2)
573 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
574 if (new_surface != NULL)
575 fullscreen_enabled = fullscreen;
578 if (backbuffer == NULL)
579 backbuffer = CreateBitmapStruct();
581 backbuffer->width = video.width;
582 backbuffer->height = video.height;
584 if (backbuffer->surface)
585 SDL_FreeSurface(backbuffer->surface);
587 backbuffer->surface = new_surface;
589 return (new_surface != NULL);
592 boolean SDLSetVideoMode(boolean fullscreen)
594 boolean success = FALSE;
598 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
600 /* switch display to fullscreen mode, if available */
601 success = SDLCreateScreen(TRUE);
605 /* switching display to fullscreen mode failed -- do not try it again */
606 video.fullscreen_available = FALSE;
610 video.fullscreen_enabled = TRUE;
614 if ((!fullscreen && video.fullscreen_enabled) || !success)
616 /* switch display to window mode */
617 success = SDLCreateScreen(FALSE);
621 /* switching display to window mode failed -- should not happen */
625 video.fullscreen_enabled = FALSE;
626 video.window_scaling_percent = setup.window_scaling_percent;
627 video.window_scaling_quality = setup.window_scaling_quality;
628 video.screen_rendering_mode =
629 (strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
630 SPECIAL_RENDERING_BITMAP :
631 strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
632 SPECIAL_RENDERING_TARGET:
633 strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
634 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
638 #if defined(TARGET_SDL2)
639 SDLRedrawWindow(); // map window
643 #if defined(PLATFORM_WIN32)
644 // experimental drag and drop code
646 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
649 SDL_SysWMinfo wminfo;
651 boolean wminfo_success = FALSE;
653 SDL_VERSION(&wminfo.version);
654 #if defined(TARGET_SDL2)
656 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
658 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
663 #if defined(TARGET_SDL2)
664 hwnd = wminfo.info.win.window;
666 hwnd = wminfo.window;
669 DragAcceptFiles(hwnd, TRUE);
678 void SDLSetWindowTitle()
680 #if defined(TARGET_SDL2)
681 SDL_SetWindowTitle(sdl_window, program.window_title);
683 SDL_WM_SetCaption(program.window_title, program.window_title);
687 #if defined(TARGET_SDL2)
688 void SDLSetWindowScaling(int window_scaling_percent)
690 if (sdl_window == NULL)
693 float window_scaling_factor = (float)window_scaling_percent / 100;
694 int new_window_width = (int)(window_scaling_factor * video.width);
695 int new_window_height = (int)(window_scaling_factor * video.height);
697 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
699 video.window_scaling_percent = window_scaling_percent;
700 video.window_width = new_window_width;
701 video.window_height = new_window_height;
706 void SDLSetWindowScalingQuality(char *window_scaling_quality)
708 SDL_Texture *new_texture;
710 if (sdl_texture_stream == NULL ||
711 sdl_texture_target == NULL)
714 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
716 new_texture = SDL_CreateTexture(sdl_renderer,
717 SDL_PIXELFORMAT_ARGB8888,
718 SDL_TEXTUREACCESS_STREAMING,
719 video.width, video.height);
721 if (new_texture != NULL)
723 SDL_DestroyTexture(sdl_texture_stream);
725 sdl_texture_stream = new_texture;
728 new_texture = SDL_CreateTexture(sdl_renderer,
729 SDL_PIXELFORMAT_ARGB8888,
730 SDL_TEXTUREACCESS_TARGET,
731 video.width, video.height);
733 if (new_texture != NULL)
735 SDL_DestroyTexture(sdl_texture_target);
737 sdl_texture_target = new_texture;
742 video.window_scaling_quality = window_scaling_quality;
745 void SDLSetScreenRenderingMode(char *screen_rendering_mode)
747 video.screen_rendering_mode =
748 (strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
749 SPECIAL_RENDERING_BITMAP :
750 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
751 SPECIAL_RENDERING_TARGET:
752 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
753 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
756 void SDLSetWindowFullscreen(boolean fullscreen)
758 if (sdl_window == NULL)
761 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
763 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
764 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
766 // if screen size was changed in fullscreen mode, correct desktop window size
767 if (!fullscreen && video.fullscreen_initial)
769 SDLSetWindowScaling(setup.window_scaling_percent);
770 SDL_SetWindowPosition(sdl_window,
771 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
773 video.fullscreen_initial = FALSE;
777 void SDLRedrawWindow()
783 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
786 SDL_Surface *surface =
787 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
790 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
792 SDLSetNativeSurface(&surface);
794 bitmap->surface = surface;
797 void SDLFreeBitmapPointers(Bitmap *bitmap)
800 SDL_FreeSurface(bitmap->surface);
801 if (bitmap->surface_masked)
802 SDL_FreeSurface(bitmap->surface_masked);
804 bitmap->surface = NULL;
805 bitmap->surface_masked = NULL;
807 #if defined(TARGET_SDL2)
809 SDL_DestroyTexture(bitmap->texture);
810 if (bitmap->texture_masked)
811 SDL_DestroyTexture(bitmap->texture_masked);
813 bitmap->texture = NULL;
814 bitmap->texture_masked = NULL;
818 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
819 int src_x, int src_y, int width, int height,
820 int dst_x, int dst_y, int mask_mode)
822 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
823 SDL_Rect src_rect, dst_rect;
835 // if (src_bitmap != backbuffer || dst_bitmap != window)
836 if (!(src_bitmap == backbuffer && dst_bitmap == window))
837 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
838 src_bitmap->surface_masked : src_bitmap->surface),
839 &src_rect, real_dst_bitmap->surface, &dst_rect);
841 if (dst_bitmap == window)
842 UpdateScreen(&dst_rect);
845 void SDLBlitTexture(Bitmap *bitmap,
846 int src_x, int src_y, int width, int height,
847 int dst_x, int dst_y, int mask_mode)
849 #if defined(TARGET_SDL2)
850 SDL_Texture *texture;
855 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
870 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
874 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
877 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
885 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
887 if (dst_bitmap == window)
891 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
892 int fade_mode, int fade_delay, int post_delay,
893 void (*draw_border_function)(void))
895 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
896 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
897 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
898 SDL_Surface *surface_screen = backbuffer->surface;
899 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
900 SDL_Rect src_rect, dst_rect;
902 int src_x = x, src_y = y;
903 int dst_x = x, dst_y = y;
904 unsigned int time_last, time_current;
906 // store function for drawing global masked border
907 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
909 // deactivate drawing of global border while fading, if needed
910 if (draw_border_function == NULL)
911 gfx.draw_global_border_function = NULL;
920 dst_rect.w = width; /* (ignored) */
921 dst_rect.h = height; /* (ignored) */
923 dst_rect2 = dst_rect;
925 /* copy source and target surfaces to temporary surfaces for fading */
926 if (fade_mode & FADE_TYPE_TRANSFORM)
928 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
929 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
931 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
932 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
934 else if (fade_mode & FADE_TYPE_FADE_IN)
936 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
937 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
939 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
941 else /* FADE_TYPE_FADE_OUT */
943 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
944 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
946 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
949 time_current = SDL_GetTicks();
951 if (fade_mode == FADE_MODE_MELT)
953 boolean done = FALSE;
955 int melt_columns = width / melt_pixels;
956 int ypos[melt_columns];
957 int max_steps = height / 8 + 32;
962 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
963 #if defined(TARGET_SDL2)
964 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
966 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
969 ypos[0] = -GetSimpleRandom(16);
971 for (i = 1 ; i < melt_columns; i++)
973 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
975 ypos[i] = ypos[i - 1] + r;
988 time_last = time_current;
989 time_current = SDL_GetTicks();
990 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
991 steps_final = MIN(MAX(0, steps), max_steps);
995 done = (steps_done >= steps_final);
997 for (i = 0 ; i < melt_columns; i++)
1005 else if (ypos[i] < height)
1010 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1012 if (ypos[i] + dy >= height)
1013 dy = height - ypos[i];
1015 /* copy part of (appearing) target surface to upper area */
1016 src_rect.x = src_x + i * melt_pixels;
1017 // src_rect.y = src_y + ypos[i];
1019 src_rect.w = melt_pixels;
1021 src_rect.h = ypos[i] + dy;
1023 dst_rect.x = dst_x + i * melt_pixels;
1024 // dst_rect.y = dst_y + ypos[i];
1027 if (steps_done >= steps_final)
1028 SDL_BlitSurface(surface_target, &src_rect,
1029 surface_screen, &dst_rect);
1033 /* copy part of (disappearing) source surface to lower area */
1034 src_rect.x = src_x + i * melt_pixels;
1036 src_rect.w = melt_pixels;
1037 src_rect.h = height - ypos[i];
1039 dst_rect.x = dst_x + i * melt_pixels;
1040 dst_rect.y = dst_y + ypos[i];
1042 if (steps_done >= steps_final)
1043 SDL_BlitSurface(surface_source, &src_rect,
1044 surface_screen, &dst_rect);
1050 src_rect.x = src_x + i * melt_pixels;
1052 src_rect.w = melt_pixels;
1053 src_rect.h = height;
1055 dst_rect.x = dst_x + i * melt_pixels;
1058 if (steps_done >= steps_final)
1059 SDL_BlitSurface(surface_target, &src_rect,
1060 surface_screen, &dst_rect);
1064 if (steps_done >= steps_final)
1066 if (draw_border_function != NULL)
1067 draw_border_function();
1069 UpdateScreen(&dst_rect2);
1073 else if (fade_mode == FADE_MODE_CURTAIN)
1077 int xx_size = width / 2;
1079 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1080 #if defined(TARGET_SDL2)
1081 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1083 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1086 for (xx = 0; xx < xx_size;)
1088 time_last = time_current;
1089 time_current = SDL_GetTicks();
1090 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1091 xx_final = MIN(MAX(0, xx), xx_size);
1096 src_rect.h = height;
1101 /* draw new (target) image to screen buffer */
1102 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1104 if (xx_final < xx_size)
1106 src_rect.w = xx_size - xx_final;
1107 src_rect.h = height;
1109 /* draw old (source) image to screen buffer (left side) */
1111 src_rect.x = src_x + xx_final;
1114 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1116 /* draw old (source) image to screen buffer (right side) */
1118 src_rect.x = src_x + xx_size;
1119 dst_rect.x = dst_x + xx_size + xx_final;
1121 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1124 if (draw_border_function != NULL)
1125 draw_border_function();
1127 /* only update the region of the screen that is affected from fading */
1128 UpdateScreen(&dst_rect2);
1131 else /* fading in, fading out or cross-fading */
1136 for (alpha = 0.0; alpha < 255.0;)
1138 time_last = time_current;
1139 time_current = SDL_GetTicks();
1140 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1141 alpha_final = MIN(MAX(0, alpha), 255);
1143 /* draw existing (source) image to screen buffer */
1144 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1146 /* draw new (target) image to screen buffer using alpha blending */
1147 #if defined(TARGET_SDL2)
1148 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1149 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1151 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1153 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1155 if (draw_border_function != NULL)
1156 draw_border_function();
1158 /* only update the region of the screen that is affected from fading */
1159 UpdateScreen(&dst_rect);
1165 unsigned int time_post_delay;
1167 time_current = SDL_GetTicks();
1168 time_post_delay = time_current + post_delay;
1170 while (time_current < time_post_delay)
1172 // do not wait longer than 10 ms at a time to be able to ...
1173 Delay(MIN(10, time_post_delay - time_current));
1175 // ... continue drawing global animations during post delay
1178 time_current = SDL_GetTicks();
1182 // restore function for drawing global masked border
1183 gfx.draw_global_border_function = draw_global_border_function;
1186 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1187 int to_x, int to_y, Uint32 color)
1189 SDL_Surface *surface = dst_bitmap->surface;
1193 swap_numbers(&from_x, &to_x);
1196 swap_numbers(&from_y, &to_y);
1200 rect.w = (to_x - from_x + 1);
1201 rect.h = (to_y - from_y + 1);
1203 SDL_FillRect(surface, &rect, color);
1206 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1207 int to_x, int to_y, Uint32 color)
1209 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1212 #if ENABLE_UNUSED_CODE
1213 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1214 int num_points, Uint32 color)
1219 for (i = 0; i < num_points - 1; i++)
1221 for (x = 0; x < line_width; x++)
1223 for (y = 0; y < line_width; y++)
1225 int dx = x - line_width / 2;
1226 int dy = y - line_width / 2;
1228 if ((x == 0 && y == 0) ||
1229 (x == 0 && y == line_width - 1) ||
1230 (x == line_width - 1 && y == 0) ||
1231 (x == line_width - 1 && y == line_width - 1))
1234 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1235 points[i+1].x + dx, points[i+1].y + dy, color);
1242 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1244 SDL_Surface *surface = src_bitmap->surface;
1246 switch (surface->format->BytesPerPixel)
1248 case 1: /* assuming 8-bpp */
1250 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1254 case 2: /* probably 15-bpp or 16-bpp */
1256 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1260 case 3: /* slow 24-bpp mode; usually not used */
1262 /* does this work? */
1263 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1267 shift = surface->format->Rshift;
1268 color |= *(pix + shift / 8) >> shift;
1269 shift = surface->format->Gshift;
1270 color |= *(pix + shift / 8) >> shift;
1271 shift = surface->format->Bshift;
1272 color |= *(pix + shift / 8) >> shift;
1278 case 4: /* probably 32-bpp */
1280 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1289 /* ========================================================================= */
1290 /* The following functions were taken from the SGE library */
1291 /* (SDL Graphics Extension Library) by Anders Lindström */
1292 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1293 /* ========================================================================= */
1295 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1297 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1299 switch (surface->format->BytesPerPixel)
1303 /* Assuming 8-bpp */
1304 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1310 /* Probably 15-bpp or 16-bpp */
1311 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1317 /* Slow 24-bpp mode, usually not used */
1321 /* Gack - slow, but endian correct */
1322 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1323 shift = surface->format->Rshift;
1324 *(pix+shift/8) = color>>shift;
1325 shift = surface->format->Gshift;
1326 *(pix+shift/8) = color>>shift;
1327 shift = surface->format->Bshift;
1328 *(pix+shift/8) = color>>shift;
1334 /* Probably 32-bpp */
1335 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1342 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1343 Uint8 R, Uint8 G, Uint8 B)
1345 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1348 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1350 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1353 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1355 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1358 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1363 /* Gack - slow, but endian correct */
1364 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1365 shift = surface->format->Rshift;
1366 *(pix+shift/8) = color>>shift;
1367 shift = surface->format->Gshift;
1368 *(pix+shift/8) = color>>shift;
1369 shift = surface->format->Bshift;
1370 *(pix+shift/8) = color>>shift;
1373 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1375 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1378 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1380 switch (dest->format->BytesPerPixel)
1383 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1387 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1391 _PutPixel24(dest,x,y,color);
1395 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1400 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1402 if (SDL_MUSTLOCK(surface))
1404 if (SDL_LockSurface(surface) < 0)
1410 _PutPixel(surface, x, y, color);
1412 if (SDL_MUSTLOCK(surface))
1414 SDL_UnlockSurface(surface);
1418 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1419 Uint8 r, Uint8 g, Uint8 b)
1421 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1424 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1426 if (y >= 0 && y <= dest->h - 1)
1428 switch (dest->format->BytesPerPixel)
1431 return y*dest->pitch;
1435 return y*dest->pitch/2;
1439 return y*dest->pitch;
1443 return y*dest->pitch/4;
1451 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1453 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1455 switch (surface->format->BytesPerPixel)
1459 /* Assuming 8-bpp */
1460 *((Uint8 *)surface->pixels + ypitch + x) = color;
1466 /* Probably 15-bpp or 16-bpp */
1467 *((Uint16 *)surface->pixels + ypitch + x) = color;
1473 /* Slow 24-bpp mode, usually not used */
1477 /* Gack - slow, but endian correct */
1478 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1479 shift = surface->format->Rshift;
1480 *(pix+shift/8) = color>>shift;
1481 shift = surface->format->Gshift;
1482 *(pix+shift/8) = color>>shift;
1483 shift = surface->format->Bshift;
1484 *(pix+shift/8) = color>>shift;
1490 /* Probably 32-bpp */
1491 *((Uint32 *)surface->pixels + ypitch + x) = color;
1498 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1503 if (SDL_MUSTLOCK(Surface))
1505 if (SDL_LockSurface(Surface) < 0)
1518 /* Do the clipping */
1519 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1523 if (x2 > Surface->w - 1)
1524 x2 = Surface->w - 1;
1531 SDL_FillRect(Surface, &l, Color);
1533 if (SDL_MUSTLOCK(Surface))
1535 SDL_UnlockSurface(Surface);
1539 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1540 Uint8 R, Uint8 G, Uint8 B)
1542 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1545 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
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);
1572 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1577 if (SDL_MUSTLOCK(Surface))
1579 if (SDL_LockSurface(Surface) < 0)
1592 /* Do the clipping */
1593 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1597 if (y2 > Surface->h - 1)
1598 y2 = Surface->h - 1;
1605 SDL_FillRect(Surface, &l, Color);
1607 if (SDL_MUSTLOCK(Surface))
1609 SDL_UnlockSurface(Surface);
1613 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1614 Uint8 R, Uint8 G, Uint8 B)
1616 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1619 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
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);
1646 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1647 Sint16 x2, Sint16 y2, Uint32 Color,
1648 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1651 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1656 sdx = (dx < 0) ? -1 : 1;
1657 sdy = (dy < 0) ? -1 : 1;
1669 for (x = 0; x < dx; x++)
1671 Callback(Surface, px, py, Color);
1685 for (y = 0; y < dy; y++)
1687 Callback(Surface, px, py, Color);
1701 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1702 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1703 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1706 sge_DoLine(Surface, X1, Y1, X2, Y2,
1707 SDL_MapRGB(Surface->format, R, G, B), Callback);
1710 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1713 if (SDL_MUSTLOCK(Surface))
1715 if (SDL_LockSurface(Surface) < 0)
1720 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1722 /* unlock the display */
1723 if (SDL_MUSTLOCK(Surface))
1725 SDL_UnlockSurface(Surface);
1729 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1730 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1732 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1735 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1737 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1742 -----------------------------------------------------------------------------
1743 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1744 -----------------------------------------------------------------------------
1747 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1748 int width, int height, Uint32 color)
1752 for (y = src_y; y < src_y + height; y++)
1754 for (x = src_x; x < src_x + width; x++)
1756 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1758 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1763 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1764 int src_x, int src_y, int width, int height,
1765 int dst_x, int dst_y)
1769 for (y = 0; y < height; y++)
1771 for (x = 0; x < width; x++)
1773 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1775 if (pixel != BLACK_PIXEL)
1776 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1782 /* ========================================================================= */
1783 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1784 /* (Rotozoomer) by Andreas Schiffler */
1785 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1786 /* ========================================================================= */
1789 -----------------------------------------------------------------------------
1792 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1793 -----------------------------------------------------------------------------
1804 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1807 tColorRGBA *sp, *csp, *dp;
1811 sp = csp = (tColorRGBA *) src->pixels;
1812 dp = (tColorRGBA *) dst->pixels;
1813 dgap = dst->pitch - dst->w * 4;
1815 for (y = 0; y < dst->h; y++)
1819 for (x = 0; x < dst->w; x++)
1821 tColorRGBA *sp0 = sp;
1822 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1823 tColorRGBA *sp00 = &sp0[0];
1824 tColorRGBA *sp01 = &sp0[1];
1825 tColorRGBA *sp10 = &sp1[0];
1826 tColorRGBA *sp11 = &sp1[1];
1829 /* create new color pixel from all four source color pixels */
1830 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1831 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1832 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1833 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1838 /* advance source pointers */
1841 /* advance destination pointer */
1845 /* advance source pointer */
1846 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1848 /* advance destination pointers */
1849 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1855 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1857 int x, y, *sax, *say, *csax, *csay;
1859 tColorRGBA *sp, *csp, *csp0, *dp;
1862 /* use specialized zoom function when scaling down to exactly half size */
1863 if (src->w == 2 * dst->w &&
1864 src->h == 2 * dst->h)
1865 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1867 /* variable setup */
1868 sx = (float) src->w / (float) dst->w;
1869 sy = (float) src->h / (float) dst->h;
1871 /* allocate memory for row increments */
1872 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1873 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1875 /* precalculate row increments */
1876 for (x = 0; x <= dst->w; x++)
1877 *csax++ = (int)(sx * x);
1879 for (y = 0; y <= dst->h; y++)
1880 *csay++ = (int)(sy * y);
1883 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1884 dp = (tColorRGBA *) dst->pixels;
1885 dgap = dst->pitch - dst->w * 4;
1888 for (y = 0; y < dst->h; y++)
1893 for (x = 0; x < dst->w; x++)
1898 /* advance source pointers */
1902 /* advance destination pointer */
1906 /* advance source pointer */
1908 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1910 /* advance destination pointers */
1911 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1921 -----------------------------------------------------------------------------
1924 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1925 -----------------------------------------------------------------------------
1928 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1930 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1931 Uint8 *sp, *dp, *csp;
1934 /* variable setup */
1935 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1936 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1938 /* allocate memory for row increments */
1939 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1940 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1942 /* precalculate row increments */
1945 for (x = 0; x < dst->w; x++)
1948 *csax = (csx >> 16);
1955 for (y = 0; y < dst->h; y++)
1958 *csay = (csy >> 16);
1965 for (x = 0; x < dst->w; x++)
1973 for (y = 0; y < dst->h; y++)
1980 sp = csp = (Uint8 *) src->pixels;
1981 dp = (Uint8 *) dst->pixels;
1982 dgap = dst->pitch - dst->w;
1986 for (y = 0; y < dst->h; y++)
1990 for (x = 0; x < dst->w; x++)
1995 /* advance source pointers */
1999 /* advance destination pointer */
2003 /* advance source pointer (for row) */
2004 csp += ((*csay) * src->pitch);
2007 /* advance destination pointers */
2018 -----------------------------------------------------------------------------
2021 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2022 'zoomx' and 'zoomy' are scaling factors for width and height.
2023 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2024 into a 32bit RGBA format on the fly.
2025 -----------------------------------------------------------------------------
2028 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2030 SDL_Surface *zoom_src = NULL;
2031 SDL_Surface *zoom_dst = NULL;
2032 boolean is_converted = FALSE;
2039 /* determine if source surface is 32 bit or 8 bit */
2040 is_32bit = (src->format->BitsPerPixel == 32);
2042 if (is_32bit || src->format->BitsPerPixel == 8)
2044 /* use source surface 'as is' */
2049 /* new source surface is 32 bit with a defined RGB ordering */
2050 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2051 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2052 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2054 is_converted = TRUE;
2057 /* allocate surface to completely contain the zoomed surface */
2060 /* target surface is 32 bit with source RGBA/ABGR ordering */
2061 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2062 zoom_src->format->Rmask,
2063 zoom_src->format->Gmask,
2064 zoom_src->format->Bmask, 0);
2068 /* target surface is 8 bit */
2069 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2073 /* lock source surface */
2074 SDL_LockSurface(zoom_src);
2076 /* check which kind of surface we have */
2079 /* call the 32 bit transformation routine to do the zooming */
2080 zoomSurfaceRGBA(zoom_src, zoom_dst);
2085 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2086 zoom_dst->format->palette->colors[i] =
2087 zoom_src->format->palette->colors[i];
2088 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2090 /* call the 8 bit transformation routine to do the zooming */
2091 zoomSurfaceY(zoom_src, zoom_dst);
2094 /* unlock source surface */
2095 SDL_UnlockSurface(zoom_src);
2097 /* free temporary surface */
2099 SDL_FreeSurface(zoom_src);
2101 /* return destination surface */
2105 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2107 Bitmap *dst_bitmap = CreateBitmapStruct();
2108 SDL_Surface **dst_surface = &dst_bitmap->surface;
2110 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2111 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2113 dst_bitmap->width = dst_width;
2114 dst_bitmap->height = dst_height;
2116 /* create zoomed temporary surface from source surface */
2117 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2119 /* create native format destination surface from zoomed temporary surface */
2120 SDLSetNativeSurface(dst_surface);
2126 /* ========================================================================= */
2127 /* load image to bitmap */
2128 /* ========================================================================= */
2130 Bitmap *SDLLoadImage(char *filename)
2132 Bitmap *new_bitmap = CreateBitmapStruct();
2133 SDL_Surface *sdl_image_tmp;
2135 print_timestamp_init("SDLLoadImage");
2137 print_timestamp_time(getBaseNamePtr(filename));
2139 /* load image to temporary surface */
2140 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2142 SetError("IMG_Load(): %s", SDL_GetError());
2147 print_timestamp_time("IMG_Load");
2149 UPDATE_BUSY_STATE();
2151 /* create native non-transparent surface for current image */
2152 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2154 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2159 print_timestamp_time("SDL_DisplayFormat (opaque)");
2161 UPDATE_BUSY_STATE();
2163 /* create native transparent surface for current image */
2164 if (sdl_image_tmp->format->Amask == 0)
2165 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2166 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2168 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2170 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2175 print_timestamp_time("SDL_DisplayFormat (masked)");
2177 UPDATE_BUSY_STATE();
2179 /* free temporary surface */
2180 SDL_FreeSurface(sdl_image_tmp);
2182 new_bitmap->width = new_bitmap->surface->w;
2183 new_bitmap->height = new_bitmap->surface->h;
2185 print_timestamp_done("SDLLoadImage");
2191 /* ------------------------------------------------------------------------- */
2192 /* custom cursor fuctions */
2193 /* ------------------------------------------------------------------------- */
2195 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2197 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2198 cursor_info->width, cursor_info->height,
2199 cursor_info->hot_x, cursor_info->hot_y);
2202 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2204 static struct MouseCursorInfo *last_cursor_info = NULL;
2205 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2206 static SDL_Cursor *cursor_default = NULL;
2207 static SDL_Cursor *cursor_current = NULL;
2209 /* if invoked for the first time, store the SDL default cursor */
2210 if (cursor_default == NULL)
2211 cursor_default = SDL_GetCursor();
2213 /* only create new cursor if cursor info (custom only) has changed */
2214 if (cursor_info != NULL && cursor_info != last_cursor_info)
2216 cursor_current = create_cursor(cursor_info);
2217 last_cursor_info = cursor_info;
2220 /* only set new cursor if cursor info (custom or NULL) has changed */
2221 if (cursor_info != last_cursor_info2)
2222 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2224 last_cursor_info2 = cursor_info;
2228 /* ========================================================================= */
2229 /* audio functions */
2230 /* ========================================================================= */
2232 void SDLOpenAudio(void)
2234 #if !defined(TARGET_SDL2)
2235 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2236 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2239 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2241 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2245 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2246 AUDIO_NUM_CHANNELS_STEREO,
2247 setup.system.audio_fragment_size) < 0)
2249 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2253 audio.sound_available = TRUE;
2254 audio.music_available = TRUE;
2255 audio.loops_available = TRUE;
2256 audio.sound_enabled = TRUE;
2258 /* set number of available mixer channels */
2259 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2260 audio.music_channel = MUSIC_CHANNEL;
2261 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2263 Mixer_InitChannels();
2266 void SDLCloseAudio(void)
2269 Mix_HaltChannel(-1);
2272 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2276 /* ========================================================================= */
2277 /* event functions */
2278 /* ========================================================================= */
2280 void SDLNextEvent(Event *event)
2282 SDL_WaitEvent(event);
2285 void SDLHandleWindowManagerEvent(Event *event)
2288 #if defined(PLATFORM_WIN32)
2289 // experimental drag and drop code
2291 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2292 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2294 #if defined(TARGET_SDL2)
2295 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2297 if (syswmmsg->msg == WM_DROPFILES)
2300 #if defined(TARGET_SDL2)
2301 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2303 HDROP hdrop = (HDROP)syswmmsg->wParam;
2307 printf("::: SDL_SYSWMEVENT:\n");
2309 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2311 for (i = 0; i < num_files; i++)
2313 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2314 char buffer[buffer_len + 1];
2316 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2318 printf("::: - '%s'\n", buffer);
2321 #if defined(TARGET_SDL2)
2322 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2324 DragFinish((HDROP)syswmmsg->wParam);
2332 /* ========================================================================= */
2333 /* joystick functions */
2334 /* ========================================================================= */
2336 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2337 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2338 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2340 static boolean SDLOpenJoystick(int nr)
2342 if (nr < 0 || nr > MAX_PLAYERS)
2345 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2348 static void SDLCloseJoystick(int nr)
2350 if (nr < 0 || nr > MAX_PLAYERS)
2353 SDL_JoystickClose(sdl_joystick[nr]);
2355 sdl_joystick[nr] = NULL;
2358 static boolean SDLCheckJoystickOpened(int nr)
2360 if (nr < 0 || nr > MAX_PLAYERS)
2363 #if defined(TARGET_SDL2)
2364 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2366 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2370 void HandleJoystickEvent(Event *event)
2374 case SDL_JOYAXISMOTION:
2375 if (event->jaxis.axis < 2)
2376 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2379 case SDL_JOYBUTTONDOWN:
2380 if (event->jbutton.button < 2)
2381 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2384 case SDL_JOYBUTTONUP:
2385 if (event->jbutton.button < 2)
2386 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2394 void SDLInitJoysticks()
2396 static boolean sdl_joystick_subsystem_initialized = FALSE;
2397 boolean print_warning = !sdl_joystick_subsystem_initialized;
2400 if (!sdl_joystick_subsystem_initialized)
2402 sdl_joystick_subsystem_initialized = TRUE;
2404 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2406 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2411 for (i = 0; i < MAX_PLAYERS; i++)
2413 /* get configured joystick for this player */
2414 char *device_name = setup.input[i].joy.device_name;
2415 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2417 if (joystick_nr >= SDL_NumJoysticks())
2419 if (setup.input[i].use_joystick && print_warning)
2420 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2425 /* misuse joystick file descriptor variable to store joystick number */
2426 joystick.fd[i] = joystick_nr;
2428 if (joystick_nr == -1)
2431 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2432 if (SDLCheckJoystickOpened(joystick_nr))
2433 SDLCloseJoystick(joystick_nr);
2435 if (!setup.input[i].use_joystick)
2438 if (!SDLOpenJoystick(joystick_nr))
2441 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2446 joystick.status = JOYSTICK_ACTIVATED;
2450 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2452 if (nr < 0 || nr >= MAX_PLAYERS)
2456 *x = sdl_js_axis[nr][0];
2458 *y = sdl_js_axis[nr][1];
2461 *b1 = sdl_js_button[nr][0];
2463 *b2 = sdl_js_button[nr][1];