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)
424 printf("::: GAME STARTS WITH FULLSCREEN %d\n", fullscreen);
427 video.fullscreen_initial = fullscreen;
431 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
432 #if !USE_DESKTOP_FULLSCREEN
433 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
436 video.window_width = window_scaling_factor * width;
437 video.window_height = window_scaling_factor * height;
440 printf("::: use window scaling factor %f\n", screen_scaling_factor);
443 if ((*backbuffer)->surface)
445 SDL_FreeSurface((*backbuffer)->surface);
446 (*backbuffer)->surface = NULL;
451 SDL_DestroyTexture(sdl_texture);
455 if (!(fullscreen && fullscreen_enabled))
459 SDL_DestroyRenderer(sdl_renderer);
465 SDL_DestroyWindow(sdl_window);
471 Error(ERR_INFO, "::: checking 'sdl_window' ...");
473 if (sdl_window == NULL)
474 Error(ERR_INFO, "::: calling SDL_CreateWindow() [%d, %d, %d] ...",
475 setup.fullscreen, fullscreen, fullscreen_enabled);
478 if (sdl_window == NULL)
479 sdl_window = SDL_CreateWindow(program.window_title,
480 SDL_WINDOWPOS_CENTERED,
481 SDL_WINDOWPOS_CENTERED,
482 #if USE_DESKTOP_FULLSCREEN
486 (int)(screen_scaling_factor * width),
487 (int)(screen_scaling_factor * height),
491 if (sdl_window != NULL)
493 if (sdl_renderer == NULL)
494 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
496 if (sdl_renderer != NULL)
498 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
499 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
501 sdl_texture = SDL_CreateTexture(sdl_renderer,
502 SDL_PIXELFORMAT_ARGB8888,
503 SDL_TEXTUREACCESS_STREAMING,
506 if (sdl_texture != NULL)
509 // (do not use alpha channel)
510 new_surface = SDL_CreateRGBSurface(0, width, height, 32,
516 // (this uses an alpha channel, which we don't want here)
517 new_surface = SDL_CreateRGBSurface(0, width, height, 32,
524 if (new_surface == NULL)
525 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
530 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
535 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
540 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
546 SDL_DestroyWindow(sdl_window);
548 sdl_window = SDL_CreateWindow(program.window_title,
549 SDL_WINDOWPOS_CENTERED,
550 SDL_WINDOWPOS_CENTERED,
554 if (sdl_window != NULL)
555 new_surface = SDL_GetWindowSurface(sdl_window);
559 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
562 // store fullscreen state ("video.fullscreen_enabled" may not reflect this!)
563 if (new_surface != NULL)
564 fullscreen_enabled = fullscreen;
569 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
571 boolean success = TRUE;
574 #if defined(TARGET_SDL2)
575 // int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
576 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
577 int surface_flags_window = SURFACE_FLAGS;
579 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
580 int surface_flags_window = SURFACE_FLAGS;
583 SDL_Surface *new_surface = NULL;
585 if (*backbuffer == NULL)
586 *backbuffer = CreateBitmapStruct();
588 /* (real bitmap might be larger in fullscreen mode with video offsets) */
589 (*backbuffer)->width = video.width;
590 (*backbuffer)->height = video.height;
592 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
594 setFullscreenParameters(setup.fullscreen_mode);
596 video_xoffset = fullscreen_xoffset;
597 video_yoffset = fullscreen_yoffset;
599 /* switch display to fullscreen mode, if available */
601 new_surface = SDLCreateScreen(backbuffer, TRUE);
604 #if defined(TARGET_SDL2)
605 sdl_window = SDL_CreateWindow(program.window_title,
606 SDL_WINDOWPOS_CENTERED,
607 SDL_WINDOWPOS_CENTERED,
608 fullscreen_width, fullscreen_height,
609 surface_flags_fullscreen);
610 if (sdl_window != NULL)
612 new_surface = SDL_GetWindowSurface(sdl_window);
614 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
615 // UpdateScreen(NULL); // immediately map window
618 new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
619 video.depth, surface_flags_fullscreen);
623 if (new_surface == NULL)
625 /* switching display to fullscreen mode failed */
626 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
628 /* do not try it again */
629 video.fullscreen_available = FALSE;
635 (*backbuffer)->surface = new_surface;
637 video.fullscreen_enabled = TRUE;
638 video.fullscreen_mode_current = setup.fullscreen_mode;
644 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
649 /* switch display to window mode */
651 new_surface = SDLCreateScreen(backbuffer, FALSE);
654 #if defined(TARGET_SDL2)
657 float screen_scaling_factor = 1.2;
658 int test_fullscreen = 0;
659 int surface_flags = (test_fullscreen ? surface_flags_fullscreen :
660 surface_flags_window);
662 if ((*backbuffer)->surface)
663 SDL_FreeSurface((*backbuffer)->surface);
666 SDL_DestroyTexture(sdl_texture);
669 SDL_DestroyRenderer(sdl_renderer);
672 SDL_DestroyWindow(sdl_window);
674 sdl_window = SDL_CreateWindow(program.window_title,
675 SDL_WINDOWPOS_CENTERED,
676 SDL_WINDOWPOS_CENTERED,
677 (int)(screen_scaling_factor * video.width),
678 (int)(screen_scaling_factor * video.height),
681 if (sdl_window != NULL)
683 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
685 if (sdl_renderer != NULL)
687 SDL_RenderSetLogicalSize(sdl_renderer, video.width, video.height);
688 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
690 sdl_texture = SDL_CreateTexture(sdl_renderer,
691 SDL_PIXELFORMAT_ARGB8888,
692 SDL_TEXTUREACCESS_STREAMING,
693 video.width, video.height);
695 if (sdl_texture != NULL)
698 // (do not use alpha channel)
699 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
705 // (this uses an alpha channel, which we don't want here)
706 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
713 if (new_surface == NULL)
714 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
719 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
724 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
729 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
735 SDL_DestroyWindow(sdl_window);
737 sdl_window = SDL_CreateWindow(program.window_title,
738 SDL_WINDOWPOS_CENTERED,
739 SDL_WINDOWPOS_CENTERED,
740 video.width, video.height,
741 surface_flags_window);
743 if (sdl_window != NULL)
745 new_surface = SDL_GetWindowSurface(sdl_window);
747 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
748 // UpdateScreen(NULL); // immediately map window
753 new_surface = SDL_SetVideoMode(video.width, video.height,
754 video.depth, surface_flags_window);
758 if (new_surface == NULL)
760 /* switching display to window mode failed -- should not happen */
761 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
767 (*backbuffer)->surface = new_surface;
769 video.fullscreen_enabled = FALSE;
770 video.window_scaling_percent = setup.window_scaling_percent;
776 #if defined(TARGET_SDL2)
777 SDLRedrawWindow(); // map window
778 // UpdateScreen(NULL); // map window
782 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
784 #if defined(PLATFORM_WIN32)
786 SDL_SysWMinfo wminfo;
789 SDL_VERSION(&wminfo.version);
790 SDL_GetWMInfo(&wminfo);
792 hwnd = wminfo.window;
794 DragAcceptFiles(hwnd, TRUE);
802 #if defined(TARGET_SDL2)
803 void SDLSetWindowScaling(int window_scaling_percent)
805 if (sdl_window == NULL)
808 float window_scaling_factor = (float)window_scaling_percent / 100;
809 int new_window_width = (int)(window_scaling_factor * video.width);
810 int new_window_height = (int)(window_scaling_factor * video.height);
813 Error(ERR_DEBUG, "::: SDLSetWindowScaling(%d) ...", window_scaling_percent);
816 SDL_SetWindowSize(sdl_window, new_window_width, new_window_height);
818 video.window_scaling_percent = window_scaling_percent;
819 video.window_width = new_window_width;
820 video.window_height = new_window_height;
823 void SDLSetWindowFullscreen(boolean fullscreen)
825 if (sdl_window == NULL)
828 #if USE_DESKTOP_FULLSCREEN
829 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
831 int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
835 Error(ERR_DEBUG, "::: SDL_SetWindowFullscreen(%d) ...", fullscreen);
838 if (SDL_SetWindowFullscreen(sdl_window, flags) == 0)
839 video.fullscreen_enabled = fullscreen;
842 printf("::: SDLSetWindowFullscreen: %d, %d\n",
843 fullscreen, video.fullscreen_initial);
847 // if game started in fullscreen mode, window will also get fullscreen size
848 if (!fullscreen && video.fullscreen_initial)
850 SDLSetWindowScaling(setup.window_scaling_percent);
851 SDL_SetWindowPosition(sdl_window,
852 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
854 video.fullscreen_initial = FALSE;
859 void SDLRedrawWindow()
865 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
868 SDL_Surface *surface_tmp, *surface_native;
870 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
873 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
875 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
876 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
878 SDL_FreeSurface(surface_tmp);
880 new_bitmap->surface = surface_native;
883 void SDLFreeBitmapPointers(Bitmap *bitmap)
886 SDL_FreeSurface(bitmap->surface);
887 if (bitmap->surface_masked)
888 SDL_FreeSurface(bitmap->surface_masked);
889 bitmap->surface = NULL;
890 bitmap->surface_masked = NULL;
893 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
894 int src_x, int src_y, int width, int height,
895 int dst_x, int dst_y, int mask_mode)
897 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
898 SDL_Rect src_rect, dst_rect;
900 if (src_bitmap == backbuffer)
902 src_x += video_xoffset;
903 src_y += video_yoffset;
911 if (dst_bitmap == backbuffer || dst_bitmap == window)
913 dst_x += video_xoffset;
914 dst_y += video_yoffset;
922 // if (src_bitmap != backbuffer || dst_bitmap != window)
923 if (!(src_bitmap == backbuffer && dst_bitmap == window))
924 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
925 src_bitmap->surface_masked : src_bitmap->surface),
926 &src_rect, real_dst_bitmap->surface, &dst_rect);
928 #if defined(TARGET_SDL2)
929 if (dst_bitmap == window)
931 // SDL_UpdateWindowSurface(sdl_window);
932 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
933 UpdateScreen(&dst_rect);
936 if (dst_bitmap == window)
937 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
941 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
944 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
947 if (dst_bitmap == backbuffer || dst_bitmap == window)
958 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
960 #if defined(TARGET_SDL2)
961 if (dst_bitmap == window)
963 // SDL_UpdateWindowSurface(sdl_window);
964 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
968 if (dst_bitmap == window)
969 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
973 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
974 int fade_mode, int fade_delay, int post_delay,
975 void (*draw_border_function)(void))
977 static boolean initialization_needed = TRUE;
978 static SDL_Surface *surface_source = NULL;
979 static SDL_Surface *surface_target = NULL;
980 static SDL_Surface *surface_black = NULL;
981 SDL_Surface *surface_screen = backbuffer->surface;
982 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
983 SDL_Rect src_rect, dst_rect;
984 #if defined(TARGET_SDL2)
987 int src_x = x, src_y = y;
988 int dst_x = x, dst_y = y;
989 unsigned int time_last, time_current;
991 /* check if screen size has changed */
992 if (surface_source != NULL && (video.width != surface_source->w ||
993 video.height != surface_source->h))
995 SDL_FreeSurface(surface_source);
996 SDL_FreeSurface(surface_target);
997 SDL_FreeSurface(surface_black);
999 initialization_needed = TRUE;
1005 src_rect.h = height;
1007 dst_x += video_xoffset;
1008 dst_y += video_yoffset;
1012 dst_rect.w = width; /* (ignored) */
1013 dst_rect.h = height; /* (ignored) */
1015 #if defined(TARGET_SDL2)
1016 dst_rect2 = dst_rect;
1019 if (initialization_needed)
1021 #if defined(TARGET_SDL2)
1022 unsigned int flags = 0;
1024 unsigned int flags = SDL_SRCALPHA;
1026 /* use same surface type as screen surface */
1027 if ((surface_screen->flags & SDL_HWSURFACE))
1028 flags |= SDL_HWSURFACE;
1030 flags |= SDL_SWSURFACE;
1033 /* create surface for temporary copy of screen buffer (source) */
1034 if ((surface_source =
1035 SDL_CreateRGBSurface(flags,
1038 surface_screen->format->BitsPerPixel,
1039 surface_screen->format->Rmask,
1040 surface_screen->format->Gmask,
1041 surface_screen->format->Bmask,
1042 surface_screen->format->Amask)) == NULL)
1043 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1045 /* create surface for cross-fading screen buffer (target) */
1046 if ((surface_target =
1047 SDL_CreateRGBSurface(flags,
1050 surface_screen->format->BitsPerPixel,
1051 surface_screen->format->Rmask,
1052 surface_screen->format->Gmask,
1053 surface_screen->format->Bmask,
1054 surface_screen->format->Amask)) == NULL)
1055 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1057 /* create black surface for fading from/to black */
1058 if ((surface_black =
1059 SDL_CreateRGBSurface(flags,
1062 surface_screen->format->BitsPerPixel,
1063 surface_screen->format->Rmask,
1064 surface_screen->format->Gmask,
1065 surface_screen->format->Bmask,
1066 surface_screen->format->Amask)) == NULL)
1067 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
1069 /* completely fill the surface with black color pixels */
1070 SDL_FillRect(surface_black, NULL,
1071 SDL_MapRGB(surface_screen->format, 0, 0, 0));
1073 initialization_needed = FALSE;
1076 /* copy source and target surfaces to temporary surfaces for fading */
1077 if (fade_mode & FADE_TYPE_TRANSFORM)
1079 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
1080 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1082 else if (fade_mode & FADE_TYPE_FADE_IN)
1084 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
1085 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
1087 else /* FADE_TYPE_FADE_OUT */
1089 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
1090 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
1093 time_current = SDL_GetTicks();
1095 if (fade_mode == FADE_MODE_MELT)
1097 boolean done = FALSE;
1098 int melt_pixels = 2;
1099 int melt_columns = width / melt_pixels;
1100 int ypos[melt_columns];
1101 int max_steps = height / 8 + 32;
1106 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1107 #if defined(TARGET_SDL2)
1108 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
1110 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
1113 ypos[0] = -GetSimpleRandom(16);
1115 for (i = 1 ; i < melt_columns; i++)
1117 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1119 ypos[i] = ypos[i - 1] + r;
1132 time_last = time_current;
1133 time_current = SDL_GetTicks();
1134 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1135 steps_final = MIN(MAX(0, steps), max_steps);
1139 done = (steps_done >= steps_final);
1141 for (i = 0 ; i < melt_columns; i++)
1149 else if (ypos[i] < height)
1154 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1156 if (ypos[i] + dy >= height)
1157 dy = height - ypos[i];
1159 /* copy part of (appearing) target surface to upper area */
1160 src_rect.x = src_x + i * melt_pixels;
1161 // src_rect.y = src_y + ypos[i];
1163 src_rect.w = melt_pixels;
1165 src_rect.h = ypos[i] + dy;
1167 dst_rect.x = dst_x + i * melt_pixels;
1168 // dst_rect.y = dst_y + ypos[i];
1171 if (steps_done >= steps_final)
1172 SDL_BlitSurface(surface_target, &src_rect,
1173 surface_screen, &dst_rect);
1177 /* copy part of (disappearing) source surface to lower area */
1178 src_rect.x = src_x + i * melt_pixels;
1180 src_rect.w = melt_pixels;
1181 src_rect.h = height - ypos[i];
1183 dst_rect.x = dst_x + i * melt_pixels;
1184 dst_rect.y = dst_y + ypos[i];
1186 if (steps_done >= steps_final)
1187 SDL_BlitSurface(surface_source, &src_rect,
1188 surface_screen, &dst_rect);
1194 src_rect.x = src_x + i * melt_pixels;
1196 src_rect.w = melt_pixels;
1197 src_rect.h = height;
1199 dst_rect.x = dst_x + i * melt_pixels;
1202 if (steps_done >= steps_final)
1203 SDL_BlitSurface(surface_target, &src_rect,
1204 surface_screen, &dst_rect);
1208 if (steps_done >= steps_final)
1210 if (draw_border_function != NULL)
1211 draw_border_function();
1213 #if defined(TARGET_SDL2)
1214 // SDL_UpdateWindowSurface(sdl_window);
1215 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
1216 UpdateScreen(&dst_rect2);
1218 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1228 for (alpha = 0.0; alpha < 255.0;)
1230 time_last = time_current;
1231 time_current = SDL_GetTicks();
1232 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1233 alpha_final = MIN(MAX(0, alpha), 255);
1235 /* draw existing (source) image to screen buffer */
1236 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1238 /* draw new (target) image to screen buffer using alpha blending */
1239 #if defined(TARGET_SDL2)
1240 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1241 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1243 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1245 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1247 if (draw_border_function != NULL)
1248 draw_border_function();
1251 /* only update the region of the screen that is affected from fading */
1252 #if defined(TARGET_SDL2)
1253 // SDL_UpdateWindowSurface(sdl_window);
1254 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1255 UpdateScreen(&dst_rect);
1257 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1260 SDL_Flip(surface_screen);
1268 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1269 int to_x, int to_y, Uint32 color)
1271 SDL_Surface *surface = dst_bitmap->surface;
1275 swap_numbers(&from_x, &to_x);
1278 swap_numbers(&from_y, &to_y);
1282 rect.w = (to_x - from_x + 1);
1283 rect.h = (to_y - from_y + 1);
1285 if (dst_bitmap == backbuffer || dst_bitmap == window)
1287 rect.x += video_xoffset;
1288 rect.y += video_yoffset;
1291 SDL_FillRect(surface, &rect, color);
1294 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1295 int to_x, int to_y, Uint32 color)
1297 if (dst_bitmap == backbuffer || dst_bitmap == window)
1299 from_x += video_xoffset;
1300 from_y += video_yoffset;
1301 to_x += video_xoffset;
1302 to_y += video_yoffset;
1305 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1309 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1310 int num_points, Uint32 color)
1315 for (i = 0; i < num_points - 1; i++)
1317 for (x = 0; x < line_width; x++)
1319 for (y = 0; y < line_width; y++)
1321 int dx = x - line_width / 2;
1322 int dy = y - line_width / 2;
1324 if ((x == 0 && y == 0) ||
1325 (x == 0 && y == line_width - 1) ||
1326 (x == line_width - 1 && y == 0) ||
1327 (x == line_width - 1 && y == line_width - 1))
1330 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1331 points[i+1].x + dx, points[i+1].y + dy, color);
1338 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1340 SDL_Surface *surface = src_bitmap->surface;
1342 if (src_bitmap == backbuffer || src_bitmap == window)
1348 switch (surface->format->BytesPerPixel)
1350 case 1: /* assuming 8-bpp */
1352 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1356 case 2: /* probably 15-bpp or 16-bpp */
1358 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1362 case 3: /* slow 24-bpp mode; usually not used */
1364 /* does this work? */
1365 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1369 shift = surface->format->Rshift;
1370 color |= *(pix + shift / 8) >> shift;
1371 shift = surface->format->Gshift;
1372 color |= *(pix + shift / 8) >> shift;
1373 shift = surface->format->Bshift;
1374 color |= *(pix + shift / 8) >> shift;
1380 case 4: /* probably 32-bpp */
1382 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1391 /* ========================================================================= */
1392 /* The following functions were taken from the SGE library */
1393 /* (SDL Graphics Extension Library) by Anders Lindström */
1394 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1395 /* ========================================================================= */
1397 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1399 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1401 switch (surface->format->BytesPerPixel)
1405 /* Assuming 8-bpp */
1406 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1412 /* Probably 15-bpp or 16-bpp */
1413 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1419 /* Slow 24-bpp mode, usually not used */
1423 /* Gack - slow, but endian correct */
1424 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1425 shift = surface->format->Rshift;
1426 *(pix+shift/8) = color>>shift;
1427 shift = surface->format->Gshift;
1428 *(pix+shift/8) = color>>shift;
1429 shift = surface->format->Bshift;
1430 *(pix+shift/8) = color>>shift;
1436 /* Probably 32-bpp */
1437 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1444 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1445 Uint8 R, Uint8 G, Uint8 B)
1447 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1450 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1452 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1455 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1457 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1460 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1465 /* Gack - slow, but endian correct */
1466 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1467 shift = surface->format->Rshift;
1468 *(pix+shift/8) = color>>shift;
1469 shift = surface->format->Gshift;
1470 *(pix+shift/8) = color>>shift;
1471 shift = surface->format->Bshift;
1472 *(pix+shift/8) = color>>shift;
1475 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1477 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1480 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1482 switch (dest->format->BytesPerPixel)
1485 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1489 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1493 _PutPixel24(dest,x,y,color);
1497 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1502 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1504 if (SDL_MUSTLOCK(surface))
1506 if (SDL_LockSurface(surface) < 0)
1512 _PutPixel(surface, x, y, color);
1514 if (SDL_MUSTLOCK(surface))
1516 SDL_UnlockSurface(surface);
1520 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1521 Uint8 r, Uint8 g, Uint8 b)
1523 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1526 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1528 if (y >= 0 && y <= dest->h - 1)
1530 switch (dest->format->BytesPerPixel)
1533 return y*dest->pitch;
1537 return y*dest->pitch/2;
1541 return y*dest->pitch;
1545 return y*dest->pitch/4;
1553 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1555 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1557 switch (surface->format->BytesPerPixel)
1561 /* Assuming 8-bpp */
1562 *((Uint8 *)surface->pixels + ypitch + x) = color;
1568 /* Probably 15-bpp or 16-bpp */
1569 *((Uint16 *)surface->pixels + ypitch + x) = color;
1575 /* Slow 24-bpp mode, usually not used */
1579 /* Gack - slow, but endian correct */
1580 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1581 shift = surface->format->Rshift;
1582 *(pix+shift/8) = color>>shift;
1583 shift = surface->format->Gshift;
1584 *(pix+shift/8) = color>>shift;
1585 shift = surface->format->Bshift;
1586 *(pix+shift/8) = color>>shift;
1592 /* Probably 32-bpp */
1593 *((Uint32 *)surface->pixels + ypitch + x) = color;
1600 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1605 if (SDL_MUSTLOCK(Surface))
1607 if (SDL_LockSurface(Surface) < 0)
1620 /* Do the clipping */
1621 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1625 if (x2 > Surface->w - 1)
1626 x2 = Surface->w - 1;
1633 SDL_FillRect(Surface, &l, Color);
1635 if (SDL_MUSTLOCK(Surface))
1637 SDL_UnlockSurface(Surface);
1641 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1642 Uint8 R, Uint8 G, Uint8 B)
1644 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1647 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1658 /* Do the clipping */
1659 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1663 if (x2 > Surface->w - 1)
1664 x2 = Surface->w - 1;
1671 SDL_FillRect(Surface, &l, Color);
1674 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1679 if (SDL_MUSTLOCK(Surface))
1681 if (SDL_LockSurface(Surface) < 0)
1694 /* Do the clipping */
1695 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1699 if (y2 > Surface->h - 1)
1700 y2 = Surface->h - 1;
1707 SDL_FillRect(Surface, &l, Color);
1709 if (SDL_MUSTLOCK(Surface))
1711 SDL_UnlockSurface(Surface);
1715 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1716 Uint8 R, Uint8 G, Uint8 B)
1718 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1721 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1732 /* Do the clipping */
1733 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1737 if (y2 > Surface->h - 1)
1738 y2 = Surface->h - 1;
1745 SDL_FillRect(Surface, &l, Color);
1748 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1749 Sint16 x2, Sint16 y2, Uint32 Color,
1750 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1753 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1758 sdx = (dx < 0) ? -1 : 1;
1759 sdy = (dy < 0) ? -1 : 1;
1771 for (x = 0; x < dx; x++)
1773 Callback(Surface, px, py, Color);
1787 for (y = 0; y < dy; y++)
1789 Callback(Surface, px, py, Color);
1803 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1804 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1805 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1808 sge_DoLine(Surface, X1, Y1, X2, Y2,
1809 SDL_MapRGB(Surface->format, R, G, B), Callback);
1812 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1815 if (SDL_MUSTLOCK(Surface))
1817 if (SDL_LockSurface(Surface) < 0)
1822 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1824 /* unlock the display */
1825 if (SDL_MUSTLOCK(Surface))
1827 SDL_UnlockSurface(Surface);
1831 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1832 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1834 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1837 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1839 if (dst_bitmap == backbuffer || dst_bitmap == window)
1845 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1850 -----------------------------------------------------------------------------
1851 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1852 -----------------------------------------------------------------------------
1855 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1856 int width, int height, Uint32 color)
1860 for (y = src_y; y < src_y + height; y++)
1862 for (x = src_x; x < src_x + width; x++)
1864 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1866 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1871 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1872 int src_x, int src_y, int width, int height,
1873 int dst_x, int dst_y)
1877 for (y = 0; y < height; y++)
1879 for (x = 0; x < width; x++)
1881 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1883 if (pixel != BLACK_PIXEL)
1884 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1890 /* ========================================================================= */
1891 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1892 /* (Rotozoomer) by Andreas Schiffler */
1893 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1894 /* ========================================================================= */
1897 -----------------------------------------------------------------------------
1900 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1901 -----------------------------------------------------------------------------
1912 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1915 tColorRGBA *sp, *csp, *dp;
1922 sp = csp = (tColorRGBA *) src->pixels;
1923 dp = (tColorRGBA *) dst->pixels;
1925 sgap = src->pitch - src->w * 4;
1927 dgap = dst->pitch - dst->w * 4;
1929 for (y = 0; y < dst->h; y++)
1933 for (x = 0; x < dst->w; x++)
1935 tColorRGBA *sp0 = sp;
1936 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1937 tColorRGBA *sp00 = &sp0[0];
1938 tColorRGBA *sp01 = &sp0[1];
1939 tColorRGBA *sp10 = &sp1[0];
1940 tColorRGBA *sp11 = &sp1[1];
1943 /* create new color pixel from all four source color pixels */
1944 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1945 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1946 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1947 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1952 /* advance source pointers */
1955 /* advance destination pointer */
1959 /* advance source pointer */
1960 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1962 /* advance destination pointers */
1963 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1969 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1971 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1972 tColorRGBA *sp, *csp, *dp;
1978 /* use specialized zoom function when scaling down to exactly half size */
1979 if (src->w == 2 * dst->w &&
1980 src->h == 2 * dst->h)
1981 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1983 /* variable setup */
1984 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1985 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1987 /* allocate memory for row increments */
1988 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1989 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1991 /* precalculate row increments */
1994 for (x = 0; x <= dst->w; x++)
2004 for (y = 0; y <= dst->h; y++)
2013 sp = csp = (tColorRGBA *) src->pixels;
2014 dp = (tColorRGBA *) dst->pixels;
2016 sgap = src->pitch - src->w * 4;
2018 dgap = dst->pitch - dst->w * 4;
2021 for (y = 0; y < dst->h; y++)
2026 for (x = 0; x < dst->w; x++)
2031 /* advance source pointers */
2033 sp += (*csax >> 16);
2035 /* advance destination pointer */
2039 /* advance source pointer */
2041 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
2043 /* advance destination pointers */
2044 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
2054 -----------------------------------------------------------------------------
2057 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
2058 -----------------------------------------------------------------------------
2061 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
2063 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
2064 Uint8 *sp, *dp, *csp;
2067 /* variable setup */
2068 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
2069 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
2071 /* allocate memory for row increments */
2072 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
2073 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
2075 /* precalculate row increments */
2078 for (x = 0; x < dst->w; x++)
2081 *csax = (csx >> 16);
2088 for (y = 0; y < dst->h; y++)
2091 *csay = (csy >> 16);
2098 for (x = 0; x < dst->w; x++)
2106 for (y = 0; y < dst->h; y++)
2113 sp = csp = (Uint8 *) src->pixels;
2114 dp = (Uint8 *) dst->pixels;
2115 dgap = dst->pitch - dst->w;
2119 for (y = 0; y < dst->h; y++)
2123 for (x = 0; x < dst->w; x++)
2128 /* advance source pointers */
2132 /* advance destination pointer */
2136 /* advance source pointer (for row) */
2137 csp += ((*csay) * src->pitch);
2140 /* advance destination pointers */
2151 -----------------------------------------------------------------------------
2154 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2155 'zoomx' and 'zoomy' are scaling factors for width and height.
2156 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2157 into a 32bit RGBA format on the fly.
2158 -----------------------------------------------------------------------------
2161 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2163 SDL_Surface *zoom_src = NULL;
2164 SDL_Surface *zoom_dst = NULL;
2165 boolean is_converted = FALSE;
2172 /* determine if source surface is 32 bit or 8 bit */
2173 is_32bit = (src->format->BitsPerPixel == 32);
2175 if (is_32bit || src->format->BitsPerPixel == 8)
2177 /* use source surface 'as is' */
2182 /* new source surface is 32 bit with a defined RGB ordering */
2183 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
2184 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2185 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2187 is_converted = TRUE;
2190 /* allocate surface to completely contain the zoomed surface */
2193 /* target surface is 32 bit with source RGBA/ABGR ordering */
2194 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
2195 zoom_src->format->Rmask,
2196 zoom_src->format->Gmask,
2197 zoom_src->format->Bmask, 0);
2201 /* target surface is 8 bit */
2202 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
2206 /* lock source surface */
2207 SDL_LockSurface(zoom_src);
2209 /* check which kind of surface we have */
2212 /* call the 32 bit transformation routine to do the zooming */
2213 zoomSurfaceRGBA(zoom_src, zoom_dst);
2218 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2219 zoom_dst->format->palette->colors[i] =
2220 zoom_src->format->palette->colors[i];
2221 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2223 /* call the 8 bit transformation routine to do the zooming */
2224 zoomSurfaceY(zoom_src, zoom_dst);
2227 /* unlock source surface */
2228 SDL_UnlockSurface(zoom_src);
2230 /* free temporary surface */
2232 SDL_FreeSurface(zoom_src);
2234 /* return destination surface */
2238 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
2240 SDL_Surface *sdl_surface_tmp;
2241 int dst_width = dst_bitmap->width;
2242 int dst_height = dst_bitmap->height;
2244 /* throw away old destination surface */
2245 SDL_FreeSurface(dst_bitmap->surface);
2247 /* create zoomed temporary surface from source surface */
2248 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2250 /* create native format destination surface from zoomed temporary surface */
2251 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
2253 /* free temporary surface */
2254 SDL_FreeSurface(sdl_surface_tmp);
2258 /* ========================================================================= */
2259 /* load image to bitmap */
2260 /* ========================================================================= */
2262 Bitmap *SDLLoadImage(char *filename)
2264 Bitmap *new_bitmap = CreateBitmapStruct();
2265 SDL_Surface *sdl_image_tmp;
2267 print_timestamp_init("SDLLoadImage");
2269 print_timestamp_time(getBaseNamePtr(filename));
2271 /* load image to temporary surface */
2272 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2274 SetError("IMG_Load(): %s", SDL_GetError());
2279 print_timestamp_time("IMG_Load");
2281 UPDATE_BUSY_STATE();
2283 /* create native non-transparent surface for current image */
2284 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2286 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2291 print_timestamp_time("SDL_DisplayFormat (opaque)");
2293 UPDATE_BUSY_STATE();
2295 /* create native transparent surface for current image */
2296 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2297 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2298 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2300 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2305 print_timestamp_time("SDL_DisplayFormat (masked)");
2307 UPDATE_BUSY_STATE();
2309 /* free temporary surface */
2310 SDL_FreeSurface(sdl_image_tmp);
2312 new_bitmap->width = new_bitmap->surface->w;
2313 new_bitmap->height = new_bitmap->surface->h;
2315 print_timestamp_done("SDLLoadImage");
2321 /* ------------------------------------------------------------------------- */
2322 /* custom cursor fuctions */
2323 /* ------------------------------------------------------------------------- */
2325 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2327 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2328 cursor_info->width, cursor_info->height,
2329 cursor_info->hot_x, cursor_info->hot_y);
2332 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2334 static struct MouseCursorInfo *last_cursor_info = NULL;
2335 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2336 static SDL_Cursor *cursor_default = NULL;
2337 static SDL_Cursor *cursor_current = NULL;
2339 /* if invoked for the first time, store the SDL default cursor */
2340 if (cursor_default == NULL)
2341 cursor_default = SDL_GetCursor();
2343 /* only create new cursor if cursor info (custom only) has changed */
2344 if (cursor_info != NULL && cursor_info != last_cursor_info)
2346 cursor_current = create_cursor(cursor_info);
2347 last_cursor_info = cursor_info;
2350 /* only set new cursor if cursor info (custom or NULL) has changed */
2351 if (cursor_info != last_cursor_info2)
2352 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2354 last_cursor_info2 = cursor_info;
2358 /* ========================================================================= */
2359 /* audio functions */
2360 /* ========================================================================= */
2362 void SDLOpenAudio(void)
2364 #if !defined(TARGET_SDL2)
2365 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2366 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2369 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2371 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2375 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2376 AUDIO_NUM_CHANNELS_STEREO,
2377 setup.system.audio_fragment_size) < 0)
2379 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2383 audio.sound_available = TRUE;
2384 audio.music_available = TRUE;
2385 audio.loops_available = TRUE;
2386 audio.sound_enabled = TRUE;
2388 /* set number of available mixer channels */
2389 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2390 audio.music_channel = MUSIC_CHANNEL;
2391 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2393 Mixer_InitChannels();
2396 void SDLCloseAudio(void)
2399 Mix_HaltChannel(-1);
2402 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2406 /* ========================================================================= */
2407 /* event functions */
2408 /* ========================================================================= */
2410 void SDLNextEvent(Event *event)
2412 SDL_WaitEvent(event);
2414 if (event->type == EVENT_BUTTONPRESS ||
2415 event->type == EVENT_BUTTONRELEASE)
2417 if (((ButtonEvent *)event)->x > video_xoffset)
2418 ((ButtonEvent *)event)->x -= video_xoffset;
2420 ((ButtonEvent *)event)->x = 0;
2421 if (((ButtonEvent *)event)->y > video_yoffset)
2422 ((ButtonEvent *)event)->y -= video_yoffset;
2424 ((ButtonEvent *)event)->y = 0;
2426 else if (event->type == EVENT_MOTIONNOTIFY)
2428 if (((MotionEvent *)event)->x > video_xoffset)
2429 ((MotionEvent *)event)->x -= video_xoffset;
2431 ((MotionEvent *)event)->x = 0;
2432 if (((MotionEvent *)event)->y > video_yoffset)
2433 ((MotionEvent *)event)->y -= video_yoffset;
2435 ((MotionEvent *)event)->y = 0;
2439 void SDLHandleWindowManagerEvent(Event *event)
2441 #if defined(PLATFORM_WIN32)
2442 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2443 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2445 if (syswmmsg->msg == WM_DROPFILES)
2447 HDROP hdrop = (HDROP)syswmmsg->wParam;
2450 printf("::: SDL_SYSWMEVENT:\n");
2452 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2454 for (i = 0; i < num_files; i++)
2456 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2457 char buffer[buffer_len + 1];
2459 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2461 printf("::: - '%s'\n", buffer);
2464 DragFinish((HDROP)syswmmsg->wParam);
2470 /* ========================================================================= */
2471 /* joystick functions */
2472 /* ========================================================================= */
2474 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2475 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2476 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2478 static boolean SDLOpenJoystick(int nr)
2480 if (nr < 0 || nr > MAX_PLAYERS)
2483 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2486 static void SDLCloseJoystick(int nr)
2488 if (nr < 0 || nr > MAX_PLAYERS)
2491 SDL_JoystickClose(sdl_joystick[nr]);
2493 sdl_joystick[nr] = NULL;
2496 static boolean SDLCheckJoystickOpened(int nr)
2498 if (nr < 0 || nr > MAX_PLAYERS)
2501 #if defined(TARGET_SDL2)
2502 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2504 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2508 void HandleJoystickEvent(Event *event)
2512 case SDL_JOYAXISMOTION:
2513 if (event->jaxis.axis < 2)
2514 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2517 case SDL_JOYBUTTONDOWN:
2518 if (event->jbutton.button < 2)
2519 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2522 case SDL_JOYBUTTONUP:
2523 if (event->jbutton.button < 2)
2524 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2532 void SDLInitJoysticks()
2534 static boolean sdl_joystick_subsystem_initialized = FALSE;
2535 boolean print_warning = !sdl_joystick_subsystem_initialized;
2538 if (!sdl_joystick_subsystem_initialized)
2540 sdl_joystick_subsystem_initialized = TRUE;
2542 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2544 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2549 for (i = 0; i < MAX_PLAYERS; i++)
2551 /* get configured joystick for this player */
2552 char *device_name = setup.input[i].joy.device_name;
2553 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2555 if (joystick_nr >= SDL_NumJoysticks())
2557 if (setup.input[i].use_joystick && print_warning)
2558 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2563 /* misuse joystick file descriptor variable to store joystick number */
2564 joystick.fd[i] = joystick_nr;
2566 if (joystick_nr == -1)
2569 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2570 if (SDLCheckJoystickOpened(joystick_nr))
2571 SDLCloseJoystick(joystick_nr);
2573 if (!setup.input[i].use_joystick)
2576 if (!SDLOpenJoystick(joystick_nr))
2579 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2584 joystick.status = JOYSTICK_ACTIVATED;
2588 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2590 if (nr < 0 || nr >= MAX_PLAYERS)
2594 *x = sdl_js_axis[nr][0];
2596 *y = sdl_js_axis[nr][1];
2599 *b1 = sdl_js_button[nr][0];
2601 *b2 = sdl_js_button[nr][1];
2606 #endif /* TARGET_SDL */