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 #if defined(TARGET_SDL2)
397 int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE;
398 #if USE_DESKTOP_FULLSCREEN
399 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
401 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
405 int surface_flags_window = SURFACE_FLAGS;
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 // default window size is unscaled
415 video.window_width = video.width;
416 video.window_height = video.height;
418 #if defined(TARGET_SDL2)
420 // store if initial screen mode on game start is fullscreen mode
421 if (sdl_window == NULL)
423 printf("::: GAME STARTS WITH FULLSCREEN %d\n", fullscreen);
425 video.fullscreen_initial = fullscreen;
429 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
430 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
432 video.window_width = window_scaling_factor * width;
433 video.window_height = window_scaling_factor * height;
436 printf("::: use window scaling factor %f\n", screen_scaling_factor);
439 if ((*backbuffer)->surface)
441 SDL_FreeSurface((*backbuffer)->surface);
442 (*backbuffer)->surface = NULL;
447 SDL_DestroyTexture(sdl_texture);
451 if (!(fullscreen && fullscreen_enabled))
455 SDL_DestroyRenderer(sdl_renderer);
461 SDL_DestroyWindow(sdl_window);
467 Error(ERR_INFO, "::: checking 'sdl_window' ...");
469 if (sdl_window == NULL)
470 Error(ERR_INFO, "::: calling SDL_CreateWindow() [%d, %d, %d] ...",
471 setup.fullscreen, fullscreen, fullscreen_enabled);
474 if (sdl_window == NULL)
475 sdl_window = SDL_CreateWindow(program.window_title,
476 SDL_WINDOWPOS_CENTERED,
477 SDL_WINDOWPOS_CENTERED,
478 #if USE_DESKTOP_FULLSCREEN
482 (int)(screen_scaling_factor * width),
483 (int)(screen_scaling_factor * height),
487 if (sdl_window != NULL)
489 if (sdl_renderer == NULL)
490 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
492 if (sdl_renderer != NULL)
494 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
495 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
497 sdl_texture = SDL_CreateTexture(sdl_renderer,
498 SDL_PIXELFORMAT_ARGB8888,
499 SDL_TEXTUREACCESS_STREAMING,
502 if (sdl_texture != NULL)
505 // (do not use alpha channel)
506 new_surface = SDL_CreateRGBSurface(0, width, height, 32,
512 // (this uses an alpha channel, which we don't want here)
513 new_surface = SDL_CreateRGBSurface(0, width, height, 32,
520 if (new_surface == NULL)
521 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
526 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
531 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
536 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
542 SDL_DestroyWindow(sdl_window);
544 sdl_window = SDL_CreateWindow(program.window_title,
545 SDL_WINDOWPOS_CENTERED,
546 SDL_WINDOWPOS_CENTERED,
550 if (sdl_window != NULL)
551 new_surface = SDL_GetWindowSurface(sdl_window);
555 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
558 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
559 if (new_surface != NULL)
560 fullscreen_enabled = fullscreen;
565 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
567 boolean success = TRUE;
570 #if defined(TARGET_SDL2)
571 // int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
572 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
573 int surface_flags_window = SURFACE_FLAGS;
575 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
576 int surface_flags_window = SURFACE_FLAGS;
579 SDL_Surface *new_surface = NULL;
581 if (*backbuffer == NULL)
582 *backbuffer = CreateBitmapStruct();
584 /* (real bitmap might be larger in fullscreen mode with video offsets) */
585 (*backbuffer)->width = video.width;
586 (*backbuffer)->height = video.height;
588 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
590 setFullscreenParameters(setup.fullscreen_mode);
592 video_xoffset = fullscreen_xoffset;
593 video_yoffset = fullscreen_yoffset;
595 /* switch display to fullscreen mode, if available */
597 new_surface = SDLCreateScreen(backbuffer, TRUE);
600 #if defined(TARGET_SDL2)
601 sdl_window = SDL_CreateWindow(program.window_title,
602 SDL_WINDOWPOS_CENTERED,
603 SDL_WINDOWPOS_CENTERED,
604 fullscreen_width, fullscreen_height,
605 surface_flags_fullscreen);
606 if (sdl_window != NULL)
608 new_surface = SDL_GetWindowSurface(sdl_window);
610 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
611 // UpdateScreen(NULL); // immediately map window
614 new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
615 video.depth, surface_flags_fullscreen);
619 if (new_surface == NULL)
621 /* switching display to fullscreen mode failed */
622 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
624 /* do not try it again */
625 video.fullscreen_available = FALSE;
631 (*backbuffer)->surface = new_surface;
633 video.fullscreen_enabled = TRUE;
634 video.fullscreen_mode_current = setup.fullscreen_mode;
640 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
645 /* switch display to window mode */
647 new_surface = SDLCreateScreen(backbuffer, FALSE);
650 #if defined(TARGET_SDL2)
653 float screen_scaling_factor = 1.2;
654 int test_fullscreen = 0;
655 int surface_flags = (test_fullscreen ? surface_flags_fullscreen :
656 surface_flags_window);
658 if ((*backbuffer)->surface)
659 SDL_FreeSurface((*backbuffer)->surface);
662 SDL_DestroyTexture(sdl_texture);
665 SDL_DestroyRenderer(sdl_renderer);
668 SDL_DestroyWindow(sdl_window);
670 sdl_window = SDL_CreateWindow(program.window_title,
671 SDL_WINDOWPOS_CENTERED,
672 SDL_WINDOWPOS_CENTERED,
673 (int)(screen_scaling_factor * video.width),
674 (int)(screen_scaling_factor * video.height),
677 if (sdl_window != NULL)
679 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
681 if (sdl_renderer != NULL)
683 SDL_RenderSetLogicalSize(sdl_renderer, video.width, video.height);
684 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
686 sdl_texture = SDL_CreateTexture(sdl_renderer,
687 SDL_PIXELFORMAT_ARGB8888,
688 SDL_TEXTUREACCESS_STREAMING,
689 video.width, video.height);
691 if (sdl_texture != NULL)
694 // (do not use alpha channel)
695 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
701 // (this uses an alpha channel, which we don't want here)
702 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
709 if (new_surface == NULL)
710 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
715 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
720 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
725 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
731 SDL_DestroyWindow(sdl_window);
733 sdl_window = SDL_CreateWindow(program.window_title,
734 SDL_WINDOWPOS_CENTERED,
735 SDL_WINDOWPOS_CENTERED,
736 video.width, video.height,
737 surface_flags_window);
739 if (sdl_window != NULL)
741 new_surface = SDL_GetWindowSurface(sdl_window);
743 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
744 // UpdateScreen(NULL); // immediately map window
749 new_surface = SDL_SetVideoMode(video.width, video.height,
750 video.depth, surface_flags_window);
754 if (new_surface == NULL)
756 /* switching display to window mode failed -- should not happen */
757 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
763 (*backbuffer)->surface = new_surface;
765 video.fullscreen_enabled = FALSE;
766 video.window_scaling_percent = setup.window_scaling_percent;
772 #if defined(TARGET_SDL2)
773 SDLRedrawWindow(); // map window
774 // UpdateScreen(NULL); // map window
778 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
780 #if defined(PLATFORM_WIN32)
782 SDL_SysWMinfo wminfo;
785 SDL_VERSION(&wminfo.version);
786 SDL_GetWMInfo(&wminfo);
788 hwnd = wminfo.window;
790 DragAcceptFiles(hwnd, TRUE);
798 #if defined(TARGET_SDL2)
799 void SDLSetWindowScaling(int window_scaling_percent)
801 if (sdl_window == NULL)
804 float window_scaling_factor = (float)window_scaling_percent / 100;
805 int new_window_width = (int)(window_scaling_factor * video.width);
806 int new_window_height = (int)(window_scaling_factor * video.height);
808 Error(ERR_DEBUG, "::: SDLSetWindowScaling(%d) ...", window_scaling_percent);
810 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
812 video.window_scaling_percent = window_scaling_percent;
813 video.window_width = new_window_width;
814 video.window_height = new_window_height;
817 void SDLSetWindowFullscreen(boolean fullscreen)
819 if (sdl_window == NULL)
822 #if USE_DESKTOP_FULLSCREEN
823 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
825 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
828 Error(ERR_DEBUG, "::: SDL_SetWindowFullscreen(%d) ...", fullscreen);
830 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
831 video.fullscreen_enabled = fullscreen;
833 printf("::: SDLSetWindowFullscreen: %d, %d\n",
834 fullscreen, video.fullscreen_initial);
837 // if game started in fullscreen mode, window will also get fullscreen size
838 if (!fullscreen && video.fullscreen_initial)
840 SDLSetWindowScaling(setup.window_scaling_percent);
841 SDL_SetWindowPosition(sdl_window,
842 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
844 video.fullscreen_initial = FALSE;
849 void SDLRedrawWindow()
855 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
858 SDL_Surface *surface_tmp, *surface_native;
860 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
863 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
865 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
866 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
868 SDL_FreeSurface(surface_tmp);
870 new_bitmap->surface = surface_native;
873 void SDLFreeBitmapPointers(Bitmap *bitmap)
876 SDL_FreeSurface(bitmap->surface);
877 if (bitmap->surface_masked)
878 SDL_FreeSurface(bitmap->surface_masked);
879 bitmap->surface = NULL;
880 bitmap->surface_masked = NULL;
883 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
884 int src_x, int src_y, int width, int height,
885 int dst_x, int dst_y, int mask_mode)
887 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
888 SDL_Rect src_rect, dst_rect;
890 if (src_bitmap == backbuffer)
892 src_x += video_xoffset;
893 src_y += video_yoffset;
901 if (dst_bitmap == backbuffer || dst_bitmap == window)
903 dst_x += video_xoffset;
904 dst_y += video_yoffset;
912 // if (src_bitmap != backbuffer || dst_bitmap != window)
913 if (!(src_bitmap == backbuffer && dst_bitmap == window))
914 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
915 src_bitmap->surface_masked : src_bitmap->surface),
916 &src_rect, real_dst_bitmap->surface, &dst_rect);
918 #if defined(TARGET_SDL2)
919 if (dst_bitmap == window)
921 // SDL_UpdateWindowSurface(sdl_window);
922 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
923 UpdateScreen(&dst_rect);
926 if (dst_bitmap == window)
927 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
931 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
934 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
937 if (dst_bitmap == backbuffer || dst_bitmap == window)
948 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
950 #if defined(TARGET_SDL2)
951 if (dst_bitmap == window)
953 // SDL_UpdateWindowSurface(sdl_window);
954 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
958 if (dst_bitmap == window)
959 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
963 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
964 int fade_mode, int fade_delay, int post_delay,
965 void (*draw_border_function)(void))
967 static boolean initialization_needed = TRUE;
968 static SDL_Surface *surface_source = NULL;
969 static SDL_Surface *surface_target = NULL;
970 static SDL_Surface *surface_black = NULL;
971 SDL_Surface *surface_screen = backbuffer->surface;
972 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
973 SDL_Rect src_rect, dst_rect;
974 #if defined(TARGET_SDL2)
977 int src_x = x, src_y = y;
978 int dst_x = x, dst_y = y;
979 unsigned int time_last, time_current;
981 /* check if screen size has changed */
982 if (surface_source != NULL && (video.width != surface_source->w ||
983 video.height != surface_source->h))
985 SDL_FreeSurface(surface_source);
986 SDL_FreeSurface(surface_target);
987 SDL_FreeSurface(surface_black);
989 initialization_needed = TRUE;
997 dst_x += video_xoffset;
998 dst_y += video_yoffset;
1002 dst_rect.w = width; /* (ignored) */
1003 dst_rect.h = height; /* (ignored) */
1005 #if defined(TARGET_SDL2)
1006 dst_rect2 = dst_rect;
1009 if (initialization_needed)
1011 #if defined(TARGET_SDL2)
1012 unsigned int flags = 0;
1014 unsigned int flags = SDL_SRCALPHA;
1016 /* use same surface type as screen surface */
1017 if ((surface_screen->flags & SDL_HWSURFACE))
1018 flags |= SDL_HWSURFACE;
1020 flags |= SDL_SWSURFACE;
1023 /* create surface for temporary copy of screen buffer (source) */
1024 if ((surface_source =
1025 SDL_CreateRGBSurface(flags,
1028 surface_screen->format->BitsPerPixel,
1029 surface_screen->format->Rmask,
1030 surface_screen->format->Gmask,
1031 surface_screen->format->Bmask,
1032 surface_screen->format->Amask)) == NULL)
1033 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1035 /* create surface for cross-fading screen buffer (target) */
1036 if ((surface_target =
1037 SDL_CreateRGBSurface(flags,
1040 surface_screen->format->BitsPerPixel,
1041 surface_screen->format->Rmask,
1042 surface_screen->format->Gmask,
1043 surface_screen->format->Bmask,
1044 surface_screen->format->Amask)) == NULL)
1045 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1047 /* create black surface for fading from/to black */
1048 if ((surface_black =
1049 SDL_CreateRGBSurface(flags,
1052 surface_screen->format->BitsPerPixel,
1053 surface_screen->format->Rmask,
1054 surface_screen->format->Gmask,
1055 surface_screen->format->Bmask,
1056 surface_screen->format->Amask)) == NULL)
1057 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1059 /* completely fill the surface with black color pixels */
1060 SDL_FillRect(surface_black, NULL,
1061 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1063 initialization_needed = FALSE;
1066 /* copy source and target surfaces to temporary surfaces for fading */
1067 if (fade_mode & FADE_TYPE_TRANSFORM)
1069 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1070 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1072 else if (fade_mode & FADE_TYPE_FADE_IN)
1074 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1075 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1077 else /* FADE_TYPE_FADE_OUT */
1079 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1080 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1083 time_current = SDL_GetTicks();
1085 if (fade_mode == FADE_MODE_MELT)
1087 boolean done = FALSE;
1088 int melt_pixels = 2;
1089 int melt_columns = width / melt_pixels;
1090 int ypos[melt_columns];
1091 int max_steps = height / 8 + 32;
1096 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1097 #if defined(TARGET_SDL2)
1098 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1100 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1103 ypos[0] = -GetSimpleRandom(16);
1105 for (i = 1 ; i < melt_columns; i++)
1107 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1109 ypos[i] = ypos[i - 1] + r;
1122 time_last = time_current;
1123 time_current = SDL_GetTicks();
1124 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1125 steps_final = MIN(MAX(0, steps), max_steps);
1129 done = (steps_done >= steps_final);
1131 for (i = 0 ; i < melt_columns; i++)
1139 else if (ypos[i] < height)
1144 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1146 if (ypos[i] + dy >= height)
1147 dy = height - ypos[i];
1149 /* copy part of (appearing) target surface to upper area */
1150 src_rect.x = src_x + i * melt_pixels;
1151 // src_rect.y = src_y + ypos[i];
1153 src_rect.w = melt_pixels;
1155 src_rect.h = ypos[i] + dy;
1157 dst_rect.x = dst_x + i * melt_pixels;
1158 // dst_rect.y = dst_y + ypos[i];
1161 if (steps_done >= steps_final)
1162 SDL_BlitSurface(surface_target, &src_rect,
1163 surface_screen, &dst_rect);
1167 /* copy part of (disappearing) source surface to lower area */
1168 src_rect.x = src_x + i * melt_pixels;
1170 src_rect.w = melt_pixels;
1171 src_rect.h = height - ypos[i];
1173 dst_rect.x = dst_x + i * melt_pixels;
1174 dst_rect.y = dst_y + ypos[i];
1176 if (steps_done >= steps_final)
1177 SDL_BlitSurface(surface_source, &src_rect,
1178 surface_screen, &dst_rect);
1184 src_rect.x = src_x + i * melt_pixels;
1186 src_rect.w = melt_pixels;
1187 src_rect.h = height;
1189 dst_rect.x = dst_x + i * melt_pixels;
1192 if (steps_done >= steps_final)
1193 SDL_BlitSurface(surface_target, &src_rect,
1194 surface_screen, &dst_rect);
1198 if (steps_done >= steps_final)
1200 if (draw_border_function != NULL)
1201 draw_border_function();
1203 #if defined(TARGET_SDL2)
1204 // SDL_UpdateWindowSurface(sdl_window);
1205 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
1206 UpdateScreen(&dst_rect2);
1208 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1218 for (alpha = 0.0; alpha < 255.0;)
1220 time_last = time_current;
1221 time_current = SDL_GetTicks();
1222 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1223 alpha_final = MIN(MAX(0, alpha), 255);
1225 /* draw existing (source) image to screen buffer */
1226 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1228 /* draw new (target) image to screen buffer using alpha blending */
1229 #if defined(TARGET_SDL2)
1230 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1231 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1233 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1235 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1237 if (draw_border_function != NULL)
1238 draw_border_function();
1241 /* only update the region of the screen that is affected from fading */
1242 #if defined(TARGET_SDL2)
1243 // SDL_UpdateWindowSurface(sdl_window);
1244 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1245 UpdateScreen(&dst_rect);
1247 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1250 SDL_Flip(surface_screen);
1258 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1259 int to_x, int to_y, Uint32 color)
1261 SDL_Surface *surface = dst_bitmap->surface;
1265 swap_numbers(&from_x, &to_x);
1268 swap_numbers(&from_y, &to_y);
1272 rect.w = (to_x - from_x + 1);
1273 rect.h = (to_y - from_y + 1);
1275 if (dst_bitmap == backbuffer || dst_bitmap == window)
1277 rect.x += video_xoffset;
1278 rect.y += video_yoffset;
1281 SDL_FillRect(surface, &rect, color);
1284 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1285 int to_x, int to_y, Uint32 color)
1287 if (dst_bitmap == backbuffer || dst_bitmap == window)
1289 from_x += video_xoffset;
1290 from_y += video_yoffset;
1291 to_x += video_xoffset;
1292 to_y += video_yoffset;
1295 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1299 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1300 int num_points, Uint32 color)
1305 for (i = 0; i < num_points - 1; i++)
1307 for (x = 0; x < line_width; x++)
1309 for (y = 0; y < line_width; y++)
1311 int dx = x - line_width / 2;
1312 int dy = y - line_width / 2;
1314 if ((x == 0 && y == 0) ||
1315 (x == 0 && y == line_width - 1) ||
1316 (x == line_width - 1 && y == 0) ||
1317 (x == line_width - 1 && y == line_width - 1))
1320 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1321 points[i+1].x + dx, points[i+1].y + dy, color);
1328 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1330 SDL_Surface *surface = src_bitmap->surface;
1332 if (src_bitmap == backbuffer || src_bitmap == window)
1338 switch (surface->format->BytesPerPixel)
1340 case 1: /* assuming 8-bpp */
1342 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1346 case 2: /* probably 15-bpp or 16-bpp */
1348 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1352 case 3: /* slow 24-bpp mode; usually not used */
1354 /* does this work? */
1355 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1359 shift = surface->format->Rshift;
1360 color |= *(pix + shift / 8) >> shift;
1361 shift = surface->format->Gshift;
1362 color |= *(pix + shift / 8) >> shift;
1363 shift = surface->format->Bshift;
1364 color |= *(pix + shift / 8) >> shift;
1370 case 4: /* probably 32-bpp */
1372 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1381 /* ========================================================================= */
1382 /* The following functions were taken from the SGE library */
1383 /* (SDL Graphics Extension Library) by Anders Lindström */
1384 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1385 /* ========================================================================= */
1387 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1389 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1391 switch (surface->format->BytesPerPixel)
1395 /* Assuming 8-bpp */
1396 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1402 /* Probably 15-bpp or 16-bpp */
1403 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1409 /* Slow 24-bpp mode, usually not used */
1413 /* Gack - slow, but endian correct */
1414 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1415 shift = surface->format->Rshift;
1416 *(pix+shift/8) = color>>shift;
1417 shift = surface->format->Gshift;
1418 *(pix+shift/8) = color>>shift;
1419 shift = surface->format->Bshift;
1420 *(pix+shift/8) = color>>shift;
1426 /* Probably 32-bpp */
1427 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1434 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1435 Uint8 R, Uint8 G, Uint8 B)
1437 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1440 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1442 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1445 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1447 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1450 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1455 /* Gack - slow, but endian correct */
1456 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1457 shift = surface->format->Rshift;
1458 *(pix+shift/8) = color>>shift;
1459 shift = surface->format->Gshift;
1460 *(pix+shift/8) = color>>shift;
1461 shift = surface->format->Bshift;
1462 *(pix+shift/8) = color>>shift;
1465 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1467 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1470 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1472 switch (dest->format->BytesPerPixel)
1475 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1479 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1483 _PutPixel24(dest,x,y,color);
1487 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1492 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1494 if (SDL_MUSTLOCK(surface))
1496 if (SDL_LockSurface(surface) < 0)
1502 _PutPixel(surface, x, y, color);
1504 if (SDL_MUSTLOCK(surface))
1506 SDL_UnlockSurface(surface);
1510 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1511 Uint8 r, Uint8 g, Uint8 b)
1513 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1516 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1518 if (y >= 0 && y <= dest->h - 1)
1520 switch (dest->format->BytesPerPixel)
1523 return y*dest->pitch;
1527 return y*dest->pitch/2;
1531 return y*dest->pitch;
1535 return y*dest->pitch/4;
1543 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1545 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1547 switch (surface->format->BytesPerPixel)
1551 /* Assuming 8-bpp */
1552 *((Uint8 *)surface->pixels + ypitch + x) = color;
1558 /* Probably 15-bpp or 16-bpp */
1559 *((Uint16 *)surface->pixels + ypitch + x) = color;
1565 /* Slow 24-bpp mode, usually not used */
1569 /* Gack - slow, but endian correct */
1570 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1571 shift = surface->format->Rshift;
1572 *(pix+shift/8) = color>>shift;
1573 shift = surface->format->Gshift;
1574 *(pix+shift/8) = color>>shift;
1575 shift = surface->format->Bshift;
1576 *(pix+shift/8) = color>>shift;
1582 /* Probably 32-bpp */
1583 *((Uint32 *)surface->pixels + ypitch + x) = color;
1590 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1595 if (SDL_MUSTLOCK(Surface))
1597 if (SDL_LockSurface(Surface) < 0)
1610 /* Do the clipping */
1611 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1615 if (x2 > Surface->w - 1)
1616 x2 = Surface->w - 1;
1623 SDL_FillRect(Surface, &l, Color);
1625 if (SDL_MUSTLOCK(Surface))
1627 SDL_UnlockSurface(Surface);
1631 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1632 Uint8 R, Uint8 G, Uint8 B)
1634 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1637 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1648 /* Do the clipping */
1649 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1653 if (x2 > Surface->w - 1)
1654 x2 = Surface->w - 1;
1661 SDL_FillRect(Surface, &l, Color);
1664 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1669 if (SDL_MUSTLOCK(Surface))
1671 if (SDL_LockSurface(Surface) < 0)
1684 /* Do the clipping */
1685 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1689 if (y2 > Surface->h - 1)
1690 y2 = Surface->h - 1;
1697 SDL_FillRect(Surface, &l, Color);
1699 if (SDL_MUSTLOCK(Surface))
1701 SDL_UnlockSurface(Surface);
1705 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1706 Uint8 R, Uint8 G, Uint8 B)
1708 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1711 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1722 /* Do the clipping */
1723 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1727 if (y2 > Surface->h - 1)
1728 y2 = Surface->h - 1;
1735 SDL_FillRect(Surface, &l, Color);
1738 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1739 Sint16 x2, Sint16 y2, Uint32 Color,
1740 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1743 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1748 sdx = (dx < 0) ? -1 : 1;
1749 sdy = (dy < 0) ? -1 : 1;
1761 for (x = 0; x < dx; x++)
1763 Callback(Surface, px, py, Color);
1777 for (y = 0; y < dy; y++)
1779 Callback(Surface, px, py, Color);
1793 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1794 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1795 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1798 sge_DoLine(Surface, X1, Y1, X2, Y2,
1799 SDL_MapRGB(Surface->format, R, G, B), Callback);
1802 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1805 if (SDL_MUSTLOCK(Surface))
1807 if (SDL_LockSurface(Surface) < 0)
1812 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1814 /* unlock the display */
1815 if (SDL_MUSTLOCK(Surface))
1817 SDL_UnlockSurface(Surface);
1821 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1822 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1824 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1827 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1829 if (dst_bitmap == backbuffer || dst_bitmap == window)
1835 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1840 -----------------------------------------------------------------------------
1841 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1842 -----------------------------------------------------------------------------
1845 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1846 int width, int height, Uint32 color)
1850 for (y = src_y; y < src_y + height; y++)
1852 for (x = src_x; x < src_x + width; x++)
1854 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1856 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1861 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1862 int src_x, int src_y, int width, int height,
1863 int dst_x, int dst_y)
1867 for (y = 0; y < height; y++)
1869 for (x = 0; x < width; x++)
1871 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1873 if (pixel != BLACK_PIXEL)
1874 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1880 /* ========================================================================= */
1881 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1882 /* (Rotozoomer) by Andreas Schiffler */
1883 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1884 /* ========================================================================= */
1887 -----------------------------------------------------------------------------
1890 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1891 -----------------------------------------------------------------------------
1902 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1905 tColorRGBA *sp, *csp, *dp;
1912 sp = csp = (tColorRGBA *) src->pixels;
1913 dp = (tColorRGBA *) dst->pixels;
1915 sgap = src->pitch - src->w * 4;
1917 dgap = dst->pitch - dst->w * 4;
1919 for (y = 0; y < dst->h; y++)
1923 for (x = 0; x < dst->w; x++)
1925 tColorRGBA *sp0 = sp;
1926 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1927 tColorRGBA *sp00 = &sp0[0];
1928 tColorRGBA *sp01 = &sp0[1];
1929 tColorRGBA *sp10 = &sp1[0];
1930 tColorRGBA *sp11 = &sp1[1];
1933 /* create new color pixel from all four source color pixels */
1934 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1935 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1936 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1937 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1942 /* advance source pointers */
1945 /* advance destination pointer */
1949 /* advance source pointer */
1950 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1952 /* advance destination pointers */
1953 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1959 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1961 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1962 tColorRGBA *sp, *csp, *dp;
1968 /* use specialized zoom function when scaling down to exactly half size */
1969 if (src->w == 2 * dst->w &&
1970 src->h == 2 * dst->h)
1971 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1973 /* variable setup */
1974 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1975 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1977 /* allocate memory for row increments */
1978 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1979 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1981 /* precalculate row increments */
1984 for (x = 0; x <= dst->w; x++)
1994 for (y = 0; y <= dst->h; y++)
2003 sp = csp = (tColorRGBA *) src->pixels;
2004 dp = (tColorRGBA *) dst->pixels;
2006 sgap = src->pitch - src->w * 4;
2008 dgap = dst->pitch - dst->w * 4;
2011 for (y = 0; y < dst->h; y++)
2016 for (x = 0; x < dst->w; x++)
2021 /* advance source pointers */
2023 sp += (*csax >> 16);
2025 /* advance destination pointer */
2029 /* advance source pointer */
2031 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
2033 /* advance destination pointers */
2034 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2044 -----------------------------------------------------------------------------
2047 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2048 -----------------------------------------------------------------------------
2051 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2053 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2054 Uint8 *sp, *dp, *csp;
2057 /* variable setup */
2058 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2059 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2061 /* allocate memory for row increments */
2062 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2063 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2065 /* precalculate row increments */
2068 for (x = 0; x < dst->w; x++)
2071 *csax = (csx >> 16);
2078 for (y = 0; y < dst->h; y++)
2081 *csay = (csy >> 16);
2088 for (x = 0; x < dst->w; x++)
2096 for (y = 0; y < dst->h; y++)
2103 sp = csp = (Uint8 *) src->pixels;
2104 dp = (Uint8 *) dst->pixels;
2105 dgap = dst->pitch - dst->w;
2109 for (y = 0; y < dst->h; y++)
2113 for (x = 0; x < dst->w; x++)
2118 /* advance source pointers */
2122 /* advance destination pointer */
2126 /* advance source pointer (for row) */
2127 csp += ((*csay) * src->pitch);
2130 /* advance destination pointers */
2141 -----------------------------------------------------------------------------
2144 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2145 'zoomx' and 'zoomy' are scaling factors for width and height.
2146 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2147 into a 32bit RGBA format on the fly.
2148 -----------------------------------------------------------------------------
2151 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2153 SDL_Surface *zoom_src = NULL;
2154 SDL_Surface *zoom_dst = NULL;
2155 boolean is_converted = FALSE;
2162 /* determine if source surface is 32 bit or 8 bit */
2163 is_32bit = (src->format->BitsPerPixel == 32);
2165 if (is_32bit || src->format->BitsPerPixel == 8)
2167 /* use source surface 'as is' */
2172 /* new source surface is 32 bit with a defined RGB ordering */
2173 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
2174 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2175 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2177 is_converted = TRUE;
2180 /* allocate surface to completely contain the zoomed surface */
2183 /* target surface is 32 bit with source RGBA/ABGR ordering */
2184 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
2185 zoom_src->format->Rmask,
2186 zoom_src->format->Gmask,
2187 zoom_src->format->Bmask, 0);
2191 /* target surface is 8 bit */
2192 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
2196 /* lock source surface */
2197 SDL_LockSurface(zoom_src);
2199 /* check which kind of surface we have */
2202 /* call the 32 bit transformation routine to do the zooming */
2203 zoomSurfaceRGBA(zoom_src, zoom_dst);
2208 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2209 zoom_dst->format->palette->colors[i] =
2210 zoom_src->format->palette->colors[i];
2211 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2213 /* call the 8 bit transformation routine to do the zooming */
2214 zoomSurfaceY(zoom_src, zoom_dst);
2217 /* unlock source surface */
2218 SDL_UnlockSurface(zoom_src);
2220 /* free temporary surface */
2222 SDL_FreeSurface(zoom_src);
2224 /* return destination surface */
2228 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
2230 SDL_Surface *sdl_surface_tmp;
2231 int dst_width = dst_bitmap->width;
2232 int dst_height = dst_bitmap->height;
2234 /* throw away old destination surface */
2235 SDL_FreeSurface(dst_bitmap->surface);
2237 /* create zoomed temporary surface from source surface */
2238 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2240 /* create native format destination surface from zoomed temporary surface */
2241 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
2243 /* free temporary surface */
2244 SDL_FreeSurface(sdl_surface_tmp);
2248 /* ========================================================================= */
2249 /* load image to bitmap */
2250 /* ========================================================================= */
2252 Bitmap *SDLLoadImage(char *filename)
2254 Bitmap *new_bitmap = CreateBitmapStruct();
2255 SDL_Surface *sdl_image_tmp;
2257 print_timestamp_init("SDLLoadImage");
2259 print_timestamp_time(getBaseNamePtr(filename));
2261 /* load image to temporary surface */
2262 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2264 SetError("IMG_Load(): %s", SDL_GetError());
2269 print_timestamp_time("IMG_Load");
2271 UPDATE_BUSY_STATE();
2273 /* create native non-transparent surface for current image */
2274 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2276 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2281 print_timestamp_time("SDL_DisplayFormat (opaque)");
2283 UPDATE_BUSY_STATE();
2285 /* create native transparent surface for current image */
2286 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2287 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2288 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2290 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2295 print_timestamp_time("SDL_DisplayFormat (masked)");
2297 UPDATE_BUSY_STATE();
2299 /* free temporary surface */
2300 SDL_FreeSurface(sdl_image_tmp);
2302 new_bitmap->width = new_bitmap->surface->w;
2303 new_bitmap->height = new_bitmap->surface->h;
2305 print_timestamp_done("SDLLoadImage");
2311 /* ------------------------------------------------------------------------- */
2312 /* custom cursor fuctions */
2313 /* ------------------------------------------------------------------------- */
2315 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2317 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2318 cursor_info->width, cursor_info->height,
2319 cursor_info->hot_x, cursor_info->hot_y);
2322 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2324 static struct MouseCursorInfo *last_cursor_info = NULL;
2325 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2326 static SDL_Cursor *cursor_default = NULL;
2327 static SDL_Cursor *cursor_current = NULL;
2329 /* if invoked for the first time, store the SDL default cursor */
2330 if (cursor_default == NULL)
2331 cursor_default = SDL_GetCursor();
2333 /* only create new cursor if cursor info (custom only) has changed */
2334 if (cursor_info != NULL && cursor_info != last_cursor_info)
2336 cursor_current = create_cursor(cursor_info);
2337 last_cursor_info = cursor_info;
2340 /* only set new cursor if cursor info (custom or NULL) has changed */
2341 if (cursor_info != last_cursor_info2)
2342 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2344 last_cursor_info2 = cursor_info;
2348 /* ========================================================================= */
2349 /* audio functions */
2350 /* ========================================================================= */
2352 void SDLOpenAudio(void)
2354 #if !defined(TARGET_SDL2)
2355 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2356 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2359 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2361 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2365 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2366 AUDIO_NUM_CHANNELS_STEREO,
2367 setup.system.audio_fragment_size) < 0)
2369 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2373 audio.sound_available = TRUE;
2374 audio.music_available = TRUE;
2375 audio.loops_available = TRUE;
2376 audio.sound_enabled = TRUE;
2378 /* set number of available mixer channels */
2379 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2380 audio.music_channel = MUSIC_CHANNEL;
2381 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2383 Mixer_InitChannels();
2386 void SDLCloseAudio(void)
2389 Mix_HaltChannel(-1);
2392 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2396 /* ========================================================================= */
2397 /* event functions */
2398 /* ========================================================================= */
2400 void SDLNextEvent(Event *event)
2402 SDL_WaitEvent(event);
2404 if (event->type == EVENT_BUTTONPRESS ||
2405 event->type == EVENT_BUTTONRELEASE)
2407 if (((ButtonEvent *)event)->x > video_xoffset)
2408 ((ButtonEvent *)event)->x -= video_xoffset;
2410 ((ButtonEvent *)event)->x = 0;
2411 if (((ButtonEvent *)event)->y > video_yoffset)
2412 ((ButtonEvent *)event)->y -= video_yoffset;
2414 ((ButtonEvent *)event)->y = 0;
2416 else if (event->type == EVENT_MOTIONNOTIFY)
2418 if (((MotionEvent *)event)->x > video_xoffset)
2419 ((MotionEvent *)event)->x -= video_xoffset;
2421 ((MotionEvent *)event)->x = 0;
2422 if (((MotionEvent *)event)->y > video_yoffset)
2423 ((MotionEvent *)event)->y -= video_yoffset;
2425 ((MotionEvent *)event)->y = 0;
2429 void SDLHandleWindowManagerEvent(Event *event)
2431 #if defined(PLATFORM_WIN32)
2432 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2433 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2435 if (syswmmsg->msg == WM_DROPFILES)
2437 HDROP hdrop = (HDROP)syswmmsg->wParam;
2440 printf("::: SDL_SYSWMEVENT:\n");
2442 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2444 for (i = 0; i < num_files; i++)
2446 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2447 char buffer[buffer_len + 1];
2449 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2451 printf("::: - '%s'\n", buffer);
2454 DragFinish((HDROP)syswmmsg->wParam);
2460 /* ========================================================================= */
2461 /* joystick functions */
2462 /* ========================================================================= */
2464 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2465 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2466 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2468 static boolean SDLOpenJoystick(int nr)
2470 if (nr < 0 || nr > MAX_PLAYERS)
2473 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2476 static void SDLCloseJoystick(int nr)
2478 if (nr < 0 || nr > MAX_PLAYERS)
2481 SDL_JoystickClose(sdl_joystick[nr]);
2483 sdl_joystick[nr] = NULL;
2486 static boolean SDLCheckJoystickOpened(int nr)
2488 if (nr < 0 || nr > MAX_PLAYERS)
2491 #if defined(TARGET_SDL2)
2492 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2494 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2498 void HandleJoystickEvent(Event *event)
2502 case SDL_JOYAXISMOTION:
2503 if (event->jaxis.axis < 2)
2504 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2507 case SDL_JOYBUTTONDOWN:
2508 if (event->jbutton.button < 2)
2509 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2512 case SDL_JOYBUTTONUP:
2513 if (event->jbutton.button < 2)
2514 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2522 void SDLInitJoysticks()
2524 static boolean sdl_joystick_subsystem_initialized = FALSE;
2525 boolean print_warning = !sdl_joystick_subsystem_initialized;
2528 if (!sdl_joystick_subsystem_initialized)
2530 sdl_joystick_subsystem_initialized = TRUE;
2532 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2534 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2539 for (i = 0; i < MAX_PLAYERS; i++)
2541 /* get configured joystick for this player */
2542 char *device_name = setup.input[i].joy.device_name;
2543 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2545 if (joystick_nr >= SDL_NumJoysticks())
2547 if (setup.input[i].use_joystick && print_warning)
2548 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2553 /* misuse joystick file descriptor variable to store joystick number */
2554 joystick.fd[i] = joystick_nr;
2556 if (joystick_nr == -1)
2559 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2560 if (SDLCheckJoystickOpened(joystick_nr))
2561 SDLCloseJoystick(joystick_nr);
2563 if (!setup.input[i].use_joystick)
2566 if (!SDLOpenJoystick(joystick_nr))
2569 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2574 joystick.status = JOYSTICK_ACTIVATED;
2578 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2580 if (nr < 0 || nr >= MAX_PLAYERS)
2584 *x = sdl_js_axis[nr][0];
2586 *y = sdl_js_axis[nr][1];
2589 *b1 = sdl_js_button[nr][0];
2591 *b2 = sdl_js_button[nr][1];
2596 #endif /* TARGET_SDL */