1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
21 #if defined(TARGET_SDL)
23 /* ========================================================================= */
25 /* ========================================================================= */
27 /* SDL internal variables */
28 #if defined(TARGET_SDL2)
29 static SDL_Window *sdl_window = NULL;
30 static SDL_Renderer *sdl_renderer = NULL;
31 static SDL_Texture *sdl_texture = NULL;
33 #define USE_RENDERER TRUE
36 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
37 static int fullscreen_width;
38 static int fullscreen_height;
39 static int fullscreen_xoffset;
40 static int fullscreen_yoffset;
41 static int video_xoffset;
42 static int video_yoffset;
44 /* functions from SGE library */
45 void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
47 #if defined(TARGET_SDL2)
48 static void UpdateScreen(SDL_Rect *rect)
51 SDL_Surface *screen = backbuffer->surface;
56 int bytes_x = screen->pitch / video.width;
57 int bytes_y = screen->pitch;
59 if (video.fullscreen_enabled)
60 bytes_x = screen->pitch / fullscreen_width;
62 SDL_UpdateTexture(sdl_texture, rect,
63 screen->pixels + rect->x * bytes_x + rect->y * bytes_y,
68 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
71 SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch);
73 SDL_RenderClear(sdl_renderer);
74 SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
75 SDL_RenderPresent(sdl_renderer);
78 SDL_UpdateWindowSurfaceRects(sdl_window, rect, 1);
80 SDL_UpdateWindowSurface(sdl_window);
85 static void setFullscreenParameters(char *fullscreen_mode_string)
87 #if defined(TARGET_SDL2)
88 fullscreen_width = video.width;
89 fullscreen_height = video.height;
90 fullscreen_xoffset = 0;
91 fullscreen_yoffset = 0;
95 struct ScreenModeInfo *fullscreen_mode;
98 fullscreen_mode = get_screen_mode_from_string(fullscreen_mode_string);
100 if (fullscreen_mode == NULL)
103 for (i = 0; video.fullscreen_modes[i].width != -1; i++)
105 if (fullscreen_mode->width == video.fullscreen_modes[i].width &&
106 fullscreen_mode->height == video.fullscreen_modes[i].height)
108 fullscreen_width = fullscreen_mode->width;
109 fullscreen_height = fullscreen_mode->height;
111 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
112 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
120 static void SDLSetWindowIcon(char *basename)
122 /* (setting the window icon on Mac OS X would replace the high-quality
123 dock icon with the currently smaller (and uglier) icon from file) */
125 #if !defined(PLATFORM_MACOSX)
126 char *filename = getCustomImageFilename(basename);
127 SDL_Surface *surface;
129 if (filename == NULL)
131 Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename);
136 if ((surface = IMG_Load(filename)) == NULL)
138 Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError());
143 /* set transparent color */
144 SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL,
145 SDL_MapRGB(surface->format, 0x00, 0x00, 0x00));
147 #if defined(TARGET_SDL2)
148 SDL_SetWindowIcon(sdl_window, surface);
150 SDL_WM_SetIcon(surface, NULL);
155 #if defined(TARGET_SDL2)
156 SDL_Surface *SDL_DisplayFormat(SDL_Surface *surface)
158 if (backbuffer == NULL ||
159 backbuffer->surface == NULL)
162 return SDL_ConvertSurface(surface, backbuffer->surface->format, 0);
166 void SDLInitVideoDisplay(void)
168 #if !defined(TARGET_SDL2)
169 if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT))
170 SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver));
172 SDL_putenv("SDL_VIDEO_CENTERED=1");
175 /* initialize SDL video */
176 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
177 Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
179 /* set default SDL depth */
180 #if !defined(TARGET_SDL2)
181 video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
183 video.default_depth = 32; // (how to determine video depth in SDL2?)
187 void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
190 #if !defined(TARGET_SDL2)
191 static int screen_xy[][2] =
199 SDL_Rect **modes = NULL;
200 boolean hardware_fullscreen_available = TRUE;
203 /* default: normal game window size */
204 fullscreen_width = video.width;
205 fullscreen_height = video.height;
206 fullscreen_xoffset = 0;
207 fullscreen_yoffset = 0;
209 #if !defined(TARGET_SDL2)
210 /* determine required standard fullscreen mode for game screen size */
211 for (i = 0; screen_xy[i][0] != -1; i++)
213 if (screen_xy[i][0] >= video.width && screen_xy[i][1] >= video.height)
215 fullscreen_width = screen_xy[i][0];
216 fullscreen_height = screen_xy[i][1];
222 fullscreen_xoffset = (fullscreen_width - video.width) / 2;
223 fullscreen_yoffset = (fullscreen_height - video.height) / 2;
227 checked_free(video.fullscreen_modes);
229 video.fullscreen_modes = NULL;
230 video.fullscreen_mode_current = NULL;
233 video.window_scaling_percent = setup.window_scaling_percent;
235 #if defined(TARGET_SDL2)
236 int num_displays = SDL_GetNumVideoDisplays();
238 if (num_displays > 0)
240 // currently only display modes of first display supported
241 int num_modes = SDL_GetNumDisplayModes(0);
245 modes = checked_calloc((num_modes + 1) * sizeof(SDL_Rect *));
247 for (i = 0; i < num_modes; i++)
249 SDL_DisplayMode mode;
251 if (SDL_GetDisplayMode(0, i, &mode) < 0)
254 modes[i] = checked_calloc(sizeof(SDL_Rect));
256 modes[i]->w = mode.w;
257 modes[i]->h = mode.h;
262 /* get available hardware supported fullscreen modes */
263 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
268 /* no hardware screen modes available => no fullscreen mode support */
269 // video.fullscreen_available = FALSE;
270 hardware_fullscreen_available = FALSE;
272 else if (modes == (SDL_Rect **)-1)
274 /* fullscreen resolution is not restricted -- all resolutions available */
275 video.fullscreen_modes = checked_calloc(2 * sizeof(struct ScreenModeInfo));
277 /* use native video buffer size for fullscreen mode */
278 video.fullscreen_modes[0].width = video.width;
279 video.fullscreen_modes[0].height = video.height;
281 video.fullscreen_modes[1].width = -1;
282 video.fullscreen_modes[1].height = -1;
286 /* in this case, a certain number of screen modes is available */
289 for (i = 0; modes[i] != NULL; i++)
291 boolean found_mode = FALSE;
293 /* screen mode is smaller than video buffer size -- skip it */
294 if (modes[i]->w < video.width || modes[i]->h < video.height)
297 if (video.fullscreen_modes != NULL)
298 for (j = 0; video.fullscreen_modes[j].width != -1; j++)
299 if (modes[i]->w == video.fullscreen_modes[j].width &&
300 modes[i]->h == video.fullscreen_modes[j].height)
303 if (found_mode) /* screen mode already stored -- skip it */
306 /* new mode found; add it to list of available fullscreen modes */
310 video.fullscreen_modes = checked_realloc(video.fullscreen_modes,
312 sizeof(struct ScreenModeInfo));
314 video.fullscreen_modes[num_modes - 1].width = modes[i]->w;
315 video.fullscreen_modes[num_modes - 1].height = modes[i]->h;
317 video.fullscreen_modes[num_modes].width = -1;
318 video.fullscreen_modes[num_modes].height = -1;
323 /* no appropriate screen modes available => no fullscreen mode support */
324 // video.fullscreen_available = FALSE;
325 hardware_fullscreen_available = FALSE;
329 video.fullscreen_available = hardware_fullscreen_available;
331 #if USE_DESKTOP_FULLSCREEN
332 // in SDL 2.0, there is always support for desktop fullscreen mode
333 // (in SDL 1.2, there is only support for "real" fullscreen mode)
334 video.fullscreen_available = TRUE;
337 #if defined(TARGET_SDL2)
340 for (i = 0; modes[i] != NULL; i++)
341 checked_free(modes[i]);
348 /* set window icon */
349 SDLSetWindowIcon(program.sdl_icon_filename);
352 /* open SDL video output device (window or fullscreen mode) */
353 if (!SDLSetVideoMode(backbuffer, fullscreen))
354 Error(ERR_EXIT, "setting video mode failed");
357 /* !!! SDL2 can only set the window icon if the window already exists !!! */
358 /* set window icon */
359 SDLSetWindowIcon(program.sdl_icon_filename);
362 /* set window and icon title */
363 #if defined(TARGET_SDL2)
364 SDL_SetWindowTitle(sdl_window, program.window_title);
366 SDL_WM_SetCaption(program.window_title, program.window_title);
369 /* SDL cannot directly draw to the visible video framebuffer like X11,
370 but always uses a backbuffer, which is then blitted to the visible
371 video framebuffer with 'SDL_UpdateRect' (or replaced with the current
372 visible video framebuffer with 'SDL_Flip', if the hardware supports
373 this). Therefore do not use an additional backbuffer for drawing, but
374 use a symbolic buffer (distinguishable from the SDL backbuffer) called
375 'window', which indicates that the SDL backbuffer should be updated to
376 the visible video framebuffer when attempting to blit to it.
378 For convenience, it seems to be a good idea to create this symbolic
379 buffer 'window' at the same size as the SDL backbuffer. Although it
380 should never be drawn to directly, it would do no harm nevertheless. */
382 /* create additional (symbolic) buffer for double-buffering */
384 ReCreateBitmap(window, video.width, video.height, video.depth);
386 *window = CreateBitmap(video.width, video.height, video.depth);
390 static SDL_Surface *SDLCreateScreen(DrawBuffer **backbuffer,
393 SDL_Surface *new_surface = NULL;
394 static boolean fullscreen_enabled = FALSE;
396 int surface_flags_window = SURFACE_FLAGS;
397 #if defined(TARGET_SDL2)
399 #if USE_DESKTOP_FULLSCREEN
400 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
402 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
406 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
409 int width = (fullscreen ? fullscreen_width : video.width);
410 int height = (fullscreen ? fullscreen_height : video.height);
411 int surface_flags = (fullscreen ? surface_flags_fullscreen :
412 surface_flags_window);
414 #if defined(TARGET_SDL2)
417 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
418 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
421 printf("::: use window scaling factor %f\n", screen_scaling_factor);
424 if ((*backbuffer)->surface)
426 SDL_FreeSurface((*backbuffer)->surface);
427 (*backbuffer)->surface = NULL;
432 SDL_DestroyTexture(sdl_texture);
436 if (!(fullscreen && fullscreen_enabled))
440 SDL_DestroyRenderer(sdl_renderer);
446 SDL_DestroyWindow(sdl_window);
451 Error(ERR_INFO, "::: checking 'sdl_window' ...");
453 if (sdl_window == NULL)
454 Error(ERR_INFO, "::: calling SDL_CreateWindow() [%d, %d, %d] ...",
455 setup.fullscreen, fullscreen, fullscreen_enabled);
457 if (sdl_window == NULL)
458 sdl_window = SDL_CreateWindow(program.window_title,
459 SDL_WINDOWPOS_CENTERED,
460 SDL_WINDOWPOS_CENTERED,
461 (int)(screen_scaling_factor * width),
462 (int)(screen_scaling_factor * height),
465 if (sdl_window != NULL)
467 if (sdl_renderer == NULL)
468 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
470 if (sdl_renderer != NULL)
472 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
473 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
475 sdl_texture = SDL_CreateTexture(sdl_renderer,
476 SDL_PIXELFORMAT_ARGB8888,
477 SDL_TEXTUREACCESS_STREAMING,
480 if (sdl_texture != NULL)
483 // (do not use alpha channel)
484 new_surface = SDL_CreateRGBSurface(0, width, height, 32,
490 // (this uses an alpha channel, which we don't want here)
491 new_surface = SDL_CreateRGBSurface(0, width, height, 32,
498 if (new_surface == NULL)
499 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
504 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
509 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
514 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
520 SDL_DestroyWindow(sdl_window);
522 sdl_window = SDL_CreateWindow(program.window_title,
523 SDL_WINDOWPOS_CENTERED,
524 SDL_WINDOWPOS_CENTERED,
528 if (sdl_window != NULL)
529 new_surface = SDL_GetWindowSurface(sdl_window);
533 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
536 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
537 if (new_surface != NULL)
538 fullscreen_enabled = fullscreen;
543 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
545 boolean success = TRUE;
548 #if defined(TARGET_SDL2)
549 // int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
550 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
551 int surface_flags_window = SURFACE_FLAGS;
553 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
554 int surface_flags_window = SURFACE_FLAGS;
557 SDL_Surface *new_surface = NULL;
559 if (*backbuffer == NULL)
560 *backbuffer = CreateBitmapStruct();
562 /* (real bitmap might be larger in fullscreen mode with video offsets) */
563 (*backbuffer)->width = video.width;
564 (*backbuffer)->height = video.height;
566 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
568 setFullscreenParameters(setup.fullscreen_mode);
570 video_xoffset = fullscreen_xoffset;
571 video_yoffset = fullscreen_yoffset;
573 /* switch display to fullscreen mode, if available */
575 new_surface = SDLCreateScreen(backbuffer, TRUE);
578 #if defined(TARGET_SDL2)
579 sdl_window = SDL_CreateWindow(program.window_title,
580 SDL_WINDOWPOS_CENTERED,
581 SDL_WINDOWPOS_CENTERED,
582 fullscreen_width, fullscreen_height,
583 surface_flags_fullscreen);
584 if (sdl_window != NULL)
586 new_surface = SDL_GetWindowSurface(sdl_window);
588 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
589 // UpdateScreen(NULL); // immediately map window
592 new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
593 video.depth, surface_flags_fullscreen);
597 if (new_surface == NULL)
599 /* switching display to fullscreen mode failed */
600 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
602 /* do not try it again */
603 video.fullscreen_available = FALSE;
609 (*backbuffer)->surface = new_surface;
611 video.fullscreen_enabled = TRUE;
612 video.fullscreen_mode_current = setup.fullscreen_mode;
618 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
623 /* switch display to window mode */
625 new_surface = SDLCreateScreen(backbuffer, FALSE);
628 #if defined(TARGET_SDL2)
631 float screen_scaling_factor = 1.2;
632 int test_fullscreen = 0;
633 int surface_flags = (test_fullscreen ? surface_flags_fullscreen :
634 surface_flags_window);
636 if ((*backbuffer)->surface)
637 SDL_FreeSurface((*backbuffer)->surface);
640 SDL_DestroyTexture(sdl_texture);
643 SDL_DestroyRenderer(sdl_renderer);
646 SDL_DestroyWindow(sdl_window);
648 sdl_window = SDL_CreateWindow(program.window_title,
649 SDL_WINDOWPOS_CENTERED,
650 SDL_WINDOWPOS_CENTERED,
651 (int)(screen_scaling_factor * video.width),
652 (int)(screen_scaling_factor * video.height),
655 if (sdl_window != NULL)
657 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
659 if (sdl_renderer != NULL)
661 SDL_RenderSetLogicalSize(sdl_renderer, video.width, video.height);
662 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
664 sdl_texture = SDL_CreateTexture(sdl_renderer,
665 SDL_PIXELFORMAT_ARGB8888,
666 SDL_TEXTUREACCESS_STREAMING,
667 video.width, video.height);
669 if (sdl_texture != NULL)
672 // (do not use alpha channel)
673 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
679 // (this uses an alpha channel, which we don't want here)
680 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
687 if (new_surface == NULL)
688 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
693 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
698 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
703 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
709 SDL_DestroyWindow(sdl_window);
711 sdl_window = SDL_CreateWindow(program.window_title,
712 SDL_WINDOWPOS_CENTERED,
713 SDL_WINDOWPOS_CENTERED,
714 video.width, video.height,
715 surface_flags_window);
717 if (sdl_window != NULL)
719 new_surface = SDL_GetWindowSurface(sdl_window);
721 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
722 // UpdateScreen(NULL); // immediately map window
727 new_surface = SDL_SetVideoMode(video.width, video.height,
728 video.depth, surface_flags_window);
732 if (new_surface == NULL)
734 /* switching display to window mode failed -- should not happen */
735 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
741 (*backbuffer)->surface = new_surface;
743 video.fullscreen_enabled = FALSE;
744 video.window_scaling_percent = setup.window_scaling_percent;
750 #if defined(TARGET_SDL2)
751 UpdateScreen(NULL); // map window
755 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
757 #if defined(PLATFORM_WIN32)
759 SDL_SysWMinfo wminfo;
762 SDL_VERSION(&wminfo.version);
763 SDL_GetWMInfo(&wminfo);
765 hwnd = wminfo.window;
767 DragAcceptFiles(hwnd, TRUE);
775 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
778 SDL_Surface *surface_tmp, *surface_native;
780 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
783 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
785 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
786 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
788 SDL_FreeSurface(surface_tmp);
790 new_bitmap->surface = surface_native;
793 void SDLFreeBitmapPointers(Bitmap *bitmap)
796 SDL_FreeSurface(bitmap->surface);
797 if (bitmap->surface_masked)
798 SDL_FreeSurface(bitmap->surface_masked);
799 bitmap->surface = NULL;
800 bitmap->surface_masked = NULL;
803 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
804 int src_x, int src_y, int width, int height,
805 int dst_x, int dst_y, int mask_mode)
807 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
808 SDL_Rect src_rect, dst_rect;
810 if (src_bitmap == backbuffer)
812 src_x += video_xoffset;
813 src_y += video_yoffset;
821 if (dst_bitmap == backbuffer || dst_bitmap == window)
823 dst_x += video_xoffset;
824 dst_y += video_yoffset;
832 // if (src_bitmap != backbuffer || dst_bitmap != window)
833 if (!(src_bitmap == backbuffer && dst_bitmap == window))
834 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
835 src_bitmap->surface_masked : src_bitmap->surface),
836 &src_rect, real_dst_bitmap->surface, &dst_rect);
838 #if defined(TARGET_SDL2)
839 if (dst_bitmap == window)
841 // SDL_UpdateWindowSurface(sdl_window);
842 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
843 UpdateScreen(&dst_rect);
846 if (dst_bitmap == window)
847 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
851 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
854 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
857 if (dst_bitmap == backbuffer || dst_bitmap == window)
868 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
870 #if defined(TARGET_SDL2)
871 if (dst_bitmap == window)
873 // SDL_UpdateWindowSurface(sdl_window);
874 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
878 if (dst_bitmap == window)
879 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
883 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
884 int fade_mode, int fade_delay, int post_delay,
885 void (*draw_border_function)(void))
887 static boolean initialization_needed = TRUE;
888 static SDL_Surface *surface_source = NULL;
889 static SDL_Surface *surface_target = NULL;
890 static SDL_Surface *surface_black = NULL;
891 SDL_Surface *surface_screen = backbuffer->surface;
892 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
893 SDL_Rect src_rect, dst_rect;
894 #if defined(TARGET_SDL2)
897 int src_x = x, src_y = y;
898 int dst_x = x, dst_y = y;
899 unsigned int time_last, time_current;
901 /* check if screen size has changed */
902 if (surface_source != NULL && (video.width != surface_source->w ||
903 video.height != surface_source->h))
905 SDL_FreeSurface(surface_source);
906 SDL_FreeSurface(surface_target);
907 SDL_FreeSurface(surface_black);
909 initialization_needed = TRUE;
917 dst_x += video_xoffset;
918 dst_y += video_yoffset;
922 dst_rect.w = width; /* (ignored) */
923 dst_rect.h = height; /* (ignored) */
925 #if defined(TARGET_SDL2)
926 dst_rect2 = dst_rect;
929 if (initialization_needed)
931 #if defined(TARGET_SDL2)
932 unsigned int flags = 0;
934 unsigned int flags = SDL_SRCALPHA;
936 /* use same surface type as screen surface */
937 if ((surface_screen->flags & SDL_HWSURFACE))
938 flags |= SDL_HWSURFACE;
940 flags |= SDL_SWSURFACE;
943 /* create surface for temporary copy of screen buffer (source) */
944 if ((surface_source =
945 SDL_CreateRGBSurface(flags,
948 surface_screen->format->BitsPerPixel,
949 surface_screen->format->Rmask,
950 surface_screen->format->Gmask,
951 surface_screen->format->Bmask,
952 surface_screen->format->Amask)) == NULL)
953 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
955 /* create surface for cross-fading screen buffer (target) */
956 if ((surface_target =
957 SDL_CreateRGBSurface(flags,
960 surface_screen->format->BitsPerPixel,
961 surface_screen->format->Rmask,
962 surface_screen->format->Gmask,
963 surface_screen->format->Bmask,
964 surface_screen->format->Amask)) == NULL)
965 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
967 /* create black surface for fading from/to black */
969 SDL_CreateRGBSurface(flags,
972 surface_screen->format->BitsPerPixel,
973 surface_screen->format->Rmask,
974 surface_screen->format->Gmask,
975 surface_screen->format->Bmask,
976 surface_screen->format->Amask)) == NULL)
977 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
979 /* completely fill the surface with black color pixels */
980 SDL_FillRect(surface_black, NULL,
981 SDL_MapRGB(surface_screen->format, 0, 0, 0));
983 initialization_needed = FALSE;
986 /* copy source and target surfaces to temporary surfaces for fading */
987 if (fade_mode & FADE_TYPE_TRANSFORM)
989 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
990 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
992 else if (fade_mode & FADE_TYPE_FADE_IN)
994 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
995 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
997 else /* FADE_TYPE_FADE_OUT */
999 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1000 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1003 time_current = SDL_GetTicks();
1005 if (fade_mode == FADE_MODE_MELT)
1007 boolean done = FALSE;
1008 int melt_pixels = 2;
1009 int melt_columns = width / melt_pixels;
1010 int ypos[melt_columns];
1011 int max_steps = height / 8 + 32;
1016 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1017 #if defined(TARGET_SDL2)
1018 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1020 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1023 ypos[0] = -GetSimpleRandom(16);
1025 for (i = 1 ; i < melt_columns; i++)
1027 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1029 ypos[i] = ypos[i - 1] + r;
1042 time_last = time_current;
1043 time_current = SDL_GetTicks();
1044 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1045 steps_final = MIN(MAX(0, steps), max_steps);
1049 done = (steps_done >= steps_final);
1051 for (i = 0 ; i < melt_columns; i++)
1059 else if (ypos[i] < height)
1064 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1066 if (ypos[i] + dy >= height)
1067 dy = height - ypos[i];
1069 /* copy part of (appearing) target surface to upper area */
1070 src_rect.x = src_x + i * melt_pixels;
1071 // src_rect.y = src_y + ypos[i];
1073 src_rect.w = melt_pixels;
1075 src_rect.h = ypos[i] + dy;
1077 dst_rect.x = dst_x + i * melt_pixels;
1078 // dst_rect.y = dst_y + ypos[i];
1081 if (steps_done >= steps_final)
1082 SDL_BlitSurface(surface_target, &src_rect,
1083 surface_screen, &dst_rect);
1087 /* copy part of (disappearing) source surface to lower area */
1088 src_rect.x = src_x + i * melt_pixels;
1090 src_rect.w = melt_pixels;
1091 src_rect.h = height - ypos[i];
1093 dst_rect.x = dst_x + i * melt_pixels;
1094 dst_rect.y = dst_y + ypos[i];
1096 if (steps_done >= steps_final)
1097 SDL_BlitSurface(surface_source, &src_rect,
1098 surface_screen, &dst_rect);
1104 src_rect.x = src_x + i * melt_pixels;
1106 src_rect.w = melt_pixels;
1107 src_rect.h = height;
1109 dst_rect.x = dst_x + i * melt_pixels;
1112 if (steps_done >= steps_final)
1113 SDL_BlitSurface(surface_target, &src_rect,
1114 surface_screen, &dst_rect);
1118 if (steps_done >= steps_final)
1120 if (draw_border_function != NULL)
1121 draw_border_function();
1123 #if defined(TARGET_SDL2)
1124 // SDL_UpdateWindowSurface(sdl_window);
1125 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
1126 UpdateScreen(&dst_rect2);
1128 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1138 for (alpha = 0.0; alpha < 255.0;)
1140 time_last = time_current;
1141 time_current = SDL_GetTicks();
1142 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1143 alpha_final = MIN(MAX(0, alpha), 255);
1145 /* draw existing (source) image to screen buffer */
1146 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1148 /* draw new (target) image to screen buffer using alpha blending */
1149 #if defined(TARGET_SDL2)
1150 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1151 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1153 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1155 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1157 if (draw_border_function != NULL)
1158 draw_border_function();
1161 /* only update the region of the screen that is affected from fading */
1162 #if defined(TARGET_SDL2)
1163 // SDL_UpdateWindowSurface(sdl_window);
1164 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1165 UpdateScreen(&dst_rect);
1167 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1170 SDL_Flip(surface_screen);
1178 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1179 int to_x, int to_y, Uint32 color)
1181 SDL_Surface *surface = dst_bitmap->surface;
1185 swap_numbers(&from_x, &to_x);
1188 swap_numbers(&from_y, &to_y);
1192 rect.w = (to_x - from_x + 1);
1193 rect.h = (to_y - from_y + 1);
1195 if (dst_bitmap == backbuffer || dst_bitmap == window)
1197 rect.x += video_xoffset;
1198 rect.y += video_yoffset;
1201 SDL_FillRect(surface, &rect, color);
1204 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1205 int to_x, int to_y, Uint32 color)
1207 if (dst_bitmap == backbuffer || dst_bitmap == window)
1209 from_x += video_xoffset;
1210 from_y += video_yoffset;
1211 to_x += video_xoffset;
1212 to_y += video_yoffset;
1215 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1219 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1220 int num_points, Uint32 color)
1225 for (i = 0; i < num_points - 1; i++)
1227 for (x = 0; x < line_width; x++)
1229 for (y = 0; y < line_width; y++)
1231 int dx = x - line_width / 2;
1232 int dy = y - line_width / 2;
1234 if ((x == 0 && y == 0) ||
1235 (x == 0 && y == line_width - 1) ||
1236 (x == line_width - 1 && y == 0) ||
1237 (x == line_width - 1 && y == line_width - 1))
1240 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1241 points[i+1].x + dx, points[i+1].y + dy, color);
1248 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1250 SDL_Surface *surface = src_bitmap->surface;
1252 if (src_bitmap == backbuffer || src_bitmap == window)
1258 switch (surface->format->BytesPerPixel)
1260 case 1: /* assuming 8-bpp */
1262 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1266 case 2: /* probably 15-bpp or 16-bpp */
1268 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1272 case 3: /* slow 24-bpp mode; usually not used */
1274 /* does this work? */
1275 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1279 shift = surface->format->Rshift;
1280 color |= *(pix + shift / 8) >> shift;
1281 shift = surface->format->Gshift;
1282 color |= *(pix + shift / 8) >> shift;
1283 shift = surface->format->Bshift;
1284 color |= *(pix + shift / 8) >> shift;
1290 case 4: /* probably 32-bpp */
1292 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1301 /* ========================================================================= */
1302 /* The following functions were taken from the SGE library */
1303 /* (SDL Graphics Extension Library) by Anders Lindström */
1304 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1305 /* ========================================================================= */
1307 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1309 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1311 switch (surface->format->BytesPerPixel)
1315 /* Assuming 8-bpp */
1316 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1322 /* Probably 15-bpp or 16-bpp */
1323 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1329 /* Slow 24-bpp mode, usually not used */
1333 /* Gack - slow, but endian correct */
1334 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1335 shift = surface->format->Rshift;
1336 *(pix+shift/8) = color>>shift;
1337 shift = surface->format->Gshift;
1338 *(pix+shift/8) = color>>shift;
1339 shift = surface->format->Bshift;
1340 *(pix+shift/8) = color>>shift;
1346 /* Probably 32-bpp */
1347 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1354 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1355 Uint8 R, Uint8 G, Uint8 B)
1357 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1360 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1362 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1365 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1367 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1370 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1375 /* Gack - slow, but endian correct */
1376 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1377 shift = surface->format->Rshift;
1378 *(pix+shift/8) = color>>shift;
1379 shift = surface->format->Gshift;
1380 *(pix+shift/8) = color>>shift;
1381 shift = surface->format->Bshift;
1382 *(pix+shift/8) = color>>shift;
1385 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1387 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1390 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1392 switch (dest->format->BytesPerPixel)
1395 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1399 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1403 _PutPixel24(dest,x,y,color);
1407 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1412 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1414 if (SDL_MUSTLOCK(surface))
1416 if (SDL_LockSurface(surface) < 0)
1422 _PutPixel(surface, x, y, color);
1424 if (SDL_MUSTLOCK(surface))
1426 SDL_UnlockSurface(surface);
1430 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1431 Uint8 r, Uint8 g, Uint8 b)
1433 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1436 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1438 if (y >= 0 && y <= dest->h - 1)
1440 switch (dest->format->BytesPerPixel)
1443 return y*dest->pitch;
1447 return y*dest->pitch/2;
1451 return y*dest->pitch;
1455 return y*dest->pitch/4;
1463 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1465 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1467 switch (surface->format->BytesPerPixel)
1471 /* Assuming 8-bpp */
1472 *((Uint8 *)surface->pixels + ypitch + x) = color;
1478 /* Probably 15-bpp or 16-bpp */
1479 *((Uint16 *)surface->pixels + ypitch + x) = color;
1485 /* Slow 24-bpp mode, usually not used */
1489 /* Gack - slow, but endian correct */
1490 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1491 shift = surface->format->Rshift;
1492 *(pix+shift/8) = color>>shift;
1493 shift = surface->format->Gshift;
1494 *(pix+shift/8) = color>>shift;
1495 shift = surface->format->Bshift;
1496 *(pix+shift/8) = color>>shift;
1502 /* Probably 32-bpp */
1503 *((Uint32 *)surface->pixels + ypitch + x) = color;
1510 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1515 if (SDL_MUSTLOCK(Surface))
1517 if (SDL_LockSurface(Surface) < 0)
1530 /* Do the clipping */
1531 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1535 if (x2 > Surface->w - 1)
1536 x2 = Surface->w - 1;
1543 SDL_FillRect(Surface, &l, Color);
1545 if (SDL_MUSTLOCK(Surface))
1547 SDL_UnlockSurface(Surface);
1551 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1552 Uint8 R, Uint8 G, Uint8 B)
1554 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1557 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1568 /* Do the clipping */
1569 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1573 if (x2 > Surface->w - 1)
1574 x2 = Surface->w - 1;
1581 SDL_FillRect(Surface, &l, Color);
1584 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1589 if (SDL_MUSTLOCK(Surface))
1591 if (SDL_LockSurface(Surface) < 0)
1604 /* Do the clipping */
1605 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1609 if (y2 > Surface->h - 1)
1610 y2 = Surface->h - 1;
1617 SDL_FillRect(Surface, &l, Color);
1619 if (SDL_MUSTLOCK(Surface))
1621 SDL_UnlockSurface(Surface);
1625 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1626 Uint8 R, Uint8 G, Uint8 B)
1628 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1631 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1642 /* Do the clipping */
1643 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1647 if (y2 > Surface->h - 1)
1648 y2 = Surface->h - 1;
1655 SDL_FillRect(Surface, &l, Color);
1658 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1659 Sint16 x2, Sint16 y2, Uint32 Color,
1660 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1663 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1668 sdx = (dx < 0) ? -1 : 1;
1669 sdy = (dy < 0) ? -1 : 1;
1681 for (x = 0; x < dx; x++)
1683 Callback(Surface, px, py, Color);
1697 for (y = 0; y < dy; y++)
1699 Callback(Surface, px, py, Color);
1713 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1714 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1715 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1718 sge_DoLine(Surface, X1, Y1, X2, Y2,
1719 SDL_MapRGB(Surface->format, R, G, B), Callback);
1722 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1725 if (SDL_MUSTLOCK(Surface))
1727 if (SDL_LockSurface(Surface) < 0)
1732 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1734 /* unlock the display */
1735 if (SDL_MUSTLOCK(Surface))
1737 SDL_UnlockSurface(Surface);
1741 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1742 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1744 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1747 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1749 if (dst_bitmap == backbuffer || dst_bitmap == window)
1755 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1760 -----------------------------------------------------------------------------
1761 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1762 -----------------------------------------------------------------------------
1765 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1766 int width, int height, Uint32 color)
1770 for (y = src_y; y < src_y + height; y++)
1772 for (x = src_x; x < src_x + width; x++)
1774 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1776 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1781 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1782 int src_x, int src_y, int width, int height,
1783 int dst_x, int dst_y)
1787 for (y = 0; y < height; y++)
1789 for (x = 0; x < width; x++)
1791 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1793 if (pixel != BLACK_PIXEL)
1794 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1800 /* ========================================================================= */
1801 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1802 /* (Rotozoomer) by Andreas Schiffler */
1803 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1804 /* ========================================================================= */
1807 -----------------------------------------------------------------------------
1810 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1811 -----------------------------------------------------------------------------
1822 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1825 tColorRGBA *sp, *csp, *dp;
1832 sp = csp = (tColorRGBA *) src->pixels;
1833 dp = (tColorRGBA *) dst->pixels;
1835 sgap = src->pitch - src->w * 4;
1837 dgap = dst->pitch - dst->w * 4;
1839 for (y = 0; y < dst->h; y++)
1843 for (x = 0; x < dst->w; x++)
1845 tColorRGBA *sp0 = sp;
1846 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1847 tColorRGBA *sp00 = &sp0[0];
1848 tColorRGBA *sp01 = &sp0[1];
1849 tColorRGBA *sp10 = &sp1[0];
1850 tColorRGBA *sp11 = &sp1[1];
1853 /* create new color pixel from all four source color pixels */
1854 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1855 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1856 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1857 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1862 /* advance source pointers */
1865 /* advance destination pointer */
1869 /* advance source pointer */
1870 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1872 /* advance destination pointers */
1873 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1879 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1881 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1882 tColorRGBA *sp, *csp, *dp;
1888 /* use specialized zoom function when scaling down to exactly half size */
1889 if (src->w == 2 * dst->w &&
1890 src->h == 2 * dst->h)
1891 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1893 /* variable setup */
1894 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1895 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1897 /* allocate memory for row increments */
1898 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1899 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1901 /* precalculate row increments */
1904 for (x = 0; x <= dst->w; x++)
1914 for (y = 0; y <= dst->h; y++)
1923 sp = csp = (tColorRGBA *) src->pixels;
1924 dp = (tColorRGBA *) dst->pixels;
1926 sgap = src->pitch - src->w * 4;
1928 dgap = dst->pitch - dst->w * 4;
1931 for (y = 0; y < dst->h; y++)
1936 for (x = 0; x < dst->w; x++)
1941 /* advance source pointers */
1943 sp += (*csax >> 16);
1945 /* advance destination pointer */
1949 /* advance source pointer */
1951 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1953 /* advance destination pointers */
1954 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1964 -----------------------------------------------------------------------------
1967 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1968 -----------------------------------------------------------------------------
1971 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1973 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1974 Uint8 *sp, *dp, *csp;
1977 /* variable setup */
1978 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1979 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1981 /* allocate memory for row increments */
1982 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1983 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1985 /* precalculate row increments */
1988 for (x = 0; x < dst->w; x++)
1991 *csax = (csx >> 16);
1998 for (y = 0; y < dst->h; y++)
2001 *csay = (csy >> 16);
2008 for (x = 0; x < dst->w; x++)
2016 for (y = 0; y < dst->h; y++)
2023 sp = csp = (Uint8 *) src->pixels;
2024 dp = (Uint8 *) dst->pixels;
2025 dgap = dst->pitch - dst->w;
2029 for (y = 0; y < dst->h; y++)
2033 for (x = 0; x < dst->w; x++)
2038 /* advance source pointers */
2042 /* advance destination pointer */
2046 /* advance source pointer (for row) */
2047 csp += ((*csay) * src->pitch);
2050 /* advance destination pointers */
2061 -----------------------------------------------------------------------------
2064 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2065 'zoomx' and 'zoomy' are scaling factors for width and height.
2066 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2067 into a 32bit RGBA format on the fly.
2068 -----------------------------------------------------------------------------
2071 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2073 SDL_Surface *zoom_src = NULL;
2074 SDL_Surface *zoom_dst = NULL;
2075 boolean is_converted = FALSE;
2082 /* determine if source surface is 32 bit or 8 bit */
2083 is_32bit = (src->format->BitsPerPixel == 32);
2085 if (is_32bit || src->format->BitsPerPixel == 8)
2087 /* use source surface 'as is' */
2092 /* new source surface is 32 bit with a defined RGB ordering */
2093 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
2094 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2095 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2097 is_converted = TRUE;
2100 /* allocate surface to completely contain the zoomed surface */
2103 /* target surface is 32 bit with source RGBA/ABGR ordering */
2104 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
2105 zoom_src->format->Rmask,
2106 zoom_src->format->Gmask,
2107 zoom_src->format->Bmask, 0);
2111 /* target surface is 8 bit */
2112 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
2116 /* lock source surface */
2117 SDL_LockSurface(zoom_src);
2119 /* check which kind of surface we have */
2122 /* call the 32 bit transformation routine to do the zooming */
2123 zoomSurfaceRGBA(zoom_src, zoom_dst);
2128 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2129 zoom_dst->format->palette->colors[i] =
2130 zoom_src->format->palette->colors[i];
2131 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2133 /* call the 8 bit transformation routine to do the zooming */
2134 zoomSurfaceY(zoom_src, zoom_dst);
2137 /* unlock source surface */
2138 SDL_UnlockSurface(zoom_src);
2140 /* free temporary surface */
2142 SDL_FreeSurface(zoom_src);
2144 /* return destination surface */
2148 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
2150 SDL_Surface *sdl_surface_tmp;
2151 int dst_width = dst_bitmap->width;
2152 int dst_height = dst_bitmap->height;
2154 /* throw away old destination surface */
2155 SDL_FreeSurface(dst_bitmap->surface);
2157 /* create zoomed temporary surface from source surface */
2158 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2160 /* create native format destination surface from zoomed temporary surface */
2161 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
2163 /* free temporary surface */
2164 SDL_FreeSurface(sdl_surface_tmp);
2168 /* ========================================================================= */
2169 /* load image to bitmap */
2170 /* ========================================================================= */
2172 Bitmap *SDLLoadImage(char *filename)
2174 Bitmap *new_bitmap = CreateBitmapStruct();
2175 SDL_Surface *sdl_image_tmp;
2177 print_timestamp_init("SDLLoadImage");
2179 print_timestamp_time(getBaseNamePtr(filename));
2181 /* load image to temporary surface */
2182 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2184 SetError("IMG_Load(): %s", SDL_GetError());
2189 print_timestamp_time("IMG_Load");
2191 UPDATE_BUSY_STATE();
2193 /* create native non-transparent surface for current image */
2194 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2196 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2201 print_timestamp_time("SDL_DisplayFormat (opaque)");
2203 UPDATE_BUSY_STATE();
2205 /* create native transparent surface for current image */
2206 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2207 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2208 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2210 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2215 print_timestamp_time("SDL_DisplayFormat (masked)");
2217 UPDATE_BUSY_STATE();
2219 /* free temporary surface */
2220 SDL_FreeSurface(sdl_image_tmp);
2222 new_bitmap->width = new_bitmap->surface->w;
2223 new_bitmap->height = new_bitmap->surface->h;
2225 print_timestamp_done("SDLLoadImage");
2231 /* ------------------------------------------------------------------------- */
2232 /* custom cursor fuctions */
2233 /* ------------------------------------------------------------------------- */
2235 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2237 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2238 cursor_info->width, cursor_info->height,
2239 cursor_info->hot_x, cursor_info->hot_y);
2242 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2244 static struct MouseCursorInfo *last_cursor_info = NULL;
2245 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2246 static SDL_Cursor *cursor_default = NULL;
2247 static SDL_Cursor *cursor_current = NULL;
2249 /* if invoked for the first time, store the SDL default cursor */
2250 if (cursor_default == NULL)
2251 cursor_default = SDL_GetCursor();
2253 /* only create new cursor if cursor info (custom only) has changed */
2254 if (cursor_info != NULL && cursor_info != last_cursor_info)
2256 cursor_current = create_cursor(cursor_info);
2257 last_cursor_info = cursor_info;
2260 /* only set new cursor if cursor info (custom or NULL) has changed */
2261 if (cursor_info != last_cursor_info2)
2262 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2264 last_cursor_info2 = cursor_info;
2268 /* ========================================================================= */
2269 /* audio functions */
2270 /* ========================================================================= */
2272 void SDLOpenAudio(void)
2274 #if !defined(TARGET_SDL2)
2275 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2276 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2279 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2281 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2285 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2286 AUDIO_NUM_CHANNELS_STEREO,
2287 setup.system.audio_fragment_size) < 0)
2289 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2293 audio.sound_available = TRUE;
2294 audio.music_available = TRUE;
2295 audio.loops_available = TRUE;
2296 audio.sound_enabled = TRUE;
2298 /* set number of available mixer channels */
2299 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2300 audio.music_channel = MUSIC_CHANNEL;
2301 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2303 Mixer_InitChannels();
2306 void SDLCloseAudio(void)
2309 Mix_HaltChannel(-1);
2312 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2316 /* ========================================================================= */
2317 /* event functions */
2318 /* ========================================================================= */
2320 void SDLNextEvent(Event *event)
2322 SDL_WaitEvent(event);
2324 if (event->type == EVENT_BUTTONPRESS ||
2325 event->type == EVENT_BUTTONRELEASE)
2327 if (((ButtonEvent *)event)->x > video_xoffset)
2328 ((ButtonEvent *)event)->x -= video_xoffset;
2330 ((ButtonEvent *)event)->x = 0;
2331 if (((ButtonEvent *)event)->y > video_yoffset)
2332 ((ButtonEvent *)event)->y -= video_yoffset;
2334 ((ButtonEvent *)event)->y = 0;
2336 else if (event->type == EVENT_MOTIONNOTIFY)
2338 if (((MotionEvent *)event)->x > video_xoffset)
2339 ((MotionEvent *)event)->x -= video_xoffset;
2341 ((MotionEvent *)event)->x = 0;
2342 if (((MotionEvent *)event)->y > video_yoffset)
2343 ((MotionEvent *)event)->y -= video_yoffset;
2345 ((MotionEvent *)event)->y = 0;
2349 void SDLHandleWindowManagerEvent(Event *event)
2351 #if defined(PLATFORM_WIN32)
2352 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2353 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2355 if (syswmmsg->msg == WM_DROPFILES)
2357 HDROP hdrop = (HDROP)syswmmsg->wParam;
2360 printf("::: SDL_SYSWMEVENT:\n");
2362 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2364 for (i = 0; i < num_files; i++)
2366 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2367 char buffer[buffer_len + 1];
2369 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2371 printf("::: - '%s'\n", buffer);
2374 DragFinish((HDROP)syswmmsg->wParam);
2380 /* ========================================================================= */
2381 /* joystick functions */
2382 /* ========================================================================= */
2384 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2385 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2386 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2388 static boolean SDLOpenJoystick(int nr)
2390 if (nr < 0 || nr > MAX_PLAYERS)
2393 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2396 static void SDLCloseJoystick(int nr)
2398 if (nr < 0 || nr > MAX_PLAYERS)
2401 SDL_JoystickClose(sdl_joystick[nr]);
2403 sdl_joystick[nr] = NULL;
2406 static boolean SDLCheckJoystickOpened(int nr)
2408 if (nr < 0 || nr > MAX_PLAYERS)
2411 #if defined(TARGET_SDL2)
2412 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2414 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2418 void HandleJoystickEvent(Event *event)
2422 case SDL_JOYAXISMOTION:
2423 if (event->jaxis.axis < 2)
2424 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2427 case SDL_JOYBUTTONDOWN:
2428 if (event->jbutton.button < 2)
2429 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2432 case SDL_JOYBUTTONUP:
2433 if (event->jbutton.button < 2)
2434 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2442 void SDLInitJoysticks()
2444 static boolean sdl_joystick_subsystem_initialized = FALSE;
2445 boolean print_warning = !sdl_joystick_subsystem_initialized;
2448 if (!sdl_joystick_subsystem_initialized)
2450 sdl_joystick_subsystem_initialized = TRUE;
2452 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2454 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2459 for (i = 0; i < MAX_PLAYERS; i++)
2461 /* get configured joystick for this player */
2462 char *device_name = setup.input[i].joy.device_name;
2463 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2465 if (joystick_nr >= SDL_NumJoysticks())
2467 if (setup.input[i].use_joystick && print_warning)
2468 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2473 /* misuse joystick file descriptor variable to store joystick number */
2474 joystick.fd[i] = joystick_nr;
2476 if (joystick_nr == -1)
2479 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2480 if (SDLCheckJoystickOpened(joystick_nr))
2481 SDLCloseJoystick(joystick_nr);
2483 if (!setup.input[i].use_joystick)
2486 if (!SDLOpenJoystick(joystick_nr))
2489 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2494 joystick.status = JOYSTICK_ACTIVATED;
2498 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2500 if (nr < 0 || nr >= MAX_PLAYERS)
2504 *x = sdl_js_axis[nr][0];
2506 *y = sdl_js_axis[nr][1];
2509 *b1 = sdl_js_button[nr][0];
2511 *b2 = sdl_js_button[nr][1];
2516 #endif /* TARGET_SDL */