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 = NULL;
31 #define USE_RENDERER TRUE
34 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
35 static int fullscreen_width;
36 static int fullscreen_height;
37 static int fullscreen_xoffset;
38 static int fullscreen_yoffset;
39 static int video_xoffset;
40 static int video_yoffset;
41 static boolean limit_screen_updates = FALSE;
44 /* functions from SGE library */
45 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
47 void SDLLimitScreenUpdates(boolean enable)
49 limit_screen_updates = enable;
52 static void UpdateScreen(SDL_Rect *rect)
54 static unsigned int update_screen_delay = 0;
55 unsigned int update_screen_delay_value = 20; /* (milliseconds) */
57 if (limit_screen_updates &&
58 !DelayReached(&update_screen_delay, update_screen_delay_value))
61 LimitScreenUpdates(FALSE);
63 #if defined(TARGET_SDL2)
65 SDL_Surface *screen = backbuffer->surface;
69 int bytes_x = screen->pitch / video.width;
70 int bytes_y = screen->pitch;
72 if (video.fullscreen_enabled)
73 bytes_x = screen->pitch / fullscreen_width;
75 SDL_UpdateTexture(sdl_texture, rect,
76 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
81 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
83 SDL_RenderClear(sdl_renderer);
84 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
85 SDL_RenderPresent(sdl_renderer);
88 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
90 SDL_UpdateWindowSurface(sdl_window);
95 SDL_UpdateRects(backbuffer->surface, 1, rect);
97 SDL_UpdateRect(backbuffer->surface, 0, 0, 0, 0);
101 static void setFullscreenParameters(char *fullscreen_mode_string)
103 #if defined(TARGET_SDL2)
104 fullscreen_width = video.width;
105 fullscreen_height = video.height;
106 fullscreen_xoffset = 0;
107 fullscreen_yoffset = 0;
111 struct ScreenModeInfo *fullscreen_mode;
114 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
116 if (fullscreen_mode == NULL)
119 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
121 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
122 fullscreen_mode->height == video.fullscreen_modes[i].height)
124 fullscreen_width = fullscreen_mode->width;
125 fullscreen_height = fullscreen_mode->height;
127 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
128 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
136 static void SDLSetWindowIcon(char *basename)
138 /* (setting the window icon on Mac OS X would replace the high-quality
139 dock icon with the currently smaller (and uglier) icon from file) */
141 #if !defined(PLATFORM_MACOSX)
142 char *filename = getCustomImageFilename(basename);
143 SDL_Surface *surface;
145 if (filename == NULL)
147 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
152 if ((surface = IMG_Load(filename)) == NULL)
154 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
159 /* set transparent color */
160 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
161 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
163 #if defined(TARGET_SDL2)
164 SDL_SetWindowIcon(sdl_window, surface);
166 SDL_WM_SetIcon(surface, NULL);
171 #if defined(TARGET_SDL2)
173 static boolean equalSDLPixelFormat(SDL_PixelFormat *format1,
174 SDL_PixelFormat *format2)
176 return (format1->format == format2->format &&
177 format1->BitsPerPixel == format2->BitsPerPixel &&
178 format1->BytesPerPixel == format2->BytesPerPixel &&
179 format1->Rmask == format2->Rmask &&
180 format1->Gmask == format2->Gmask &&
181 format1->Bmask == format2->Bmask &&
182 format1->Amask == format2->Amask);
185 boolean SDLSetNativeSurface(SDL_Surface **surface)
187 SDL_Surface *new_surface;
189 if (surface == NULL ||
191 backbuffer == NULL ||
192 backbuffer->surface == NULL)
195 // if pixel format already optimized for destination surface, do nothing
196 if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format))
199 new_surface = SDL_ConvertSurface(*surface, backbuffer->surface->format, 0);
201 SDL_FreeSurface(*surface);
203 *surface = new_surface;
208 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
213 if (backbuffer == NULL ||
214 backbuffer->surface == NULL)
215 return SDL_ConvertSurface(surface, surface->format, 0);
217 return SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
222 boolean SDLSetNativeSurface(SDL_Surface **surface)
224 SDL_Surface *new_surface;
229 new_surface = SDL_DisplayFormat(*surface);
231 if (new_surface == NULL)
232 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
234 SDL_FreeSurface(*surface);
236 *surface = new_surface;
241 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
243 SDL_Surface *new_surface = SDL_DisplayFormat(surface);
245 if (new_surface == NULL)
246 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
253 void SDLInitVideoDisplay(void)
255 #if !defined(TARGET_SDL2)
256 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
257 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
259 SDL_putenv("SDL_VIDEO_CENTERED=1");
262 /* initialize SDL video */
263 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
264 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
266 /* set default SDL depth */
267 #if !defined(TARGET_SDL2)
268 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
270 video.default_depth = 32; // (how to determine video depth in SDL2?)
274 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
277 #if !defined(TARGET_SDL2)
278 static int screen_xy[][2] =
286 SDL_Rect **modes = NULL;
287 boolean hardware_fullscreen_available = TRUE;
290 /* default: normal game window size */
291 fullscreen_width = video.width;
292 fullscreen_height = video.height;
293 fullscreen_xoffset = 0;
294 fullscreen_yoffset = 0;
296 #if !defined(TARGET_SDL2)
297 /* determine required standard fullscreen mode for game screen size */
298 for (i = 0; screen_xy[i][0] != -1; i++)
300 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
302 fullscreen_width = screen_xy[i][0];
303 fullscreen_height = screen_xy[i][1];
309 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
310 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
313 checked_free(video.fullscreen_modes);
315 video.fullscreen_modes = NULL;
316 video.fullscreen_mode_current = NULL;
318 video.window_scaling_percent = setup.window_scaling_percent;
319 video.window_scaling_quality = setup.window_scaling_quality;
321 #if defined(TARGET_SDL2)
322 int num_displays = SDL_GetNumVideoDisplays();
324 if (num_displays > 0)
326 // currently only display modes of first display supported
327 int num_modes = SDL_GetNumDisplayModes(0);
331 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
333 for (i = 0; i < num_modes; i++)
335 SDL_DisplayMode mode;
337 if (SDL_GetDisplayMode(0, i, &mode) < 0)
340 modes[i] = checked_calloc(sizeof(SDL_Rect));
342 modes[i]->w = mode.w;
343 modes[i]->h = mode.h;
348 /* get available hardware supported fullscreen modes */
349 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
354 /* no hardware screen modes available => no fullscreen mode support */
355 // video.fullscreen_available = FALSE;
356 hardware_fullscreen_available = FALSE;
358 else if (modes == (SDL_Rect **)-1)
360 /* fullscreen resolution is not restricted -- all resolutions available */
361 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
363 /* use native video buffer size for fullscreen mode */
364 video.fullscreen_modes[0].width = video.width;
365 video.fullscreen_modes[0].height = video.height;
367 video.fullscreen_modes[1].width = -1;
368 video.fullscreen_modes[1].height = -1;
372 /* in this case, a certain number of screen modes is available */
375 for (i = 0; modes[i] != NULL; i++)
377 boolean found_mode = FALSE;
379 /* screen mode is smaller than video buffer size -- skip it */
380 if (modes[i]->w < video.width || modes[i]->h < video.height)
383 if (video.fullscreen_modes != NULL)
384 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
385 if (modes[i]->w == video.fullscreen_modes[j].width &&
386 modes[i]->h == video.fullscreen_modes[j].height)
389 if (found_mode) /* screen mode already stored -- skip it */
392 /* new mode found; add it to list of available fullscreen modes */
396 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
398 sizeof(struct ScreenModeInfo));
400 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
401 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
403 video.fullscreen_modes[num_modes].width = -1;
404 video.fullscreen_modes[num_modes].height = -1;
409 /* no appropriate screen modes available => no fullscreen mode support */
410 // video.fullscreen_available = FALSE;
411 hardware_fullscreen_available = FALSE;
415 video.fullscreen_available = hardware_fullscreen_available;
417 #if USE_DESKTOP_FULLSCREEN
418 // in SDL 2.0, there is always support for desktop fullscreen mode
419 // (in SDL 1.2, there is only support for "real" fullscreen mode)
420 video.fullscreen_available = TRUE;
423 #if defined(TARGET_SDL2)
426 for (i = 0; modes[i] != NULL; i++)
427 checked_free(modes[i]);
433 /* open SDL video output device (window or fullscreen mode) */
434 if (!SDLSetVideoMode(backbuffer, fullscreen))
435 Error(ERR_EXIT, "setting video mode failed");
437 /* !!! SDL2 can only set the window icon if the window already exists !!! */
438 /* set window icon */
439 SDLSetWindowIcon(program.sdl_icon_filename);
441 /* set window and icon title */
442 #if defined(TARGET_SDL2)
443 SDL_SetWindowTitle(sdl_window, program.window_title);
445 SDL_WM_SetCaption(program.window_title, program.window_title);
448 /* SDL cannot directly draw to the visible video framebuffer like X11,
449 but always uses a backbuffer, which is then blitted to the visible
450 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
451 visible video framebuffer with 'SDL_Flip', if the hardware supports
452 this). Therefore do not use an additional backbuffer for drawing, but
453 use a symbolic buffer (distinguishable from the SDL backbuffer) called
454 'window', which indicates that the SDL backbuffer should be updated to
455 the visible video framebuffer when attempting to blit to it.
457 For convenience, it seems to be a good idea to create this symbolic
458 buffer 'window' at the same size as the SDL backbuffer. Although it
459 should never be drawn to directly, it would do no harm nevertheless. */
461 /* create additional (symbolic) buffer for double-buffering */
462 ReCreateBitmap(window, video.width, video.height, video.depth);
465 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
468 SDL_Surface *new_surface = NULL;
470 #if defined(TARGET_SDL2)
471 static boolean fullscreen_enabled = FALSE;
472 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
473 #if USE_DESKTOP_FULLSCREEN
474 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
476 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
480 int surface_flags_window = SURFACE_FLAGS;
481 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
484 int width = (fullscreen ? fullscreen_width : video.width);
485 int height = (fullscreen ? fullscreen_height : video.height);
486 int surface_flags = (fullscreen ? surface_flags_fullscreen :
487 surface_flags_window);
489 // default window size is unscaled
490 video.window_width = video.width;
491 video.window_height = video.height;
493 #if defined(TARGET_SDL2)
495 // store if initial screen mode on game start is fullscreen mode
496 if (sdl_window == NULL)
497 video.fullscreen_initial = fullscreen;
500 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
501 #if !USE_DESKTOP_FULLSCREEN
502 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
505 video.window_width = window_scaling_factor * width;
506 video.window_height = window_scaling_factor * height;
508 if ((*backbuffer)->surface)
510 SDL_FreeSurface((*backbuffer)->surface);
511 (*backbuffer)->surface = NULL;
516 SDL_DestroyTexture(sdl_texture);
520 if (!(fullscreen && fullscreen_enabled))
524 SDL_DestroyRenderer(sdl_renderer);
530 SDL_DestroyWindow(sdl_window);
535 if (sdl_window == NULL)
536 sdl_window = SDL_CreateWindow(program.window_title,
537 SDL_WINDOWPOS_CENTERED,
538 SDL_WINDOWPOS_CENTERED,
539 #if USE_DESKTOP_FULLSCREEN
543 (int)(screen_scaling_factor * width),
544 (int)(screen_scaling_factor * height),
548 if (sdl_window != NULL)
551 /* if SDL_CreateRenderer() is called from within a VirtualBox Windows VM
552 *without* enabling 2D/3D acceleration and/or guest additions installed,
553 it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because
554 it will try to use accelerated graphics and apparently fails miserably) */
555 if (sdl_renderer == NULL)
556 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_SOFTWARE);
558 if (sdl_renderer == NULL)
559 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
562 if (sdl_renderer != NULL)
564 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
565 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
566 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality);
568 sdl_texture = SDL_CreateTexture(sdl_renderer,
569 SDL_PIXELFORMAT_ARGB8888,
570 SDL_TEXTUREACCESS_STREAMING,
573 if (sdl_texture != NULL)
575 // use SDL default values for RGB masks and no alpha channel
576 new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0);
578 if (new_surface == NULL)
579 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
584 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
589 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
594 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
600 SDL_DestroyWindow(sdl_window);
602 sdl_window = SDL_CreateWindow(program.window_title,
603 SDL_WINDOWPOS_CENTERED,
604 SDL_WINDOWPOS_CENTERED,
608 if (sdl_window != NULL)
609 new_surface = SDL_GetWindowSurface(sdl_window);
613 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
616 #if defined(TARGET_SDL2)
617 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
618 if (new_surface != NULL)
619 fullscreen_enabled = fullscreen;
625 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
627 boolean success = TRUE;
628 SDL_Surface *new_surface = NULL;
632 if (*backbuffer == NULL)
633 *backbuffer = CreateBitmapStruct();
635 /* (real bitmap might be larger in fullscreen mode with video offsets) */
636 (*backbuffer)->width = video.width;
637 (*backbuffer)->height = video.height;
639 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
641 setFullscreenParameters(setup.fullscreen_mode);
643 video_xoffset = fullscreen_xoffset;
644 video_yoffset = fullscreen_yoffset;
646 /* switch display to fullscreen mode, if available */
647 new_surface = SDLCreateScreen(backbuffer, TRUE);
649 if (new_surface == NULL)
651 /* switching display to fullscreen mode failed */
652 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
654 /* do not try it again */
655 video.fullscreen_available = FALSE;
661 (*backbuffer)->surface = new_surface;
663 video.fullscreen_enabled = TRUE;
664 video.fullscreen_mode_current = setup.fullscreen_mode;
670 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
675 /* switch display to window mode */
676 new_surface = SDLCreateScreen(backbuffer, FALSE);
678 if (new_surface == NULL)
680 /* switching display to window mode failed -- should not happen */
681 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
687 (*backbuffer)->surface = new_surface;
689 video.fullscreen_enabled = FALSE;
690 video.window_scaling_percent = setup.window_scaling_percent;
691 video.window_scaling_quality = setup.window_scaling_quality;
697 #if defined(TARGET_SDL2)
698 SDLRedrawWindow(); // map window
701 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
703 #if defined(PLATFORM_WIN32)
705 SDL_SysWMinfo wminfo;
707 boolean wminfo_success = FALSE;
709 SDL_VERSION(&wminfo.version);
710 #if defined(TARGET_SDL2)
712 wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo);
714 wminfo_success = (SDL_GetWMInfo(&wminfo) == 1);
719 #if defined(TARGET_SDL2)
720 hwnd = wminfo.info.win.window;
722 hwnd = wminfo.window;
725 DragAcceptFiles(hwnd, TRUE);
733 void SDLSetWindowTitle()
735 #if defined(TARGET_SDL2)
736 SDL_SetWindowTitle(sdl_window, program.window_title);
738 SDL_WM_SetCaption(program.window_title, program.window_title);
742 #if defined(TARGET_SDL2)
743 void SDLSetWindowScaling(int window_scaling_percent)
745 if (sdl_window == NULL)
748 float window_scaling_factor = (float)window_scaling_percent / 100;
749 int new_window_width = (int)(window_scaling_factor * video.width);
750 int new_window_height = (int)(window_scaling_factor * video.height);
752 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
754 video.window_scaling_percent = window_scaling_percent;
755 video.window_width = new_window_width;
756 video.window_height = new_window_height;
761 void SDLSetWindowScalingQuality(char *window_scaling_quality)
763 if (sdl_texture == NULL)
766 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality);
768 SDL_Texture *new_texture = SDL_CreateTexture(sdl_renderer,
769 SDL_PIXELFORMAT_ARGB8888,
770 SDL_TEXTUREACCESS_STREAMING,
771 video.width, video.height);
773 if (new_texture != NULL)
775 SDL_DestroyTexture(sdl_texture);
777 sdl_texture = new_texture;
782 video.window_scaling_quality = window_scaling_quality;
785 void SDLSetWindowFullscreen(boolean fullscreen)
787 if (sdl_window == NULL)
790 #if USE_DESKTOP_FULLSCREEN
791 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
793 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
796 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
797 video.fullscreen_enabled = fullscreen;
799 // if game started in fullscreen mode, window will also get fullscreen size
800 if (!fullscreen && video.fullscreen_initial)
802 SDLSetWindowScaling(setup.window_scaling_percent);
803 SDL_SetWindowPosition(sdl_window,
804 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
806 video.fullscreen_initial = FALSE;
810 void SDLRedrawWindow()
816 void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
819 SDL_Surface *surface =
820 SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
823 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
825 SDLSetNativeSurface(&surface);
827 bitmap->surface = surface;
830 void SDLFreeBitmapPointers(Bitmap *bitmap)
833 SDL_FreeSurface(bitmap->surface);
834 if (bitmap->surface_masked)
835 SDL_FreeSurface(bitmap->surface_masked);
836 bitmap->surface = NULL;
837 bitmap->surface_masked = NULL;
840 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
841 int src_x, int src_y, int width, int height,
842 int dst_x, int dst_y, int mask_mode)
844 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
845 SDL_Rect src_rect, dst_rect;
847 if (src_bitmap == backbuffer)
849 src_x += video_xoffset;
850 src_y += video_yoffset;
858 if (dst_bitmap == backbuffer || dst_bitmap == window)
860 dst_x += video_xoffset;
861 dst_y += video_yoffset;
869 // if (src_bitmap != backbuffer || dst_bitmap != window)
870 if (!(src_bitmap == backbuffer && dst_bitmap == window))
871 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
872 src_bitmap->surface_masked : src_bitmap->surface),
873 &src_rect, real_dst_bitmap->surface, &dst_rect);
875 #if defined(TARGET_SDL2)
876 if (dst_bitmap == window)
878 // SDL_UpdateWindowSurface(sdl_window);
879 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
880 UpdateScreen(&dst_rect);
883 if (dst_bitmap == window)
885 // SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
886 UpdateScreen(&dst_rect);
891 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
894 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
897 if (dst_bitmap == backbuffer || dst_bitmap == window)
908 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
910 #if defined(TARGET_SDL2)
911 if (dst_bitmap == window)
913 // SDL_UpdateWindowSurface(sdl_window);
914 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
918 if (dst_bitmap == window)
920 // SDL_UpdateRect(backbuffer->surface, x, y, width, height);
926 void SDLFadeRectangle(Bitmap *bitmap_cross, 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 static boolean initialization_needed = TRUE;
931 static SDL_Surface *surface_source = NULL;
932 static SDL_Surface *surface_target = NULL;
933 static SDL_Surface *surface_black = NULL;
934 SDL_Surface *surface_screen = backbuffer->surface;
935 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
936 SDL_Rect src_rect, dst_rect;
938 int src_x = x, src_y = y;
939 int dst_x = x, dst_y = y;
940 unsigned int time_last, time_current;
942 /* check if screen size has changed */
943 if (surface_source != NULL && (video.width != surface_source->w ||
944 video.height != surface_source->h))
946 SDL_FreeSurface(surface_source);
947 SDL_FreeSurface(surface_target);
948 SDL_FreeSurface(surface_black);
950 initialization_needed = TRUE;
958 dst_x += video_xoffset;
959 dst_y += video_yoffset;
963 dst_rect.w = width; /* (ignored) */
964 dst_rect.h = height; /* (ignored) */
966 dst_rect2 = dst_rect;
968 if (initialization_needed)
970 #if defined(TARGET_SDL2)
971 unsigned int flags = 0;
973 unsigned int flags = SDL_SRCALPHA;
975 /* use same surface type as screen surface */
976 if ((surface_screen->flags & SDL_HWSURFACE))
977 flags |= SDL_HWSURFACE;
979 flags |= SDL_SWSURFACE;
982 /* create surface for temporary copy of screen buffer (source) */
983 if ((surface_source =
984 SDL_CreateRGBSurface(flags,
987 surface_screen->format->BitsPerPixel,
988 surface_screen->format->Rmask,
989 surface_screen->format->Gmask,
990 surface_screen->format->Bmask,
991 surface_screen->format->Amask)) == NULL)
992 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
994 /* create surface for cross-fading screen buffer (target) */
995 if ((surface_target =
996 SDL_CreateRGBSurface(flags,
999 surface_screen->format->BitsPerPixel,
1000 surface_screen->format->Rmask,
1001 surface_screen->format->Gmask,
1002 surface_screen->format->Bmask,
1003 surface_screen->format->Amask)) == NULL)
1004 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1006 /* create black surface for fading from/to black */
1007 if ((surface_black =
1008 SDL_CreateRGBSurface(flags,
1011 surface_screen->format->BitsPerPixel,
1012 surface_screen->format->Rmask,
1013 surface_screen->format->Gmask,
1014 surface_screen->format->Bmask,
1015 surface_screen->format->Amask)) == NULL)
1016 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1018 /* completely fill the surface with black color pixels */
1019 SDL_FillRect(surface_black, NULL,
1020 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1022 initialization_needed = FALSE;
1025 /* copy source and target surfaces to temporary surfaces for fading */
1026 if (fade_mode & FADE_TYPE_TRANSFORM)
1028 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1029 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1031 else if (fade_mode & FADE_TYPE_FADE_IN)
1033 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1034 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1036 else /* FADE_TYPE_FADE_OUT */
1038 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1039 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1042 time_current = SDL_GetTicks();
1044 if (fade_mode == FADE_MODE_MELT)
1046 boolean done = FALSE;
1047 int melt_pixels = 2;
1048 int melt_columns = width / melt_pixels;
1049 int ypos[melt_columns];
1050 int max_steps = height / 8 + 32;
1055 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1056 #if defined(TARGET_SDL2)
1057 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1059 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1062 ypos[0] = -GetSimpleRandom(16);
1064 for (i = 1 ; i < melt_columns; i++)
1066 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1068 ypos[i] = ypos[i - 1] + r;
1081 time_last = time_current;
1082 time_current = SDL_GetTicks();
1083 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1084 steps_final = MIN(MAX(0, steps), max_steps);
1088 done = (steps_done >= steps_final);
1090 for (i = 0 ; i < melt_columns; i++)
1098 else if (ypos[i] < height)
1103 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1105 if (ypos[i] + dy >= height)
1106 dy = height - ypos[i];
1108 /* copy part of (appearing) target surface to upper area */
1109 src_rect.x = src_x + i * melt_pixels;
1110 // src_rect.y = src_y + ypos[i];
1112 src_rect.w = melt_pixels;
1114 src_rect.h = ypos[i] + dy;
1116 dst_rect.x = dst_x + i * melt_pixels;
1117 // dst_rect.y = dst_y + ypos[i];
1120 if (steps_done >= steps_final)
1121 SDL_BlitSurface(surface_target, &src_rect,
1122 surface_screen, &dst_rect);
1126 /* copy part of (disappearing) source surface to lower area */
1127 src_rect.x = src_x + i * melt_pixels;
1129 src_rect.w = melt_pixels;
1130 src_rect.h = height - ypos[i];
1132 dst_rect.x = dst_x + i * melt_pixels;
1133 dst_rect.y = dst_y + ypos[i];
1135 if (steps_done >= steps_final)
1136 SDL_BlitSurface(surface_source, &src_rect,
1137 surface_screen, &dst_rect);
1143 src_rect.x = src_x + i * melt_pixels;
1145 src_rect.w = melt_pixels;
1146 src_rect.h = height;
1148 dst_rect.x = dst_x + i * melt_pixels;
1151 if (steps_done >= steps_final)
1152 SDL_BlitSurface(surface_target, &src_rect,
1153 surface_screen, &dst_rect);
1157 if (steps_done >= steps_final)
1159 if (draw_border_function != NULL)
1160 draw_border_function();
1162 #if defined(TARGET_SDL2)
1163 // SDL_UpdateWindowSurface(sdl_window);
1164 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
1165 UpdateScreen(&dst_rect2);
1167 // SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1168 UpdateScreen(&dst_rect2);
1178 for (alpha = 0.0; alpha < 255.0;)
1180 time_last = time_current;
1181 time_current = SDL_GetTicks();
1182 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1183 alpha_final = MIN(MAX(0, alpha), 255);
1185 /* draw existing (source) image to screen buffer */
1186 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1188 /* draw new (target) image to screen buffer using alpha blending */
1189 #if defined(TARGET_SDL2)
1190 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1191 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1193 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1195 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1197 if (draw_border_function != NULL)
1198 draw_border_function();
1200 /* only update the region of the screen that is affected from fading */
1201 UpdateScreen(&dst_rect);
1208 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1209 int to_x, int to_y, Uint32 color)
1211 SDL_Surface *surface = dst_bitmap->surface;
1215 swap_numbers(&from_x, &to_x);
1218 swap_numbers(&from_y, &to_y);
1222 rect.w = (to_x - from_x + 1);
1223 rect.h = (to_y - from_y + 1);
1225 if (dst_bitmap == backbuffer || dst_bitmap == window)
1227 rect.x += video_xoffset;
1228 rect.y += video_yoffset;
1231 SDL_FillRect(surface, &rect, color);
1234 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1235 int to_x, int to_y, Uint32 color)
1237 if (dst_bitmap == backbuffer || dst_bitmap == window)
1239 from_x += video_xoffset;
1240 from_y += video_yoffset;
1241 to_x += video_xoffset;
1242 to_y += video_yoffset;
1245 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1248 #if ENABLE_UNUSED_CODE
1249 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1250 int num_points, Uint32 color)
1255 for (i = 0; i < num_points - 1; i++)
1257 for (x = 0; x < line_width; x++)
1259 for (y = 0; y < line_width; y++)
1261 int dx = x - line_width / 2;
1262 int dy = y - line_width / 2;
1264 if ((x == 0 && y == 0) ||
1265 (x == 0 && y == line_width - 1) ||
1266 (x == line_width - 1 && y == 0) ||
1267 (x == line_width - 1 && y == line_width - 1))
1270 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1271 points[i+1].x + dx, points[i+1].y + dy, color);
1278 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1280 SDL_Surface *surface = src_bitmap->surface;
1282 if (src_bitmap == backbuffer || src_bitmap == window)
1288 switch (surface->format->BytesPerPixel)
1290 case 1: /* assuming 8-bpp */
1292 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1296 case 2: /* probably 15-bpp or 16-bpp */
1298 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1302 case 3: /* slow 24-bpp mode; usually not used */
1304 /* does this work? */
1305 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1309 shift = surface->format->Rshift;
1310 color |= *(pix + shift / 8) >> shift;
1311 shift = surface->format->Gshift;
1312 color |= *(pix + shift / 8) >> shift;
1313 shift = surface->format->Bshift;
1314 color |= *(pix + shift / 8) >> shift;
1320 case 4: /* probably 32-bpp */
1322 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1331 /* ========================================================================= */
1332 /* The following functions were taken from the SGE library */
1333 /* (SDL Graphics Extension Library) by Anders Lindström */
1334 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1335 /* ========================================================================= */
1337 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1339 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1341 switch (surface->format->BytesPerPixel)
1345 /* Assuming 8-bpp */
1346 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1352 /* Probably 15-bpp or 16-bpp */
1353 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1359 /* Slow 24-bpp mode, usually not used */
1363 /* Gack - slow, but endian correct */
1364 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1365 shift = surface->format->Rshift;
1366 *(pix+shift/8) = color>>shift;
1367 shift = surface->format->Gshift;
1368 *(pix+shift/8) = color>>shift;
1369 shift = surface->format->Bshift;
1370 *(pix+shift/8) = color>>shift;
1376 /* Probably 32-bpp */
1377 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1384 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1385 Uint8 R, Uint8 G, Uint8 B)
1387 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1390 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1392 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1395 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1397 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1400 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1405 /* Gack - slow, but endian correct */
1406 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1407 shift = surface->format->Rshift;
1408 *(pix+shift/8) = color>>shift;
1409 shift = surface->format->Gshift;
1410 *(pix+shift/8) = color>>shift;
1411 shift = surface->format->Bshift;
1412 *(pix+shift/8) = color>>shift;
1415 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1417 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1420 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1422 switch (dest->format->BytesPerPixel)
1425 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1429 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1433 _PutPixel24(dest,x,y,color);
1437 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1442 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1444 if (SDL_MUSTLOCK(surface))
1446 if (SDL_LockSurface(surface) < 0)
1452 _PutPixel(surface, x, y, color);
1454 if (SDL_MUSTLOCK(surface))
1456 SDL_UnlockSurface(surface);
1460 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1461 Uint8 r, Uint8 g, Uint8 b)
1463 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1466 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1468 if (y >= 0 && y <= dest->h - 1)
1470 switch (dest->format->BytesPerPixel)
1473 return y*dest->pitch;
1477 return y*dest->pitch/2;
1481 return y*dest->pitch;
1485 return y*dest->pitch/4;
1493 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1495 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1497 switch (surface->format->BytesPerPixel)
1501 /* Assuming 8-bpp */
1502 *((Uint8 *)surface->pixels + ypitch + x) = color;
1508 /* Probably 15-bpp or 16-bpp */
1509 *((Uint16 *)surface->pixels + ypitch + x) = color;
1515 /* Slow 24-bpp mode, usually not used */
1519 /* Gack - slow, but endian correct */
1520 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1521 shift = surface->format->Rshift;
1522 *(pix+shift/8) = color>>shift;
1523 shift = surface->format->Gshift;
1524 *(pix+shift/8) = color>>shift;
1525 shift = surface->format->Bshift;
1526 *(pix+shift/8) = color>>shift;
1532 /* Probably 32-bpp */
1533 *((Uint32 *)surface->pixels + ypitch + x) = color;
1540 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1545 if (SDL_MUSTLOCK(Surface))
1547 if (SDL_LockSurface(Surface) < 0)
1560 /* Do the clipping */
1561 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1565 if (x2 > Surface->w - 1)
1566 x2 = Surface->w - 1;
1573 SDL_FillRect(Surface, &l, Color);
1575 if (SDL_MUSTLOCK(Surface))
1577 SDL_UnlockSurface(Surface);
1581 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1582 Uint8 R, Uint8 G, Uint8 B)
1584 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1587 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1598 /* Do the clipping */
1599 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1603 if (x2 > Surface->w - 1)
1604 x2 = Surface->w - 1;
1611 SDL_FillRect(Surface, &l, Color);
1614 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1619 if (SDL_MUSTLOCK(Surface))
1621 if (SDL_LockSurface(Surface) < 0)
1634 /* Do the clipping */
1635 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1639 if (y2 > Surface->h - 1)
1640 y2 = Surface->h - 1;
1647 SDL_FillRect(Surface, &l, Color);
1649 if (SDL_MUSTLOCK(Surface))
1651 SDL_UnlockSurface(Surface);
1655 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1656 Uint8 R, Uint8 G, Uint8 B)
1658 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1661 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1672 /* Do the clipping */
1673 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1677 if (y2 > Surface->h - 1)
1678 y2 = Surface->h - 1;
1685 SDL_FillRect(Surface, &l, Color);
1688 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1689 Sint16 x2, Sint16 y2, Uint32 Color,
1690 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1693 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1698 sdx = (dx < 0) ? -1 : 1;
1699 sdy = (dy < 0) ? -1 : 1;
1711 for (x = 0; x < dx; x++)
1713 Callback(Surface, px, py, Color);
1727 for (y = 0; y < dy; y++)
1729 Callback(Surface, px, py, Color);
1743 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1744 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1745 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1748 sge_DoLine(Surface, X1, Y1, X2, Y2,
1749 SDL_MapRGB(Surface->format, R, G, B), Callback);
1752 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1755 if (SDL_MUSTLOCK(Surface))
1757 if (SDL_LockSurface(Surface) < 0)
1762 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1764 /* unlock the display */
1765 if (SDL_MUSTLOCK(Surface))
1767 SDL_UnlockSurface(Surface);
1771 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1772 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1774 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1777 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1779 if (dst_bitmap == backbuffer || dst_bitmap == window)
1785 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1790 -----------------------------------------------------------------------------
1791 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1792 -----------------------------------------------------------------------------
1795 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1796 int width, int height, Uint32 color)
1800 for (y = src_y; y < src_y + height; y++)
1802 for (x = src_x; x < src_x + width; x++)
1804 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1806 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1811 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1812 int src_x, int src_y, int width, int height,
1813 int dst_x, int dst_y)
1817 for (y = 0; y < height; y++)
1819 for (x = 0; x < width; x++)
1821 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1823 if (pixel != BLACK_PIXEL)
1824 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1830 /* ========================================================================= */
1831 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1832 /* (Rotozoomer) by Andreas Schiffler */
1833 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1834 /* ========================================================================= */
1837 -----------------------------------------------------------------------------
1840 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1841 -----------------------------------------------------------------------------
1852 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1855 tColorRGBA *sp, *csp, *dp;
1859 sp = csp = (tColorRGBA *) src->pixels;
1860 dp = (tColorRGBA *) dst->pixels;
1861 dgap = dst->pitch - dst->w * 4;
1863 for (y = 0; y < dst->h; y++)
1867 for (x = 0; x < dst->w; x++)
1869 tColorRGBA *sp0 = sp;
1870 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1871 tColorRGBA *sp00 = &sp0[0];
1872 tColorRGBA *sp01 = &sp0[1];
1873 tColorRGBA *sp10 = &sp1[0];
1874 tColorRGBA *sp11 = &sp1[1];
1877 /* create new color pixel from all four source color pixels */
1878 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1879 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1880 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1881 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1886 /* advance source pointers */
1889 /* advance destination pointer */
1893 /* advance source pointer */
1894 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1896 /* advance destination pointers */
1897 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1903 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1905 int x, y, *sax, *say, *csax, *csay;
1907 tColorRGBA *sp, *csp, *csp0, *dp;
1910 /* use specialized zoom function when scaling down to exactly half size */
1911 if (src->w == 2 * dst->w &&
1912 src->h == 2 * dst->h)
1913 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1915 /* variable setup */
1916 sx = (float) src->w / (float) dst->w;
1917 sy = (float) src->h / (float) dst->h;
1919 /* allocate memory for row increments */
1920 csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1921 csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1923 /* precalculate row increments */
1924 for (x = 0; x <= dst->w; x++)
1925 *csax++ = (int)(sx * x);
1927 for (y = 0; y <= dst->h; y++)
1928 *csay++ = (int)(sy * y);
1931 sp = csp = csp0 = (tColorRGBA *) src->pixels;
1932 dp = (tColorRGBA *) dst->pixels;
1933 dgap = dst->pitch - dst->w * 4;
1936 for (y = 0; y < dst->h; y++)
1941 for (x = 0; x < dst->w; x++)
1946 /* advance source pointers */
1950 /* advance destination pointer */
1954 /* advance source pointer */
1956 csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch);
1958 /* advance destination pointers */
1959 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1969 -----------------------------------------------------------------------------
1972 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1973 -----------------------------------------------------------------------------
1976 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1978 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1979 Uint8 *sp, *dp, *csp;
1982 /* variable setup */
1983 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1984 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1986 /* allocate memory for row increments */
1987 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1988 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1990 /* precalculate row increments */
1993 for (x = 0; x < dst->w; x++)
1996 *csax = (csx >> 16);
2003 for (y = 0; y < dst->h; y++)
2006 *csay = (csy >> 16);
2013 for (x = 0; x < dst->w; x++)
2021 for (y = 0; y < dst->h; y++)
2028 sp = csp = (Uint8 *) src->pixels;
2029 dp = (Uint8 *) dst->pixels;
2030 dgap = dst->pitch - dst->w;
2034 for (y = 0; y < dst->h; y++)
2038 for (x = 0; x < dst->w; x++)
2043 /* advance source pointers */
2047 /* advance destination pointer */
2051 /* advance source pointer (for row) */
2052 csp += ((*csay) * src->pitch);
2055 /* advance destination pointers */
2066 -----------------------------------------------------------------------------
2069 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2070 'zoomx' and 'zoomy' are scaling factors for width and height.
2071 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2072 into a 32bit RGBA format on the fly.
2073 -----------------------------------------------------------------------------
2076 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2078 SDL_Surface *zoom_src = NULL;
2079 SDL_Surface *zoom_dst = NULL;
2080 boolean is_converted = FALSE;
2087 /* determine if source surface is 32 bit or 8 bit */
2088 is_32bit = (src->format->BitsPerPixel == 32);
2090 if (is_32bit || src->format->BitsPerPixel == 8)
2092 /* use source surface 'as is' */
2097 /* new source surface is 32 bit with a defined RGB ordering */
2098 zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32,
2099 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2100 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2102 is_converted = TRUE;
2105 /* allocate surface to completely contain the zoomed surface */
2108 /* target surface is 32 bit with source RGBA/ABGR ordering */
2109 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32,
2110 zoom_src->format->Rmask,
2111 zoom_src->format->Gmask,
2112 zoom_src->format->Bmask, 0);
2116 /* target surface is 8 bit */
2117 zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8,
2121 /* lock source surface */
2122 SDL_LockSurface(zoom_src);
2124 /* check which kind of surface we have */
2127 /* call the 32 bit transformation routine to do the zooming */
2128 zoomSurfaceRGBA(zoom_src, zoom_dst);
2133 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2134 zoom_dst->format->palette->colors[i] =
2135 zoom_src->format->palette->colors[i];
2136 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2138 /* call the 8 bit transformation routine to do the zooming */
2139 zoomSurfaceY(zoom_src, zoom_dst);
2142 /* unlock source surface */
2143 SDL_UnlockSurface(zoom_src);
2145 /* free temporary surface */
2147 SDL_FreeSurface(zoom_src);
2149 /* return destination surface */
2153 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
2155 Bitmap *dst_bitmap = CreateBitmapStruct();
2156 SDL_Surface **dst_surface = &dst_bitmap->surface;
2158 dst_width = MAX(1, dst_width); /* prevent zero bitmap width */
2159 dst_height = MAX(1, dst_height); /* prevent zero bitmap height */
2161 dst_bitmap->width = dst_width;
2162 dst_bitmap->height = dst_height;
2164 /* create zoomed temporary surface from source surface */
2165 *dst_surface = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2167 /* create native format destination surface from zoomed temporary surface */
2168 SDLSetNativeSurface(dst_surface);
2174 /* ========================================================================= */
2175 /* load image to bitmap */
2176 /* ========================================================================= */
2178 Bitmap *SDLLoadImage(char *filename)
2180 Bitmap *new_bitmap = CreateBitmapStruct();
2181 SDL_Surface *sdl_image_tmp;
2183 print_timestamp_init("SDLLoadImage");
2185 print_timestamp_time(getBaseNamePtr(filename));
2187 /* load image to temporary surface */
2188 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2190 SetError("IMG_Load(): %s", SDL_GetError());
2195 print_timestamp_time("IMG_Load");
2197 UPDATE_BUSY_STATE();
2199 /* create native non-transparent surface for current image */
2200 if ((new_bitmap->surface = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2202 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2207 print_timestamp_time("SDL_DisplayFormat (opaque)");
2209 UPDATE_BUSY_STATE();
2211 /* create native transparent surface for current image */
2212 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2213 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2215 if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL)
2217 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2222 print_timestamp_time("SDL_DisplayFormat (masked)");
2224 UPDATE_BUSY_STATE();
2226 /* free temporary surface */
2227 SDL_FreeSurface(sdl_image_tmp);
2229 new_bitmap->width = new_bitmap->surface->w;
2230 new_bitmap->height = new_bitmap->surface->h;
2232 print_timestamp_done("SDLLoadImage");
2238 /* ------------------------------------------------------------------------- */
2239 /* custom cursor fuctions */
2240 /* ------------------------------------------------------------------------- */
2242 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2244 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2245 cursor_info->width, cursor_info->height,
2246 cursor_info->hot_x, cursor_info->hot_y);
2249 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2251 static struct MouseCursorInfo *last_cursor_info = NULL;
2252 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2253 static SDL_Cursor *cursor_default = NULL;
2254 static SDL_Cursor *cursor_current = NULL;
2256 /* if invoked for the first time, store the SDL default cursor */
2257 if (cursor_default == NULL)
2258 cursor_default = SDL_GetCursor();
2260 /* only create new cursor if cursor info (custom only) has changed */
2261 if (cursor_info != NULL && cursor_info != last_cursor_info)
2263 cursor_current = create_cursor(cursor_info);
2264 last_cursor_info = cursor_info;
2267 /* only set new cursor if cursor info (custom or NULL) has changed */
2268 if (cursor_info != last_cursor_info2)
2269 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2271 last_cursor_info2 = cursor_info;
2275 /* ========================================================================= */
2276 /* audio functions */
2277 /* ========================================================================= */
2279 void SDLOpenAudio(void)
2281 #if !defined(TARGET_SDL2)
2282 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2283 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2286 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2288 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2292 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2293 AUDIO_NUM_CHANNELS_STEREO,
2294 setup.system.audio_fragment_size) < 0)
2296 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2300 audio.sound_available = TRUE;
2301 audio.music_available = TRUE;
2302 audio.loops_available = TRUE;
2303 audio.sound_enabled = TRUE;
2305 /* set number of available mixer channels */
2306 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2307 audio.music_channel = MUSIC_CHANNEL;
2308 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2310 Mixer_InitChannels();
2313 void SDLCloseAudio(void)
2316 Mix_HaltChannel(-1);
2319 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2323 /* ========================================================================= */
2324 /* event functions */
2325 /* ========================================================================= */
2327 void SDLNextEvent(Event *event)
2329 SDL_WaitEvent(event);
2331 if (event->type == EVENT_BUTTONPRESS ||
2332 event->type == EVENT_BUTTONRELEASE)
2334 if (((ButtonEvent *)event)->x > video_xoffset)
2335 ((ButtonEvent *)event)->x -= video_xoffset;
2337 ((ButtonEvent *)event)->x = 0;
2338 if (((ButtonEvent *)event)->y > video_yoffset)
2339 ((ButtonEvent *)event)->y -= video_yoffset;
2341 ((ButtonEvent *)event)->y = 0;
2343 else if (event->type == EVENT_MOTIONNOTIFY)
2345 if (((MotionEvent *)event)->x > video_xoffset)
2346 ((MotionEvent *)event)->x -= video_xoffset;
2348 ((MotionEvent *)event)->x = 0;
2349 if (((MotionEvent *)event)->y > video_yoffset)
2350 ((MotionEvent *)event)->y -= video_yoffset;
2352 ((MotionEvent *)event)->y = 0;
2356 void SDLHandleWindowManagerEvent(Event *event)
2358 #if defined(PLATFORM_WIN32)
2359 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2360 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2362 #if defined(TARGET_SDL2)
2363 if (syswmmsg->msg.win.msg == WM_DROPFILES)
2365 if (syswmmsg->msg == WM_DROPFILES)
2368 #if defined(TARGET_SDL2)
2369 HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam;
2371 HDROP hdrop = (HDROP)syswmmsg->wParam;
2375 printf("::: SDL_SYSWMEVENT:\n");
2377 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2379 for (i = 0; i < num_files; i++)
2381 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2382 char buffer[buffer_len + 1];
2384 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2386 printf("::: - '%s'\n", buffer);
2389 #if defined(TARGET_SDL2)
2390 DragFinish((HDROP)syswmmsg->msg.win.wParam);
2392 DragFinish((HDROP)syswmmsg->wParam);
2399 /* ========================================================================= */
2400 /* joystick functions */
2401 /* ========================================================================= */
2403 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2404 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2405 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2407 static boolean SDLOpenJoystick(int nr)
2409 if (nr < 0 || nr > MAX_PLAYERS)
2412 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2415 static void SDLCloseJoystick(int nr)
2417 if (nr < 0 || nr > MAX_PLAYERS)
2420 SDL_JoystickClose(sdl_joystick[nr]);
2422 sdl_joystick[nr] = NULL;
2425 static boolean SDLCheckJoystickOpened(int nr)
2427 if (nr < 0 || nr > MAX_PLAYERS)
2430 #if defined(TARGET_SDL2)
2431 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2433 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2437 void HandleJoystickEvent(Event *event)
2441 case SDL_JOYAXISMOTION:
2442 if (event->jaxis.axis < 2)
2443 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2446 case SDL_JOYBUTTONDOWN:
2447 if (event->jbutton.button < 2)
2448 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2451 case SDL_JOYBUTTONUP:
2452 if (event->jbutton.button < 2)
2453 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2461 void SDLInitJoysticks()
2463 static boolean sdl_joystick_subsystem_initialized = FALSE;
2464 boolean print_warning = !sdl_joystick_subsystem_initialized;
2467 if (!sdl_joystick_subsystem_initialized)
2469 sdl_joystick_subsystem_initialized = TRUE;
2471 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2473 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2478 for (i = 0; i < MAX_PLAYERS; i++)
2480 /* get configured joystick for this player */
2481 char *device_name = setup.input[i].joy.device_name;
2482 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2484 if (joystick_nr >= SDL_NumJoysticks())
2486 if (setup.input[i].use_joystick && print_warning)
2487 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2492 /* misuse joystick file descriptor variable to store joystick number */
2493 joystick.fd[i] = joystick_nr;
2495 if (joystick_nr == -1)
2498 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2499 if (SDLCheckJoystickOpened(joystick_nr))
2500 SDLCloseJoystick(joystick_nr);
2502 if (!setup.input[i].use_joystick)
2505 if (!SDLOpenJoystick(joystick_nr))
2508 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2513 joystick.status = JOYSTICK_ACTIVATED;
2517 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2519 if (nr < 0 || nr >= MAX_PLAYERS)
2523 *x = sdl_js_axis[nr][0];
2525 *y = sdl_js_axis[nr][1];
2528 *b1 = sdl_js_button[nr][0];
2530 *b2 = sdl_js_button[nr][1];