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(int draw_target)
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_target, 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_target);
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_target, 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);
98 FinalizeScreen(DRAW_TO_SCREEN);
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 // deactivate use of target texture if render targets are not supported
110 if ((video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
111 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE) &&
112 sdl_texture_target == NULL)
113 video.screen_rendering_mode = SPECIAL_RENDERING_OFF;
115 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET)
116 sdl_texture = sdl_texture_target;
120 int bytes_x = screen->pitch / video.width;
121 int bytes_y = screen->pitch;
123 SDL_UpdateTexture(sdl_texture, rect,
124 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
129 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
132 // clear render target buffer
133 SDL_RenderClear(sdl_renderer);
135 // set renderer to use target texture for rendering
136 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
137 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
138 SDL_SetRenderTarget(sdl_renderer, sdl_texture_target);
140 // copy backbuffer texture to render target buffer
141 if (video.screen_rendering_mode != SPECIAL_RENDERING_TARGET)
142 SDL_RenderCopy(sdl_renderer, sdl_texture_stream, NULL, NULL);
144 if (video.screen_rendering_mode != SPECIAL_RENDERING_BITMAP)
145 FinalizeScreen(DRAW_TO_SCREEN);
147 // when using target texture, copy it to screen buffer
148 if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
149 video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
151 SDL_SetRenderTarget(sdl_renderer, NULL);
152 SDL_RenderCopy(sdl_renderer, sdl_texture_target, NULL, NULL);
156 // global synchronization point of the game to align video frame delay
157 if (with_frame_delay)
158 WaitUntilDelayReached(&video.frame_delay, video.frame_delay_value);
160 #if defined(TARGET_SDL2)
161 // show render target buffer on screen
162 SDL_RenderPresent(sdl_renderer);
165 SDL_UpdateRects(screen, 1, rect);
167 SDL_UpdateRect(screen, 0, 0, 0, 0);
171 static void UpdateScreen_WithFrameDelay(SDL_Rect *rect)
173 UpdateScreenExt(rect, TRUE);
176 static void UpdateScreen_WithoutFrameDelay(SDL_Rect *rect)
178 UpdateScreenExt(rect, FALSE);
181 static void SDLSetWindowIcon(char *basename)
183 /* (setting the window icon on Mac OS X would replace the high-quality
184 dock icon with the currently smaller (and uglier) icon from file) */
186 #if !defined(PLATFORM_MACOSX)
187 char *filename = getCustomImageFilename(basename);
188 SDL_Surface *surface;
190 if (filename == NULL)
192 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
197 if ((surface = IMG_Load(filename)) == NULL)
199 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
204 /* set transparent color */
205 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
206 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
208 #if defined(TARGET_SDL2)
209 SDL_SetWindowIcon(sdl_window, surface);
211 SDL_WM_SetIcon(surface, NULL);
216 #if defined(TARGET_SDL2)
218 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
219 SDL_PixelFormat *format2)
221 return (format1->format == format2->format &&
222 format1->BitsPerPixel == format2->BitsPerPixel &&
223 format1->BytesPerPixel == format2->BytesPerPixel &&
224 format1->Rmask == format2->Rmask &&
225 format1->Gmask == format2->Gmask &&
226 format1->Bmask == format2->Bmask);
229 boolean SDLSetNativeSurface(SDL_Surface **surface)
231 SDL_Surface *new_surface;
233 if (surface == NULL ||
235 backbuffer == NULL ||
236 backbuffer->surface == NULL)
239 // if pixel format already optimized for destination surface, do nothing
240 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
243 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
245 if (new_surface == NULL)
246 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
248 SDL_FreeSurface(*surface);
250 *surface = new_surface;
255 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
257 SDL_PixelFormat format;
258 SDL_Surface *new_surface;
263 if (backbuffer && backbuffer->surface)
265 format = *backbuffer->surface->format;
266 format.Amask = surface->format->Amask; // keep alpha channel
270 format = *surface->format;
273 new_surface = SDL_ConvertSurface(surface, &format, 0);
275 if (new_surface == NULL)
276 Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError());
283 boolean SDLSetNativeSurface(SDL_Surface **surface)
285 SDL_Surface *new_surface;
287 if (surface == NULL ||
292 new_surface = SDL_DisplayFormat(*surface);
294 if (new_surface == NULL)
295 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
297 SDL_FreeSurface(*surface);
299 *surface = new_surface;
304 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
306 SDL_Surface *new_surface;
308 if (video.initialized)
309 new_surface = SDL_DisplayFormat(surface);
311 new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS);
313 if (new_surface == NULL)
314 Error(ERR_EXIT, "%s() failed: %s",
315 (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"),
323 #if defined(TARGET_SDL2)
324 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
326 SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface);
329 Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s",
336 void SDLCreateBitmapTextures(Bitmap *bitmap)
338 #if defined(TARGET_SDL2)
343 SDL_DestroyTexture(bitmap->texture);
344 if (bitmap->texture_masked)
345 SDL_DestroyTexture(bitmap->texture_masked);
347 bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface);
348 bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked);
352 void SDLFreeBitmapTextures(Bitmap *bitmap)
354 #if defined(TARGET_SDL2)
359 SDL_DestroyTexture(bitmap->texture);
360 if (bitmap->texture_masked)
361 SDL_DestroyTexture(bitmap->texture_masked);
363 bitmap->texture = NULL;
364 bitmap->texture_masked = NULL;
368 void SDLInitVideoDisplay(void)
370 #if !defined(TARGET_SDL2)
371 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
372 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
374 SDL_putenv("SDL_VIDEO_CENTERED=1");
377 /* initialize SDL video */
378 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
379 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
381 /* set default SDL depth */
382 #if !defined(TARGET_SDL2)
383 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
385 video.default_depth = 32; // (how to determine video depth in SDL2?)
389 void SDLInitVideoBuffer(boolean fullscreen)
391 video.window_scaling_percent = setup.window_scaling_percent;
392 video.window_scaling_quality = setup.window_scaling_quality;
394 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
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);
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 #if defined(TARGET_SDL2)
450 int renderer_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
452 /* If SDL_CreateRenderer() is called from within a VirtualBox Windows VM
453 _without_ enabling 2D/3D acceleration and/or guest additions installed,
454 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
455 it will try to use accelerated graphics and apparently fails miserably) */
456 int renderer_flags = SDL_RENDERER_SOFTWARE;
460 int width = video.width;
461 int height = video.height;
462 int surface_flags = (fullscreen ? surface_flags_fullscreen :
463 surface_flags_window);
465 // default window size is unscaled
466 video.window_width = video.width;
467 video.window_height = video.height;
469 #if defined(TARGET_SDL2)
471 // store if initial screen mode is fullscreen mode when changing screen size
472 video.fullscreen_initial = fullscreen;
474 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
476 video.window_width = window_scaling_factor * width;
477 video.window_height = window_scaling_factor * height;
479 if (sdl_texture_stream)
481 SDL_DestroyTexture(sdl_texture_stream);
482 sdl_texture_stream = NULL;
485 if (sdl_texture_target)
487 SDL_DestroyTexture(sdl_texture_target);
488 sdl_texture_target = NULL;
491 if (!(fullscreen && fullscreen_enabled))
495 SDL_DestroyRenderer(sdl_renderer);
501 SDL_DestroyWindow(sdl_window);
506 if (sdl_window == NULL)
507 sdl_window = SDL_CreateWindow(program.window_title,
508 SDL_WINDOWPOS_CENTERED,
509 SDL_WINDOWPOS_CENTERED,
514 if (sdl_window != NULL)
516 if (sdl_renderer == NULL)
517 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, renderer_flags);
519 if (sdl_renderer != NULL)
521 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
522 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
523 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
525 sdl_texture_stream = SDL_CreateTexture(sdl_renderer,
526 SDL_PIXELFORMAT_ARGB8888,
527 SDL_TEXTUREACCESS_STREAMING,
530 if (SDL_RenderTargetSupported(sdl_renderer))
531 sdl_texture_target = SDL_CreateTexture(sdl_renderer,
532 SDL_PIXELFORMAT_ARGB8888,
533 SDL_TEXTUREACCESS_TARGET,
536 if (sdl_texture_stream != NULL)
538 // use SDL default values for RGB masks and no alpha channel
539 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
541 if (new_surface == NULL)
542 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
546 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
551 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
556 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
561 if (gfx.final_screen_bitmap == NULL)
562 gfx.final_screen_bitmap = CreateBitmapStruct();
564 gfx.final_screen_bitmap->width = width;
565 gfx.final_screen_bitmap->height = height;
567 gfx.final_screen_bitmap->surface =
568 SDL_SetVideoMode(width, height, video.depth, surface_flags);
570 if (gfx.final_screen_bitmap->surface != NULL)
573 SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0);
575 if (new_surface == NULL)
576 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
579 new_surface = gfx.final_screen_bitmap->surface;
580 gfx.final_screen_bitmap = NULL;
586 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
590 #if defined(TARGET_SDL2)
591 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
592 if (new_surface != NULL)
593 fullscreen_enabled = fullscreen;
596 if (backbuffer == NULL)
597 backbuffer = CreateBitmapStruct();
599 backbuffer->width = video.width;
600 backbuffer->height = video.height;
602 if (backbuffer->surface)
603 SDL_FreeSurface(backbuffer->surface);
605 backbuffer->surface = new_surface;
607 return (new_surface != NULL);
610 boolean SDLSetVideoMode(boolean fullscreen)
612 boolean success = FALSE;
616 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
618 /* switch display to fullscreen mode, if available */
619 success = SDLCreateScreen(TRUE);
623 /* switching display to fullscreen mode failed -- do not try it again */
624 video.fullscreen_available = FALSE;
628 video.fullscreen_enabled = TRUE;
632 if ((!fullscreen && video.fullscreen_enabled) || !success)
634 /* switch display to window mode */
635 success = SDLCreateScreen(FALSE);
639 /* switching display to window mode failed -- should not happen */
643 video.fullscreen_enabled = FALSE;
644 video.window_scaling_percent = setup.window_scaling_percent;
645 video.window_scaling_quality = setup.window_scaling_quality;
647 SDLSetScreenRenderingMode(setup.screen_rendering_mode);
651 #if defined(TARGET_SDL2)
652 SDLRedrawWindow(); // map window
656 #if defined(PLATFORM_WIN32)
657 // experimental drag and drop code
659 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
662 SDL_SysWMinfo wminfo;
664 boolean wminfo_success = FALSE;
666 SDL_VERSION(&wminfo.version);
667 #if defined(TARGET_SDL2)
669 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
671 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
676 #if defined(TARGET_SDL2)
677 hwnd = wminfo.info.win.window;
679 hwnd = wminfo.window;
682 DragAcceptFiles(hwnd, TRUE);
691 void SDLSetWindowTitle()
693 #if defined(TARGET_SDL2)
694 SDL_SetWindowTitle(sdl_window, program.window_title);
696 SDL_WM_SetCaption(program.window_title, program.window_title);
700 #if defined(TARGET_SDL2)
701 void SDLSetWindowScaling(int window_scaling_percent)
703 if (sdl_window == NULL)
706 float window_scaling_factor = (float)window_scaling_percent / 100;
707 int new_window_width = (int)(window_scaling_factor * video.width);
708 int new_window_height = (int)(window_scaling_factor * video.height);
710 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
712 video.window_scaling_percent = window_scaling_percent;
713 video.window_width = new_window_width;
714 video.window_height = new_window_height;
719 void SDLSetWindowScalingQuality(char *window_scaling_quality)
721 SDL_Texture *new_texture;
723 if (sdl_texture_stream == NULL)
726 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
728 new_texture = SDL_CreateTexture(sdl_renderer,
729 SDL_PIXELFORMAT_ARGB8888,
730 SDL_TEXTUREACCESS_STREAMING,
731 video.width, video.height);
733 if (new_texture != NULL)
735 SDL_DestroyTexture(sdl_texture_stream);
737 sdl_texture_stream = new_texture;
740 if (SDL_RenderTargetSupported(sdl_renderer))
741 new_texture = SDL_CreateTexture(sdl_renderer,
742 SDL_PIXELFORMAT_ARGB8888,
743 SDL_TEXTUREACCESS_TARGET,
744 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 SDLSetWindowFullscreen(boolean fullscreen)
762 if (sdl_window == NULL)
765 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
767 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
768 video.fullscreen_enabled = fullscreen_enabled = fullscreen;
770 // if screen size was changed in fullscreen mode, correct desktop window size
771 if (!fullscreen && video.fullscreen_initial)
773 SDLSetWindowScaling(setup.window_scaling_percent);
774 SDL_SetWindowPosition(sdl_window,
775 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
777 video.fullscreen_initial = FALSE;
782 void SDLSetScreenRenderingMode(char *screen_rendering_mode)
784 #if defined(TARGET_SDL2)
785 video.screen_rendering_mode =
786 (strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ?
787 SPECIAL_RENDERING_BITMAP :
788 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ?
789 SPECIAL_RENDERING_TARGET:
790 strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ?
791 SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF);
793 video.screen_rendering_mode = SPECIAL_RENDERING_BITMAP;
797 void SDLRedrawWindow()
799 UpdateScreen_WithoutFrameDelay(NULL);
802 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
805 SDL_Surface *surface =
806 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
809 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
811 SDLSetNativeSurface(&surface);
813 bitmap->surface = surface;
816 void SDLFreeBitmapPointers(Bitmap *bitmap)
819 SDL_FreeSurface(bitmap->surface);
820 if (bitmap->surface_masked)
821 SDL_FreeSurface(bitmap->surface_masked);
823 bitmap->surface = NULL;
824 bitmap->surface_masked = NULL;
826 #if defined(TARGET_SDL2)
828 SDL_DestroyTexture(bitmap->texture);
829 if (bitmap->texture_masked)
830 SDL_DestroyTexture(bitmap->texture_masked);
832 bitmap->texture = NULL;
833 bitmap->texture_masked = NULL;
837 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
838 int src_x, int src_y, int width, int height,
839 int dst_x, int dst_y, int mask_mode)
841 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
842 SDL_Rect src_rect, dst_rect;
854 // if (src_bitmap != backbuffer || dst_bitmap != window)
855 if (!(src_bitmap == backbuffer && dst_bitmap == window))
856 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
857 src_bitmap->surface_masked : src_bitmap->surface),
858 &src_rect, real_dst_bitmap->surface, &dst_rect);
860 if (dst_bitmap == window)
861 UpdateScreen_WithFrameDelay(&dst_rect);
864 void SDLBlitTexture(Bitmap *bitmap,
865 int src_x, int src_y, int width, int height,
866 int dst_x, int dst_y, int mask_mode)
868 #if defined(TARGET_SDL2)
869 SDL_Texture *texture;
874 (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture);
889 SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
893 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
896 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
904 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
906 if (dst_bitmap == window)
907 UpdateScreen_WithFrameDelay(&rect);
910 void PrepareFadeBitmap(int draw_target)
912 Bitmap *fade_bitmap =
913 (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
914 draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
916 if (fade_bitmap == NULL)
919 // copy backbuffer to fading buffer
920 BlitBitmap(backbuffer, fade_bitmap, 0, 0, gfx.win_xsize, gfx.win_ysize, 0, 0);
922 // add border and animations to fading buffer
923 FinalizeScreen(draw_target);
926 void SDLFadeRectangle(int x, int y, int width, int height,
927 int fade_mode, int fade_delay, int post_delay,
928 void (*draw_border_function)(void))
930 SDL_Surface *surface_backup = gfx.fade_bitmap_backup->surface;
931 SDL_Surface *surface_source = gfx.fade_bitmap_source->surface;
932 SDL_Surface *surface_target = gfx.fade_bitmap_target->surface;
933 SDL_Surface *surface_black = gfx.fade_bitmap_black->surface;
934 SDL_Surface *surface_screen = backbuffer->surface;
935 SDL_Rect src_rect, dst_rect;
937 int src_x = x, src_y = y;
938 int dst_x = x, dst_y = y;
939 unsigned int time_last, time_current;
941 // store function for drawing global masked border
942 void (*draw_global_border_function)(int) = gfx.draw_global_border_function;
944 // deactivate drawing of global border while fading, if needed
945 if (draw_border_function == NULL)
946 gfx.draw_global_border_function = NULL;
955 dst_rect.w = width; /* (ignored) */
956 dst_rect.h = height; /* (ignored) */
958 dst_rect2 = dst_rect;
960 // before fading in, store backbuffer (without animation graphics)
961 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
962 SDL_BlitSurface(surface_screen, &dst_rect, surface_backup, &src_rect);
964 /* copy source and target surfaces to temporary surfaces for fading */
965 if (fade_mode & FADE_TYPE_TRANSFORM)
967 // (source and target fading buffer already prepared)
969 else if (fade_mode & FADE_TYPE_FADE_IN)
971 // (target fading buffer already prepared)
972 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
974 else /* FADE_TYPE_FADE_OUT */
976 // (source fading buffer already prepared)
977 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
980 time_current = SDL_GetTicks();
982 if (fade_mode == FADE_MODE_MELT)
984 boolean done = FALSE;
986 int melt_columns = width / melt_pixels;
987 int ypos[melt_columns];
988 int max_steps = height / 8 + 32;
993 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
994 #if defined(TARGET_SDL2)
995 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
997 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1000 ypos[0] = -GetSimpleRandom(16);
1002 for (i = 1 ; i < melt_columns; i++)
1004 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1006 ypos[i] = ypos[i - 1] + r;
1019 time_last = time_current;
1020 time_current = SDL_GetTicks();
1021 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1022 steps_final = MIN(MAX(0, steps), max_steps);
1026 done = (steps_done >= steps_final);
1028 for (i = 0 ; i < melt_columns; i++)
1036 else if (ypos[i] < height)
1041 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1043 if (ypos[i] + dy >= height)
1044 dy = height - ypos[i];
1046 /* copy part of (appearing) target surface to upper area */
1047 src_rect.x = src_x + i * melt_pixels;
1048 // src_rect.y = src_y + ypos[i];
1050 src_rect.w = melt_pixels;
1052 src_rect.h = ypos[i] + dy;
1054 dst_rect.x = dst_x + i * melt_pixels;
1055 // dst_rect.y = dst_y + ypos[i];
1058 if (steps_done >= steps_final)
1059 SDL_BlitSurface(surface_target, &src_rect,
1060 surface_screen, &dst_rect);
1064 /* copy part of (disappearing) source surface to lower area */
1065 src_rect.x = src_x + i * melt_pixels;
1067 src_rect.w = melt_pixels;
1068 src_rect.h = height - ypos[i];
1070 dst_rect.x = dst_x + i * melt_pixels;
1071 dst_rect.y = dst_y + ypos[i];
1073 if (steps_done >= steps_final)
1074 SDL_BlitSurface(surface_source, &src_rect,
1075 surface_screen, &dst_rect);
1081 src_rect.x = src_x + i * melt_pixels;
1083 src_rect.w = melt_pixels;
1084 src_rect.h = height;
1086 dst_rect.x = dst_x + i * melt_pixels;
1089 if (steps_done >= steps_final)
1090 SDL_BlitSurface(surface_target, &src_rect,
1091 surface_screen, &dst_rect);
1095 if (steps_done >= steps_final)
1097 if (draw_border_function != NULL)
1098 draw_border_function();
1100 UpdateScreen_WithFrameDelay(&dst_rect2);
1104 else if (fade_mode == FADE_MODE_CURTAIN)
1108 int xx_size = width / 2;
1110 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1111 #if defined(TARGET_SDL2)
1112 SDL_SetSurfaceBlendMode(surface_source, SDL_BLENDMODE_NONE);
1114 SDL_SetAlpha(surface_source, 0, 0); /* disable alpha blending */
1117 for (xx = 0; xx < xx_size;)
1119 time_last = time_current;
1120 time_current = SDL_GetTicks();
1121 xx += xx_size * ((float)(time_current - time_last) / fade_delay);
1122 xx_final = MIN(MAX(0, xx), xx_size);
1127 src_rect.h = height;
1132 /* draw new (target) image to screen buffer */
1133 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1135 if (xx_final < xx_size)
1137 src_rect.w = xx_size - xx_final;
1138 src_rect.h = height;
1140 /* draw old (source) image to screen buffer (left side) */
1142 src_rect.x = src_x + xx_final;
1145 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1147 /* draw old (source) image to screen buffer (right side) */
1149 src_rect.x = src_x + xx_size;
1150 dst_rect.x = dst_x + xx_size + xx_final;
1152 SDL_BlitSurface(surface_source, &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_WithFrameDelay(&dst_rect2);
1162 else /* fading in, fading out or cross-fading */
1167 for (alpha = 0.0; alpha < 255.0;)
1169 time_last = time_current;
1170 time_current = SDL_GetTicks();
1171 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1172 alpha_final = MIN(MAX(0, alpha), 255);
1174 /* draw existing (source) image to screen buffer */
1175 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1177 /* draw new (target) image to screen buffer using alpha blending */
1178 #if defined(TARGET_SDL2)
1179 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1180 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1182 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1184 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1186 if (draw_border_function != NULL)
1187 draw_border_function();
1189 /* only update the region of the screen that is affected from fading */
1190 UpdateScreen_WithFrameDelay(&dst_rect);
1196 unsigned int time_post_delay;
1198 time_current = SDL_GetTicks();
1199 time_post_delay = time_current + post_delay;
1201 while (time_current < time_post_delay)
1203 // updating the screen contains waiting for frame delay (non-busy)
1204 UpdateScreen_WithFrameDelay(NULL);
1206 time_current = SDL_GetTicks();
1210 // restore function for drawing global masked border
1211 gfx.draw_global_border_function = draw_global_border_function;
1213 // after fading in, restore backbuffer (without animation graphics)
1214 if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM))
1215 SDL_BlitSurface(surface_backup, &dst_rect, surface_screen, &src_rect);
1218 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1219 int to_x, int to_y, Uint32 color)
1221 SDL_Surface *surface = dst_bitmap->surface;
1225 swap_numbers(&from_x, &to_x);
1228 swap_numbers(&from_y, &to_y);
1232 rect.w = (to_x - from_x + 1);
1233 rect.h = (to_y - from_y + 1);
1235 SDL_FillRect(surface, &rect, color);
1238 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1239 int to_x, int to_y, Uint32 color)
1241 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1244 #if ENABLE_UNUSED_CODE
1245 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1246 int num_points, Uint32 color)
1251 for (i = 0; i < num_points - 1; i++)
1253 for (x = 0; x < line_width; x++)
1255 for (y = 0; y < line_width; y++)
1257 int dx = x - line_width / 2;
1258 int dy = y - line_width / 2;
1260 if ((x == 0 && y == 0) ||
1261 (x == 0 && y == line_width - 1) ||
1262 (x == line_width - 1 && y == 0) ||
1263 (x == line_width - 1 && y == line_width - 1))
1266 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1267 points[i+1].x + dx, points[i+1].y + dy, color);
1274 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1276 SDL_Surface *surface = src_bitmap->surface;
1278 switch (surface->format->BytesPerPixel)
1280 case 1: /* assuming 8-bpp */
1282 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1286 case 2: /* probably 15-bpp or 16-bpp */
1288 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1292 case 3: /* slow 24-bpp mode; usually not used */
1294 /* does this work? */
1295 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1299 shift = surface->format->Rshift;
1300 color |= *(pix + shift / 8) >> shift;
1301 shift = surface->format->Gshift;
1302 color |= *(pix + shift / 8) >> shift;
1303 shift = surface->format->Bshift;
1304 color |= *(pix + shift / 8) >> shift;
1310 case 4: /* probably 32-bpp */
1312 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1321 /* ========================================================================= */
1322 /* The following functions were taken from the SGE library */
1323 /* (SDL Graphics Extension Library) by Anders Lindström */
1324 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1325 /* ========================================================================= */
1327 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1329 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1331 switch (surface->format->BytesPerPixel)
1335 /* Assuming 8-bpp */
1336 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1342 /* Probably 15-bpp or 16-bpp */
1343 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1349 /* Slow 24-bpp mode, usually not used */
1353 /* Gack - slow, but endian correct */
1354 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1355 shift = surface->format->Rshift;
1356 *(pix+shift/8) = color>>shift;
1357 shift = surface->format->Gshift;
1358 *(pix+shift/8) = color>>shift;
1359 shift = surface->format->Bshift;
1360 *(pix+shift/8) = color>>shift;
1366 /* Probably 32-bpp */
1367 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1374 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1375 Uint8 R, Uint8 G, Uint8 B)
1377 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1380 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1382 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1385 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1387 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1390 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1395 /* Gack - slow, but endian correct */
1396 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1397 shift = surface->format->Rshift;
1398 *(pix+shift/8) = color>>shift;
1399 shift = surface->format->Gshift;
1400 *(pix+shift/8) = color>>shift;
1401 shift = surface->format->Bshift;
1402 *(pix+shift/8) = color>>shift;
1405 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1407 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1410 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1412 switch (dest->format->BytesPerPixel)
1415 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1419 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1423 _PutPixel24(dest,x,y,color);
1427 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1432 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1434 if (SDL_MUSTLOCK(surface))
1436 if (SDL_LockSurface(surface) < 0)
1442 _PutPixel(surface, x, y, color);
1444 if (SDL_MUSTLOCK(surface))
1446 SDL_UnlockSurface(surface);
1450 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1451 Uint8 r, Uint8 g, Uint8 b)
1453 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1456 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1458 if (y >= 0 && y <= dest->h - 1)
1460 switch (dest->format->BytesPerPixel)
1463 return y*dest->pitch;
1467 return y*dest->pitch/2;
1471 return y*dest->pitch;
1475 return y*dest->pitch/4;
1483 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1485 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1487 switch (surface->format->BytesPerPixel)
1491 /* Assuming 8-bpp */
1492 *((Uint8 *)surface->pixels + ypitch + x) = color;
1498 /* Probably 15-bpp or 16-bpp */
1499 *((Uint16 *)surface->pixels + ypitch + x) = color;
1505 /* Slow 24-bpp mode, usually not used */
1509 /* Gack - slow, but endian correct */
1510 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1511 shift = surface->format->Rshift;
1512 *(pix+shift/8) = color>>shift;
1513 shift = surface->format->Gshift;
1514 *(pix+shift/8) = color>>shift;
1515 shift = surface->format->Bshift;
1516 *(pix+shift/8) = color>>shift;
1522 /* Probably 32-bpp */
1523 *((Uint32 *)surface->pixels + ypitch + x) = color;
1530 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1535 if (SDL_MUSTLOCK(Surface))
1537 if (SDL_LockSurface(Surface) < 0)
1550 /* Do the clipping */
1551 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1555 if (x2 > Surface->w - 1)
1556 x2 = Surface->w - 1;
1563 SDL_FillRect(Surface, &l, Color);
1565 if (SDL_MUSTLOCK(Surface))
1567 SDL_UnlockSurface(Surface);
1571 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1572 Uint8 R, Uint8 G, Uint8 B)
1574 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1577 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1588 /* Do the clipping */
1589 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1593 if (x2 > Surface->w - 1)
1594 x2 = Surface->w - 1;
1601 SDL_FillRect(Surface, &l, Color);
1604 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1609 if (SDL_MUSTLOCK(Surface))
1611 if (SDL_LockSurface(Surface) < 0)
1624 /* Do the clipping */
1625 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1629 if (y2 > Surface->h - 1)
1630 y2 = Surface->h - 1;
1637 SDL_FillRect(Surface, &l, Color);
1639 if (SDL_MUSTLOCK(Surface))
1641 SDL_UnlockSurface(Surface);
1645 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1646 Uint8 R, Uint8 G, Uint8 B)
1648 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1651 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1662 /* Do the clipping */
1663 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1667 if (y2 > Surface->h - 1)
1668 y2 = Surface->h - 1;
1675 SDL_FillRect(Surface, &l, Color);
1678 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1679 Sint16 x2, Sint16 y2, Uint32 Color,
1680 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1683 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1688 sdx = (dx < 0) ? -1 : 1;
1689 sdy = (dy < 0) ? -1 : 1;
1701 for (x = 0; x < dx; x++)
1703 Callback(Surface, px, py, Color);
1717 for (y = 0; y < dy; y++)
1719 Callback(Surface, px, py, Color);
1733 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1734 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1735 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1738 sge_DoLine(Surface, X1, Y1, X2, Y2,
1739 SDL_MapRGB(Surface->format, R, G, B), Callback);
1742 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1745 if (SDL_MUSTLOCK(Surface))
1747 if (SDL_LockSurface(Surface) < 0)
1752 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1754 /* unlock the display */
1755 if (SDL_MUSTLOCK(Surface))
1757 SDL_UnlockSurface(Surface);
1761 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1762 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1764 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1767 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1769 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1774 -----------------------------------------------------------------------------
1775 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1776 -----------------------------------------------------------------------------
1779 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1780 int width, int height, Uint32 color)
1784 for (y = src_y; y < src_y + height; y++)
1786 for (x = src_x; x < src_x + width; x++)
1788 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1790 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1795 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1796 int src_x, int src_y, int width, int height,
1797 int dst_x, int dst_y)
1801 for (y = 0; y < height; y++)
1803 for (x = 0; x < width; x++)
1805 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1807 if (pixel != BLACK_PIXEL)
1808 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1814 /* ========================================================================= */
1815 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1816 /* (Rotozoomer) by Andreas Schiffler */
1817 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1818 /* ========================================================================= */
1821 -----------------------------------------------------------------------------
1824 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1825 -----------------------------------------------------------------------------
1836 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1839 tColorRGBA *sp, *csp, *dp;
1843 sp = csp = (tColorRGBA *) src->pixels;
1844 dp = (tColorRGBA *) dst->pixels;
1845 dgap = dst->pitch - dst->w * 4;
1847 for (y = 0; y < dst->h; y++)
1851 for (x = 0; x < dst->w; x++)
1853 tColorRGBA *sp0 = sp;
1854 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1855 tColorRGBA *sp00 = &sp0[0];
1856 tColorRGBA *sp01 = &sp0[1];
1857 tColorRGBA *sp10 = &sp1[0];
1858 tColorRGBA *sp11 = &sp1[1];
1861 /* create new color pixel from all four source color pixels */
1862 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1863 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1864 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1865 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1870 /* advance source pointers */
1873 /* advance destination pointer */
1877 /* advance source pointer */
1878 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1880 /* advance destination pointers */
1881 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1887 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1889 int x, y, *sax, *say, *csax, *csay;
1891 tColorRGBA *sp, *csp, *csp0, *dp;
1894 /* use specialized zoom function when scaling down to exactly half size */
1895 if (src->w == 2 * dst->w &&
1896 src->h == 2 * dst->h)
1897 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1899 /* variable setup */
1900 sx = (float) src->w / (float) dst->w;
1901 sy = (float) src->h / (float) dst->h;
1903 /* allocate memory for row increments */
1904 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1905 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1907 /* precalculate row increments */
1908 for (x = 0; x <= dst->w; x++)
1909 *csax++ = (int)(sx * x);
1911 for (y = 0; y <= dst->h; y++)
1912 *csay++ = (int)(sy * y);
1915 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1916 dp = (tColorRGBA *) dst->pixels;
1917 dgap = dst->pitch - dst->w * 4;
1920 for (y = 0; y < dst->h; y++)
1925 for (x = 0; x < dst->w; x++)
1930 /* advance source pointers */
1934 /* advance destination pointer */
1938 /* advance source pointer */
1940 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1942 /* advance destination pointers */
1943 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1953 -----------------------------------------------------------------------------
1956 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1957 -----------------------------------------------------------------------------
1960 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1962 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1963 Uint8 *sp, *dp, *csp;
1966 /* variable setup */
1967 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1968 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1970 /* allocate memory for row increments */
1971 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1972 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1974 /* precalculate row increments */
1977 for (x = 0; x < dst->w; x++)
1980 *csax = (csx >> 16);
1987 for (y = 0; y < dst->h; y++)
1990 *csay = (csy >> 16);
1997 for (x = 0; x < dst->w; x++)
2005 for (y = 0; y < dst->h; y++)
2012 sp = csp = (Uint8 *) src->pixels;
2013 dp = (Uint8 *) dst->pixels;
2014 dgap = dst->pitch - dst->w;
2018 for (y = 0; y < dst->h; y++)
2022 for (x = 0; x < dst->w; x++)
2027 /* advance source pointers */
2031 /* advance destination pointer */
2035 /* advance source pointer (for row) */
2036 csp += ((*csay) * src->pitch);
2039 /* advance destination pointers */
2050 -----------------------------------------------------------------------------
2053 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2054 'zoomx' and 'zoomy' are scaling factors for width and height.
2055 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2056 into a 32bit RGBA format on the fly.
2057 -----------------------------------------------------------------------------
2060 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2062 SDL_Surface *zoom_src = NULL;
2063 SDL_Surface *zoom_dst = NULL;
2064 boolean is_converted = FALSE;
2071 /* determine if source surface is 32 bit or 8 bit */
2072 is_32bit = (src->format->BitsPerPixel == 32);
2074 if (is_32bit || src->format->BitsPerPixel == 8)
2076 /* use source surface 'as is' */
2081 /* new source surface is 32 bit with a defined RGB ordering */
2082 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2083 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2084 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2086 is_converted = TRUE;
2089 /* allocate surface to completely contain the zoomed surface */
2092 /* target surface is 32 bit with source RGBA/ABGR ordering */
2093 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2094 zoom_src->format->Rmask,
2095 zoom_src->format->Gmask,
2096 zoom_src->format->Bmask, 0);
2100 /* target surface is 8 bit */
2101 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2105 /* lock source surface */
2106 SDL_LockSurface(zoom_src);
2108 /* check which kind of surface we have */
2111 /* call the 32 bit transformation routine to do the zooming */
2112 zoomSurfaceRGBA(zoom_src, zoom_dst);
2117 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2118 zoom_dst->format->palette->colors[i] =
2119 zoom_src->format->palette->colors[i];
2120 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2122 /* call the 8 bit transformation routine to do the zooming */
2123 zoomSurfaceY(zoom_src, zoom_dst);
2126 /* unlock source surface */
2127 SDL_UnlockSurface(zoom_src);
2129 /* free temporary surface */
2131 SDL_FreeSurface(zoom_src);
2133 /* return destination surface */
2137 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2139 Bitmap *dst_bitmap = CreateBitmapStruct();
2140 SDL_Surface **dst_surface = &dst_bitmap->surface;
2142 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2143 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2145 dst_bitmap->width = dst_width;
2146 dst_bitmap->height = dst_height;
2148 /* create zoomed temporary surface from source surface */
2149 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2151 /* create native format destination surface from zoomed temporary surface */
2152 SDLSetNativeSurface(dst_surface);
2158 /* ========================================================================= */
2159 /* load image to bitmap */
2160 /* ========================================================================= */
2162 Bitmap *SDLLoadImage(char *filename)
2164 Bitmap *new_bitmap = CreateBitmapStruct();
2165 SDL_Surface *sdl_image_tmp;
2167 print_timestamp_init("SDLLoadImage");
2169 print_timestamp_time(getBaseNamePtr(filename));
2171 /* load image to temporary surface */
2172 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2174 SetError("IMG_Load(): %s", SDL_GetError());
2179 print_timestamp_time("IMG_Load");
2181 UPDATE_BUSY_STATE();
2183 /* create native non-transparent surface for current image */
2184 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2186 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2191 print_timestamp_time("SDL_DisplayFormat (opaque)");
2193 UPDATE_BUSY_STATE();
2195 /* create native transparent surface for current image */
2196 if (sdl_image_tmp->format->Amask == 0)
2197 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2198 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2200 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2202 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2207 print_timestamp_time("SDL_DisplayFormat (masked)");
2209 UPDATE_BUSY_STATE();
2211 /* free temporary surface */
2212 SDL_FreeSurface(sdl_image_tmp);
2214 new_bitmap->width = new_bitmap->surface->w;
2215 new_bitmap->height = new_bitmap->surface->h;
2217 print_timestamp_done("SDLLoadImage");
2223 /* ------------------------------------------------------------------------- */
2224 /* custom cursor fuctions */
2225 /* ------------------------------------------------------------------------- */
2227 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2229 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2230 cursor_info->width, cursor_info->height,
2231 cursor_info->hot_x, cursor_info->hot_y);
2234 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2236 static struct MouseCursorInfo *last_cursor_info = NULL;
2237 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2238 static SDL_Cursor *cursor_default = NULL;
2239 static SDL_Cursor *cursor_current = NULL;
2241 /* if invoked for the first time, store the SDL default cursor */
2242 if (cursor_default == NULL)
2243 cursor_default = SDL_GetCursor();
2245 /* only create new cursor if cursor info (custom only) has changed */
2246 if (cursor_info != NULL && cursor_info != last_cursor_info)
2248 cursor_current = create_cursor(cursor_info);
2249 last_cursor_info = cursor_info;
2252 /* only set new cursor if cursor info (custom or NULL) has changed */
2253 if (cursor_info != last_cursor_info2)
2254 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2256 last_cursor_info2 = cursor_info;
2260 /* ========================================================================= */
2261 /* audio functions */
2262 /* ========================================================================= */
2264 void SDLOpenAudio(void)
2266 #if !defined(TARGET_SDL2)
2267 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2268 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2271 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2273 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2277 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2278 AUDIO_NUM_CHANNELS_STEREO,
2279 setup.system.audio_fragment_size) < 0)
2281 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2285 audio.sound_available = TRUE;
2286 audio.music_available = TRUE;
2287 audio.loops_available = TRUE;
2288 audio.sound_enabled = TRUE;
2290 /* set number of available mixer channels */
2291 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2292 audio.music_channel = MUSIC_CHANNEL;
2293 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2295 Mixer_InitChannels();
2298 void SDLCloseAudio(void)
2301 Mix_HaltChannel(-1);
2304 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2308 /* ========================================================================= */
2309 /* event functions */
2310 /* ========================================================================= */
2312 void SDLNextEvent(Event *event)
2314 SDL_WaitEvent(event);
2317 void SDLHandleWindowManagerEvent(Event *event)
2320 #if defined(PLATFORM_WIN32)
2321 // experimental drag and drop code
2323 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2324 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2326 #if defined(TARGET_SDL2)
2327 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2329 if (syswmmsg->msg == WM_DROPFILES)
2332 #if defined(TARGET_SDL2)
2333 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2335 HDROP hdrop = (HDROP)syswmmsg->wParam;
2339 printf("::: SDL_SYSWMEVENT:\n");
2341 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2343 for (i = 0; i < num_files; i++)
2345 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2346 char buffer[buffer_len + 1];
2348 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2350 printf("::: - '%s'\n", buffer);
2353 #if defined(TARGET_SDL2)
2354 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2356 DragFinish((HDROP)syswmmsg->wParam);
2364 /* ========================================================================= */
2365 /* joystick functions */
2366 /* ========================================================================= */
2368 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2369 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2370 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2372 static boolean SDLOpenJoystick(int nr)
2374 if (nr < 0 || nr > MAX_PLAYERS)
2377 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2380 static void SDLCloseJoystick(int nr)
2382 if (nr < 0 || nr > MAX_PLAYERS)
2385 SDL_JoystickClose(sdl_joystick[nr]);
2387 sdl_joystick[nr] = NULL;
2390 static boolean SDLCheckJoystickOpened(int nr)
2392 if (nr < 0 || nr > MAX_PLAYERS)
2395 #if defined(TARGET_SDL2)
2396 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2398 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2402 void HandleJoystickEvent(Event *event)
2406 case SDL_JOYAXISMOTION:
2407 if (event->jaxis.axis < 2)
2408 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2411 case SDL_JOYBUTTONDOWN:
2412 if (event->jbutton.button < 2)
2413 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2416 case SDL_JOYBUTTONUP:
2417 if (event->jbutton.button < 2)
2418 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2426 void SDLInitJoysticks()
2428 static boolean sdl_joystick_subsystem_initialized = FALSE;
2429 boolean print_warning = !sdl_joystick_subsystem_initialized;
2432 if (!sdl_joystick_subsystem_initialized)
2434 sdl_joystick_subsystem_initialized = TRUE;
2436 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2438 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2443 for (i = 0; i < MAX_PLAYERS; i++)
2445 /* get configured joystick for this player */
2446 char *device_name = setup.input[i].joy.device_name;
2447 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2449 if (joystick_nr >= SDL_NumJoysticks())
2451 if (setup.input[i].use_joystick && print_warning)
2452 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2457 /* misuse joystick file descriptor variable to store joystick number */
2458 joystick.fd[i] = joystick_nr;
2460 if (joystick_nr == -1)
2463 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2464 if (SDLCheckJoystickOpened(joystick_nr))
2465 SDLCloseJoystick(joystick_nr);
2467 if (!setup.input[i].use_joystick)
2470 if (!SDLOpenJoystick(joystick_nr))
2473 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2478 joystick.status = JOYSTICK_ACTIVATED;
2482 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2484 if (nr < 0 || nr >= MAX_PLAYERS)
2488 *x = sdl_js_axis[nr][0];
2490 *y = sdl_js_axis[nr][1];
2493 *b1 = sdl_js_button[nr][0];
2495 *b2 = sdl_js_button[nr][1];