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;
395 int surface_flags_window = SURFACE_FLAGS;
396 #if defined(TARGET_SDL2)
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_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
408 int width = (fullscreen ? fullscreen_width : video.width);
409 int height = (fullscreen ? fullscreen_height : video.height);
410 int surface_flags = (fullscreen ? surface_flags_fullscreen :
411 surface_flags_window);
413 #if defined(TARGET_SDL2)
416 float window_scaling_factor = (float)setup.window_scaling_percent / 100;
417 float screen_scaling_factor = (fullscreen ? 1 : window_scaling_factor);
420 printf("::: use window scaling factor %f\n", screen_scaling_factor);
423 if ((*backbuffer)->surface)
424 SDL_FreeSurface((*backbuffer)->surface);
427 SDL_DestroyTexture(sdl_texture);
430 SDL_DestroyRenderer(sdl_renderer);
433 SDL_DestroyWindow(sdl_window);
435 sdl_window = SDL_CreateWindow(program.window_title,
436 SDL_WINDOWPOS_CENTERED,
437 SDL_WINDOWPOS_CENTERED,
438 (int)(screen_scaling_factor * width),
439 (int)(screen_scaling_factor * height),
442 if (sdl_window != NULL)
444 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
446 if (sdl_renderer != NULL)
448 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
449 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
451 sdl_texture = SDL_CreateTexture(sdl_renderer,
452 SDL_PIXELFORMAT_ARGB8888,
453 SDL_TEXTUREACCESS_STREAMING,
456 if (sdl_texture != NULL)
459 // (do not use alpha channel)
460 new_surface = SDL_CreateRGBSurface(0, width, height, 32,
466 // (this uses an alpha channel, which we don't want here)
467 new_surface = SDL_CreateRGBSurface(0, width, height, 32,
474 if (new_surface == NULL)
475 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
480 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
485 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
490 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
496 SDL_DestroyWindow(sdl_window);
498 sdl_window = SDL_CreateWindow(program.window_title,
499 SDL_WINDOWPOS_CENTERED,
500 SDL_WINDOWPOS_CENTERED,
504 if (sdl_window != NULL)
505 new_surface = SDL_GetWindowSurface(sdl_window);
509 new_surface = SDL_SetVideoMode(width, height, video.depth, surface_flags);
515 boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
517 boolean success = TRUE;
520 #if defined(TARGET_SDL2)
521 // int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN;
522 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP;
523 int surface_flags_window = SURFACE_FLAGS;
525 int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
526 int surface_flags_window = SURFACE_FLAGS;
529 SDL_Surface *new_surface = NULL;
531 if (*backbuffer == NULL)
532 *backbuffer = CreateBitmapStruct();
534 /* (real bitmap might be larger in fullscreen mode with video offsets) */
535 (*backbuffer)->width = video.width;
536 (*backbuffer)->height = video.height;
538 if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available)
540 setFullscreenParameters(setup.fullscreen_mode);
542 video_xoffset = fullscreen_xoffset;
543 video_yoffset = fullscreen_yoffset;
545 /* switch display to fullscreen mode, if available */
547 new_surface = SDLCreateScreen(backbuffer, TRUE);
550 #if defined(TARGET_SDL2)
551 sdl_window = SDL_CreateWindow(program.window_title,
552 SDL_WINDOWPOS_CENTERED,
553 SDL_WINDOWPOS_CENTERED,
554 fullscreen_width, fullscreen_height,
555 surface_flags_fullscreen);
556 if (sdl_window != NULL)
558 new_surface = SDL_GetWindowSurface(sdl_window);
560 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
561 // UpdateScreen(NULL); // immediately map window
564 new_surface = SDL_SetVideoMode(fullscreen_width, fullscreen_height,
565 video.depth, surface_flags_fullscreen);
569 if (new_surface == NULL)
571 /* switching display to fullscreen mode failed */
572 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
574 /* do not try it again */
575 video.fullscreen_available = FALSE;
581 (*backbuffer)->surface = new_surface;
583 video.fullscreen_enabled = TRUE;
584 video.fullscreen_mode_current = setup.fullscreen_mode;
590 if ((!fullscreen && video.fullscreen_enabled) || new_surface == NULL)
595 /* switch display to window mode */
597 new_surface = SDLCreateScreen(backbuffer, FALSE);
600 #if defined(TARGET_SDL2)
603 float screen_scaling_factor = 1.2;
604 int test_fullscreen = 0;
605 int surface_flags = (test_fullscreen ? surface_flags_fullscreen :
606 surface_flags_window);
608 if ((*backbuffer)->surface)
609 SDL_FreeSurface((*backbuffer)->surface);
612 SDL_DestroyTexture(sdl_texture);
615 SDL_DestroyRenderer(sdl_renderer);
618 SDL_DestroyWindow(sdl_window);
620 sdl_window = SDL_CreateWindow(program.window_title,
621 SDL_WINDOWPOS_CENTERED,
622 SDL_WINDOWPOS_CENTERED,
623 (int)(screen_scaling_factor * video.width),
624 (int)(screen_scaling_factor * video.height),
627 if (sdl_window != NULL)
629 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
631 if (sdl_renderer != NULL)
633 SDL_RenderSetLogicalSize(sdl_renderer, video.width, video.height);
634 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
636 sdl_texture = SDL_CreateTexture(sdl_renderer,
637 SDL_PIXELFORMAT_ARGB8888,
638 SDL_TEXTUREACCESS_STREAMING,
639 video.width, video.height);
641 if (sdl_texture != NULL)
644 // (do not use alpha channel)
645 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
651 // (this uses an alpha channel, which we don't want here)
652 new_surface = SDL_CreateRGBSurface(0, video.width, video.height, 32,
659 if (new_surface == NULL)
660 Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s",
665 Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError());
670 Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError());
675 Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError());
681 SDL_DestroyWindow(sdl_window);
683 sdl_window = SDL_CreateWindow(program.window_title,
684 SDL_WINDOWPOS_CENTERED,
685 SDL_WINDOWPOS_CENTERED,
686 video.width, video.height,
687 surface_flags_window);
689 if (sdl_window != NULL)
691 new_surface = SDL_GetWindowSurface(sdl_window);
693 // SDL_UpdateWindowSurface(sdl_window); // immediately map window
694 // UpdateScreen(NULL); // immediately map window
699 new_surface = SDL_SetVideoMode(video.width, video.height,
700 video.depth, surface_flags_window);
704 if (new_surface == NULL)
706 /* switching display to window mode failed -- should not happen */
707 Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError());
713 (*backbuffer)->surface = new_surface;
715 video.fullscreen_enabled = FALSE;
716 video.window_scaling_percent = setup.window_scaling_percent;
722 #if defined(TARGET_SDL2)
723 UpdateScreen(NULL); // map window
727 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
729 #if defined(PLATFORM_WIN32)
731 SDL_SysWMinfo wminfo;
734 SDL_VERSION(&wminfo.version);
735 SDL_GetWMInfo(&wminfo);
737 hwnd = wminfo.window;
739 DragAcceptFiles(hwnd, TRUE);
747 void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
750 SDL_Surface *surface_tmp, *surface_native;
752 if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
755 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
757 if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
758 Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
760 SDL_FreeSurface(surface_tmp);
762 new_bitmap->surface = surface_native;
765 void SDLFreeBitmapPointers(Bitmap *bitmap)
768 SDL_FreeSurface(bitmap->surface);
769 if (bitmap->surface_masked)
770 SDL_FreeSurface(bitmap->surface_masked);
771 bitmap->surface = NULL;
772 bitmap->surface_masked = NULL;
775 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
776 int src_x, int src_y, int width, int height,
777 int dst_x, int dst_y, int mask_mode)
779 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
780 SDL_Rect src_rect, dst_rect;
782 if (src_bitmap == backbuffer)
784 src_x += video_xoffset;
785 src_y += video_yoffset;
793 if (dst_bitmap == backbuffer || dst_bitmap == window)
795 dst_x += video_xoffset;
796 dst_y += video_yoffset;
804 // if (src_bitmap != backbuffer || dst_bitmap != window)
805 if (!(src_bitmap == backbuffer && dst_bitmap == window))
806 SDL_BlitSurface((mask_mode == BLIT_MASKED ?
807 src_bitmap->surface_masked : src_bitmap->surface),
808 &src_rect, real_dst_bitmap->surface, &dst_rect);
810 #if defined(TARGET_SDL2)
811 if (dst_bitmap == window)
813 // SDL_UpdateWindowSurface(sdl_window);
814 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
815 UpdateScreen(&dst_rect);
818 if (dst_bitmap == window)
819 SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
823 void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height,
826 Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
829 if (dst_bitmap == backbuffer || dst_bitmap == window)
840 SDL_FillRect(real_dst_bitmap->surface, &rect, color);
842 #if defined(TARGET_SDL2)
843 if (dst_bitmap == window)
845 // SDL_UpdateWindowSurface(sdl_window);
846 // SDL_UpdateWindowSurfaceRects(sdl_window, &rect, 1);
850 if (dst_bitmap == window)
851 SDL_UpdateRect(backbuffer->surface, x, y, width, height);
855 void SDLFadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
856 int fade_mode, int fade_delay, int post_delay,
857 void (*draw_border_function)(void))
859 static boolean initialization_needed = TRUE;
860 static SDL_Surface *surface_source = NULL;
861 static SDL_Surface *surface_target = NULL;
862 static SDL_Surface *surface_black = NULL;
863 SDL_Surface *surface_screen = backbuffer->surface;
864 SDL_Surface *surface_cross = (bitmap_cross ? bitmap_cross->surface : NULL);
865 SDL_Rect src_rect, dst_rect;
866 #if defined(TARGET_SDL2)
869 int src_x = x, src_y = y;
870 int dst_x = x, dst_y = y;
871 unsigned int time_last, time_current;
873 /* check if screen size has changed */
874 if (surface_source != NULL && (video.width != surface_source->w ||
875 video.height != surface_source->h))
877 SDL_FreeSurface(surface_source);
878 SDL_FreeSurface(surface_target);
879 SDL_FreeSurface(surface_black);
881 initialization_needed = TRUE;
889 dst_x += video_xoffset;
890 dst_y += video_yoffset;
894 dst_rect.w = width; /* (ignored) */
895 dst_rect.h = height; /* (ignored) */
897 #if defined(TARGET_SDL2)
898 dst_rect2 = dst_rect;
901 if (initialization_needed)
903 #if defined(TARGET_SDL2)
904 unsigned int flags = 0;
906 unsigned int flags = SDL_SRCALPHA;
908 /* use same surface type as screen surface */
909 if ((surface_screen->flags & SDL_HWSURFACE))
910 flags |= SDL_HWSURFACE;
912 flags |= SDL_SWSURFACE;
915 /* create surface for temporary copy of screen buffer (source) */
916 if ((surface_source =
917 SDL_CreateRGBSurface(flags,
920 surface_screen->format->BitsPerPixel,
921 surface_screen->format->Rmask,
922 surface_screen->format->Gmask,
923 surface_screen->format->Bmask,
924 surface_screen->format->Amask)) == NULL)
925 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
927 /* create surface for cross-fading screen buffer (target) */
928 if ((surface_target =
929 SDL_CreateRGBSurface(flags,
932 surface_screen->format->BitsPerPixel,
933 surface_screen->format->Rmask,
934 surface_screen->format->Gmask,
935 surface_screen->format->Bmask,
936 surface_screen->format->Amask)) == NULL)
937 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
939 /* create black surface for fading from/to black */
941 SDL_CreateRGBSurface(flags,
944 surface_screen->format->BitsPerPixel,
945 surface_screen->format->Rmask,
946 surface_screen->format->Gmask,
947 surface_screen->format->Bmask,
948 surface_screen->format->Amask)) == NULL)
949 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
951 /* completely fill the surface with black color pixels */
952 SDL_FillRect(surface_black, NULL,
953 SDL_MapRGB(surface_screen->format, 0, 0, 0));
955 initialization_needed = FALSE;
958 /* copy source and target surfaces to temporary surfaces for fading */
959 if (fade_mode & FADE_TYPE_TRANSFORM)
961 SDL_BlitSurface(surface_cross, &src_rect, surface_source, &src_rect);
962 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
964 else if (fade_mode & FADE_TYPE_FADE_IN)
966 SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect);
967 SDL_BlitSurface(surface_screen, &dst_rect, surface_target, &src_rect);
969 else /* FADE_TYPE_FADE_OUT */
971 SDL_BlitSurface(surface_screen, &dst_rect, surface_source, &src_rect);
972 SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect);
975 time_current = SDL_GetTicks();
977 if (fade_mode == FADE_MODE_MELT)
979 boolean done = FALSE;
981 int melt_columns = width / melt_pixels;
982 int ypos[melt_columns];
983 int max_steps = height / 8 + 32;
988 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
989 #if defined(TARGET_SDL2)
990 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_NONE);
992 SDL_SetAlpha(surface_target, 0, 0); /* disable alpha blending */
995 ypos[0] = -GetSimpleRandom(16);
997 for (i = 1 ; i < melt_columns; i++)
999 int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */
1001 ypos[i] = ypos[i - 1] + r;
1014 time_last = time_current;
1015 time_current = SDL_GetTicks();
1016 steps += max_steps * ((float)(time_current - time_last) / fade_delay);
1017 steps_final = MIN(MAX(0, steps), max_steps);
1021 done = (steps_done >= steps_final);
1023 for (i = 0 ; i < melt_columns; i++)
1031 else if (ypos[i] < height)
1036 int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3);
1038 if (ypos[i] + dy >= height)
1039 dy = height - ypos[i];
1041 /* copy part of (appearing) target surface to upper area */
1042 src_rect.x = src_x + i * melt_pixels;
1043 // src_rect.y = src_y + ypos[i];
1045 src_rect.w = melt_pixels;
1047 src_rect.h = ypos[i] + dy;
1049 dst_rect.x = dst_x + i * melt_pixels;
1050 // dst_rect.y = dst_y + ypos[i];
1053 if (steps_done >= steps_final)
1054 SDL_BlitSurface(surface_target, &src_rect,
1055 surface_screen, &dst_rect);
1059 /* copy part of (disappearing) source surface to lower area */
1060 src_rect.x = src_x + i * melt_pixels;
1062 src_rect.w = melt_pixels;
1063 src_rect.h = height - ypos[i];
1065 dst_rect.x = dst_x + i * melt_pixels;
1066 dst_rect.y = dst_y + ypos[i];
1068 if (steps_done >= steps_final)
1069 SDL_BlitSurface(surface_source, &src_rect,
1070 surface_screen, &dst_rect);
1076 src_rect.x = src_x + i * melt_pixels;
1078 src_rect.w = melt_pixels;
1079 src_rect.h = height;
1081 dst_rect.x = dst_x + i * melt_pixels;
1084 if (steps_done >= steps_final)
1085 SDL_BlitSurface(surface_target, &src_rect,
1086 surface_screen, &dst_rect);
1090 if (steps_done >= steps_final)
1092 if (draw_border_function != NULL)
1093 draw_border_function();
1095 #if defined(TARGET_SDL2)
1096 // SDL_UpdateWindowSurface(sdl_window);
1097 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect2, 1);
1098 UpdateScreen(&dst_rect2);
1100 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1110 for (alpha = 0.0; alpha < 255.0;)
1112 time_last = time_current;
1113 time_current = SDL_GetTicks();
1114 alpha += 255 * ((float)(time_current - time_last) / fade_delay);
1115 alpha_final = MIN(MAX(0, alpha), 255);
1117 /* draw existing (source) image to screen buffer */
1118 SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect);
1120 /* draw new (target) image to screen buffer using alpha blending */
1121 #if defined(TARGET_SDL2)
1122 SDL_SetSurfaceAlphaMod(surface_target, alpha_final);
1123 SDL_SetSurfaceBlendMode(surface_target, SDL_BLENDMODE_BLEND);
1125 SDL_SetAlpha(surface_target, SDL_SRCALPHA, alpha_final);
1127 SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect);
1129 if (draw_border_function != NULL)
1130 draw_border_function();
1133 /* only update the region of the screen that is affected from fading */
1134 #if defined(TARGET_SDL2)
1135 // SDL_UpdateWindowSurface(sdl_window);
1136 // SDL_UpdateWindowSurfaceRects(sdl_window, &dst_rect, 1);
1137 UpdateScreen(&dst_rect);
1139 SDL_UpdateRect(surface_screen, dst_x, dst_y, width, height);
1142 SDL_Flip(surface_screen);
1150 void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
1151 int to_x, int to_y, Uint32 color)
1153 SDL_Surface *surface = dst_bitmap->surface;
1157 swap_numbers(&from_x, &to_x);
1160 swap_numbers(&from_y, &to_y);
1164 rect.w = (to_x - from_x + 1);
1165 rect.h = (to_y - from_y + 1);
1167 if (dst_bitmap == backbuffer || dst_bitmap == window)
1169 rect.x += video_xoffset;
1170 rect.y += video_yoffset;
1173 SDL_FillRect(surface, &rect, color);
1176 void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
1177 int to_x, int to_y, Uint32 color)
1179 if (dst_bitmap == backbuffer || dst_bitmap == window)
1181 from_x += video_xoffset;
1182 from_y += video_yoffset;
1183 to_x += video_xoffset;
1184 to_y += video_yoffset;
1187 sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color);
1191 void SDLDrawLines(SDL_Surface *surface, struct XY *points,
1192 int num_points, Uint32 color)
1197 for (i = 0; i < num_points - 1; i++)
1199 for (x = 0; x < line_width; x++)
1201 for (y = 0; y < line_width; y++)
1203 int dx = x - line_width / 2;
1204 int dy = y - line_width / 2;
1206 if ((x == 0 && y == 0) ||
1207 (x == 0 && y == line_width - 1) ||
1208 (x == line_width - 1 && y == 0) ||
1209 (x == line_width - 1 && y == line_width - 1))
1212 sge_Line(surface, points[i].x + dx, points[i].y + dy,
1213 points[i+1].x + dx, points[i+1].y + dy, color);
1220 Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
1222 SDL_Surface *surface = src_bitmap->surface;
1224 if (src_bitmap == backbuffer || src_bitmap == window)
1230 switch (surface->format->BytesPerPixel)
1232 case 1: /* assuming 8-bpp */
1234 return *((Uint8 *)surface->pixels + y * surface->pitch + x);
1238 case 2: /* probably 15-bpp or 16-bpp */
1240 return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
1244 case 3: /* slow 24-bpp mode; usually not used */
1246 /* does this work? */
1247 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
1251 shift = surface->format->Rshift;
1252 color |= *(pix + shift / 8) >> shift;
1253 shift = surface->format->Gshift;
1254 color |= *(pix + shift / 8) >> shift;
1255 shift = surface->format->Bshift;
1256 color |= *(pix + shift / 8) >> shift;
1262 case 4: /* probably 32-bpp */
1264 return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
1273 /* ========================================================================= */
1274 /* The following functions were taken from the SGE library */
1275 /* (SDL Graphics Extension Library) by Anders Lindström */
1276 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */
1277 /* ========================================================================= */
1279 void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1281 if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1)
1283 switch (surface->format->BytesPerPixel)
1287 /* Assuming 8-bpp */
1288 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1294 /* Probably 15-bpp or 16-bpp */
1295 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1301 /* Slow 24-bpp mode, usually not used */
1305 /* Gack - slow, but endian correct */
1306 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1307 shift = surface->format->Rshift;
1308 *(pix+shift/8) = color>>shift;
1309 shift = surface->format->Gshift;
1310 *(pix+shift/8) = color>>shift;
1311 shift = surface->format->Bshift;
1312 *(pix+shift/8) = color>>shift;
1318 /* Probably 32-bpp */
1319 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1326 void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1327 Uint8 R, Uint8 G, Uint8 B)
1329 _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
1332 void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1334 *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
1337 void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1339 *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
1342 void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1347 /* Gack - slow, but endian correct */
1348 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
1349 shift = surface->format->Rshift;
1350 *(pix+shift/8) = color>>shift;
1351 shift = surface->format->Gshift;
1352 *(pix+shift/8) = color>>shift;
1353 shift = surface->format->Bshift;
1354 *(pix+shift/8) = color>>shift;
1357 void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1359 *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
1362 void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
1364 switch (dest->format->BytesPerPixel)
1367 *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
1371 *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
1375 _PutPixel24(dest,x,y,color);
1379 *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
1384 void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
1386 if (SDL_MUSTLOCK(surface))
1388 if (SDL_LockSurface(surface) < 0)
1394 _PutPixel(surface, x, y, color);
1396 if (SDL_MUSTLOCK(surface))
1398 SDL_UnlockSurface(surface);
1402 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
1403 Uint8 r, Uint8 g, Uint8 b)
1405 sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
1408 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
1410 if (y >= 0 && y <= dest->h - 1)
1412 switch (dest->format->BytesPerPixel)
1415 return y*dest->pitch;
1419 return y*dest->pitch/2;
1423 return y*dest->pitch;
1427 return y*dest->pitch/4;
1435 void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
1437 if (x >= 0 && x <= surface->w - 1 && ypitch >= 0)
1439 switch (surface->format->BytesPerPixel)
1443 /* Assuming 8-bpp */
1444 *((Uint8 *)surface->pixels + ypitch + x) = color;
1450 /* Probably 15-bpp or 16-bpp */
1451 *((Uint16 *)surface->pixels + ypitch + x) = color;
1457 /* Slow 24-bpp mode, usually not used */
1461 /* Gack - slow, but endian correct */
1462 pix = (Uint8 *)surface->pixels + ypitch + x*3;
1463 shift = surface->format->Rshift;
1464 *(pix+shift/8) = color>>shift;
1465 shift = surface->format->Gshift;
1466 *(pix+shift/8) = color>>shift;
1467 shift = surface->format->Bshift;
1468 *(pix+shift/8) = color>>shift;
1474 /* Probably 32-bpp */
1475 *((Uint32 *)surface->pixels + ypitch + x) = color;
1482 void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1487 if (SDL_MUSTLOCK(Surface))
1489 if (SDL_LockSurface(Surface) < 0)
1502 /* Do the clipping */
1503 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1507 if (x2 > Surface->w - 1)
1508 x2 = Surface->w - 1;
1515 SDL_FillRect(Surface, &l, Color);
1517 if (SDL_MUSTLOCK(Surface))
1519 SDL_UnlockSurface(Surface);
1523 void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y,
1524 Uint8 R, Uint8 G, Uint8 B)
1526 sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B));
1529 void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color)
1540 /* Do the clipping */
1541 if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0)
1545 if (x2 > Surface->w - 1)
1546 x2 = Surface->w - 1;
1553 SDL_FillRect(Surface, &l, Color);
1556 void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1561 if (SDL_MUSTLOCK(Surface))
1563 if (SDL_LockSurface(Surface) < 0)
1576 /* Do the clipping */
1577 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1581 if (y2 > Surface->h - 1)
1582 y2 = Surface->h - 1;
1589 SDL_FillRect(Surface, &l, Color);
1591 if (SDL_MUSTLOCK(Surface))
1593 SDL_UnlockSurface(Surface);
1597 void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2,
1598 Uint8 R, Uint8 G, Uint8 B)
1600 sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B));
1603 void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
1614 /* Do the clipping */
1615 if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0)
1619 if (y2 > Surface->h - 1)
1620 y2 = Surface->h - 1;
1627 SDL_FillRect(Surface, &l, Color);
1630 void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1,
1631 Sint16 x2, Sint16 y2, Uint32 Color,
1632 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1635 Sint16 dx, dy, sdx, sdy, x, y, px, py;
1640 sdx = (dx < 0) ? -1 : 1;
1641 sdy = (dy < 0) ? -1 : 1;
1653 for (x = 0; x < dx; x++)
1655 Callback(Surface, px, py, Color);
1669 for (y = 0; y < dy; y++)
1671 Callback(Surface, px, py, Color);
1685 void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1,
1686 Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B,
1687 void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y,
1690 sge_DoLine(Surface, X1, Y1, X2, Y2,
1691 SDL_MapRGB(Surface->format, R, G, B), Callback);
1694 void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
1697 if (SDL_MUSTLOCK(Surface))
1699 if (SDL_LockSurface(Surface) < 0)
1704 sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel);
1706 /* unlock the display */
1707 if (SDL_MUSTLOCK(Surface))
1709 SDL_UnlockSurface(Surface);
1713 void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
1714 Sint16 y2, Uint8 R, Uint8 G, Uint8 B)
1716 sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
1719 void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
1721 if (dst_bitmap == backbuffer || dst_bitmap == window)
1727 sge_PutPixel(dst_bitmap->surface, x, y, pixel);
1732 -----------------------------------------------------------------------------
1733 quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
1734 -----------------------------------------------------------------------------
1737 void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
1738 int width, int height, Uint32 color)
1742 for (y = src_y; y < src_y + height; y++)
1744 for (x = src_x; x < src_x + width; x++)
1746 Uint32 pixel = SDLGetPixel(bitmap, x, y);
1748 SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
1753 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
1754 int src_x, int src_y, int width, int height,
1755 int dst_x, int dst_y)
1759 for (y = 0; y < height; y++)
1761 for (x = 0; x < width; x++)
1763 Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
1765 if (pixel != BLACK_PIXEL)
1766 SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
1772 /* ========================================================================= */
1773 /* The following functions were taken from the SDL_gfx library version 2.0.3 */
1774 /* (Rotozoomer) by Andreas Schiffler */
1775 /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */
1776 /* ========================================================================= */
1779 -----------------------------------------------------------------------------
1782 zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
1783 -----------------------------------------------------------------------------
1794 int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst)
1797 tColorRGBA *sp, *csp, *dp;
1804 sp = csp = (tColorRGBA *) src->pixels;
1805 dp = (tColorRGBA *) dst->pixels;
1807 sgap = src->pitch - src->w * 4;
1809 dgap = dst->pitch - dst->w * 4;
1811 for (y = 0; y < dst->h; y++)
1815 for (x = 0; x < dst->w; x++)
1817 tColorRGBA *sp0 = sp;
1818 tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
1819 tColorRGBA *sp00 = &sp0[0];
1820 tColorRGBA *sp01 = &sp0[1];
1821 tColorRGBA *sp10 = &sp1[0];
1822 tColorRGBA *sp11 = &sp1[1];
1825 /* create new color pixel from all four source color pixels */
1826 new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4;
1827 new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4;
1828 new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4;
1829 new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4;
1834 /* advance source pointers */
1837 /* advance destination pointer */
1841 /* advance source pointer */
1842 csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch);
1844 /* advance destination pointers */
1845 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1851 int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
1853 int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1854 tColorRGBA *sp, *csp, *dp;
1860 /* use specialized zoom function when scaling down to exactly half size */
1861 if (src->w == 2 * dst->w &&
1862 src->h == 2 * dst->h)
1863 return zoomSurfaceRGBA_scaleDownBy2(src, dst);
1865 /* variable setup */
1866 sx = (int) (65536.0 * (float) src->w / (float) dst->w);
1867 sy = (int) (65536.0 * (float) src->h / (float) dst->h);
1869 /* allocate memory for row increments */
1870 sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
1871 say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
1873 /* precalculate row increments */
1876 for (x = 0; x <= dst->w; x++)
1886 for (y = 0; y <= dst->h; y++)
1895 sp = csp = (tColorRGBA *) src->pixels;
1896 dp = (tColorRGBA *) dst->pixels;
1898 sgap = src->pitch - src->w * 4;
1900 dgap = dst->pitch - dst->w * 4;
1903 for (y = 0; y < dst->h; y++)
1908 for (x = 0; x < dst->w; x++)
1913 /* advance source pointers */
1915 sp += (*csax >> 16);
1917 /* advance destination pointer */
1921 /* advance source pointer */
1923 csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
1925 /* advance destination pointers */
1926 dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
1936 -----------------------------------------------------------------------------
1939 zoomes 8 bit palette/Y 'src' surface to 'dst' surface
1940 -----------------------------------------------------------------------------
1943 int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
1945 Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
1946 Uint8 *sp, *dp, *csp;
1949 /* variable setup */
1950 sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
1951 sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
1953 /* allocate memory for row increments */
1954 sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
1955 say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
1957 /* precalculate row increments */
1960 for (x = 0; x < dst->w; x++)
1963 *csax = (csx >> 16);
1970 for (y = 0; y < dst->h; y++)
1973 *csay = (csy >> 16);
1980 for (x = 0; x < dst->w; x++)
1988 for (y = 0; y < dst->h; y++)
1995 sp = csp = (Uint8 *) src->pixels;
1996 dp = (Uint8 *) dst->pixels;
1997 dgap = dst->pitch - dst->w;
2001 for (y = 0; y < dst->h; y++)
2005 for (x = 0; x < dst->w; x++)
2010 /* advance source pointers */
2014 /* advance destination pointer */
2018 /* advance source pointer (for row) */
2019 csp += ((*csay) * src->pitch);
2022 /* advance destination pointers */
2033 -----------------------------------------------------------------------------
2036 Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
2037 'zoomx' and 'zoomy' are scaling factors for width and height.
2038 If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
2039 into a 32bit RGBA format on the fly.
2040 -----------------------------------------------------------------------------
2043 SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
2045 SDL_Surface *zoom_src = NULL;
2046 SDL_Surface *zoom_dst = NULL;
2047 boolean is_converted = FALSE;
2054 /* determine if source surface is 32 bit or 8 bit */
2055 is_32bit = (src->format->BitsPerPixel == 32);
2057 if (is_32bit || src->format->BitsPerPixel == 8)
2059 /* use source surface 'as is' */
2064 /* new source surface is 32 bit with a defined RGB ordering */
2065 zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
2066 0x000000ff, 0x0000ff00, 0x00ff0000, 0);
2067 SDL_BlitSurface(src, NULL, zoom_src, NULL);
2069 is_converted = TRUE;
2072 /* allocate surface to completely contain the zoomed surface */
2075 /* target surface is 32 bit with source RGBA/ABGR ordering */
2076 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
2077 zoom_src->format->Rmask,
2078 zoom_src->format->Gmask,
2079 zoom_src->format->Bmask, 0);
2083 /* target surface is 8 bit */
2084 zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
2088 /* lock source surface */
2089 SDL_LockSurface(zoom_src);
2091 /* check which kind of surface we have */
2094 /* call the 32 bit transformation routine to do the zooming */
2095 zoomSurfaceRGBA(zoom_src, zoom_dst);
2100 for (i = 0; i < zoom_src->format->palette->ncolors; i++)
2101 zoom_dst->format->palette->colors[i] =
2102 zoom_src->format->palette->colors[i];
2103 zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
2105 /* call the 8 bit transformation routine to do the zooming */
2106 zoomSurfaceY(zoom_src, zoom_dst);
2109 /* unlock source surface */
2110 SDL_UnlockSurface(zoom_src);
2112 /* free temporary surface */
2114 SDL_FreeSurface(zoom_src);
2116 /* return destination surface */
2120 void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
2122 SDL_Surface *sdl_surface_tmp;
2123 int dst_width = dst_bitmap->width;
2124 int dst_height = dst_bitmap->height;
2126 /* throw away old destination surface */
2127 SDL_FreeSurface(dst_bitmap->surface);
2129 /* create zoomed temporary surface from source surface */
2130 sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
2132 /* create native format destination surface from zoomed temporary surface */
2133 dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
2135 /* free temporary surface */
2136 SDL_FreeSurface(sdl_surface_tmp);
2140 /* ========================================================================= */
2141 /* load image to bitmap */
2142 /* ========================================================================= */
2144 Bitmap *SDLLoadImage(char *filename)
2146 Bitmap *new_bitmap = CreateBitmapStruct();
2147 SDL_Surface *sdl_image_tmp;
2149 print_timestamp_init("SDLLoadImage");
2151 print_timestamp_time(getBaseNamePtr(filename));
2153 /* load image to temporary surface */
2154 if ((sdl_image_tmp = IMG_Load(filename)) == NULL)
2156 SetError("IMG_Load(): %s", SDL_GetError());
2161 print_timestamp_time("IMG_Load");
2163 UPDATE_BUSY_STATE();
2165 /* create native non-transparent surface for current image */
2166 if ((new_bitmap->surface = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2168 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2173 print_timestamp_time("SDL_DisplayFormat (opaque)");
2175 UPDATE_BUSY_STATE();
2177 /* create native transparent surface for current image */
2178 SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL,
2179 SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
2180 if ((new_bitmap->surface_masked = SDL_DisplayFormat(sdl_image_tmp)) == NULL)
2182 SetError("SDL_DisplayFormat(): %s", SDL_GetError());
2187 print_timestamp_time("SDL_DisplayFormat (masked)");
2189 UPDATE_BUSY_STATE();
2191 /* free temporary surface */
2192 SDL_FreeSurface(sdl_image_tmp);
2194 new_bitmap->width = new_bitmap->surface->w;
2195 new_bitmap->height = new_bitmap->surface->h;
2197 print_timestamp_done("SDLLoadImage");
2203 /* ------------------------------------------------------------------------- */
2204 /* custom cursor fuctions */
2205 /* ------------------------------------------------------------------------- */
2207 static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
2209 return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
2210 cursor_info->width, cursor_info->height,
2211 cursor_info->hot_x, cursor_info->hot_y);
2214 void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
2216 static struct MouseCursorInfo *last_cursor_info = NULL;
2217 static struct MouseCursorInfo *last_cursor_info2 = NULL;
2218 static SDL_Cursor *cursor_default = NULL;
2219 static SDL_Cursor *cursor_current = NULL;
2221 /* if invoked for the first time, store the SDL default cursor */
2222 if (cursor_default == NULL)
2223 cursor_default = SDL_GetCursor();
2225 /* only create new cursor if cursor info (custom only) has changed */
2226 if (cursor_info != NULL && cursor_info != last_cursor_info)
2228 cursor_current = create_cursor(cursor_info);
2229 last_cursor_info = cursor_info;
2232 /* only set new cursor if cursor info (custom or NULL) has changed */
2233 if (cursor_info != last_cursor_info2)
2234 SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
2236 last_cursor_info2 = cursor_info;
2240 /* ========================================================================= */
2241 /* audio functions */
2242 /* ========================================================================= */
2244 void SDLOpenAudio(void)
2246 #if !defined(TARGET_SDL2)
2247 if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
2248 SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
2251 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
2253 Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
2257 if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
2258 AUDIO_NUM_CHANNELS_STEREO,
2259 setup.system.audio_fragment_size) < 0)
2261 Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
2265 audio.sound_available = TRUE;
2266 audio.music_available = TRUE;
2267 audio.loops_available = TRUE;
2268 audio.sound_enabled = TRUE;
2270 /* set number of available mixer channels */
2271 audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS);
2272 audio.music_channel = MUSIC_CHANNEL;
2273 audio.first_sound_channel = FIRST_SOUND_CHANNEL;
2275 Mixer_InitChannels();
2278 void SDLCloseAudio(void)
2281 Mix_HaltChannel(-1);
2284 SDL_QuitSubSystem(SDL_INIT_AUDIO);
2288 /* ========================================================================= */
2289 /* event functions */
2290 /* ========================================================================= */
2292 void SDLNextEvent(Event *event)
2294 SDL_WaitEvent(event);
2296 if (event->type == EVENT_BUTTONPRESS ||
2297 event->type == EVENT_BUTTONRELEASE)
2299 if (((ButtonEvent *)event)->x > video_xoffset)
2300 ((ButtonEvent *)event)->x -= video_xoffset;
2302 ((ButtonEvent *)event)->x = 0;
2303 if (((ButtonEvent *)event)->y > video_yoffset)
2304 ((ButtonEvent *)event)->y -= video_yoffset;
2306 ((ButtonEvent *)event)->y = 0;
2308 else if (event->type == EVENT_MOTIONNOTIFY)
2310 if (((MotionEvent *)event)->x > video_xoffset)
2311 ((MotionEvent *)event)->x -= video_xoffset;
2313 ((MotionEvent *)event)->x = 0;
2314 if (((MotionEvent *)event)->y > video_yoffset)
2315 ((MotionEvent *)event)->y -= video_yoffset;
2317 ((MotionEvent *)event)->y = 0;
2321 void SDLHandleWindowManagerEvent(Event *event)
2323 #if defined(PLATFORM_WIN32)
2324 SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event;
2325 SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg);
2327 if (syswmmsg->msg == WM_DROPFILES)
2329 HDROP hdrop = (HDROP)syswmmsg->wParam;
2332 printf("::: SDL_SYSWMEVENT:\n");
2334 num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
2336 for (i = 0; i < num_files; i++)
2338 int buffer_len = DragQueryFile(hdrop, i, NULL, 0);
2339 char buffer[buffer_len + 1];
2341 DragQueryFile(hdrop, i, buffer, buffer_len + 1);
2343 printf("::: - '%s'\n", buffer);
2346 DragFinish((HDROP)syswmmsg->wParam);
2352 /* ========================================================================= */
2353 /* joystick functions */
2354 /* ========================================================================= */
2356 static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
2357 static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2358 static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
2360 static boolean SDLOpenJoystick(int nr)
2362 if (nr < 0 || nr > MAX_PLAYERS)
2365 return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
2368 static void SDLCloseJoystick(int nr)
2370 if (nr < 0 || nr > MAX_PLAYERS)
2373 SDL_JoystickClose(sdl_joystick[nr]);
2375 sdl_joystick[nr] = NULL;
2378 static boolean SDLCheckJoystickOpened(int nr)
2380 if (nr < 0 || nr > MAX_PLAYERS)
2383 #if defined(TARGET_SDL2)
2384 return (sdl_joystick[nr] != NULL ? TRUE : FALSE);
2386 return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
2390 void HandleJoystickEvent(Event *event)
2394 case SDL_JOYAXISMOTION:
2395 if (event->jaxis.axis < 2)
2396 sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
2399 case SDL_JOYBUTTONDOWN:
2400 if (event->jbutton.button < 2)
2401 sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
2404 case SDL_JOYBUTTONUP:
2405 if (event->jbutton.button < 2)
2406 sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
2414 void SDLInitJoysticks()
2416 static boolean sdl_joystick_subsystem_initialized = FALSE;
2417 boolean print_warning = !sdl_joystick_subsystem_initialized;
2420 if (!sdl_joystick_subsystem_initialized)
2422 sdl_joystick_subsystem_initialized = TRUE;
2424 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
2426 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
2431 for (i = 0; i < MAX_PLAYERS; i++)
2433 /* get configured joystick for this player */
2434 char *device_name = setup.input[i].joy.device_name;
2435 int joystick_nr = getJoystickNrFromDeviceName(device_name);
2437 if (joystick_nr >= SDL_NumJoysticks())
2439 if (setup.input[i].use_joystick && print_warning)
2440 Error(ERR_WARN, "cannot find joystick %d", joystick_nr);
2445 /* misuse joystick file descriptor variable to store joystick number */
2446 joystick.fd[i] = joystick_nr;
2448 if (joystick_nr == -1)
2451 /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
2452 if (SDLCheckJoystickOpened(joystick_nr))
2453 SDLCloseJoystick(joystick_nr);
2455 if (!setup.input[i].use_joystick)
2458 if (!SDLOpenJoystick(joystick_nr))
2461 Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
2466 joystick.status = JOYSTICK_ACTIVATED;
2470 boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
2472 if (nr < 0 || nr >= MAX_PLAYERS)
2476 *x = sdl_js_axis[nr][0];
2478 *y = sdl_js_axis[nr][1];
2481 *b1 = sdl_js_button[nr][0];
2483 *b2 = sdl_js_button[nr][1];
2488 #endif /* TARGET_SDL */