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 UpdateScreenExt(SDL_Rect *rect, boolean with_frame_delay)
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);
150 // global synchronization point of the game to align video frame delay
151 if (with_frame_delay)
152 WaitUntilDelayReached(&video.frame_delay, video.frame_delay_value);
154 #if defined(TARGET_SDL2)
155 // show render target buffer on screen
156 SDL_RenderPresent(sdl_renderer);
159 SDL_UpdateRects(screen, 1, rect);
161 SDL_UpdateRect(screen, 0, 0, 0, 0);
165 static void UpdateScreen_WithFrameDelay(SDL_Rect *rect)
167 UpdateScreenExt(rect, TRUE);
170 static void UpdateScreen_WithoutFrameDelay(SDL_Rect *rect)
172 UpdateScreenExt(rect, FALSE);
175 static void SDLSetWindowIcon(char *basename)
177 /* (setting the window icon on Mac OS X would replace the high-quality
178 dock icon with the currently smaller (and uglier) icon from file) */
180 #if !defined(PLATFORM_MACOSX)
181 char *filename = getCustomImageFilename(basename);
182 SDL_Surface *surface;
184 if (filename == NULL)
186 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
191 if ((surface = IMG_Load(filename)) == NULL)
193 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
198 /* set transparent color */
199 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
200 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
202 #if defined(TARGET_SDL2)
203 SDL_SetWindowIcon(sdl_window, surface);
205 SDL_WM_SetIcon(surface, NULL);
210 #if defined(TARGET_SDL2)
212 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
213 SDL_PixelFormat *format2)
215 return (format1->format == format2->format &&
216 format1->BitsPerPixel == format2->BitsPerPixel &&
217 format1->BytesPerPixel == format2->BytesPerPixel &&
218 format1->Rmask == format2->Rmask &&
219 format1->Gmask == format2->Gmask &&
220 format1->Bmask == format2->Bmask &&
221 format1->Amask == format2->Amask);
224 boolean SDLSetNativeSurface(SDL_Surface **surface)
226 SDL_Surface *new_surface;
228 if (surface == NULL ||
230 backbuffer == NULL ||
231 backbuffer->surface == NULL)
234 // if pixel format already optimized for destination surface, do nothing
235 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
238 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
240 if (new_surface == NULL)
241 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
243 SDL_FreeSurface(*surface);
245 *surface = new_surface;
250 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
252 SDL_PixelFormat format;
253 SDL_Surface *new_surface;
258 if (backbuffer && backbuffer->surface)
260 format = *backbuffer->surface->format;
261 format.Amask = surface->format->Amask; // keep alpha channel
265 format = *surface->format;
268 new_surface = SDL_ConvertSurface(surface, &format, 0);
270 if (new_surface == NULL)
271 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
278 boolean SDLSetNativeSurface(SDL_Surface **surface)
280 SDL_Surface *new_surface;
282 if (surface == NULL ||
287 new_surface = SDL_DisplayFormat(*surface);
289 if (new_surface == NULL)
290 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
292 SDL_FreeSurface(*surface);
294 *surface = new_surface;
299 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
301 SDL_Surface *new_surface;
303 if (video.initialized)
304 new_surface = SDL_DisplayFormat(surface);
306 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
308 if (new_surface == NULL)
309 Error(ERR_EXIT, "%s() failed: %s",
310 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
318 #if defined(TARGET_SDL2)
319 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
321 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
324 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
331 void SDLCreateBitmapTextures(Bitmap *bitmap)
333 #if defined(TARGET_SDL2)
338 SDL_DestroyTexture(bitmap->texture);
339 if (bitmap->texture_masked)
340 SDL_DestroyTexture(bitmap->texture_masked);
342 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
343 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
347 void SDLFreeBitmapTextures(Bitmap *bitmap)
349 #if defined(TARGET_SDL2)
354 SDL_DestroyTexture(bitmap->texture);
355 if (bitmap->texture_masked)
356 SDL_DestroyTexture(bitmap->texture_masked);
358 bitmap->texture = NULL;
359 bitmap->texture_masked = NULL;
363 void SDLInitVideoDisplay(void)
365 #if !defined(TARGET_SDL2)
366 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
367 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
369 SDL_putenv("SDL_VIDEO_CENTERED=1");
372 /* initialize SDL video */
373 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
374 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
376 /* set default SDL depth */
377 #if !defined(TARGET_SDL2)
378 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
380 video.default_depth = 32; // (how to determine video depth in SDL2?)
384 void SDLInitVideoBuffer(boolean fullscreen)
386 video.window_scaling_percent = setup.window_scaling_percent;
387 video.window_scaling_quality = setup.window_scaling_quality;
388 video.screen_rendering_mode =
389 (strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
390 SPECIAL_RENDERING_BITMAP :
391 strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
392 SPECIAL_RENDERING_TARGET:
393 strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
394 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
396 #if defined(TARGET_SDL2)
397 // SDL 2.0: support for (desktop) fullscreen mode available
398 video.fullscreen_available = TRUE;
400 // SDL 1.2: no support for fullscreen mode in R'n'D anymore
401 video.fullscreen_available = FALSE;
404 /* open SDL video output device (window or fullscreen mode) */
405 if (!SDLSetVideoMode(fullscreen))
406 Error(ERR_EXIT, "setting video mode failed");
408 /* !!! SDL2 can only set the window icon if the window already exists !!! */
409 /* set window icon */
410 SDLSetWindowIcon(program.icon_filename);
412 /* set window and icon title */
413 #if defined(TARGET_SDL2)
414 SDL_SetWindowTitle(sdl_window, program.window_title);
416 SDL_WM_SetCaption(program.window_title, program.window_title);
419 /* SDL cannot directly draw to the visible video framebuffer like X11,
420 but always uses a backbuffer, which is then blitted to the visible
421 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
422 visible video framebuffer with 'SDL_Flip', if the hardware supports
423 this). Therefore do not use an additional backbuffer for drawing, but
424 use a symbolic buffer (distinguishable from the SDL backbuffer) called
425 'window', which indicates that the SDL backbuffer should be updated to
426 the visible video framebuffer when attempting to blit to it.
428 For convenience, it seems to be a good idea to create this symbolic
429 buffer 'window' at the same size as the SDL backbuffer. Although it
430 should never be drawn to directly, it would do no harm nevertheless. */
432 /* create additional (symbolic) buffer for double-buffering */
433 ReCreateBitmap(&window, video.width, video.height, video.depth);
436 static boolean SDLCreateScreen(boolean fullscreen)
438 SDL_Surface *new_surface = NULL;
440 #if defined(TARGET_SDL2)
441 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
442 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
444 int surface_flags_window = SURFACE_FLAGS;
445 int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2)
448 int width = video.width;
449 int height = video.height;
450 int surface_flags = (fullscreen ? surface_flags_fullscreen :
451 surface_flags_window);
453 // default window size is unscaled
454 video.window_width = video.width;
455 video.window_height = video.height;
457 #if defined(TARGET_SDL2)
459 // store if initial screen mode is fullscreen mode when changing screen size
460 video.fullscreen_initial = fullscreen;
462 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
464 video.window_width = window_scaling_factor * width;
465 video.window_height = window_scaling_factor * height;
467 if (sdl_texture_stream)
469 SDL_DestroyTexture(sdl_texture_stream);
470 sdl_texture_stream = NULL;
473 if (sdl_texture_target)
475 SDL_DestroyTexture(sdl_texture_target);
476 sdl_texture_target = NULL;
479 if (!(fullscreen && fullscreen_enabled))
483 SDL_DestroyRenderer(sdl_renderer);
489 SDL_DestroyWindow(sdl_window);
494 if (sdl_window == NULL)
495 sdl_window = SDL_CreateWindow(program.window_title,
496 SDL_WINDOWPOS_CENTERED,
497 SDL_WINDOWPOS_CENTERED,
502 if (sdl_window != NULL)
505 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
506 *without* enabling 2D/3D acceleration and/or guest additions installed,
507 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
508 it will try to use accelerated graphics and apparently fails miserably) */
509 if (sdl_renderer == NULL)
510 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
512 if (sdl_renderer == NULL)
513 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
516 if (sdl_renderer != NULL)
518 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
519 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
520 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
522 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
523 SDL_PIXELFORMAT_ARGB8888,
524 SDL_TEXTUREACCESS_STREAMING,
527 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
528 SDL_PIXELFORMAT_ARGB8888,
529 SDL_TEXTUREACCESS_TARGET,
532 if (sdl_texture_stream != NULL &&
533 sdl_texture_target != NULL)
535 // use SDL default values for RGB masks and no alpha channel
536 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
538 if (new_surface == NULL)
539 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
543 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
548 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
553 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
558 if (gfx.final_screen_bitmap == NULL)
559 gfx.final_screen_bitmap = CreateBitmapStruct();
561 gfx.final_screen_bitmap->width = width;
562 gfx.final_screen_bitmap->height = height;
564 gfx.final_screen_bitmap->surface =
565 SDL_SetVideoMode(width, height, video.depth, surface_flags);
567 if (gfx.final_screen_bitmap->surface != NULL)
570 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
572 if (new_surface == NULL)
573 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
576 new_surface = gfx.final_screen_bitmap->surface;
577 gfx.final_screen_bitmap = NULL;
583 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
587 #if defined(TARGET_SDL2)
588 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
589 if (new_surface != NULL)
590 fullscreen_enabled = fullscreen;
593 if (backbuffer == NULL)
594 backbuffer = CreateBitmapStruct();
596 backbuffer->width = video.width;
597 backbuffer->height = video.height;
599 if (backbuffer->surface)
600 SDL_FreeSurface(backbuffer->surface);
602 backbuffer->surface = new_surface;
604 return (new_surface != NULL);
607 boolean SDLSetVideoMode(boolean fullscreen)
609 boolean success = FALSE;
613 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
615 /* switch display to fullscreen mode, if available */
616 success = SDLCreateScreen(TRUE);
620 /* switching display to fullscreen mode failed -- do not try it again */
621 video.fullscreen_available = FALSE;
625 video.fullscreen_enabled = TRUE;
629 if ((!fullscreen && video.fullscreen_enabled) || !success)
631 /* switch display to window mode */
632 success = SDLCreateScreen(FALSE);
636 /* switching display to window mode failed -- should not happen */
640 video.fullscreen_enabled = FALSE;
641 video.window_scaling_percent = setup.window_scaling_percent;
642 video.window_scaling_quality = setup.window_scaling_quality;
643 video.screen_rendering_mode =
644 (strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
645 SPECIAL_RENDERING_BITMAP :
646 strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
647 SPECIAL_RENDERING_TARGET:
648 strEqual(setup.screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
649 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
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 SDL_Texture *new_texture;
725 if (sdl_texture_stream == NULL ||
726 sdl_texture_target == NULL)
729 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
731 new_texture = SDL_CreateTexture(sdl_renderer,
732 SDL_PIXELFORMAT_ARGB8888,
733 SDL_TEXTUREACCESS_STREAMING,
734 video.width, video.height);
736 if (new_texture != NULL)
738 SDL_DestroyTexture(sdl_texture_stream);
740 sdl_texture_stream = new_texture;
743 new_texture = SDL_CreateTexture(sdl_renderer,
744 SDL_PIXELFORMAT_ARGB8888,
745 SDL_TEXTUREACCESS_TARGET,
746 video.width, video.height);
748 if (new_texture != NULL)
750 SDL_DestroyTexture(sdl_texture_target);
752 sdl_texture_target = new_texture;
757 video.window_scaling_quality = window_scaling_quality;
760 void SDLSetScreenRenderingMode(char *screen_rendering_mode)
762 video.screen_rendering_mode =
763 (strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
764 SPECIAL_RENDERING_BITMAP :
765 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
766 SPECIAL_RENDERING_TARGET:
767 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
768 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
771 void SDLSetWindowFullscreen(boolean fullscreen)
773 if (sdl_window == NULL)
776 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
778 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
779 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
781 // if screen size was changed in fullscreen mode, correct desktop window size
782 if (!fullscreen && video.fullscreen_initial)
784 SDLSetWindowScaling(setup.window_scaling_percent);
785 SDL_SetWindowPosition(sdl_window,
786 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
788 video.fullscreen_initial = FALSE;
792 void SDLRedrawWindow()
794 UpdateScreen_WithoutFrameDelay(NULL);
798 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
801 SDL_Surface *surface =
802 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
805 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
807 SDLSetNativeSurface(&surface);
809 bitmap->surface = surface;
812 void SDLFreeBitmapPointers(Bitmap *bitmap)
815 SDL_FreeSurface(bitmap->surface);
816 if (bitmap->surface_masked)
817 SDL_FreeSurface(bitmap->surface_masked);
819 bitmap->surface = NULL;
820 bitmap->surface_masked = NULL;
822 #if defined(TARGET_SDL2)
824 SDL_DestroyTexture(bitmap->texture);
825 if (bitmap->texture_masked)
826 SDL_DestroyTexture(bitmap->texture_masked);
828 bitmap->texture = NULL;
829 bitmap->texture_masked = NULL;
833 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
834 int src_x, int src_y, int width, int height,
835 int dst_x, int dst_y, int mask_mode)
837 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
838 SDL_Rect src_rect, dst_rect;
850 // if (src_bitmap != backbuffer || dst_bitmap != window)
851 if (!(src_bitmap == backbuffer && dst_bitmap == window))
852 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
853 src_bitmap->surface_masked : src_bitmap->surface),
854 &src_rect, real_dst_bitmap->surface, &dst_rect);
856 if (dst_bitmap == window)
857 UpdateScreen_WithFrameDelay(&dst_rect);
860 void SDLBlitTexture(Bitmap *bitmap,
861 int src_x, int src_y, int width, int height,
862 int dst_x, int dst_y, int mask_mode)
864 #if defined(TARGET_SDL2)
865 SDL_Texture *texture;
870 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
885 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
889 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
892 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
900 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
902 if (dst_bitmap == window)
903 UpdateScreen_WithFrameDelay(&rect);
906 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
907 int fade_mode, int fade_delay, int post_delay,
908 void (*draw_border_function)(void))
910 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
911 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
912 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
913 SDL_Surface *surface_screen = backbuffer->surface;
914 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
915 SDL_Rect src_rect, dst_rect;
917 int src_x = x, src_y = y;
918 int dst_x = x, dst_y = y;
919 unsigned int time_last, time_current;
921 // store function for drawing global masked border
922 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
924 // deactivate drawing of global border while fading, if needed
925 if (draw_border_function == NULL)
926 gfx.draw_global_border_function = NULL;
935 dst_rect.w = width; /* (ignored) */
936 dst_rect.h = height; /* (ignored) */
938 dst_rect2 = dst_rect;
940 /* copy source and target surfaces to temporary surfaces for fading */
941 if (fade_mode & FADE_TYPE_TRANSFORM)
943 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
944 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
946 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
947 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
949 else if (fade_mode & FADE_TYPE_FADE_IN)
951 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
952 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
954 draw_global_border_function(DRAW_BORDER_TO_FADE_TARGET);
956 else /* FADE_TYPE_FADE_OUT */
958 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
959 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
961 draw_global_border_function(DRAW_BORDER_TO_FADE_SOURCE);
964 time_current = SDL_GetTicks();
966 if (fade_mode == FADE_MODE_MELT)
968 boolean done = FALSE;
970 int melt_columns = width / melt_pixels;
971 int ypos[melt_columns];
972 int max_steps = height / 8 + 32;
977 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
978 #if defined(TARGET_SDL2)
979 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
981 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
984 ypos[0] = -GetSimpleRandom(16);
986 for (i = 1 ; i < melt_columns; i++)
988 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
990 ypos[i] = ypos[i - 1] + r;
1003 time_last = time_current;
1004 time_current = SDL_GetTicks();
1005 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1006 steps_final = MIN(MAX(0, steps), max_steps);
1010 done = (steps_done >= steps_final);
1012 for (i = 0 ; i < melt_columns; i++)
1020 else if (ypos[i] < height)
1025 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1027 if (ypos[i] + dy >= height)
1028 dy = height - ypos[i];
1030 /* copy part of (appearing) target surface to upper area */
1031 src_rect.x = src_x + i * melt_pixels;
1032 // src_rect.y = src_y + ypos[i];
1034 src_rect.w = melt_pixels;
1036 src_rect.h = ypos[i] + dy;
1038 dst_rect.x = dst_x + i * melt_pixels;
1039 // dst_rect.y = dst_y + ypos[i];
1042 if (steps_done >= steps_final)
1043 SDL_BlitSurface(surface_target, &src_rect,
1044 surface_screen, &dst_rect);
1048 /* copy part of (disappearing) source surface to lower area */
1049 src_rect.x = src_x + i * melt_pixels;
1051 src_rect.w = melt_pixels;
1052 src_rect.h = height - ypos[i];
1054 dst_rect.x = dst_x + i * melt_pixels;
1055 dst_rect.y = dst_y + ypos[i];
1057 if (steps_done >= steps_final)
1058 SDL_BlitSurface(surface_source, &src_rect,
1059 surface_screen, &dst_rect);
1065 src_rect.x = src_x + i * melt_pixels;
1067 src_rect.w = melt_pixels;
1068 src_rect.h = height;
1070 dst_rect.x = dst_x + i * melt_pixels;
1073 if (steps_done >= steps_final)
1074 SDL_BlitSurface(surface_target, &src_rect,
1075 surface_screen, &dst_rect);
1079 if (steps_done >= steps_final)
1081 if (draw_border_function != NULL)
1082 draw_border_function();
1084 UpdateScreen_WithFrameDelay(&dst_rect2);
1088 else if (fade_mode == FADE_MODE_CURTAIN)
1092 int xx_size = width / 2;
1094 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1095 #if defined(TARGET_SDL2)
1096 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1098 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1101 for (xx = 0; xx < xx_size;)
1103 time_last = time_current;
1104 time_current = SDL_GetTicks();
1105 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1106 xx_final = MIN(MAX(0, xx), xx_size);
1111 src_rect.h = height;
1116 /* draw new (target) image to screen buffer */
1117 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1119 if (xx_final < xx_size)
1121 src_rect.w = xx_size - xx_final;
1122 src_rect.h = height;
1124 /* draw old (source) image to screen buffer (left side) */
1126 src_rect.x = src_x + xx_final;
1129 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1131 /* draw old (source) image to screen buffer (right side) */
1133 src_rect.x = src_x + xx_size;
1134 dst_rect.x = dst_x + xx_size + xx_final;
1136 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1139 if (draw_border_function != NULL)
1140 draw_border_function();
1142 /* only update the region of the screen that is affected from fading */
1143 UpdateScreen_WithFrameDelay(&dst_rect2);
1146 else /* fading in, fading out or cross-fading */
1151 for (alpha = 0.0; alpha < 255.0;)
1153 time_last = time_current;
1154 time_current = SDL_GetTicks();
1155 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1156 alpha_final = MIN(MAX(0, alpha), 255);
1158 /* draw existing (source) image to screen buffer */
1159 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1161 /* draw new (target) image to screen buffer using alpha blending */
1162 #if defined(TARGET_SDL2)
1163 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1164 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1166 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1168 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1170 if (draw_border_function != NULL)
1171 draw_border_function();
1173 /* only update the region of the screen that is affected from fading */
1174 UpdateScreen_WithFrameDelay(&dst_rect);
1180 unsigned int time_post_delay;
1182 time_current = SDL_GetTicks();
1183 time_post_delay = time_current + post_delay;
1185 while (time_current < time_post_delay)
1187 // updating the screen contains waiting for frame delay (non-busy)
1188 UpdateScreen_WithFrameDelay(NULL);
1190 time_current = SDL_GetTicks();
1194 // restore function for drawing global masked border
1195 gfx.draw_global_border_function = draw_global_border_function;
1198 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1199 int to_x, int to_y, Uint32 color)
1201 SDL_Surface *surface = dst_bitmap->surface;
1205 swap_numbers(&from_x, &to_x);
1208 swap_numbers(&from_y, &to_y);
1212 rect.w = (to_x - from_x + 1);
1213 rect.h = (to_y - from_y + 1);
1215 SDL_FillRect(surface, &rect, color);
1218 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1219 int to_x, int to_y, Uint32 color)
1221 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1224 #if ENABLE_UNUSED_CODE
1225 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1226 int num_points, Uint32 color)
1231 for (i = 0; i < num_points - 1; i++)
1233 for (x = 0; x < line_width; x++)
1235 for (y = 0; y < line_width; y++)
1237 int dx = x - line_width / 2;
1238 int dy = y - line_width / 2;
1240 if ((x == 0 && y == 0) ||
1241 (x == 0 && y == line_width - 1) ||
1242 (x == line_width - 1 && y == 0) ||
1243 (x == line_width - 1 && y == line_width - 1))
1246 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1247 points[i+1].x + dx, points[i+1].y + dy, color);
1254 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1256 SDL_Surface *surface = src_bitmap->surface;
1258 switch (surface->format->BytesPerPixel)
1260 case 1: /* assuming 8-bpp */
1262 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1266 case 2: /* probably 15-bpp or 16-bpp */
1268 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1272 case 3: /* slow 24-bpp mode; usually not used */
1274 /* does this work? */
1275 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1279 shift = surface->format->Rshift;
1280 color |= *(pix + shift / 8) >> shift;
1281 shift = surface->format->Gshift;
1282 color |= *(pix + shift / 8) >> shift;
1283 shift = surface->format->Bshift;
1284 color |= *(pix + shift / 8) >> shift;
1290 case 4: /* probably 32-bpp */
1292 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1301 /* ========================================================================= */
1302 /* The following functions were taken from the SGE library */
1303 /* (SDL Graphics Extension Library) by Anders Lindström */
1304 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1305 /* ========================================================================= */
1307 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1309 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1311 switch (surface->format->BytesPerPixel)
1315 /* Assuming 8-bpp */
1316 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1322 /* Probably 15-bpp or 16-bpp */
1323 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1329 /* Slow 24-bpp mode, usually not used */
1333 /* Gack - slow, but endian correct */
1334 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1335 shift = surface->format->Rshift;
1336 *(pix+shift/8) = color>>shift;
1337 shift = surface->format->Gshift;
1338 *(pix+shift/8) = color>>shift;
1339 shift = surface->format->Bshift;
1340 *(pix+shift/8) = color>>shift;
1346 /* Probably 32-bpp */
1347 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1354 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1355 Uint8 R, Uint8 G, Uint8 B)
1357 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1360 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1362 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1365 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1367 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1370 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1375 /* Gack - slow, but endian correct */
1376 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1377 shift = surface->format->Rshift;
1378 *(pix+shift/8) = color>>shift;
1379 shift = surface->format->Gshift;
1380 *(pix+shift/8) = color>>shift;
1381 shift = surface->format->Bshift;
1382 *(pix+shift/8) = color>>shift;
1385 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1387 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1390 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1392 switch (dest->format->BytesPerPixel)
1395 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1399 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1403 _PutPixel24(dest,x,y,color);
1407 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1412 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1414 if (SDL_MUSTLOCK(surface))
1416 if (SDL_LockSurface(surface) < 0)
1422 _PutPixel(surface, x, y, color);
1424 if (SDL_MUSTLOCK(surface))
1426 SDL_UnlockSurface(surface);
1430 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1431 Uint8 r, Uint8 g, Uint8 b)
1433 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1436 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1438 if (y >= 0 && y <= dest->h - 1)
1440 switch (dest->format->BytesPerPixel)
1443 return y*dest->pitch;
1447 return y*dest->pitch/2;
1451 return y*dest->pitch;
1455 return y*dest->pitch/4;
1463 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1465 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1467 switch (surface->format->BytesPerPixel)
1471 /* Assuming 8-bpp */
1472 *((Uint8 *)surface->pixels + ypitch + x) = color;
1478 /* Probably 15-bpp or 16-bpp */
1479 *((Uint16 *)surface->pixels + ypitch + x) = color;
1485 /* Slow 24-bpp mode, usually not used */
1489 /* Gack - slow, but endian correct */
1490 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1491 shift = surface->format->Rshift;
1492 *(pix+shift/8) = color>>shift;
1493 shift = surface->format->Gshift;
1494 *(pix+shift/8) = color>>shift;
1495 shift = surface->format->Bshift;
1496 *(pix+shift/8) = color>>shift;
1502 /* Probably 32-bpp */
1503 *((Uint32 *)surface->pixels + ypitch + x) = color;
1510 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1515 if (SDL_MUSTLOCK(Surface))
1517 if (SDL_LockSurface(Surface) < 0)
1530 /* Do the clipping */
1531 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1535 if (x2 > Surface->w - 1)
1536 x2 = Surface->w - 1;
1543 SDL_FillRect(Surface, &l, Color);
1545 if (SDL_MUSTLOCK(Surface))
1547 SDL_UnlockSurface(Surface);
1551 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1552 Uint8 R, Uint8 G, Uint8 B)
1554 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1557 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1568 /* Do the clipping */
1569 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1573 if (x2 > Surface->w - 1)
1574 x2 = Surface->w - 1;
1581 SDL_FillRect(Surface, &l, Color);
1584 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1589 if (SDL_MUSTLOCK(Surface))
1591 if (SDL_LockSurface(Surface) < 0)
1604 /* Do the clipping */
1605 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1609 if (y2 > Surface->h - 1)
1610 y2 = Surface->h - 1;
1617 SDL_FillRect(Surface, &l, Color);
1619 if (SDL_MUSTLOCK(Surface))
1621 SDL_UnlockSurface(Surface);
1625 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1626 Uint8 R, Uint8 G, Uint8 B)
1628 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1631 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1642 /* Do the clipping */
1643 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1647 if (y2 > Surface->h - 1)
1648 y2 = Surface->h - 1;
1655 SDL_FillRect(Surface, &l, Color);
1658 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1659 Sint16 x2, Sint16 y2, Uint32 Color,
1660 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1663 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1668 sdx = (dx < 0) ? -1 : 1;
1669 sdy = (dy < 0) ? -1 : 1;
1681 for (x = 0; x < dx; x++)
1683 Callback(Surface, px, py, Color);
1697 for (y = 0; y < dy; y++)
1699 Callback(Surface, px, py, Color);
1713 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1714 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1715 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1718 sge_DoLine(Surface, X1, Y1, X2, Y2,
1719 SDL_MapRGB(Surface->format, R, G, B), Callback);
1722 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1725 if (SDL_MUSTLOCK(Surface))
1727 if (SDL_LockSurface(Surface) < 0)
1732 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1734 /* unlock the display */
1735 if (SDL_MUSTLOCK(Surface))
1737 SDL_UnlockSurface(Surface);
1741 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1742 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1744 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1747 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1749 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1754 -----------------------------------------------------------------------------
1755 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1756 -----------------------------------------------------------------------------
1759 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1760 int width, int height, Uint32 color)
1764 for (y = src_y; y < src_y + height; y++)
1766 for (x = src_x; x < src_x + width; x++)
1768 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1770 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1775 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1776 int src_x, int src_y, int width, int height,
1777 int dst_x, int dst_y)
1781 for (y = 0; y < height; y++)
1783 for (x = 0; x < width; x++)
1785 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1787 if (pixel != BLACK_PIXEL)
1788 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1794 /* ========================================================================= */
1795 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1796 /* (Rotozoomer) by Andreas Schiffler */
1797 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1798 /* ========================================================================= */
1801 -----------------------------------------------------------------------------
1804 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1805 -----------------------------------------------------------------------------
1816 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1819 tColorRGBA *sp, *csp, *dp;
1823 sp = csp = (tColorRGBA *) src->pixels;
1824 dp = (tColorRGBA *) dst->pixels;
1825 dgap = dst->pitch - dst->w * 4;
1827 for (y = 0; y < dst->h; y++)
1831 for (x = 0; x < dst->w; x++)
1833 tColorRGBA *sp0 = sp;
1834 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1835 tColorRGBA *sp00 = &sp0[0];
1836 tColorRGBA *sp01 = &sp0[1];
1837 tColorRGBA *sp10 = &sp1[0];
1838 tColorRGBA *sp11 = &sp1[1];
1841 /* create new color pixel from all four source color pixels */
1842 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1843 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1844 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1845 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1850 /* advance source pointers */
1853 /* advance destination pointer */
1857 /* advance source pointer */
1858 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1860 /* advance destination pointers */
1861 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1867 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1869 int x, y, *sax, *say, *csax, *csay;
1871 tColorRGBA *sp, *csp, *csp0, *dp;
1874 /* use specialized zoom function when scaling down to exactly half size */
1875 if (src->w == 2 * dst->w &&
1876 src->h == 2 * dst->h)
1877 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1879 /* variable setup */
1880 sx = (float) src->w / (float) dst->w;
1881 sy = (float) src->h / (float) dst->h;
1883 /* allocate memory for row increments */
1884 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1885 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1887 /* precalculate row increments */
1888 for (x = 0; x <= dst->w; x++)
1889 *csax++ = (int)(sx * x);
1891 for (y = 0; y <= dst->h; y++)
1892 *csay++ = (int)(sy * y);
1895 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1896 dp = (tColorRGBA *) dst->pixels;
1897 dgap = dst->pitch - dst->w * 4;
1900 for (y = 0; y < dst->h; y++)
1905 for (x = 0; x < dst->w; x++)
1910 /* advance source pointers */
1914 /* advance destination pointer */
1918 /* advance source pointer */
1920 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1922 /* advance destination pointers */
1923 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1933 -----------------------------------------------------------------------------
1936 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1937 -----------------------------------------------------------------------------
1940 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1942 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1943 Uint8 *sp, *dp, *csp;
1946 /* variable setup */
1947 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1948 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1950 /* allocate memory for row increments */
1951 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1952 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1954 /* precalculate row increments */
1957 for (x = 0; x < dst->w; x++)
1960 *csax = (csx >> 16);
1967 for (y = 0; y < dst->h; y++)
1970 *csay = (csy >> 16);
1977 for (x = 0; x < dst->w; x++)
1985 for (y = 0; y < dst->h; y++)
1992 sp = csp = (Uint8 *) src->pixels;
1993 dp = (Uint8 *) dst->pixels;
1994 dgap = dst->pitch - dst->w;
1998 for (y = 0; y < dst->h; y++)
2002 for (x = 0; x < dst->w; x++)
2007 /* advance source pointers */
2011 /* advance destination pointer */
2015 /* advance source pointer (for row) */
2016 csp += ((*csay) * src->pitch);
2019 /* advance destination pointers */
2030 -----------------------------------------------------------------------------
2033 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2034 'zoomx' and 'zoomy' are scaling factors for width and height.
2035 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2036 into a 32bit RGBA format on the fly.
2037 -----------------------------------------------------------------------------
2040 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2042 SDL_Surface *zoom_src = NULL;
2043 SDL_Surface *zoom_dst = NULL;
2044 boolean is_converted = FALSE;
2051 /* determine if source surface is 32 bit or 8 bit */
2052 is_32bit = (src->format->BitsPerPixel == 32);
2054 if (is_32bit || src->format->BitsPerPixel == 8)
2056 /* use source surface 'as is' */
2061 /* new source surface is 32 bit with a defined RGB ordering */
2062 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2063 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2064 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2066 is_converted = TRUE;
2069 /* allocate surface to completely contain the zoomed surface */
2072 /* target surface is 32 bit with source RGBA/ABGR ordering */
2073 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2074 zoom_src->format->Rmask,
2075 zoom_src->format->Gmask,
2076 zoom_src->format->Bmask, 0);
2080 /* target surface is 8 bit */
2081 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2085 /* lock source surface */
2086 SDL_LockSurface(zoom_src);
2088 /* check which kind of surface we have */
2091 /* call the 32 bit transformation routine to do the zooming */
2092 zoomSurfaceRGBA(zoom_src, zoom_dst);
2097 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2098 zoom_dst->format->palette->colors[i] =
2099 zoom_src->format->palette->colors[i];
2100 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2102 /* call the 8 bit transformation routine to do the zooming */
2103 zoomSurfaceY(zoom_src, zoom_dst);
2106 /* unlock source surface */
2107 SDL_UnlockSurface(zoom_src);
2109 /* free temporary surface */
2111 SDL_FreeSurface(zoom_src);
2113 /* return destination surface */
2117 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2119 Bitmap *dst_bitmap = CreateBitmapStruct();
2120 SDL_Surface **dst_surface = &dst_bitmap->surface;
2122 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2123 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2125 dst_bitmap->width = dst_width;
2126 dst_bitmap->height = dst_height;
2128 /* create zoomed temporary surface from source surface */
2129 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2131 /* create native format destination surface from zoomed temporary surface */
2132 SDLSetNativeSurface(dst_surface);
2138 /* ========================================================================= */
2139 /* load image to bitmap */
2140 /* ========================================================================= */
2142 Bitmap *SDLLoadImage(char *filename)
2144 Bitmap *new_bitmap = CreateBitmapStruct();
2145 SDL_Surface *sdl_image_tmp;
2147 print_timestamp_init("SDLLoadImage");
2149 print_timestamp_time(getBaseNamePtr(filename));
2151 /* load image to temporary surface */
2152 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2154 SetError("IMG_Load(): %s", SDL_GetError());
2159 print_timestamp_time("IMG_Load");
2161 UPDATE_BUSY_STATE();
2163 /* create native non-transparent surface for current image */
2164 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2166 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2171 print_timestamp_time("SDL_DisplayFormat (opaque)");
2173 UPDATE_BUSY_STATE();
2175 /* create native transparent surface for current image */
2176 if (sdl_image_tmp->format->Amask == 0)
2177 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2178 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2180 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2182 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2187 print_timestamp_time("SDL_DisplayFormat (masked)");
2189 UPDATE_BUSY_STATE();
2191 /* free temporary surface */
2192 SDL_FreeSurface(sdl_image_tmp);
2194 new_bitmap->width = new_bitmap->surface->w;
2195 new_bitmap->height = new_bitmap->surface->h;
2197 print_timestamp_done("SDLLoadImage");
2203 /* ------------------------------------------------------------------------- */
2204 /* custom cursor fuctions */
2205 /* ------------------------------------------------------------------------- */
2207 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2209 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2210 cursor_info->width, cursor_info->height,
2211 cursor_info->hot_x, cursor_info->hot_y);
2214 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2216 static struct MouseCursorInfo *last_cursor_info = NULL;
2217 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2218 static SDL_Cursor *cursor_default = NULL;
2219 static SDL_Cursor *cursor_current = NULL;
2221 /* if invoked for the first time, store the SDL default cursor */
2222 if (cursor_default == NULL)
2223 cursor_default = SDL_GetCursor();
2225 /* only create new cursor if cursor info (custom only) has changed */
2226 if (cursor_info != NULL && cursor_info != last_cursor_info)
2228 cursor_current = create_cursor(cursor_info);
2229 last_cursor_info = cursor_info;
2232 /* only set new cursor if cursor info (custom or NULL) has changed */
2233 if (cursor_info != last_cursor_info2)
2234 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2236 last_cursor_info2 = cursor_info;
2240 /* ========================================================================= */
2241 /* audio functions */
2242 /* ========================================================================= */
2244 void SDLOpenAudio(void)
2246 #if !defined(TARGET_SDL2)
2247 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2248 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2251 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2253 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2257 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2258 AUDIO_NUM_CHANNELS_STEREO,
2259 setup.system.audio_fragment_size) < 0)
2261 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2265 audio.sound_available = TRUE;
2266 audio.music_available = TRUE;
2267 audio.loops_available = TRUE;
2268 audio.sound_enabled = TRUE;
2270 /* set number of available mixer channels */
2271 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2272 audio.music_channel = MUSIC_CHANNEL;
2273 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2275 Mixer_InitChannels();
2278 void SDLCloseAudio(void)
2281 Mix_HaltChannel(-1);
2284 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2288 /* ========================================================================= */
2289 /* event functions */
2290 /* ========================================================================= */
2292 void SDLNextEvent(Event *event)
2294 SDL_WaitEvent(event);
2297 void SDLHandleWindowManagerEvent(Event *event)
2300 #if defined(PLATFORM_WIN32)
2301 // experimental drag and drop code
2303 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2304 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2306 #if defined(TARGET_SDL2)
2307 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2309 if (syswmmsg->msg == WM_DROPFILES)
2312 #if defined(TARGET_SDL2)
2313 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2315 HDROP hdrop = (HDROP)syswmmsg->wParam;
2319 printf("::: SDL_SYSWMEVENT:\n");
2321 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2323 for (i = 0; i < num_files; i++)
2325 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2326 char buffer[buffer_len + 1];
2328 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2330 printf("::: - '%s'\n", buffer);
2333 #if defined(TARGET_SDL2)
2334 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2336 DragFinish((HDROP)syswmmsg->wParam);
2344 /* ========================================================================= */
2345 /* joystick functions */
2346 /* ========================================================================= */
2348 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2349 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2350 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2352 static boolean SDLOpenJoystick(int nr)
2354 if (nr < 0 || nr > MAX_PLAYERS)
2357 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2360 static void SDLCloseJoystick(int nr)
2362 if (nr < 0 || nr > MAX_PLAYERS)
2365 SDL_JoystickClose(sdl_joystick[nr]);
2367 sdl_joystick[nr] = NULL;
2370 static boolean SDLCheckJoystickOpened(int nr)
2372 if (nr < 0 || nr > MAX_PLAYERS)
2375 #if defined(TARGET_SDL2)
2376 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2378 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2382 void HandleJoystickEvent(Event *event)
2386 case SDL_JOYAXISMOTION:
2387 if (event->jaxis.axis < 2)
2388 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2391 case SDL_JOYBUTTONDOWN:
2392 if (event->jbutton.button < 2)
2393 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2396 case SDL_JOYBUTTONUP:
2397 if (event->jbutton.button < 2)
2398 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2406 void SDLInitJoysticks()
2408 static boolean sdl_joystick_subsystem_initialized = FALSE;
2409 boolean print_warning = !sdl_joystick_subsystem_initialized;
2412 if (!sdl_joystick_subsystem_initialized)
2414 sdl_joystick_subsystem_initialized = TRUE;
2416 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2418 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2423 for (i = 0; i < MAX_PLAYERS; i++)
2425 /* get configured joystick for this player */
2426 char *device_name = setup.input[i].joy.device_name;
2427 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2429 if (joystick_nr >= SDL_NumJoysticks())
2431 if (setup.input[i].use_joystick && print_warning)
2432 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2437 /* misuse joystick file descriptor variable to store joystick number */
2438 joystick.fd[i] = joystick_nr;
2440 if (joystick_nr == -1)
2443 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2444 if (SDLCheckJoystickOpened(joystick_nr))
2445 SDLCloseJoystick(joystick_nr);
2447 if (!setup.input[i].use_joystick)
2450 if (!SDLOpenJoystick(joystick_nr))
2453 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2458 joystick.status = JOYSTICK_ACTIVATED;
2462 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2464 if (nr < 0 || nr >= MAX_PLAYERS)
2468 *x = sdl_js_axis[nr][0];
2470 *y = sdl_js_axis[nr][1];
2473 *b1 = sdl_js_button[nr][0];
2475 *b2 = sdl_js_button[nr][1];